@dotobokuri/fleet-console 1.59.0 → 1.60.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 (68) hide show
  1. package/AGENTS.md +1 -1
  2. package/dist/cli.mjs +12 -2
  3. package/dist/client/assets/{_baseUniq-CKkDoWU8.js → _baseUniq-CA3I-KTP.js} +1 -1
  4. package/dist/client/assets/{arc-CcRdX8oF.js → arc-DOkIWugv.js} +1 -1
  5. package/dist/client/assets/{architectureDiagram-Q4EWVU46-gaFzE1W7.js → architectureDiagram-Q4EWVU46--Z_t3Gn9.js} +1 -1
  6. package/dist/client/assets/{blockDiagram-DXYQGD6D-Bzybih30.js → blockDiagram-DXYQGD6D-CrRA5qvl.js} +1 -1
  7. package/dist/client/assets/{c4Diagram-AHTNJAMY-Dz8bwV9j.js → c4Diagram-AHTNJAMY-DKvbMOAM.js} +1 -1
  8. package/dist/client/assets/channel-Bjfd2afp.js +1 -0
  9. package/dist/client/assets/{chunk-4BX2VUAB-DmgZtGyV.js → chunk-4BX2VUAB-D6wc2KrB.js} +1 -1
  10. package/dist/client/assets/{chunk-4TB4RGXK-DX1WxV3U.js → chunk-4TB4RGXK-B4QvYh7f.js} +1 -1
  11. package/dist/client/assets/{chunk-55IACEB6-Bk4b3T9u.js → chunk-55IACEB6-B0VZPoad.js} +1 -1
  12. package/dist/client/assets/{chunk-EDXVE4YY-BzGadfvT.js → chunk-EDXVE4YY-BdHIgvVh.js} +1 -1
  13. package/dist/client/assets/{chunk-FMBD7UC4-44f7YyvW.js → chunk-FMBD7UC4-BAYTd_pU.js} +1 -1
  14. package/dist/client/assets/{chunk-OYMX7WX6-CyUAky9W.js → chunk-OYMX7WX6-DkZ-neug.js} +1 -1
  15. package/dist/client/assets/{chunk-QZHKN3VN-C11OUntR.js → chunk-QZHKN3VN-B5h7E8GE.js} +1 -1
  16. package/dist/client/assets/{chunk-YZCP3GAM-DVTmWawU.js → chunk-YZCP3GAM-COMJ2EwJ.js} +1 -1
  17. package/dist/client/assets/classDiagram-6PBFFD2Q-DgpHvFOU.js +1 -0
  18. package/dist/client/assets/classDiagram-v2-HSJHXN6E-DgpHvFOU.js +1 -0
  19. package/dist/client/assets/clone-sFXqwEZz.js +1 -0
  20. package/dist/client/assets/{cose-bilkent-S5V4N54A-CEatGsZv.js → cose-bilkent-S5V4N54A-JvC7pCqe.js} +1 -1
  21. package/dist/client/assets/{dagre-KV5264BT-DlrgN02H.js → dagre-KV5264BT-jZdVPQcJ.js} +1 -1
  22. package/dist/client/assets/{diagram-5BDNPKRD-BZ3hRO5t.js → diagram-5BDNPKRD-B6-u7AU2.js} +1 -1
  23. package/dist/client/assets/{diagram-G4DWMVQ6-B-izS46x.js → diagram-G4DWMVQ6-CV5G3KNM.js} +1 -1
  24. package/dist/client/assets/{diagram-MMDJMWI5-Cw-wnJGs.js → diagram-MMDJMWI5-ZLrEkNww.js} +1 -1
  25. package/dist/client/assets/{diagram-TYMM5635-BoWnyd4_.js → diagram-TYMM5635-D1tv2JX9.js} +1 -1
  26. package/dist/client/assets/{erDiagram-SMLLAGMA-BUmyXZbP.js → erDiagram-SMLLAGMA-Bta0Mt3t.js} +1 -1
  27. package/dist/client/assets/{flowDiagram-DWJPFMVM-COS3kjS0.js → flowDiagram-DWJPFMVM-C282oRLT.js} +1 -1
  28. package/dist/client/assets/{ganttDiagram-T4ZO3ILL-BTr1fdio.js → ganttDiagram-T4ZO3ILL-D9P4CVIW.js} +1 -1
  29. package/dist/client/assets/{gitGraphDiagram-UUTBAWPF-BkGkaosN.js → gitGraphDiagram-UUTBAWPF-DLQnTjJ2.js} +1 -1
  30. package/dist/client/assets/{graph-DmbgK-mH.js → graph-Cd8Q-8WG.js} +1 -1
  31. package/dist/client/assets/index-B3gusU1E.js +465 -0
  32. package/dist/client/assets/index-_PHObHQ-.css +1 -0
  33. package/dist/client/assets/{infoDiagram-42DDH7IO-B8zI6k1l.js → infoDiagram-42DDH7IO-ClhLpons.js} +1 -1
  34. package/dist/client/assets/{ishikawaDiagram-UXIWVN3A-cIcEzrcK.js → ishikawaDiagram-UXIWVN3A-BDeZ2vOG.js} +1 -1
  35. package/dist/client/assets/{journeyDiagram-VCZTEJTY-DhuabHCk.js → journeyDiagram-VCZTEJTY-DbJhbFKN.js} +1 -1
  36. package/dist/client/assets/{kanban-definition-6JOO6SKY-uHTkqxhX.js → kanban-definition-6JOO6SKY-CYKcE2fE.js} +1 -1
  37. package/dist/client/assets/{layout-Cfgk_duA.js → layout-CuAgTRkn.js} +1 -1
  38. package/dist/client/assets/{linear-BKvV0sr5.js → linear-3EL9MakS.js} +1 -1
  39. package/dist/client/assets/{mermaid.core-DozmrCuG.js → mermaid.core-7qKaxHEA.js} +4 -4
  40. package/dist/client/assets/{min-ke46otlW.js → min-4mJsdKjT.js} +1 -1
  41. package/dist/client/assets/{mindmap-definition-QFDTVHPH-d7xzxhzf.js → mindmap-definition-QFDTVHPH-B-Zve2OH.js} +1 -1
  42. package/dist/client/assets/{pieDiagram-DEJITSTG-C4S9Jy5A.js → pieDiagram-DEJITSTG-DlsdbAii.js} +1 -1
  43. package/dist/client/assets/{quadrantDiagram-34T5L4WZ-CoQnj3kv.js → quadrantDiagram-34T5L4WZ-Cb4h0xwt.js} +1 -1
  44. package/dist/client/assets/{requirementDiagram-MS252O5E-CdopMDtg.js → requirementDiagram-MS252O5E-CZNGYqJt.js} +1 -1
  45. package/dist/client/assets/{sankeyDiagram-XADWPNL6-DdR4zdh4.js → sankeyDiagram-XADWPNL6-DeVSGR6W.js} +1 -1
  46. package/dist/client/assets/{sequenceDiagram-FGHM5R23-NeYZWVQm.js → sequenceDiagram-FGHM5R23-Te7TkLIe.js} +1 -1
  47. package/dist/client/assets/{stateDiagram-FHFEXIEX-D0CQGKV_.js → stateDiagram-FHFEXIEX-Be-0oYyv.js} +1 -1
  48. package/dist/client/assets/stateDiagram-v2-QKLJ7IA2-BnQ2lBhr.js +1 -0
  49. package/dist/client/assets/{timeline-definition-GMOUNBTQ-Bz2b3nfQ.js → timeline-definition-GMOUNBTQ-DQyUgC-K.js} +1 -1
  50. package/dist/client/assets/{vennDiagram-DHZGUBPP-CVO2Ja80.js → vennDiagram-DHZGUBPP-BrArIWI8.js} +1 -1
  51. package/dist/client/assets/{wardley-RL74JXVD-Ba_GKs5u.js → wardley-RL74JXVD-6-sWm8kk.js} +1 -1
  52. package/dist/client/assets/{wardleyDiagram-NUSXRM2D-yP3xvrPy.js → wardleyDiagram-NUSXRM2D-C4MvFXGS.js} +1 -1
  53. package/dist/client/assets/{xychartDiagram-5P7HB3ND-BLSs6w4C.js → xychartDiagram-5P7HB3ND-CGrtjhmr.js} +1 -1
  54. package/dist/client/index.html +2 -2
  55. package/dist/fleet-plugins/file-explorer/routes.mjs +132 -13
  56. package/dist/fleet-plugins/ledger/routes.mjs +223 -16
  57. package/dist/fleet-plugins/quota/routes.mjs +33 -2
  58. package/dist/fleet-plugins/scuttlebutt/routes.mjs +5 -5
  59. package/dist/fleet-plugins/terminal/routes.mjs +411 -61
  60. package/dist/fleet.mjs +274 -43
  61. package/package.json +1 -1
  62. package/dist/client/assets/channel-CAhLkt5l.js +0 -1
  63. package/dist/client/assets/classDiagram-6PBFFD2Q-BSvLoE2t.js +0 -1
  64. package/dist/client/assets/classDiagram-v2-HSJHXN6E-BSvLoE2t.js +0 -1
  65. package/dist/client/assets/clone-o26VS_sk.js +0 -1
  66. package/dist/client/assets/index-C-3spb_b.js +0 -465
  67. package/dist/client/assets/index-FU1PGEfG.css +0 -1
  68. package/dist/client/assets/stateDiagram-v2-QKLJ7IA2-hM1GV37r.js +0 -1
@@ -20195,6 +20195,10 @@ var CLAUDE_COMPAT_CONTEXT_WINDOW = 1e6;
20195
20195
  var CLAUDE_DEFAULT_CONTEXT_WINDOW = 2e5;
20196
20196
  var CLAUDE_COMPACT_RESERVE = 32e3;
20197
20197
  var PROVIDER_COMPACT_RESERVE = 16e3;
20198
+ var COMPACT_CEILING_EARLY_PERCENT = 88;
20199
+ var COMPACT_CEILING_LATE_PERCENT = 97;
20200
+ var COMPACT_CEILING_CUSTOM_MIN = 70;
20201
+ var COMPACT_CEILING_CUSTOM_MAX = 99;
20198
20202
  var DEFAULT_MAX_JSON_BYTES = 16 * 1024 * 1024;
20199
20203
  var DEFAULT_MAX_SSE_FRAME_BYTES = 1024 * 1024;
20200
20204
  var MAX_SSE_SEPARATOR_BYTES = 4;
@@ -20212,20 +20216,41 @@ function hasClaudeOneMillionMarker(modelId) {
20212
20216
  function stripClaudeOneMillionMarker(modelId) {
20213
20217
  return modelId.replace(/\[1m\]$/i, "");
20214
20218
  }
20215
- function projectClaudeContextInputTokens(inputTokens, advertisedContextWindow, upstreamContextWindow = advertisedContextWindow) {
20219
+ function projectClaudeContextInputTokens(inputTokens, advertisedContextWindow, upstreamContextWindow = advertisedContextWindow, compactCeiling) {
20216
20220
  if (!Number.isFinite(inputTokens) || inputTokens < 0) return inputTokens;
20217
20221
  const advertisedWindow = positiveContextWindow(advertisedContextWindow);
20218
20222
  if (advertisedWindow === void 0) return inputTokens;
20219
20223
  const projectionWindow = positiveContextWindow(upstreamContextWindow) ?? advertisedWindow;
20220
20224
  const coordinate = advertisedWindow >= CLAUDE_COMPAT_CONTEXT_WINDOW ? CLAUDE_COMPAT_CONTEXT_WINDOW : CLAUDE_DEFAULT_CONTEXT_WINDOW;
20221
20225
  const claudeCompactThreshold = coordinate - CLAUDE_COMPACT_RESERVE;
20222
- const providerCompactThreshold = projectionWindow - PROVIDER_COMPACT_RESERVE;
20226
+ const providerCompactThreshold = compactThresholdTokens(projectionWindow, compactCeiling);
20223
20227
  if (providerCompactThreshold <= 0) return Math.min(coordinate, inputTokens);
20224
20228
  return Math.min(
20225
20229
  coordinate,
20226
20230
  Math.ceil(inputTokens * claudeCompactThreshold / providerCompactThreshold)
20227
20231
  );
20228
20232
  }
20233
+ function compactThresholdTokens(window, compactCeiling) {
20234
+ if (!Number.isFinite(window) || window <= 0) return window;
20235
+ const percent2 = compactCeilingPercent(compactCeiling);
20236
+ if (percent2 === void 0) return window - PROVIDER_COMPACT_RESERVE;
20237
+ return Math.floor(window * percent2 / 100);
20238
+ }
20239
+ function compactCeilingPercent(compactCeiling) {
20240
+ if (compactCeiling === "early") return COMPACT_CEILING_EARLY_PERCENT;
20241
+ if (compactCeiling === "late") return COMPACT_CEILING_LATE_PERCENT;
20242
+ if (typeof compactCeiling === "number" && Number.isInteger(compactCeiling) && compactCeiling >= COMPACT_CEILING_CUSTOM_MIN && compactCeiling <= COMPACT_CEILING_CUSTOM_MAX) {
20243
+ return compactCeiling;
20244
+ }
20245
+ return void 0;
20246
+ }
20247
+ function normalizeCompactCeiling(value) {
20248
+ if (value === "early" || value === "late") return value;
20249
+ if (typeof value === "number" && Number.isInteger(value) && value >= COMPACT_CEILING_CUSTOM_MIN && value <= COMPACT_CEILING_CUSTOM_MAX) {
20250
+ return value;
20251
+ }
20252
+ return void 0;
20253
+ }
20229
20254
  async function* projectAnthropicResponseUsage(chunks, options) {
20230
20255
  const contextWindow = positiveContextWindow(options.contextWindow);
20231
20256
  const responseModel = typeof options.responseModel === "string" && options.responseModel.length > 0 ? options.responseModel : void 0;
@@ -20239,7 +20264,8 @@ async function* projectAnthropicResponseUsage(chunks, options) {
20239
20264
  chunks,
20240
20265
  contextWindow,
20241
20266
  responseModel,
20242
- positiveLimit(options.maxSseFrameBytes, DEFAULT_MAX_SSE_FRAME_BYTES)
20267
+ positiveLimit(options.maxSseFrameBytes, DEFAULT_MAX_SSE_FRAME_BYTES),
20268
+ options.compactCeiling
20243
20269
  );
20244
20270
  return;
20245
20271
  }
@@ -20248,13 +20274,14 @@ async function* projectAnthropicResponseUsage(chunks, options) {
20248
20274
  chunks,
20249
20275
  contextWindow,
20250
20276
  responseModel,
20251
- positiveLimit(options.maxJsonBytes, DEFAULT_MAX_JSON_BYTES)
20277
+ positiveLimit(options.maxJsonBytes, DEFAULT_MAX_JSON_BYTES),
20278
+ options.compactCeiling
20252
20279
  );
20253
20280
  return;
20254
20281
  }
20255
20282
  yield* chunks;
20256
20283
  }
20257
- async function* projectJsonUsage(chunks, contextWindow, responseModel, maxBytes) {
20284
+ async function* projectJsonUsage(chunks, contextWindow, responseModel, maxBytes, compactCeiling) {
20258
20285
  const buffered = [];
20259
20286
  let bufferedBytes = 0;
20260
20287
  let passthrough = false;
@@ -20274,10 +20301,10 @@ async function* projectJsonUsage(chunks, contextWindow, responseModel, maxBytes)
20274
20301
  }
20275
20302
  if (passthrough || bufferedBytes === 0) return;
20276
20303
  const original = concatChunks(buffered, bufferedBytes);
20277
- const projected = projectJsonBytes(original, contextWindow, responseModel);
20304
+ const projected = projectJsonBytes(original, contextWindow, responseModel, compactCeiling);
20278
20305
  yield projected ?? original;
20279
20306
  }
20280
- async function* projectSseUsage(chunks, contextWindow, responseModel, maxFrameBytes) {
20307
+ async function* projectSseUsage(chunks, contextWindow, responseModel, maxFrameBytes, compactCeiling) {
20281
20308
  let buffered = new Uint8Array(0);
20282
20309
  let oversizedFrame = false;
20283
20310
  for await (const chunk of chunks) {
@@ -20304,7 +20331,7 @@ async function* projectSseUsage(chunks, contextWindow, responseModel, maxFrameBy
20304
20331
  const frame = buffered.slice(0, separator.index);
20305
20332
  const separatorBytes = buffered.slice(separator.index, separator.index + separator.length);
20306
20333
  const originalFrame = buffered.slice(0, separator.index + separator.length);
20307
- const projectedFrame = frame.byteLength > maxFrameBytes ? void 0 : projectSseFrame(frame, contextWindow, responseModel);
20334
+ const projectedFrame = frame.byteLength > maxFrameBytes ? void 0 : projectSseFrame(frame, contextWindow, responseModel, compactCeiling);
20308
20335
  yield projectedFrame === void 0 ? originalFrame : concatBytes(projectedFrame, separatorBytes);
20309
20336
  buffered = buffered.slice(separator.index + separator.length);
20310
20337
  }
@@ -20318,17 +20345,17 @@ async function* projectSseUsage(chunks, contextWindow, responseModel, maxFrameBy
20318
20345
  }
20319
20346
  if (buffered.byteLength > 0) yield buffered;
20320
20347
  }
20321
- function projectJsonBytes(bytes, contextWindow, responseModel) {
20348
+ function projectJsonBytes(bytes, contextWindow, responseModel, compactCeiling) {
20322
20349
  let parsed;
20323
20350
  try {
20324
20351
  parsed = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(bytes));
20325
20352
  } catch {
20326
20353
  return void 0;
20327
20354
  }
20328
- const projected = projectAnthropicUsageEnvelope(parsed, contextWindow, responseModel);
20355
+ const projected = projectAnthropicUsageEnvelope(parsed, contextWindow, responseModel, compactCeiling);
20329
20356
  return projected.changed ? new TextEncoder().encode(JSON.stringify(projected.value)) : void 0;
20330
20357
  }
20331
- function projectSseFrame(frame, contextWindow, responseModel) {
20358
+ function projectSseFrame(frame, contextWindow, responseModel, compactCeiling) {
20332
20359
  let text2;
20333
20360
  try {
20334
20361
  text2 = new TextDecoder("utf-8", { fatal: true }).decode(frame);
@@ -20354,7 +20381,7 @@ function projectSseFrame(frame, contextWindow, responseModel) {
20354
20381
  } catch {
20355
20382
  return void 0;
20356
20383
  }
20357
- const projected = projectAnthropicUsageEnvelope(parsed, contextWindow, responseModel);
20384
+ const projected = projectAnthropicUsageEnvelope(parsed, contextWindow, responseModel, compactCeiling);
20358
20385
  if (!projected.changed) return void 0;
20359
20386
  const firstDataIndex = dataIndexes[0];
20360
20387
  const dataIndexSet = new Set(dataIndexes);
@@ -20368,19 +20395,19 @@ function projectSseFrame(frame, contextWindow, responseModel) {
20368
20395
  }
20369
20396
  return new TextEncoder().encode(outputLines.join(newline));
20370
20397
  }
20371
- function projectAnthropicUsageEnvelope(value, contextWindow, responseModel) {
20398
+ function projectAnthropicUsageEnvelope(value, contextWindow, responseModel, compactCeiling) {
20372
20399
  if (!isRecord2(value)) return { changed: false, value };
20373
20400
  let projectedValue = value;
20374
20401
  let changed = false;
20375
20402
  if (contextWindow !== void 0) {
20376
- const topLevelUsage = projectUsageProperty(projectedValue, "usage", contextWindow);
20403
+ const topLevelUsage = projectUsageProperty(projectedValue, "usage", contextWindow, compactCeiling);
20377
20404
  if (topLevelUsage.changed) {
20378
20405
  projectedValue = topLevelUsage.value;
20379
20406
  changed = true;
20380
20407
  }
20381
20408
  const message = projectedValue.message;
20382
20409
  if (isRecord2(message)) {
20383
- const messageUsage = projectUsageProperty(message, "usage", contextWindow);
20410
+ const messageUsage = projectUsageProperty(message, "usage", contextWindow, compactCeiling);
20384
20411
  if (messageUsage.changed) {
20385
20412
  projectedValue = { ...projectedValue, message: messageUsage.value };
20386
20413
  changed = true;
@@ -20400,7 +20427,7 @@ function projectAnthropicUsageEnvelope(value, contextWindow, responseModel) {
20400
20427
  }
20401
20428
  return { changed, value: projectedValue };
20402
20429
  }
20403
- function projectUsageProperty(container, property, contextWindow) {
20430
+ function projectUsageProperty(container, property, contextWindow, compactCeiling) {
20404
20431
  const usage4 = container[property];
20405
20432
  if (!isRecord2(usage4)) return { changed: false, value: container };
20406
20433
  const coordinates = ANTHROPIC_INPUT_USAGE_FIELDS.map((field) => {
@@ -20409,7 +20436,7 @@ function projectUsageProperty(container, property, contextWindow) {
20409
20436
  }).filter((entry) => entry !== void 0);
20410
20437
  if (coordinates.length === 0) return { changed: false, value: container };
20411
20438
  const total = coordinates.reduce((sum, entry) => sum + entry.tokens, 0);
20412
- const projectedTotal = projectClaudeContextInputTokens(total, contextWindow);
20439
+ const projectedTotal = projectClaudeContextInputTokens(total, contextWindow, contextWindow, compactCeiling);
20413
20440
  if (projectedTotal === total) return { changed: false, value: container };
20414
20441
  const projectedUsage = { ...usage4 };
20415
20442
  const remainderField = coordinates.some((entry) => entry.field === "input_tokens") ? "input_tokens" : coordinates[0].field;
@@ -22073,12 +22100,13 @@ function stringMetadata(metadata) {
22073
22100
  );
22074
22101
  return entries.length === 0 ? void 0 : Object.fromEntries(entries);
22075
22102
  }
22076
- function toAnthropicCacheAwareUsage(rawInputTokens, cachedInputTokens, cacheWriteInputTokens, outputTokens, advertisedContextWindow, upstreamContextWindow) {
22103
+ function toAnthropicCacheAwareUsage(rawInputTokens, cachedInputTokens, cacheWriteInputTokens, outputTokens, advertisedContextWindow, upstreamContextWindow, compactCeiling) {
22077
22104
  const safeInputTokens = Number.isFinite(rawInputTokens) && rawInputTokens > 0 ? rawInputTokens : 0;
22078
22105
  const projectedTotal = projectClaudeContextInputTokens(
22079
22106
  safeInputTokens,
22080
22107
  advertisedContextWindow,
22081
- upstreamContextWindow
22108
+ upstreamContextWindow,
22109
+ compactCeiling
22082
22110
  );
22083
22111
  if (safeInputTokens === 0) {
22084
22112
  return {
@@ -22128,7 +22156,8 @@ function anthropicUsageFromCanonical(usage4, advertisedContextWindow, options =
22128
22156
  usage4?.cache_write_input_tokens,
22129
22157
  options.forceOutputZero ? 0 : usage4?.output_tokens ?? 0,
22130
22158
  advertisedContextWindow,
22131
- usage4?.context_window
22159
+ usage4?.context_window,
22160
+ options.compactCeiling
22132
22161
  );
22133
22162
  }
22134
22163
  async function collectAnthropicMessage(events, fallbackModel, options = {}) {
@@ -22231,7 +22260,8 @@ async function collectAnthropicMessage(events, fallbackModel, options = {}) {
22231
22260
  cacheWriteInputTokens,
22232
22261
  outputTokens,
22233
22262
  options.contextWindow,
22234
- upstreamContextWindow
22263
+ upstreamContextWindow,
22264
+ options.compactCeiling
22235
22265
  )
22236
22266
  };
22237
22267
  }
@@ -22309,7 +22339,8 @@ data: ${JSON.stringify(data)}
22309
22339
  stop_reason: null,
22310
22340
  stop_sequence: null,
22311
22341
  usage: anthropicUsageFromCanonical(event.response.usage, options.contextWindow, {
22312
- forceOutputZero: true
22342
+ forceOutputZero: true,
22343
+ compactCeiling: options.compactCeiling
22313
22344
  })
22314
22345
  }
22315
22346
  });
@@ -22475,7 +22506,9 @@ data: ${JSON.stringify(data)}
22475
22506
  // Claude Code updates context occupancy from the terminal cumulative
22476
22507
  // usage frame. Sending output-only leaves Responses-backed models at
22477
22508
  // zero input usage even though Kimi's native Anthropic stream works.
22478
- usage: anthropicUsageFromCanonical(event.response.usage, options.contextWindow)
22509
+ usage: anthropicUsageFromCanonical(event.response.usage, options.contextWindow, {
22510
+ compactCeiling: options.compactCeiling
22511
+ })
22479
22512
  });
22480
22513
  yield encode3("message_stop", { type: "message_stop" });
22481
22514
  messageStopped = true;
@@ -22720,6 +22753,20 @@ function nextEventBoundary(buffer) {
22720
22753
  const match = /\r\n\r\n|\n\n|\r\r/.exec(buffer);
22721
22754
  return match === null ? void 0 : { index: match.index, length: match[0].length };
22722
22755
  }
22756
+ function nextEventBoundaryBytes(buffer) {
22757
+ for (let index = 0; index < buffer.byteLength; index += 1) {
22758
+ const first = buffer[index];
22759
+ if (first === 10) {
22760
+ if (buffer[index + 1] === 10) return { index, length: 2 };
22761
+ continue;
22762
+ }
22763
+ if (first !== 13) continue;
22764
+ if (buffer[index + 1] === 13) return { index, length: 2 };
22765
+ if (buffer[index + 1] !== 10) continue;
22766
+ if (buffer[index + 2] === 13 && buffer[index + 3] === 10) return { index, length: 4 };
22767
+ }
22768
+ return void 0;
22769
+ }
22723
22770
  function parseSseFrameFields(frame) {
22724
22771
  let eventName;
22725
22772
  const data = [];
@@ -22863,6 +22910,104 @@ async function* logCanonicalEvents(events, event) {
22863
22910
  yield item;
22864
22911
  }
22865
22912
  }
22913
+ function logRawWireEvent(label, eventName, data) {
22914
+ if (!wireLogEnabled()) return;
22915
+ wireLog(label, {
22916
+ ...eventName === void 0 ? {} : { event: eventName },
22917
+ data
22918
+ });
22919
+ }
22920
+ var RAW_EVENT_MAX_FRAME_BYTES = 1024 * 1024;
22921
+ var RAW_EVENT_MAX_JSON_BYTES = 16 * 1024 * 1024;
22922
+ async function* logRawPassthroughBody(chunks, options) {
22923
+ if (!wireLogEnabled()) {
22924
+ yield* chunks;
22925
+ return;
22926
+ }
22927
+ const mediaType = options.contentType?.split(";", 1)[0]?.trim().toLowerCase();
22928
+ if (mediaType === "text/event-stream") {
22929
+ yield* tapPassthroughSse(chunks, options.label);
22930
+ return;
22931
+ }
22932
+ if (mediaType === "application/json" || mediaType?.endsWith("+json")) {
22933
+ yield* tapPassthroughJson(chunks, options.label);
22934
+ return;
22935
+ }
22936
+ yield* chunks;
22937
+ }
22938
+ async function* tapPassthroughSse(chunks, label) {
22939
+ let pending = new Uint8Array(0);
22940
+ let oversizedFrame = false;
22941
+ for await (const chunk of chunks) {
22942
+ pending = concatBytes2(pending, chunk);
22943
+ let boundary = nextEventBoundaryBytes(pending);
22944
+ while (boundary !== void 0) {
22945
+ const frame = pending.slice(0, boundary.index);
22946
+ pending = pending.slice(boundary.index + boundary.length);
22947
+ if (!oversizedFrame && frame.byteLength <= RAW_EVENT_MAX_FRAME_BYTES) {
22948
+ tapPassthroughFrameBytes(label, frame);
22949
+ }
22950
+ oversizedFrame = false;
22951
+ boundary = nextEventBoundaryBytes(pending);
22952
+ }
22953
+ if (pending.byteLength > RAW_EVENT_MAX_FRAME_BYTES) {
22954
+ pending = pending.slice(Math.max(0, pending.byteLength - 3));
22955
+ oversizedFrame = true;
22956
+ }
22957
+ yield chunk;
22958
+ }
22959
+ if (!oversizedFrame && pending.byteLength > 0) {
22960
+ tapPassthroughFrameBytes(label, pending);
22961
+ }
22962
+ }
22963
+ function tapPassthroughFrameBytes(label, frameBytes) {
22964
+ let frame;
22965
+ try {
22966
+ frame = new TextDecoder("utf-8", { fatal: true }).decode(frameBytes);
22967
+ } catch {
22968
+ return;
22969
+ }
22970
+ const { event: eventName, data } = parseSseFrameFields(frame);
22971
+ if (data.length === 0 || data === "[DONE]") return;
22972
+ let parsed;
22973
+ try {
22974
+ parsed = JSON.parse(data);
22975
+ } catch {
22976
+ return;
22977
+ }
22978
+ logRawWireEvent(label, eventName, parsed);
22979
+ }
22980
+ async function* tapPassthroughJson(chunks, label) {
22981
+ let pending = new Uint8Array(0);
22982
+ let oversized = false;
22983
+ for await (const chunk of chunks) {
22984
+ if (!oversized) {
22985
+ if (pending.byteLength + chunk.byteLength > RAW_EVENT_MAX_JSON_BYTES) {
22986
+ oversized = true;
22987
+ pending = new Uint8Array(0);
22988
+ } else {
22989
+ pending = concatBytes2(pending, chunk);
22990
+ }
22991
+ }
22992
+ yield chunk;
22993
+ }
22994
+ if (oversized || pending.byteLength === 0) return;
22995
+ let parsed;
22996
+ try {
22997
+ parsed = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(pending));
22998
+ } catch {
22999
+ return;
23000
+ }
23001
+ logRawWireEvent(label, void 0, parsed);
23002
+ }
23003
+ function concatBytes2(left, right) {
23004
+ if (left.byteLength === 0) return right;
23005
+ if (right.byteLength === 0) return left;
23006
+ const combined = new Uint8Array(left.byteLength + right.byteLength);
23007
+ combined.set(left, 0);
23008
+ combined.set(right, left.byteLength);
23009
+ return combined;
23010
+ }
22866
23011
  var OPENAI_RESPONSES_URL = "https://api.openai.com/v1/responses";
22867
23012
  var CHATGPT_CODEX_RESPONSES_URL = "https://chatgpt.com/backend-api/codex/responses";
22868
23013
  var DEFAULT_MAX_UPSTREAM_BODY_BYTES = 64 * 1024 * 1024;
@@ -23293,6 +23438,7 @@ function parseEventFrame(frame) {
23293
23438
  `OpenAI SSE contained invalid JSON: ${error51 instanceof Error ? error51.message : String(error51)}`
23294
23439
  );
23295
23440
  }
23441
+ logRawWireEvent("openai.wire.event", eventName, parsed);
23296
23442
  if (isRecord3(parsed) && typeof parsed.type !== "string" && eventName !== void 0) {
23297
23443
  parsed = { ...parsed, type: eventName };
23298
23444
  }
@@ -23790,12 +23936,14 @@ var AnthropicMessagesGateway = class {
23790
23936
  }),
23791
23937
  body: withSseKeepAlive(encodeAnthropicSse(events, {
23792
23938
  contextWindow: options.contextWindow,
23939
+ compactCeiling: options.compactCeiling,
23793
23940
  model: request.model
23794
23941
  }))
23795
23942
  };
23796
23943
  }
23797
23944
  const message = await collectAnthropicMessage(events, request.model, {
23798
23945
  contextWindow: options.contextWindow,
23946
+ compactCeiling: options.compactCeiling,
23799
23947
  model: request.model
23800
23948
  });
23801
23949
  return {
@@ -24521,6 +24669,7 @@ function parseEventFrame2(frame) {
24521
24669
  `Grok CLI SSE contained invalid JSON: ${error51 instanceof Error ? error51.message : String(error51)}`
24522
24670
  );
24523
24671
  }
24672
+ logRawWireEvent("xai-responses.wire.event", eventName, parsed);
24524
24673
  if (isRecord5(parsed) && typeof parsed.type !== "string" && eventName !== void 0) {
24525
24674
  parsed = { ...parsed, type: eventName };
24526
24675
  }
@@ -28524,6 +28673,7 @@ ${argumentsText}`;
28524
28673
  continue;
28525
28674
  }
28526
28675
  const decodedFrame = decodeCursorServerMessage(frame.payload);
28676
+ logRawWireEvent("cursor.wire.event", void 0, decodedFrame);
28527
28677
  if (!isCursorHeartbeatFrame(decodedFrame)) noteSemanticProgress();
28528
28678
  handleFrame(decodedFrame);
28529
28679
  }
@@ -29146,12 +29296,14 @@ function normalizeAiGatewaySettings(value) {
29146
29296
  }];
29147
29297
  }) : [];
29148
29298
  const providerPriority = sanitizeProviderPriority(value.providerPriority);
29299
+ const compactCeiling = normalizeCompactCeiling(value.compactCeiling);
29149
29300
  return {
29150
29301
  version: 1,
29151
29302
  ...models.length > 0 ? { models } : {},
29152
29303
  ...value.cursorDiagnosticsEnabled === true ? { cursorDiagnosticsEnabled: true } : {},
29153
29304
  ...typeof value.wireLogEnabled === "boolean" ? { wireLogEnabled: value.wireLogEnabled } : {},
29154
- ...providerPriority ? { providerPriority: [...providerPriority] } : {}
29305
+ ...providerPriority ? { providerPriority: [...providerPriority] } : {},
29306
+ ...compactCeiling !== void 0 ? { compactCeiling } : {}
29155
29307
  };
29156
29308
  }
29157
29309
  function sanitizeProviderPriority(value) {
@@ -29757,17 +29909,19 @@ async function* translateChatCompletionsStream(body, options, toolSchemas) {
29757
29909
  while (boundary !== void 0) {
29758
29910
  const frame = buffer.slice(0, boundary.index);
29759
29911
  buffer = buffer.slice(boundary.index + boundary.length);
29760
- const data = chatFrameData(frame);
29761
- if (data !== void 0) {
29762
- yield* consumeChunk(data);
29912
+ const frameData = chatFrameData(frame);
29913
+ if (frameData !== void 0) {
29914
+ logRawWireEvent("openai-chat.wire.event", frameData.event, frameData.data);
29915
+ yield* consumeChunk(frameData.data);
29763
29916
  }
29764
29917
  boundary = nextEventBoundary(buffer);
29765
29918
  }
29766
29919
  }
29767
29920
  if (buffer.trim().length > 0) {
29768
- const data = chatFrameData(buffer);
29769
- if (data !== void 0) {
29770
- yield* consumeChunk(data);
29921
+ const frameData = chatFrameData(buffer);
29922
+ if (frameData !== void 0) {
29923
+ logRawWireEvent("openai-chat.wire.event", frameData.event, frameData.data);
29924
+ yield* consumeChunk(frameData.data);
29771
29925
  }
29772
29926
  }
29773
29927
  yield* finish();
@@ -29777,12 +29931,15 @@ async function* translateChatCompletionsStream(body, options, toolSchemas) {
29777
29931
  }
29778
29932
  }
29779
29933
  function chatFrameData(frame) {
29780
- const { data } = parseSseFrameFields(frame);
29934
+ const { event: eventName, data } = parseSseFrameFields(frame);
29781
29935
  if (data.length === 0 || data === "[DONE]") {
29782
29936
  return void 0;
29783
29937
  }
29784
29938
  try {
29785
- return JSON.parse(data);
29939
+ return {
29940
+ ...eventName === void 0 ? {} : { event: eventName },
29941
+ data: JSON.parse(data)
29942
+ };
29786
29943
  } catch (error51) {
29787
29944
  throw new UpstreamProtocolError(
29788
29945
  `Chat Completions SSE contained invalid JSON: ${error51 instanceof Error ? error51.message : String(error51)}`
@@ -29980,6 +30137,7 @@ function parseEventFrame3(frame) {
29980
30137
  `OpenCode Go SSE contained invalid JSON: ${error51 instanceof Error ? error51.message : String(error51)}`
29981
30138
  );
29982
30139
  }
30140
+ logRawWireEvent("opencode-go-responses.wire.event", eventName, parsed);
29983
30141
  if (isRecord11(parsed) && typeof parsed.type !== "string" && eventName !== void 0) {
29984
30142
  parsed = { ...parsed, type: eventName };
29985
30143
  }
@@ -30426,9 +30584,14 @@ async function proxyAnthropicMessages(res, body, options) {
30426
30584
  }
30427
30585
  const rawBody = readResponseBody(upstream.body);
30428
30586
  const contentType = upstream.headers.get("content-type");
30429
- const projectedBody = options.contextWindow === void 0 && options.responseModel === void 0 ? rawBody : projectAnthropicResponseUsage(rawBody, {
30587
+ const observedBody = options.wireEventLabel === void 0 ? rawBody : logRawPassthroughBody(rawBody, {
30588
+ label: options.wireEventLabel,
30589
+ contentType
30590
+ });
30591
+ const projectedBody = options.contextWindow === void 0 && options.responseModel === void 0 ? observedBody : projectAnthropicResponseUsage(observedBody, {
30430
30592
  contentType,
30431
30593
  contextWindow: options.contextWindow,
30594
+ compactCeiling: options.compactCeiling,
30432
30595
  responseModel: options.responseModel
30433
30596
  });
30434
30597
  const responseBody = options.keepAlive === true && contentType?.split(";", 1)[0]?.trim().toLowerCase() === "text/event-stream" ? withSseKeepAlive(projectedBody) : projectedBody;
@@ -30479,17 +30642,19 @@ function isOpencodeAnthropicPassthrough(model) {
30479
30642
  function createOpencodeGateway(wire) {
30480
30643
  return new AnthropicMessagesGateway(createOpencodeGoAdapter(wire));
30481
30644
  }
30482
- async function proxyToOpencode(requestHeaders, res, body, model, contextWindow, apiKey, fetchImpl, signal) {
30645
+ async function proxyToOpencode(requestHeaders, res, body, model, contextWindow, compactCeiling, apiKey, fetchImpl, signal) {
30483
30646
  const headers = opencodeAnthropicHeaders(requestHeaders, apiKey);
30484
30647
  const responseModel = typeof body.model === "string" ? body.model : void 0;
30485
30648
  await proxyAnthropicMessages(res, opencodeRequestBody(body, model), {
30486
30649
  contextWindow,
30650
+ compactCeiling,
30487
30651
  responseModel,
30488
30652
  keepAlive: true,
30489
30653
  fetchImpl,
30490
30654
  headers,
30491
30655
  signal,
30492
- url: OPENCODE_GO_MESSAGES_URL
30656
+ url: OPENCODE_GO_MESSAGES_URL,
30657
+ wireEventLabel: "opencode-go-anthropic.wire.event"
30493
30658
  });
30494
30659
  }
30495
30660
  var AI_GATEWAY_ROUTE_SEGMENT = "ai-gateway";
@@ -30542,6 +30707,13 @@ function createAiGatewayRouter(deps) {
30542
30707
  return false;
30543
30708
  }
30544
30709
  };
30710
+ const compactCeiling = () => {
30711
+ try {
30712
+ return gatewaySettings()?.compactCeiling;
30713
+ } catch {
30714
+ return void 0;
30715
+ }
30716
+ };
30545
30717
  const handle = async ({ req, res, pathname }) => {
30546
30718
  if (pathname.endsWith("/api/hello")) {
30547
30719
  res.writeHead(200, { "content-type": "application/json" });
@@ -30661,6 +30833,7 @@ function createAiGatewayRouter(deps) {
30661
30833
  return true;
30662
30834
  }
30663
30835
  const claudeContextWindow = target2.contextWindow;
30836
+ const ceiling = compactCeiling();
30664
30837
  if (target2.provider === "kimi") {
30665
30838
  await proxyToKimi(
30666
30839
  req.headers,
@@ -30668,6 +30841,7 @@ function createAiGatewayRouter(deps) {
30668
30841
  body,
30669
30842
  upstreamModelId(target2),
30670
30843
  claudeContextWindow,
30844
+ ceiling,
30671
30845
  credential,
30672
30846
  fetchImpl,
30673
30847
  controller.signal
@@ -30681,6 +30855,7 @@ function createAiGatewayRouter(deps) {
30681
30855
  body,
30682
30856
  upstreamModelId(target2),
30683
30857
  claudeContextWindow,
30858
+ ceiling,
30684
30859
  credential,
30685
30860
  fetchImpl,
30686
30861
  controller.signal
@@ -30693,6 +30868,7 @@ function createAiGatewayRouter(deps) {
30693
30868
  const upstream = await gateway.stream(body, {
30694
30869
  apiKey: credential,
30695
30870
  ...claudeContextWindow ? { contextWindow: claudeContextWindow } : {},
30871
+ ...ceiling === void 0 ? {} : { compactCeiling: ceiling },
30696
30872
  ...modelContextWindow === void 0 ? {} : { modelContextWindow },
30697
30873
  ...diagnosticsEnabled === void 0 ? {} : { diagnosticsEnabled },
30698
30874
  signal: controller.signal,
@@ -30736,20 +30912,23 @@ async function proxyToAnthropic(requestHeaders, res, body, fetchImpl, signal) {
30736
30912
  fetchImpl,
30737
30913
  headers,
30738
30914
  signal,
30739
- url: ANTHROPIC_MESSAGES_URL
30915
+ url: ANTHROPIC_MESSAGES_URL,
30916
+ wireEventLabel: "anthropic.wire.event"
30740
30917
  });
30741
30918
  }
30742
- async function proxyToKimi(requestHeaders, res, body, model, contextWindow, apiKey, fetchImpl, signal) {
30919
+ async function proxyToKimi(requestHeaders, res, body, model, contextWindow, compactCeiling, apiKey, fetchImpl, signal) {
30743
30920
  const headers = kimiAnthropicHeaders(requestHeaders, apiKey);
30744
30921
  const responseModel = typeof body.model === "string" ? body.model : void 0;
30745
30922
  await proxyAnthropicMessages(res, kimiRequestBody(body, model), {
30746
30923
  contextWindow,
30924
+ compactCeiling,
30747
30925
  responseModel,
30748
30926
  keepAlive: true,
30749
30927
  fetchImpl,
30750
30928
  headers,
30751
30929
  signal,
30752
- url: KIMI_MESSAGES_URL
30930
+ url: KIMI_MESSAGES_URL,
30931
+ wireEventLabel: "kimi-anthropic.wire.event"
30753
30932
  });
30754
30933
  }
30755
30934
  function createGatewayFor(model, chatgptAccountId, originator) {
@@ -30844,6 +31023,7 @@ function createAiGatewaySettingsStore(deps = {}) {
30844
31023
  // 우선순위는 이 update 계약이 나르지 않는 별도 표면의 설정이다. 이월하지 않으면
30845
31024
  // 무관한 모델 노출 저장 한 번이 사용자의 소진 순서를 지운다.
30846
31025
  ...current.providerPriority ? { providerPriority: current.providerPriority } : {},
31026
+ ...current.compactCeiling !== void 0 ? { compactCeiling: current.compactCeiling } : {},
30847
31027
  ...value ?? {}
30848
31028
  })),
30849
31029
  writeCursorDiagnosticsEnabled: (enabled) => update((current) => normalizeAiGatewaySettings({
@@ -30859,6 +31039,16 @@ function createAiGatewaySettingsStore(deps = {}) {
30859
31039
  const withoutWireLog = { ...next };
30860
31040
  delete withoutWireLog.wireLogEnabled;
30861
31041
  return withoutWireLog;
31042
+ }),
31043
+ writeCompactCeiling: (ceiling) => update((current) => {
31044
+ const next = normalizeAiGatewaySettings({
31045
+ ...current,
31046
+ ...ceiling === void 0 ? {} : { compactCeiling: ceiling }
31047
+ });
31048
+ if (ceiling !== void 0) return next;
31049
+ const withoutCeiling = { ...next };
31050
+ delete withoutCeiling.compactCeiling;
31051
+ return withoutCeiling;
30862
31052
  })
30863
31053
  };
30864
31054
  }
@@ -30887,7 +31077,7 @@ function readLegacySettings(legacyPath) {
30887
31077
  return hasStoredValue(settings2) ? { kind: "adopt", settings: settings2 } : { kind: "nothing" };
30888
31078
  }
30889
31079
  function hasStoredValue(settings2) {
30890
- return (settings2.models?.length ?? 0) > 0 || settings2.cursorDiagnosticsEnabled !== void 0 || settings2.wireLogEnabled !== void 0;
31080
+ return (settings2.models?.length ?? 0) > 0 || settings2.cursorDiagnosticsEnabled !== void 0 || settings2.wireLogEnabled !== void 0 || settings2.providerPriority !== void 0 || settings2.compactCeiling !== void 0;
30891
31081
  }
30892
31082
 
30893
31083
  // ../../packages/fleet-admiral/src/ai-gateway/auth.ts
@@ -44830,7 +45020,13 @@ function buildAgentCliLaunchKinds(metadata, operationType, gatewaySelection) {
44830
45020
  id: cli.id,
44831
45021
  type: operationType,
44832
45022
  title: cli.label,
44833
- ...disabledReason ? { disabled: true, disabledReason } : cli.id === "claude-gateway" ? { variants: buildClaudeGatewayLaunchVariants(gatewaySelection) } : {}
45023
+ ...disabledReason ? { disabled: true, disabledReason } : cli.id === "claude-gateway" ? {
45024
+ variants: buildClaudeGatewayLaunchVariants(gatewaySelection),
45025
+ // 채팅으로 태어나는 길은 SDK 인수 계약 위에 서므로 Claude Gateway 종류에서만 열린다
45026
+ // (전환 경로의 `chat_unsupported`와 같은 판정). 다른 종류는 선언하지 않으므로
45027
+ // 컴포저의 시작 뷰 선택 자체가 서지 않는다.
45028
+ launchViews: ["terminal", "chat"]
45029
+ } : {}
44834
45030
  };
44835
45031
  });
44836
45032
  }
@@ -46497,6 +46693,25 @@ function createConsoleObservabilityStore(deps = {}) {
46497
46693
  clearTerminalSessionBackgroundPending(session);
46498
46694
  return toTerminalSessionInfo(session);
46499
46695
  }
46696
+ function setTerminalSessionChatActive(sessionId, active) {
46697
+ const session = terminalSessionsById.get(sessionId);
46698
+ if (!session) return null;
46699
+ if (session.chatActive === true === active) return null;
46700
+ if (active) session.chatActive = true;
46701
+ else {
46702
+ delete session.chatActive;
46703
+ delete session.chatWorking;
46704
+ }
46705
+ return toTerminalSessionInfo(session);
46706
+ }
46707
+ function setTerminalSessionChatWorking(sessionId, working) {
46708
+ const session = terminalSessionsById.get(sessionId);
46709
+ if (!session || session.chatActive !== true) return null;
46710
+ if (session.chatWorking === true === working) return toTerminalSessionInfo(session);
46711
+ if (working) session.chatWorking = true;
46712
+ else delete session.chatWorking;
46713
+ return toTerminalSessionInfo(session);
46714
+ }
46500
46715
  function renameTerminalSession(sessionId, rawLabel) {
46501
46716
  const session = terminalSessionsById.get(sessionId);
46502
46717
  if (!session) return null;
@@ -46609,6 +46824,8 @@ function createConsoleObservabilityStore(deps = {}) {
46609
46824
  setTerminalSessionBackgroundPending,
46610
46825
  getTerminalSessionSettledAgentIds,
46611
46826
  setTerminalSessionModelActivity,
46827
+ setTerminalSessionChatActive,
46828
+ setTerminalSessionChatWorking,
46612
46829
  transitionTerminalSessionToDormant,
46613
46830
  removeTerminalSession,
46614
46831
  registerTerminalRuntimeSession,
@@ -46632,6 +46849,8 @@ function toTerminalSessionInfo(state) {
46632
46849
  ...state.modelActivity ? { modelActivity: state.modelActivity } : {},
46633
46850
  ...state.attentionPending === true ? { attentionPending: true } : {},
46634
46851
  ...state.backgroundPending === true ? { backgroundPending: true } : {},
46852
+ ...state.chatActive === true ? { chatActive: true } : {},
46853
+ ...state.chatWorking === true ? { chatWorking: true } : {},
46635
46854
  createdAt: state.createdAt,
46636
46855
  theaterId: state.theaterId,
46637
46856
  registrationId: state.registrationId,
@@ -46892,7 +47111,10 @@ var AgentChatSession = class {
46892
47111
  createSdk;
46893
47112
  sdk = null;
46894
47113
  sdkFlight = null;
46895
- /** resume 좌표는 트랜스크립트 파일명이 말하는 세션 id다 — 캡처 id는 드리프트할 수 있다. */
47114
+ /**
47115
+ * resume 좌표는 트랜스크립트 파일명이 말하는 세션 id다 — 캡처 id는 드리프트할 수 있다.
47116
+ * `fresh`는 아직 세션이 없으므로 null로 출발하고, 첫 SDK 메시지의 session_id가 이 자리를 채운다.
47117
+ */
46896
47118
  latestSessionId;
46897
47119
  journal = [];
46898
47120
  seq = 0;
@@ -46904,16 +47126,18 @@ var AgentChatSession = class {
46904
47126
  this.operationId = operationId;
46905
47127
  this.seed = seed;
46906
47128
  this.createSdk = createSdk;
46907
- this.latestSessionId = path19__default.basename(seed.transcriptPath, ".jsonl");
47129
+ this.latestSessionId = seed.origin.kind === "resume" ? path19__default.basename(seed.origin.transcriptPath, ".jsonl") : null;
46908
47130
  }
46909
47131
  get busy() {
46910
47132
  return this.pendingTurns > 0;
46911
47133
  }
46912
47134
  async replayTranscript() {
47135
+ if (this.seed.origin.kind === "fresh") return;
47136
+ const transcriptPath = this.seed.origin.transcriptPath;
46913
47137
  this.push({ kind: "replay-start" });
46914
47138
  let turns = 0;
46915
47139
  try {
46916
- const raw = await promises.readFile(this.seed.transcriptPath, "utf8");
47140
+ const raw = await promises.readFile(transcriptPath, "utf8");
46917
47141
  for (const line of raw.split("\n")) {
46918
47142
  if (line.trim().length === 0) continue;
46919
47143
  for (const event of chatEventsFromTranscriptLine(line, { cwd: this.seed.cwd })) {
@@ -46938,6 +47162,13 @@ var AgentChatSession = class {
46938
47162
  * 턴을 직렬화해 실행한다. 반환은 큐 등록 시점이다 — 진행·실패는 저널 이벤트로 전달된다.
46939
47163
  * 실패한 턴은 반드시 run.close()로 슬롯을 반납한다(스파이크에서 실증한 함정).
46940
47164
  */
47165
+ /**
47166
+ * 활동축이 이 세션의 턴을 받을 수 있는지 미리 확인한다. 큐에 넣은 뒤에는 HTTP 응답이 이미
47167
+ * 떠났으므로, 거절은 요청 경계에서만 시끄러울 수 있다.
47168
+ */
47169
+ canReportActivity() {
47170
+ return this.seed.canReportActivity();
47171
+ }
46941
47172
  send(text2) {
46942
47173
  if (this.disposed) return;
46943
47174
  this.pendingTurns += 1;
@@ -46995,18 +47226,24 @@ var AgentChatSession = class {
46995
47226
  /**
46996
47227
  * 원 트랜스크립트를 격리 config dir의 같은 projects/<인코딩된 cwd>/ 아래로 복사한다.
46997
47228
  * 인코딩 규칙을 재구현하지 않는다 — 원 경로의 부모 디렉터리 이름이 곧 그 인코딩이다.
47229
+ * 채팅으로 태어난 세션에는 복사할 원본이 없다 — SDK가 자기 dir 안에 스스로 만든다.
46998
47230
  */
46999
47231
  async copyTranscriptIntoConfigDir(configDir) {
47000
- const projectDirName = path19__default.basename(path19__default.dirname(this.seed.transcriptPath));
47232
+ if (this.seed.origin.kind === "fresh") return;
47233
+ const projectDirName = path19__default.basename(path19__default.dirname(this.seed.origin.transcriptPath));
47001
47234
  const dest = path19__default.join(configDir, "projects", projectDirName, `${this.latestSessionId}.jsonl`);
47002
47235
  await promises.mkdir(path19__default.dirname(dest), { recursive: true, mode: 448 });
47003
- await promises.copyFile(this.seed.transcriptPath, dest);
47236
+ await promises.copyFile(this.seed.origin.transcriptPath, dest);
47004
47237
  }
47005
47238
  async runTurn(text2) {
47006
47239
  if (this.disposed) return;
47007
47240
  this.push({ kind: "dispatch", text: text2, at: Date.now() });
47008
47241
  this.push({ kind: "turn-start", at: Date.now() });
47009
- this.push({ kind: "status", working: true });
47242
+ if (!this.seed.reportActivity(true)) {
47243
+ this.push({ kind: "error", code: "chat_activity_unavailable" });
47244
+ this.push({ kind: "turn-end", ok: false });
47245
+ return;
47246
+ }
47010
47247
  let sawResult = false;
47011
47248
  try {
47012
47249
  const sdk = await this.ensureSdk();
@@ -47015,7 +47252,9 @@ var AgentChatSession = class {
47015
47252
  model: this.seed.model,
47016
47253
  ...this.seed.effort ? { effort: this.seed.effort } : {},
47017
47254
  cwd: this.seed.cwd,
47018
- resume: this.latestSessionId,
47255
+ // 채팅으로 태어난 세션의 첫 턴에는 이어붙일 좌표가 없다 — resume 없이 시작하고,
47256
+ // SDK가 돌려주는 session_id가 그 자리를 채운다(그다음 턴부터는 resume이 선다).
47257
+ ...this.latestSessionId ? { resume: this.latestSessionId } : {},
47019
47258
  permissionMode: "bypassPermissions",
47020
47259
  // 스트리밍 감각의 근거 — 글자 단위 text_delta를 받으려면 부분 메시지가 필요하다.
47021
47260
  includePartialMessages: true
@@ -47040,7 +47279,7 @@ var AgentChatSession = class {
47040
47279
  this.push({ kind: "error", code: "chat_turn_failed" });
47041
47280
  if (!sawResult) this.push({ kind: "turn-end", ok: false });
47042
47281
  } finally {
47043
- this.push({ kind: "status", working: false });
47282
+ this.seed.reportActivity(false);
47044
47283
  }
47045
47284
  }
47046
47285
  /**
@@ -47049,15 +47288,19 @@ var AgentChatSession = class {
47049
47288
  */
47050
47289
  async writeBackTranscript() {
47051
47290
  const sdk = this.sdk;
47052
- if (!sdk) return;
47053
- const projectDirName = path19__default.basename(path19__default.dirname(this.seed.transcriptPath));
47054
- const source = path19__default.join(sdk.configDir, "projects", projectDirName, `${this.latestSessionId}.jsonl`);
47291
+ if (!sdk || !this.latestSessionId) return;
47292
+ const sessionId = this.latestSessionId;
47293
+ const projectDirName = await this.resolveProjectDirName(sdk.configDir);
47294
+ if (!projectDirName) return;
47295
+ const source = path19__default.join(sdk.configDir, "projects", projectDirName, `${sessionId}.jsonl`);
47055
47296
  const sourceStat = await promises.stat(source).catch(() => null);
47056
47297
  if (!sourceStat?.isFile()) return;
47057
- const dest = path19__default.join(path19__default.dirname(this.seed.transcriptPath), `${this.latestSessionId}.jsonl`);
47298
+ const destDir = this.seed.origin.kind === "resume" ? path19__default.dirname(this.seed.origin.transcriptPath) : path19__default.join(this.seed.origin.transcriptRoot, projectDirName);
47299
+ const dest = path19__default.join(destDir, `${sessionId}.jsonl`);
47058
47300
  const destStat = await promises.stat(dest).catch(() => null);
47059
47301
  if (destStat?.isFile() && destStat.size > sourceStat.size) return;
47060
47302
  try {
47303
+ if (this.seed.origin.kind === "fresh") await promises.mkdir(destDir, { recursive: true, mode: 448 });
47061
47304
  await promises.copyFile(source, dest);
47062
47305
  } catch {
47063
47306
  this.push({ kind: "error", code: "chat_writeback_failed" });
@@ -47065,12 +47308,25 @@ var AgentChatSession = class {
47065
47308
  }
47066
47309
  this.seed.onProviderSessionUpdate({
47067
47310
  provider: "claude",
47068
- sessionId: this.latestSessionId,
47311
+ sessionId,
47069
47312
  transcriptPath: dest,
47070
47313
  source: "chat-mode",
47071
47314
  capturedAt: (/* @__PURE__ */ new Date()).toISOString()
47072
47315
  });
47073
47316
  }
47317
+ /**
47318
+ * 이 세션의 트랜스크립트가 앉은 projects 디렉터리 이름. resume은 원 경로가 이미 말해 주고,
47319
+ * fresh는 SDK가 자기 dir 안에 만든 이름을 읽는다 — cwd 인코딩 규칙을 재구현하지 않기 위해서다.
47320
+ * 격리 dir은 이 세션 전용이라 그 아래 projects 항목은 하나뿐이며, 여럿이면 무엇이 우리 것인지
47321
+ * 말할 수 없으므로 되쓰지 않는다(잘못된 뿌리에 남의 세션을 심는 것보다 낫다).
47322
+ */
47323
+ async resolveProjectDirName(configDir) {
47324
+ if (this.seed.origin.kind === "resume") return path19__default.basename(path19__default.dirname(this.seed.origin.transcriptPath));
47325
+ const entries = await promises.readdir(path19__default.join(configDir, "projects"), { withFileTypes: true }).catch(() => null);
47326
+ if (!entries) return null;
47327
+ const dirs = entries.filter((entry) => entry.isDirectory());
47328
+ return dirs.length === 1 ? dirs[0]?.name ?? null : null;
47329
+ }
47074
47330
  };
47075
47331
  var AgentChatRegistry = class {
47076
47332
  sessions = /* @__PURE__ */ new Map();
@@ -47300,6 +47556,15 @@ function registerTerminalSettingsRoutes(ctx, deps) {
47300
47556
  ));
47301
47557
  return true;
47302
47558
  }
47559
+ if ("compactCeiling" in update) {
47560
+ const stored = deps.aiGatewayStore.writeCompactCeiling(update.compactCeiling);
47561
+ ctx.host.http.writeJson(res, 200, toTerminalSettingsState(
47562
+ deps.globalOptionsService.load(),
47563
+ stored,
47564
+ deps.wireLogRuntime.enabled()
47565
+ ));
47566
+ return true;
47567
+ }
47303
47568
  const updated = deps.globalOptionsService.update((current) => ({ ...current, ...update }));
47304
47569
  ctx.host.http.writeJson(res, 200, toTerminalSettingsState(
47305
47570
  updated,
@@ -47326,7 +47591,8 @@ function toTerminalSettingsState(data, aiGateway, wireLogEnabled2) {
47326
47591
  } : null,
47327
47592
  aiGatewayCatalog: buildAiGatewayCatalog(),
47328
47593
  cursorDiagnosticsEnabled: aiGateway.cursorDiagnosticsEnabled === true,
47329
- wireLogEnabled: wireLogEnabled2
47594
+ wireLogEnabled: wireLogEnabled2,
47595
+ compactCeiling: aiGateway.compactCeiling ?? null
47330
47596
  };
47331
47597
  }
47332
47598
  function resolveAgentIdleDormantMinutes(data) {
@@ -47353,6 +47619,11 @@ function parseTerminalSettingsBody(value) {
47353
47619
  if (keys[0] === "wireLogEnabled") {
47354
47620
  return typeof body.wireLogEnabled === "boolean" ? { wireLogEnabled: body.wireLogEnabled } : null;
47355
47621
  }
47622
+ if (keys[0] === "compactCeiling") {
47623
+ if (body.compactCeiling === null) return { compactCeiling: void 0 };
47624
+ const ceiling = normalizeCompactCeiling(body.compactCeiling);
47625
+ return ceiling === void 0 ? null : { compactCeiling: ceiling };
47626
+ }
47356
47627
  return null;
47357
47628
  }
47358
47629
  function isAgentIdleDormantMinutes(value) {
@@ -47407,7 +47678,13 @@ var OPERATION_DELETED_EVENT_CHANNEL = "operation:deleted";
47407
47678
  var OPERATION_PURGED_EVENT_CHANNEL = "operation:purged";
47408
47679
  var TERMINAL_PLUGIN_ID = "terminal";
47409
47680
  var CHAT_MODE_PAYLOAD_KEY = "chatMode";
47681
+ var CHAT_BORN_PAYLOAD_KEY = "chatBorn";
47410
47682
  var CHAT_SUPPORTED_CLI_ID = "claude-gateway";
47683
+ function resolveClaudeProjectsRoot() {
47684
+ const configured = process4.env.CLAUDE_CONFIG_DIR;
47685
+ const configDir = configured && configured.length > 0 ? configured : path19__default.join(os3__default.homedir(), ".claude");
47686
+ return path19__default.join(configDir, "projects");
47687
+ }
47411
47688
  async function registerAgentRoutes(ctx, terminalRuntime, deps) {
47412
47689
  const api = await createAgentApi(ctx, terminalRuntime, deps);
47413
47690
  terminalRuntime.registerLaunchResolver(AGENT_OPERATION_TYPE, api.launch);
@@ -47713,6 +47990,15 @@ async function createAgentApi(ctx, terminalRuntime, deps) {
47713
47990
  const prompt = typeof body?.prompt === "string" ? sanitizeLaunchPrompt(body.prompt) : void 0;
47714
47991
  const attachmentIds = readAttachmentIds(body?.attachmentIds, res);
47715
47992
  if (attachmentIds === false) return true;
47993
+ if (body?.viewMode !== void 0 && body.viewMode !== "terminal" && body.viewMode !== "chat") {
47994
+ ctx.host.http.writeJson(res, 400, { error: "invalid_view_mode" });
47995
+ return true;
47996
+ }
47997
+ const chatBorn = body?.viewMode === "chat";
47998
+ if (chatBorn && cliId !== CHAT_SUPPORTED_CLI_ID) {
47999
+ ctx.host.http.writeJson(res, 409, { error: "chat_unsupported" });
48000
+ return true;
48001
+ }
47716
48002
  const cwd = ctx.host.paths.resolveTheaterPath(theaterId);
47717
48003
  if (!cwd) {
47718
48004
  ctx.host.http.writeJson(res, 404, { error: "theater_not_found" });
@@ -47732,7 +48018,8 @@ async function createAgentApi(ctx, terminalRuntime, deps) {
47732
48018
  await createSession(cwd, theaterId, cliId, res, {
47733
48019
  ...launchOptions,
47734
48020
  ...composedPrompt ? { prompt: composedPrompt } : {},
47735
- ...attachmentIds.length > 0 ? { attachmentIds } : {}
48021
+ ...attachmentIds.length > 0 ? { attachmentIds } : {},
48022
+ ...chatBorn ? { chatBorn: true } : {}
47736
48023
  });
47737
48024
  } catch (error51) {
47738
48025
  if (attachmentIds.length > 0) launchAttachments.unreserve(attachmentIds);
@@ -47805,6 +48092,37 @@ async function createAgentApi(ctx, terminalRuntime, deps) {
47805
48092
  }
47806
48093
  return methodNotAllowed2(res);
47807
48094
  }
48095
+ async function startChatBornSession(sessionId, res, launchOptions) {
48096
+ const rollback = (status, error51) => {
48097
+ if (launchOptions.attachmentIds && launchOptions.attachmentIds.length > 0) {
48098
+ launchAttachments.unreserve(launchOptions.attachmentIds);
48099
+ }
48100
+ ctx.host.operations.delete(sessionId);
48101
+ observability.removeTerminalSession(sessionId);
48102
+ ctx.host.http.writeJson(res, status, { error: error51 });
48103
+ };
48104
+ const node = ctx.host.operations.get(sessionId);
48105
+ if (!node) return rollback(500, "session_not_found");
48106
+ observability.updateTerminalSessionStatus(sessionId, "dormant");
48107
+ const activated = observability.setTerminalSessionChatActive(sessionId, true);
48108
+ if (activated) observability.notifySessionUpdated(activated);
48109
+ const seed = await resolveChatSeed(node);
48110
+ if (!seed.ok) return rollback(seed.status, seed.error);
48111
+ let chat;
48112
+ try {
48113
+ chat = await chatRegistry.ensure(sessionId, () => seed.seed);
48114
+ } catch {
48115
+ return rollback(503, "chat_unavailable");
48116
+ }
48117
+ if (launchOptions.prompt) chat.send(launchOptions.prompt);
48118
+ if (launchOptions.attachmentIds && launchOptions.attachmentIds.length > 0) {
48119
+ launchAttachments.bind(sessionId, launchOptions.attachmentIds);
48120
+ if (!ctx.host.operations.get(sessionId)) launchAttachments.releaseSession(sessionId);
48121
+ }
48122
+ const created = observability.getTerminalSessionInfo(sessionId);
48123
+ if (created) observability.notifySessionUpdated(created);
48124
+ ctx.host.http.writeJson(res, 200, created ?? { sessionId });
48125
+ }
47808
48126
  async function createSession(cwd, theaterId, cliId, res, launchOptions = {}) {
47809
48127
  const meta3 = (await buildAgentCliLaunchMetadata()).find((entry) => entry.id === cliId);
47810
48128
  if (!meta3 || !meta3.available || !meta3.signedIn) {
@@ -47832,10 +48150,17 @@ async function createAgentApi(ctx, terminalRuntime, deps) {
47832
48150
  // Claude Code의 resume가 launch 좌표를 자체 복원한다고 가정하지 않는다 — 정규화된
47833
48151
  // 최초 선택을 Operation에 남겨 dormant·Console 재시작 뒤에도 같은 인자로 재개한다.
47834
48152
  ...launchOptions.model ? { launchModel: launchOptions.model } : {},
47835
- ...launchOptions.effort ? { launchEffort: launchOptions.effort } : {}
48153
+ ...launchOptions.effort ? { launchEffort: launchOptions.effort } : {},
48154
+ // 채팅으로 태어난 Operation은 두 마커를 함께 진다. chatMode가 뷰를 가르고, chatBorn이
48155
+ // "transcript 부재는 상실이 아니라 아직 첫 턴 전"이라는 뜻을 durable하게 남긴다.
48156
+ ...launchOptions.chatBorn ? { [CHAT_MODE_PAYLOAD_KEY]: true, [CHAT_BORN_PAYLOAD_KEY]: true } : {}
47836
48157
  },
47837
48158
  createdAt: session.createdAt
47838
48159
  });
48160
+ if (launchOptions.chatBorn) {
48161
+ await startChatBornSession(sessionId, res, launchOptions);
48162
+ return;
48163
+ }
47839
48164
  try {
47840
48165
  await terminalRuntime.attach({
47841
48166
  cwd,
@@ -47911,6 +48236,8 @@ async function createAgentApi(ctx, terminalRuntime, deps) {
47911
48236
  const cleared = { ...ctx.host.operations.get(sessionId)?.payload ?? node.payload };
47912
48237
  delete cleared[CHAT_MODE_PAYLOAD_KEY];
47913
48238
  ctx.host.operations.patch(sessionId, { payload: cleared });
48239
+ const releasedOnResume = observability.setTerminalSessionChatActive(sessionId, false);
48240
+ if (releasedOnResume) observability.notifySessionUpdated(releasedOnResume);
47914
48241
  resumeNode = ctx.host.operations.get(sessionId) ?? node;
47915
48242
  if (!fresh) resumeProviderSession = readProviderSession(resumeNode.payload) ?? providerSession;
47916
48243
  }
@@ -48038,6 +48365,11 @@ async function createAgentApi(ctx, terminalRuntime, deps) {
48038
48365
  }
48039
48366
  try {
48040
48367
  const chat = await chatRegistry.ensure(sessionId, () => seed.seed);
48368
+ if (!chat.canReportActivity()) {
48369
+ settleAttachments(false);
48370
+ ctx.host.http.writeJson(res, 503, { error: "chat_activity_unavailable" });
48371
+ return true;
48372
+ }
48041
48373
  chat.send(composeLaunchPromptWithAttachments(text2.trim(), attachmentPaths));
48042
48374
  } catch {
48043
48375
  settleAttachments(false);
@@ -48115,6 +48447,8 @@ async function createAgentApi(ctx, terminalRuntime, deps) {
48115
48447
  const cleared = { ...ctx.host.operations.get(sessionId)?.payload ?? node.payload };
48116
48448
  delete cleared[CHAT_MODE_PAYLOAD_KEY];
48117
48449
  ctx.host.operations.patch(sessionId, { payload: cleared });
48450
+ const released = observability.setTerminalSessionChatActive(sessionId, false);
48451
+ if (released) observability.notifySessionUpdated(released);
48118
48452
  ctx.host.http.writeJson(res, 200, { ok: true });
48119
48453
  return true;
48120
48454
  }
@@ -48140,6 +48474,8 @@ async function createAgentApi(ctx, terminalRuntime, deps) {
48140
48474
  }
48141
48475
  }
48142
48476
  ctx.host.operations.patch(sessionId, { payload: { ...node.payload, [CHAT_MODE_PAYLOAD_KEY]: true } });
48477
+ const activated = observability.setTerminalSessionChatActive(sessionId, true);
48478
+ if (activated) observability.notifySessionUpdated(activated);
48143
48479
  if (live) {
48144
48480
  terminalRuntime.invalidateTicketsForSession(sessionId);
48145
48481
  terminalRuntime.terminate(sessionId);
@@ -48215,9 +48551,11 @@ async function createAgentApi(ctx, terminalRuntime, deps) {
48215
48551
  return { ok: false, status: 409, error: "chat_unsupported" };
48216
48552
  }
48217
48553
  const providerSession = readProviderSession(node.payload);
48218
- if (!providerSession?.transcriptPath) return { ok: false, status: 409, error: "chat_transcript_missing" };
48219
- const transcriptPath = await resolveTranscriptPath(providerSession.transcriptPath, node.ts.createdAt);
48220
- if (!transcriptPath) return { ok: false, status: 409, error: "chat_transcript_missing" };
48554
+ const transcriptPath = providerSession?.transcriptPath ? await resolveTranscriptPath(providerSession.transcriptPath, node.ts.createdAt) : null;
48555
+ const chatBorn = node.payload[CHAT_BORN_PAYLOAD_KEY] === true;
48556
+ const neverStarted = chatBorn && !providerSession;
48557
+ if (!transcriptPath && !neverStarted) return { ok: false, status: 409, error: "chat_transcript_missing" };
48558
+ const sessionOrigin = transcriptPath ? { kind: "resume", transcriptPath } : { kind: "fresh", transcriptRoot: resolveClaudeProjectsRoot() };
48221
48559
  const origin = ctx.host.server.origin();
48222
48560
  if (!origin) return { ok: false, status: 503, error: "chat_gateway_unavailable" };
48223
48561
  const cwd = readPayloadString(node.payload, "cwd") || ctx.host.paths.resolveTheaterPath(node.theaterId);
@@ -48231,11 +48569,18 @@ async function createAgentApi(ctx, terminalRuntime, deps) {
48231
48569
  model,
48232
48570
  ...effort ? { effort } : {},
48233
48571
  cwd,
48234
- transcriptPath,
48572
+ origin: sessionOrigin,
48235
48573
  onProviderSessionUpdate: (updated) => {
48236
48574
  const operation = ctx.host.operations.get(node.id);
48237
48575
  if (operation) ctx.host.operations.patch(node.id, { payload: { ...operation.payload, providerSession: updated } });
48238
48576
  observability.updateTerminalSessionProviderSession(node.id, updated);
48577
+ },
48578
+ canReportActivity: () => observability.getTerminalSessionInfo(node.id)?.chatActive === true,
48579
+ reportActivity: (working) => {
48580
+ const updated = observability.setTerminalSessionChatWorking(node.id, working);
48581
+ if (!updated) return false;
48582
+ observability.notifySessionUpdated(updated);
48583
+ return true;
48239
48584
  }
48240
48585
  }
48241
48586
  };
@@ -48492,8 +48837,13 @@ async function createAgentApi(ctx, terminalRuntime, deps) {
48492
48837
  for (const operation of ctx.host.operations.list()) {
48493
48838
  if (operation.pluginId !== ctx.pluginId || operation.type !== AGENT_OPERATION_TYPE) continue;
48494
48839
  const providerSession = readProviderSession(operation.payload);
48495
- if (!providerSession || observability.getTerminalSessionInfo(operation.id)) continue;
48840
+ const chatBorn = operation.payload[CHAT_BORN_PAYLOAD_KEY] === true;
48841
+ if (!providerSession && !chatBorn || observability.getTerminalSessionInfo(operation.id)) continue;
48496
48842
  const dormant = injectOperation(operation);
48843
+ if (operation.payload[CHAT_MODE_PAYLOAD_KEY] === true) {
48844
+ const adopted = observability.setTerminalSessionChatActive(operation.id, true);
48845
+ if (adopted) observability.notifySessionUpdated(adopted);
48846
+ }
48497
48847
  const cwd = readPayloadString(operation.payload, "cwd") || (ctx.host.paths.resolveTheaterPath(operation.theaterId) ?? "");
48498
48848
  ctx.host.operations.patch(operation.id, { payload: toOperationPayload(operation.payload, cwd, dormant, providerSession, observability.getDurableOperation(operation.id)?.providerTitle) });
48499
48849
  }