@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.
Files changed (67) hide show
  1. package/README.md +1 -0
  2. package/dist/cli.mjs +60 -18
  3. package/dist/client/assets/{_baseUniq-B6CLI4cf.js → _baseUniq-CVUU389k.js} +1 -1
  4. package/dist/client/assets/{arc-r3CRqUQ5.js → arc-Fg3WjPoW.js} +1 -1
  5. package/dist/client/assets/{architectureDiagram-Q4EWVU46-CJfgw2eJ.js → architectureDiagram-Q4EWVU46-gAB_QWIv.js} +1 -1
  6. package/dist/client/assets/{blockDiagram-DXYQGD6D-CkBuOBUs.js → blockDiagram-DXYQGD6D-DCY_3CSv.js} +1 -1
  7. package/dist/client/assets/{c4Diagram-AHTNJAMY-Ln5TenJL.js → c4Diagram-AHTNJAMY-2ai4d9rg.js} +1 -1
  8. package/dist/client/assets/channel-DlA1BRCV.js +1 -0
  9. package/dist/client/assets/{chunk-4BX2VUAB-BiYTw90k.js → chunk-4BX2VUAB-C-sjgNCE.js} +1 -1
  10. package/dist/client/assets/{chunk-4TB4RGXK-nPQaGu1w.js → chunk-4TB4RGXK-Co7w9KaD.js} +1 -1
  11. package/dist/client/assets/{chunk-55IACEB6-BU2oCJkl.js → chunk-55IACEB6-Dspr2174.js} +1 -1
  12. package/dist/client/assets/{chunk-EDXVE4YY-Ej7y6KOv.js → chunk-EDXVE4YY-UzzG0ax3.js} +1 -1
  13. package/dist/client/assets/{chunk-FMBD7UC4-hOkBpfhE.js → chunk-FMBD7UC4-DKXcUQqJ.js} +1 -1
  14. package/dist/client/assets/{chunk-OYMX7WX6-Cv43HwvT.js → chunk-OYMX7WX6-vW--qrkP.js} +1 -1
  15. package/dist/client/assets/{chunk-QZHKN3VN-Bi7AEJxb.js → chunk-QZHKN3VN-DyE-yBhf.js} +1 -1
  16. package/dist/client/assets/{chunk-YZCP3GAM-CBwmJdga.js → chunk-YZCP3GAM-C7LLTO2-.js} +1 -1
  17. package/dist/client/assets/classDiagram-6PBFFD2Q-rBpGSdtk.js +1 -0
  18. package/dist/client/assets/classDiagram-v2-HSJHXN6E-rBpGSdtk.js +1 -0
  19. package/dist/client/assets/clone-_1aYWCbr.js +1 -0
  20. package/dist/client/assets/{cose-bilkent-S5V4N54A-ERDn7bly.js → cose-bilkent-S5V4N54A-BkDNeJiw.js} +1 -1
  21. package/dist/client/assets/{dagre-KV5264BT-DapcbnEu.js → dagre-KV5264BT-DqeN9oF3.js} +1 -1
  22. package/dist/client/assets/{diagram-5BDNPKRD-DbRBVaVH.js → diagram-5BDNPKRD-BXzt4-3Y.js} +1 -1
  23. package/dist/client/assets/{diagram-G4DWMVQ6-CLP0MwBH.js → diagram-G4DWMVQ6-DbzDYVOf.js} +1 -1
  24. package/dist/client/assets/{diagram-MMDJMWI5-BMZ9AsEI.js → diagram-MMDJMWI5-wPQu3o7B.js} +1 -1
  25. package/dist/client/assets/{diagram-TYMM5635-DtPPkZ2y.js → diagram-TYMM5635-C-vwFwzf.js} +1 -1
  26. package/dist/client/assets/{erDiagram-SMLLAGMA-DIvbhhTb.js → erDiagram-SMLLAGMA-CcukuTgN.js} +1 -1
  27. package/dist/client/assets/{flowDiagram-DWJPFMVM-C_R3RpTk.js → flowDiagram-DWJPFMVM-BT8ZNr2Y.js} +1 -1
  28. package/dist/client/assets/{ganttDiagram-T4ZO3ILL-eaIqpHsY.js → ganttDiagram-T4ZO3ILL-B_wNcZrL.js} +1 -1
  29. package/dist/client/assets/{gitGraphDiagram-UUTBAWPF-CYCsHY_E.js → gitGraphDiagram-UUTBAWPF-dUwwvDSd.js} +1 -1
  30. package/dist/client/assets/{graph-HfvOsgk2.js → graph-C4i_jr7e.js} +1 -1
  31. package/dist/client/assets/index-BXtDpU36.js +465 -0
  32. package/dist/client/assets/index-CLb_APbh.css +1 -0
  33. package/dist/client/assets/{infoDiagram-42DDH7IO-rmDH5YRZ.js → infoDiagram-42DDH7IO-Bf2KPu0t.js} +1 -1
  34. package/dist/client/assets/{ishikawaDiagram-UXIWVN3A-EAZO3mIY.js → ishikawaDiagram-UXIWVN3A-DjHChg2o.js} +1 -1
  35. package/dist/client/assets/{journeyDiagram-VCZTEJTY-4vWYlXOF.js → journeyDiagram-VCZTEJTY-B08epGYF.js} +1 -1
  36. package/dist/client/assets/{kanban-definition-6JOO6SKY-CkkSfsbD.js → kanban-definition-6JOO6SKY-BFasXRgc.js} +1 -1
  37. package/dist/client/assets/{layout-DWbhbrdO.js → layout-Q_W10VzL.js} +1 -1
  38. package/dist/client/assets/{linear-BjRBsqi0.js → linear-Dy4fc5kq.js} +1 -1
  39. package/dist/client/assets/{mermaid.core-RuG-kUU2.js → mermaid.core-OtTy8N5f.js} +4 -4
  40. package/dist/client/assets/{min-D--jZrv5.js → min-DODD7JTz.js} +1 -1
  41. package/dist/client/assets/{mindmap-definition-QFDTVHPH-fLwhQBcX.js → mindmap-definition-QFDTVHPH-DMhpsiYD.js} +1 -1
  42. package/dist/client/assets/{pieDiagram-DEJITSTG-DJkWnAQK.js → pieDiagram-DEJITSTG-C5usaVgs.js} +1 -1
  43. package/dist/client/assets/{quadrantDiagram-34T5L4WZ-Kd4q9kEz.js → quadrantDiagram-34T5L4WZ-B-b2NvBz.js} +1 -1
  44. package/dist/client/assets/{requirementDiagram-MS252O5E-Bgrtq8Kh.js → requirementDiagram-MS252O5E-D6_4jY3n.js} +1 -1
  45. package/dist/client/assets/{sankeyDiagram-XADWPNL6-BW9BdQ-8.js → sankeyDiagram-XADWPNL6-B6imEhCV.js} +1 -1
  46. package/dist/client/assets/{sequenceDiagram-FGHM5R23-KpgcxIJb.js → sequenceDiagram-FGHM5R23-BRHNnuqK.js} +1 -1
  47. package/dist/client/assets/{stateDiagram-FHFEXIEX-CNaCHtL2.js → stateDiagram-FHFEXIEX-RiIddIHL.js} +1 -1
  48. package/dist/client/assets/stateDiagram-v2-QKLJ7IA2-CsHfIgMa.js +1 -0
  49. package/dist/client/assets/{timeline-definition-GMOUNBTQ-MGPKEXGI.js → timeline-definition-GMOUNBTQ-BhP14Blt.js} +1 -1
  50. package/dist/client/assets/{vennDiagram-DHZGUBPP-bDOCVDJ1.js → vennDiagram-DHZGUBPP-CtzwrBNs.js} +1 -1
  51. package/dist/client/assets/{wardley-RL74JXVD-DuvLJQPg.js → wardley-RL74JXVD-TXsee18-.js} +1 -1
  52. package/dist/client/assets/{wardleyDiagram-NUSXRM2D-BdBIEtIl.js → wardleyDiagram-NUSXRM2D-CrJP7pf7.js} +1 -1
  53. package/dist/client/assets/{xychartDiagram-5P7HB3ND-vycMI6c3.js → xychartDiagram-5P7HB3ND-rB-PigjI.js} +1 -1
  54. package/dist/client/index.html +2 -2
  55. package/dist/fleet-plugins/ledger/routes.mjs +7 -12
  56. package/dist/fleet-plugins/quota/routes.mjs +7 -12
  57. package/dist/fleet-plugins/scuttlebutt/routes.mjs +44 -15
  58. package/dist/fleet-plugins/terminal/routes.mjs +300 -88
  59. package/dist/fleet.mjs +443 -222
  60. package/package.json +1 -1
  61. package/dist/client/assets/channel-DBCxCWtI.js +0 -1
  62. package/dist/client/assets/classDiagram-6PBFFD2Q-QQSWiJjR.js +0 -1
  63. package/dist/client/assets/classDiagram-v2-HSJHXN6E-QQSWiJjR.js +0 -1
  64. package/dist/client/assets/clone-vom5rXcJ.js +0 -1
  65. package/dist/client/assets/index-C2erdgSj.css +0 -1
  66. package/dist/client/assets/index-CrEYBugN.js +0 -465
  67. 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-15T00:00:00Z",
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 \u2014 ultra advertised for sol/sol-wm/terra, luna stops at max) for model/effort/service-tier; contextWindow=272000 is codex debug models context_window/max_context_window (codex-cli 0.146.0, 2026-08-02)",
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 deliverable;
31497
- const narrowed = deliverable.filter((rung) => chosen.includes(rung));
31498
- return narrowed.length > 0 ? narrowed : deliverable;
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 || !deps.sessions.canAttach(context.sessionId)) {
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, "ultra"];
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 efforts = (selection.effortExposure[model.id] ?? exposableEffortLadder(model)).filter((effort) => EFFORT_AXIS.includes(effort));
45410
- const gatedEfforts = APEX_EFFORTS.filter((effort) => efforts.includes(effort));
45411
- const effortAxis = EFFORT_AXIS.filter((effort) => !APEX_EFFORTS.includes(effort) || efforts.includes(effort));
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
- ...efforts.length > 0 ? {
45417
- effortAxis,
45418
- ...gatedEfforts.length > 0 ? { gatedEfforts } : {},
45419
- chips: efforts.map((effort) => ({
45420
- id: effort,
45421
- label: EFFORT_LABELS[effort] ?? effort.toUpperCase(),
45422
- launch: { model: model.id, effort }
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 (![...NATIVE_CLAUDE_EFFORTS, "ultra"].includes(effort)) return false;
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 MAX_CHAT_ANSWER_MESSAGE_CHARS = 2e3;
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: "Stream Agent chat events.", category: "Terminal Plugin", gate: "origin-write", transport: "sse" },
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, MAX_CHAT_ANSWER_MESSAGE_CHARS) } : {}
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
- let closed = false;
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) {