@cocorograph/hub-agent 0.7.90 → 0.7.91
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 +43 -15
package/package.json
CHANGED
package/src/main.mjs
CHANGED
|
@@ -1146,6 +1146,11 @@ export async function startDaemon({ version, ptyModule, claudeSdk } = {}) {
|
|
|
1146
1146
|
// ready-for-input 判定: claude プロセスの子プロセスを内省し「Stop フック/ツール実行が
|
|
1147
1147
|
// 終わって真に入力可能になった」エッジを検出する (proc-introspect.mjs)。capture-pane は
|
|
1148
1148
|
// Stop フック実行中を観測できないため、これが「stop の早期消灯/誤フラッシュ」の根治。
|
|
1149
|
+
// TUI の tmux session_name → Claude session_id。state loop 起動より**前**に作る。
|
|
1150
|
+
// 後で作ると state loop には undefined が渡り、バックグラウンド時だけ cwd 最新 JSONL
|
|
1151
|
+
// へフォールバックして別会話の context% を表示する。
|
|
1152
|
+
ctx.tuiReboundSessions = new Map()
|
|
1153
|
+
|
|
1149
1154
|
const readinessTracker = new ReadinessTracker()
|
|
1150
1155
|
// claude.tui.bind ハンドラが「生成中か (isArmed)」を参照して、生成中 claude を rebind の
|
|
1151
1156
|
// respawn-pane -k で kill する「謎停止」を防ぐ (生成中ガード)。
|
|
@@ -1360,11 +1365,6 @@ export async function startDaemon({ version, ptyModule, claudeSdk } = {}) {
|
|
|
1360
1365
|
)
|
|
1361
1366
|
}
|
|
1362
1367
|
|
|
1363
|
-
// T04784 会話継続バインディングの冪等性ガード: tmux セッション名 → 最後に --resume で
|
|
1364
|
-
// 載せ替えた Claude session_id。TUI ビューが remount のたびに claude.tui.bind を送っても、
|
|
1365
|
-
// 同じ id への再 respawn (= claude 再起動) を抑止する。
|
|
1366
|
-
ctx.tuiReboundSessions = new Map()
|
|
1367
|
-
|
|
1368
1368
|
// session 回転通知 (T04786 後続) の多重送信ガード: 回転キー (tmux 名 or cwd) →
|
|
1369
1369
|
// 最後に push した new_session_id。閲覧ハートビートは 5s 間隔で来るため、フロントが
|
|
1370
1370
|
// 切替を完了し new id でハートビートを送り直すまでの間に来る余分なハートビートで
|
|
@@ -2295,6 +2295,9 @@ export async function pushImmediateChatState({
|
|
|
2295
2295
|
stalled: false,
|
|
2296
2296
|
turn_active: false,
|
|
2297
2297
|
cli_kind: cliKind,
|
|
2298
|
+
// context_pct がどの会話の値かを明示する。frontend は ID が変わったときだけ
|
|
2299
|
+
// 0% を採用し、同一会話の一時的な 0/null は直近の確定値を保持する。
|
|
2300
|
+
context_session_id: sessionId ?? null,
|
|
2298
2301
|
chat_session_id: sessionId ?? null,
|
|
2299
2302
|
})
|
|
2300
2303
|
}
|
|
@@ -2610,10 +2613,13 @@ export function startStateLoop({ client, plugins, logger, intervalMs, claudeBrid
|
|
|
2610
2613
|
// (cwd, cliKind) キー化により「チャット信号の cliKind == 行の cliKind」が恒真に
|
|
2611
2614
|
// なったので、常に非 null の構造値を送る方が真に厳しい (= 情報量が多い) 上位互換。
|
|
2612
2615
|
//
|
|
2613
|
-
//
|
|
2614
|
-
//
|
|
2616
|
+
// context_session_id は「この context_pct がどの会話の値か」。チャットの session/thread を
|
|
2617
|
+
// 優先し、Claude TUI 専用行では bind 済みの session_id(fresh は fresh:<request_id>)を使う。
|
|
2618
|
+
// frontend はこれを境界として、新規会話の 0% と同一会話の一時的な 0/null を区別する。
|
|
2615
2619
|
const chatCliKind = sessionCliKind
|
|
2616
|
-
const
|
|
2620
|
+
const contextSessionId =
|
|
2621
|
+
chat?.sessionId ??
|
|
2622
|
+
(sessionCliKind === "claude" ? boundSessions?.get(s.session_name) ?? null : codexThreadId)
|
|
2617
2623
|
|
|
2618
2624
|
const prev = lastByName.get(s.session_name)
|
|
2619
2625
|
if (
|
|
@@ -2627,7 +2633,7 @@ export function startStateLoop({ client, plugins, logger, intervalMs, claudeBrid
|
|
|
2627
2633
|
prev.stalled !== stalled ||
|
|
2628
2634
|
prev.turn_active !== turnActive ||
|
|
2629
2635
|
prev.cli_kind !== chatCliKind ||
|
|
2630
|
-
prev.
|
|
2636
|
+
prev.context_session_id !== contextSessionId
|
|
2631
2637
|
) {
|
|
2632
2638
|
lastByName.set(s.session_name, {
|
|
2633
2639
|
status,
|
|
@@ -2639,7 +2645,9 @@ export function startStateLoop({ client, plugins, logger, intervalMs, claudeBrid
|
|
|
2639
2645
|
stalled,
|
|
2640
2646
|
turn_active: turnActive,
|
|
2641
2647
|
cli_kind: chatCliKind,
|
|
2642
|
-
|
|
2648
|
+
context_session_id: contextSessionId,
|
|
2649
|
+
// 旧クライアント互換。新規 consumer は context_session_id を使う。
|
|
2650
|
+
chat_session_id: contextSessionId,
|
|
2643
2651
|
})
|
|
2644
2652
|
// 計装 (2026-06-19, 既定 OFF=2026-06-20): 状態変化時に値を記録する。常時 info はログ肥大の
|
|
2645
2653
|
// 主因のため HUB_AGENT_STATE_TRACE=1 のときだけ出す。childBusy/outputActive を分けて出し、
|
|
@@ -2658,7 +2666,7 @@ export function startStateLoop({ client, plugins, logger, intervalMs, claudeBrid
|
|
|
2658
2666
|
context_pct: contextPct,
|
|
2659
2667
|
turn_active: turnActive,
|
|
2660
2668
|
cli_kind: chatCliKind,
|
|
2661
|
-
|
|
2669
|
+
context_session_id: contextSessionId,
|
|
2662
2670
|
},
|
|
2663
2671
|
"session.state push",
|
|
2664
2672
|
)
|
|
@@ -2680,9 +2688,11 @@ export function startStateLoop({ client, plugins, logger, intervalMs, claudeBrid
|
|
|
2680
2688
|
turn_active: turnActive,
|
|
2681
2689
|
// cli_kind (T05945): セッション名由来の構造値 ('claude' | 'codex')。frontend の
|
|
2682
2690
|
// 単一セレクタ (useCockpitSessionDisplay) が「この push はどの CLI 行のものか」を
|
|
2683
|
-
// 判定する唯一の軸。
|
|
2691
|
+
// 判定する唯一の軸。context_session_id は context% の会話 ID。
|
|
2684
2692
|
cli_kind: chatCliKind,
|
|
2685
|
-
|
|
2693
|
+
context_session_id: contextSessionId,
|
|
2694
|
+
// 旧クライアント互換。新規 consumer は context_session_id を使う。
|
|
2695
|
+
chat_session_id: contextSessionId,
|
|
2686
2696
|
})
|
|
2687
2697
|
}
|
|
2688
2698
|
// 消滅セッションの GC (perf監査/メモリリーク対策): tmux から消えたセッションの状態 Map を
|
|
@@ -4172,7 +4182,11 @@ async function dispatch(msg, ctx) {
|
|
|
4172
4182
|
// 非 fresh (resume/auto) の bind = ユーザーが既存会話を選んだ → 保留中の +新規 defer は破棄。
|
|
4173
4183
|
if (!fresh) ctx.pendingFreshRespawn.delete(sessionName)
|
|
4174
4184
|
let rebind = { ok: false, skipped: false }
|
|
4175
|
-
|
|
4185
|
+
// 新規会話の 0% は会話切替として扱うため、request_id を送れない旧 client
|
|
4186
|
+
// 経由でも bind ごとに固有IDを作る。空の `fresh:` を再利用すると、2回目以降の
|
|
4187
|
+
// 新規会話が同一会話扱いになり、直前値が残る。
|
|
4188
|
+
const freshBindId = request_id || randomUUID()
|
|
4189
|
+
const bindKey = fresh ? `fresh:${freshBindId}` : targetId
|
|
4176
4190
|
const recordDeferredFresh = () =>
|
|
4177
4191
|
ctx.pendingFreshRespawn.set(sessionName, {
|
|
4178
4192
|
cwd,
|
|
@@ -4281,6 +4295,19 @@ async function dispatch(msg, ctx) {
|
|
|
4281
4295
|
noCache: true,
|
|
4282
4296
|
logger,
|
|
4283
4297
|
})
|
|
4298
|
+
// bind が確定している復帰は、capture-pane の見た目や cwd 最新ファイルでなく
|
|
4299
|
+
// **指定 session_id の JSONL** から context% を即時解決する。fresh はまだ実 ID
|
|
4300
|
+
// が無いため 0% と fresh:<request_id> を対にして送る。
|
|
4301
|
+
const contextSessionId = fresh ? bindKey : targetId
|
|
4302
|
+
const boundContext =
|
|
4303
|
+
targetId && cwd
|
|
4304
|
+
? await jsonlContextForCwd(cwd, targetId).catch(() => null)
|
|
4305
|
+
: null
|
|
4306
|
+
const contextPct = fresh
|
|
4307
|
+
? 0
|
|
4308
|
+
: typeof boundContext?.percent === "number"
|
|
4309
|
+
? boundContext.percent
|
|
4310
|
+
: snap.context_pct
|
|
4284
4311
|
// 【問題1 根治 2026-06-22】配る status はプロセス実体の busy を権威に解決する
|
|
4285
4312
|
// (resolveBindSnapshotStatus)。capture(SPINNER_LINE_RE)の偽陽性に勝たせる。
|
|
4286
4313
|
// - busy=true (ターン進行中): capture gap で snap.status が waiting に化けても
|
|
@@ -4296,7 +4323,8 @@ async function dispatch(msg, ctx) {
|
|
|
4296
4323
|
type: "session.state",
|
|
4297
4324
|
session_name: sessionName,
|
|
4298
4325
|
status: snapStatus,
|
|
4299
|
-
context_pct:
|
|
4326
|
+
context_pct: contextPct,
|
|
4327
|
+
context_session_id: contextSessionId ?? null,
|
|
4300
4328
|
permission_mode: snap.permission_mode,
|
|
4301
4329
|
stable:
|
|
4302
4330
|
!busy && snapStatus !== "processing" && snap.stable === true,
|