@cocorograph/hub-agent 0.6.83 → 0.6.85
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/state.mjs +67 -11
package/package.json
CHANGED
package/src/state.mjs
CHANGED
|
@@ -132,17 +132,67 @@ function footerRegion(text, lines = 8) {
|
|
|
132
132
|
}
|
|
133
133
|
|
|
134
134
|
/**
|
|
135
|
-
*
|
|
136
|
-
*
|
|
137
|
-
*
|
|
138
|
-
*
|
|
139
|
-
*
|
|
140
|
-
*
|
|
135
|
+
* 作業スピナー行 (ライブステータス行) の構造パターン。実機採取 (2026-06-15):
|
|
136
|
+
* "· Blanching… (2m 4s · ↓ 7.5k tokens)" (出力中)
|
|
137
|
+
* "✽ Scurrying… (16m 55s · ↓ 66.8k tokens)" (出力中)
|
|
138
|
+
* "· Puzzling… (11m 12s · thinking)" (思考中・tokens 語が無い)
|
|
139
|
+
* = 行頭グリフ (·/✻/✽/✶… 1 文字) + 語 + 省略記号 + 括弧で囲まれたライブ経過タイマー。
|
|
140
|
+
* 語 (Blanching/Puzzling/Orbiting…) は無数にあり版で増減するため語リストにしない。行頭は
|
|
141
|
+
* 英数字・空白・本文の箇条書き記号 (-*>#|) を除く 1 文字に限定し、本文プローズ (英字始まり)
|
|
142
|
+
* や箇条書きへの誤マッチを防ぐ。完了サマリー "✻ Brewed for 2m 52s" は省略記号も括弧タイマー
|
|
143
|
+
* も持たないので一致しない。
|
|
144
|
+
*/
|
|
145
|
+
const SPINNER_LINE_RE =
|
|
146
|
+
/^\s{0,4}[^\sA-Za-z0-9\-*>#|]\s*[A-Za-z]+(?:…|\.\.\.)\s*\(\s*(?:\d+\s*m\s*)?\d+\s*s\b/
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* スピナー行 i の「下」が入力欄チロム (空行/罫線/❯ プロンプト/tips/字下げ継続/権限バナー)
|
|
150
|
+
* のみかを判定する。ライブのスピナーはペイン最下部の入力欄直上に描かれ、下には本文行が
|
|
151
|
+
* 来ない。一方、本文中に書かれた「スピナー行の引用」(解説テキスト・表セル・コードブロック等)
|
|
152
|
+
* は下に列 0 の本文行が続く。これを使って「未生成なのにローダーが点灯する」誤検出を防ぐ。
|
|
153
|
+
* 列 0 の本文行が下に在れば引用とみなし false。
|
|
154
|
+
*/
|
|
155
|
+
function _belowIsOnlyChrome(lines, i) {
|
|
156
|
+
for (let j = i + 1; j < lines.length; j++) {
|
|
157
|
+
const ln = lines[j]
|
|
158
|
+
if (ln.trim() === "") continue // 空行
|
|
159
|
+
if (/^\s*─{3,}\s*$/.test(ln)) continue // 入力欄の罫線
|
|
160
|
+
if (/^\s*[❯>]/.test(ln)) continue // 入力プロンプト
|
|
161
|
+
if (/^\s*⎿/.test(ln)) continue // tips / ツリー装飾行
|
|
162
|
+
if (/^\s{4,}\S/.test(ln)) continue // tips 折り返し等の字下げ継続
|
|
163
|
+
if (
|
|
164
|
+
/shift\+tab|← for|for shortcuts|accept edits|plan mode|auto mode|bypass permissions|new task\?|to save|auto-compact|context left/i.test(
|
|
165
|
+
ln,
|
|
166
|
+
)
|
|
167
|
+
)
|
|
168
|
+
continue // 権限バナー / フッターのヒント
|
|
169
|
+
return false // 列 0 の本文行 = スピナー行の引用とみなす
|
|
170
|
+
}
|
|
171
|
+
return true
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* 作業スピナーのフッター行を検出する (生成中=processing の補助シグナル)。
|
|
176
|
+
*
|
|
177
|
+
* 現行版は "esc to interrupt" をフッターに出さない (主シグナルが実機で死んでいる) ため、
|
|
178
|
+
* これが生成中検出の実効シグナルになる。フッター領域 (末尾 12 行) を下から走査し、次の
|
|
179
|
+
* いずれかに一致しかつ「下が入力欄チロムのみ (本文行の引用でない)」行があれば生成中とみなす:
|
|
180
|
+
* (a) スピナー構造行 (SPINNER_LINE_RE)。tokens の有無に依存しないので thinking も拾う。
|
|
181
|
+
* (b) "tokens" 語 + 経過秒の同一行同居 (回帰防止。"(↑ 3.4k tokens · 7s)" の語順も拾う)。
|
|
182
|
+
*
|
|
183
|
+
* 下チロム判定 (_belowIsOnlyChrome) が肝: スピナー行の構造は、本文に「生成中フッターは
|
|
184
|
+
* … (Ns) です」と書いた引用や表セルにも現れ得る。それらは下に本文行が続くため除外し、
|
|
185
|
+
* ペイン最下部の入力欄直上にあるライブのスピナーだけを生成中と判定する (誤点灯防止)。
|
|
141
186
|
*/
|
|
142
187
|
function detectWorkingSpinner(text) {
|
|
143
|
-
const
|
|
144
|
-
|
|
145
|
-
|
|
188
|
+
const lines = text.split("\n")
|
|
189
|
+
const start = Math.max(0, lines.length - 12)
|
|
190
|
+
for (let i = lines.length - 1; i >= start; i--) {
|
|
191
|
+
const line = lines[i]
|
|
192
|
+
const isSpinner = SPINNER_LINE_RE.test(line)
|
|
193
|
+
const isTokenFooter =
|
|
194
|
+
/\btokens\b/i.test(line) && /(?:^|[\s(])\d+\s*s\b/.test(line)
|
|
195
|
+
if ((isSpinner || isTokenFooter) && _belowIsOnlyChrome(lines, i)) return true
|
|
146
196
|
}
|
|
147
197
|
return false
|
|
148
198
|
}
|
|
@@ -441,10 +491,16 @@ function _outputSignature(text) {
|
|
|
441
491
|
}
|
|
442
492
|
|
|
443
493
|
/** 内容安定による「確実に停止」判定。processing (ローダー在中) は常に false で、
|
|
444
|
-
* 停止後に出力領域が STABLE_CONFIRM_MS 不変であれば true。
|
|
494
|
+
* 停止後に出力領域が STABLE_CONFIRM_MS 不変であれば true。
|
|
495
|
+
*
|
|
496
|
+
* 多重防御 (2026-06-15): status の読み違いがあっても、ライブスピナー (経過タイマー) が
|
|
497
|
+
* ペインに在る間は「確実に停止」を絶対に返さない。frontend は stable=true を受けると
|
|
498
|
+
* 2 サンプル消灯確認 (paneOffConfirmed) をバイパスして即消灯するため、将来 claude が
|
|
499
|
+
* 未知のフッター形式を出して status を取りこぼしても、タイマーが画面に出ている限り
|
|
500
|
+
* 即消灯の暴発を防ぐ保険にする (生成中ローダー消失の再発防止)。 */
|
|
445
501
|
function _computeStable(sessionName, status, text) {
|
|
446
502
|
const now = Date.now()
|
|
447
|
-
if (status === "processing") {
|
|
503
|
+
if (status === "processing" || detectWorkingSpinner(text)) {
|
|
448
504
|
_stabilityByName.set(sessionName, { sig: _outputSignature(text), since: now })
|
|
449
505
|
return false
|
|
450
506
|
}
|