@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/package.json +1 -1
- package/src/claude-md-sync.mjs +704 -57
- package/src/claude-md.mjs +12 -8
- package/src/main.mjs +27 -10
- package/src/pane-cli-flag.mjs +30 -0
- package/src/pointer-context.mjs +196 -0
- package/src/state.mjs +39 -195
- package/src/tmux.mjs +6 -94
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
|
-
|
|
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
|
-
|
|
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 側実体)。
|