tailii-host 0.9.0 → 0.10.0
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/dist/backend/herdr.js +8 -1
- package/dist/backend/herdr.js.map +1 -1
- package/dist/backend/tmux.js +90 -15
- package/dist/backend/tmux.js.map +1 -1
- package/dist/chat/subagentTranscript.js +4 -0
- package/dist/chat/subagentTranscript.js.map +1 -1
- package/dist/chat/transcriptTailer.js +8 -0
- package/dist/chat/transcriptTailer.js.map +1 -1
- package/dist/codex/codexAppServer.d.ts +74 -3
- package/dist/codex/codexAppServer.js +252 -12
- package/dist/codex/codexAppServer.js.map +1 -1
- package/dist/codex/codexNativeTurnController.d.ts +99 -2
- package/dist/codex/codexNativeTurnController.js +218 -8
- package/dist/codex/codexNativeTurnController.js.map +1 -1
- package/dist/codex/codexPlanItem.d.ts +14 -0
- package/dist/codex/codexPlanItem.js +50 -0
- package/dist/codex/codexPlanItem.js.map +1 -0
- package/dist/codex/codexRolloutTailer.d.ts +10 -0
- package/dist/codex/codexRolloutTailer.js +60 -2
- package/dist/codex/codexRolloutTailer.js.map +1 -1
- package/dist/codex/codexSystemNotice.d.ts +22 -1
- package/dist/codex/codexSystemNotice.js +46 -0
- package/dist/codex/codexSystemNotice.js.map +1 -1
- package/dist/engine/engine.js +1 -0
- package/dist/engine/engine.js.map +1 -1
- package/dist/engine/handlers/codex.js +36 -1
- package/dist/engine/handlers/codex.js.map +1 -1
- package/dist/hub/hubProtocol.d.ts +22 -1
- package/dist/hub/hubProtocol.js +53 -1
- package/dist/hub/hubProtocol.js.map +1 -1
- package/dist/hub/sessionHub.d.ts +12 -0
- package/dist/hub/sessionHub.js +96 -5
- package/dist/hub/sessionHub.js.map +1 -1
- package/dist/protocol/decode.js +52 -0
- package/dist/protocol/decode.js.map +1 -1
- package/dist/protocol/messages.d.ts +58 -0
- package/dist/sessions/claudeSessionStore.js +4 -0
- package/dist/sessions/claudeSessionStore.js.map +1 -1
- package/dist/sessions/sessionSearch.js +5 -0
- package/dist/sessions/sessionSearch.js.map +1 -1
- package/dist/shared/clientBuild.d.ts +1 -1
- package/dist/shared/clientBuild.js +1 -1
- package/dist/shared/clientBuild.js.map +1 -1
- package/dist/shared/compactSummary.d.ts +9 -0
- package/dist/shared/compactSummary.js +16 -0
- package/dist/shared/compactSummary.js.map +1 -0
- package/package.json +3 -3
package/dist/hub/sessionHub.js
CHANGED
|
@@ -12,7 +12,7 @@ import { PROTOCOL_V1, PROTOCOL_V2 } from "../protocol.js";
|
|
|
12
12
|
import { ChatInjectionRejectedError, LoginCodeError } from "../backend/tmux.js";
|
|
13
13
|
import { CodexAppServerManager } from "../codex/codexAppServer.js";
|
|
14
14
|
import { CodexNativeTurnController, chatContentKey, } from "../codex/codexNativeTurnController.js";
|
|
15
|
-
import { CONTEXT_STREAM_ID as CODEX_CONTEXT_STREAM_ID, CONTEXT_WINDOW_STREAM_ID as CODEX_CONTEXT_WINDOW_STREAM_ID, MODEL_STREAM_ID as CODEX_MODEL_STREAM_ID, } from "../codex/codexRolloutTailer.js";
|
|
15
|
+
import { COLLABORATION_MODE_STREAM_ID as CODEX_COLLABORATION_MODE_STREAM_ID, CONTEXT_STREAM_ID as CODEX_CONTEXT_STREAM_ID, CONTEXT_WINDOW_STREAM_ID as CODEX_CONTEXT_WINDOW_STREAM_ID, MODEL_STREAM_ID as CODEX_MODEL_STREAM_ID, } from "../codex/codexRolloutTailer.js";
|
|
16
16
|
import { claudeTranscriptPathFor } from "../sessions/transcriptPath.js";
|
|
17
17
|
/**
|
|
18
18
|
* backfilling 中の購読者は publishConversationEvent が丸ごと飛ばす。旗が立ちっぱなしになると
|
|
@@ -510,6 +510,40 @@ export class SessionHub {
|
|
|
510
510
|
void this.drainCodexQueue(message.session, actor);
|
|
511
511
|
return;
|
|
512
512
|
}
|
|
513
|
+
if (message.type === "codex_goal_submit") {
|
|
514
|
+
// 目標操作(codex-goal)。turn と同じ hub 所有の thread 接続で実行し、結果と通知を会話 stream へ返す。
|
|
515
|
+
const controller = this.ensureCodexTurnController();
|
|
516
|
+
const goal = controller.goal;
|
|
517
|
+
if (goal === undefined) {
|
|
518
|
+
this.sendTo(client, {
|
|
519
|
+
type: "codex_goal_result", id: message.id, status: "failed",
|
|
520
|
+
error: "この host の Codex 連携は目標(goal)に対応していません。",
|
|
521
|
+
});
|
|
522
|
+
return;
|
|
523
|
+
}
|
|
524
|
+
void goal.call(controller, {
|
|
525
|
+
session: message.session, threadId: message.threadId, cwd: message.cwd, action: message.action,
|
|
526
|
+
...(message.objective !== undefined ? { objective: message.objective } : {}),
|
|
527
|
+
...(message.status !== undefined ? { status: message.status } : {}),
|
|
528
|
+
...(message.tokenBudget !== undefined ? { tokenBudget: message.tokenBudget } : {}),
|
|
529
|
+
}).then((result) => {
|
|
530
|
+
this.sendTo(client, {
|
|
531
|
+
type: "codex_goal_result", id: message.id, status: "ok",
|
|
532
|
+
...(result.goal !== null ? { goal: result.goal } : {}),
|
|
533
|
+
...(result.cleared !== undefined ? { cleared: result.cleared } : {}),
|
|
534
|
+
});
|
|
535
|
+
// 解除 / 完了後に購読者も turn も無ければ、目標のために保持していた thread 接続を畳む。
|
|
536
|
+
this.maybeCloseIdleCodexSession(message.session);
|
|
537
|
+
}, (error) => {
|
|
538
|
+
this.options.log?.(`codex goal ${message.action} 失敗 session=${message.session}: ${String(error)}`);
|
|
539
|
+
this.sendTo(client, {
|
|
540
|
+
type: "codex_goal_result", id: message.id, status: "failed", error: String(error),
|
|
541
|
+
});
|
|
542
|
+
// 失敗でも、この操作のために開いただけの thread 接続は残さない。
|
|
543
|
+
this.maybeCloseIdleCodexSession(message.session);
|
|
544
|
+
});
|
|
545
|
+
return;
|
|
546
|
+
}
|
|
513
547
|
if (message.type === "codex_turn_interrupt") {
|
|
514
548
|
void this.codexTurnController?.interruptTurn?.(message.session).catch((error) => {
|
|
515
549
|
this.publishCodexMarker(message.session, `codex-interrupt-error-${message.id}`, `⚠️ Codex turn 中断失敗: ${String(error)}`);
|
|
@@ -881,10 +915,22 @@ export class SessionHub {
|
|
|
881
915
|
actor.tail?.stop();
|
|
882
916
|
actor.tail = null;
|
|
883
917
|
actor.codexLive = null;
|
|
884
|
-
|
|
885
|
-
this.codexTurnController?.closeSession(session);
|
|
918
|
+
this.maybeCloseIdleCodexSession(session);
|
|
886
919
|
}
|
|
887
920
|
}
|
|
921
|
+
/**
|
|
922
|
+
* 購読者ゼロ・turn なし・active な目標なし、のときだけ Codex thread 接続を畳む。
|
|
923
|
+
* 目標が active な間は購読者がいなくても保持する(継続 turn を観測するため, codex-goal)。
|
|
924
|
+
*/
|
|
925
|
+
maybeCloseIdleCodexSession(session) {
|
|
926
|
+
if ((this.actors.get(session)?.subscribers.size ?? 0) > 0)
|
|
927
|
+
return;
|
|
928
|
+
if (this.activeCodexTurns.has(session))
|
|
929
|
+
return;
|
|
930
|
+
if (this.codexTurnController?.hasActiveGoal?.(session) === true)
|
|
931
|
+
return;
|
|
932
|
+
this.codexTurnController?.closeSession(session);
|
|
933
|
+
}
|
|
888
934
|
startSharedTail(session, actor, newerThanMs) {
|
|
889
935
|
const meta = this.options.metadataStore.get(session);
|
|
890
936
|
if (meta === null) {
|
|
@@ -933,6 +979,8 @@ export class SessionHub {
|
|
|
933
979
|
lastModel: null,
|
|
934
980
|
subscribedModel: null,
|
|
935
981
|
scanLastModel: null,
|
|
982
|
+
subscribedCollaborationMode: null,
|
|
983
|
+
lastCollaborationMode: null,
|
|
936
984
|
};
|
|
937
985
|
actor.codexLive = state;
|
|
938
986
|
// 履歴表示は rollout だけで完結する。App Server の購読(daemon 起動・接続・thread/resume・
|
|
@@ -955,6 +1003,7 @@ export class SessionHub {
|
|
|
955
1003
|
// 会話を開いていない間の /model や設定変更は thread/settings/updated が誰にも届かない。
|
|
956
1004
|
// resume 応答の現在モデルを backfill 完了後に配信し、開き直しで表示を実体へ揃える。
|
|
957
1005
|
state.subscribedModel = snapshot.model ?? null;
|
|
1006
|
+
state.subscribedCollaborationMode = snapshot.collaborationMode ?? null;
|
|
958
1007
|
if (!snapshot.liveSubscribed) {
|
|
959
1008
|
this.options.log?.(`Codex App Server の履歴スナップショットが読めない(turn 前の未materialize か履歴読み取り失敗)ため、rollout fallbackへ移行 session=${session} thread=${threadId}` +
|
|
960
1009
|
(snapshot.liveSubscriptionError ? `(理由: ${snapshot.liveSubscriptionError})` : ""));
|
|
@@ -1006,6 +1055,14 @@ export class SessionHub {
|
|
|
1006
1055
|
// 処理中状態を自己修復できない。
|
|
1007
1056
|
}
|
|
1008
1057
|
this.publishCodexModelMarker(session, actor, state, subscribedModel);
|
|
1058
|
+
// thread の現在の collaboration mode(controller が把握している場合)。履歴(task_started)由来の値は
|
|
1059
|
+
// iOS が採用しないので、実体はここで 1 回配る(codex-plan-mode)。
|
|
1060
|
+
const subscribedCollaborationMode = state.subscribedCollaborationMode;
|
|
1061
|
+
state.subscribedCollaborationMode = null;
|
|
1062
|
+
if (subscribedCollaborationMode !== null) {
|
|
1063
|
+
state.lastCollaborationMode = subscribedCollaborationMode;
|
|
1064
|
+
this.publishCodexMarker(session, CODEX_COLLABORATION_MODE_STREAM_ID, subscribedCollaborationMode);
|
|
1065
|
+
}
|
|
1009
1066
|
}
|
|
1010
1067
|
openCodexRollout(session, actor, cwd, threadId, newerThanMs) {
|
|
1011
1068
|
if (this.options.tailFactory === undefined)
|
|
@@ -1307,6 +1364,15 @@ export class SessionHub {
|
|
|
1307
1364
|
type: "conversation_event", session, serverSeq: 0, payload: codexModelMarker(currentModel),
|
|
1308
1365
|
});
|
|
1309
1366
|
}
|
|
1367
|
+
// collaboration mode も同様(turn を伴わない `/plan` 等は境界前の live 配信にしか無い, codex-plan-mode)。
|
|
1368
|
+
const currentCollaborationMode = actor.codexLive?.lastCollaborationMode ?? null;
|
|
1369
|
+
if (currentCollaborationMode !== null) {
|
|
1370
|
+
this.sendTo(client, {
|
|
1371
|
+
type: "conversation_event", session, serverSeq: 0,
|
|
1372
|
+
payload: { type: "chat_output", v: PROTOCOL_V1, streamId: CODEX_COLLABORATION_MODE_STREAM_ID,
|
|
1373
|
+
role: "system", text: currentCollaborationMode, eof: true },
|
|
1374
|
+
});
|
|
1375
|
+
}
|
|
1310
1376
|
};
|
|
1311
1377
|
// 進捗は「最後に 1 行流れた時刻」で測る。履歴行ごとに setTimeout を張り替えると
|
|
1312
1378
|
// 巨大な transcript でタイマー生成が支配的になるため、タイマーは 1 本のまま残時間を見る。
|
|
@@ -1706,9 +1772,29 @@ export class SessionHub {
|
|
|
1706
1772
|
this.activeCodexTurns.delete(session);
|
|
1707
1773
|
this.applyProcessing(session, state);
|
|
1708
1774
|
this.broadcast({ type: "session_processing", session, state });
|
|
1709
|
-
|
|
1710
|
-
|
|
1775
|
+
// 購読者ゼロで turn が終われば接続を畳む。ただし目標(goal)が active な会話は畳まない:
|
|
1776
|
+
// 継続 turn は server 起点で、購読を落とすと処理中 / heartbeat / 完了通知を観測できない
|
|
1777
|
+
// (reaper が idle 扱いで pane を掃除する)ため(codex-goal)。
|
|
1778
|
+
if (state === "done")
|
|
1779
|
+
this.maybeCloseIdleCodexSession(session);
|
|
1780
|
+
},
|
|
1781
|
+
onGoal: (session, goal) => {
|
|
1782
|
+
// 目標の現在値を会話 stream に載せる(replay buffer 経由で後から加わった購読者にも届く)。
|
|
1783
|
+
this.publishConversationEvent(session, this.actor(session), {
|
|
1784
|
+
type: "codex_goal_state", v: PROTOCOL_V2, session, ...(goal !== null ? { goal } : {}),
|
|
1785
|
+
});
|
|
1786
|
+
if (goal === null || goal.status !== "active")
|
|
1787
|
+
this.maybeCloseIdleCodexSession(session);
|
|
1788
|
+
},
|
|
1789
|
+
onCollaborationMode: (session, mode) => {
|
|
1790
|
+
// backfill 中は iOS が live 行を history-done まで捨てるため、finish で配る値も最新へ更新しておく。
|
|
1791
|
+
const live = this.actors.get(session)?.codexLive ?? null;
|
|
1792
|
+
if (live !== null) {
|
|
1793
|
+
live.lastCollaborationMode = mode;
|
|
1794
|
+
if (live.phase === "backfill")
|
|
1795
|
+
live.subscribedCollaborationMode = mode;
|
|
1711
1796
|
}
|
|
1797
|
+
this.publishCodexMarker(session, CODEX_COLLABORATION_MODE_STREAM_ID, mode);
|
|
1712
1798
|
},
|
|
1713
1799
|
onModel: (session, model) => this.publishCodexMarker(session, CODEX_MODEL_STREAM_ID, model),
|
|
1714
1800
|
onTokenUsage: (session, totalTokens, contextWindow) => {
|
|
@@ -1801,6 +1887,10 @@ export class SessionHub {
|
|
|
1801
1887
|
effort: message.effort,
|
|
1802
1888
|
approvalPolicy: message.approvalPolicy,
|
|
1803
1889
|
sandbox: message.sandbox,
|
|
1890
|
+
// collaboration mode(プランモード, codex-plan-mode)。旧 engine は付けないので従来どおり省略。
|
|
1891
|
+
...(message.collaborationMode !== undefined && message.collaborationMode !== null
|
|
1892
|
+
? { collaborationMode: message.collaborationMode }
|
|
1893
|
+
: {}),
|
|
1804
1894
|
});
|
|
1805
1895
|
const actor = this.actors.get(message.session);
|
|
1806
1896
|
if (actor === undefined || actor !== expectedActor)
|
|
@@ -2428,6 +2518,7 @@ function sameCodexRetry(left, right) {
|
|
|
2428
2518
|
left.clientUserMessageId === right.clientUserMessageId && left.effort === right.effort &&
|
|
2429
2519
|
(left.approvalPolicy ?? null) === (right.approvalPolicy ?? null) &&
|
|
2430
2520
|
left.sandbox === right.sandbox &&
|
|
2521
|
+
(left.collaborationMode ?? null) === (right.collaborationMode ?? null) &&
|
|
2431
2522
|
left.threadId === right.threadId && left.cwd === right.cwd;
|
|
2432
2523
|
}
|
|
2433
2524
|
/** 利用中モデル通知(`pc:model`)の conversation_event payload。 */
|