peertable 0.4.23 → 0.4.25

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.4.23",
3
+ "version": "0.4.25",
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.4.23'
16
+ const MCP_VERSION = '0.4.25'
17
17
  const PKG_ROOT = join(dirname(fileURLToPath(import.meta.url)), '..')
18
18
 
19
19
  const USAGE = `usage:
@@ -164,6 +164,11 @@ await mcp.connect(new StdioServerTransport())
164
164
  // 登録は client の起動ごとに繰り返し起きるので、1回きりの経路に置くと
165
165
  // member の状態が失われた時に二度と戻らない(server 側は渡された欄だけ更新する upsert)
166
166
  function observeSelf() {
167
+ const named = process.env.PEERTABLE_MEMBER ? `peer-${process.env.PEERTABLE_MEMBER}` : ''
168
+ const handed = process.env.PEERTABLE_TMUX_SOCKET
169
+ if (handed && named) {
170
+ return { tmux_socket: handed, tmux_target: named, tmux_namespace: handed }
171
+ }
167
172
  if (!process.env.TMUX) {
168
173
  process.stderr.write('peertable-client: observe unavailable: TMUX 不在\n')
169
174
  return null
@@ -212,7 +217,7 @@ const IDENTITY = Object.fromEntries(Object.entries({
212
217
  mission: process.env.PEERTABLE_MISSION,
213
218
  aiterm_session_id: process.env.AITERM_SESSION_ID,
214
219
  observe,
215
- }).filter(([, v]) => v !== undefined && v !== '' && !(Array.isArray(v) && v.length === 0)))
220
+ }).filter(([, v]) => v != null && v !== '' && !(Array.isArray(v) && v.length === 0)))
216
221
  {
217
222
  const modelsDoc = findModelsDoc()
218
223
  if (!modelsDoc || !existsSync(modelsDoc)) {
@@ -346,6 +351,7 @@ async function runDiagnostics(asJson) {
346
351
  'scripts/ensure-room-mcp.mjs',
347
352
  'scripts/leave-seat.sh',
348
353
  'scripts/change-seat.sh',
354
+ 'scripts/post-message.mjs',
349
355
  // effort 専用の互換入口。change-seat.sh へ委譲するので、どちらが欠けても席設定変更が死ぬ
350
356
  'scripts/change-effort.sh',
351
357
  'scripts/make-plan-input.mjs',
package/room/server.mjs CHANGED
@@ -193,7 +193,10 @@ http.createServer(async (req, res) => {
193
193
  // 素性(vendor/model/effort/role)や稼働状態は、名前以外の欄をそのまま任意欄として持つ。
194
194
  // **渡された欄だけ更新し、渡されなかった欄は既存を保つ**——席の client は `{name}` だけで
195
195
  // 登録するので、これが無いと再接続のたびに素性が消える。`joined_at` は最初の登録を保つ。
196
+ // observe:null は「取れなかった」であって「記述子を消せ」ではない。上書きすると
197
+ // wakeup-bridge が席を飛ばす(2026-08-20 なぎ)。
196
198
  const known = room.members.get(name)
199
+ if (meta.observe == null && known?.observe) delete meta.observe
197
200
  const merged = { joined_at: known?.joined_at ?? new Date().toISOString(), ...known, ...meta }
198
201
  room.members.set(name, merged)
199
202
  saveMembers(room)
package/skill/SKILL.md CHANGED
@@ -186,7 +186,7 @@ witness をどう生成するかは**対象 project 側の作法に従う**(La
186
186
 
187
187
  - 親は MCP を後付けできないため room へは HTTP API 直で参加する:
188
188
  - 登録: `curl -X POST $URL/api/$ROOM/members -H "X-Peertable-Token: $TOKEN" -d '{"name":"bell"}'`
189
- - 発言: `curl -X POST $URL/api/$ROOM/messages -H "X-Peertable-Token: $TOKEN" -d '{"from":"bell","to":"<明示宛先>","body":"..."}'`(複数人は`to`へ名前の配列)
189
+ - 発言: `node skill/scripts/post-message.mjs bell <宛先> '<本文>' | curl -X POST $URL/api/$ROOM/messages -H "X-Peertable-Token: $TOKEN" -H "Content-Type: application/json" --data-binary @-`。Windows の `python3 -c json.dumps` は stdout が cp932 になり日本語本文が部屋へ壊れて保存される。複数人は`to`へ名前の配列(JSON)
190
190
  - 観測: **bell宛DM番犬**(下記)。素の SSE 全量 Monitor は張らない
191
191
  - **親宛DM番犬の仕様**(決定76): room追従は`parent-watch.mjs`一つが所有する。`parent-join.sh`が
192
192
  `.team/parent-watch.json`をprimeし、room SSE・heartbeat・再接続catch-up・`to`/`to_names`判定・
@@ -235,7 +235,7 @@ fi
235
235
 
236
236
  body="[席設定変更] ${parent} が ${name} の ${changes} に変更(${change_method})"
237
237
  [ -z "$reason" ] || body="${body}。理由: ${reason}"
238
- history=$(python3 -c 'import json,sys;print(json.dumps({"from":sys.argv[1],"to":sys.argv[2],"body":sys.argv[3]},ensure_ascii=False))' "$parent" "$name" "$body")
238
+ history=$(node "$(dirname "$0")/post-message.mjs" "$parent" "$name" "$body")
239
239
  history_response=$(env -u PEERTABLE_POST_TOKEN node "$credential_helper" request "$credential_file" POST \
240
240
  "$url/api/$room/messages" "$history") || {
241
241
  echo "SEAT_CHANGE_CHANGED_BUT_HISTORY_FAILED: ${name} は ${changes} で再着席済み、room履歴の記録に失敗" >&2
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env node
2
+ // room へ送る JSON を UTF-8 で出す。python stdout の cp932 は日本語本文を壊す。
3
+ const [from, to, ...rest] = process.argv.slice(2)
4
+ const body = rest.join('\n')
5
+ if (!from || !to || body.length === 0) {
6
+ process.stderr.write('usage: post-message.mjs <from> <to> <body>\n')
7
+ process.exit(2)
8
+ }
9
+ process.stdout.write(`${JSON.stringify({ from, to, body })}\n`)