peertable 0.4.9 → 0.4.10

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
@@ -73,7 +73,7 @@ docker compose -f deploy/compose.yaml up -d
73
73
 
74
74
  `http://localhost:8790` を開くと、全 room にライブ Web ビュー(SSE)が付く。**Web UI は観戦専用**——書込は全て API 経由で、`PEERTABLE_POST_TOKEN` 設定時はトークン必須。外から届く設置では必ずトークンを設定する。
75
75
 
76
- ライブビューはメンバーごとに vendor / model / effort と**稼働状態**(作業中・待機・**承認待ち**(許可ダイアログで止まっている)・停止)を出す。作業中の席はアイコンが動き、完了宣言(`[done]` / `[完了]` / `受理:` 等)の瞬間に席の上へ印が浮く。状態変化は SSE で押し込むので、30秒の再取得を待たず観測周期(約8秒)で切り替わる。発言にはログ番号(`[123]`)が付き、ライブ新着はブロック単位で現れる。**点が付かない席は「誰も報告していない席」**——状態の送信は別プロセス(スキルが起こす)で、**書けない時は常駐せずに死ぬ**ので「起きているのに黙っている」状態は存在しない。
76
+ ライブビューはメンバーごとに vendor / model / effort / role と**稼働状態**(作業中・待機・**承認待ち**(許可ダイアログで止まっている)・停止)を出す。作業中の席はアイコンが動き、完了宣言(`[done]` / `[完了]` / `受理:` 等)の瞬間に席の上へ印が浮く。状態変化は SSE で押し込むので、30秒の再取得を待たず観測周期(約8秒)で切り替わる。発言にはログ番号(`[123]`)が付き、ライブ新着はブロック単位で現れる。**点が付かない席は「誰も報告していない席」**——状態の送信は別プロセス(スキルが起こす)で、**書けない時は常駐せずに死ぬ**ので「起きているのに黙っている」状態は存在しない。
77
77
 
78
78
  観測先は**席自身が名乗る**(`observe: {tmux_socket, tmux_target}`)。席の起動スクリプトと、席の中で動く MCP クライアントの両方が自分の tmux socket / session を登録するので、**スキル以外の経路で立てた席(aiterm の素の pane など)もそのまま観測対象になる**。表示名から `peer-<名前>` を推測しないので、任意のセッション名で立てた席が消える問題は起きない。名乗っていない古い席だけが従来の推測へ落ちる。常駐は専用 tmux セッションが保持し、**起動側は「起こした」ではなく「最初の観測が届いた」ことを確かめてから成功を返す**(確かめられなければログ末尾を出して非ゼロで落ちる)。
79
79
 
@@ -107,9 +107,9 @@ 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.7**。
110
+ 現在のnpm releaseは **peertable 0.4.10**。
111
111
 
112
- 設計文書と決定履歴(**87 決定**)は [docs/plan.md](docs/plan.md)。
112
+ 設計文書と決定履歴(**89 決定**)は [docs/plan.md](docs/plan.md)。
113
113
 
114
114
  Claude Code channels はリサーチプレビューのため、フラグ・プロトコルは変わりうる。
115
115
 
package/README.md CHANGED
@@ -109,7 +109,7 @@ docker compose -f deploy/compose.yaml up -d
109
109
 
110
110
  Open `http://localhost:8790` — every room gets a live web view (SSE). **The web UI is spectator-only**: all writes go through the API and require `PEERTABLE_POST_TOKEN` when set. Set the token whenever the server is reachable from outside.
111
111
 
112
- The live view shows, per member: vendor / model / reasoning effort, and a **working state** — 作業中 (busy) · 待機 (idle) · 承認待ち (blocked on a permission prompt) · 停止 (dead). A busy seat's avatar animates; a completion (`[done]` / `[完了]` / `受理:` …) pops a marker over the seat. State changes are pushed over SSE, so the icon turns within the observer's polling interval (~8s), not on the next 30-second refresh. Messages carry their log number (`[123]`) for quoting, and live arrivals reveal block by block. **A seat with no dot is one nobody is reporting on** — the state feed is a separate opt-in process (the skill starts it for you), and it refuses to run if it cannot write, so "running but silent" cannot happen.
112
+ The live view shows, per member: vendor / model / reasoning effort / role, and a **working state** — 作業中 (busy) · 待機 (idle) · 承認待ち (blocked on a permission prompt) · 停止 (dead). A busy seat's avatar animates; a completion (`[done]` / `[完了]` / `受理:` …) pops a marker over the seat. State changes are pushed over SSE, so the icon turns within the observer's polling interval (~8s), not on the next 30-second refresh. Messages carry their log number (`[123]`) for quoting, and live arrivals reveal block by block. **A seat with no dot is one nobody is reporting on** — the state feed is a separate opt-in process (the skill starts it for you), and it refuses to run if it cannot write, so "running but silent" cannot happen.
113
113
 
114
114
  Seats **declare where to watch them** (`observe: {tmux_socket, tmux_target}`). Both the seat launcher and the MCP client running inside the seat register their own tmux socket and session, so **a seat you started outside the skill — a bare aiterm pane, say — is observed too**. Nothing infers `peer-<name>` from the display name, so a seat under an arbitrary session name no longer vanishes from the view; only seats that never declared fall back to the old guess. The state feed lives in its own tmux session, and whatever starts it waits for the **first observation to land** before reporting success — not merely for a process to exist. If it never lands, the starter prints the log tail and exits non-zero.
115
115
 
@@ -143,9 +143,9 @@ 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.7**.
146
+ The current npm release is **peertable 0.4.10**.
147
147
 
148
- The design document and decision log (**87 decisions**, in Japanese) live in [docs/plan.md](docs/plan.md).
148
+ The design document and decision log (**89 decisions**, in Japanese) live in [docs/plan.md](docs/plan.md).
149
149
 
150
150
  Depends on Claude Code **channels**, currently a research preview — flags and protocol may change.
151
151
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "peertable",
3
- "version": "0.4.9",
3
+ "version": "0.4.10",
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.9'
14
+ const MCP_VERSION = '0.4.10'
15
15
  const PKG_ROOT = join(dirname(fileURLToPath(import.meta.url)), '..')
16
16
 
17
17
  const USAGE = `usage:
@@ -136,7 +136,7 @@ mcp.setRequestHandler(CallToolRequestSchema, async req => {
136
136
  await mcp.connect(new StdioServerTransport())
137
137
 
138
138
  // 参加登録し、現在のログ末尾から未読を数え始める。
139
- // 素性(vendor/model/effort)は launch-seat.sh が env へ入れる。**登録のたびに載せる**——
139
+ // 素性(vendor/model/effort/role)は launch-seat.sh が env へ入れる。**登録のたびに載せる**——
140
140
  // 登録は client の起動ごとに繰り返し起きるので、1回きりの経路に置くと
141
141
  // member の状態が失われた時に二度と戻らない(server 側は渡された欄だけ更新する upsert)
142
142
  function observeSelf() {
package/room/server.mjs CHANGED
@@ -100,7 +100,7 @@ function normalizeAudience(to, toNames) {
100
100
  }
101
101
 
102
102
  // SSE の member イベントで押し込む欄。閲覧者が気づく欄だけに絞る(POST /members 参照)
103
- const MEMBER_EVENT_FIELDS = ['status', 'busy_since', 'vendor', 'model', 'effort']
103
+ const MEMBER_EVENT_FIELDS = ['status', 'busy_since', 'vendor', 'model', 'effort', 'role']
104
104
 
105
105
  // room ログへは書かない・system 発言も出さない稼働状態の push。post() とは別の経路
106
106
  function emitMember(room, name, meta) {
@@ -190,7 +190,7 @@ http.createServer(async (req, res) => {
190
190
  }
191
191
  if (req.method === 'POST' && rest === 'members') {
192
192
  const { name, ...meta } = JSON.parse(body)
193
- // 素性(vendor/model/effort)や稼働状態は、名前以外の欄をそのまま任意欄として持つ。
193
+ // 素性(vendor/model/effort/role)や稼働状態は、名前以外の欄をそのまま任意欄として持つ。
194
194
  // **渡された欄だけ更新し、渡されなかった欄は既存を保つ**——席の client は `{name}` だけで
195
195
  // 登録するので、これが無いと再接続のたびに素性が消える。`joined_at` は最初の登録を保つ。
196
196
  const known = room.members.get(name)
@@ -463,8 +463,8 @@ async function refreshMembers(){
463
463
  const color=avatarColor(m.name)
464
464
  c.style.setProperty('--h',color.h);c.style.setProperty('--av-bg',color.bg);c.style.setProperty('--av-fg',color.fg);c.dataset.name=m.name
465
465
  // 素性は任意欄。名乗っていない席は行ごと出ない(空欄を「不明」として見せない)。
466
- // vendor/model/effort を1行へ畳む(launch-seat.sh:108 の着席ログと読み口を揃える。effort の語は出さない)
467
- const idParts=[m.vendor,m.model,m.effort].filter(Boolean)
466
+ // vendor/model/effort/role を1行へ畳む(着席ログと読み口を揃える。effort / role の語は出さない)
467
+ const idParts=[m.vendor,m.model,m.effort,m.role].filter(Boolean)
468
468
  const meta=[idParts.length?idParts.join(' / '):null].filter(Boolean)
469
469
  // 稼働状態は**報告が新しい時だけ**採る。途絶えたら unknown へ落とす——古い状態を出し続けるのが
470
470
  // いちばん悪い(動いていない席を「動いている」と見せる)。閾値は bridge の心拍30秒の3倍
@@ -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.7' })
19
+ const client = new Client({ name: 'peertable-seat-configure', version: '0.4.10' })
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.7' })
11
+ const client = new Client({ name: 'peertable-seat-launch', version: '0.4.10' })
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',
@@ -512,7 +512,7 @@ PY
512
512
  fi
513
513
  fi
514
514
 
515
- # 席の素性(vendor / model / effort)を room へ渡す。参加者一覧のホバー表示に使う。
515
+ # 席の素性(vendor / model / effort / role)を room へ渡す。参加者一覧のホバー表示に使う。
516
516
  # 席自身の client も起動時に `{name}` だけで登録するので、server 側は
517
517
  # **欄が無い登録で既存の素性を消さない**(upsert)ことが前提である。
518
518
  # effort は渡された時だけ入れる——欄が無い=「不明」ではなく「CLI 既定で走っている」。
@@ -552,7 +552,7 @@ print('yes' if m.get('model') and m.get('role') and m.get('aiterm_session_id') a
552
552
  PY
553
553
  )
554
554
  if [ "$stored" = yes ]; then
555
- echo "metadata: ${vendor} / ${model}${effort:+ / $effort}"
555
+ echo "metadata: ${vendor} / ${model}${effort:+ / $effort}${role:+ / $role}"
556
556
  else
557
557
  echo "metadata は保存されなかった: この room サーバーは素性欄を持たない版(席は着席済み・一覧に素性が出ないだけ)" >&2
558
558
  fi