peertable 0.8.15 → 0.8.16

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.15",
3
+ "version": "0.8.16",
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.8.15'
16
+ const MCP_VERSION = '0.8.16'
17
17
  const PKG_ROOT = join(dirname(fileURLToPath(import.meta.url)), '..')
18
18
 
19
19
  const USAGE = `usage:
@@ -0,0 +1,20 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
+ <plist version="1.0">
4
+ <dict>
5
+ <key>Label</key><string>dev.kitepon.peertable-bridges</string>
6
+ <key>ProgramArguments</key>
7
+ <array>
8
+ <string>/bin/bash</string>
9
+ <string>/Users/kite/Developer/peertable/skill/scripts/ensure-all-bridges.sh</string>
10
+ </array>
11
+ <key>EnvironmentVariables</key>
12
+ <dict>
13
+ <key>PATH</key><string>/opt/homebrew/bin:/usr/bin:/bin:/usr/sbin:/sbin</string>
14
+ </dict>
15
+ <key>RunAtLoad</key><true/>
16
+ <key>StartInterval</key><integer>120</integer>
17
+ <key>StandardOutPath</key><string>/Users/kite/Library/Logs/peertable-bridges.log</string>
18
+ <key>StandardErrorPath</key><string>/Users/kite/Library/Logs/peertable-bridges.log</string>
19
+ </dict>
20
+ </plist>
@@ -0,0 +1,38 @@
1
+ #!/bin/bash
2
+ # launchd(dev.kitepon.peertable-bridges)から2分周期で呼ばれ、稼働中の全円卓のbridgeを
3
+ # 生存保証する。ensure-bridge.sh は生きていれば何もしない冪等な入口なので、この巡回は
4
+ # 「死んだら次の周期で自動再起動」を意味する(オーナー裁定 2026-08-29「毎回手で復活させるな」)。
5
+ # 対象卓の発見は実物(.team/setup-state.json の存在)だけを根拠にする。登録簿は持たない。
6
+ set -u
7
+ # launchd環境にはTMPDIRが無く、tmux socketの既定解決($TMPDIR/claude-tmux-sockets/…)が
8
+ # /tmp側へ落ちて全ensureが失敗する(実被弾 2026-08-29)。macOSの正規per-user tempを自前導出する。
9
+ if [ -z "${TMPDIR:-}" ] && command -v getconf >/dev/null; then
10
+ TMPDIR="$(getconf DARWIN_USER_TEMP_DIR 2>/dev/null || true)"
11
+ [ -n "$TMPDIR" ] && export TMPDIR
12
+ fi
13
+ scripts="$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)"
14
+ for state in /Users/kite/Developer/*/.team/setup-state.json; do
15
+ [ -f "$state" ] || continue
16
+ proj="$(dirname "$(dirname "$state")")"
17
+ bash "$scripts/ensure-bridge.sh" "$proj" seat-status >/dev/null 2>&1 \
18
+ || echo "$(date -u +%FT%TZ) ensure失敗: seat-status $proj"
19
+ bash "$scripts/ensure-bridge.sh" "$proj" alarm >/dev/null 2>&1 \
20
+ || echo "$(date -u +%FT%TZ) ensure失敗: alarm $proj"
21
+ # wakeup は配達先の席名一覧が要る。room 台帳から現行メンバーを実物で読む
22
+ server="$(python3 -c "import json;print(json.load(open('$state'))['server_url'])" 2>/dev/null)"
23
+ room="$(python3 -c "import json;print(json.load(open('$state'))['room'])" 2>/dev/null)"
24
+ if [ -n "$server" ] && [ -n "$room" ]; then
25
+ seats="$(curl -s --max-time 10 "$server/api/$room/members" | python3 -c "
26
+ import json,sys
27
+ try:
28
+ ms=json.load(sys.stdin).get('members',[])
29
+ except Exception:
30
+ ms=[]
31
+ print(' '.join(m['name'] for m in ms if m.get('observe') or m.get('harness')))" 2>/dev/null)"
32
+ if [ -n "$seats" ]; then
33
+ # shellcheck disable=SC2086
34
+ bash "$scripts/ensure-bridge.sh" "$proj" wakeup $seats >/dev/null 2>&1 \
35
+ || echo "$(date -u +%FT%TZ) ensure失敗: wakeup $proj ($seats)"
36
+ fi
37
+ fi
38
+ done
@@ -60,6 +60,11 @@ if tmux_at has-session -t "$target" 2>/dev/null; then
60
60
  fi
61
61
  elif tmux_at list-sessions >/dev/null 2>&1; then
62
62
  : # serverへ到達でき、対象sessionが無い
63
+ elif [ -n "${member_socket:-}" ] && [ ! -S "${member_socket}" ]; then
64
+ # socketファイル自体が消えている=tmux serverごと死んでいる(OS再起動等)。
65
+ # 席のprocessは存在しえないので「畳めない」ではなく「畳む対象が無い」が正
66
+ # (実被弾 2026-08-29: Mac再起動後のresumeが全席でここに落ちて再起動できなかった)
67
+ echo "SEAT_LEAVE_SESSION_GONE: tmux socket消失(${member_socket})。畳む対象なしとして続行" >&2
63
68
  else
64
69
  echo "SEAT_LEAVE_SESSION_UNREADABLE: ${member_socket:-tmux}" >&2
65
70
  failed=1
@@ -10,7 +10,7 @@
10
10
  import { execFileSync } from 'node:child_process'
11
11
  import { existsSync, readFileSync, renameSync, statSync, unlinkSync, writeFileSync } from 'node:fs'
12
12
  import { join } from 'node:path'
13
- import { resolveLatticeExecutable, resolvePostToken } from './seat-usage.mjs'
13
+ import { resolveLatticeExecutable, resolvePostToken, parentWatchShouldNotify } from './seat-usage.mjs'
14
14
  import { addressedToParent as messageAddressedToParent, latticeStaffingChanged, tableStallUpdate } from './parent-watch-logic.mjs'
15
15
 
16
16
  const args = process.argv.slice(2)
@@ -171,6 +171,10 @@ function exitWhenParentStdinCloses() {
171
171
  if (typeof stdin.resume === 'function') stdin.resume()
172
172
  }
173
173
 
174
+ async function logQuiet(event) {
175
+ process.stderr.write(`[quiet] ${JSON.stringify(event)}\n`)
176
+ }
177
+
174
178
  async function writeEvent(event) {
175
179
  await new Promise((resolve, reject) => {
176
180
  process.stdout.write(`${JSON.stringify(event)}\n`, error => error ? reject(error) : resolve())
@@ -197,7 +201,7 @@ async function acceptLatticeState(next) {
197
201
  state = { ...state, lattice: next, last_event_at: now() }
198
202
  saveState(state)
199
203
  if (!changed) return false
200
- await writeEvent({
204
+ await logQuiet({
201
205
  schema: 'peertable.parent-watch-event.v1',
202
206
  type: 'parent_lattice_update',
203
207
  parent,
@@ -232,7 +236,8 @@ async function acceptMessage(message) {
232
236
  const matched = addressedToParent(message)
233
237
  if (matched) {
234
238
  const roomUpdate = message.to === 'all'
235
- await writeEvent({
239
+ const emit = parentWatchShouldNotify(message, roomUpdate) ? writeEvent : logQuiet
240
+ await emit({
236
241
  schema: 'peertable.parent-watch-event.v1',
237
242
  type: roomUpdate ? 'parent_room_update' : 'parent_dm',
238
243
  parent,
@@ -444,3 +444,12 @@ export function subtreeCpuSeconds(psRows, rootPid, { includeChild = () => true,
444
444
  }
445
445
  return total
446
446
  }
447
+
448
+ // ---- 親番犬の「起こす価値」判定(2026-08-29 オーナー裁定「番犬が必要な時だけ呼べ」)----
449
+ // 選別は親のターン(有料)でなく機械(無料)が行う。起こすのは親の行動が要るものだけ。
450
+ const ROUTINE_WAIT_DM = /^\s*\[待機\]/u
451
+ export function parentWatchShouldNotify(message, roomUpdate) {
452
+ const body = String(message?.body ?? '')
453
+ if (roomUpdate) return /全タスク完了|\[オーナー宛/u.test(body)
454
+ return !ROUTINE_WAIT_DM.test(body)
455
+ }