@cocorograph/hub-agent 0.8.74 → 0.8.75
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/README.md +1 -1
- package/package.json +1 -1
- package/src/hooks.mjs +0 -15
- package/src/main.mjs +4 -69
- package/src/tmux.mjs +0 -23
package/README.md
CHANGED
|
@@ -105,7 +105,7 @@ hub-agent/
|
|
|
105
105
|
│ ├── ws-client.mjs # outbound WSS + reconnect with jitter
|
|
106
106
|
│ ├── claude-stream-bridge.mjs # Claude Agent SDK チャット中継
|
|
107
107
|
│ ├── codex-stream-bridge.mjs # Codex app-server チャット中継
|
|
108
|
-
│ ├── tmux.mjs # tmux
|
|
108
|
+
│ ├── tmux.mjs # tmux list/create/kill
|
|
109
109
|
│ ├── state.mjs # session status / context_pct 検知
|
|
110
110
|
│ ├── skills.mjs # ~/.claude/skills 集計
|
|
111
111
|
│ ├── usage.mjs # Claude Code 使用量集計
|
package/package.json
CHANGED
package/src/hooks.mjs
CHANGED
|
@@ -17,7 +17,6 @@
|
|
|
17
17
|
export const HOOK_NAMES = Object.freeze([
|
|
18
18
|
"onAgentStart",
|
|
19
19
|
"onAgentStop",
|
|
20
|
-
"interceptTmuxExec",
|
|
21
20
|
"interceptSessionCreate",
|
|
22
21
|
"interceptSessionKill",
|
|
23
22
|
"filterSessions",
|
|
@@ -25,26 +24,12 @@ export const HOOK_NAMES = Object.freeze([
|
|
|
25
24
|
"transformStatusDetection",
|
|
26
25
|
])
|
|
27
26
|
|
|
28
|
-
/**
|
|
29
|
-
* @typedef {Object} TmuxExecArgs
|
|
30
|
-
* @property {string[]} args
|
|
31
|
-
* @property {Record<string, string>} env
|
|
32
|
-
*/
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* @typedef {Object} TmuxExecDecision
|
|
36
|
-
* @property {string} command
|
|
37
|
-
* @property {string[]} args
|
|
38
|
-
* @property {Record<string, string>} [env]
|
|
39
|
-
*/
|
|
40
|
-
|
|
41
27
|
/**
|
|
42
28
|
* @typedef {Object} Plugin
|
|
43
29
|
* @property {string} name
|
|
44
30
|
* @property {{
|
|
45
31
|
* onAgentStart?: (ctx: HookContext) => Promise<void>,
|
|
46
32
|
* onAgentStop?: (ctx: HookContext) => Promise<void>,
|
|
47
|
-
* interceptTmuxExec?: (ctx: HookContext & TmuxExecArgs) => Promise<TmuxExecDecision | null>,
|
|
48
33
|
* }} hooks
|
|
49
34
|
*/
|
|
50
35
|
|
package/src/main.mjs
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* - plugin discovery + onAgentStart broadcast
|
|
6
6
|
* - WS メッセージのディスパッチ:
|
|
7
7
|
* - claude.* / codex.* → ClaudeStreamBridge / CodexStreamBridge (チャット)
|
|
8
|
-
* - tmux.* → tmux module (
|
|
8
|
+
* - tmux.* → tmux module (セッション一覧・作成・削除)
|
|
9
9
|
*
|
|
10
10
|
* 仕様書: ナレッジ/インフラ/cockpit-hub-hosted-integration-spec (id=6080)
|
|
11
11
|
*/
|
|
@@ -43,7 +43,7 @@ import {
|
|
|
43
43
|
resolveSyncTargets,
|
|
44
44
|
syncBundleTargets,
|
|
45
45
|
} from "./hub-bundle.mjs"
|
|
46
|
-
import { loadPlugins, runHookBroadcast
|
|
46
|
+
import { loadPlugins, runHookBroadcast } from "./plugin-loader.mjs"
|
|
47
47
|
import { WsClient } from "./ws-client.mjs"
|
|
48
48
|
import { DispatchScheduler } from "./dispatch-scheduler.mjs"
|
|
49
49
|
import { AsyncTtlCache } from "./async-ttl-cache.mjs"
|
|
@@ -104,7 +104,6 @@ import {
|
|
|
104
104
|
buildWorktreeIndex,
|
|
105
105
|
createSession as createTmuxSession,
|
|
106
106
|
createWorktreeDir,
|
|
107
|
-
execTmux,
|
|
108
107
|
killManySessions,
|
|
109
108
|
killSession as killTmuxSession,
|
|
110
109
|
listSessions as listTmuxSessions,
|
|
@@ -387,10 +386,10 @@ export function withDeadline(promise, timeoutMs, onTimeout) {
|
|
|
387
386
|
/**
|
|
388
387
|
* B7: 直列 dispatchChain をバイパスして即時処理してよい低レイテンシ経路かを判定する。
|
|
389
388
|
* - claude.interrupt / codex.interrupt (2026-07-02): 停止指示。前段に重い dispatch
|
|
390
|
-
* (tmux
|
|
389
|
+
* (tmux セッション操作等) が滞留していると停止が遅延するため直列キューを
|
|
391
390
|
* バイパスする。中断は「現ターンを止める」冪等な制御で、入力系のような順序依存が無い
|
|
392
391
|
* (むしろキュー内の後続入力より先に届くべき)。
|
|
393
|
-
* 入力系 (claude.input)・他の制御系 (permission / tmux
|
|
392
|
+
* 入力系 (claude.input)・他の制御系 (permission / tmux セッション操作等) は
|
|
394
393
|
* WS 受信順 = pane 反映順を守るため false (= 直列キューに残す)。
|
|
395
394
|
*/
|
|
396
395
|
export function isFastPathMessage(type) {
|
|
@@ -3330,65 +3329,6 @@ export function handleClaudeChatInput(msg, ctx) {
|
|
|
3330
3329
|
return p
|
|
3331
3330
|
}
|
|
3332
3331
|
|
|
3333
|
-
/**
|
|
3334
|
-
* `tmux.exec` を処理し、`tmux.result` を返す。
|
|
3335
|
-
*
|
|
3336
|
-
* 公式 Hub の送信入口は撤去済みだが、公開 0.x package の root handler / deep import、
|
|
3337
|
-
* plugin hook、旧 Hub との互換入口として handler・dispatch・execTmux を維持する。
|
|
3338
|
-
*
|
|
3339
|
-
* plugin の `interceptTmuxExec` hook が `{ command, args, env }` を返したときは、その
|
|
3340
|
-
* command を代わりに spawn する (例: remote-ops プラグインで ssh 越しに実行)。hook が
|
|
3341
|
-
* 何も返さなければ既定のローカル `execTmux` へ落ちる。どちらの経路でも
|
|
3342
|
-
* `request_id` / `stdout` / `stderr` / `exit_code` / `plugin` の 5 フィールドを揃えて返す。
|
|
3343
|
-
*
|
|
3344
|
-
* dispatch から呼ぶ用のヘルパーだが、テストから直接叩けるよう export している
|
|
3345
|
-
* (handleStreamsSyncResponse / handleClaudeChatInput と同じ扱い)。
|
|
3346
|
-
*
|
|
3347
|
-
* @param {{request_id?:string, args?:string[]}} msg
|
|
3348
|
-
* @param {{plugins:any[], logger:object, client:{send:Function}}} ctx
|
|
3349
|
-
* @param {{execTmux?:Function}} [deps] 既定実装の差し替え口 (テスト専用)。
|
|
3350
|
-
*/
|
|
3351
|
-
export async function handleTmuxExec(msg, ctx, deps = {}) {
|
|
3352
|
-
const execTmuxImpl = deps.execTmux || execTmux
|
|
3353
|
-
const args = Array.isArray(msg.args) ? msg.args : []
|
|
3354
|
-
const hookResult = await runHookChain(ctx.plugins, "interceptTmuxExec", {
|
|
3355
|
-
logger: ctx.logger,
|
|
3356
|
-
args,
|
|
3357
|
-
env: process.env,
|
|
3358
|
-
})
|
|
3359
|
-
let result
|
|
3360
|
-
if (hookResult?.result?.command) {
|
|
3361
|
-
// plugin が独自 command で差し替え (例: remote-ops プラグインで ssh 越し)
|
|
3362
|
-
const { command, args: spawnArgs, env } = hookResult.result
|
|
3363
|
-
try {
|
|
3364
|
-
const { execFile } = await import("node:child_process")
|
|
3365
|
-
const { promisify } = await import("node:util")
|
|
3366
|
-
const execFileP = promisify(execFile)
|
|
3367
|
-
const { stdout, stderr } = await execFileP(command, spawnArgs, {
|
|
3368
|
-
env: env || process.env,
|
|
3369
|
-
maxBuffer: 4 * 1024 * 1024,
|
|
3370
|
-
})
|
|
3371
|
-
result = { stdout, stderr, exit_code: 0 }
|
|
3372
|
-
} catch (err) {
|
|
3373
|
-
result = {
|
|
3374
|
-
stdout: err.stdout || "",
|
|
3375
|
-
stderr: err.stderr || err.message || "",
|
|
3376
|
-
exit_code: typeof err.code === "number" ? err.code : 1,
|
|
3377
|
-
}
|
|
3378
|
-
}
|
|
3379
|
-
} else {
|
|
3380
|
-
result = await execTmuxImpl(args)
|
|
3381
|
-
}
|
|
3382
|
-
ctx.client.send({
|
|
3383
|
-
type: "tmux.result",
|
|
3384
|
-
request_id: msg.request_id,
|
|
3385
|
-
stdout: result.stdout,
|
|
3386
|
-
stderr: result.stderr,
|
|
3387
|
-
exit_code: result.exit_code,
|
|
3388
|
-
plugin: hookResult?.plugin || null,
|
|
3389
|
-
})
|
|
3390
|
-
}
|
|
3391
|
-
|
|
3392
3332
|
/**
|
|
3393
3333
|
* claude.attach の ready 直後にpushする履歴を組み立てる。
|
|
3394
3334
|
* Browserからの claude.history.request 往復を省くため、resume時だけ先回りして読む。
|
|
@@ -5470,11 +5410,6 @@ export async function dispatch(msg, ctx) {
|
|
|
5470
5410
|
}
|
|
5471
5411
|
return
|
|
5472
5412
|
}
|
|
5473
|
-
case "tmux.exec": {
|
|
5474
|
-
// ロジックは handleTmuxExec へ抽出 (テストから直接呼べる)。
|
|
5475
|
-
await handleTmuxExec(msg, ctx)
|
|
5476
|
-
return
|
|
5477
|
-
}
|
|
5478
5413
|
case "tmux.list_sessions": {
|
|
5479
5414
|
try {
|
|
5480
5415
|
const snapshot = await tmuxSessionsSnapshotCache.get(async () => {
|
package/src/tmux.mjs
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* tmux サブプロセス呼び出し抽象 (Sprint E)。
|
|
3
3
|
*
|
|
4
|
-
* - `execTmux(args)`: raw 実行 (stdout / stderr / exit_code を返す)
|
|
5
4
|
* - `listSessions()`: 構造化された TmuxSession[] を返す。各 session に
|
|
6
5
|
* status (state.mjs の detectSessionState) と cwd (active pane の current_path)
|
|
7
6
|
* を並列で付与
|
|
@@ -601,28 +600,6 @@ export async function setTmuxGlobalEnv(name, value, opts = {}) {
|
|
|
601
600
|
}
|
|
602
601
|
}
|
|
603
602
|
|
|
604
|
-
/**
|
|
605
|
-
* 汎用 tmux 実行 (raw)。任意の tmux サブコマンドを実行して結果を返す低レベル API。
|
|
606
|
-
*
|
|
607
|
-
* @returns {Promise<{stdout: string, stderr: string, exit_code: number}>}
|
|
608
|
-
*/
|
|
609
|
-
export async function execTmux(args, opts = {}) {
|
|
610
|
-
if (!Array.isArray(args)) throw new TypeError("execTmux requires args: string[]")
|
|
611
|
-
try {
|
|
612
|
-
const { stdout, stderr } = await execFileP(tmuxBin(opts), args, {
|
|
613
|
-
env: opts.env || process.env,
|
|
614
|
-
maxBuffer: 4 * 1024 * 1024,
|
|
615
|
-
})
|
|
616
|
-
return { stdout, stderr, exit_code: 0 }
|
|
617
|
-
} catch (err) {
|
|
618
|
-
return {
|
|
619
|
-
stdout: err.stdout || "",
|
|
620
|
-
stderr: err.stderr || err.message || "",
|
|
621
|
-
exit_code: typeof err.code === "number" ? err.code : 1,
|
|
622
|
-
}
|
|
623
|
-
}
|
|
624
|
-
}
|
|
625
|
-
|
|
626
603
|
// P1 (重複排除): cwd 取得は state.mjs の getSessionCwd (キャッシュ付き) を共用する。
|
|
627
604
|
// 旧 tmux.mjs 私有実装は display-message を毎回 spawn しており、state loop の
|
|
628
605
|
// listSessionStates と list_sessions が別キャッシュ無しで二重 fork していた。
|