peertable 0.4.5 → 0.4.7

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.ja.md CHANGED
@@ -107,7 +107,7 @@ Codex では、スキルが所有する room MCP block をプロジェクトの
107
107
 
108
108
  動いており、**自分自身の開発に使っている**。2026-08-08 に end-to-end 検証済み——オーケストレーターなしの完全な一周(2 メンバーが相談し、claim し、インターフェースを交渉し、見つけた罠を共有して小さなプロジェクトを出荷)を**外部介入ゼロ**で完走。2026-08-13の実席ライフサイクルでは、作業席が親を通じてsession contextを保ったままmodel / effortを変更し、再起動後はroomと工程正本から再着任した。2026-08-14にはGrok 4.6席の着席、room参加、同一sessionの4.6↔4.5変更、DM起床を実機で確認した。2026-08-17にGrok席はidle待ち、broadcastは本文を残し、tmuxの無い親でbridge cursorが止まらないよう直した。
109
109
 
110
- 現在のnpm releaseは **peertable 0.4.5**。
110
+ 現在のnpm releaseは **peertable 0.4.7**。
111
111
 
112
112
  設計文書と決定履歴(**87 決定**)は [docs/plan.md](docs/plan.md)。
113
113
 
package/README.md CHANGED
@@ -143,7 +143,7 @@ It interviews you, names the members, scaffolds `.team/` (charter + roles, isola
143
143
 
144
144
  Working, and used to build itself. First verified end-to-end on 2026-08-08 with a full no-orchestrator loop: two members consulted, claimed, negotiated an interface, shared a discovered pitfall, and shipped a small project with **zero external intervention**. A 2026-08-13 real-seat lifecycle verified in-place model/effort changes and restart recovery. On 2026-08-14, a Grok 4.6 seat joined the room, changed 4.6↔4.5 in the same session, and woke on a direct message in a live acceptance run. On 2026-08-17 the wake-up path was corrected so Grok seats wait for idle, broadcasts keep their body, and a parent without a tmux seat cannot stall the bridge cursor.
145
145
 
146
- The current npm release is **peertable 0.4.5**.
146
+ The current npm release is **peertable 0.4.7**.
147
147
 
148
148
  The design document and decision log (**87 decisions**, in Japanese) live in [docs/plan.md](docs/plan.md).
149
149
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "peertable",
3
- "version": "0.4.5",
3
+ "version": "0.4.7",
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
@@ -11,7 +11,7 @@ import { fileURLToPath } from 'node:url'
11
11
 
12
12
  // client.mjs 側のハードコード版数。package.json の version と一致していることを
13
13
  // diagnostics の version_consistency が見る(2 つの版数源の drift 検出。決定45)
14
- const MCP_VERSION = '0.4.5'
14
+ const MCP_VERSION = '0.4.7'
15
15
  const PKG_ROOT = join(dirname(fileURLToPath(import.meta.url)), '..')
16
16
 
17
17
  const USAGE = `usage:
package/skill/SKILL.md CHANGED
@@ -108,10 +108,10 @@ script は内部で Aiterm の公開 `claude_agent` / `codex_agent` / `grok_agen
108
108
  - **id に plan key だけの固定値を使わない。** `close` しても run directory は残り `run list` は closed を返さないので、**「無いのに `RUN_EXISTS` で作れない」**袋小路に入る(2026-08-09 実測)
109
109
  - `RUN_EXISTS` が返ったら**相手の run を推定せず**、再 list → active があれば共有、無ければ別の一意 id で作り直す
110
110
  - **席は自分で `todo start` してから `run intake` する。** intake が返すのは隔離 worktree と `intervention`(`none` か `hold`)で、**許可証ではない**。`hold` は「他の着手済み task と競合しているから留まれ」という装置の指示である
111
- - **`todo done` canonical の cwd/store へ打ち、証跡は worktree から渡す。** `done.sh <task> --evidence-from <worktree>/evidence/<plan>/<task>.md`。cwd 1つで兼ねると必ずどちらかが外れる(canonical では証跡が読めず、worktree では accept が見ない store を書く)。**canonical へ証跡を複製して通すのは偽装**——linked worktree は object DB を共有するので複製は要らない
111
+ - **`todo done` は監査担当が打つ。** canonical の cwd/store へ打ち、証跡は worktree から渡す。`done.sh <task> --evidence-from <worktree>/evidence/<plan>/<task>.md`。cwd 1つで兼ねると必ずどちらかが外れる(canonical では証跡が読めず、worktree では accept が見ない store を書く)。**canonical へ証跡を複製して通すのは偽装**——linked worktree は object DB を共有するので複製は要らない。**accept は intake 席が、todo done の後に打つ**(engine は done 前の accept を拒否する。done.sh が accept を先に要求すると循環する)
112
112
  - **worktree と lease は設備の供給である。** 席が要求すれば出てくるもので、出してもらうものではない
113
113
  - **席と spool は接触しない。** 席が触るのは room と worktree だけで、`.lattice/` の直読み・直書き禁止の契約はそのまま
114
- - **席の作法の正本は `templates/member.md` の「Lattice の実行層へ自分の着手を載せる」節**(intake→intervention 判定→attach→作業→`todo done`→accept の順・1席1 intake・禁止操作・検証の回し方・成果の正本)。ここに二重化しない
114
+ - **席の作法の正本は `templates/member.md` の「Lattice の実行層へ自分の着手を載せる」節**(intake→intervention 判定→attach→作業→監査担当が `done.sh`→intake 席が accept の順・1席1 intake・禁止操作・検証の回し方・成果の正本)。ここに二重化しない
115
115
  - **席は自分の pid を装置へ渡す(attach)。** その pid は `.team/seats/<名前>.json`(`launch-seat.sh` が着席直後に書く)が持ち、席は読んで `schema` を足すだけで attach input になる。**raw argv を保存しない**——token値をargvから除いた後も、将来の引数を無条件に複製しない。持つのはdigestだけ
116
116
  - **run-bridge は可視化の中継であって、必須経路ではない**(決定63)。落ちていても席は自分で intake / attach / accept を打てるし、介入も `lattice run intake intervention --run <ref> --task <id>` で自分で読める。**見えなくなるだけ**である
117
117
  - **ブリッジの起動**: `scripts/ensure-bridge.sh <project> run [--lattice <path>]`。停止は `node scripts/run-bridge.mjs <project> --stop`(**teardown.sh が自動で行う**)。**spool dir も席名も取らない**(配車をしないので要らない。渡すと typed error で落ちる)。ADR 0157 の作法(pid 記録・起動時に前の記録を掃除・SIGTERM→SIGKILL)はそのまま
@@ -233,7 +233,7 @@ witness をどう生成するかは**対象 project 側の作法に従う**(La
233
233
  - **Codex 席のダイアログは2種で、片方は既定が誤り**(Codex CLI v0.146.0・実測): ディレクトリ trust(`1. Yes, continue`=既定で正しい)と、**更新案内(`1. Update now`)は既定のまま Enter を押すと立卓の途中で `npm install -g @openai/codex` が走る**。1つ下の「2. Skip」を選ぶ。更新案内は毎回は出ないので、出た時だけ通す
234
234
  - **Codex はターン実行中でも素送信を受け付ける**(実測 2026-08-08)。busy 中に送った文言はそのターンの中で読まれ、指示どおりに動く(steering)。Codex 席の起床は idle 待ちを持たない
235
235
  - **Grok はターン実行中の素送信を今の仕事へ混ぜない**(実測 2026-08-17・Grok Build TUI 既定 `follow_up_behavior=queue`)。届いた文は入力キューへ積まれ、次の user ターンになる。起床ブリッジは Grok 席だけ pane が idle になるまで送らない。busy の判定は `esc to interrupt`、待ち中の `send a message to interrupt`、番号付きキュー+`Enter:send now`
236
- - **席の沈黙は「詰まり」と同義ではない。** 発言間隔やファイルの更新時刻から止まったと判定しない——実装が終わって検証に時間を使っているだけのことがある。判定は `tmux_at capture-pane -t peer-<名前> -p`(POSIX は `tmux -S <sock>`、Windows psmux は `tmux -L aiterm-<hash>`。決定88)で**実状態を読む**: 画面に **`esc to interrupt` が在れば長いターンの最中**(通知はターン後にまとめて届くので、呼びかけを足しても速くならない)/選択ダイアログで止まっているなら既知の停止要因/`pane_dead=1` なら落ちている。**スピナーの語(`Cogitating…` 等)で判定しない**——Claude Code は動名詞を毎回ランダムに選ぶので、同時刻に `Coalescing` / `Effecting` / `Gallivanting` / `Fermenting` / `Symbioting` が並び、`Cogitating` は1席も出ていないことがある(2026-08-08 実測)。**`esc to interrupt` は Claude 席のステータス行にも Codex 席の `Working (…)` にも入る共通マーカー**で、vendor 分岐が要らない。**読み取りだけなら相手の作業を壊さない**ので、憶測を room へ流す前にこれを見る(2026-08-08 に2人が独立に踏み、先に憶測を流した側が訂正を出した)
236
+ - **席の沈黙は「詰まり」と同義ではない。** 発言間隔やファイルの更新時刻から止まったと判定しない——実装が終わって検証に時間を使っているだけのことがある。判定は `tmux_at capture-pane -t peer-<名前> -p`(POSIX は `tmux -S <sock>`、Windows psmux は `tmux -L aiterm-<hash>`。決定88)で**実状態を読む**: 画面に **`esc to interrupt` が在れば長いターンの最中**(通知はターン後にまとめて届くので、呼びかけを足しても速くならない)/選択ダイアログで止まっているなら既知の停止要因/`pane_dead=1` なら落ちている。**スピナーの動名詞(`Cogitating…` 等)で判定しない**——毎回ランダムなので語そのものは使わない(2026-08-08 実測)。Fable のツール実行中は `… (7m 48s` の経過時間行と `/btw` `without interrupting Claude's current work` が固定句として出る。思考中は `thinking with` / `almost done thinking`。**`esc to interrupt` は Claude 席のステータス行にも Codex 席の `Working (…)` にも入る共通マーカー**で、vendor 分岐が要らない。**読み取りだけなら相手の作業を壊さない**ので、憶測を room へ流す前にこれを見る(2026-08-08 に2人が独立に踏み、先に憶測を流した側が訂正を出した)
237
237
  - **`claude-in-chrome` の呼び出しは返らないことがある**。原因は2種で、解き方が違う(2026-08-08 に席1つが9分半沈黙して実測):
238
238
  - **接続ブラウザが複数あって、拡張がどれを使うか選ばせている**——選択待ちのまま返らない。**AI 側から解ける**(オーナーに「どちらを使うか」を一言聞けば済む)。今回の実例はこちら。デバッグ接続が宙吊りのまま「Claude がこのブラウザのデバッグを開始しました[キャンセル]」バナーが残る形もあり、キャンセルを押せば呼び出しは即エラーで返る
239
239
  - **ブラウザに alert/confirm 等のモーダルが出ている**——拡張が以後のコマンドを受け取れない。**AI 側から解けない**ので、人がダイアログを閉じるしかない
@@ -16,7 +16,7 @@ if (!session_id || (!model && !reasoning_effort)) {
16
16
  // Aiterm のmanaged session metadataは実行時state root(macOSではTMPDIR)にある。
17
17
  // stdio transportの既定環境は親のTMPDIRを落とすため、同じ公開serverへ明示継承する。
18
18
  const transport = new StdioClientTransport({ command: 'aiterm-mcp', env: process.env })
19
- const client = new Client({ name: 'peertable-seat-configure', version: '0.4.5' })
19
+ const client = new Client({ name: 'peertable-seat-configure', version: '0.4.7' })
20
20
  await client.connect(transport)
21
21
  const result = await client.callTool({
22
22
  name: 'agent_configure',
@@ -8,7 +8,7 @@ if (!session_name || !['claude', 'codex', 'grok'].includes(vendor) || !model ||
8
8
  throw new Error('SEAT_AITERM_LAUNCH_ARGS_INVALID')
9
9
  }
10
10
 
11
- const client = new Client({ name: 'peertable-seat-launch', version: '0.4.5' })
11
+ const client = new Client({ name: 'peertable-seat-launch', version: '0.4.7' })
12
12
  await client.connect(new StdioClientTransport({ command: 'aiterm-mcp', env: process.env }))
13
13
  const env_vars = [
14
14
  'PEERTABLE_URL', 'PEERTABLE_ROOM', 'PEERTABLE_MEMBER', 'PEERTABLE_CREDENTIAL_FILE',
@@ -199,8 +199,12 @@ export function classifyPaneTail(tail) {
199
199
  if (typeof tail !== 'string') return 'idle'
200
200
  if (tail.includes('esc to interrupt')) return 'busy'
201
201
  // Claude Code 2.1 / Fable TUI は思考中に esc to interrupt を出さない(2026-08-19 実測)。
202
- // 動名詞(Wibbling 等)は毎回変わるので使わない。思考中の固定句だけを busy にする。
202
+ // 動名詞(Sprouting / Wibbling 等)は毎回変わるので使わない。
203
+ // 思考中の固定句に加え、ツール実行中は経過時間付きスピナー行と /btw の固定ヒントが出る。
203
204
  if (tail.includes('thinking with') || tail.includes('almost done thinking')) return 'busy'
205
+ if (tail.includes("without interrupting Claude's current work")) return 'busy'
206
+ if (tail.includes('Calling tools')) return 'busy'
207
+ if (/…\s*\(\d+(?:m \d+)?s\b/u.test(tail)) return 'busy'
204
208
  if (BLOCKED_MARKERS.some(marker => tail.includes(marker))) return 'blocked'
205
209
  return 'idle'
206
210
  }
@@ -35,7 +35,8 @@ usage: done.sh <task_id> [--plan <plan_key>] [--evidence-from <隔離worktreeの
35
35
  evidence/<plan>/<task>.md を commit 済みにして done.sh <task_id> を実行する。
36
36
  wrapper が証跡から記述子を生成し、lattice todo doneで同じ本文を最終試験結果として canonical store へ記録する。
37
37
  pull run の worktree で作業した場合だけ --evidence-from に同じrepoの絶対pathを渡す。
38
- accept intake がある場合は、先に run intake accept を完了させる。
38
+ この script は監査担当が打つ。accept intake 席が todo done の後に打つ(engine 正順)。
39
+ 未accept・未着地は警告だけで、done を止めない。
39
40
  USAGE
40
41
  }
41
42
 
@@ -177,10 +178,9 @@ while [ "$#" -gt 0 ]; do
177
178
  done
178
179
  [ -n "$plan" ] || { echo "ERROR: 完了処理を続けられない: --plan または PEERTABLE_PLAN が必要" >&2; exit 1; }
179
180
  if [ -n "$evidence_from" ]; then
180
- case "$evidence_from" in
181
- /*) ;;
182
- *) echo "ERROR: --evidence-from は絶対pathでなければならない: $evidence_from" >&2; exit 1 ;;
183
- esac
181
+ if ! python3 -c 'import os,sys; sys.exit(0 if os.path.isabs(sys.argv[1]) else 1)' "$evidence_from"; then
182
+ echo "ERROR: --evidence-from は絶対pathでなければならない: $evidence_from" >&2; exit 1
183
+ fi
184
184
  # **黙って canonical の証跡へ落ちない。** 落ちると「worktree の成果を done した」と見えるのに
185
185
  # 実際は別の file を hash することになり、受理された内容と成果物が食い違う
186
186
  [ -f "$evidence_from" ] || { echo "ERROR: --evidence-from の証跡が存在しない: $evidence_from" >&2; exit 1; }
@@ -240,11 +240,9 @@ case "$task_status" in
240
240
  *) echo "ERROR: 完了処理を続けられない: ToDoが完了可能状態でない: $task_status" >&2; exit 1 ;;
241
241
  esac
242
242
 
243
- # **receipt が未 accept のまま done を打たせない。** 実行層に載せた task の成果の正本は
244
- # Lattice が撮った observed diff(accepted receipt)であって、ToDo done ではない。
245
- # 2026-08-11 実測: accept が `RUNTIME_CONFLICT_HOLD` で止まっているのに done は通り、
246
- # 「ToDo は完了・成果はどこにも着地していない」状態が親の事後照合まで誰にも見えなかった
247
- # (そして landing-only mode は receipt が無ければ 0 本=無言になる)。
243
+ # **done accept は別軸。** engine は todo done の後にだけ accept できる。
244
+ # 監査担当が done.sh で閉じ、intake 席が accept する。未 accept を done の拒否条件にすると循環する。
245
+ # 読めない状態は成功へ倒さない。未accept・未着地は警告(未push と同じ)。
248
246
  # **実行層に載っていない task は素通しする**——pull run の利用は任意で、載っていない卓を止めない。
249
247
  gate_runs=$("$done_gate_cli" run list --json 2>&1) || {
250
248
  echo "ERROR: receipt の状態を読めない(run list が失敗): $gate_runs" >&2; exit 1;
@@ -322,12 +320,6 @@ for index, intake in enumerate(intakes):
322
320
  entry = intake
323
321
  print("absent" if entry is None else ("accepted" if entry.get("accepted_head_sha") else "pending"))
324
322
  ' "$t") || { echo "ERROR: receipt の状態を読めない: $gate_state" >&2; exit 1; }
325
- if [ "$gate_state" = pending ]; then
326
- echo "ERROR: receipt が未acceptのまま done は打てない: ${t} @ ${gate_ref}" >&2
327
- echo " 先に受理させる: ${done_gate_cli} run intake accept --run ${gate_ref} --task ${t}" >&2
328
- echo " (accept が hold で止まる場合、その理由の解消が完了条件であって、done は迂回路ではない)" >&2
329
- exit 1
330
- fi
331
323
  done
332
324
 
333
325
  # descriptor の path は repo 内の相対(repo 外の絶対 path は --evidence が INVALID_ARGUMENTS で弾く)。
@@ -378,9 +370,7 @@ if [ -n "$upstream_ref" ]; then
378
370
  fi
379
371
  fi
380
372
 
381
- # pull run を使った task は、accept 済みで、かつこの task の receipt が
382
- # canonical branch へ着地したことまで確認する。別 task の未着地だけでは
383
- # この task の completed を止めない。
373
+ # pull run に載った task は、accept / 着地を警告として出す。done 自体は止めない。
384
374
  for gate_ref in $gate_refs; do
385
375
  gate_obs=""
386
376
  gate_obs=$("$done_gate_cli" run observe --run "$gate_ref" 2>&1) || {
@@ -420,14 +410,14 @@ else:
420
410
  exit 1
421
411
  }
422
412
  [ "$gate_state" = absent ] && continue
423
- [ "$gate_state" = accepted ] || {
424
- echo "ERROR: 完了処理を続けられない: receipt が未accept: ${t} @ ${gate_ref}" >&2
425
- exit 1
426
- }
413
+ if [ "$gate_state" != accepted ]; then
414
+ echo "accept: ${t} @ ${gate_ref}(intake 席が accept する。done は記録済み)" >&2
415
+ continue
416
+ fi
427
417
  landing_report=""
428
418
  landing_report=$("$done_gate_cli" run landing --run "$gate_ref" 2>&1) || {
429
- echo "ERROR: 完了処理を続けられない: run landing が失敗: $gate_ref: $landing_report" >&2
430
- exit 1
419
+ echo "着地状態を読めない: run landing が失敗: $gate_ref: $landing_report" >&2
420
+ continue
431
421
  }
432
422
  landing_task=$(printf '%s' "$landing_report" | python3 -c '
433
423
  import json, sys
@@ -459,8 +449,7 @@ else:
459
449
  exit 1
460
450
  }
461
451
  [ "$landing_task" = landed ] || {
462
- echo "ERROR: 完了処理を続けられない: task receipt がcanonical landing済みでない: ${t} @ ${gate_ref}" >&2
463
- exit 1
452
+ echo "未着地: ${t} @ ${gate_ref}(task receipt が canonical へ未着地)" >&2
464
453
  }
465
454
  done
466
455