@cocorograph/hub-agent 0.6.62 → 0.6.64
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 +39 -1
- package/src/tmux.mjs +53 -0
- package/src/tui-permission-bridge.mjs +3 -0
package/package.json
CHANGED
package/src/main.mjs
CHANGED
|
@@ -69,6 +69,7 @@ import {
|
|
|
69
69
|
removeWorktree as removeWorktreeDir,
|
|
70
70
|
resumeWithMessage,
|
|
71
71
|
setTmuxGlobalEnv,
|
|
72
|
+
setTuiEffort,
|
|
72
73
|
setTuiModel,
|
|
73
74
|
} from "./tmux.mjs"
|
|
74
75
|
import { TuiPermissionBridge } from "./tui-permission-bridge.mjs"
|
|
@@ -572,7 +573,7 @@ export async function startDaemon({ version, ptyModule, claudeSdk } = {}) {
|
|
|
572
573
|
const tuiPermissionBridge = new TuiPermissionBridge({ logger })
|
|
573
574
|
tuiPermissionBridge.on(
|
|
574
575
|
"permission",
|
|
575
|
-
({ request_id, session_id, cwd, tool_name, input }) => {
|
|
576
|
+
({ request_id, session_id, cwd, tool_name, input, context_text }) => {
|
|
576
577
|
if (cwd) {
|
|
577
578
|
try {
|
|
578
579
|
recordChatActivity(cwd, { inputPending: true })
|
|
@@ -588,6 +589,8 @@ export async function startDaemon({ version, ptyModule, claudeSdk } = {}) {
|
|
|
588
589
|
request_id,
|
|
589
590
|
tool_name,
|
|
590
591
|
input,
|
|
592
|
+
// 質問/承認カードの直前アシスタント説明 (フック由来。browser がカード上部に表示)。
|
|
593
|
+
context_text: context_text ?? null,
|
|
591
594
|
})
|
|
592
595
|
},
|
|
593
596
|
)
|
|
@@ -1419,6 +1422,39 @@ async function dispatch(msg, ctx) {
|
|
|
1419
1422
|
})()
|
|
1420
1423
|
return
|
|
1421
1424
|
}
|
|
1425
|
+
case "claude.tui.setEffort": {
|
|
1426
|
+
// effort バッジ選択 → 対話 claude TUI へ `/effort <level>` を送って reasoning effort を
|
|
1427
|
+
// 切り替える。setModel と同設計: agent が実キーを送出 → 全ブラウザへ claude.tui.effort を
|
|
1428
|
+
// broadcast し、実際に動いているターミナルの effort を正本として全端末に同期する。
|
|
1429
|
+
// effort は jsonl に記録されないため、この即時 broadcast が唯一の表示根拠になる。
|
|
1430
|
+
const cwd = typeof msg.cwd === "string" ? msg.cwd : ""
|
|
1431
|
+
const sessionName =
|
|
1432
|
+
typeof msg.session_name === "string" ? msg.session_name : ""
|
|
1433
|
+
if (!sessionName) return
|
|
1434
|
+
// effort="" は「auto」= `/effort auto`。frontend へはそのまま空で返し、バッジは auto 表示。
|
|
1435
|
+
const effort = typeof msg.effort === "string" ? msg.effort : ""
|
|
1436
|
+
;(async () => {
|
|
1437
|
+
try {
|
|
1438
|
+
await setTuiEffort(sessionName, effort || "auto", { logger })
|
|
1439
|
+
ctx.client.send({
|
|
1440
|
+
type: "claude.tui.effort",
|
|
1441
|
+
cwd: cwd || undefined,
|
|
1442
|
+
session_name: sessionName,
|
|
1443
|
+
effort,
|
|
1444
|
+
})
|
|
1445
|
+
logger.info(
|
|
1446
|
+
{ session: sessionName, cwd, effort: effort || "(auto)" },
|
|
1447
|
+
"tui effort switched → notified browser",
|
|
1448
|
+
)
|
|
1449
|
+
} catch (err) {
|
|
1450
|
+
logger.warn(
|
|
1451
|
+
{ err: err?.message, session: sessionName },
|
|
1452
|
+
"claude.tui.setEffort failed",
|
|
1453
|
+
)
|
|
1454
|
+
}
|
|
1455
|
+
})()
|
|
1456
|
+
return
|
|
1457
|
+
}
|
|
1422
1458
|
case "claude.tui.probePermission": {
|
|
1423
1459
|
// 読み取り専用の権限モード問い合わせ (cold-load seed)。キーは送らず、ペインを
|
|
1424
1460
|
// 読んで現在の実モードを claude.tui.permission として broadcast するだけ。
|
|
@@ -1501,6 +1537,8 @@ async function dispatch(msg, ctx) {
|
|
|
1501
1537
|
request_id: p.request_id,
|
|
1502
1538
|
tool_name: p.tool_name,
|
|
1503
1539
|
input: p.input,
|
|
1540
|
+
// 再 hydrate でも直前説明を保つ (listPending が payload ごと保持している)。
|
|
1541
|
+
context_text: p.context_text ?? null,
|
|
1504
1542
|
})
|
|
1505
1543
|
}
|
|
1506
1544
|
if (pend.length) {
|
package/src/tmux.mjs
CHANGED
|
@@ -934,6 +934,59 @@ export async function setTuiModel(name, modelArg, opts = {}) {
|
|
|
934
934
|
}
|
|
935
935
|
}
|
|
936
936
|
|
|
937
|
+
/**
|
|
938
|
+
* 対話 claude TUI に `/effort <level>` を送って reasoning effort を切り替える。
|
|
939
|
+
*
|
|
940
|
+
* cockpit の effort バッジ選択 (claude.tui.setEffort) の書込側。モデル切替 (setTuiModel) と
|
|
941
|
+
* 同設計で、frontend は raw pty.data ではなく claude.tui.setEffort を送り、agent 側で本関数を
|
|
942
|
+
* 実行 → 全ブラウザへ claude.tui.effort を broadcast して全端末を実 effort に揃える。
|
|
943
|
+
*
|
|
944
|
+
* `/effort` は引数 (low/medium/high/xhigh/max/auto) を受理し即時反映する (確認プロンプトを
|
|
945
|
+
* 挟まない)。effort 非対応レベルを与えても CLI がモデルの対応上限へ自動フォールバックする。
|
|
946
|
+
* `auto` はモデル既定へリセット。copy-mode に入っているとキーが奪われるので先に抜ける。
|
|
947
|
+
* ベストエフォート。
|
|
948
|
+
*
|
|
949
|
+
* @param {string} name tmux セッション名
|
|
950
|
+
* @param {string} effortArg `/effort` 引数 (low/medium/high/xhigh/max または "auto")
|
|
951
|
+
* @param {{logger?:object,tmuxBin?:string}} [opts]
|
|
952
|
+
* @returns {Promise<{ok:boolean, error?:string}>}
|
|
953
|
+
*/
|
|
954
|
+
export async function setTuiEffort(name, effortArg, opts = {}) {
|
|
955
|
+
const bin = tmuxBin(opts)
|
|
956
|
+
const arg = String(effortArg || "auto").replace(/[\r\n]+/g, " ").trim()
|
|
957
|
+
if (!arg) return { ok: false, error: "empty effort arg" }
|
|
958
|
+
try {
|
|
959
|
+
// copy-mode 等に入っているとキーが奪われるので、入っている時だけ抜ける。
|
|
960
|
+
try {
|
|
961
|
+
const { stdout } = await execFileP(bin, [
|
|
962
|
+
"display-message",
|
|
963
|
+
"-p",
|
|
964
|
+
"-t",
|
|
965
|
+
`${name}:`,
|
|
966
|
+
"-F",
|
|
967
|
+
"#{pane_in_mode}",
|
|
968
|
+
])
|
|
969
|
+
if (stdout.trim() === "1") {
|
|
970
|
+
await execFileP(bin, ["send-keys", "-t", name, "-X", "cancel"])
|
|
971
|
+
}
|
|
972
|
+
} catch {
|
|
973
|
+
// pane_in_mode 取得失敗はベストエフォートで無視。
|
|
974
|
+
}
|
|
975
|
+
// `/effort <level>` をリテラルで送る (-l でキー名解釈・スラッシュ補完の暴発を避ける)。
|
|
976
|
+
await execFileP(bin, ["send-keys", "-t", name, "-l", `/effort ${arg}`])
|
|
977
|
+
await _delay(120)
|
|
978
|
+
// Enter で本文確定 (send-keys の離散イベントなので paste 吸収は起きにくい)。
|
|
979
|
+
await execFileP(bin, ["send-keys", "-t", name, "Enter"])
|
|
980
|
+
return { ok: true }
|
|
981
|
+
} catch (err) {
|
|
982
|
+
opts.logger?.warn(
|
|
983
|
+
{ session: name, effort: arg, err: err?.message },
|
|
984
|
+
"setTuiEffort failed",
|
|
985
|
+
)
|
|
986
|
+
return { ok: false, error: err?.message || String(err) }
|
|
987
|
+
}
|
|
988
|
+
}
|
|
989
|
+
|
|
937
990
|
/**
|
|
938
991
|
* 中断キャンセル後の入力欄復旧 (claude.tui.recoverInput / agent >= 0.6.57)。
|
|
939
992
|
*
|
|
@@ -111,6 +111,9 @@ export class TuiPermissionBridge extends EventEmitter {
|
|
|
111
111
|
cwd: body.cwd ?? null,
|
|
112
112
|
tool_name: body.tool_name ?? "",
|
|
113
113
|
input: body.tool_input ?? {},
|
|
114
|
+
// 質問/承認カードの直前アシスタント説明 (フックが transcript から抽出して同梱)。
|
|
115
|
+
// browser はこれをカード上部に表示し、jsonl tail の到着レースに依らず文脈を読める。
|
|
116
|
+
context_text: body.context_text ?? null,
|
|
114
117
|
}
|
|
115
118
|
// payload も保持する (セッション切替でビュー再マウント時の re-hydrate / listPending 用)。
|
|
116
119
|
this._pending.set(request_id, { payload, at: Date.now() })
|