peertable 0.8.11 → 0.8.13
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.
|
|
3
|
+
"version": "0.8.13",
|
|
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.
|
|
16
|
+
const MCP_VERSION = '0.8.13'
|
|
17
17
|
const PKG_ROOT = join(dirname(fileURLToPath(import.meta.url)), '..')
|
|
18
18
|
|
|
19
19
|
const USAGE = `usage:
|
|
@@ -27,7 +27,7 @@ import { execFileSync } from 'node:child_process'
|
|
|
27
27
|
import { existsSync, readFileSync, renameSync, writeFileSync, unlinkSync } from 'node:fs'
|
|
28
28
|
import { join } from 'node:path'
|
|
29
29
|
|
|
30
|
-
import { STOP_DECLARATION, attributeJobSession, combineSeatLamp, hasActiveDescendant, subtreeCpuSeconds, patrolTargets, classifyPaneTail, decideBridgeContinuation, deriveMissingSession, isPaneProcessStopped, parsePaneTokenHint, resolveLatticeExecutable, resolvePostToken, resolveSeatObservation, resolveTmuxSocket, supportsMemberObservation, tmuxArgv, tmuxPanePid } from './seat-usage.mjs'
|
|
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
31
|
|
|
32
32
|
const args = process.argv.slice(2)
|
|
33
33
|
const proj = args[0]
|
|
@@ -114,9 +114,18 @@ function readSeat(member, previous, observedAt) {
|
|
|
114
114
|
const tentativeStatus = classifyPaneTail(tail)
|
|
115
115
|
// pane 自体は生きたまま中の CLI プロセスだけが停止する局面(Lattice pull run の accept hold 等)を
|
|
116
116
|
// 拾う。画面の残像だけでは idle に誤判定するため、idle と読めた時だけ実プロセスの stat を見る。
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
117
|
+
let status = tentativeStatus
|
|
118
|
+
if (tentativeStatus === 'idle') {
|
|
119
|
+
const panePid = tmuxPanePid(target.socket, target.target)
|
|
120
|
+
if (isPaneProcessStopped(panePid)) status = 'dead'
|
|
121
|
+
else {
|
|
122
|
+
// harness死亡でshellだけ残った席(実被弾 2026-08-26: mio)。画面の残像はidleに見える
|
|
123
|
+
try {
|
|
124
|
+
const rows = execFileSync('ps', ['-axo', 'pid=,ppid=,command='], { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] }).split('\n')
|
|
125
|
+
if (isPaneHarnessMissing(rows, Number(panePid))) status = 'dead'
|
|
126
|
+
} catch { /* psが使えない端末では従来判定のまま */ }
|
|
127
|
+
}
|
|
128
|
+
}
|
|
120
129
|
const busySince = status === 'busy' || status === 'blocked'
|
|
121
130
|
? ((previous?.status === 'busy' || previous?.status === 'blocked') && previous.busySince ? previous.busySince : observedAt)
|
|
122
131
|
: null
|
|
@@ -236,6 +236,28 @@ export function tmuxPanePid(socket, target, exec = execFileSync) {
|
|
|
236
236
|
* (`pane_dead=0`)で、末尾の画面は停止直前のまま残るため、`classifyPaneTail` だけでは
|
|
237
237
|
* `idle` と誤判定する。
|
|
238
238
|
*/
|
|
239
|
+
/**
|
|
240
|
+
* paneのshellだけが生きていて中のharnessが死んだ席をdeadと判定する素材(実被弾 2026-08-26:
|
|
241
|
+
* mioのCodexが落ちて素のbashが露出、ランプはidle表示のまま番犬DMがshellへ打鍵され続けた)。
|
|
242
|
+
* pane processがshell(bash/zsh/sh系)で、子プロセスが1つも居なければ、席のharnessは存在しない。
|
|
243
|
+
* pane processがharness本体(shellでない)の場合はこの判定の対象外——それが生きていれば席は生きている。
|
|
244
|
+
*/
|
|
245
|
+
export function isPaneHarnessMissing(psRows, panePid) {
|
|
246
|
+
if (!panePid) return false
|
|
247
|
+
let command = null
|
|
248
|
+
let hasChild = false
|
|
249
|
+
for (const row of psRows) {
|
|
250
|
+
const m = /^\s*(\d+)\s+(\d+)\s+(.+)$/.exec(row)
|
|
251
|
+
if (!m) continue
|
|
252
|
+
if (m[1] === String(panePid)) command = m[3].trim()
|
|
253
|
+
if (m[2] === String(panePid)) hasChild = true
|
|
254
|
+
}
|
|
255
|
+
if (command === null) return false
|
|
256
|
+
const bin = command.split(/\s+/)[0].split('/').pop()
|
|
257
|
+
if (!/^(?:-?bash|-?zsh|-?sh|-?dash|-?ksh)$/.test(bin)) return false
|
|
258
|
+
return !hasChild
|
|
259
|
+
}
|
|
260
|
+
|
|
239
261
|
export function isPaneProcessStopped(panePid, exec = execFileSync) {
|
|
240
262
|
if (!panePid) return false
|
|
241
263
|
try {
|