peertable 0.8.22 → 0.8.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/LICENSE +21 -21
- package/README.ja.md +128 -128
- package/README.md +164 -164
- package/package.json +48 -47
- package/room/Dockerfile +7 -7
- package/room/client.mjs +17 -6
- package/room/message-bounds.mjs +55 -0
- package/skill/02_models.snapshot.md +103 -103
- package/skill/SKILL.md +265 -265
- package/skill/launchd/dev.kitepon.peertable-bridges.plist +20 -20
- package/skill/scripts/agent-pane-status.mjs +6 -0
- package/skill/scripts/alarm-bridge.mjs +28 -11
- package/skill/scripts/alarm-condition.mjs +7 -0
- package/skill/scripts/alarm-set.sh +22 -10
- package/skill/scripts/alarm-write.mjs +27 -0
- package/skill/scripts/archive-room-log.py +0 -0
- package/skill/scripts/bridge-record-live.mjs +0 -0
- package/skill/scripts/change-effort.sh +0 -0
- package/skill/scripts/change-seat.sh +0 -0
- package/skill/scripts/claude-dialog.mjs +4 -1
- package/skill/scripts/codex-dialog.mjs +18 -5
- package/skill/scripts/codex-parent-watch.sh +0 -0
- package/skill/scripts/doctor.sh +0 -0
- package/skill/scripts/ensure-all-bridges.sh +0 -0
- package/skill/scripts/ensure-bridge.sh +19 -6
- package/skill/scripts/ensure-codex-room-mcp.mjs +0 -0
- package/skill/scripts/ensure-project-runtime.sh +13 -0
- package/skill/scripts/ensure-room-mcp.mjs +0 -0
- package/skill/scripts/external-pane.mjs +0 -0
- package/skill/scripts/grok-seat-config.mjs +47 -0
- package/skill/scripts/kickoff-gate.mjs +0 -0
- package/skill/scripts/launch-seat.sh +74 -65
- package/skill/scripts/leave-seat.sh +0 -0
- package/skill/scripts/make-plan-input.mjs +0 -0
- package/skill/scripts/parent-join.sh +0 -0
- package/skill/scripts/parent-watch.mjs +2 -3
- package/skill/scripts/platform/windows/build-bridge-command.mjs +7 -2
- package/skill/scripts/resolve-seat-placement.mjs +0 -0
- package/skill/scripts/resume.sh +2 -9
- package/skill/scripts/runtime-contract.test.mjs +158 -0
- package/skill/scripts/runtime-digest.mjs +25 -0
- package/skill/scripts/seat-status-bridge.mjs +2 -2
- package/skill/scripts/seat-usage.mjs +8 -0
- package/skill/scripts/set-mission.sh +0 -0
- package/skill/scripts/setup.sh +3 -6
- package/skill/scripts/teardown.sh +0 -0
- package/skill/scripts/tmux-at.bash +22 -22
- package/skill/scripts/upgrade-team-assets.sh +4 -0
- package/skill/scripts/vendors/grok/pane-status.mjs +7 -0
- package/skill/scripts/wakeup-bridge.mjs +36 -10
- package/skill/templates/charter.md +20 -20
- package/skill/templates/mcp.json +5 -5
- package/skill/templates/member-standalone.md +60 -60
- package/skill/templates/member.md +159 -159
- package/skill/templates/parent.md +141 -141
- package/skill/templates/tasks.md +8 -8
|
@@ -1,20 +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>
|
|
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,6 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { classifyPaneTail, paneStatusTail } from './seat-usage.mjs'
|
|
3
|
+
|
|
4
|
+
const chunks = []
|
|
5
|
+
for await (const chunk of process.stdin) chunks.push(chunk)
|
|
6
|
+
process.stdout.write(`${classifyPaneTail(paneStatusTail(Buffer.concat(chunks).toString('utf8')))}\n`)
|
|
@@ -21,6 +21,8 @@ import { join } from 'node:path'
|
|
|
21
21
|
import { promisify } from 'node:util'
|
|
22
22
|
|
|
23
23
|
import { resolvePostToken } from './seat-usage.mjs'
|
|
24
|
+
import { resolveLatticeExecutable } from './seat-usage.mjs'
|
|
25
|
+
import { latticeTaskAvailable } from './alarm-condition.mjs'
|
|
24
26
|
import { observePidCommand } from './seat-identity.mjs'
|
|
25
27
|
import { updateBridgeProgress } from './bridge-record-live.mjs'
|
|
26
28
|
|
|
@@ -53,6 +55,7 @@ if (flag === '--stop') process.exit(0)
|
|
|
53
55
|
|
|
54
56
|
const setup = JSON.parse(readFileSync(join(team, 'setup-state.json'), 'utf8'))
|
|
55
57
|
const { room, server_url: url } = setup
|
|
58
|
+
const lattice = setup.lattice_cli ? resolveLatticeExecutable(setup.lattice_cli) : null
|
|
56
59
|
const token = resolvePostToken(process.env)
|
|
57
60
|
if (!token) { console.error('ALARM_BRIDGE_TOKEN_MISSING: 書込トークンが無い'); process.exit(1) }
|
|
58
61
|
mkdirSync(alarmsDir, { recursive: true })
|
|
@@ -86,23 +89,37 @@ async function tick() {
|
|
|
86
89
|
if (Date.now() < due) continue
|
|
87
90
|
let reg
|
|
88
91
|
try { reg = JSON.parse(readFileSync(file, 'utf8')) } catch { continue } // 書込途中は次周へ
|
|
89
|
-
|
|
90
|
-
|
|
92
|
+
const typed = reg.condition?.type === 'lattice_task_ready'
|
|
93
|
+
const legacy = typeof reg.script === 'string' && reg.script.length > 0
|
|
94
|
+
if (typeof reg.seat !== 'string' || !reg.seat || (!typed && !legacy)) {
|
|
95
|
+
log(`ALARM_REGISTRATION_INVALID: ${entry}(seat/condition が無い)を撤去する`)
|
|
91
96
|
try { unlinkSync(file) } catch {}
|
|
92
97
|
continue
|
|
93
98
|
}
|
|
94
99
|
nextDue.set(file, Date.now() + Math.max(2, Number(reg.interval_s) || 10) * 1000)
|
|
95
100
|
let met = false
|
|
96
101
|
let firedOutput = ''
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
102
|
+
if (typed) {
|
|
103
|
+
if (!lattice) {
|
|
104
|
+
log(`ALARM_CONDITION_EVALUATION_FAILED: ${entry} lattice_cli がsetup-stateに無い`)
|
|
105
|
+
} else {
|
|
106
|
+
try {
|
|
107
|
+
const { stdout } = await run(lattice.command, lattice.argv, { timeout: 30_000, maxBuffer: 1024 * 1024, cwd: proj })
|
|
108
|
+
const status = JSON.parse(stdout)
|
|
109
|
+
met = latticeTaskAvailable(status, reg.condition.task_id, reg.condition.plan_key ?? '')
|
|
110
|
+
} catch (e) {
|
|
111
|
+
log(`ALARM_CONDITION_EVALUATION_FAILED: ${entry} ${e.message.split('\n')[0]}`)
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
} else {
|
|
115
|
+
try {
|
|
116
|
+
const { stdout, stderr } = await run('bash', ['-c', reg.script], { timeout: 30_000, maxBuffer: 1024 * 1024 })
|
|
117
|
+
met = true
|
|
118
|
+
firedOutput = `${stdout ?? ''}${stderr ?? ''}`.trim().slice(0, 300)
|
|
119
|
+
} catch (e) {
|
|
120
|
+
// exit 非0 = 条件未成立(正常)。timeout/spawn 失敗はログへ(成立と区別し、握りつぶさない)
|
|
121
|
+
if (e.killed || e.code === 'ENOENT') log(`条件スクリプトの実行失敗(${entry}): ${e.message}`)
|
|
122
|
+
}
|
|
106
123
|
}
|
|
107
124
|
if (!met) continue
|
|
108
125
|
try {
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
export function latticeTaskAvailable(status, taskId, planKey = '') {
|
|
4
|
+
if (!status || typeof status !== 'object' || typeof taskId !== 'string' || !taskId) return false
|
|
5
|
+
const candidates = [...(status.next_ready ?? []), ...(status.active_set ?? [])]
|
|
6
|
+
return candidates.some(task => task?.task_id === taskId && (!planKey || task?.plan_key === planKey))
|
|
7
|
+
}
|
|
@@ -1,14 +1,25 @@
|
|
|
1
1
|
#!/bin/bash
|
|
2
2
|
# 目覚まし係へ待機解放条件を登録する(席が待機に入る前に使う)。
|
|
3
|
-
# usage: alarm-set.sh <project_dir> <seat> <note> <
|
|
3
|
+
# usage: alarm-set.sh <project_dir> <seat> <note> --lattice-task-ready <task_id> [--plan <plan_key>]
|
|
4
|
+
# alarm-set.sh <project_dir> <seat> <note> <script...> # 外部条件の後方互換
|
|
4
5
|
# script は bash -c で実行され、exit 0 で条件成立とみなされる。
|
|
5
6
|
# **script はシングルクォートで渡すこと**。ダブルクォートだと `$()` や変数が登録側の
|
|
6
7
|
# shell で先に展開され、判定コマンドでなく展開結果が登録される(かえで実測 2026-08-22)。
|
|
7
8
|
# 成立すると席へ「[待機解放条件成立] <note>」が配達され、登録は自動で消える。
|
|
8
9
|
set -eu
|
|
9
10
|
proj="${1:?project_dir}"; seat="${2:?seat}"; note="${3:?note}"; shift 3
|
|
10
|
-
script
|
|
11
|
-
|
|
11
|
+
condition_kind=script
|
|
12
|
+
task_id=""; plan_key=""; script=""
|
|
13
|
+
if [ "${1:-}" = "--lattice-task-ready" ]; then
|
|
14
|
+
condition_kind=lattice_task_ready
|
|
15
|
+
task_id="${2:-}"; shift 2
|
|
16
|
+
[ -n "$task_id" ] || { echo "ALARM_SET_TASK_REQUIRED: task_id が空" >&2; exit 2; }
|
|
17
|
+
if [ "${1:-}" = "--plan" ]; then plan_key="${2:-}"; shift 2; fi
|
|
18
|
+
[ "$#" -eq 0 ] || { echo "ALARM_SET_ARGS_INVALID: 余分な引数 $*" >&2; exit 2; }
|
|
19
|
+
else
|
|
20
|
+
script="$*"
|
|
21
|
+
[ -n "$script" ] || { echo "ALARM_SET_SCRIPT_REQUIRED: 条件スクリプトが空" >&2; exit 2; }
|
|
22
|
+
fi
|
|
12
23
|
# 誤った project path を mkdir -p が幻のツリーとして実体化し、誰も読まない場所へ exit 0 で
|
|
13
24
|
# 登録が「成功」する(実被弾 2026-08-28: worktree cwd からの相対 'poly' が poly/poly/.team/ を
|
|
14
25
|
# 生み、席は登録済みと思って15時間停滞)。目覚まし係が読むのは既存卓の .team だけなので、
|
|
@@ -18,11 +29,12 @@ proj="$(cd -- "$proj" 2>/dev/null && pwd)" || { echo "ALARM_SET_PROJECT_INVALID:
|
|
|
18
29
|
dir="$proj/.team/alarms"
|
|
19
30
|
mkdir -p "$dir"
|
|
20
31
|
id="$(date +%s)-$$"
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
32
|
+
script_dir=$(cd "$(dirname "$0")" && pwd -P)
|
|
33
|
+
if [ "$condition_kind" = lattice_task_ready ]; then
|
|
34
|
+
printf '%s\0%s\0%s\0%s\0%s' "$condition_kind" "$seat" "$note" "$task_id" "$plan_key" \
|
|
35
|
+
| node "$script_dir/alarm-write.mjs" "$dir/$id.json"
|
|
36
|
+
else
|
|
37
|
+
printf '%s\0%s\0%s\0%s' "$condition_kind" "$seat" "$note" "$script" \
|
|
38
|
+
| node "$script_dir/alarm-write.mjs" "$dir/$id.json"
|
|
39
|
+
fi
|
|
28
40
|
echo "ALARM_SET_OK: ${dir}/${id}.json(seat=${seat} note=${note})"
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Git Bash→Windows native processのargv文字コード変換を通さず、UTF-8 stdinでalarmを保存する。
|
|
3
|
+
import { writeFileSync } from 'node:fs'
|
|
4
|
+
|
|
5
|
+
const out = process.argv[2]
|
|
6
|
+
if (!out) throw new Error('ALARM_WRITE_PATH_REQUIRED')
|
|
7
|
+
|
|
8
|
+
const chunks = []
|
|
9
|
+
for await (const chunk of process.stdin) chunks.push(chunk)
|
|
10
|
+
const fields = Buffer.concat(chunks).toString('utf8').split('\0')
|
|
11
|
+
const kind = fields.shift()
|
|
12
|
+
let payload
|
|
13
|
+
if (kind === 'script' && fields.length === 3 && fields.every(value => value.length > 0)) {
|
|
14
|
+
const [seat, note, script] = fields
|
|
15
|
+
payload = { seat, note, script }
|
|
16
|
+
} else if (kind === 'lattice_task_ready' && fields.length === 4
|
|
17
|
+
&& fields.slice(0, 3).every(value => value.length > 0)) {
|
|
18
|
+
const [seat, note, task_id, plan_key] = fields
|
|
19
|
+
payload = { seat, note, condition: { type: 'lattice_task_ready', task_id, ...(plan_key ? { plan_key } : {}) } }
|
|
20
|
+
} else {
|
|
21
|
+
throw new Error('ALARM_WRITE_PAYLOAD_INVALID')
|
|
22
|
+
}
|
|
23
|
+
writeFileSync(out, `${JSON.stringify({
|
|
24
|
+
...payload,
|
|
25
|
+
interval_s: 10,
|
|
26
|
+
created_at: new Date().toISOString(),
|
|
27
|
+
})}\n`, { encoding: 'utf8', mode: 0o600 })
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -19,5 +19,8 @@ const isMain = Boolean(process.argv[1]) && resolve(process.argv[1]) === fileURLT
|
|
|
19
19
|
if (isMain) {
|
|
20
20
|
const chunks = []
|
|
21
21
|
for await (const chunk of process.stdin) chunks.push(chunk)
|
|
22
|
-
|
|
22
|
+
const action = keysForClaudeMcpPane(Buffer.concat(chunks).toString('utf8'))
|
|
23
|
+
if (process.argv.includes('--keys')) {
|
|
24
|
+
if (action) process.stdout.write(`${action.keys.join('\n')}\n`)
|
|
25
|
+
} else process.stdout.write(`${JSON.stringify(action)}\n`)
|
|
23
26
|
}
|
|
@@ -10,19 +10,28 @@ export const COMMAND_APPROVAL_DONT_ASK = "don't ask again"
|
|
|
10
10
|
|
|
11
11
|
export function keysForCodexPane(screen) {
|
|
12
12
|
const text = String(screen ?? '')
|
|
13
|
-
|
|
13
|
+
const lines = text.split(/\r?\n/u).slice(-24)
|
|
14
|
+
const tail = lines.join('\n')
|
|
15
|
+
// scrollbackに残った古いdialogより、現在のbusy表示/通常composerを優先する。
|
|
16
|
+
// active dialog自身の選択肢行(`› 1.`)は通常composerとして数えない。
|
|
17
|
+
const busy = /esc to interrupt/iu.test(tail)
|
|
18
|
+
const idleComposer = lines.some(line => /^\s*›(?:\s*$|\s+(?!\d+\.))/u.test(line))
|
|
19
|
+
&& lines.some(line => /gpt-[\w.-]+/iu.test(line) && line.includes('·'))
|
|
20
|
+
if (busy || idleComposer) return null
|
|
21
|
+
const dialogText = tail
|
|
22
|
+
if (dialogText.includes(MCP_ALLOW_NEEDLE) && dialogText.includes(MCP_ALWAYS_ALLOW)) {
|
|
14
23
|
return { kind: 'mcp-allow', keys: ['Down', 'Down', 'Enter'] }
|
|
15
24
|
}
|
|
16
|
-
if (
|
|
25
|
+
if (dialogText.includes(COMMAND_APPROVAL_NEEDLE) && dialogText.toLowerCase().includes(COMMAND_APPROVAL_DONT_ASK)) {
|
|
17
26
|
return { kind: 'command-approval', keys: ['Down', 'Enter'] }
|
|
18
27
|
}
|
|
19
|
-
if (
|
|
28
|
+
if (dialogText.includes('Hooks need review')) {
|
|
20
29
|
return { kind: 'hooks', keys: ['Down', 'Enter'] }
|
|
21
30
|
}
|
|
22
|
-
if (
|
|
31
|
+
if (dialogText.includes('Update now')) {
|
|
23
32
|
return { kind: 'update', keys: ['Down', 'Enter'] }
|
|
24
33
|
}
|
|
25
|
-
if (
|
|
34
|
+
if (dialogText.includes('Yes, continue') && dialogText.includes('Do you trust the contents of this directory')) {
|
|
26
35
|
return { kind: 'trust', keys: ['Enter'] }
|
|
27
36
|
}
|
|
28
37
|
return null
|
|
@@ -42,5 +51,9 @@ if (isMain) {
|
|
|
42
51
|
if (process.argv.includes('--ready-ok')) {
|
|
43
52
|
process.exit(blocksCodexReady(screen) ? 2 : 0)
|
|
44
53
|
}
|
|
54
|
+
if (process.argv.includes('--keys')) {
|
|
55
|
+
if (action) process.stdout.write(`${action.keys.join('\n')}\n`)
|
|
56
|
+
process.exit(0)
|
|
57
|
+
}
|
|
45
58
|
process.stdout.write(`${JSON.stringify(action)}\n`)
|
|
46
59
|
}
|
|
File without changes
|
package/skill/scripts/doctor.sh
CHANGED
|
File without changes
|
|
File without changes
|
|
@@ -4,6 +4,10 @@ set -euo pipefail
|
|
|
4
4
|
|
|
5
5
|
proj="$1"; name="$2"; shift 2
|
|
6
6
|
case "$name" in seat-status) script="seat-status-bridge.mjs" ;; wakeup) script="wakeup-bridge.mjs" ;; alarm) script="alarm-bridge.mjs" ;; run) echo "ENSURE_BRIDGE_RETIRED: run-bridge は退役した(2026-08-22)。介入は席が自分の Lattice コマンド応答で受け取る" >&2; exit 1 ;; *) echo "usage: ensure-bridge.sh <project> <seat-status|wakeup|alarm> [args...]" >&2; exit 1 ;; esac
|
|
7
|
+
scripts_dir=$(cd "$(dirname "$0")" && pwd -P)
|
|
8
|
+
repo=$(cd "$scripts_dir/../.." && pwd -P)
|
|
9
|
+
peertable_version=$(node -p "require(process.argv[1]).version" "$repo/package.json")
|
|
10
|
+
peertable_runtime_digest=$(node "$scripts_dir/runtime-digest.mjs")
|
|
7
11
|
team="$proj/.team"; record="$team/$name-bridge.json"; log="$team/$name-bridge.log"
|
|
8
12
|
force=false
|
|
9
13
|
if [ "${1:-}" = "--force" ]; then force=true; shift; fi
|
|
@@ -17,7 +21,16 @@ if [ $# -eq 0 ] && [ -f "$record" ]; then
|
|
|
17
21
|
fi
|
|
18
22
|
fi
|
|
19
23
|
if [ -f "$record" ]; then
|
|
20
|
-
if node "$
|
|
24
|
+
if node "$scripts_dir/bridge-record-live.mjs" "$record"; then
|
|
25
|
+
record_version=$(node -e 'const x=require(process.argv[1]);process.stdout.write(x.peertable_version||"")' "$record")
|
|
26
|
+
record_digest=$(node -e 'const x=require(process.argv[1]);process.stdout.write(x.peertable_runtime_digest||"")' "$record")
|
|
27
|
+
if [ "$record_version" = "$peertable_version" ] && [ "$record_digest" = "$peertable_runtime_digest" ]; then exit 0; fi
|
|
28
|
+
echo "${name}-bridge: Peertable ${record_version:-unknown} → ${peertable_version} の現行runtimeへ自動更新する" >&2
|
|
29
|
+
node "$scripts_dir/$script" "$proj" --stop || {
|
|
30
|
+
echo "${name}-bridge: 旧版bridgeを停止できないため更新を中止する" >&2
|
|
31
|
+
exit 1
|
|
32
|
+
}
|
|
33
|
+
fi
|
|
21
34
|
if ! "$force" && grep -q 'WRITE_DENIED' "$log" 2>/dev/null; then echo "${name}-bridge: 前回はWRITE_DENIEDで終了。--forceを指定すること" >&2; exit 1; fi
|
|
22
35
|
fi
|
|
23
36
|
# shellcheck disable=SC1091
|
|
@@ -49,8 +62,8 @@ if [ "$(node -p 'process.platform')" = "win32" ]; then
|
|
|
49
62
|
# psmuxが起動する正規shellはPowerShell 7。POSIXの`env`とMSYS pathを文字列のまま
|
|
50
63
|
# 渡すとnodeへ到達する前に終了するため、Windows nodeに各pathをargvとして変換させ、
|
|
51
64
|
# PowerShell EncodedCommandを一箇所で組み立てる。
|
|
52
|
-
win_command=$(node "$
|
|
53
|
-
"$
|
|
65
|
+
win_command=$(node "$scripts_dir/platform/windows/build-bridge-command.mjs" \
|
|
66
|
+
"$scripts_dir/$script" "$proj" "$log" "$@")
|
|
54
67
|
tmux_at new-session -d -s "$session" "$win_command"
|
|
55
68
|
else
|
|
56
69
|
tmux_at new-session -d -s "$session" "env${env_prefix} node $(dirname "$0")/$script $(printf '%q ' "$proj" "$@") >> $(printf '%q' "$log") 2>&1"
|
|
@@ -60,10 +73,10 @@ for _ in $(seq 1 30); do
|
|
|
60
73
|
# **末尾は本物の改行にする。** `"\\n"` と書くと JS がリテラルの `\`+`n` を足し、
|
|
61
74
|
# record が JSON として壊れる——`--stop` も次回起動も `JSON.parse` で落ちて、
|
|
62
75
|
# 「止められない・建て直せない常駐」ができる(2026-08-11 実測)。一時 file→rename で原子的に。
|
|
63
|
-
node -e 'const fs=require("fs");const p=process.argv[1],a=process.argv.slice(
|
|
76
|
+
node -e 'const fs=require("fs");const p=process.argv[1],version=process.argv[2],digest=process.argv[3],a=process.argv.slice(4);
|
|
64
77
|
const t=`${p}.${process.pid}.tmp`;
|
|
65
|
-
fs.writeFileSync(t,JSON.stringify({...JSON.parse(fs.readFileSync(p,"utf8")),args:a})+"\n");
|
|
66
|
-
fs.renameSync(t,p)' "$record" "$@"
|
|
78
|
+
fs.writeFileSync(t,JSON.stringify({...JSON.parse(fs.readFileSync(p,"utf8")),peertable_version:version,peertable_runtime_digest:digest,args:a})+"\n");
|
|
79
|
+
fs.renameSync(t,p)' "$record" "$peertable_version" "$peertable_runtime_digest" "$@"
|
|
67
80
|
exit 0
|
|
68
81
|
fi
|
|
69
82
|
sleep .5
|
|
File without changes
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# 円卓runtimeを一回の呼出しで現行Peertable版へ収束させる正規入口。
|
|
3
|
+
set -euo pipefail
|
|
4
|
+
|
|
5
|
+
proj="${1:-}"
|
|
6
|
+
[ -n "$proj" ] || { echo "usage: ensure-project-runtime.sh <project_dir>" >&2; exit 2; }
|
|
7
|
+
scripts=$(cd "$(dirname "$0")" && pwd -P)
|
|
8
|
+
|
|
9
|
+
for kind in alarm seat-status wakeup; do
|
|
10
|
+
"$scripts/ensure-bridge.sh" "$proj" "$kind"
|
|
11
|
+
done
|
|
12
|
+
|
|
13
|
+
echo "peertable runtime ready: alarm / seat-status / wakeup"
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Peertable席のGrokをroom専用にする。GROK_HOMEだけではClaude/Cursor互換源を読むため、
|
|
3
|
+
// compatを明示OFFにし、project .mcp.jsonのroom以外もnative高優先設定でdisableする。
|
|
4
|
+
import { chmodSync, mkdirSync, readFileSync, renameSync, writeFileSync } from 'node:fs'
|
|
5
|
+
import { dirname, join, resolve } from 'node:path'
|
|
6
|
+
|
|
7
|
+
const [projectArg, outputArg] = process.argv.slice(2)
|
|
8
|
+
if (!projectArg || !outputArg) throw new Error('GROK_SEAT_CONFIG_ARGS_INVALID')
|
|
9
|
+
const project = resolve(projectArg)
|
|
10
|
+
const output = resolve(outputArg)
|
|
11
|
+
const rootMcp = JSON.parse(readFileSync(join(project, '.mcp.json'), 'utf8'))
|
|
12
|
+
const servers = rootMcp?.mcpServers
|
|
13
|
+
if (!servers || typeof servers !== 'object' || Array.isArray(servers) || !servers.room) {
|
|
14
|
+
throw new Error('GROK_SEAT_ROOM_MCP_MISSING')
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const disabled = Object.keys(servers).filter(name => name !== 'room').sort((a, b) => a.localeCompare(b, 'en'))
|
|
18
|
+
const lines = [
|
|
19
|
+
`disabled_mcp_servers = ${JSON.stringify(disabled)}`,
|
|
20
|
+
'',
|
|
21
|
+
'[ui]',
|
|
22
|
+
'permission_mode = "always-approve"',
|
|
23
|
+
'',
|
|
24
|
+
'[compat.claude]',
|
|
25
|
+
'skills = false',
|
|
26
|
+
'rules = false',
|
|
27
|
+
'agents = false',
|
|
28
|
+
'mcps = false',
|
|
29
|
+
'hooks = false',
|
|
30
|
+
'sessions = false',
|
|
31
|
+
'',
|
|
32
|
+
'[compat.cursor]',
|
|
33
|
+
'skills = false',
|
|
34
|
+
'rules = false',
|
|
35
|
+
'agents = false',
|
|
36
|
+
'mcps = false',
|
|
37
|
+
'hooks = false',
|
|
38
|
+
'sessions = false',
|
|
39
|
+
'',
|
|
40
|
+
'[compat.codex]',
|
|
41
|
+
'sessions = false',
|
|
42
|
+
]
|
|
43
|
+
mkdirSync(dirname(output), { recursive: true, mode: 0o700 })
|
|
44
|
+
const temp = `${output}.${process.pid}.tmp`
|
|
45
|
+
writeFileSync(temp, `${lines.join('\n')}\n`, { encoding: 'utf8', mode: 0o600 })
|
|
46
|
+
chmodSync(temp, 0o600)
|
|
47
|
+
renameSync(temp, output)
|
|
File without changes
|