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.
Files changed (2) hide show
  1. package/bridge.mjs +66 -3
  2. 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> # launches `claude`, shared
7
- npx thinkpool-pair <ROOM> -- <cmd…> # share any other CLI
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
- const [cmd, ...cmdArgs] = dashIdx >= 0 ? argv.slice(dashIdx + 1) : ['claude']
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.1.0",
4
- "description": "Share your local Claude (or any CLI) into a ThinkPool Code room, live.",
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.0"
12
+ "node-pty": "^1.2.0-beta.13"
13
13
  }
14
14
  }