peertable 0.8.21 → 0.8.23

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.21",
3
+ "version": "0.8.23",
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.21'
16
+ const MCP_VERSION = '0.8.23'
17
17
  const PKG_ROOT = join(dirname(fileURLToPath(import.meta.url)), '..')
18
18
 
19
19
  const USAGE = `usage:
@@ -19,5 +19,8 @@ const isMain = Boolean(process.argv[1]) && resolve(process.argv[1]) === fileURLT
19
19
  if (isMain) {
20
20
  const chunks = []
21
21
  for await (const chunk of process.stdin) chunks.push(chunk)
22
- process.stdout.write(`${JSON.stringify(keysForClaudeMcpPane(Buffer.concat(chunks).toString('utf8')))}\n`)
22
+ const action = keysForClaudeMcpPane(Buffer.concat(chunks).toString('utf8'))
23
+ if (process.argv.includes('--keys')) {
24
+ if (action) process.stdout.write(`${action.keys.join('\n')}\n`)
25
+ } else process.stdout.write(`${JSON.stringify(action)}\n`)
23
26
  }
@@ -42,5 +42,9 @@ if (isMain) {
42
42
  if (process.argv.includes('--ready-ok')) {
43
43
  process.exit(blocksCodexReady(screen) ? 2 : 0)
44
44
  }
45
+ if (process.argv.includes('--keys')) {
46
+ if (action) process.stdout.write(`${action.keys.join('\n')}\n`)
47
+ process.exit(0)
48
+ }
45
49
  process.stdout.write(`${JSON.stringify(action)}\n`)
46
50
  }
@@ -476,31 +476,29 @@ claude_trust_accepted=false
476
476
  codex_dialog_helper="$peertable_script_dir/codex-dialog.mjs"
477
477
  claude_dialog_helper="$peertable_script_dir/claude-dialog.mjs"
478
478
  pass_codex_pane() {
479
- local json key
480
- json=$(printf '%s' "$1" | node "$codex_dialog_helper" || true)
481
- [ -n "$json" ] && [ "$json" != "null" ] || return 1
479
+ local keys key
480
+ keys=$(printf '%s' "$1" | node "$codex_dialog_helper" --keys || true)
481
+ [ -n "$keys" ] || return 1
482
+ sleep .3
482
483
  while IFS= read -r key; do
483
484
  [ -n "$key" ] || continue
484
485
  tmux_at send-keys -t "$sess" "$key" || return 1
485
486
  sleep .3
486
- done < <(python3 -c 'import json,sys
487
- a=json.loads(sys.stdin.read() or "null")
488
- print("\n".join(a.get("keys") or []) if isinstance(a, dict) else "")' <<<"$json")
487
+ sleep .3
488
+ done <<<"$keys"
489
489
  return 0
490
490
  }
491
491
  codex_pane_blocks_ready() {
492
492
  printf '%s' "$1" | node "$codex_dialog_helper" --ready-ok
493
493
  }
494
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
495
+ local keys key
496
+ keys=$(printf '%s' "$1" | node "$claude_dialog_helper" --keys || true)
497
+ [ -n "$keys" ] || return 1
498
498
  while IFS= read -r key; do
499
499
  [ -n "$key" ] || continue
500
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")
501
+ done <<<"$keys"
504
502
  return 0
505
503
  }
506
504
  while [ $SECONDS -lt "$room_ready_deadline" ]; do
@@ -617,6 +615,29 @@ fi
617
615
 
618
616
  if [ -n "$brief" ] && [ "$brief_dispatched" != true ]; then
619
617
  if [ "$brief_in_composer" != true ]; then
618
+ brief_ready_deadline=$((SECONDS + 90))
619
+ brief_ready_streak=0
620
+ brief_ready=false
621
+ while [ $SECONDS -lt "$brief_ready_deadline" ]; do
622
+ brief_ready_screen=$(tmux_at capture-pane -t "$sess" -p 2>/dev/null || true)
623
+ if [ "$harness" = codex ] && pass_codex_pane "$brief_ready_screen"; then
624
+ brief_ready_streak=0
625
+ sleep 1
626
+ continue
627
+ fi
628
+ if [ "$harness" != codex ] || printf '%s\n' "$brief_ready_screen" | node -e '
629
+ let s="";process.stdin.on("data",c=>s+=c).on("end",()=>{const l=s.split(/\r?\n/).slice(-24);const p=l.some(x=>x.trim()==="›"||x.trimStart().startsWith("› "));const f=l.some(x=>/gpt-/.test(x)&&x.includes("·"));process.exit(p&&f?0:1)})'; then
630
+ brief_ready_streak=$((brief_ready_streak + 1))
631
+ if [ "$brief_ready_streak" -ge 11 ]; then brief_ready=true; break; fi
632
+ else
633
+ brief_ready_streak=0
634
+ fi
635
+ sleep 1
636
+ done
637
+ if [ "$brief_ready" != true ]; then
638
+ echo "LAUNCH_BRIEF_NOT_READY: Aiterm dispatch前に入力promptの安定を観測できない" >&2
639
+ exit 1
640
+ fi
620
641
  if node "$peertable_script_dir/aiterm-send.mjs" "$sess" "$brief_file" >/dev/null; then
621
642
  brief_completed=true
622
643
  echo "briefed: $sess(Aiterm pty_send)"
@@ -330,9 +330,7 @@ async function catchUp() {
330
330
  // 長寿命なのはbackground taskのloopだけで、端末sessionやNode processは常駐させない。
331
331
  if (mode === '--poll') {
332
332
  await catchUp()
333
- process.exit(0)
334
- }
335
-
333
+ } else {
336
334
  const nextWindowMs = Number(process.env.PEERTABLE_PARENT_WATCH_WINDOW_MS ?? 55_000)
337
335
  if (mode === '--next' && (!Number.isFinite(nextWindowMs) || nextWindowMs < 100)) {
338
336
  console.error('PARENT_WATCH_WINDOW_INVALID')
@@ -411,3 +409,4 @@ for (;;) {
411
409
  await sleep(Math.min(2000, Math.max(1, deadline - Date.now())))
412
410
  }
413
411
  }
412
+ }
@@ -1,10 +1,22 @@
1
- # sourced by launch-seat / leave-seat / teardown / ensure-bridge / change-seat
2
- # POSIX は tmux -S <sock>。Windows psmux は -L <aiterm-ns>(-S は既定 namespace へ落ちる)。
3
- _peertable_tmux_scripts=$(CDPATH= cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)
4
- tmux_at() {
5
- local prefix
6
- prefix=$(node "$_peertable_tmux_scripts/tmux-socket.mjs" --prefix) || return 1
7
- # shellcheck disable=SC2206
8
- local -a conn=($prefix)
9
- command tmux "${conn[@]}" "$@"
10
- }
1
+ # sourced by launch-seat / leave-seat / teardown / ensure-bridge / change-seat
2
+ # POSIX は tmux -S <sock>。Windows psmux は -L <aiterm-ns>(-S は既定 namespace へ落ちる)。
3
+ _peertable_tmux_scripts=$(CDPATH= cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)
4
+ tmux_at() {
5
+ local prefix
6
+ prefix=$(node "$_peertable_tmux_scripts/tmux-socket.mjs" --prefix) || return 1
7
+ # shellcheck disable=SC2206
8
+ local -a conn=($prefix)
9
+ # tmux server は最初に立てた process の locale を一生使い、C/POSIX/未設定だと UTF-8 の
10
+ # send-keys/paste を破壊する(実被弾 2026-08-29: launchd の bridge 巡回が LANG 無しで
11
+ # server を立て、以後の日本語込み席起動コマンドが全て化けて Codex 席が着席不能になった)。
12
+ # launchd/cron 由来の呼び出しでも server が UTF-8 で立つよう、壊れた既定の時だけ注入する。
13
+ # 利用者が C/POSIX 以外を明示設定している場合はその選択を尊重して触らない(aiterm と同じ判定)。
14
+ local effective="${LC_ALL:-${LC_CTYPE:-${LANG:-}}}"
15
+ if [ -z "$effective" ] || [[ "$effective" =~ ^(C|POSIX)$ ]]; then
16
+ local ctype="C.UTF-8"
17
+ [ "$(uname)" = "Darwin" ] && ctype="UTF-8"
18
+ env -u LC_ALL LC_CTYPE="$ctype" tmux "${conn[@]}" "$@"
19
+ else
20
+ command tmux "${conn[@]}" "$@"
21
+ fi
22
+ }