@dotobokuri/fleet-console 1.62.0 → 1.63.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/README.md +1 -0
- package/dist/cli.mjs +60 -18
- package/dist/client/assets/{_baseUniq-B6CLI4cf.js → _baseUniq-CVUU389k.js} +1 -1
- package/dist/client/assets/{arc-r3CRqUQ5.js → arc-Fg3WjPoW.js} +1 -1
- package/dist/client/assets/{architectureDiagram-Q4EWVU46-CJfgw2eJ.js → architectureDiagram-Q4EWVU46-gAB_QWIv.js} +1 -1
- package/dist/client/assets/{blockDiagram-DXYQGD6D-CkBuOBUs.js → blockDiagram-DXYQGD6D-DCY_3CSv.js} +1 -1
- package/dist/client/assets/{c4Diagram-AHTNJAMY-Ln5TenJL.js → c4Diagram-AHTNJAMY-2ai4d9rg.js} +1 -1
- package/dist/client/assets/channel-DlA1BRCV.js +1 -0
- package/dist/client/assets/{chunk-4BX2VUAB-BiYTw90k.js → chunk-4BX2VUAB-C-sjgNCE.js} +1 -1
- package/dist/client/assets/{chunk-4TB4RGXK-nPQaGu1w.js → chunk-4TB4RGXK-Co7w9KaD.js} +1 -1
- package/dist/client/assets/{chunk-55IACEB6-BU2oCJkl.js → chunk-55IACEB6-Dspr2174.js} +1 -1
- package/dist/client/assets/{chunk-EDXVE4YY-Ej7y6KOv.js → chunk-EDXVE4YY-UzzG0ax3.js} +1 -1
- package/dist/client/assets/{chunk-FMBD7UC4-hOkBpfhE.js → chunk-FMBD7UC4-DKXcUQqJ.js} +1 -1
- package/dist/client/assets/{chunk-OYMX7WX6-Cv43HwvT.js → chunk-OYMX7WX6-vW--qrkP.js} +1 -1
- package/dist/client/assets/{chunk-QZHKN3VN-Bi7AEJxb.js → chunk-QZHKN3VN-DyE-yBhf.js} +1 -1
- package/dist/client/assets/{chunk-YZCP3GAM-CBwmJdga.js → chunk-YZCP3GAM-C7LLTO2-.js} +1 -1
- package/dist/client/assets/classDiagram-6PBFFD2Q-rBpGSdtk.js +1 -0
- package/dist/client/assets/classDiagram-v2-HSJHXN6E-rBpGSdtk.js +1 -0
- package/dist/client/assets/clone-_1aYWCbr.js +1 -0
- package/dist/client/assets/{cose-bilkent-S5V4N54A-ERDn7bly.js → cose-bilkent-S5V4N54A-BkDNeJiw.js} +1 -1
- package/dist/client/assets/{dagre-KV5264BT-DapcbnEu.js → dagre-KV5264BT-DqeN9oF3.js} +1 -1
- package/dist/client/assets/{diagram-5BDNPKRD-DbRBVaVH.js → diagram-5BDNPKRD-BXzt4-3Y.js} +1 -1
- package/dist/client/assets/{diagram-G4DWMVQ6-CLP0MwBH.js → diagram-G4DWMVQ6-DbzDYVOf.js} +1 -1
- package/dist/client/assets/{diagram-MMDJMWI5-BMZ9AsEI.js → diagram-MMDJMWI5-wPQu3o7B.js} +1 -1
- package/dist/client/assets/{diagram-TYMM5635-DtPPkZ2y.js → diagram-TYMM5635-C-vwFwzf.js} +1 -1
- package/dist/client/assets/{erDiagram-SMLLAGMA-DIvbhhTb.js → erDiagram-SMLLAGMA-CcukuTgN.js} +1 -1
- package/dist/client/assets/{flowDiagram-DWJPFMVM-C_R3RpTk.js → flowDiagram-DWJPFMVM-BT8ZNr2Y.js} +1 -1
- package/dist/client/assets/{ganttDiagram-T4ZO3ILL-eaIqpHsY.js → ganttDiagram-T4ZO3ILL-B_wNcZrL.js} +1 -1
- package/dist/client/assets/{gitGraphDiagram-UUTBAWPF-CYCsHY_E.js → gitGraphDiagram-UUTBAWPF-dUwwvDSd.js} +1 -1
- package/dist/client/assets/{graph-HfvOsgk2.js → graph-C4i_jr7e.js} +1 -1
- package/dist/client/assets/index-BXtDpU36.js +465 -0
- package/dist/client/assets/index-CLb_APbh.css +1 -0
- package/dist/client/assets/{infoDiagram-42DDH7IO-rmDH5YRZ.js → infoDiagram-42DDH7IO-Bf2KPu0t.js} +1 -1
- package/dist/client/assets/{ishikawaDiagram-UXIWVN3A-EAZO3mIY.js → ishikawaDiagram-UXIWVN3A-DjHChg2o.js} +1 -1
- package/dist/client/assets/{journeyDiagram-VCZTEJTY-4vWYlXOF.js → journeyDiagram-VCZTEJTY-B08epGYF.js} +1 -1
- package/dist/client/assets/{kanban-definition-6JOO6SKY-CkkSfsbD.js → kanban-definition-6JOO6SKY-BFasXRgc.js} +1 -1
- package/dist/client/assets/{layout-DWbhbrdO.js → layout-Q_W10VzL.js} +1 -1
- package/dist/client/assets/{linear-BjRBsqi0.js → linear-Dy4fc5kq.js} +1 -1
- package/dist/client/assets/{mermaid.core-RuG-kUU2.js → mermaid.core-OtTy8N5f.js} +4 -4
- package/dist/client/assets/{min-D--jZrv5.js → min-DODD7JTz.js} +1 -1
- package/dist/client/assets/{mindmap-definition-QFDTVHPH-fLwhQBcX.js → mindmap-definition-QFDTVHPH-DMhpsiYD.js} +1 -1
- package/dist/client/assets/{pieDiagram-DEJITSTG-DJkWnAQK.js → pieDiagram-DEJITSTG-C5usaVgs.js} +1 -1
- package/dist/client/assets/{quadrantDiagram-34T5L4WZ-Kd4q9kEz.js → quadrantDiagram-34T5L4WZ-B-b2NvBz.js} +1 -1
- package/dist/client/assets/{requirementDiagram-MS252O5E-Bgrtq8Kh.js → requirementDiagram-MS252O5E-D6_4jY3n.js} +1 -1
- package/dist/client/assets/{sankeyDiagram-XADWPNL6-BW9BdQ-8.js → sankeyDiagram-XADWPNL6-B6imEhCV.js} +1 -1
- package/dist/client/assets/{sequenceDiagram-FGHM5R23-KpgcxIJb.js → sequenceDiagram-FGHM5R23-BRHNnuqK.js} +1 -1
- package/dist/client/assets/{stateDiagram-FHFEXIEX-CNaCHtL2.js → stateDiagram-FHFEXIEX-RiIddIHL.js} +1 -1
- package/dist/client/assets/stateDiagram-v2-QKLJ7IA2-CsHfIgMa.js +1 -0
- package/dist/client/assets/{timeline-definition-GMOUNBTQ-MGPKEXGI.js → timeline-definition-GMOUNBTQ-BhP14Blt.js} +1 -1
- package/dist/client/assets/{vennDiagram-DHZGUBPP-bDOCVDJ1.js → vennDiagram-DHZGUBPP-CtzwrBNs.js} +1 -1
- package/dist/client/assets/{wardley-RL74JXVD-DuvLJQPg.js → wardley-RL74JXVD-TXsee18-.js} +1 -1
- package/dist/client/assets/{wardleyDiagram-NUSXRM2D-BdBIEtIl.js → wardleyDiagram-NUSXRM2D-CrJP7pf7.js} +1 -1
- package/dist/client/assets/{xychartDiagram-5P7HB3ND-vycMI6c3.js → xychartDiagram-5P7HB3ND-rB-PigjI.js} +1 -1
- package/dist/client/index.html +2 -2
- package/dist/fleet-plugins/ledger/routes.mjs +7 -12
- package/dist/fleet-plugins/quota/routes.mjs +7 -12
- package/dist/fleet-plugins/scuttlebutt/routes.mjs +44 -15
- package/dist/fleet-plugins/terminal/routes.mjs +300 -88
- package/dist/fleet.mjs +443 -222
- package/package.json +1 -1
- package/dist/client/assets/channel-DBCxCWtI.js +0 -1
- package/dist/client/assets/classDiagram-6PBFFD2Q-QQSWiJjR.js +0 -1
- package/dist/client/assets/classDiagram-v2-HSJHXN6E-QQSWiJjR.js +0 -1
- package/dist/client/assets/clone-vom5rXcJ.js +0 -1
- package/dist/client/assets/index-C2erdgSj.css +0 -1
- package/dist/client/assets/index-CrEYBugN.js +0 -465
- package/dist/client/assets/stateDiagram-v2-QKLJ7IA2-D3k4sLJ4.js +0 -1
|
@@ -20834,12 +20834,12 @@ var benchmarks_default = {
|
|
|
20834
20834
|
};
|
|
20835
20835
|
var models_default = {
|
|
20836
20836
|
version: 1,
|
|
20837
|
-
updatedAt: "2026-08-
|
|
20837
|
+
updatedAt: "2026-08-17T00:00:00Z",
|
|
20838
20838
|
providers: {
|
|
20839
20839
|
codex: {
|
|
20840
20840
|
name: "Codex",
|
|
20841
20841
|
defaultModel: "gpt-5.6-sol",
|
|
20842
|
-
source: "codex app-server model/list (codex-cli 0.147.0, 2026-08-11
|
|
20842
|
+
source: "codex app-server model/list (codex-cli 0.147.0, observed 2026-08-11) for model/effort/service-tier; Fleet catalog effort ladders are capped at max because harness launch capabilities are not model rungs; contextWindow=272000 is codex debug models context_window/max_context_window (codex-cli 0.146.0, observed 2026-08-02)",
|
|
20843
20843
|
models: [
|
|
20844
20844
|
{
|
|
20845
20845
|
modelId: "gpt-5.6-sol",
|
|
@@ -20853,8 +20853,7 @@ var models_default = {
|
|
|
20853
20853
|
"medium",
|
|
20854
20854
|
"high",
|
|
20855
20855
|
"xhigh",
|
|
20856
|
-
"max"
|
|
20857
|
-
"ultra"
|
|
20856
|
+
"max"
|
|
20858
20857
|
]
|
|
20859
20858
|
},
|
|
20860
20859
|
aliases: [
|
|
@@ -20876,8 +20875,7 @@ var models_default = {
|
|
|
20876
20875
|
"medium",
|
|
20877
20876
|
"high",
|
|
20878
20877
|
"xhigh",
|
|
20879
|
-
"max"
|
|
20880
|
-
"ultra"
|
|
20878
|
+
"max"
|
|
20881
20879
|
]
|
|
20882
20880
|
},
|
|
20883
20881
|
aliases: [
|
|
@@ -20897,8 +20895,7 @@ var models_default = {
|
|
|
20897
20895
|
"medium",
|
|
20898
20896
|
"high",
|
|
20899
20897
|
"xhigh",
|
|
20900
|
-
"max"
|
|
20901
|
-
"ultra"
|
|
20898
|
+
"max"
|
|
20902
20899
|
]
|
|
20903
20900
|
},
|
|
20904
20901
|
aliases: [
|
|
@@ -20920,8 +20917,7 @@ var models_default = {
|
|
|
20920
20917
|
"medium",
|
|
20921
20918
|
"high",
|
|
20922
20919
|
"xhigh",
|
|
20923
|
-
"max"
|
|
20924
|
-
"ultra"
|
|
20920
|
+
"max"
|
|
20925
20921
|
]
|
|
20926
20922
|
},
|
|
20927
20923
|
aliases: [
|
|
@@ -21453,8 +21449,7 @@ var GATEWAY_REASONING_EFFORTS = [
|
|
|
21453
21449
|
"medium",
|
|
21454
21450
|
"high",
|
|
21455
21451
|
"xhigh",
|
|
21456
|
-
"max"
|
|
21457
|
-
"ultra"
|
|
21452
|
+
"max"
|
|
21458
21453
|
];
|
|
21459
21454
|
var GatewayEffortUpstreamModelIdsSchema = external_exports.partialRecord(
|
|
21460
21455
|
external_exports.enum(GATEWAY_REASONING_EFFORTS),
|
|
@@ -21881,8 +21876,7 @@ var ANTHROPIC_EFFORT_RUNGS = /* @__PURE__ */ new Set([
|
|
|
21881
21876
|
"medium",
|
|
21882
21877
|
"high",
|
|
21883
21878
|
"xhigh",
|
|
21884
|
-
"max"
|
|
21885
|
-
"ultra"
|
|
21879
|
+
"max"
|
|
21886
21880
|
]);
|
|
21887
21881
|
function freezeGatewayModelEffort(effort) {
|
|
21888
21882
|
if (!effort?.supported) return UNSUPPORTED_GATEWAY_MODEL_EFFORT;
|
|
@@ -31491,11 +31485,10 @@ var GENERAL_PURPOSE_AGENT_PROMPT = [
|
|
|
31491
31485
|
].join("\n");
|
|
31492
31486
|
var FLEET_PLUGIN_NAME = "fleet";
|
|
31493
31487
|
function exposedEffortLadder(modelId, ladder, exposure) {
|
|
31494
|
-
const deliverable = ladder.filter((rung) => rung !== "ultra");
|
|
31495
31488
|
const chosen = exposure?.[modelId];
|
|
31496
|
-
if (chosen === void 0 || chosen.length === 0) return
|
|
31497
|
-
const narrowed =
|
|
31498
|
-
return narrowed.length > 0 ? narrowed :
|
|
31489
|
+
if (chosen === void 0 || chosen.length === 0) return ladder;
|
|
31490
|
+
const narrowed = ladder.filter((rung) => chosen.includes(rung));
|
|
31491
|
+
return narrowed.length > 0 ? narrowed : ladder;
|
|
31499
31492
|
}
|
|
31500
31493
|
function buildGatewayCustomAgents(exposed, exposure) {
|
|
31501
31494
|
const agents = {};
|
|
@@ -44313,6 +44306,9 @@ function shouldSyncDirectoryForTest(platform) {
|
|
|
44313
44306
|
function readSocketRole(value) {
|
|
44314
44307
|
return value === "viewer" ? "viewer" : void 0;
|
|
44315
44308
|
}
|
|
44309
|
+
function readTicketChannel(value) {
|
|
44310
|
+
return value === "chat" ? "chat" : void 0;
|
|
44311
|
+
}
|
|
44316
44312
|
var DEFAULT_TICKET_TTL_MS = 1e4;
|
|
44317
44313
|
function createPluginTerminalTicketRegistry(deps = {}) {
|
|
44318
44314
|
const ttlMs = deps.ttlMs ?? DEFAULT_TICKET_TTL_MS;
|
|
@@ -45000,7 +44996,23 @@ function createPluginTerminalUpgradeHandler(deps) {
|
|
|
45000
44996
|
return true;
|
|
45001
44997
|
}
|
|
45002
44998
|
const context = deps.tickets.consume(url2.searchParams.get("ticket"));
|
|
45003
|
-
if (!context
|
|
44999
|
+
if (!context) {
|
|
45000
|
+
socket.destroy();
|
|
45001
|
+
return true;
|
|
45002
|
+
}
|
|
45003
|
+
if (context.channel === "chat") {
|
|
45004
|
+
const attachChat = deps.attachChat;
|
|
45005
|
+
if (!attachChat) {
|
|
45006
|
+
socket.destroy();
|
|
45007
|
+
return true;
|
|
45008
|
+
}
|
|
45009
|
+
const server2 = getWebSocketServer();
|
|
45010
|
+
server2.handleUpgrade(req, socket, head, (ws) => {
|
|
45011
|
+
attachChat(ws, context);
|
|
45012
|
+
});
|
|
45013
|
+
return true;
|
|
45014
|
+
}
|
|
45015
|
+
if (!deps.sessions.canAttach(context.sessionId)) {
|
|
45004
45016
|
socket.destroy();
|
|
45005
45017
|
return true;
|
|
45006
45018
|
}
|
|
@@ -45039,6 +45051,7 @@ function readUpgradeUrl(req) {
|
|
|
45039
45051
|
var SHELL_OPERATION_TYPE = "shell";
|
|
45040
45052
|
function createTerminalRuntime(ctx) {
|
|
45041
45053
|
const tickets = createPluginTerminalTicketRegistry();
|
|
45054
|
+
let chatAttach = null;
|
|
45042
45055
|
const terminalExitListeners = /* @__PURE__ */ new Set();
|
|
45043
45056
|
const terminalTitleListeners = /* @__PURE__ */ new Map();
|
|
45044
45057
|
const terminalLaunchResolvers = /* @__PURE__ */ new Map();
|
|
@@ -45061,7 +45074,14 @@ function createTerminalRuntime(ctx) {
|
|
|
45061
45074
|
const upgrade = createPluginTerminalUpgradeHandler({
|
|
45062
45075
|
tickets,
|
|
45063
45076
|
sessions,
|
|
45064
|
-
isAuthorized: ctx.host.security.isTerminalAuthorized
|
|
45077
|
+
isAuthorized: ctx.host.security.isTerminalAuthorized,
|
|
45078
|
+
attachChat: (socket, context) => {
|
|
45079
|
+
if (!chatAttach) {
|
|
45080
|
+
socket.close(1013, "chat_unavailable");
|
|
45081
|
+
return;
|
|
45082
|
+
}
|
|
45083
|
+
chatAttach(socket, context);
|
|
45084
|
+
}
|
|
45065
45085
|
});
|
|
45066
45086
|
return {
|
|
45067
45087
|
handleUpgrade: upgrade.handleUpgrade,
|
|
@@ -45097,7 +45117,14 @@ function createTerminalRuntime(ctx) {
|
|
|
45097
45117
|
if (terminalLaunchResolvers.get(operationType) === resolver) terminalLaunchResolvers.delete(operationType);
|
|
45098
45118
|
};
|
|
45099
45119
|
},
|
|
45120
|
+
bindChatAttach: (attach) => {
|
|
45121
|
+
chatAttach = attach;
|
|
45122
|
+
return () => {
|
|
45123
|
+
if (chatAttach === attach) chatAttach = null;
|
|
45124
|
+
};
|
|
45125
|
+
},
|
|
45100
45126
|
stop: async () => {
|
|
45127
|
+
chatAttach = null;
|
|
45101
45128
|
upgrade.close();
|
|
45102
45129
|
await sessions.stop();
|
|
45103
45130
|
terminalExitListeners.clear();
|
|
@@ -45345,6 +45372,7 @@ var EFFORT_LABELS = {
|
|
|
45345
45372
|
ultra: "ULTRACODE"
|
|
45346
45373
|
};
|
|
45347
45374
|
var APEX_EFFORTS = ["max", "ultra"];
|
|
45375
|
+
var ULTRACODE_LAUNCH_EFFORT = "ultra";
|
|
45348
45376
|
var NATIVE_MODEL_LABELS = {
|
|
45349
45377
|
// Claude Code's 1M coordinates stay under their plain menu labels.
|
|
45350
45378
|
"fable[1m]": "Fable",
|
|
@@ -45401,27 +45429,27 @@ function buildClaudeGatewayLaunchVariants(selection) {
|
|
|
45401
45429
|
}
|
|
45402
45430
|
return groups;
|
|
45403
45431
|
}
|
|
45404
|
-
var EFFORT_AXIS = [...NATIVE_CLAUDE_EFFORTS,
|
|
45432
|
+
var EFFORT_AXIS = [...NATIVE_CLAUDE_EFFORTS, ULTRACODE_LAUNCH_EFFORT];
|
|
45405
45433
|
function providerGroupId(provider) {
|
|
45406
45434
|
return `gateway:${provider}`;
|
|
45407
45435
|
}
|
|
45408
45436
|
function toGatewayRow(model, selection) {
|
|
45409
|
-
const
|
|
45410
|
-
const
|
|
45411
|
-
const effortAxis =
|
|
45437
|
+
const ordinary = selection.effortExposure[model.id] ?? exposableEffortLadder(model);
|
|
45438
|
+
const hasMax = ordinary.includes("max");
|
|
45439
|
+
const effortAxis = ordinary.length === 0 ? [ULTRACODE_LAUNCH_EFFORT] : [...NATIVE_CLAUDE_EFFORTS.filter((effort) => effort !== "max" || hasMax), ULTRACODE_LAUNCH_EFFORT];
|
|
45440
|
+
const gatedEfforts = hasMax ? ["max", ULTRACODE_LAUNCH_EFFORT] : [ULTRACODE_LAUNCH_EFFORT];
|
|
45441
|
+
const chips = [...ordinary, ULTRACODE_LAUNCH_EFFORT];
|
|
45412
45442
|
return {
|
|
45413
45443
|
id: model.id,
|
|
45414
45444
|
label: bareModelName(model),
|
|
45415
45445
|
launch: { model: model.id },
|
|
45416
|
-
|
|
45417
|
-
|
|
45418
|
-
|
|
45419
|
-
|
|
45420
|
-
|
|
45421
|
-
|
|
45422
|
-
|
|
45423
|
-
}))
|
|
45424
|
-
} : {}
|
|
45446
|
+
effortAxis,
|
|
45447
|
+
gatedEfforts,
|
|
45448
|
+
chips: chips.map((effort) => ({
|
|
45449
|
+
id: effort,
|
|
45450
|
+
label: EFFORT_LABELS[effort] ?? effort.toUpperCase(),
|
|
45451
|
+
launch: { model: model.id, effort }
|
|
45452
|
+
}))
|
|
45425
45453
|
};
|
|
45426
45454
|
}
|
|
45427
45455
|
function resolveDisabledReason(cli) {
|
|
@@ -45684,6 +45712,32 @@ async function createIsolatedClaudeConfigDir(tempRoot = tmpdir()) {
|
|
|
45684
45712
|
}
|
|
45685
45713
|
};
|
|
45686
45714
|
}
|
|
45715
|
+
function readVendorContextUsage(response) {
|
|
45716
|
+
if (typeof response !== "object" || response === null) return null;
|
|
45717
|
+
const usage4 = response;
|
|
45718
|
+
if (typeof usage4.totalTokens !== "number" || typeof usage4.maxTokens !== "number") return null;
|
|
45719
|
+
const rows = Array.isArray(usage4.categories) ? usage4.categories : [];
|
|
45720
|
+
const memory = Array.isArray(usage4.memoryFiles) ? usage4.memoryFiles : [];
|
|
45721
|
+
const mcp = Array.isArray(usage4.mcpTools) ? usage4.mcpTools : [];
|
|
45722
|
+
return {
|
|
45723
|
+
total: usage4.totalTokens,
|
|
45724
|
+
max: usage4.maxTokens,
|
|
45725
|
+
model: typeof usage4.model === "string" ? usage4.model : "",
|
|
45726
|
+
compactAt: usage4.isAutoCompactEnabled === true && typeof usage4.autoCompactThreshold === "number" ? usage4.autoCompactThreshold : null,
|
|
45727
|
+
categories: rows.flatMap((row) => {
|
|
45728
|
+
const entry = row;
|
|
45729
|
+
return typeof entry?.name === "string" && typeof entry.tokens === "number" ? [{ name: entry.name, tokens: entry.tokens, deferred: entry.isDeferred === true }] : [];
|
|
45730
|
+
}),
|
|
45731
|
+
memoryFiles: memory.flatMap((row) => {
|
|
45732
|
+
const entry = row;
|
|
45733
|
+
return typeof entry?.path === "string" && typeof entry.tokens === "number" ? [{ path: entry.path, tokens: entry.tokens }] : [];
|
|
45734
|
+
}),
|
|
45735
|
+
mcpTools: mcp.flatMap((row) => {
|
|
45736
|
+
const entry = row;
|
|
45737
|
+
return typeof entry?.name === "string" && typeof entry.tokens === "number" ? [{ name: entry.name, server: typeof entry.serverName === "string" ? entry.serverName : "", tokens: entry.tokens }] : [];
|
|
45738
|
+
})
|
|
45739
|
+
};
|
|
45740
|
+
}
|
|
45687
45741
|
function runVendorQuery(input) {
|
|
45688
45742
|
const run = query({
|
|
45689
45743
|
prompt: input.prompt,
|
|
@@ -45691,6 +45745,14 @@ function runVendorQuery(input) {
|
|
|
45691
45745
|
});
|
|
45692
45746
|
let closed = false;
|
|
45693
45747
|
return {
|
|
45748
|
+
async getContextUsage() {
|
|
45749
|
+
if (closed || typeof run.getContextUsage !== "function") return null;
|
|
45750
|
+
try {
|
|
45751
|
+
return readVendorContextUsage(await run.getContextUsage());
|
|
45752
|
+
} catch {
|
|
45753
|
+
return null;
|
|
45754
|
+
}
|
|
45755
|
+
},
|
|
45694
45756
|
[Symbol.asyncIterator]() {
|
|
45695
45757
|
const iterator = run[Symbol.asyncIterator]();
|
|
45696
45758
|
return {
|
|
@@ -45814,7 +45876,8 @@ async function createClaudeGatewaySdk(options) {
|
|
|
45814
45876
|
} finally {
|
|
45815
45877
|
release();
|
|
45816
45878
|
}
|
|
45817
|
-
}
|
|
45879
|
+
},
|
|
45880
|
+
getContextUsage: () => run.getContextUsage()
|
|
45818
45881
|
};
|
|
45819
45882
|
active = tracked;
|
|
45820
45883
|
return tracked;
|
|
@@ -46401,7 +46464,8 @@ var GatewayLaunchOptionError = class extends Error {
|
|
|
46401
46464
|
}
|
|
46402
46465
|
};
|
|
46403
46466
|
function isGatewayLaunchEffortAllowed(selection, model, effort) {
|
|
46404
|
-
if (
|
|
46467
|
+
if (effort === "ultra") return true;
|
|
46468
|
+
if (!GATEWAY_REASONING_EFFORTS.includes(effort)) return false;
|
|
46405
46469
|
const efforts = selection.effortExposure[model.id] ?? exposableEffortLadder(model);
|
|
46406
46470
|
return efforts.includes(effort);
|
|
46407
46471
|
}
|
|
@@ -47951,6 +48015,8 @@ function capText(text2) {
|
|
|
47951
48015
|
// ../fleet-plugins/terminal/server/agent-api/chat-session.ts
|
|
47952
48016
|
var JOURNAL_CAP = 2e3;
|
|
47953
48017
|
var TOOL_NAME_CAP = 500;
|
|
48018
|
+
var CONTEXT_RESERVED_NAME = "Autocompact buffer";
|
|
48019
|
+
var CONTEXT_UNSPENT = /* @__PURE__ */ new Set([CONTEXT_RESERVED_NAME, "Free space"]);
|
|
47954
48020
|
var JOB_KIND_CAP = 200;
|
|
47955
48021
|
var JOB_TAIL_READ_BYTES = 256 * 1024;
|
|
47956
48022
|
var JOB_TRANSCRIPT_READ_BYTES = 4 * 1024 * 1024;
|
|
@@ -48041,6 +48107,11 @@ var AgentChatSession = class {
|
|
|
48041
48107
|
* dispose(). 어느 경로로도 비워지지 않으면 SDK는 무기한 멈춘다(권한 요청에 park deadline이 없다).
|
|
48042
48108
|
*/
|
|
48043
48109
|
pendingAsks = /* @__PURE__ */ new Map();
|
|
48110
|
+
/**
|
|
48111
|
+
* 문맥 스냅숏의 세대. 턴마다 하나씩 오르며, 늦게 도착한 응답이 자기 턴의 것인지 가른다 —
|
|
48112
|
+
* 답은 턴이 끝난 뒤에 오므로(실측), 그 사이 새 턴이 시작했다면 그 값은 남의 턴 자리에 앉는다.
|
|
48113
|
+
*/
|
|
48114
|
+
contextGeneration = 0;
|
|
48044
48115
|
constructor(operationId, seed, createSdk) {
|
|
48045
48116
|
this.operationId = operationId;
|
|
48046
48117
|
this.seed = seed;
|
|
@@ -48352,6 +48423,58 @@ var AgentChatSession = class {
|
|
|
48352
48423
|
this.seed.reportAwaiting(true);
|
|
48353
48424
|
});
|
|
48354
48425
|
}
|
|
48426
|
+
/**
|
|
48427
|
+
* 턴이 시작하는 순간 자식에게 문맥 내역을 묻고, 답이 오면 그대로 저널에 싣는다.
|
|
48428
|
+
*
|
|
48429
|
+
* **이 한 번이 유일한 기회다**(실측). 자식은 턴이 시작되면 control 채널을 닫아, +0ms의 요청만
|
|
48430
|
+
* 답을 받고 그 뒤의 요청은 턴이 10초를 돌든 전부 "Query closed before response received"로
|
|
48431
|
+
* 끝난다. 주기적으로 물어 최신값을 좇는 설계는 이 자식에서 성립하지 않는다.
|
|
48432
|
+
*
|
|
48433
|
+
* 그래서 값은 **이 턴이 시작될 때까지의** 문맥이다 — 방금 끝난 턴이 더한 몫은 다음 턴이
|
|
48434
|
+
* 시작될 때 비로소 드러난다. 화면은 그 지연을 감추지 않는다.
|
|
48435
|
+
*
|
|
48436
|
+
* 응답을 기다리지 않는 이유는 스트림 때문이다: 여기서 await하면 첫 메시지 소비가 그만큼 늦다.
|
|
48437
|
+
* 늦게 도착한 답도 같은 턴의 시작 시점 값이므로, 그때 실어도 뜻이 달라지지 않는다.
|
|
48438
|
+
*/
|
|
48439
|
+
snapshotContextAtTurnStart(run) {
|
|
48440
|
+
const generation = ++this.contextGeneration;
|
|
48441
|
+
try {
|
|
48442
|
+
void run.getContextUsage().then((usage4) => {
|
|
48443
|
+
if (usage4 && generation === this.contextGeneration) this.pushContext(usage4);
|
|
48444
|
+
}, () => void 0);
|
|
48445
|
+
} catch {
|
|
48446
|
+
}
|
|
48447
|
+
}
|
|
48448
|
+
/**
|
|
48449
|
+
* 턴 시작 시점의 문맥을 저널에 심는다.
|
|
48450
|
+
*
|
|
48451
|
+
* 총량을 vendor의 `total`이 아니라 **카테고리 합으로 다시 세는** 이유는 실측이다: 게이트웨이
|
|
48452
|
+
* 세션에서 그 값(24,948)은 카테고리 합(129,670)과 크게 어긋났다 — 전자는 게이트웨이가 실제로
|
|
48453
|
+
* 읽은 토큰이고 후자는 CLI가 센 로컬 배분이다. 화면은 내역과 총량을 나란히 세우므로 둘이
|
|
48454
|
+
* 다른 셈을 쓰면 사용자가 보는 자리에서 모순이 드러난다. 내역이 곧 총량이어야 한다.
|
|
48455
|
+
*
|
|
48456
|
+
* 예약분(자동 압축 여유)과 남은 자리는 **쓴 것이 아니다**. 같은 목록에 두면 합이 언제나 창
|
|
48457
|
+
* 전체가 되어 미터가 항상 100%를 가리킨다.
|
|
48458
|
+
*/
|
|
48459
|
+
pushContext(usage4) {
|
|
48460
|
+
const spent = usage4.categories.filter((category) => !category.deferred && category.tokens > 0 && !CONTEXT_UNSPENT.has(category.name));
|
|
48461
|
+
const reserved = usage4.categories.find((category) => category.name === CONTEXT_RESERVED_NAME);
|
|
48462
|
+
this.push({
|
|
48463
|
+
kind: "context",
|
|
48464
|
+
total: spent.reduce((sum, category) => sum + category.tokens, 0),
|
|
48465
|
+
max: usage4.max,
|
|
48466
|
+
...reserved && reserved.tokens > 0 ? { reserved: reserved.tokens } : {},
|
|
48467
|
+
...usage4.compactAt === null ? {} : { compactAt: usage4.compactAt },
|
|
48468
|
+
slices: spent.map((category) => ({ name: category.name, tokens: category.tokens })),
|
|
48469
|
+
...usage4.memoryFiles.length > 0 ? { memoryFiles: usage4.memoryFiles.map((file2) => ({ name: file2.path, tokens: file2.tokens })) } : {},
|
|
48470
|
+
...usage4.mcpTools.length > 0 ? {
|
|
48471
|
+
mcpTools: usage4.mcpTools.map((tool) => ({
|
|
48472
|
+
name: tool.server ? `${tool.server} \xB7 ${tool.name}` : tool.name,
|
|
48473
|
+
tokens: tool.tokens
|
|
48474
|
+
}))
|
|
48475
|
+
} : {}
|
|
48476
|
+
});
|
|
48477
|
+
}
|
|
48355
48478
|
push(event) {
|
|
48356
48479
|
const entry = { seq: ++this.seq, event };
|
|
48357
48480
|
if (event.kind === "job-progress") {
|
|
@@ -48466,6 +48589,7 @@ var AgentChatSession = class {
|
|
|
48466
48589
|
return;
|
|
48467
48590
|
}
|
|
48468
48591
|
this.activeRun = run;
|
|
48592
|
+
this.snapshotContextAtTurnStart(run);
|
|
48469
48593
|
try {
|
|
48470
48594
|
for await (const message of run) {
|
|
48471
48595
|
if (typeof message.session_id === "string" && message.session_id.length > 0) {
|
|
@@ -48617,6 +48741,105 @@ var AgentChatRegistry = class {
|
|
|
48617
48741
|
}
|
|
48618
48742
|
};
|
|
48619
48743
|
|
|
48744
|
+
// ../fleet-plugins/terminal/server/agent-api/chat-ws.ts
|
|
48745
|
+
var MAX_CHAT_ANSWER_MESSAGE_CHARS = 2e3;
|
|
48746
|
+
var CHAT_UNAVAILABLE_CLOSE_CODE = 1013;
|
|
48747
|
+
function attachAgentChatSocket(socket, start) {
|
|
48748
|
+
let closed = false;
|
|
48749
|
+
let unsubscribe = null;
|
|
48750
|
+
let session = null;
|
|
48751
|
+
socket.once("close", () => {
|
|
48752
|
+
closed = true;
|
|
48753
|
+
unsubscribe?.();
|
|
48754
|
+
unsubscribe = null;
|
|
48755
|
+
session = null;
|
|
48756
|
+
});
|
|
48757
|
+
socket.on("message", (data, isBinary) => {
|
|
48758
|
+
if (closed || isBinary || !session) return;
|
|
48759
|
+
const command = readChatSocketCommand(decodeSocketText(data));
|
|
48760
|
+
if (!command) {
|
|
48761
|
+
sendJson(socket, { type: "nack", error: "invalid_command", ...commandId(data) ? { id: commandId(data) } : {} });
|
|
48762
|
+
return;
|
|
48763
|
+
}
|
|
48764
|
+
if (command.type === "stop") {
|
|
48765
|
+
if (!session.stopTurn()) {
|
|
48766
|
+
sendJson(socket, { type: "nack", id: command.id, error: "chat_idle" });
|
|
48767
|
+
return;
|
|
48768
|
+
}
|
|
48769
|
+
sendJson(socket, { type: "ok", id: command.id });
|
|
48770
|
+
return;
|
|
48771
|
+
}
|
|
48772
|
+
const result = session.answer(command.askId, {
|
|
48773
|
+
...command.answers ? { answers: command.answers } : {},
|
|
48774
|
+
...command.approve === true ? { approve: true } : {},
|
|
48775
|
+
...command.message !== void 0 ? { message: command.message.slice(0, MAX_CHAT_ANSWER_MESSAGE_CHARS) } : {}
|
|
48776
|
+
});
|
|
48777
|
+
if (!result.ok) {
|
|
48778
|
+
sendJson(socket, { type: "nack", id: command.id, error: result.error });
|
|
48779
|
+
return;
|
|
48780
|
+
}
|
|
48781
|
+
sendJson(socket, { type: "ok", id: command.id });
|
|
48782
|
+
});
|
|
48783
|
+
void start().then((ready) => {
|
|
48784
|
+
if (closed) return;
|
|
48785
|
+
if ("error" in ready) {
|
|
48786
|
+
sendJson(socket, { seq: 0, event: { kind: "error", code: ready.error } });
|
|
48787
|
+
socket.close(CHAT_UNAVAILABLE_CLOSE_CODE, ready.error);
|
|
48788
|
+
return;
|
|
48789
|
+
}
|
|
48790
|
+
session = ready;
|
|
48791
|
+
unsubscribe = ready.subscribe((entry) => {
|
|
48792
|
+
if (!closed) sendJson(socket, entry);
|
|
48793
|
+
});
|
|
48794
|
+
}).catch(() => {
|
|
48795
|
+
if (closed) return;
|
|
48796
|
+
sendJson(socket, { seq: 0, event: { kind: "error", code: "chat_unavailable" } });
|
|
48797
|
+
socket.close(CHAT_UNAVAILABLE_CLOSE_CODE, "chat_unavailable");
|
|
48798
|
+
});
|
|
48799
|
+
}
|
|
48800
|
+
function sendJson(socket, value) {
|
|
48801
|
+
if (socket.readyState !== 1) return;
|
|
48802
|
+
socket.send(Buffer.from(JSON.stringify(value), "utf8"), { binary: false });
|
|
48803
|
+
}
|
|
48804
|
+
function decodeSocketText(data) {
|
|
48805
|
+
if (Buffer.isBuffer(data)) return data.toString("utf8");
|
|
48806
|
+
if (Array.isArray(data)) return Buffer.concat(data).toString("utf8");
|
|
48807
|
+
return Buffer.from(data).toString("utf8");
|
|
48808
|
+
}
|
|
48809
|
+
function commandId(data) {
|
|
48810
|
+
try {
|
|
48811
|
+
const parsed = JSON.parse(decodeSocketText(data));
|
|
48812
|
+
if (parsed && typeof parsed === "object" && typeof parsed.id === "string") {
|
|
48813
|
+
return parsed.id;
|
|
48814
|
+
}
|
|
48815
|
+
} catch {
|
|
48816
|
+
}
|
|
48817
|
+
return void 0;
|
|
48818
|
+
}
|
|
48819
|
+
function readChatSocketCommand(raw) {
|
|
48820
|
+
let parsed;
|
|
48821
|
+
try {
|
|
48822
|
+
parsed = JSON.parse(raw);
|
|
48823
|
+
} catch {
|
|
48824
|
+
return null;
|
|
48825
|
+
}
|
|
48826
|
+
if (!parsed || typeof parsed !== "object") return null;
|
|
48827
|
+
const value = parsed;
|
|
48828
|
+
if (typeof value.id !== "string" || value.id.length === 0) return null;
|
|
48829
|
+
if (value.type === "stop") return { type: "stop", id: value.id };
|
|
48830
|
+
if (value.type !== "answer" || typeof value.askId !== "string" || value.askId.length === 0) return null;
|
|
48831
|
+
const answers = Array.isArray(value.answers) ? value.answers.filter((entry) => typeof entry === "string") : void 0;
|
|
48832
|
+
if (Array.isArray(value.answers) && answers?.length !== value.answers.length) return null;
|
|
48833
|
+
return {
|
|
48834
|
+
type: "answer",
|
|
48835
|
+
id: value.id,
|
|
48836
|
+
askId: value.askId,
|
|
48837
|
+
...answers ? { answers } : {},
|
|
48838
|
+
...value.approve === true ? { approve: true } : {},
|
|
48839
|
+
...typeof value.message === "string" ? { message: value.message } : {}
|
|
48840
|
+
};
|
|
48841
|
+
}
|
|
48842
|
+
|
|
48620
48843
|
// ../fleet-plugins/terminal/server/agent-api/analysis-types.ts
|
|
48621
48844
|
var ANALYSIS_ERROR_CODES = {
|
|
48622
48845
|
captureMissing: "analysis_capture_missing",
|
|
@@ -48909,7 +49132,7 @@ var TERMINAL_PLUGIN_ID = "terminal";
|
|
|
48909
49132
|
var CHAT_MODE_PAYLOAD_KEY = "chatMode";
|
|
48910
49133
|
var CHAT_BORN_PAYLOAD_KEY = "chatBorn";
|
|
48911
49134
|
var CHAT_SUPPORTED_CLI_ID = "claude-gateway";
|
|
48912
|
-
var
|
|
49135
|
+
var MAX_CHAT_ANSWER_MESSAGE_CHARS2 = 2e3;
|
|
48913
49136
|
function resolveClaudeConfigDir() {
|
|
48914
49137
|
const configured = process4.env.CLAUDE_CONFIG_DIR;
|
|
48915
49138
|
return configured && configured.length > 0 ? configured : path19__default.join(os3__default.homedir(), ".claude");
|
|
@@ -48934,7 +49157,7 @@ async function registerAgentRoutes(ctx, terminalRuntime, deps) {
|
|
|
48934
49157
|
{ method: "POST", path: "/sessions/:sessionId/message", summary: "Deliver a prompt to an Agent session.", category: "Terminal Plugin", gate: "origin-write", transport: "http" },
|
|
48935
49158
|
{ method: "POST", path: "/sessions/:sessionId/chat", summary: "Switch an Agent session to chat mode.", category: "Terminal Plugin", gate: "origin-write", transport: "http" },
|
|
48936
49159
|
{ method: "DELETE", path: "/sessions/:sessionId/chat", summary: "Leave chat mode for an Agent session.", category: "Terminal Plugin", gate: "origin-write", transport: "http" },
|
|
48937
|
-
{ method: "GET", path: "/sessions/:sessionId/chat-stream", summary: "
|
|
49160
|
+
{ method: "GET", path: "/sessions/:sessionId/chat-stream", summary: "Removed \u2014 Chat Mode observation uses the ticketed WebSocket.", category: "Terminal Plugin", gate: "origin-write", transport: "http" },
|
|
48938
49161
|
{ method: "POST", path: "/sessions/:sessionId/chat-answer", summary: "Answer a pending Agent chat question.", category: "Terminal Plugin", gate: "origin-write", transport: "http" },
|
|
48939
49162
|
{ method: "POST", path: "/sessions/:sessionId/chat-stop", summary: "Stop the in-flight Agent chat turn.", category: "Terminal Plugin", gate: "origin-write", transport: "http" },
|
|
48940
49163
|
{ method: "GET", path: "/sessions/:sessionId/chat-job", summary: "Read one Agent chat background job's detail.", category: "Terminal Plugin", gate: "origin-write", transport: "http" },
|
|
@@ -49001,6 +49224,27 @@ async function createAgentApi(ctx, terminalRuntime, deps) {
|
|
|
49001
49224
|
const oscActivityTrackers = /* @__PURE__ */ new Map();
|
|
49002
49225
|
const testChatSdkFactory = globalThis.__fleetAgentChatSdkFactory;
|
|
49003
49226
|
const chatRegistry = testChatSdkFactory ? new AgentChatRegistry(testChatSdkFactory) : new AgentChatRegistry();
|
|
49227
|
+
const unbindChatAttach = terminalRuntime.bindChatAttach((socket, context) => {
|
|
49228
|
+
const sessionId = context.sessionId;
|
|
49229
|
+
attachAgentChatSocket(socket, async () => {
|
|
49230
|
+
const node = ctx.host.operations.get(sessionId);
|
|
49231
|
+
if (!node || node.pluginId !== ctx.pluginId || node.type !== AGENT_OPERATION_TYPE) {
|
|
49232
|
+
return { error: "session_not_found" };
|
|
49233
|
+
}
|
|
49234
|
+
if (node.payload[CHAT_MODE_PAYLOAD_KEY] !== true) return { error: "chat_not_active" };
|
|
49235
|
+
const seed = await resolveChatSeed(node);
|
|
49236
|
+
if (!seed.ok) return { error: seed.error };
|
|
49237
|
+
if (ctx.host.operations.get(sessionId)?.payload[CHAT_MODE_PAYLOAD_KEY] !== true) {
|
|
49238
|
+
return { error: "chat_not_active" };
|
|
49239
|
+
}
|
|
49240
|
+
try {
|
|
49241
|
+
return await chatRegistry.ensure(sessionId, () => seed.seed);
|
|
49242
|
+
} catch {
|
|
49243
|
+
return { error: "chat_unavailable" };
|
|
49244
|
+
}
|
|
49245
|
+
});
|
|
49246
|
+
});
|
|
49247
|
+
ctx.host.lifecycle.registerCleanup(unbindChatAttach);
|
|
49004
49248
|
const launchResolver = createAgentTerminalLaunchResolver({
|
|
49005
49249
|
agentRuntime: runtime,
|
|
49006
49250
|
...deps.aiGateway ? { aiGateway: deps.aiGateway } : {},
|
|
@@ -49136,6 +49380,23 @@ async function createAgentApi(ctx, terminalRuntime, deps) {
|
|
|
49136
49380
|
ctx.host.http.writeJson(res, 404, { error: "terminal_session_not_found" });
|
|
49137
49381
|
return true;
|
|
49138
49382
|
}
|
|
49383
|
+
const channel = readTicketChannel(body?.channel);
|
|
49384
|
+
if (channel === "chat") {
|
|
49385
|
+
if (operation.payload[CHAT_MODE_PAYLOAD_KEY] !== true) {
|
|
49386
|
+
ctx.host.http.writeJson(res, 409, { error: "chat_not_active" });
|
|
49387
|
+
return true;
|
|
49388
|
+
}
|
|
49389
|
+
ctx.host.http.writeJson(res, 200, terminalRuntime.issueTicket({
|
|
49390
|
+
cwd: readPayloadString(operation.payload, "cwd") ?? ctx.host.paths.resolveTheaterPath(operation.theaterId) ?? "",
|
|
49391
|
+
sessionId: operation.id,
|
|
49392
|
+
operationId: operation.id,
|
|
49393
|
+
operationType: operation.type,
|
|
49394
|
+
pluginId: operation.pluginId,
|
|
49395
|
+
theaterId: operation.theaterId,
|
|
49396
|
+
channel: "chat"
|
|
49397
|
+
}));
|
|
49398
|
+
return true;
|
|
49399
|
+
}
|
|
49139
49400
|
if (observability.getTerminalSessionInfo(operation.id)?.status === "dormant") {
|
|
49140
49401
|
ctx.host.http.writeJson(res, 409, { error: "operation_dormant" });
|
|
49141
49402
|
return true;
|
|
@@ -49750,7 +50011,7 @@ async function createAgentApi(ctx, terminalRuntime, deps) {
|
|
|
49750
50011
|
const result = chat.answer(askId, {
|
|
49751
50012
|
...answers ? { answers } : {},
|
|
49752
50013
|
...body?.approve === true ? { approve: true } : {},
|
|
49753
|
-
...typeof body?.message === "string" ? { message: body.message.slice(0,
|
|
50014
|
+
...typeof body?.message === "string" ? { message: body.message.slice(0, MAX_CHAT_ANSWER_MESSAGE_CHARS2) } : {}
|
|
49754
50015
|
});
|
|
49755
50016
|
if (!result.ok) {
|
|
49756
50017
|
const status = result.error === "ask_not_found" ? 404 : result.error === "plan_truncated" ? 409 : 400;
|
|
@@ -49818,56 +50079,7 @@ async function createAgentApi(ctx, terminalRuntime, deps) {
|
|
|
49818
50079
|
ctx.host.http.writeJson(res, 409, { error: "chat_not_active" });
|
|
49819
50080
|
return true;
|
|
49820
50081
|
}
|
|
49821
|
-
|
|
49822
|
-
let unsubscribe = null;
|
|
49823
|
-
const write = (data) => {
|
|
49824
|
-
if (!closed && !res.writableEnded && !res.destroyed) res.write(data);
|
|
49825
|
-
};
|
|
49826
|
-
res.writeHead(200, {
|
|
49827
|
-
"Content-Type": "text/event-stream",
|
|
49828
|
-
"Cache-Control": "no-store",
|
|
49829
|
-
Connection: "keep-alive",
|
|
49830
|
-
"Cross-Origin-Opener-Policy": "same-origin",
|
|
49831
|
-
"Cross-Origin-Resource-Policy": "same-origin",
|
|
49832
|
-
"Referrer-Policy": "no-referrer",
|
|
49833
|
-
"X-Content-Type-Options": "nosniff"
|
|
49834
|
-
});
|
|
49835
|
-
write(": open\n\n");
|
|
49836
|
-
const keepalive = setInterval(() => write(": keepalive\n\n"), 3e4);
|
|
49837
|
-
req.on("close", () => {
|
|
49838
|
-
closed = true;
|
|
49839
|
-
clearInterval(keepalive);
|
|
49840
|
-
unsubscribe?.();
|
|
49841
|
-
});
|
|
49842
|
-
void (async () => {
|
|
49843
|
-
const seed = await resolveChatSeed(node);
|
|
49844
|
-
if (!seed.ok) {
|
|
49845
|
-
write(`data: ${JSON.stringify({ seq: 0, event: { kind: "error", code: seed.error } })}
|
|
49846
|
-
|
|
49847
|
-
`);
|
|
49848
|
-
res.end();
|
|
49849
|
-
return;
|
|
49850
|
-
}
|
|
49851
|
-
if (ctx.host.operations.get(sessionId)?.payload[CHAT_MODE_PAYLOAD_KEY] !== true) {
|
|
49852
|
-
write(`data: ${JSON.stringify({ seq: 0, event: { kind: "error", code: "chat_not_active" } })}
|
|
49853
|
-
|
|
49854
|
-
`);
|
|
49855
|
-
res.end();
|
|
49856
|
-
return;
|
|
49857
|
-
}
|
|
49858
|
-
try {
|
|
49859
|
-
const chat = await chatRegistry.ensure(sessionId, () => seed.seed);
|
|
49860
|
-
if (closed) return;
|
|
49861
|
-
unsubscribe = chat.subscribe((entry) => write(`data: ${JSON.stringify(entry)}
|
|
49862
|
-
|
|
49863
|
-
`));
|
|
49864
|
-
} catch {
|
|
49865
|
-
write(`data: ${JSON.stringify({ seq: 0, event: { kind: "error", code: "chat_unavailable" } })}
|
|
49866
|
-
|
|
49867
|
-
`);
|
|
49868
|
-
res.end();
|
|
49869
|
-
}
|
|
49870
|
-
})();
|
|
50082
|
+
ctx.host.http.writeJson(res, 410, { error: "chat_stream_moved" });
|
|
49871
50083
|
return true;
|
|
49872
50084
|
}
|
|
49873
50085
|
async function resolveChatSeed(node) {
|