@cocorograph/hub-agent 0.6.95 → 0.6.96
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 +27 -1
- package/src/proc-introspect.mjs +6 -0
package/package.json
CHANGED
package/src/main.mjs
CHANGED
|
@@ -1027,11 +1027,20 @@ function startReadinessLoop({ tracker, logger, intervalMs = 700 }) {
|
|
|
1027
1027
|
// 窓経過後に false へ落ちる (ターン終了後のスピナー固着=症状A を悪化させない短さ)。
|
|
1028
1028
|
const OUTPUT_ACTIVE_MS = Number(process.env.HUB_AGENT_OUTPUT_ACTIVE_MS ?? 8000)
|
|
1029
1029
|
|
|
1030
|
+
// 権威的な「応答停止 (ハング)」判定の無進捗しきい値。ターン進行中 (armed) なのに、実際の
|
|
1031
|
+
// 進捗 (子プロセス実行中 / 出力フロー / ペインのライブ processing) がこの時間継続して観測
|
|
1032
|
+
// されなければ stalled とする。frontend 側の jsonl 無音タイマー (長時間ツールで誤検知し、
|
|
1033
|
+
// 本当のハングでは turnActive クリアにより見逃す) を置き換える正本。frontend の
|
|
1034
|
+
// TURN_STALL_WARN_MS と揃える。
|
|
1035
|
+
const STALL_WARN_MS = Number(process.env.HUB_AGENT_STALL_WARN_MS ?? 90000)
|
|
1036
|
+
|
|
1030
1037
|
function startStateLoop({ client, plugins, logger, intervalMs, claudeBridge, readinessTracker }) {
|
|
1031
1038
|
const lastByName = new Map() // session_name → {status, context_pct}
|
|
1032
1039
|
const lastTurnAtByName = new Map() // session_name → 最後に event ファイル化した turnAt
|
|
1033
1040
|
// (i) session_name → {sig, changedAt}: 出力領域署名の最終変化時刻 (出力フロー検知用)。
|
|
1034
1041
|
const outputFlowByName = new Map()
|
|
1042
|
+
// 権威的 stall 判定: session_name → 最後に「進捗あり」と観測した時刻 (ms)。
|
|
1043
|
+
const lastProgressAtByName = new Map()
|
|
1035
1044
|
let stopped = false
|
|
1036
1045
|
|
|
1037
1046
|
// RC-8: WS 再接続のたびに差分送信の基準 (lastByName) をクリアし、次 tick で全 session.state を
|
|
@@ -1118,6 +1127,20 @@ function startStateLoop({ client, plugins, logger, intervalMs, claudeBridge, rea
|
|
|
1118
1127
|
outputActive = Date.now() - changedAt < OUTPUT_ACTIVE_MS
|
|
1119
1128
|
}
|
|
1120
1129
|
const procBusy = childBusy || outputActive
|
|
1130
|
+
// 権威的 stall 判定。armed (ターン進行中=prompt_submit 受信後 stop/ready 未) なのに
|
|
1131
|
+
// 進捗 (procBusy=子プロセス/出力フロー or ペインの live processing) が STALL_WARN_MS
|
|
1132
|
+
// 継続して無いとき stalled=true。armed でない / 進捗ありのときは進捗時刻を更新して
|
|
1133
|
+
// 無進捗カウントをリセットする。frontend はこれを応答停止バナーの正本に使う。
|
|
1134
|
+
const armed = readinessTracker
|
|
1135
|
+
? readinessTracker.isArmed(s.session_name)
|
|
1136
|
+
: false
|
|
1137
|
+
const nowMs = Date.now()
|
|
1138
|
+
const progressing = procBusy || status === "processing"
|
|
1139
|
+
if (progressing || !armed) {
|
|
1140
|
+
lastProgressAtByName.set(s.session_name, nowMs)
|
|
1141
|
+
}
|
|
1142
|
+
const lastProgressAt = lastProgressAtByName.get(s.session_name) ?? nowMs
|
|
1143
|
+
const stalled = armed && nowMs - lastProgressAt >= STALL_WARN_MS
|
|
1121
1144
|
const prev = lastByName.get(s.session_name)
|
|
1122
1145
|
if (
|
|
1123
1146
|
!prev ||
|
|
@@ -1125,7 +1148,8 @@ function startStateLoop({ client, plugins, logger, intervalMs, claudeBridge, rea
|
|
|
1125
1148
|
prev.context_pct !== contextPct ||
|
|
1126
1149
|
prev.permission_mode !== permissionMode ||
|
|
1127
1150
|
prev.stable !== stable ||
|
|
1128
|
-
prev.proc_busy !== procBusy
|
|
1151
|
+
prev.proc_busy !== procBusy ||
|
|
1152
|
+
prev.stalled !== stalled
|
|
1129
1153
|
) {
|
|
1130
1154
|
lastByName.set(s.session_name, {
|
|
1131
1155
|
status,
|
|
@@ -1133,6 +1157,7 @@ function startStateLoop({ client, plugins, logger, intervalMs, claudeBridge, rea
|
|
|
1133
1157
|
permission_mode: permissionMode,
|
|
1134
1158
|
stable,
|
|
1135
1159
|
proc_busy: procBusy,
|
|
1160
|
+
stalled,
|
|
1136
1161
|
})
|
|
1137
1162
|
client.send({
|
|
1138
1163
|
type: "session.state",
|
|
@@ -1142,6 +1167,7 @@ function startStateLoop({ client, plugins, logger, intervalMs, claudeBridge, rea
|
|
|
1142
1167
|
permission_mode: permissionMode,
|
|
1143
1168
|
stable,
|
|
1144
1169
|
proc_busy: procBusy,
|
|
1170
|
+
stalled,
|
|
1145
1171
|
})
|
|
1146
1172
|
}
|
|
1147
1173
|
}
|
package/src/proc-introspect.mjs
CHANGED
|
@@ -324,6 +324,12 @@ export class ReadinessTracker {
|
|
|
324
324
|
return this.byName.get(name)?.busy ?? false
|
|
325
325
|
}
|
|
326
326
|
|
|
327
|
+
/** ターン進行中か (prompt_submit で arm 後、ready/cap で disarm するまで true)。
|
|
328
|
+
* 生成中・Stop フック中の両方を含む。state loop が権威的な stall 判定に使う。 */
|
|
329
|
+
isArmed(name) {
|
|
330
|
+
return this.byName.get(name)?.armed ?? false
|
|
331
|
+
}
|
|
332
|
+
|
|
327
333
|
/** readiness loop が観測対象に含めるべきか (armed / busy / grace 中)。 */
|
|
328
334
|
isActive(name) {
|
|
329
335
|
const s = this.byName.get(name)
|