thinkpool-pair 0.1.0 → 0.2.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 +66 -3
- package/package.json +3 -3
package/bridge.mjs
CHANGED
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
thinkpool-pair — share your local Claude (or any CLI) into a
|
|
4
4
|
ThinkPool Code room, live. ONE command, seamless:
|
|
5
5
|
|
|
6
|
-
npx thinkpool-pair <ROOM> #
|
|
7
|
-
npx thinkpool-pair <ROOM> -- <cmd…> # share
|
|
6
|
+
npx thinkpool-pair <ROOM> # auto-detects your agents, pick one
|
|
7
|
+
npx thinkpool-pair <ROOM> -- <cmd…> # share a specific CLI (skip the picker)
|
|
8
8
|
|
|
9
9
|
It spawns the CLI in a PTY so you use it exactly like your normal
|
|
10
10
|
terminal — and every byte streams to the room over Supabase realtime
|
|
@@ -14,6 +14,9 @@
|
|
|
14
14
|
───────────────────────────────────────────────────────────── */
|
|
15
15
|
|
|
16
16
|
import os from 'node:os'
|
|
17
|
+
import fs from 'node:fs'
|
|
18
|
+
import path from 'node:path'
|
|
19
|
+
import readline from 'node:readline'
|
|
17
20
|
import { createClient } from '@supabase/supabase-js'
|
|
18
21
|
|
|
19
22
|
// Public client creds (the same anon values the web app ships — safe to embed).
|
|
@@ -30,11 +33,71 @@ catch {
|
|
|
30
33
|
process.exit(1)
|
|
31
34
|
}
|
|
32
35
|
|
|
36
|
+
// ── Known coding-agent CLIs we feature in the picker ──────────────
|
|
37
|
+
// Order = display order; Claude Code stays first (the original default). The
|
|
38
|
+
// picker only offers the ones actually installed (PATH probe below). Power
|
|
39
|
+
// users can bypass it entirely with `-- <any command>`.
|
|
40
|
+
const KNOWN_AGENTS = [
|
|
41
|
+
{ label: 'Claude Code', cmd: 'claude' },
|
|
42
|
+
{ label: 'Codex CLI', cmd: 'codex' },
|
|
43
|
+
{ label: 'Gemini CLI', cmd: 'gemini' },
|
|
44
|
+
{ label: 'Aider', cmd: 'aider' },
|
|
45
|
+
{ label: 'Cursor CLI', cmd: 'cursor-agent' },
|
|
46
|
+
{ label: 'opencode', cmd: 'opencode' },
|
|
47
|
+
{ label: 'Copilot CLI', cmd: 'copilot' },
|
|
48
|
+
{ label: 'Goose', cmd: 'goose' },
|
|
49
|
+
{ label: 'Crush', cmd: 'crush' },
|
|
50
|
+
{ label: 'Qwen Code', cmd: 'qwen' },
|
|
51
|
+
]
|
|
52
|
+
|
|
53
|
+
// Is `c` on PATH? Pure-Node scan (no `which` subprocess), cross-platform.
|
|
54
|
+
const onPath = (c) => {
|
|
55
|
+
const exts = process.platform === 'win32'
|
|
56
|
+
? (process.env.PATHEXT || '.EXE;.CMD;.BAT;.COM').split(';')
|
|
57
|
+
: ['']
|
|
58
|
+
for (const dir of (process.env.PATH || '').split(path.delimiter)) {
|
|
59
|
+
if (!dir) continue
|
|
60
|
+
for (const ext of exts) {
|
|
61
|
+
try { if (fs.existsSync(path.join(dir, c + ext))) return true } catch { /* noop */ }
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return false
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Pick which installed agent to share → resolves to a command string. A single
|
|
68
|
+
// match (or non-TTY stdin, e.g. piped) auto-selects with no prompt.
|
|
69
|
+
const pickAgent = (installed) => new Promise((resolve) => {
|
|
70
|
+
if (installed.length === 1 || !process.stdin.isTTY) { resolve(installed[0].cmd); return }
|
|
71
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stderr })
|
|
72
|
+
process.stderr.write('\n Which coding agent do you want to share?\n\n')
|
|
73
|
+
installed.forEach((a, i) => process.stderr.write(` ${i + 1}) ${a.label}\n`))
|
|
74
|
+
process.stderr.write('\n')
|
|
75
|
+
rl.question(' Pick a number [1]: ', (ans) => {
|
|
76
|
+
rl.close()
|
|
77
|
+
const n = parseInt(String(ans).trim(), 10)
|
|
78
|
+
const idx = Number.isInteger(n) && n >= 1 && n <= installed.length ? n - 1 : 0
|
|
79
|
+
resolve(installed[idx].cmd)
|
|
80
|
+
})
|
|
81
|
+
})
|
|
82
|
+
|
|
33
83
|
const argv = process.argv.slice(2)
|
|
34
84
|
const room = (argv[0] || '').toUpperCase().trim()
|
|
35
85
|
if (!room) { console.error('usage: npx thinkpool-pair <ROOM> [-- <command…>]'); process.exit(1) }
|
|
36
86
|
const dashIdx = argv.indexOf('--')
|
|
37
|
-
|
|
87
|
+
let cmd, cmdArgs
|
|
88
|
+
if (dashIdx >= 0) {
|
|
89
|
+
// Explicit override: `-- <cmd> [args…]` skips the picker.
|
|
90
|
+
;[cmd, ...cmdArgs] = argv.slice(dashIdx + 1)
|
|
91
|
+
} else {
|
|
92
|
+
// Auto-detect: probe the known agents, then pick (or auto-pick a lone match).
|
|
93
|
+
const installed = KNOWN_AGENTS.filter(a => onPath(a.cmd))
|
|
94
|
+
if (installed.length === 0) {
|
|
95
|
+
console.error(`\n No known coding-agent CLI found on your PATH.\n Install one (claude / codex / gemini / aider / cursor-agent / opencode …)\n or share a specific command: npx thinkpool-pair ${room} -- <your-command>\n`)
|
|
96
|
+
process.exit(1)
|
|
97
|
+
}
|
|
98
|
+
cmd = await pickAgent(installed)
|
|
99
|
+
cmdArgs = []
|
|
100
|
+
}
|
|
38
101
|
const name = process.env.TP_NAME || os.userInfo().username || 'host'
|
|
39
102
|
|
|
40
103
|
const supabase = createClient(SUPABASE_URL, SUPABASE_ANON, {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "thinkpool-pair",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Share
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "Share a local coding-agent CLI (Claude Code, Codex, Gemini, Aider, …) into a ThinkPool Code room, live.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": "bridge.mjs",
|
|
7
7
|
"engines": {
|
|
@@ -9,6 +9,6 @@
|
|
|
9
9
|
},
|
|
10
10
|
"dependencies": {
|
|
11
11
|
"@supabase/supabase-js": "^2.45.0",
|
|
12
|
-
"node-pty": "^1.0.
|
|
12
|
+
"node-pty": "^1.2.0-beta.13"
|
|
13
13
|
}
|
|
14
14
|
}
|