@seflless/ghosttown 1.4.1 → 1.5.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.
- package/package.json +1 -1
- package/src/cli.js +44 -32
package/package.json
CHANGED
package/src/cli.js
CHANGED
|
@@ -100,16 +100,16 @@ function getCurrentTmuxSessionName() {
|
|
|
100
100
|
}
|
|
101
101
|
|
|
102
102
|
/**
|
|
103
|
-
* Check if currently inside a ghosttown session (named
|
|
103
|
+
* Check if currently inside a ghosttown session (named gt-<N>)
|
|
104
104
|
*/
|
|
105
105
|
function isInsideGhosttownSession() {
|
|
106
106
|
const sessionName = getCurrentTmuxSessionName();
|
|
107
|
-
return sessionName && sessionName.startsWith('
|
|
107
|
+
return sessionName && sessionName.startsWith('gt-');
|
|
108
108
|
}
|
|
109
109
|
|
|
110
110
|
/**
|
|
111
111
|
* Get the next available ghosttown session ID
|
|
112
|
-
* Scans existing tmux sessions named
|
|
112
|
+
* Scans existing tmux sessions named gt-<N> and returns max(N) + 1
|
|
113
113
|
*/
|
|
114
114
|
function getNextSessionId() {
|
|
115
115
|
try {
|
|
@@ -119,12 +119,12 @@ function getNextSessionId() {
|
|
|
119
119
|
stdio: ['pipe', 'pipe', 'pipe'],
|
|
120
120
|
});
|
|
121
121
|
|
|
122
|
-
// Find all
|
|
122
|
+
// Find all gt-<N> sessions and extract IDs
|
|
123
123
|
const sessionIds = output
|
|
124
124
|
.split('\n')
|
|
125
|
-
.filter((name) => name.startsWith('
|
|
125
|
+
.filter((name) => name.startsWith('gt-'))
|
|
126
126
|
.map((name) => {
|
|
127
|
-
const id = Number.parseInt(name.replace('
|
|
127
|
+
const id = Number.parseInt(name.replace('gt-', ''), 10);
|
|
128
128
|
return Number.isNaN(id) ? 0 : id;
|
|
129
129
|
});
|
|
130
130
|
|
|
@@ -150,9 +150,9 @@ function listSessions() {
|
|
|
150
150
|
const BEIGE = '\x1b[38;2;255;220;150m';
|
|
151
151
|
|
|
152
152
|
try {
|
|
153
|
-
// Get detailed session information
|
|
153
|
+
// Get detailed session information including last activity time
|
|
154
154
|
const output = execSync(
|
|
155
|
-
'tmux list-sessions -F "#{session_name}|#{
|
|
155
|
+
'tmux list-sessions -F "#{session_name}|#{session_activity}|#{session_attached}|#{session_windows}"',
|
|
156
156
|
{
|
|
157
157
|
encoding: 'utf8',
|
|
158
158
|
stdio: ['pipe', 'pipe', 'pipe'],
|
|
@@ -161,12 +161,15 @@ function listSessions() {
|
|
|
161
161
|
|
|
162
162
|
const sessions = output
|
|
163
163
|
.split('\n')
|
|
164
|
-
.filter((line) => line.startsWith('
|
|
164
|
+
.filter((line) => line.startsWith('gt-'))
|
|
165
165
|
.map((line) => {
|
|
166
|
-
const [name,
|
|
166
|
+
const [name, activity, attached, windows] = line.split('|');
|
|
167
|
+
// Extract just the number from gt-<N>
|
|
168
|
+
const id = name.replace('gt-', '');
|
|
167
169
|
return {
|
|
170
|
+
id,
|
|
168
171
|
name,
|
|
169
|
-
|
|
172
|
+
activity: new Date(Number.parseInt(activity, 10) * 1000),
|
|
170
173
|
attached: attached === '1',
|
|
171
174
|
windows: Number.parseInt(windows, 10),
|
|
172
175
|
};
|
|
@@ -179,21 +182,24 @@ function listSessions() {
|
|
|
179
182
|
process.exit(0);
|
|
180
183
|
}
|
|
181
184
|
|
|
185
|
+
// Sort by last activity (most recent first)
|
|
186
|
+
sessions.sort((a, b) => b.activity.getTime() - a.activity.getTime());
|
|
187
|
+
|
|
182
188
|
// Print header
|
|
183
189
|
console.log('\n\x1b[1mGhosttown Sessions\x1b[0m\n');
|
|
184
190
|
console.log(
|
|
185
|
-
`${CYAN}${'
|
|
191
|
+
`${CYAN}${'ID'.padEnd(6)} ${'Last Activity'.padEnd(22)} ${'Status'.padEnd(10)} Windows${RESET}`
|
|
186
192
|
);
|
|
187
193
|
|
|
188
194
|
// Print sessions
|
|
189
195
|
for (const session of sessions) {
|
|
190
|
-
const
|
|
196
|
+
const activityStr = session.activity.toLocaleString();
|
|
191
197
|
// Status has ANSI codes so we need to pad the visible text differently
|
|
192
198
|
const statusPadded = session.attached
|
|
193
199
|
? `\x1b[32m${'attached'.padEnd(10)}${RESET}`
|
|
194
200
|
: `\x1b[33m${'detached'.padEnd(10)}${RESET}`;
|
|
195
201
|
console.log(
|
|
196
|
-
`${session.
|
|
202
|
+
`${session.id.padEnd(6)} ${activityStr.padEnd(22)} ${statusPadded} ${session.windows}`
|
|
197
203
|
);
|
|
198
204
|
}
|
|
199
205
|
|
|
@@ -221,7 +227,7 @@ function createTmuxSession(command) {
|
|
|
221
227
|
}
|
|
222
228
|
|
|
223
229
|
const sessionId = getNextSessionId();
|
|
224
|
-
const sessionName = `
|
|
230
|
+
const sessionName = `gt-${sessionId}`;
|
|
225
231
|
|
|
226
232
|
try {
|
|
227
233
|
// Create tmux session and attach directly (not detached)
|
|
@@ -268,14 +274,17 @@ function printDetachMessage(sessionName) {
|
|
|
268
274
|
const formatHint = (label, command) =>
|
|
269
275
|
` ${CYAN}${label.padStart(labelWidth)}${RESET} ${BEIGE}${command}${RESET}`;
|
|
270
276
|
|
|
277
|
+
// Extract just the ID from gt-<N>
|
|
278
|
+
const sessionId = sessionName.replace('gt-', '');
|
|
279
|
+
|
|
271
280
|
return [
|
|
272
281
|
'',
|
|
273
282
|
` ${BOLD_YELLOW}You've detached from your ghosttown session.${RESET}`,
|
|
274
283
|
` ${DIM}It's now running in the background.${RESET}`,
|
|
275
284
|
'',
|
|
276
|
-
formatHint('To reattach:', `
|
|
285
|
+
formatHint('To reattach:', `gt attach ${sessionId}`),
|
|
277
286
|
'',
|
|
278
|
-
formatHint('To list all sessions:', '
|
|
287
|
+
formatHint('To list all sessions:', 'gt list'),
|
|
279
288
|
'',
|
|
280
289
|
'',
|
|
281
290
|
].join('\n');
|
|
@@ -369,9 +378,9 @@ function attachToSession(sessionName) {
|
|
|
369
378
|
const RED = '\x1b[31m';
|
|
370
379
|
const BEIGE = '\x1b[38;2;255;220;150m';
|
|
371
380
|
|
|
372
|
-
// Add
|
|
373
|
-
if (!sessionName.startsWith('
|
|
374
|
-
sessionName = `
|
|
381
|
+
// Add gt- prefix if not present
|
|
382
|
+
if (!sessionName.startsWith('gt-')) {
|
|
383
|
+
sessionName = `gt-${sessionName}`;
|
|
375
384
|
}
|
|
376
385
|
|
|
377
386
|
// Check if session exists
|
|
@@ -521,9 +530,9 @@ function killSession(sessionName) {
|
|
|
521
530
|
sessionName = getCurrentTmuxSessionName();
|
|
522
531
|
}
|
|
523
532
|
|
|
524
|
-
// Add
|
|
525
|
-
if (!sessionName.startsWith('
|
|
526
|
-
sessionName = `
|
|
533
|
+
// Add gt- prefix if not present
|
|
534
|
+
if (!sessionName.startsWith('gt-')) {
|
|
535
|
+
sessionName = `gt-${sessionName}`;
|
|
527
536
|
}
|
|
528
537
|
|
|
529
538
|
// Check if session exists
|
|
@@ -557,10 +566,13 @@ function killSession(sessionName) {
|
|
|
557
566
|
stdio: 'pipe',
|
|
558
567
|
});
|
|
559
568
|
|
|
569
|
+
// Extract just the ID from gt-<N>
|
|
570
|
+
const sessionId = sessionName.replace('gt-', '');
|
|
571
|
+
|
|
560
572
|
console.log('');
|
|
561
|
-
console.log(` ${BOLD_YELLOW}Session
|
|
573
|
+
console.log(` ${BOLD_YELLOW}Session ${sessionId} has been killed.${RESET}`);
|
|
562
574
|
console.log('');
|
|
563
|
-
console.log(` ${CYAN}To list remaining:${RESET} ${BEIGE}
|
|
575
|
+
console.log(` ${CYAN}To list remaining:${RESET} ${BEIGE}gt list${RESET}`);
|
|
564
576
|
console.log('');
|
|
565
577
|
process.exit(0);
|
|
566
578
|
} catch (err) {
|
|
@@ -590,26 +602,26 @@ Usage: ghosttown [options] [command]
|
|
|
590
602
|
|
|
591
603
|
Options:
|
|
592
604
|
-p, --port <port> Port to listen on (default: 8080, or PORT env var)
|
|
593
|
-
-k, --kill [session] Kill a session (current if inside one, or specify)
|
|
605
|
+
-k, --kill [session] Kill a session (current if inside one, or specify by ID)
|
|
594
606
|
-v, --version Show version number
|
|
595
607
|
-h, --help Show this help message
|
|
596
608
|
|
|
597
609
|
Commands:
|
|
598
610
|
list List all ghosttown tmux sessions
|
|
599
|
-
attach <
|
|
611
|
+
attach <id> Attach to a ghosttown session by ID (e.g., 'gt attach 1')
|
|
600
612
|
detach Detach from current ghosttown session
|
|
601
613
|
update Update ghosttown to the latest version
|
|
602
|
-
<command> Run command in a new tmux session (
|
|
614
|
+
<command> Run command in a new tmux session (gt-<id>)
|
|
603
615
|
|
|
604
616
|
Examples:
|
|
605
617
|
ghosttown Start the web terminal server
|
|
606
618
|
ghosttown -p 3000 Start the server on port 3000
|
|
607
619
|
ghosttown list List all ghosttown sessions
|
|
608
|
-
ghosttown attach
|
|
620
|
+
ghosttown attach 1 Attach to session gt-1
|
|
609
621
|
ghosttown detach Detach from current session
|
|
610
622
|
ghosttown update Update to the latest version
|
|
611
623
|
ghosttown -k Kill current session (when inside one)
|
|
612
|
-
ghosttown -k
|
|
624
|
+
ghosttown -k 1 Kill session gt-1
|
|
613
625
|
ghosttown vim Run vim in a new tmux session
|
|
614
626
|
ghosttown "npm run dev" Run npm in a new tmux session
|
|
615
627
|
|
|
@@ -652,8 +664,8 @@ Aliases:
|
|
|
652
664
|
else if (arg === 'attach') {
|
|
653
665
|
const sessionArg = args[i + 1];
|
|
654
666
|
if (!sessionArg) {
|
|
655
|
-
console.error('Error: attach requires a session
|
|
656
|
-
console.error('Usage:
|
|
667
|
+
console.error('Error: attach requires a session ID');
|
|
668
|
+
console.error('Usage: gt attach <id>');
|
|
657
669
|
handled = true;
|
|
658
670
|
break;
|
|
659
671
|
}
|