thinkpool-pair 0.4.0 → 0.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/bridge.mjs +50 -4
- package/package.json +1 -1
package/bridge.mjs
CHANGED
|
@@ -7,6 +7,14 @@
|
|
|
7
7
|
npx thinkpool-pair <ROOM> -- <cmd…> # share a specific CLI (skip the picker)
|
|
8
8
|
npx thinkpool-pair <ROOM> --headless # pure relay — terminals open from the web
|
|
9
9
|
|
|
10
|
+
v0.5 — continue, don't restart: when the picked agent supports
|
|
11
|
+
resuming (Claude Code: `--continue` = most recent conversation in
|
|
12
|
+
THIS directory) and a prior session exists here, the bridge offers to
|
|
13
|
+
continue it instead of starting fresh — quit your running agent, run
|
|
14
|
+
the bridge in the same directory, and you're back in the same
|
|
15
|
+
conversation, now shared. `--continue` / `--fresh` skip the question.
|
|
16
|
+
(True attach to a live process was ruled out: reptyr-style TTY
|
|
17
|
+
hijacking is Linux-only and SIP-blocked on macOS.)
|
|
10
18
|
v0.4 — room file drops: files dropped/pasted in the web room download
|
|
11
19
|
to a temp dir here (file-put → file-done) so the agent can read them.
|
|
12
20
|
v0.3 — multi-terminal. The bridge is your machine's presence in the
|
|
@@ -49,8 +57,12 @@ catch {
|
|
|
49
57
|
// Order = display order; Claude Code stays first (the original default). The
|
|
50
58
|
// picker only offers the ones actually installed (PATH probe below). Power
|
|
51
59
|
// users can bypass it entirely with `-- <any command>`.
|
|
60
|
+
// `resume` marks agents where continuing the latest session is a SAFE,
|
|
61
|
+
// verified flag (wrong flags kill the spawn → bridge exits — only add
|
|
62
|
+
// agents after checking the real CLI). probe() must be cheap + read-only;
|
|
63
|
+
// a miss just means "continue" isn't offered.
|
|
52
64
|
const KNOWN_AGENTS = [
|
|
53
|
-
{ label: 'Claude Code', cmd: 'claude' },
|
|
65
|
+
{ label: 'Claude Code', cmd: 'claude', resume: { args: ['--continue'], probe: claudeHasSession } },
|
|
54
66
|
{ label: 'Codex CLI', cmd: 'codex' },
|
|
55
67
|
{ label: 'Gemini CLI', cmd: 'gemini' },
|
|
56
68
|
{ label: 'Aider', cmd: 'aider' },
|
|
@@ -62,6 +74,16 @@ const KNOWN_AGENTS = [
|
|
|
62
74
|
{ label: 'Qwen Code', cmd: 'qwen' },
|
|
63
75
|
]
|
|
64
76
|
|
|
77
|
+
// Does Claude Code have a resumable conversation for THIS directory?
|
|
78
|
+
// Sessions live under ~/.claude/projects/<cwd with [/\.:] → '-'> (one
|
|
79
|
+
// subdir per session). Read-only probe; any miss = no "continue" offer.
|
|
80
|
+
function claudeHasSession() {
|
|
81
|
+
try {
|
|
82
|
+
const slug = path.resolve(process.cwd()).replace(/[/\\.:]/g, '-')
|
|
83
|
+
return fs.readdirSync(path.join(os.homedir(), '.claude', 'projects', slug)).length > 0
|
|
84
|
+
} catch { return false }
|
|
85
|
+
}
|
|
86
|
+
|
|
65
87
|
// Is `c` on PATH? Pure-Node scan (no `which` subprocess), cross-platform.
|
|
66
88
|
const onPath = (c) => {
|
|
67
89
|
const exts = process.platform === 'win32'
|
|
@@ -94,11 +116,23 @@ const pickAgent = (installed) => new Promise((resolve) => {
|
|
|
94
116
|
|
|
95
117
|
const argv = process.argv.slice(2)
|
|
96
118
|
const room = (argv[0] || '').toUpperCase().trim()
|
|
97
|
-
if (!room || room.startsWith('-')) { console.error('usage: npx thinkpool-pair <ROOM> [--headless] [-- <command…>]'); process.exit(1) }
|
|
119
|
+
if (!room || room.startsWith('-')) { console.error('usage: npx thinkpool-pair <ROOM> [--headless] [--continue|--fresh] [-- <command…>]'); process.exit(1) }
|
|
98
120
|
const headless = argv.includes('--headless')
|
|
99
121
|
const installedAgents = KNOWN_AGENTS.filter(a => onPath(a.cmd))
|
|
100
122
|
const dashIdx = argv.indexOf('--')
|
|
101
|
-
|
|
123
|
+
// Own flags are only read from BEFORE `--`; after it, every token belongs
|
|
124
|
+
// to the shared command (`-- claude --continue` must not trip these).
|
|
125
|
+
const ownArgs = dashIdx >= 0 ? argv.slice(0, dashIdx) : argv
|
|
126
|
+
const forceContinue = ownArgs.includes('--continue')
|
|
127
|
+
const forceFresh = ownArgs.includes('--fresh')
|
|
128
|
+
|
|
129
|
+
// One yes/no on the bridge's stderr (same channel as the agent picker).
|
|
130
|
+
const askYesNo = (q) => new Promise((resolve) => {
|
|
131
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stderr })
|
|
132
|
+
rl.question(q, (ans) => { rl.close(); resolve(!/^n/i.test(String(ans).trim())) })
|
|
133
|
+
})
|
|
134
|
+
|
|
135
|
+
let attachedCmd = null, attachedArgs = [], continuing = false
|
|
102
136
|
if (dashIdx >= 0) {
|
|
103
137
|
;[attachedCmd, ...attachedArgs] = argv.slice(dashIdx + 1)
|
|
104
138
|
} else if (!headless) {
|
|
@@ -107,6 +141,18 @@ if (dashIdx >= 0) {
|
|
|
107
141
|
process.exit(1)
|
|
108
142
|
}
|
|
109
143
|
attachedCmd = await pickAgent(installedAgents)
|
|
144
|
+
// Continue the latest session instead of starting fresh — offered only
|
|
145
|
+
// when the agent supports it AND a prior session exists in this cwd.
|
|
146
|
+
// --continue forces it (your call even if the probe misses); --fresh
|
|
147
|
+
// skips the question; non-TTY stays fresh (no surprise in scripts).
|
|
148
|
+
const agent = KNOWN_AGENTS.find(a => a.cmd === attachedCmd)
|
|
149
|
+
if (agent?.resume && !forceFresh) {
|
|
150
|
+
if (forceContinue) continuing = true
|
|
151
|
+
else if (process.stdin.isTTY && agent.resume.probe()) {
|
|
152
|
+
continuing = await askYesNo(`\n Continue your latest ${agent.label} session in this directory? [Y/n] `)
|
|
153
|
+
}
|
|
154
|
+
if (continuing) attachedArgs = [...agent.resume.args]
|
|
155
|
+
}
|
|
110
156
|
}
|
|
111
157
|
const name = process.env.TP_NAME || os.userInfo().username || 'host'
|
|
112
158
|
|
|
@@ -326,7 +372,7 @@ channel
|
|
|
326
372
|
announce()
|
|
327
373
|
process.stderr.write(headless
|
|
328
374
|
? `\n ◆ thinkpool — relaying room ${room} (headless). Open terminals from the web UI.\n\n`
|
|
329
|
-
: `\n ◆ thinkpool — sharing "${attachedCmd}" into room ${room}. Open the web UI and you're both in.\n\n`)
|
|
375
|
+
: `\n ◆ thinkpool — sharing "${attachedCmd}"${continuing ? ' (continuing your latest session)' : ''} into room ${room}. Open the web UI and you're both in.\n\n`)
|
|
330
376
|
}
|
|
331
377
|
})
|
|
332
378
|
|
package/package.json
CHANGED