@cocorograph/hub-agent 0.8.18 → 0.8.20

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/src/tmux.mjs CHANGED
@@ -23,12 +23,8 @@ import { fileURLToPath } from "node:url"
23
23
 
24
24
  import { ensureClaudeMd } from "./claude-md.mjs"
25
25
  import { syncClaudeMdWithHub } from "./claude-md-sync.mjs"
26
- import {
27
- capturePane,
28
- detectInputBoxText,
29
- detectSessionState,
30
- getSessionCwd,
31
- } from "./state.mjs"
26
+ import { detectSessionState, getSessionCwd } from "./state.mjs"
27
+ import { shouldLaunchPaneCli } from "./pane-cli-flag.mjs"
32
28
  import { baseSessionName, sessionNameFor } from "./session-names.mjs"
33
29
  import { boundSessionId, getSessionUsages, isFreshUnboundBind, jsonlContextForCwd } from "./usage.mjs"
34
30
 
@@ -510,25 +506,9 @@ export function composeClaudeCmdFromOptions(opts = {}) {
510
506
 
511
507
  const DEFAULT_CLAUDE_CMD = buildClaudeCmd()
512
508
 
513
- /**
514
- * tmux pane で CLI (claude / codex) の TUI を起動してよいかを判定する。
515
- *
516
- * **既定は false**(pane は素のシェルのまま)。Cockpit のターミナルモードは
517
- * 2026-07-03 に封印済みで、通常運用は常にチャットモード (Agent SDK / codex
518
- * app-server) になった。それでも createSession は pane で TUI を起動し続けていたため、
519
- * **誰も見ていない CLI が常駐**する。実測 (2026-08-01 中村さん端末): tmux セッション
520
- * 33 個に対して pane の `claude` プロセス 31 個・合計 RSS 1.7 GB。
521
- *
522
- * `HUB_AGENT_TMUX_LAUNCH_CLI=1` のときだけ従来どおり起動する(デバッグ・TUI を
523
- * 意図的に使いたいときの逃げ道)。呼び出し元ごとに挙動を変えないため、判定は
524
- * この 1 箇所 (createSession 内) だけで行い、opts では上書きさせない。
525
- *
526
- * @param {NodeJS.ProcessEnv} [env]
527
- * @returns {boolean}
528
- */
529
- export function shouldLaunchPaneCli(env = process.env) {
530
- return env?.HUB_AGENT_TMUX_LAUNCH_CLI === "1"
531
- }
509
+ // 判定の実体は ./pane-cli-flag.mjs (state.mjs との循環 import を避けるため分離)。
510
+ // ここからの re-export は後方互換 (既存の `from "./tmux.mjs"` を壊さない)。
511
+ export { shouldLaunchPaneCli }
532
512
 
533
513
  function tmuxBin(opts = {}) {
534
514
  return opts.tmuxBin || DEFAULT_TMUX_BIN
@@ -797,7 +777,7 @@ export async function killManySessions(names, opts = {}) {
797
777
  *
798
778
  * ⚠️ **既定では pane に CLI (claude / codex) を起動しない**(pane は素のシェルのまま)。
799
779
  * Cockpit の通常運用はチャットモードで、pane の TUI は誰も見ないまま常駐して
800
- * メモリを食うだけだったため (詳細は shouldLaunchPaneCli の JSDoc)。
780
+ * メモリを食うだけだったため (詳細は `pane-cli-flag.mjs` の shouldLaunchPaneCli の JSDoc)。
801
781
  * `HUB_AGENT_TMUX_LAUNCH_CLI=1` のときだけ従来どおり CLI を send-keys する。
802
782
  *
803
783
  * - 同名 session が既にあれば 'duplicate session' throw
@@ -1165,74 +1145,6 @@ export function injectCodexHomeEnv(codexCmd, codexHome) {
1165
1145
 
1166
1146
  const _delay = (ms) => new Promise((r) => setTimeout(r, ms))
1167
1147
 
1168
- /**
1169
- * `/model` / `/effort` 切替時に claude TUI が出す確認ダイアログを検知する正規表現。
1170
- *
1171
- * claude v2.1.170 実機確認 (2026-06-10): 会話に出力済みの履歴 (prior output) があると、
1172
- * モデル/effort 切替は即時反映されず確認ダイアログを挟む。ダイアログは:
1173
- * - タイトル: "Switch model?" / "Change effort level?"
1174
- * - 本文: "This conversation is cached for the current model. Switching to … means the
1175
- * full history gets re-read on your next message."
1176
- * - 選択肢: "Yes, switch to …" (デフォルトハイライト) / "No, go back"
1177
- * デフォルトが確定側なので Enter 1 回で承認できる。複数マーカーのいずれかで判定する
1178
- * (文言の小変更に多少強くする)。
1179
- */
1180
- const SWITCH_CONFIRM_DIALOG_RE =
1181
- /Switch model\?|Change effort level\?|Yes, switch to|No, go back|full history gets re-read/i
1182
-
1183
- /**
1184
- * `/model` / `/effort` の確認ダイアログを「描画を検知してから」Enter で畳む。
1185
- *
1186
- * 旧実装は本文確定 Enter の一定時間後に盲打ちで追い Enter を 1 回送っていたが、確認
1187
- * ダイアログのレンダはコマンド確定から遅延することがあり (TUI の全画面再描画ラグ)、
1188
- * 固定待ちの Enter がダイアログ描画前に着弾して取りこぼされ、ダイアログが残ったまま
1189
- * 次の入力の Enter を吸収する事故になっていた。代わりにペインを短周期で読み、ダイアログ
1190
- * が実際に描画されたのを確認してから Enter を送り、消えるまで数回リトライする。ダイアログ
1191
- * が出ない場合 (prior output 無し = 即時反映) は余計な Enter を送らない (空 Enter が
1192
- * 別の場面で誤確定するのを避ける)。ベストエフォート。
1193
- *
1194
- * タイミングは opts で上書きできる (テストで短縮するため):
1195
- * - confirmAppearMs: ダイアログ出現を待つ上限 (既定 2400ms)
1196
- * - confirmPollMs: 出現待ちのポーリング間隔 (既定 150ms)
1197
- * - confirmDismissMs: 承認後にダイアログ消失を待つ上限 (既定 2000ms)
1198
- *
1199
- * @param {string} bin tmux バイナリパス
1200
- * @param {string} name tmux セッション名
1201
- * @param {{logger?:object,tmuxBin?:string,confirmAppearMs?:number,confirmPollMs?:number,confirmDismissMs?:number}} opts
1202
- * @returns {Promise<boolean>} 確認ダイアログを承認したら true
1203
- */
1204
- async function _confirmSwitchDialog(bin, name, opts) {
1205
- const appearMs = opts.confirmAppearMs ?? 2400
1206
- const pollMs = opts.confirmPollMs ?? 150
1207
- const dismissMs = opts.confirmDismissMs ?? 2000
1208
- // ダイアログ出現待ち: コマンド確定から最大 appearMs 観測する (レンダ遅延の上限想定)。
1209
- const APPEAR_DEADLINE = Date.now() + appearMs
1210
- let appeared = false
1211
- while (Date.now() < APPEAR_DEADLINE) {
1212
- const text = await capturePane(name, { ...opts, noCache: true })
1213
- if (SWITCH_CONFIRM_DIALOG_RE.test(text)) {
1214
- appeared = true
1215
- break
1216
- }
1217
- await _delay(pollMs)
1218
- }
1219
- if (!appeared) return false // prior output 無し = 即時反映済み。追い Enter 不要。
1220
-
1221
- // ダイアログが消える (= 承認反映) まで Enter を送ってリトライする。
1222
- const DISMISS_DEADLINE = Date.now() + dismissMs
1223
- while (Date.now() < DISMISS_DEADLINE) {
1224
- await execFileP(bin, ["send-keys", "-t", name, "Enter"])
1225
- await _delay(180)
1226
- const after = await capturePane(name, { ...opts, noCache: true })
1227
- if (!SWITCH_CONFIRM_DIALOG_RE.test(after)) return true
1228
- }
1229
- opts.logger?.warn(
1230
- { session: name },
1231
- "switch confirm dialog still visible after retries",
1232
- )
1233
- return true
1234
- }
1235
-
1236
1148
  /**
1237
1149
  * 離席中キュー投入: 送信待ちメッセージ 1 件を、ブラウザがそのセッションのターミナルを
1238
1150
  * マウントしていなくても tmux send-keys で対話 claude TUI へ投入する (案A の agent 側実体)。