peertable 0.8.18 → 0.8.19

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.18",
3
+ "version": "0.8.19",
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.18'
16
+ const MCP_VERSION = '0.8.19'
17
17
  const PKG_ROOT = join(dirname(fileURLToPath(import.meta.url)), '..')
18
18
 
19
19
  const USAGE = `usage:
@@ -22,6 +22,7 @@ import { promisify } from 'node:util'
22
22
 
23
23
  import { resolvePostToken } from './seat-usage.mjs'
24
24
  import { observePidCommand } from './seat-identity.mjs'
25
+ import { updateBridgeProgress } from './bridge-record-live.mjs'
25
26
 
26
27
  const run = promisify(execFile)
27
28
  const [proj, flag] = process.argv.slice(2)
@@ -57,9 +58,10 @@ if (!token) { console.error('ALARM_BRIDGE_TOKEN_MISSING: 書込トークンが
57
58
  mkdirSync(alarmsDir, { recursive: true })
58
59
 
59
60
  const self = observePidCommand(process.pid)
61
+ const startedAt = new Date().toISOString()
60
62
  writeFileSync(record, JSON.stringify({
61
63
  pid: process.pid, start_identity: self.started_identity, room, server_url: url,
62
- started_at: new Date().toISOString(), ready_at: new Date().toISOString(),
64
+ started_at: startedAt, ready_at: startedAt, last_progress_at: startedAt,
63
65
  }) + '\n')
64
66
  const cleanup = () => { try { unlinkSync(record) } catch {} process.exit(0) }
65
67
  process.on('SIGTERM', cleanup)
@@ -117,5 +119,6 @@ async function tick() {
117
119
  log(`alarm-bridge start: room=${room} project=${proj} pid=${process.pid}`)
118
120
  for (;;) {
119
121
  try { await tick() } catch (e) { log(`tick 失敗(続行): ${e.message}`) }
122
+ updateBridgeProgress(record)
120
123
  await sleep(2000)
121
124
  }
@@ -3,7 +3,7 @@
3
3
  // Windows は pid を再利用する。alive な pid だけでは本人ではない
4
4
  // (2026-08-21 実測: wakeup-bridge.json の pid が oracle-mcp に再利用され、
5
5
  // 本物の配達は死んだまま ensure-bridge が起動済みと誤認した)。
6
- import { readFileSync } from 'node:fs'
6
+ import { readFileSync, renameSync, writeFileSync } from 'node:fs'
7
7
  import { resolve } from 'node:path'
8
8
  import { fileURLToPath } from 'node:url'
9
9
 
@@ -21,6 +21,13 @@ export function bridgeRecordLive(record, now = Date.now()) {
21
21
  return (now - at) <= STALE_MS
22
22
  }
23
23
 
24
+ export function updateBridgeProgress(path, now = new Date()) {
25
+ const record = JSON.parse(readFileSync(path, 'utf8'))
26
+ const temporary = `${path}.${process.pid}.tmp`
27
+ writeFileSync(temporary, JSON.stringify({ ...record, last_progress_at: now.toISOString() }) + '\n')
28
+ renameSync(temporary, path)
29
+ }
30
+
24
31
  const invokedDirectly = Boolean(process.argv[1])
25
32
  && resolve(fileURLToPath(import.meta.url)).toLowerCase() === resolve(process.argv[1]).toLowerCase()
26
33
  if (invokedDirectly) {
@@ -25,6 +25,10 @@ fi
25
25
  sock=$(node "$(dirname "$0")/tmux-socket.mjs")
26
26
  room=$(node -e 'process.stdout.write(require(process.argv[1]).room)' "$team/setup-state.json")
27
27
  session="peertable-${name}-${room}"
28
+ # **session が在るだけでは常駐が生きている証拠にならない**(中の node だけ死んで殻が残る)。
29
+ # pid/進捗の生存確認を通れずここへ来たsessionは、Windowsでlogを開いたままの可能性がある。
30
+ # log切詰めより先に畳み、EBUSYを発生させない。
31
+ tmux_at kill-session -t "$session" 2>/dev/null || true
28
32
  # **死んだ記録をここで消す。** 残すと下の loop が前回の `ready_at` を読んで、
29
33
  # 新しい bridge が1バイトも動いていない段階で success を返す——「起動していないのに
30
34
  # 起動したと言う」=この supervisor が塞ぐはずの穴そのものになる。
@@ -41,9 +45,6 @@ for v in PEERTABLE_TMUX_SOCKET PEERTABLE_POST_TOKEN PEERTABLE_CREDENTIAL_FILE PE
41
45
  eval "val=\${$v:-}"
42
46
  [ -n "$val" ] && env_prefix="$env_prefix $v=$(printf '%q' "$val")"
43
47
  done
44
- # **session が在るだけでは常駐が生きている証拠にならない**(中の node だけ死んで殻が残る)。
45
- # 上で pid 生存を確かめて here まで来た=生きていないので、殻は畳んでから立て直す。
46
- tmux_at kill-session -t "$session" 2>/dev/null || true
47
48
  if [ "$(node -p 'process.platform')" = "win32" ]; then
48
49
  # psmuxが起動する正規shellはPowerShell 7。POSIXの`env`とMSYS pathを文字列のまま
49
50
  # 渡すとnodeへ到達する前に終了するため、Windows nodeに各pathをargvとして変換させ、
@@ -28,6 +28,7 @@ import { existsSync, readFileSync, renameSync, writeFileSync, unlinkSync } from
28
28
  import { join } from 'node:path'
29
29
 
30
30
  import { STOP_DECLARATION, attributeJobSession, combineSeatLamp, isPaneHarnessMissing, hasActiveDescendant, subtreeCpuSeconds, patrolTargets, classifyPaneTail, decideBridgeContinuation, deriveMissingSession, isPaneProcessStopped, parsePaneTokenHint, resolveLatticeExecutable, resolvePostToken, resolveSeatObservation, resolveTmuxSocket, supportsMemberObservation, tmuxArgv, tmuxPanePid } from './seat-usage.mjs'
31
+ import { updateBridgeProgress } from './bridge-record-live.mjs'
31
32
 
32
33
  const args = process.argv.slice(2)
33
34
  const proj = args[0]
@@ -381,7 +382,8 @@ function recordReady() {
381
382
  readyRecorded = true
382
383
  const record = JSON.parse(readFileSync(pidPath, 'utf8'))
383
384
  const temporary = `${pidPath}.${process.pid}.tmp`
384
- writeFileSync(temporary, JSON.stringify({ ...record, ready_at: new Date().toISOString() }) + '\n')
385
+ const readyAt = new Date().toISOString()
386
+ writeFileSync(temporary, JSON.stringify({ ...record, ready_at: readyAt, last_progress_at: readyAt }) + '\n')
385
387
  renameSync(temporary, pidPath)
386
388
  }
387
389
 
@@ -484,6 +486,7 @@ let provenWritable = false
484
486
  async function guardedTick() {
485
487
  await beatBridge()
486
488
  const { attempted, failed } = await tick() ?? NOTHING_ATTEMPTED
489
+ updateBridgeProgress(pidPath)
487
490
  const decided = decideBridgeContinuation({ attempted, failed, provenWritable, failedTicks, limit: FAILED_TICK_LIMIT })
488
491
  provenWritable = decided.provenWritable
489
492
  failedTicks = decided.failedTicks