peertable 0.8.19 → 0.8.21
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "peertable",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.21",
|
|
4
4
|
"description": "A round table of peer agents. No orchestrator at the head. Turn Claude Code, Codex, and Grok sessions into a team of equal, long-lived peers.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
package/room/client.mjs
CHANGED
|
@@ -13,7 +13,7 @@ import { findModelsDoc, resolveSeatIdentity } from '../skill/scripts/resolve-sea
|
|
|
13
13
|
|
|
14
14
|
// client.mjs 側のハードコード版数。package.json の version と一致していることを
|
|
15
15
|
// diagnostics の version_consistency が見る(2 つの版数源の drift 検出。決定45)
|
|
16
|
-
const MCP_VERSION = '0.8.
|
|
16
|
+
const MCP_VERSION = '0.8.21'
|
|
17
17
|
const PKG_ROOT = join(dirname(fileURLToPath(import.meta.url)), '..')
|
|
18
18
|
|
|
19
19
|
const USAGE = `usage:
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { readFileSync } from 'node:fs'
|
|
3
|
+
import { Client } from '@modelcontextprotocol/sdk/client/index.js'
|
|
4
|
+
import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js'
|
|
5
|
+
|
|
6
|
+
const [sessionId, promptFile] = process.argv.slice(2)
|
|
7
|
+
if (!sessionId || !promptFile) throw new Error('SEAT_AITERM_SEND_ARGS_INVALID')
|
|
8
|
+
const prompt = readFileSync(promptFile, 'utf8')
|
|
9
|
+
const client = new Client({ name: 'peertable-seat-send', version: '0.8.21' })
|
|
10
|
+
await client.connect(new StdioClientTransport({ command: 'aiterm-mcp', env: process.env }))
|
|
11
|
+
const result = await client.callTool({
|
|
12
|
+
name: 'pty_send',
|
|
13
|
+
arguments: { session_id: sessionId, text: prompt, enter: true },
|
|
14
|
+
})
|
|
15
|
+
await client.close()
|
|
16
|
+
if (result.isError) throw new Error(result.content?.[0]?.text || 'SEAT_AITERM_SEND_FAILED')
|
|
17
|
+
const receipt = result.structuredContent ?? JSON.parse(result.content?.[0]?.text ?? '{}')
|
|
18
|
+
if (receipt?.schema !== 'aiterm.pty-send-result.v1' || receipt.session_id !== sessionId
|
|
19
|
+
|| receipt.mode !== 'agent_dispatch' || receipt.submit_residue === true) {
|
|
20
|
+
throw new Error('SEAT_AITERM_SEND_RECEIPT_INVALID')
|
|
21
|
+
}
|
|
22
|
+
process.stdout.write(`${JSON.stringify(receipt)}\n`)
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { resolve } from 'node:path'
|
|
3
|
+
import { fileURLToPath } from 'node:url'
|
|
4
|
+
|
|
5
|
+
export function keysForClaudeMcpPane(screen) {
|
|
6
|
+
const text = String(screen ?? '')
|
|
7
|
+
if (text.includes('New MCP server found in this project: room')) {
|
|
8
|
+
return { kind: 'single-mcp-consent', keys: ['Down', 'Enter'] }
|
|
9
|
+
}
|
|
10
|
+
if (/new MCP servers found in this project/iu.test(text) && text.includes('Enable selected')) {
|
|
11
|
+
const selected = text.split(/\r?\n/u).filter(line => /\[✔\]/u.test(line))
|
|
12
|
+
if (!selected.some(line => /\broom\b/u.test(line))) return null
|
|
13
|
+
return { kind: 'multi-mcp-consent', keys: [...selected.map(() => 'Down'), 'Enter'] }
|
|
14
|
+
}
|
|
15
|
+
return null
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const isMain = Boolean(process.argv[1]) && resolve(process.argv[1]) === fileURLToPath(import.meta.url)
|
|
19
|
+
if (isMain) {
|
|
20
|
+
const chunks = []
|
|
21
|
+
for await (const chunk of process.stdin) chunks.push(chunk)
|
|
22
|
+
process.stdout.write(`${JSON.stringify(keysForClaudeMcpPane(Buffer.concat(chunks).toString('utf8')))}\n`)
|
|
23
|
+
}
|
|
@@ -474,6 +474,7 @@ codex_update_accepted=false
|
|
|
474
474
|
codex_trust_accepted=false
|
|
475
475
|
claude_trust_accepted=false
|
|
476
476
|
codex_dialog_helper="$peertable_script_dir/codex-dialog.mjs"
|
|
477
|
+
claude_dialog_helper="$peertable_script_dir/claude-dialog.mjs"
|
|
477
478
|
pass_codex_pane() {
|
|
478
479
|
local json key
|
|
479
480
|
json=$(printf '%s' "$1" | node "$codex_dialog_helper" || true)
|
|
@@ -481,6 +482,7 @@ pass_codex_pane() {
|
|
|
481
482
|
while IFS= read -r key; do
|
|
482
483
|
[ -n "$key" ] || continue
|
|
483
484
|
tmux_at send-keys -t "$sess" "$key" || return 1
|
|
485
|
+
sleep .3
|
|
484
486
|
done < <(python3 -c 'import json,sys
|
|
485
487
|
a=json.loads(sys.stdin.read() or "null")
|
|
486
488
|
print("\n".join(a.get("keys") or []) if isinstance(a, dict) else "")' <<<"$json")
|
|
@@ -489,6 +491,18 @@ print("\n".join(a.get("keys") or []) if isinstance(a, dict) else "")' <<<"$json"
|
|
|
489
491
|
codex_pane_blocks_ready() {
|
|
490
492
|
printf '%s' "$1" | node "$codex_dialog_helper" --ready-ok
|
|
491
493
|
}
|
|
494
|
+
pass_claude_mcp_pane() {
|
|
495
|
+
local json key
|
|
496
|
+
json=$(printf '%s' "$1" | node "$claude_dialog_helper" || true)
|
|
497
|
+
[ -n "$json" ] && [ "$json" != "null" ] || return 1
|
|
498
|
+
while IFS= read -r key; do
|
|
499
|
+
[ -n "$key" ] || continue
|
|
500
|
+
tmux_at send-keys -t "$sess" "$key" || return 1
|
|
501
|
+
done < <(python3 -c 'import json,sys
|
|
502
|
+
a=json.loads(sys.stdin.read() or "null")
|
|
503
|
+
print("\n".join(a.get("keys") or []) if isinstance(a, dict) else "")' <<<"$json")
|
|
504
|
+
return 0
|
|
505
|
+
}
|
|
492
506
|
while [ $SECONDS -lt "$room_ready_deadline" ]; do
|
|
493
507
|
# Grok Build は初めて開く作業treeで、room MCPを初期化する前にworkspace trustを尋ねる。
|
|
494
508
|
# Peertableが正式に着席させるtreeなので、この既知文言だけを一度通す。未知の確認画面を
|
|
@@ -551,17 +565,11 @@ while [ $SECONDS -lt "$room_ready_deadline" ]; do
|
|
|
551
565
|
# 同意が member 登録より前に出る。選択肢2(this and all future)だけを通す。
|
|
552
566
|
if [ "$harness" = claude ] && [ "$mcp_consent_accepted" != true ]; then
|
|
553
567
|
claude_screen=$(tmux_at capture-pane -t "$sess" -p 2>/dev/null || true)
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
fi
|
|
560
|
-
mcp_consent_accepted=true
|
|
561
|
-
room_ready_deadline=$((SECONDS + 90))
|
|
562
|
-
echo "claude room MCP consent: accepted"
|
|
563
|
-
;;
|
|
564
|
-
esac
|
|
568
|
+
if pass_claude_mcp_pane "$claude_screen"; then
|
|
569
|
+
mcp_consent_accepted=true
|
|
570
|
+
room_ready_deadline=$((SECONDS + 90))
|
|
571
|
+
echo "claude room MCP consent: accepted"
|
|
572
|
+
fi
|
|
565
573
|
fi
|
|
566
574
|
room_members=$(curl -sf "$url/api/$room/members" 2>/dev/null || true)
|
|
567
575
|
if printf '%s' "$room_members" | python3 -c 'import json,sys; name=sys.argv[1]; members=json.load(sys.stdin).get("members",[]); raise SystemExit(0 if any(m.get("name") == name for m in members) else 1)' "$name"; then
|
|
@@ -608,6 +616,15 @@ if [ "$brief_dispatched" = true ]; then
|
|
|
608
616
|
fi
|
|
609
617
|
|
|
610
618
|
if [ -n "$brief" ] && [ "$brief_dispatched" != true ]; then
|
|
619
|
+
if [ "$brief_in_composer" != true ]; then
|
|
620
|
+
if node "$peertable_script_dir/aiterm-send.mjs" "$sess" "$brief_file" >/dev/null; then
|
|
621
|
+
brief_completed=true
|
|
622
|
+
echo "briefed: $sess(Aiterm pty_send)"
|
|
623
|
+
else
|
|
624
|
+
echo "LAUNCH_BRIEF_SEND_FAILED: Aiterm pty_sendでbriefをdispatchできない" >&2
|
|
625
|
+
exit 1
|
|
626
|
+
fi
|
|
627
|
+
else
|
|
611
628
|
# Codex はヘッダを描いた後も MCP 初期化を続ける。Aiterm の ready 契約に合わせ、
|
|
612
629
|
# 同じ可視 pane 内に入力候補行とモデルフッタがある構造を連続して観測する。
|
|
613
630
|
# hook / MCP warning の更新で画面全体が変わっても、入力欄周辺が ready なら通す。
|
|
@@ -675,6 +692,7 @@ if [ -n "$brief" ] && [ "$brief_dispatched" != true ]; then
|
|
|
675
692
|
fi
|
|
676
693
|
brief_completed=true
|
|
677
694
|
echo "briefed: $sess"
|
|
695
|
+
fi
|
|
678
696
|
fi
|
|
679
697
|
fi
|
|
680
698
|
|