peertable 0.8.45 → 0.8.46

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.45",
3
+ "version": "0.8.46",
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
@@ -14,7 +14,7 @@ import { boundedRecent, boundedUnread } from './message-bounds.mjs'
14
14
 
15
15
  // client.mjs 側のハードコード版数。package.json の version と一致していることを
16
16
  // diagnostics の version_consistency が見る(2 つの版数源の drift 検出。決定45)
17
- const MCP_VERSION = '0.8.45'
17
+ const MCP_VERSION = '0.8.46'
18
18
  const PKG_ROOT = join(dirname(fileURLToPath(import.meta.url)), '..')
19
19
 
20
20
  const USAGE = `usage:
package/skill/SKILL.md CHANGED
@@ -75,7 +75,7 @@ script は内部で Aiterm の公開 `claude_agent` / `codex_agent` / `grok_agen
75
75
  6.5 **席の稼働状態ブリッジ**: setup/launch/resumeが`ensure-project-runtime.sh`を内部で1回呼び、alarm/seat-status/wakeupを現行版へ収束させるので、**AIが個別bridgeを操作する段は無い**。観測先はmemberの`observe: {tmux_socket, tmux_target}`を優先する。ランプは現在のpaneからbusy/blocked/idle/deadを判定し、通信失敗表示が残るGrok席をbusyにしない
76
76
  6.7 **model / effort変更(本人要請→親実行)**: 本人は希望と理由を自然文で親だけへDMする。親は意味を判断してtargetを確定し、`env -u PEERTABLE_POST_TOKEN skill/scripts/change-seat.sh <project> <member> [--model <model>] [--effort <effort>] [--parent <name>] [--reason <text>]`を実行する。定型文への言い直し、完全一致の再送、本人DMの機械検査は行わない。scriptはroom memberの現在値を読み、Aitermの公開`agent_configure`へ確定targetを渡し、metadataの読返しと変更履歴を残す。targetはlive catalogで検証し、変更後の記録に失敗した場合も成功へ丸めない。
77
77
  - 同じharness内のmodel / effort変更はAitermが同一sessionと会話contextを保って行う。harness変更だけは再起動を伴うため、本人はrole・工程正本・roomログから再着任する
78
- 6.8 **mission 更新(席が自分で実行)**: 工程が変わったら席が `env -u PEERTABLE_POST_TOKEN skill/scripts/set-mission.sh <project> <name> <text>` を打つ。`POST /members` で chip を更新し、`[mission] <name>: <text>` を全員へ1行出す。席は再起動しない。親は代行しない。`change-seat.sh` に mission を足さない。
78
+ 6.8 **mission 更新(席が自分で実行)**: missionはフェーズ・campaign全体での担いであり、今やっている作業・待機状態を書く欄ではない(現在作業はroom発言から機械導出される。オーナー裁定 2026-08-30)。フェーズが変わったら席が `env -u PEERTABLE_POST_TOKEN skill/scripts/set-mission.sh <project> <name> <text>` を打つ。`POST /members` で chip を更新し、`[mission] <name>: <text>` を全員へ1行出す。席は再起動しない。親は代行しない。`change-seat.sh` に mission を足さない。
79
79
 
80
80
  7. **親の着卓**(このセッション): `scripts/parent-join.sh <project> [name] [model] [effort] [harness]` で member 登録とparent-watch cursorのprimeを行う。**`effort` は任意のまま据え置く**——席は `launch-seat.sh` が `--effort` で実際に設定するので「渡した値=実挙動」だが、親は既に走っているセッションで自分の effort を機械的に知る経路が無く、推測して載せると画面が嘘をつく。続けて、ClaudeとGrokはMonitor、Codexはyieldしたbackground tool taskとして**親宛DM番犬**を1世代だけ張る(形は下記「親の operating notes」の番犬仕様)。**着卓完了の条件は、parent-join が投稿する耳疎通probe(`EAR_PROBE_SENT` の nonce)を自分の監視イベントとして受信すること**——番犬プロセスの生存は耳の証拠にならない(前セッションの耳へ吠え続け親宛DMが全損した実被弾 2026-08-22)。受信できないなら監視を張り直す。通常席用wakeup-bridgeに親を載せない。broadcastのkickoffは廃止済み。以後の post も API 直(同 notes)
81
81
  8. **起動確認**: room の members に全員いる / 最初の claim が room に流れる(Lattice 併用モードはそれが Lattice へ到達している=`lattice todo status --json` の active に出ることも確認する。単独モードは room の claim 宣言だけが到達の証拠)/ Web UI で観測できる、をチェックして報告する
@@ -272,7 +272,18 @@ async function nudgeIfDropped(name, busySince) {
272
272
  // to:"all" は失効させない——親の待機宣言運用(起きても返信不要)と両立させるため。
273
273
  const PATROL_INTERVAL_MS = 30_000
274
274
  const PATROL_NAG_INTERVAL_MS = 300_000 // 条件が続く席へは5分間隔で再吠えする(1回きりにしない)
275
+ // 通報先の親名は parent-watch の記録から読む(wakeup-bridge と同じ解決規則)
276
+ const parentName = (() => {
277
+ if (process.env.PEERTABLE_PARENT_NAME) return process.env.PEERTABLE_PARENT_NAME
278
+ try {
279
+ const watch = JSON.parse(readFileSync(join(proj, '.team', 'parent-watch.json'), 'utf8'))
280
+ return typeof watch.parent === 'string' ? watch.parent : null
281
+ } catch { return null }
282
+ })()
283
+ const PATROL_ESCALATE_AFTER = 3 // 連続催促がこの回数に達したら親へ縮退疑いを1回通報する
275
284
  const patrolLastNag = new Map() // seat -> epoch_ms
285
+ const patrolNagStreak = new Map() // seat -> 連続催促数(催促条件が消えたらリセット)
286
+ const patrolEscalated = new Set() // 同一縮退エピソードでの親通報は1回だけ
276
287
  const busyStartedAt = new Map() // seat -> epoch_ms(このbridgeプロセスが観測した最後のターン開始・pane基準)
277
288
  const paneLast = new Map() // seat -> 直前周期のpane生status(番犬系専用。表示合成とは分離)
278
289
  const paneJobCpuSeconds = new Map() // seat -> 前周期の非足場子孫の累積CPU秒
@@ -303,8 +314,32 @@ async function patrolClaims() {
303
314
  lastBusyStartAt: seat => busyStartedAt.get(seat) ?? null,
304
315
  now, lastNag: patrolLastNag, nagIntervalMs: PATROL_NAG_INTERVAL_MS,
305
316
  })
317
+ // 催促対象から外れた席は縮退エピソード終了とみなし、計数と通報記録を消す
318
+ const targetSeats = new Set(targets.map(t => t.seat))
319
+ for (const seat of [...patrolNagStreak.keys()]) {
320
+ if (!targetSeats.has(seat)) { patrolNagStreak.delete(seat); patrolEscalated.delete(seat) }
321
+ }
306
322
  for (const { seat, task } of targets) {
307
323
  patrolLastNag.set(seat, now)
324
+ const streak = (patrolNagStreak.get(seat) ?? 0) + 1
325
+ patrolNagStreak.set(seat, streak)
326
+ // 催促に空返事を続ける縮退(実被弾 2026-08-30: 「作業を続けます」と返すだけの席へ
327
+ // 1時間催促を繰り返し、誰にも知られず空転した)。3回で親へ1回だけ通報する。
328
+ // 親宛DMはparent-watchが即時に親を起こす
329
+ if (streak >= PATROL_ESCALATE_AFTER && !patrolEscalated.has(seat)) {
330
+ patrolEscalated.add(seat)
331
+ try {
332
+ await fetch(`${url}/api/${encodeURIComponent(room)}/messages`, {
333
+ method: 'POST',
334
+ headers: { 'Content-Type': 'application/json', ...(token ? { 'X-Peertable-Token': token } : {}) },
335
+ body: JSON.stringify({ from: 'alarm', to: parentName ?? 'bell',
336
+ body: `[縮退疑い] ${seat} は工程 ${task} を保有したまま、継続催促${streak}回に停止宣言も進捗も返していない。空返事ループの可能性が高い。席の再起動を検討すること` }),
337
+ })
338
+ console.error(`seat-status-bridge: 縮退疑いを親へ通報した(${seat} / ${task} / 催促${streak}回)`)
339
+ } catch (e) {
340
+ console.error(`seat-status-bridge: 縮退通報に失敗: ${e.message}`)
341
+ }
342
+ }
308
343
  try {
309
344
  const res = await fetch(`${url}/api/${encodeURIComponent(room)}/messages`, {
310
345
  method: 'POST',
@@ -54,8 +54,13 @@
54
54
 
55
55
  ## 工程が変わった時の mission
56
56
 
57
+ **mission はフェーズ・campaign 全体での自分の担いを書く欄である**(例:「atlas-casework の受入監査担当」
58
+ 「fact-watch 実装の主担当」)。**今やっている作業・待機状態・進捗を書かない**——現在作業は room 発言
59
+ ([claim]/[引受] 等)からサーバーが機械導出して別に表示する(オーナー裁定 2026-08-30:
60
+ 「ミッションはフェーズや工程全体として見たときのミッション。今やってることを書く場所じゃない」)。
57
61
  着席時の mission は起動スナップショットである。campaign / plan が次のフェーズへ進んだら、
58
- 自分で更新する。親に依頼しない。席は再起動しない。
62
+ 自分で更新する。親に依頼しない。席は再起動しない。更新は**フェーズの変わり目だけ**であり、
63
+ 工程・作業のたびに書き換えない。
59
64
 
60
65
  ```
61
66
  env -u PEERTABLE_POST_TOKEN "$(npm root -g)/peertable/skill/scripts/set-mission.sh" . "$PEERTABLE_MEMBER" "<新しい使命>"