@cocorograph/hub-agent 0.8.26 → 0.8.27
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/codex-stream-bridge.mjs +120 -3
- package/src/sibling-inject.mjs +69 -5
package/package.json
CHANGED
|
@@ -315,6 +315,29 @@ export function deriveResumeTurnState(thread) {
|
|
|
315
315
|
return { threadStatus, lastTurnStatus, turnActive, activeTurnId }
|
|
316
316
|
}
|
|
317
317
|
|
|
318
|
+
/**
|
|
319
|
+
* sibling 依頼の識別子 (`request_id`) から配送 ID を **決定的に** 導出する (2026-08-05)。
|
|
320
|
+
*
|
|
321
|
+
* ⚠️ なぜランダムではいけないか: `_deliverInjection` は導出した値を `input({inputId})` に渡し、
|
|
322
|
+
* `input()` はその id を `session.acceptedInputIds` に控えて **同じ id の再到着を no-op にする**
|
|
323
|
+
* (重複ガード)。ここが `randomUUID()` だと同一依頼の再処理 (hub-agent 再起動後の sweep で同じ
|
|
324
|
+
* 要求ファイルを読み直す / 送信側がタイムアウトと誤認して同じ依頼を投げ直す) が毎回「別物」と
|
|
325
|
+
* 見なされ、ガードが一度も効かない = 同じ本文が二重に実行される。
|
|
326
|
+
*
|
|
327
|
+
* ⚠️ 冪等キーなので **異なる依頼同士で衝突させてはいけない**。`request_id` は要求ファイル名
|
|
328
|
+
* (cockpit_orch.py は uuid4 の hex) であり依頼ごとに一意なので、加工せず丸ごと使う (切り詰め・
|
|
329
|
+
* 正規化をすると衝突の余地が生まれる)。`sib-` の接頭辞は browser 入力の inputId と名前空間を
|
|
330
|
+
* 分けるためだけのもの。
|
|
331
|
+
*
|
|
332
|
+
* @param {unknown} requestId sibling 要求ファイルの `<request_id>`
|
|
333
|
+
* @returns {string|null} 導出した配送 ID。識別子が無い経路では null (呼び出し側が randomUUID)
|
|
334
|
+
*/
|
|
335
|
+
export function siblingDeliveryId(requestId) {
|
|
336
|
+
if (typeof requestId !== "string") return null
|
|
337
|
+
const trimmed = requestId.trim()
|
|
338
|
+
return trimmed ? `sib-${trimmed}` : null
|
|
339
|
+
}
|
|
340
|
+
|
|
318
341
|
/**
|
|
319
342
|
* 配達保証 (S2, 2026-07-05): `input()` が reject したエラーを `codex.input.nack` の
|
|
320
343
|
* `reason` へ分類する。
|
|
@@ -1216,6 +1239,21 @@ export class CodexStreamBridge extends EventEmitter {
|
|
|
1216
1239
|
}
|
|
1217
1240
|
}
|
|
1218
1241
|
|
|
1242
|
+
/**
|
|
1243
|
+
* 重複ガードの台帳から id を取り消す (2026-08-05)。
|
|
1244
|
+
*
|
|
1245
|
+
* `input()` は turn/start を打つ **前** に `_recordAcceptedInput` するため、RPC が失敗して
|
|
1246
|
+
* 「1 度もターンが起きていない」ときでも id が受理済みとして残る。sibling 注入はここで
|
|
1247
|
+
* `delivery_failed` (= 再送してよい) を返すので、id を残したままだと**正当な再送を重複と
|
|
1248
|
+
* 誤判定して握り潰す**。受理を取り消した経路だけで呼ぶこと。
|
|
1249
|
+
*/
|
|
1250
|
+
_forgetAcceptedInput(session, inputId) {
|
|
1251
|
+
const ids = session?.acceptedInputIds
|
|
1252
|
+
if (!Array.isArray(ids) || typeof inputId !== "string" || !inputId) return
|
|
1253
|
+
const at = ids.indexOf(inputId)
|
|
1254
|
+
if (at !== -1) ids.splice(at, 1)
|
|
1255
|
+
}
|
|
1256
|
+
|
|
1219
1257
|
_pendingInputItems(session) {
|
|
1220
1258
|
if (!session || !Array.isArray(session.inputQueue)) return []
|
|
1221
1259
|
return session.inputQueue.filter((item) => item !== session.dispatchingInput)
|
|
@@ -2158,15 +2196,18 @@ export class CodexStreamBridge extends EventEmitter {
|
|
|
2158
2196
|
*
|
|
2159
2197
|
* @param {string} cwd
|
|
2160
2198
|
* @param {string} text
|
|
2199
|
+
* @param {'peer'|'orchestrator'} [source]
|
|
2200
|
+
* @param {string} [requestId] sibling 要求の識別子 (配送 ID を決定的に導出し重複を止める)
|
|
2161
2201
|
* @returns {Promise<
|
|
2162
2202
|
* {status:"delivered", session:object, delivery_id:string, accepted_via:string}
|
|
2203
|
+
* | {status:"delivery_queued", session:object, delivery_id:string, accepted_via:string, reason:string}
|
|
2163
2204
|
* | {status:"delivery_unconfirmed", session:object, delivery_id:string, accepted_via:string, reason:string}
|
|
2164
2205
|
* | {status:"delivery_failed", session:object, delivery_id:string, reason:string}
|
|
2165
2206
|
* | {status:"ambiguous", candidates:object[]}
|
|
2166
2207
|
* | {status:"not_found"}
|
|
2167
2208
|
* >}
|
|
2168
2209
|
*/
|
|
2169
|
-
async sendToCwd(cwd, text, source) {
|
|
2210
|
+
async sendToCwd(cwd, text, source, requestId) {
|
|
2170
2211
|
if (!cwd || !text) return { status: "not_found" }
|
|
2171
2212
|
// 案B: distinct session で走査(多対一 Map の重複を除く)。
|
|
2172
2213
|
const cands = this._liveSessions().filter((s) => s.cwd === cwd)
|
|
@@ -2206,6 +2247,7 @@ export class CodexStreamBridge extends EventEmitter {
|
|
|
2206
2247
|
cwd,
|
|
2207
2248
|
selection: "sole-candidate",
|
|
2208
2249
|
candidates: this.describeLiveSessions(cwd).length,
|
|
2250
|
+
request_id: requestId,
|
|
2209
2251
|
})
|
|
2210
2252
|
}
|
|
2211
2253
|
|
|
@@ -2234,9 +2276,11 @@ export class CodexStreamBridge extends EventEmitter {
|
|
|
2234
2276
|
* @param {string} cwd 呼び出し元がトークン検証した cwd (この cwd のセッションにのみ注入)
|
|
2235
2277
|
* @param {string} id 宛先 stream_id (一意・推奨) または thread_id
|
|
2236
2278
|
* @param {string} text
|
|
2279
|
+
* @param {'peer'|'orchestrator'} [source]
|
|
2280
|
+
* @param {string} [requestId] sibling 要求の識別子 (配送 ID を決定的に導出し重複を止める)
|
|
2237
2281
|
* @returns {Promise<object>}
|
|
2238
2282
|
*/
|
|
2239
|
-
async sendToStream(cwd, id, text, source) {
|
|
2283
|
+
async sendToStream(cwd, id, text, source, requestId) {
|
|
2240
2284
|
if (!cwd || !id || !text) return { status: "not_found" }
|
|
2241
2285
|
let bySid = null
|
|
2242
2286
|
const byThread = []
|
|
@@ -2266,6 +2310,7 @@ export class CodexStreamBridge extends EventEmitter {
|
|
|
2266
2310
|
cwd,
|
|
2267
2311
|
requested_id: id,
|
|
2268
2312
|
selection: bySid ? "stream_id" : "thread_id",
|
|
2313
|
+
request_id: requestId,
|
|
2269
2314
|
})
|
|
2270
2315
|
}
|
|
2271
2316
|
|
|
@@ -2274,10 +2319,41 @@ export class CodexStreamBridge extends EventEmitter {
|
|
|
2274
2319
|
* dispatched (本関数開始) → accepted (turn RPC成功) →
|
|
2275
2320
|
* delivered (同一sessionの userMessage item/completed echo) → durable (rollout監査、別層)。
|
|
2276
2321
|
* ここでは delivered までを同期的に確認し、echo timeout は成功扱いしない。
|
|
2322
|
+
*
|
|
2323
|
+
* ⚠️ 例外は「相手が応答生成中」(2026-08-05)。この場合メッセージは次ターン FIFO に受理される
|
|
2324
|
+
* だけで **echo は次のターンが始まるまで来ない**ので、待つと最長でターン 1 本ぶん (実測 30 分)
|
|
2325
|
+
* ブロックする。旧実装は `inputId` を渡していなかったため `input()` の即時 resolve 経路にも
|
|
2326
|
+
* 乗らず、送信元 CLI が待ちきれず「hub-agent が起動していない」と誤報 → 再送 → 二重配送を
|
|
2327
|
+
* 起こしていた。キューが「待たせる席」なので、hub-agent が送信元を待たせる必要は無い。
|
|
2328
|
+
* 順番待ちは `delivery_queued` (echo 欠落 = `delivery_unconfirmed` とは別の状態) で即返す。
|
|
2277
2329
|
*/
|
|
2278
2330
|
async _deliverInjection(session, text, source, context = {}) {
|
|
2279
|
-
|
|
2331
|
+
// 冪等キー: sibling 依頼の識別子から決定的に導出する (無い経路のみランダム)。
|
|
2332
|
+
const deliveryId = siblingDeliveryId(context.request_id) || randomUUID()
|
|
2280
2333
|
const sourceStreamId = session.stream_id
|
|
2334
|
+
// 同一依頼の再処理 (hub-agent 再起動後の sweep 等) は、ここで打ち切って二重実行しない。
|
|
2335
|
+
// 見ているのは `input()` の重複ガードと同じ `acceptedInputIds` なので判定は原理的に一致する
|
|
2336
|
+
// (ここで弾き損ねても input() 側が turn を二重に起こさない = 二段構え)。
|
|
2337
|
+
if (deliveryId && session.acceptedInputIds?.includes(deliveryId)) {
|
|
2338
|
+
this.logger?.info?.(
|
|
2339
|
+
{
|
|
2340
|
+
...context,
|
|
2341
|
+
delivery_id: deliveryId,
|
|
2342
|
+
stream_id: sourceStreamId,
|
|
2343
|
+
thread_id: session.threadId,
|
|
2344
|
+
delivery_state: "queued",
|
|
2345
|
+
reason: "duplicate_request",
|
|
2346
|
+
},
|
|
2347
|
+
"codex sibling injection duplicate request ignored (already accepted)",
|
|
2348
|
+
)
|
|
2349
|
+
return {
|
|
2350
|
+
status: "delivery_queued",
|
|
2351
|
+
session: this._describe(session),
|
|
2352
|
+
delivery_id: deliveryId,
|
|
2353
|
+
accepted_via: "duplicate",
|
|
2354
|
+
reason: "duplicate_request",
|
|
2355
|
+
}
|
|
2356
|
+
}
|
|
2281
2357
|
const injectHandle = this._recordInjectSource(
|
|
2282
2358
|
session,
|
|
2283
2359
|
text,
|
|
@@ -2320,8 +2396,16 @@ export class CodexStreamBridge extends EventEmitter {
|
|
|
2320
2396
|
stream_id: sourceStreamId,
|
|
2321
2397
|
message: { role: "user", content: text },
|
|
2322
2398
|
deliveryId,
|
|
2399
|
+
// ⚠️ inputId を渡すのが「順番待ちで即返す」の肝。渡さないと input() の
|
|
2400
|
+
// `acceptedAsQueued = queuedAtArrival && !!inputId` が常に false になり、
|
|
2401
|
+
// 実際に turn/start を打つまで promise が解決しない (= 相手のターンが終わるまで
|
|
2402
|
+
// 送信元をブロックする)。browser 送信は既に inputId を渡して即返しになっている。
|
|
2403
|
+
inputId: deliveryId,
|
|
2323
2404
|
})
|
|
2324
2405
|
} catch (err) {
|
|
2406
|
+
// turn/start は 1 度も成功していない = 再送してよい。重複ガードの台帳から取り消して
|
|
2407
|
+
// おかないと、同じ request_id での正当な再送を「重複」と誤判定して握り潰す。
|
|
2408
|
+
this._forgetAcceptedInput(session, deliveryId)
|
|
2325
2409
|
this._removeInjectSource(session, injectHandle)
|
|
2326
2410
|
this.logger?.error?.(
|
|
2327
2411
|
{
|
|
@@ -2355,6 +2439,39 @@ export class CodexStreamBridge extends EventEmitter {
|
|
|
2355
2439
|
},
|
|
2356
2440
|
"codex sibling injection accepted",
|
|
2357
2441
|
)
|
|
2442
|
+
if (accepted?.method === "queued") {
|
|
2443
|
+
// 相手が応答生成中 (または pump 進行中): 次ターン FIFO に受理済み。echo は次のターンが
|
|
2444
|
+
// 始まるまで来ないので **待たない** (待てばターン 1 本ぶんブロックする)。injectHandle は
|
|
2445
|
+
// 消さずに残す — 後で届く userMessage echo を _tagInjectSourceOnItem が拾い、受け手画面で
|
|
2446
|
+
// 連携カードとして表示するために要る。
|
|
2447
|
+
// 永続記録は claude 版と同じ「受理時点」で行う (hub-agent 再起動後の hydrate で、この注入を
|
|
2448
|
+
// 通常の user 依頼として表示しないため)。
|
|
2449
|
+
recordInjectSourcePersistent(session.cwd, text, source).catch(() => {})
|
|
2450
|
+
this.logger?.info?.(
|
|
2451
|
+
{
|
|
2452
|
+
...context,
|
|
2453
|
+
delivery_id: deliveryId,
|
|
2454
|
+
stream_id: sourceStreamId,
|
|
2455
|
+
current_stream_id: session.stream_id,
|
|
2456
|
+
thread_id: session.threadId,
|
|
2457
|
+
accepted_via: accepted?.method || null,
|
|
2458
|
+
delivery_state: "queued",
|
|
2459
|
+
reason: "queued_behind_active_turn",
|
|
2460
|
+
queued: this._pendingInputItems(session).length,
|
|
2461
|
+
active_turn_id: session.activeTurnId || null,
|
|
2462
|
+
},
|
|
2463
|
+
"codex sibling injection queued behind active turn",
|
|
2464
|
+
)
|
|
2465
|
+
return {
|
|
2466
|
+
// ⚠️ delivery_unconfirmed と混ぜない。あちらは「届いたか分からない」、こちらは
|
|
2467
|
+
// 「受理済み・順番待ち・再送不要」で、送信元が取るべき行動が正反対になる。
|
|
2468
|
+
status: "delivery_queued",
|
|
2469
|
+
session: this._describe(session),
|
|
2470
|
+
delivery_id: deliveryId,
|
|
2471
|
+
accepted_via: accepted?.method || null,
|
|
2472
|
+
reason: "queued_behind_active_turn",
|
|
2473
|
+
}
|
|
2474
|
+
}
|
|
2358
2475
|
const delivery = await this._waitInjectDelivery(injectHandle)
|
|
2359
2476
|
if (!delivery?.delivered) {
|
|
2360
2477
|
this.logger?.warn?.(
|
package/src/sibling-inject.mjs
CHANGED
|
@@ -37,6 +37,15 @@
|
|
|
37
37
|
* candidates_nameable?}` を書く (`candidates_nameable` は曖昧系エラーのときのみ。CLI が
|
|
38
38
|
* 「候補を実行可能な `--to` として並べてよいか」を hint の文言に依存せず判定するための boolean)。
|
|
39
39
|
*
|
|
40
|
+
* ⚠️ codex の `delivery_state` は 4 値ある (2026-08-05 に `queued` を追加):
|
|
41
|
+
* - `delivered` … userMessage echo まで確認済み (ok:true)
|
|
42
|
+
* - `queued` … **相手が応答生成中**。次ターンのキューに受理済みで、echo は次の
|
|
43
|
+
* ターンが始まるまで来ない。**再送不要** (ok:true)
|
|
44
|
+
* - `accepted_unconfirmed` … turn RPC は通ったが echo を確認できない (ok:false)
|
|
45
|
+
* - `failed` … turn RPC が失敗。再送してよい (ok:false)
|
|
46
|
+
* `queued` を待たずに即返すのが要点で、待つと相手のターン (実測 30 分) ぶん送信元がブロックし、
|
|
47
|
+
* 待ちきれない CLI が「hub-agent が起動していない」と誤報して再送 → 二重配送になる。
|
|
48
|
+
*
|
|
40
49
|
* ⚠️ 曖昧系のエラーコードは 2 つある (2026-08-02 クロスレビュー round2 major):
|
|
41
50
|
* - `ambiguous_target` … 候補を `--to` で名指しできる (解消手段がある)
|
|
42
51
|
* - `ambiguous_target_unnameable` … 名指しでは解消できない (session_id 未確定 / resume 競合)
|
|
@@ -64,6 +73,17 @@ const DELIVERY_UNCONFIRMED_HINT =
|
|
|
64
73
|
"再送すると重複配送になります。再送前に対象セッションの受信状態または rollout 監査を確認してください。"
|
|
65
74
|
const DELIVERY_FAILED_HINT =
|
|
66
75
|
"turn RPC の受付前または受付中に失敗しました。対象セッションを確認して再送してください。"
|
|
76
|
+
/**
|
|
77
|
+
* 「受理済み・順番待ち」= 相手が応答生成中なのでメッセージは次ターンのキューに入った (2026-08-05)。
|
|
78
|
+
*
|
|
79
|
+
* ⚠️ `delivery_unconfirmed` と語彙を分ける。あちらは「届いたか分からない (再送すると重複の恐れ)」、
|
|
80
|
+
* こちらは「確実に受理された。相手のターンが終われば実行される」で、**送信元が取るべき行動が違う**
|
|
81
|
+
* (前者は受信状態の確認、後者は待つだけ)。旧実装はここで hub-agent が送信元をブロックし続け、
|
|
82
|
+
* 待ちきれない CLI が「hub-agent が起動していない」と誤報して再送 → 二重配送を起こしていた。
|
|
83
|
+
*/
|
|
84
|
+
const DELIVERY_QUEUED_HINT =
|
|
85
|
+
"相手セッションが応答生成中のため、メッセージは次ターンのキューに入りました (受理済み)。" +
|
|
86
|
+
"相手のターンが終わり次第そのまま実行されるので、再送は不要です。"
|
|
67
87
|
|
|
68
88
|
/** 曖昧だが `--to` で名指しして解消できる (候補を実行可能な宛先として案内してよい)。 */
|
|
69
89
|
export const AMBIGUOUS_TARGET_ERROR = "ambiguous_target"
|
|
@@ -148,7 +168,9 @@ function claudeCandidatesNameability(candidates) {
|
|
|
148
168
|
*/
|
|
149
169
|
function ambiguousTargetOutcome(cliKind, targetSessionId, candidates) {
|
|
150
170
|
// 名指し可否の判定はここ 1 回だけ。error も hint もこの値から導くので三者は原理的に一致する。
|
|
151
|
-
// codex
|
|
171
|
+
// codex は候補ごとに必ず一意な接続 ID (stream_id) を持つため、候補を見るまでもなく名指しで
|
|
172
|
+
// 解消できる (既定の宛先は会話 ID = thread_id だが、同じ会話に複数の接続がぶら下がると会話 ID
|
|
173
|
+
// では一意に定まらない。そのときに接続 ID で絞り込む、という降格した位置づけ)。
|
|
152
174
|
const nameability = cliKind === "codex" ? "nameable" : claudeCandidatesNameability(candidates)
|
|
153
175
|
const nameable = nameability === "nameable"
|
|
154
176
|
const lead = targetSessionId
|
|
@@ -158,7 +180,19 @@ function ambiguousTargetOutcome(cliKind, targetSessionId, candidates) {
|
|
|
158
180
|
: `この cwd には live な ${cliKind} セッションが複数あるため、宛先を省略すると一意に定まりません。`
|
|
159
181
|
let remedy
|
|
160
182
|
if (cliKind === "codex") {
|
|
161
|
-
|
|
183
|
+
// ⚠️ 「stream_id を指定」とだけ案内しない (2026-08-05)。--list / --list-all が既定で表示する
|
|
184
|
+
// 宛先は **会話 ID (thread_id)** で、stream_id は「同じ会話に複数の接続がある稀なケース」の
|
|
185
|
+
// 曖昧解消用へ降格した。利用者が画面で見ているのは --list が候補に併記する `stream=…` の
|
|
186
|
+
// 表記なので、案内もその表記に合わせる (見えていない用語を指示すると手詰まりになる)。
|
|
187
|
+
// ⚠️ 曖昧の中身は 2 通りで、必要な id が違うので案内も分ける:
|
|
188
|
+
// - 宛先省略 (targetSessionId 無し) … **別々の会話**が同居している。会話 ID で名指しできる。
|
|
189
|
+
// - 明示宛先が曖昧 (会話 ID 指定) … **同じ会話に複数の接続**。会話 ID では絞れず接続 ID が要る。
|
|
190
|
+
remedy = targetSessionId
|
|
191
|
+
? `同じ会話に複数の接続がぶら下がっているため、会話 ID では一意に定まりません。` +
|
|
192
|
+
`--list が候補に併記する接続 ID (stream=…) を --to に指定してください。`
|
|
193
|
+
: `--list が表示する宛先 (会話 ID) を --to に指定して名指ししてください。` +
|
|
194
|
+
`同じ会話に複数の接続がぶら下がっていて会話 ID でも一意に定まらない場合は、` +
|
|
195
|
+
`--list が併記する接続 ID (stream=…) を --to に指定してください。`
|
|
162
196
|
} else if (nameability === "nameable") {
|
|
163
197
|
remedy =
|
|
164
198
|
`候補はそれぞれ別の会話で session_id が異なるため、session_id で名指しできます ` +
|
|
@@ -191,6 +225,27 @@ function deliveredStateFor(kind) {
|
|
|
191
225
|
return kind === "codex" ? "delivered" : "dispatched"
|
|
192
226
|
}
|
|
193
227
|
|
|
228
|
+
/**
|
|
229
|
+
* 「受理済み・順番待ち」(`delivery_queued`) の結果を組み立てる。
|
|
230
|
+
*
|
|
231
|
+
* ⚠️ 明示宛先 / 宛先省略の **両分岐で同じ形**を返すため 1 箇所に置く (delivered /
|
|
232
|
+
* delivery_unconfirmed は 2 か所に書かれており、実際にキーが片方だけずれる余地がある)。
|
|
233
|
+
* `ok: true` にするのは、これが失敗ではなく **受理** だから。送信元に「失敗した」と読ませると
|
|
234
|
+
* 再送を誘発し、キューに 2 通並ぶ (今回直した二重配送そのもの)。ただし配達済みとも読ませない
|
|
235
|
+
* よう `delivery_state` は `delivered` ではなく `queued` にし、hint で待てばよいことを伝える。
|
|
236
|
+
*/
|
|
237
|
+
function queuedResult(r) {
|
|
238
|
+
return {
|
|
239
|
+
ok: true,
|
|
240
|
+
delivered_to: r.session ?? null,
|
|
241
|
+
delivery_id: r.delivery_id,
|
|
242
|
+
delivery_state: "queued",
|
|
243
|
+
accepted_via: r.accepted_via,
|
|
244
|
+
reason: r.reason,
|
|
245
|
+
hint: DELIVERY_QUEUED_HINT,
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
194
249
|
export class SiblingInjectBridge {
|
|
195
250
|
/**
|
|
196
251
|
* @param {{dir?: string, claudeBridge?: object, codexBridge?: object, logger?: object}} [opts]
|
|
@@ -343,8 +398,10 @@ export class SiblingInjectBridge {
|
|
|
343
398
|
} else if (isExplicit) {
|
|
344
399
|
// 明示宛先: session_id (claude) / stream_id|thread_id (codex) で cwd 一致下に確定解決。
|
|
345
400
|
// sendToStream は {status:"delivered"|"not_found"|"ambiguous"} を返す。
|
|
401
|
+
// request_id を渡すのは、bridge 側が配送 ID を **決定的に** 導出して同一依頼の再処理を
|
|
402
|
+
// 重複ガードで止められるようにするため (claude bridge は余分な引数を無視する)。
|
|
346
403
|
const r = bridge?.sendToStream
|
|
347
|
-
? await bridge.sendToStream(cwd, target_session_id, message, injectSource)
|
|
404
|
+
? await bridge.sendToStream(cwd, target_session_id, message, injectSource, request_id)
|
|
348
405
|
: { status: "not_found" }
|
|
349
406
|
if (r.status === "delivered") {
|
|
350
407
|
result = {
|
|
@@ -356,6 +413,8 @@ export class SiblingInjectBridge {
|
|
|
356
413
|
accepted_via: r.accepted_via,
|
|
357
414
|
item_id: r.item_id,
|
|
358
415
|
}
|
|
416
|
+
} else if (r.status === "delivery_queued") {
|
|
417
|
+
result = queuedResult(r)
|
|
359
418
|
} else if (r.status === "delivery_unconfirmed" || r.status === "delivery_failed") {
|
|
360
419
|
result = {
|
|
361
420
|
ok: false,
|
|
@@ -410,7 +469,7 @@ export class SiblingInjectBridge {
|
|
|
410
469
|
// あった。sendToCwd を status 返却にして解決と配送を 1 呼び出しに統合し、delivered_to は
|
|
411
470
|
// **実配送先 (r.session)** を返す。
|
|
412
471
|
const r = bridge?.sendToCwd
|
|
413
|
-
? await bridge.sendToCwd(cwd, text, injectSource)
|
|
472
|
+
? await bridge.sendToCwd(cwd, text, injectSource, request_id)
|
|
414
473
|
: { status: "not_found" }
|
|
415
474
|
if (r.status === "delivered") {
|
|
416
475
|
result = {
|
|
@@ -422,6 +481,8 @@ export class SiblingInjectBridge {
|
|
|
422
481
|
accepted_via: r.accepted_via,
|
|
423
482
|
item_id: r.item_id,
|
|
424
483
|
}
|
|
484
|
+
} else if (r.status === "delivery_queued") {
|
|
485
|
+
result = queuedResult(r)
|
|
425
486
|
} else if (r.status === "delivery_unconfirmed" || r.status === "delivery_failed") {
|
|
426
487
|
result = {
|
|
427
488
|
ok: false,
|
|
@@ -467,6 +528,7 @@ export class SiblingInjectBridge {
|
|
|
467
528
|
delivery_id: result.delivery_id,
|
|
468
529
|
delivery_state: result.delivery_state,
|
|
469
530
|
durable_state: result.durable_state,
|
|
531
|
+
reason: result.reason,
|
|
470
532
|
}
|
|
471
533
|
: {
|
|
472
534
|
error: result.error,
|
|
@@ -478,7 +540,9 @@ export class SiblingInjectBridge {
|
|
|
478
540
|
result.ok
|
|
479
541
|
? result.delivery_state === "delivered"
|
|
480
542
|
? "sibling-inject delivered"
|
|
481
|
-
:
|
|
543
|
+
: result.delivery_state === "queued"
|
|
544
|
+
? "sibling-inject queued"
|
|
545
|
+
: "sibling-inject dispatched"
|
|
482
546
|
: "sibling-inject failed",
|
|
483
547
|
)
|
|
484
548
|
await this._writeResult(request_id, result)
|