claude-term-tabs 2.1.3 → 2.1.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.
- package/README.md +1 -1
- package/dist/pause/ui.js +21 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
Find a running Claude Code session by what you remember about it, and switch to its terminal tab.
|
|
8
8
|
|
|
9
|
-

|
|
10
10
|
|
|
11
11
|
```bash
|
|
12
12
|
ctt working on pause in claude-term-tabs
|
package/dist/pause/ui.js
CHANGED
|
@@ -4,7 +4,7 @@ import { mkdtempSync, rmSync } from 'node:fs';
|
|
|
4
4
|
import { tmpdir } from 'node:os';
|
|
5
5
|
import { join } from 'node:path';
|
|
6
6
|
import { writeOwnerOnly } from "../fsutil.js";
|
|
7
|
-
import { createServer } from 'node:net';
|
|
7
|
+
import { connect, createServer } from 'node:net';
|
|
8
8
|
import { createInterface } from 'node:readline';
|
|
9
9
|
import { tickPause, stragglerLines } from "./run.js";
|
|
10
10
|
import { FINAL_STATES } from "./state.js";
|
|
@@ -12,6 +12,7 @@ import { shellQuote } from "../shell.js";
|
|
|
12
12
|
/** How often the straggler list refreshes. */
|
|
13
13
|
export const POLL_MS = 3000;
|
|
14
14
|
const CLEAR = '\x1b[2J\x1b[H';
|
|
15
|
+
const LISTEN_WAIT_MS = 2000;
|
|
15
16
|
const SAFE_PATH = /^[A-Za-z0-9._\/-]+$/;
|
|
16
17
|
const HEADER = 'ctt pause: Enter or double-click jumps to a session · ctrl-r re-sends the stop prompt · Esc stops waiting';
|
|
17
18
|
/** fzf arguments for the live straggler list; `self` is the argv prefix that re-invokes ctt. */
|
|
@@ -105,7 +106,9 @@ async function fzfUi(io, initial) {
|
|
|
105
106
|
child.on('exit', () => { exited = true; });
|
|
106
107
|
child.on('error', () => { exited = true; });
|
|
107
108
|
child.stdin.end(initial.join('\n'));
|
|
108
|
-
|
|
109
|
+
await listening(port, () => exited);
|
|
110
|
+
// `abort` closes fzf, which often exits before it answers, so its failure is expected.
|
|
111
|
+
const post = async (action, closing = false) => {
|
|
109
112
|
if (exited)
|
|
110
113
|
return;
|
|
111
114
|
try {
|
|
@@ -114,7 +117,7 @@ async function fzfUi(io, initial) {
|
|
|
114
117
|
process.stderr.write(`claude-term-tabs: the list refused an update (${res.status})\n`);
|
|
115
118
|
}
|
|
116
119
|
catch (err) {
|
|
117
|
-
if (!exited)
|
|
120
|
+
if (!exited && !closing)
|
|
118
121
|
process.stderr.write(`claude-term-tabs: could not update the list: ${err.message}\n`);
|
|
119
122
|
}
|
|
120
123
|
};
|
|
@@ -124,7 +127,7 @@ async function fzfUi(io, initial) {
|
|
|
124
127
|
await post(reloadAction(linesFile));
|
|
125
128
|
},
|
|
126
129
|
finish: async () => {
|
|
127
|
-
await post('abort');
|
|
130
|
+
await post('abort', true);
|
|
128
131
|
if (!exited)
|
|
129
132
|
await new Promise(resolve => child.once('exit', () => resolve()));
|
|
130
133
|
rmSync(dir, { recursive: true, force: true });
|
|
@@ -132,6 +135,20 @@ async function fzfUi(io, initial) {
|
|
|
132
135
|
closed: () => exited
|
|
133
136
|
};
|
|
134
137
|
}
|
|
138
|
+
/** Resolves once fzf accepts connections on `port`, it has exited, or LISTEN_WAIT_MS has passed. */
|
|
139
|
+
async function listening(port, gone) {
|
|
140
|
+
const deadline = Date.now() + LISTEN_WAIT_MS;
|
|
141
|
+
while (!gone() && Date.now() < deadline) {
|
|
142
|
+
const up = await new Promise(resolve => {
|
|
143
|
+
const socket = connect(port, '127.0.0.1');
|
|
144
|
+
socket.once('connect', () => { socket.destroy(); resolve(true); });
|
|
145
|
+
socket.once('error', () => { resolve(false); });
|
|
146
|
+
});
|
|
147
|
+
if (up)
|
|
148
|
+
return;
|
|
149
|
+
await new Promise(resolve => setTimeout(resolve, 50));
|
|
150
|
+
}
|
|
151
|
+
}
|
|
135
152
|
function freePort() {
|
|
136
153
|
return new Promise((resolve, reject) => {
|
|
137
154
|
const server = createServer();
|