peertable 0.8.2 → 0.8.4
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/skill/scripts/parent-join.sh +4 -0
- package/skill/scripts/parent-watch.mjs +25 -1
- package/skill/scripts/platform/windows/parent-member-json.mjs +7 -0
- package/skill/scripts/platform/windows/resolve-lattice-command.mjs +9 -0
- package/skill/scripts/seat-status-bridge.mjs +3 -5
- package/skill/scripts/seat-usage.mjs +2 -7
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "peertable",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.4",
|
|
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.4'
|
|
17
17
|
const PKG_ROOT = join(dirname(fileURLToPath(import.meta.url)), '..')
|
|
18
18
|
|
|
19
19
|
const USAGE = `usage:
|
|
@@ -31,6 +31,9 @@ if [ -z "$parent_harness" ] && [ -n "$model" ]; then
|
|
|
31
31
|
claude*|opus*|sonnet*|haiku*|fable*) parent_harness=claude ;;
|
|
32
32
|
esac
|
|
33
33
|
fi
|
|
34
|
+
if [ "$(node -p 'process.platform')" = win32 ]; then
|
|
35
|
+
member=$(node "$(dirname "$0")/platform/windows/parent-member-json.mjs" "$name" "$model" "$effort" "$parent_harness" "$mission")
|
|
36
|
+
else
|
|
34
37
|
member=$(python3 - "$name" "$model" "$effort" "$parent_harness" "$mission" <<'PY'
|
|
35
38
|
import json, sys
|
|
36
39
|
name, model, effort, harness, mission = sys.argv[1:6]
|
|
@@ -50,6 +53,7 @@ body['delivery'] = {'kind': 'parent_watch', 'host': harness or ''}
|
|
|
50
53
|
print(json.dumps(body, ensure_ascii=False))
|
|
51
54
|
PY
|
|
52
55
|
)
|
|
56
|
+
fi
|
|
53
57
|
curl -sf -X POST "$url/api/$room/members" \
|
|
54
58
|
-H "X-Peertable-Token: $PEERTABLE_POST_TOKEN" -H 'content-type: application/json' \
|
|
55
59
|
-d "$member" > /dev/null
|
|
@@ -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 } from './seat-usage.mjs'
|
|
13
|
+
import { resolveLatticeExecutable, resolvePostToken } 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)
|
|
@@ -209,6 +209,24 @@ async function acceptLatticeState(next) {
|
|
|
209
209
|
return true
|
|
210
210
|
}
|
|
211
211
|
|
|
212
|
+
const receiptToken = resolvePostToken(process.env)
|
|
213
|
+
const postedParentReceipts = new Set()
|
|
214
|
+
async function postParentReceipt(seq) {
|
|
215
|
+
if (postedParentReceipts.has(seq)) return
|
|
216
|
+
postedParentReceipts.add(seq)
|
|
217
|
+
try {
|
|
218
|
+
const res = await fetch(`${serverUrl}/api/${encodeURIComponent(room)}/deliveries`, {
|
|
219
|
+
method: 'POST',
|
|
220
|
+
headers: { 'Content-Type': 'application/json', ...(receiptToken ? { 'X-Peertable-Token': receiptToken } : {}) },
|
|
221
|
+
body: JSON.stringify({ seq, recipient: parent, result: 'delivered', reason: 'parent_watch' }),
|
|
222
|
+
})
|
|
223
|
+
if (!res.ok) throw new Error(`HTTP ${res.status}`)
|
|
224
|
+
} catch (error) {
|
|
225
|
+
postedParentReceipts.delete(seq)
|
|
226
|
+
process.stderr.write(`PARENT_RECEIPT_FAILED: seq=${seq} ${error.message}\n`)
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
212
230
|
async function acceptMessage(message) {
|
|
213
231
|
if (!Number.isSafeInteger(message?.seq) || message.seq <= state.last_seq) return false
|
|
214
232
|
const matched = addressedToParent(message)
|
|
@@ -225,6 +243,12 @@ async function acceptMessage(message) {
|
|
|
225
243
|
body: roomUpdate ? (message.body || ROOM_UPDATE_FALLBACK) : message.body,
|
|
226
244
|
message,
|
|
227
245
|
})
|
|
246
|
+
// 親宛の名指しDMは、この中継(writeEvent成功=親の通知ストリームへ入った)をもって配達成立とし、
|
|
247
|
+
// server の配送 receipt へ delivered(reason: parent_watch) を書く(2026-08-25 オーナー裁定)。
|
|
248
|
+
// これが無いと送り手の席から親宛DMが永遠に pending に見え、報告の再記録ループで
|
|
249
|
+
// 席のターンを燃やし続ける(実被弾: mio が報告のたびに「bell配達pending」を再送)。
|
|
250
|
+
// to:"all" は席側配達(wakeup-bridge)が receipt を所有するので書かない。
|
|
251
|
+
if (!roomUpdate) await postParentReceipt(message.seq)
|
|
228
252
|
}
|
|
229
253
|
state = { ...state, last_seq: message.seq, last_event_at: now() }
|
|
230
254
|
saveState(state)
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
const [name, model, effort, harness, mission] = process.argv.slice(2)
|
|
2
|
+
const body = { name, roles: ['統括'], observe: null, delivery: { kind: 'parent_watch', host: harness || '' } }
|
|
3
|
+
if (harness) { body.harness = harness; body.vendor = harness }
|
|
4
|
+
if (model) body.model = model
|
|
5
|
+
if (effort) body.effort = effort
|
|
6
|
+
if (mission) body.mission = mission
|
|
7
|
+
process.stdout.write(`${JSON.stringify(body)}\n`)
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export function resolveWindowsLatticeCommand(cli, exists) {
|
|
2
|
+
const lower = cli.toLowerCase()
|
|
3
|
+
const shim = lower.endsWith('.cmd') || lower.endsWith('.bat') || lower.endsWith('.exe')
|
|
4
|
+
? cli
|
|
5
|
+
: exists(`${cli}.cmd`)
|
|
6
|
+
? `${cli}.cmd`
|
|
7
|
+
: cli
|
|
8
|
+
return { command: process.env.ComSpec || 'cmd.exe', argv: ['/d', '/c', shim, 'todo', 'status', '--json'] }
|
|
9
|
+
}
|
|
@@ -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, combineSeatLamp, hasActiveDescendant, patrolTargets, classifyPaneTail, decideBridgeContinuation, deriveMissingSession, isPaneProcessStopped, parsePaneTokenHint, resolvePostToken, resolveSeatObservation, resolveTmuxSocket, supportsMemberObservation, tmuxArgv, tmuxPanePid } from './seat-usage.mjs'
|
|
30
|
+
import { STOP_DECLARATION, combineSeatLamp, hasActiveDescendant, 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]
|
|
@@ -232,10 +232,8 @@ async function patrolClaims() {
|
|
|
232
232
|
try {
|
|
233
233
|
// doctor.sh と同じ解決規則(LATTICE_CLI env → setup記録 → 既定 'lattice'、Windowsは .cmd 解決)
|
|
234
234
|
const latticeCli = process.env.LATTICE_CLI || (typeof setup.lattice_cli === 'string' && setup.lattice_cli) || 'lattice'
|
|
235
|
-
const
|
|
236
|
-
|
|
237
|
-
: latticeCli
|
|
238
|
-
const out = execFileSync(latticeCommand, ['todo', 'status', '--json'], { cwd: proj, encoding: 'utf8' })
|
|
235
|
+
const lattice = resolveLatticeExecutable(latticeCli)
|
|
236
|
+
const out = execFileSync(lattice.command, lattice.argv, { cwd: proj, encoding: 'utf8' })
|
|
239
237
|
activeTasks = (JSON.parse(out).active_set ?? []).map(t => t.task_id)
|
|
240
238
|
} catch (e) {
|
|
241
239
|
console.error(`seat-status-bridge: claim巡回がLatticeを読めない(今周期は検査しない): ${e.message.split('\n')[0]}`)
|
|
@@ -3,6 +3,7 @@ import { existsSync, readFileSync, readdirSync } from 'node:fs'
|
|
|
3
3
|
import { execFileSync } from 'node:child_process'
|
|
4
4
|
import { homedir, tmpdir } from 'node:os'
|
|
5
5
|
import path, { join } from 'node:path'
|
|
6
|
+
import { resolveWindowsLatticeCommand } from './platform/windows/resolve-lattice-command.mjs'
|
|
6
7
|
|
|
7
8
|
const TOKEN_HINT = /[↓↑]\s*([0-9]+(?:\.[0-9]+)?)\s*([kKmM]?)\s*tokens\b/gu
|
|
8
9
|
|
|
@@ -105,13 +106,7 @@ export function tmuxArgv(extraArgs = [], { socket, env = process.env, platform =
|
|
|
105
106
|
export function resolveLatticeExecutable(cli, { platform = process.platform, exists = existsSync } = {}) {
|
|
106
107
|
if (typeof cli !== 'string' || !cli) return { command: cli, argv: ['todo', 'status', '--json'] }
|
|
107
108
|
if (platform !== 'win32') return { command: cli, argv: ['todo', 'status', '--json'] }
|
|
108
|
-
|
|
109
|
-
const cmd = lower.endsWith('.cmd') || lower.endsWith('.bat') || lower.endsWith('.exe')
|
|
110
|
-
? cli
|
|
111
|
-
: exists(`${cli}.cmd`)
|
|
112
|
-
? `${cli}.cmd`
|
|
113
|
-
: cli
|
|
114
|
-
return { command: process.env.ComSpec || 'cmd.exe', argv: ['/d', '/c', cmd, 'todo', 'status', '--json'] }
|
|
109
|
+
return resolveWindowsLatticeCommand(cli, exists)
|
|
115
110
|
}
|
|
116
111
|
|
|
117
112
|
/** member の自己申告を優先し、無い既存 member だけ旧 session 名へ互換フォールバックする。 */
|