thinkpool-pair 0.6.9 → 0.6.11
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 +3 -0
- package/bridge.mjs +10 -3
- package/package.json +4 -2
- package/service.mjs +19 -8
package/README.md
CHANGED
|
@@ -35,6 +35,9 @@ The bridge self-heals at three levels — all cross-platform (macOS / Linux / Wi
|
|
|
35
35
|
npx thinkpool-pair install-service <ROOM> -- claude # set and forget
|
|
36
36
|
npx thinkpool-pair uninstall-service <ROOM> # remove it
|
|
37
37
|
```
|
|
38
|
+
The service runs `npx thinkpool-pair@latest`, so it **auto-updates** — new
|
|
39
|
+
versions apply on the next restart, no re-install. (Linux: run
|
|
40
|
+
`loginctl enable-linger $USER` once to keep it running after logout.)
|
|
38
41
|
- **Watchdog** — if the realtime channel wedges for >60s, the bridge exits so the
|
|
39
42
|
supervisor/service restarts a clean process. Brief network blips reconnect on
|
|
40
43
|
their own.
|
package/bridge.mjs
CHANGED
|
@@ -49,11 +49,13 @@ const SCROLLBACK_MAX = 120_000
|
|
|
49
49
|
|
|
50
50
|
// node-pty is a native module — loaded lazily so a friendly message shows
|
|
51
51
|
// if it isn't built yet.
|
|
52
|
-
|
|
52
|
+
// Structured Claude (the default) runs through the Agent SDK and needs NO PTY,
|
|
53
|
+
// so a failed node-pty build must not block the bridge — it only disables the
|
|
54
|
+
// raw-PTY path (other CLIs / TP_PTY=1), which we flag clearly if it's used.
|
|
55
|
+
let pty = null
|
|
53
56
|
try { pty = (await import('node-pty')).default ?? (await import('node-pty')) }
|
|
54
57
|
catch {
|
|
55
|
-
console.error('\n node-pty
|
|
56
|
-
process.exit(1)
|
|
58
|
+
console.error('\n ⚠ node-pty not built — raw terminal sharing is off (structured Claude still works).\n For PTY mode (bash / aider / codex / TP_PTY=1): install a C toolchain, then `npm i` in the bridge.\n (Xcode CLT on mac · build-essential on linux · VS Build Tools on Windows.)\n')
|
|
57
59
|
}
|
|
58
60
|
|
|
59
61
|
// ── Known coding-agent CLIs we feature in the picker ──────────────
|
|
@@ -325,6 +327,11 @@ const attachedDims = () => ({
|
|
|
325
327
|
|
|
326
328
|
function openTerm({ id, cmd, args = [], attached = false, cols, rows }) {
|
|
327
329
|
if (terms.has(id)) return
|
|
330
|
+
if (!pty) { // raw-PTY path needs node-pty; structured Claude never lands here
|
|
331
|
+
process.stderr.write(`\n ⚠ can't open "${cmd}" — node-pty isn't built (PTY mode disabled).\n`)
|
|
332
|
+
bcast('term-exit', { id })
|
|
333
|
+
return
|
|
334
|
+
}
|
|
328
335
|
const ad = attached ? attachedDims() : null
|
|
329
336
|
const term = pty.spawn(cmd, args, {
|
|
330
337
|
name: 'xterm-256color',
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "thinkpool-pair",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.11",
|
|
4
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": {
|
|
@@ -21,7 +21,9 @@
|
|
|
21
21
|
},
|
|
22
22
|
"dependencies": {
|
|
23
23
|
"@anthropic-ai/claude-agent-sdk": "^0.3.173",
|
|
24
|
-
"@supabase/supabase-js": "^2.45.0"
|
|
24
|
+
"@supabase/supabase-js": "^2.45.0"
|
|
25
|
+
},
|
|
26
|
+
"optionalDependencies": {
|
|
25
27
|
"node-pty": "^1.2.0-beta.13"
|
|
26
28
|
}
|
|
27
29
|
}
|
package/service.mjs
CHANGED
|
@@ -12,24 +12,34 @@
|
|
|
12
12
|
import os from 'node:os'
|
|
13
13
|
import fs from 'node:fs'
|
|
14
14
|
import path from 'node:path'
|
|
15
|
-
import { fileURLToPath } from 'node:url'
|
|
16
15
|
import { execSync } from 'node:child_process'
|
|
17
16
|
|
|
18
|
-
const BRIDGE = fileURLToPath(new URL('./bridge.mjs', import.meta.url))
|
|
19
17
|
const label = (room) => `io.thinkpool.pair.${room.toLowerCase()}`
|
|
20
18
|
const xml = (s) => String(s).replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>')
|
|
21
19
|
|
|
20
|
+
// Resolve the real npx next to the current node, so the service stays seamless:
|
|
21
|
+
// it runs `npx -y thinkpool-pair@latest …`, always picking up the newest publish
|
|
22
|
+
// with no re-install. Absolute path + injected PATH so it works under launchd /
|
|
23
|
+
// systemd's bare environment (which don't search PATH for argv[0]).
|
|
24
|
+
function npxPath(platform) {
|
|
25
|
+
const bin = path.dirname(process.execPath)
|
|
26
|
+
const cand = path.join(bin, platform === 'win32' ? 'npx.cmd' : 'npx')
|
|
27
|
+
try { fs.accessSync(cand); return cand } catch { return platform === 'win32' ? 'npx.cmd' : 'npx' }
|
|
28
|
+
}
|
|
29
|
+
|
|
22
30
|
// Pure artifact builder — returned shape is testable without side effects.
|
|
23
|
-
// `mode:'service'` lets the OS supervise (no --supervise); 'supervise' wraps it.
|
|
24
31
|
export function buildArtifact(platform, { room, cmdArgs = [] }) {
|
|
25
|
-
const
|
|
32
|
+
const npx = npxPath(platform)
|
|
26
33
|
const cwd = process.cwd()
|
|
27
34
|
const logDir = path.join(os.homedir(), '.thinkpool-pair')
|
|
28
35
|
const log = path.join(logDir, `${room}.log`)
|
|
29
36
|
const tail = cmdArgs.length ? ['--', ...cmdArgs] : []
|
|
37
|
+
// OS-supervised tiers (launchd KeepAlive / systemd Restart) don't need
|
|
38
|
+
// --supervise; the latest published bridge is fetched by npx each (re)start.
|
|
39
|
+
const pkgArgs = ['-y', 'thinkpool-pair@latest', room]
|
|
30
40
|
|
|
31
41
|
if (platform === 'darwin') {
|
|
32
|
-
const args = [
|
|
42
|
+
const args = [npx, ...pkgArgs, ...tail] // launchd KeepAlive supervises
|
|
33
43
|
const file = path.join(os.homedir(), 'Library', 'LaunchAgents', `${label(room)}.plist`)
|
|
34
44
|
const content = `<?xml version="1.0" encoding="UTF-8"?>
|
|
35
45
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
@@ -47,7 +57,7 @@ export function buildArtifact(platform, { room, cmdArgs = [] }) {
|
|
|
47
57
|
}
|
|
48
58
|
|
|
49
59
|
if (platform === 'linux') {
|
|
50
|
-
const args = [
|
|
60
|
+
const args = [npx, ...pkgArgs, ...tail] // systemd Restart=always supervises
|
|
51
61
|
const file = path.join(os.homedir(), '.config', 'systemd', 'user', `${label(room)}.service`)
|
|
52
62
|
const content = `[Unit]
|
|
53
63
|
Description=ThinkPool Code bridge (${room})
|
|
@@ -73,7 +83,8 @@ WantedBy=default.target
|
|
|
73
83
|
// running --supervise gives login-persistence + crash-restart, dependency-free.
|
|
74
84
|
const startup = path.join(process.env.APPDATA || path.join(os.homedir(), 'AppData', 'Roaming'), 'Microsoft', 'Windows', 'Start Menu', 'Programs', 'Startup')
|
|
75
85
|
const file = path.join(startup, `thinkpool-pair-${room}.cmd`)
|
|
76
|
-
|
|
86
|
+
// Startup folder isn't a supervisor → keep --supervise for crash-restart.
|
|
87
|
+
const inner = ['npx', '-y', 'thinkpool-pair@latest', room, '--supervise', ...tail].join(' ')
|
|
77
88
|
const content = `@echo off\r\ntitle thinkpool-pair ${room}\r\n${inner}\r\n`
|
|
78
89
|
return { file, content, logDir, post: [], note: 'Installed to the Startup folder — runs at login with --supervise (auto-restart on crash). Start it now without rebooting by double-clicking the .cmd, or run it from a terminal.' }
|
|
79
90
|
}
|
|
@@ -90,7 +101,7 @@ export function installService(room, cmdArgs = []) {
|
|
|
90
101
|
for (const cmd of a.post) {
|
|
91
102
|
try { execSync(cmd, { stdio: 'inherit' }) } catch (e) { process.stderr.write(` ⚠ "${cmd}" failed: ${e.message}\n`) }
|
|
92
103
|
}
|
|
93
|
-
process.stderr.write(` ◆ ${a.note}\n ◆ logs: ${path.join(a.logDir, `${room}.log`)}\n ◆ remove with: thinkpool-pair uninstall-service ${room}\n\n`)
|
|
104
|
+
process.stderr.write(` ◆ ${a.note}\n ◆ tracks thinkpool-pair@latest — new versions apply on next restart, no re-install.\n ◆ logs: ${path.join(a.logDir, `${room}.log`)}\n ◆ remove with: thinkpool-pair uninstall-service ${room}\n\n`)
|
|
94
105
|
}
|
|
95
106
|
|
|
96
107
|
export function uninstallService(room) {
|