@cocorograph/hub-agent 0.8.14 → 0.8.15

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.8.14",
3
+ "version": "0.8.15",
4
4
  "description": "Hub Hosted Cockpit のローカル常駐 agent。Hub と outbound WSS で接続し、ローカルの tmux/pty を中継する。",
5
5
  "type": "module",
6
6
  "license": "UNLICENSED",
@@ -1408,11 +1408,20 @@ export class ClaudeStreamSession {
1408
1408
  * メッセージ本文。drain 由来の emit でのみ渡す。frontend はこれを user バブルへ
1409
1409
  * 昇格させる。キャンセル / 追加由来の emit では空 (昇格させない)。これにより
1410
1410
  * 「先頭の pending をキャンセルした」のを「実行開始した」と誤認しなくなる (0.6.26)。
1411
- * @param {{force?: boolean}} [opts] force=true のとき署名重複チェックを無視して必ず
1412
- * emit する。再アタッチ時のキュー snapshot 再送 (キュー再表示バグ修正, 0.6.30) に使う。
1413
- * 署名が前回と同一でも browser がライブ配信を取りこぼしている可能性があるため。 */
1411
+ * @param {{force?: boolean, startedIds?: (string|null)[], discarded?: string[]}} [opts]
1412
+ * force=true のとき署名重複チェックを無視して必ず emit する。再アタッチ時のキュー
1413
+ * snapshot 再送 (キュー再表示バグ修正, 0.6.30) に使う。署名が前回と同一でも browser が
1414
+ * ライブ配信を取りこぼしている可能性があるため。
1415
+ * discarded は「実行せずに捨てた input_id」(close 時の pending 破棄)。browser はこれを
1416
+ * 受けてチップを消さず未配信印を付ける (無言削除の根治, 2026-07-31)。 */
1414
1417
  _emitQueueState(started = [], opts = undefined) {
1415
1418
  const force = opts?.force === true
1419
+ // 無言削除の根治 (2026-07-31): 実行せずに捨てた input_id。空配列は載せない
1420
+ // (旧 browser との後方互換 = 未知フィールドは無視されるが、無駄なノイズも出さない)。
1421
+ const discarded =
1422
+ Array.isArray(opts?.discarded) && opts.discarded.length > 0
1423
+ ? [...opts.discarded]
1424
+ : undefined
1416
1425
  // 実行開始した項目の input_id (started と parallel。T06603 cross-review major#2)。
1417
1426
  // 本文テキストだけだと、同一本文を連投したときに 2 通目のユーザー発言バブルが
1418
1427
  // 「既に同じ本文のバブルがある」と誤判定されて永久に出ない。id で突合させる。
@@ -1446,6 +1455,8 @@ export class ClaudeStreamSession {
1446
1455
  // items は id 付きでキャンセルボタンの対象特定に使う (0.6.26)。
1447
1456
  this.onEvent?.({
1448
1457
  ...this._buildQueueSnapshot(),
1458
+ // 実行せずに捨てた id (close 時の pending 破棄)。載る時だけキーを出す。
1459
+ ...(discarded ? { discarded } : {}),
1449
1460
  started,
1450
1461
  // started と parallel。連携注入なら 'peer'|'orchestrator'、通常は null。
1451
1462
  startedSources,
@@ -2105,12 +2116,30 @@ export class ClaudeStreamSession {
2105
2116
  close() {
2106
2117
  this._closed = true
2107
2118
  // 改修3: 未処理の pending を破棄 (セッション終了後に drain しないため)。
2119
+ const discardedIds = this._pendingMessages
2120
+ .map((m) => m.id)
2121
+ .filter((id) => typeof id === "string" && id)
2108
2122
  const hadPending = this._pendingMessages.length > 0
2109
2123
  this._pendingMessages = []
2124
+ // 無言削除の根治 (2026-07-31): 破棄した id を **受理済みリングから外す**。
2125
+ // browser の 2 軸判定は「キューに無い + 受理済み = 実行完了」なので、破棄した id を
2126
+ // accepted に残したまま空 snapshot を送ると、**実行していない送信を実行完了と誤認して
2127
+ // チップを無言削除**する (ユーザーが送った本文が痕跡なく消える)。accepted から外し、
2128
+ // かつ discarded として明示して「捨てた」ことを browser に伝える。
2129
+ for (const id of discardedIds) {
2130
+ const at = this._acceptedInputIds.indexOf(id)
2131
+ if (at !== -1) this._acceptedInputIds.splice(at, 1)
2132
+ }
2110
2133
  // T06603 (2026-07-25): 破棄したことを必ず通知する。従来は無言で捨てていたため、
2111
2134
  // 「セッションが畳まれた後もチップだけが残る」表示が残留していた。破棄は状態変化なので
2112
2135
  // force で貫通させる (started=[] なのでバブル昇格は起きない)。
2113
- if (hadPending) this._emitQueueState([], { force: true })
2136
+ if (hadPending) {
2137
+ this.logger?.info(
2138
+ { stream_id: this.stream_id, discarded: discardedIds.length },
2139
+ "pending messages discarded on close",
2140
+ )
2141
+ this._emitQueueState([], { force: true, discarded: discardedIds })
2142
+ }
2114
2143
  // 常駐 query は input キューを閉じて generator を終わらせ query を完走させる。
2115
2144
  if (this._inputQueue) this._inputQueue.close()
2116
2145
  this.abortTurn()