peertable 0.4.33 → 0.4.34

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.4.33",
3
+ "version": "0.4.34",
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.4.33'
16
+ const MCP_VERSION = '0.4.34'
17
17
  const PKG_ROOT = join(dirname(fileURLToPath(import.meta.url)), '..')
18
18
 
19
19
  const USAGE = `usage:
package/skill/SKILL.md CHANGED
@@ -240,8 +240,9 @@ witness をどう生成するかは**対象 project 側の作法に従う**(La
240
240
  - **メンバー起動の既知ダイアログは2種だけ**(実測 2026-08-08): 未信頼ディレクトリの workspace trust(`1. Yes, I trust this folder`)と開発 channel 警告(`1. I am using this for local development`)。`--dangerously-skip-permissions` を付けているので MCP 同意ダイアログは出ない。信頼済みディレクトリでは trust も出ない
241
241
  - **Codex 席のダイアログは3種で、更新案内と hooks の既定は誤り**(Codex CLI v0.146.0 および 2026-08-20 実測): ディレクトリ trust(`1. Yes, continue`=既定で正しい)。**更新案内(`1. Update now`)は既定のまま Enter を押すと立卓の途中で `npm install -g @openai/codex` が走る**ので「2. Skip」。**`Hooks need review` は room MCP 初期化より前に出る**(`SEAT_ROOM_MCP_NOT_READY` のまま rollback)。`launch-seat.sh` は「2. Trust all and continue」を通す。失敗時は rollback 前に `.team/<name>-pane-on-fail.txt` を残す。待ち時間のポーリングで代用しない
242
242
  - **Codex はターン実行中でも素送信を受け付ける**(実測 2026-08-08)。busy 中に送った文言はそのターンの中で読まれ、指示どおりに動く(steering)。Codex 席への TUI 配達は idle 待ちを持たない
243
- - **Grok はターン実行中の素送信を今の仕事へ混ぜない**(実測 2026-08-17・Grok Build TUI 既定 `follow_up_behavior=queue`)。届いた文は入力キューへ積まれ、次の user ターンになる。TUI 配達は Grok 席だけ pane が idle になるまで送らない。busy の判定は `esc to interrupt`、待ち中の `send a message to interrupt`、番号付きキュー+`Enter:send now`
244
- - **席の沈黙は「詰まり」と同義ではない。** 発言間隔やファイルの更新時刻から止まったと判定しない——実装が終わって検証に時間を使っているだけのことがある。判定は `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人が独立に踏み、先に憶測を流した側が訂正を出した)
243
+ - **Grok はターン実行中の素送信を今の仕事へ混ぜない**(実測 2026-08-17・Grok Build TUI 既定 `follow_up_behavior=queue`)。届いた文は入力キューへ積まれ、次の user ターンになる。TUI 配達は Grok 席だけ pane が idle になるまで送らない。busy の判定は `esc to interrupt` に加え、Grok 固有の `Waiting for response` / `Responding…` / `[stop]` / 未完了 `[hooks: 1/3]`(実測 2026-08-21。Grok は `esc to interrupt` を出さないので、これを見ないと作業中が待機に見える)、待ち中の `send a message to interrupt`、番号付きキュー+`Enter:send now`
244
+ - **Grok `Help improve Grok [Opt out] [Opt in]` バナーは席を死んだように見せる**(実測 2026-08-21。auth の `coding_data_retention_opt_out` だけでは消えない)。`launch-seat.sh` は `GROK_PRIVACY_NOTICE_ROLLOUT=0` を着席 env へ渡す。キー送信では消えない。既存席は再着席するまで残る
245
+ - **席の沈黙は「詰まり」と同義ではない。** 発言間隔やファイルの更新時刻から止まったと判定しない——実装が終わって検証に時間を使っているだけのことがある。判定は `tmux_at capture-pane -t peer-<名前> -p`(POSIX は `tmux -S <sock>`、Windows psmux は `tmux -L aiterm-<hash>`。決定88)で**実状態を読む**: 画面に **`esc to interrupt` が在れば長いターンの最中**(通知はターン後にまとめて届くので、呼びかけを足しても速くならない)/Grok は **`Waiting for response` / `Responding…` / `[stop]`** が同じ意味/選択ダイアログで止まっているなら既知の停止要因/`Help improve Grok` バナーは承認待ち/`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 (…)` にも入る共通マーカー**。Grok には無い。**読み取りだけなら相手の作業を壊さない**ので、憶測を room へ流す前にこれを見る(2026-08-08 に2人が独立に踏み、先に憶測を流した側が訂正を出した)
245
246
  - **`claude-in-chrome` の呼び出しは返らないことがある**。原因は2種で、解き方が違う(2026-08-08 に席1つが9分半沈黙して実測):
246
247
  - **接続ブラウザが複数あって、拡張がどれを使うか選ばせている**——選択待ちのまま返らない。**AI 側から解ける**(オーナーに「どちらを使うか」を一言聞けば済む)。今回の実例はこちら。デバッグ接続が宙吊りのまま「Claude がこのブラウザのデバッグを開始しました[キャンセル]」バナーが残る形もあり、キャンセルを押せば呼び出しは即エラーで返る
247
248
  - **ブラウザに alert/confirm 等のモーダルが出ている**——拡張が以後のコマンドを受け取れない。**AI 側から解けない**ので、人がダイアログを閉じるしかない
@@ -20,7 +20,10 @@ if (process.env.PEERTABLE_PLAN) env_vars.push(
20
20
  'PEERTABLE_PLAN', 'LATTICE_CLI', 'LATTICE_TODO_ACTOR_HOST',
21
21
  'LATTICE_TODO_ACTOR_SESSION', 'LATTICE_TODO_ACTOR_AGENT',
22
22
  )
23
- if (vendor === 'grok' && process.env.GROK_HOME) env_vars.push('GROK_HOME')
23
+ if (vendor === 'grok') {
24
+ if (process.env.GROK_HOME) env_vars.push('GROK_HOME')
25
+ env_vars.push('GROK_PRIVACY_NOTICE_ROLLOUT')
26
+ }
24
27
  if (vendor === 'codex' && process.env.CODEX_HOME) env_vars.push('CODEX_HOME')
25
28
  const result = await client.callTool({
26
29
  name: `${vendor}_agent`,
@@ -372,7 +372,10 @@ if [ "$mode" = "lattice" ]; then
372
372
  [ -n "$lattice_cli" ] && launch_env+=("LATTICE_CLI=$lattice_cli")
373
373
  fi
374
374
  if [ "$vendor" = grok ]; then
375
+ # 実測 2026-08-21: auth の coding_data_retention_opt_out だけでは
376
+ # `Help improve Grok [Opt out] [Opt in]` バナーが残る。席が死んだように見える。
375
377
  launch_env+=("GROK_HOME=$grok_home")
378
+ launch_env+=("GROK_PRIVACY_NOTICE_ROLLOUT=0")
376
379
  fi
377
380
  if [ "$vendor" = codex ]; then
378
381
  codex_home="${proj}/.team/seats/${name}.codex"
@@ -7,9 +7,10 @@
7
7
  //
8
8
  // 判定(2026-08-08 実測。**推測でパターンを書かない**):
9
9
  // busy = pane の末尾に `esc to interrupt` が在る。Claude 席のステータス行にも Codex 席の `Working (…)` にも
10
- // 同じ文字列が入るので **vendor 分岐が要らない**。実行中の動名詞(Cogitating/Coalescing/Effecting/
11
- // Gallivanting/Fermenting/Symbioting…)は**毎回変わる**ので判定に使わない——語で照合すると全席を
12
- // idle と誤判定して、画面が嘘をつく
10
+ // 同じ文字列が入る。Grok はこれを出さず `Waiting for response` / `Responding…` / `[stop]` を出す
11
+ // (2026-08-21 実測。これを見ないと作業中の Grok 席が idle に見える)。実行中の動名詞
12
+ // (Cogitating/Coalescing/Effecting/Gallivanting/Fermenting/Symbioting…)は**毎回変わる**ので
13
+ // 判定に使わない——語で照合すると全席を idle と誤判定して、画面が嘘をつく
13
14
  // blocked = 既知の承認ダイアログ文言が末尾に在る(`esc to interrupt` は消えている)。2026-08-08 実測:
14
15
  // 確認ダイアログで停止した席が busy と `esc to interrupt` 不在から idle 側に誤判定され、
15
16
  // 動けない席へ卓が代走を申し出るところまで進んだ。判定順は busy → blocked → idle
@@ -191,6 +191,14 @@ export const BLOCKED_MARKERS = [
191
191
  'Do you want to proceed?',
192
192
  ]
193
193
 
194
+ /** Grok TUI の SpaceXAI coding-data バナー(2026-08-21 実測。入力は通るが席が死んだように見える)。 */
195
+ export function isGrokPrivacyBanner(tail) {
196
+ return typeof tail === 'string'
197
+ && tail.includes('Help improve Grok')
198
+ && tail.includes('[Opt out]')
199
+ && tail.includes('[Opt in]')
200
+ }
201
+
194
202
  /**
195
203
  * pane 末尾の生文字列から画面状態を判定する。判定順は busy → blocked → idle
196
204
  * (承認プロンプト表示中は `esc to interrupt` が消えるので busy を先に見る)。
@@ -205,7 +213,14 @@ export function classifyPaneTail(tail) {
205
213
  if (tail.includes("without interrupting Claude's current work")) return 'busy'
206
214
  if (tail.includes('Calling tools')) return 'busy'
207
215
  if (/…\s*\(\d+(?:m \d+)?s\b/u.test(tail)) return 'busy'
216
+ // Grok Build TUI は esc to interrupt を出さない(2026-08-21 実測)。
217
+ // 生成中は `Waiting for response…` / `Responding…` と `[stop]`。
218
+ // 完了後の `Worked for 38s` は idle。未完了 hook だけ `[hooks: 1/3]`。
219
+ if (tail.includes('Waiting for response') || tail.includes('Responding…') || tail.includes('Responding...')) return 'busy'
220
+ if (tail.includes('[stop]')) return 'busy'
221
+ if (/\[hooks:\s*\d+\/\d+\]/u.test(tail)) return 'busy'
208
222
  if (BLOCKED_MARKERS.some(marker => tail.includes(marker))) return 'blocked'
223
+ if (isGrokPrivacyBanner(tail)) return 'blocked'
209
224
  return 'idle'
210
225
  }
211
226