@cocorograph/hub-agent 0.7.21 → 0.7.22

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cocorograph/hub-agent",
3
- "version": "0.7.21",
3
+ "version": "0.7.22",
4
4
  "description": "Hub Hosted Cockpit のローカル常駐 agent。Hub と outbound WSS で接続し、ローカルの tmux/pty を中継する。",
5
5
  "type": "module",
6
6
  "license": "UNLICENSED",
@@ -31,10 +31,25 @@ const _TOOL_CALL_RE = /^[A-Z][A-Za-z0-9_]*\s*\(/
31
31
 
32
32
  const _BOX_LINE_RE = /^[─-▟]/
33
33
 
34
- const _STATUS_LINE_RE = /^[✨✹●⚫◯]\s/
34
+ // 状態 / スピナー行。Claude 2.1.x は「考え中」スピナーに ✻ ✳ ✽ ✶ ✵ 等の星形グリフを
35
+ // 循環使用する (例: "✻ Sautéed for 2s" / "✳ Frolicking… (3s · ↓ 34 tokens)")。説明段落に
36
+ // 紛れ込ませないよう除外グリフを広く取る (旧版は ✨✹●⚫◯ のみで ✻✳✽ を取りこぼしていた)。
37
+ const _STATUS_LINE_RE = /^[✨✹✺✻✷✸✹✳✲✱✽✶✵✴✦✧⋆●⚫◯◉]\s/
35
38
 
36
39
  const _ELLIPSIS_TAIL_RE = /\n[ \t]*…\s*\+\d+\s+lines[^\n]*$/
37
40
 
41
+ // stop hook サマリ行。Claude 2.1.x は "Ran N stop hooks (ctrl+o to expand)" を
42
+ // アシスタント本文と同じ ⏺ プレフィックス付きで描画するため、ツール呼び出しと同様に
43
+ // 「説明段落の始点」候補から除外する (誤って始点にすると hook エラー出力を巻き込む)。
44
+ const _STOP_HOOK_SUMMARY_RE = /^Ran\s+\d+\s+stop\s+hooks?\b/i
45
+
46
+ // ツール結果 / フック結果の継続行 (⎿)。説明段落の途中で現れたら打ち切る。
47
+ const _TOOL_RESULT_RE = /^\s*⎿/
48
+
49
+ // 入力欄に映るユーザープロンプトのエコー (❯ + 本文)。メニュー選択肢 (❯ 1. ...) と
50
+ // 空の入力欄 (❯ のみ) は除外する。これがある = ターン境界の目印として使う。
51
+ const _INPUT_ECHO_RE = /^❯\s+(?!\d+\.\s)\S/
52
+
38
53
  /**
39
54
  * @param {string|undefined|null} paneText capturePane の出力 (ANSI 除去済み)
40
55
  * @returns {string|null} 直近のアシスタント説明 (失敗時 null)
@@ -49,11 +64,20 @@ export function extractLastAssistantText(paneText) {
49
64
  if (!line.startsWith(ASSIST_PREFIX + " ")) continue
50
65
  const rest = line.slice(ASSIST_PREFIX.length + 1).trimStart()
51
66
  if (_TOOL_CALL_RE.test(rest)) continue
67
+ if (_STOP_HOOK_SUMMARY_RE.test(rest)) continue
52
68
  startIdx = i
53
69
  break
54
70
  }
55
71
  if (startIdx < 0) return null
56
72
 
73
+ // 前ターン取り違え防止: startIdx より下 (= より新しい) に現ターンのユーザープロンプト
74
+ // エコーがあるなら、その ⏺ は前ターンの説明である。現ターンはツールへ直行 (説明文なし) と
75
+ // 判断し null へ縮退する (古い説明を出すより「説明なし」が安全。capture-pane が処理中の
76
+ // ノイズだらけのペインを撮ったときに前ターン本文や hook 出力を掴むのを防ぐ)。
77
+ for (let j = startIdx + 1; j < lines.length; j++) {
78
+ if (_INPUT_ECHO_RE.test(lines[j])) return null
79
+ }
80
+
57
81
  const parts = []
58
82
  let consecBlank = 0
59
83
  for (let i = startIdx; i < lines.length; i++) {
@@ -62,6 +86,8 @@ export function extractLastAssistantText(paneText) {
62
86
  if (line.startsWith(ASSIST_PREFIX + " ")) break
63
87
  if (_BOX_LINE_RE.test(line)) break
64
88
  if (_STATUS_LINE_RE.test(line.trim())) break
89
+ if (_TOOL_RESULT_RE.test(line)) break
90
+ if (_INPUT_ECHO_RE.test(line)) break
65
91
  }
66
92
  if (!line.trim()) {
67
93
  consecBlank++
@@ -116,4 +142,8 @@ export const __test = {
116
142
  _MIN_CHARS,
117
143
  _TOOL_CALL_RE,
118
144
  _BOX_LINE_RE,
145
+ _STATUS_LINE_RE,
146
+ _STOP_HOOK_SUMMARY_RE,
147
+ _TOOL_RESULT_RE,
148
+ _INPUT_ECHO_RE,
119
149
  }