@cocorograph/hub-agent 0.8.82 → 0.8.84
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/src/main.mjs +21 -1051
- package/src/proc-introspect.mjs +0 -20
- package/src/sibling-inject.mjs +31 -0
- package/src/tmux.mjs +7 -719
- package/src/pane-cli-flag.mjs +0 -30
- package/src/state.mjs +0 -595
package/src/proc-introspect.mjs
CHANGED
|
@@ -107,26 +107,6 @@ export function descendantsOf(rootPid, procMap, children = buildChildren(procMap
|
|
|
107
107
|
return out
|
|
108
108
|
}
|
|
109
109
|
|
|
110
|
-
/**
|
|
111
|
-
* tmux session の pane_pid を取得する (失敗時 null)。
|
|
112
|
-
*/
|
|
113
|
-
export async function getPanePid(sessionName, { tmuxBin = "tmux", execFileImpl = execFileP } = {}) {
|
|
114
|
-
if (!sessionName || /[/\\]/.test(sessionName)) return null
|
|
115
|
-
try {
|
|
116
|
-
const { stdout } = await execFileImpl(tmuxBin, [
|
|
117
|
-
"display-message",
|
|
118
|
-
"-p",
|
|
119
|
-
"-t",
|
|
120
|
-
`${sessionName}:`,
|
|
121
|
-
"-F",
|
|
122
|
-
"#{pane_pid}",
|
|
123
|
-
])
|
|
124
|
-
const n = Number(stdout.trim())
|
|
125
|
-
return Number.isFinite(n) && n > 0 ? n : null
|
|
126
|
-
} catch {
|
|
127
|
-
return null
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
110
|
|
|
131
111
|
/**
|
|
132
112
|
* pane_pid から対話 claude 本体の pid を解決する。
|
package/src/sibling-inject.mjs
CHANGED
|
@@ -88,6 +88,13 @@ export const SIBLING_REQUESTS_DIR =
|
|
|
88
88
|
const RESTART_REQUEST_TIMEOUT_MS = 5_000
|
|
89
89
|
const RESTART_RESULT_POLL_MS = 20
|
|
90
90
|
const SIBLING_SWEEP_DEBOUNCE_MS = 25
|
|
91
|
+
/**
|
|
92
|
+
* fs.watch の取りこぼし保険。macOS の FSEvents は通知を落とす・遅らせることがあり、通知でしか
|
|
93
|
+
* 再走査しないと、置かれた要求が次の別通知まで処理されない (2026-09-19 実測: テストで数回に 1 回、
|
|
94
|
+
* 2 秒以内に通知が届かなかった)。二重処理は _ingest の _seen で防ぐので、定期走査と通知走査は
|
|
95
|
+
* 重なってよい。
|
|
96
|
+
*/
|
|
97
|
+
export const SIBLING_BACKSTOP_SWEEP_MS = 1000
|
|
91
98
|
|
|
92
99
|
export const ACTIVE_DELEGATIONS_PER_SESSION_LIMIT = 100
|
|
93
100
|
export const DELEGATION_LEDGER_RETENTION_MS = 24 * 60 * 60 * 1000
|
|
@@ -443,6 +450,10 @@ export class SiblingInjectBridge {
|
|
|
443
450
|
this._seen = new Set()
|
|
444
451
|
this._watcher = null
|
|
445
452
|
this._sweepTimer = null
|
|
453
|
+
this._backstopTimer = null
|
|
454
|
+
this._backstopRunning = false
|
|
455
|
+
/** start/stop の世代。await 中に stop された start が後から watcher を張らないようにする。 */
|
|
456
|
+
this._lifecycleGen = 0
|
|
446
457
|
this._now = now
|
|
447
458
|
this.reviewEvents = new ReviewEventStore(path.join(dir, "review-events"), now)
|
|
448
459
|
this._processKill = processKill
|
|
@@ -718,6 +729,7 @@ export class SiblingInjectBridge {
|
|
|
718
729
|
/** 監視ディレクトリを作成し、既存要求を sweep してから fs.watch を張る。 */
|
|
719
730
|
async start() {
|
|
720
731
|
this.stop()
|
|
732
|
+
const gen = this._lifecycleGen
|
|
721
733
|
try {
|
|
722
734
|
await this._prepareDir()
|
|
723
735
|
} catch (err) {
|
|
@@ -728,6 +740,9 @@ export class SiblingInjectBridge {
|
|
|
728
740
|
return
|
|
729
741
|
}
|
|
730
742
|
await this._sweep({ startup: true })
|
|
743
|
+
// await の間に stop() / 再 start() が走っていたら、この start は watcher を張らない
|
|
744
|
+
// (張ると閉じる持ち主のいない fs.watch が残り、プロセスが終了しなくなる)。
|
|
745
|
+
if (gen !== this._lifecycleGen) return
|
|
731
746
|
try {
|
|
732
747
|
this._watcher = this._watchFn(this.dir, () => {
|
|
733
748
|
// fs.watch のfilenameはOS都合で欠落・統合されうる。tmp作成とrenameを
|
|
@@ -747,6 +762,19 @@ export class SiblingInjectBridge {
|
|
|
747
762
|
"sibling-inject watcher: fs.watch failed, watcher disabled",
|
|
748
763
|
)
|
|
749
764
|
}
|
|
765
|
+
// watcher が張れなかった場合も、定期走査だけで要求を処理し続ける。
|
|
766
|
+
this._backstopTimer = setInterval(() => {
|
|
767
|
+
if (this._backstopRunning) return
|
|
768
|
+
this._backstopRunning = true
|
|
769
|
+
this._sweep()
|
|
770
|
+
.catch((err) => {
|
|
771
|
+
this.logger?.warn({ err: err?.message }, "sibling-inject backstop sweep failed")
|
|
772
|
+
})
|
|
773
|
+
.finally(() => {
|
|
774
|
+
this._backstopRunning = false
|
|
775
|
+
})
|
|
776
|
+
}, SIBLING_BACKSTOP_SWEEP_MS)
|
|
777
|
+
this._backstopTimer.unref?.()
|
|
750
778
|
}
|
|
751
779
|
|
|
752
780
|
/** 起動時 / 取りこぼし保険: dir 内の全要求ファイルを読む。 */
|
|
@@ -1288,6 +1316,7 @@ export class SiblingInjectBridge {
|
|
|
1288
1316
|
|
|
1289
1317
|
/** watcher を閉じる。 */
|
|
1290
1318
|
stop() {
|
|
1319
|
+
this._lifecycleGen += 1
|
|
1291
1320
|
try {
|
|
1292
1321
|
this._watcher?.close()
|
|
1293
1322
|
} catch {
|
|
@@ -1296,6 +1325,8 @@ export class SiblingInjectBridge {
|
|
|
1296
1325
|
this._watcher = null
|
|
1297
1326
|
if (this._sweepTimer) clearTimeout(this._sweepTimer)
|
|
1298
1327
|
this._sweepTimer = null
|
|
1328
|
+
if (this._backstopTimer) clearInterval(this._backstopTimer)
|
|
1329
|
+
this._backstopTimer = null
|
|
1299
1330
|
}
|
|
1300
1331
|
}
|
|
1301
1332
|
|