peertable 0.8.44 → 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 +1 -1
- package/room/client.mjs +1 -1
- package/room/server.mjs +6 -7
- package/skill/SKILL.md +1 -1
- package/skill/scripts/seat-status-bridge.mjs +35 -0
- package/skill/templates/member.md +6 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "peertable",
|
|
3
|
-
"version": "0.8.
|
|
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.
|
|
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/room/server.mjs
CHANGED
|
@@ -598,9 +598,9 @@ const UI = room => `<!doctype html><html lang="ja"><head><meta charset="utf-8"><
|
|
|
598
598
|
.bridgewarn:empty{display:none}
|
|
599
599
|
.chip.has-meta{cursor:pointer}
|
|
600
600
|
/* 稼働状態の点。報告が途絶えたら unknown(中空)へ落として、古い状態を出し続けない */
|
|
601
|
-
.chip .
|
|
602
|
-
.chip .
|
|
603
|
-
.chip .activity{display:block;
|
|
601
|
+
.chip .id{display:inline-grid;grid-template-columns:min-content}
|
|
602
|
+
.chip .nm{display:inline-flex;align-items:center;gap:5px;white-space:nowrap}
|
|
603
|
+
.chip .activity{display:block;width:0;min-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--dim);font-size:10px;font-weight:500}
|
|
604
604
|
.chip .st{flex:none;display:inline-block;width:7px;height:7px;border-radius:50%;background:var(--dim)}
|
|
605
605
|
.chip .st.busy{background:var(--busy)}
|
|
606
606
|
.chip .st.idle{background:var(--idle)}
|
|
@@ -610,7 +610,7 @@ const UI = room => `<!doctype html><html lang="ja"><head><meta charset="utf-8"><
|
|
|
610
610
|
.metapop{position:fixed;z-index:20;background:var(--surface);border:1px solid var(--line);border-radius:10px;padding:8px 10px;font-size:12px;box-shadow:0 6px 20px rgba(0,0,0,.18);max-width:70vw}
|
|
611
611
|
.metapop .metaname{font-weight:600;margin-bottom:2px}
|
|
612
612
|
.metapop .metaline{color:var(--dim)}
|
|
613
|
-
.chip{position:relative;flex:none;display:flex;align-items:center;gap:7px;
|
|
613
|
+
.chip{position:relative;flex:none;display:flex;align-items:center;gap:7px;padding:6px 11px 6px 6px;border:1px solid var(--line);border-radius:12px;background:var(--surface);font-size:12px;font-weight:600}
|
|
614
614
|
.chip .av{width:22px;height:22px;font-size:11px;flex:none}
|
|
615
615
|
.chip .id{display:flex;flex-direction:column;gap:1px;min-width:0;line-height:1.25}
|
|
616
616
|
.chip.recent{border-color:hsl(var(--h) var(--sat) var(--edge))}
|
|
@@ -840,11 +840,10 @@ async function refreshMembers(){
|
|
|
840
840
|
const id=el('span','id')
|
|
841
841
|
const nameRow=el('span','nm',m.name)
|
|
842
842
|
nameRow.appendChild(el('span','st '+(st??'unknown')))
|
|
843
|
-
nameRow.appendChild(el('span','state-label',stateText))
|
|
844
843
|
id.appendChild(nameRow)
|
|
845
|
-
id.appendChild(el('span','activity',
|
|
844
|
+
id.appendChild(el('span','activity',rolesText||'役割未設定'))
|
|
846
845
|
c.appendChild(id)
|
|
847
|
-
c.setAttribute('aria-label',m.name+'、'+stateText+'、'+(
|
|
846
|
+
c.setAttribute('aria-label',m.name+'、'+stateText+'、'+(rolesText||'役割未設定'))
|
|
848
847
|
// タップ環境には hover が無いので、押した時に同じ内容を出す(ホバーは title が担う)
|
|
849
848
|
if(meta.length){c.classList.add('has-meta');c.addEventListener('click',ev=>{ev.stopPropagation();showMeta(c,m,meta)})}
|
|
850
849
|
membersEl.appendChild(c)
|
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 更新(席が自分で実行)**:
|
|
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" "<新しい使命>"
|