@dotobokuri/fleet-console 1.59.0 → 1.61.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +1 -1
- package/dist/cli.d.ts +13 -2
- package/dist/cli.mjs +126 -30
- package/dist/client/assets/{_baseUniq-CKkDoWU8.js → _baseUniq-9W447fNf.js} +1 -1
- package/dist/client/assets/{arc-CcRdX8oF.js → arc-hoitnVWi.js} +1 -1
- package/dist/client/assets/{architectureDiagram-Q4EWVU46-gaFzE1W7.js → architectureDiagram-Q4EWVU46-DYd58Vfc.js} +1 -1
- package/dist/client/assets/{blockDiagram-DXYQGD6D-Bzybih30.js → blockDiagram-DXYQGD6D-kuFqPdP_.js} +1 -1
- package/dist/client/assets/{c4Diagram-AHTNJAMY-Dz8bwV9j.js → c4Diagram-AHTNJAMY-C7n41zCn.js} +1 -1
- package/dist/client/assets/channel-D2TsEFjE.js +1 -0
- package/dist/client/assets/{chunk-4BX2VUAB-DmgZtGyV.js → chunk-4BX2VUAB-DrHeb54-.js} +1 -1
- package/dist/client/assets/{chunk-4TB4RGXK-DX1WxV3U.js → chunk-4TB4RGXK-DFjT6kwT.js} +1 -1
- package/dist/client/assets/{chunk-55IACEB6-Bk4b3T9u.js → chunk-55IACEB6-DxEzuA7W.js} +1 -1
- package/dist/client/assets/{chunk-EDXVE4YY-BzGadfvT.js → chunk-EDXVE4YY-aAlF0YEo.js} +1 -1
- package/dist/client/assets/{chunk-FMBD7UC4-44f7YyvW.js → chunk-FMBD7UC4-DwqRMFL1.js} +1 -1
- package/dist/client/assets/{chunk-OYMX7WX6-CyUAky9W.js → chunk-OYMX7WX6-DCkUlaRi.js} +1 -1
- package/dist/client/assets/{chunk-QZHKN3VN-C11OUntR.js → chunk-QZHKN3VN-B1Dx8Zhl.js} +1 -1
- package/dist/client/assets/{chunk-YZCP3GAM-DVTmWawU.js → chunk-YZCP3GAM-J2bgJmn-.js} +1 -1
- package/dist/client/assets/classDiagram-6PBFFD2Q-DhjJiPic.js +1 -0
- package/dist/client/assets/classDiagram-v2-HSJHXN6E-DhjJiPic.js +1 -0
- package/dist/client/assets/clone-DwVC2-Mi.js +1 -0
- package/dist/client/assets/{cose-bilkent-S5V4N54A-CEatGsZv.js → cose-bilkent-S5V4N54A-BxzLzyJp.js} +1 -1
- package/dist/client/assets/{dagre-KV5264BT-DlrgN02H.js → dagre-KV5264BT-D1ixDJxZ.js} +1 -1
- package/dist/client/assets/{diagram-5BDNPKRD-BZ3hRO5t.js → diagram-5BDNPKRD-DZPIz1Pa.js} +1 -1
- package/dist/client/assets/{diagram-G4DWMVQ6-B-izS46x.js → diagram-G4DWMVQ6-Pbcr-a5H.js} +1 -1
- package/dist/client/assets/{diagram-MMDJMWI5-Cw-wnJGs.js → diagram-MMDJMWI5-CBssBmPY.js} +1 -1
- package/dist/client/assets/{diagram-TYMM5635-BoWnyd4_.js → diagram-TYMM5635-cVQUs6jp.js} +1 -1
- package/dist/client/assets/{erDiagram-SMLLAGMA-BUmyXZbP.js → erDiagram-SMLLAGMA-ChMSAXos.js} +1 -1
- package/dist/client/assets/{flowDiagram-DWJPFMVM-COS3kjS0.js → flowDiagram-DWJPFMVM-FEIrU5mu.js} +1 -1
- package/dist/client/assets/{ganttDiagram-T4ZO3ILL-BTr1fdio.js → ganttDiagram-T4ZO3ILL-D6ELHTJY.js} +1 -1
- package/dist/client/assets/{gitGraphDiagram-UUTBAWPF-BkGkaosN.js → gitGraphDiagram-UUTBAWPF-DTJ6HgV4.js} +1 -1
- package/dist/client/assets/{graph-DmbgK-mH.js → graph-uscjDdHm.js} +1 -1
- package/dist/client/assets/index-DMjY1OQ0.js +465 -0
- package/dist/client/assets/index-Ec4RaE0g.css +1 -0
- package/dist/client/assets/{infoDiagram-42DDH7IO-B8zI6k1l.js → infoDiagram-42DDH7IO-C2AlA___.js} +1 -1
- package/dist/client/assets/{ishikawaDiagram-UXIWVN3A-cIcEzrcK.js → ishikawaDiagram-UXIWVN3A-BZGfIhBp.js} +1 -1
- package/dist/client/assets/{journeyDiagram-VCZTEJTY-DhuabHCk.js → journeyDiagram-VCZTEJTY-DnGNMdvj.js} +1 -1
- package/dist/client/assets/{kanban-definition-6JOO6SKY-uHTkqxhX.js → kanban-definition-6JOO6SKY-BkuplZGR.js} +1 -1
- package/dist/client/assets/{layout-Cfgk_duA.js → layout-BBayH8iU.js} +1 -1
- package/dist/client/assets/{linear-BKvV0sr5.js → linear-BQvaHed0.js} +1 -1
- package/dist/client/assets/{mermaid.core-DozmrCuG.js → mermaid.core-CO0f3d6Y.js} +4 -4
- package/dist/client/assets/{min-ke46otlW.js → min-B610GdeY.js} +1 -1
- package/dist/client/assets/{mindmap-definition-QFDTVHPH-d7xzxhzf.js → mindmap-definition-QFDTVHPH-gwkhgCyj.js} +1 -1
- package/dist/client/assets/{pieDiagram-DEJITSTG-C4S9Jy5A.js → pieDiagram-DEJITSTG-DYU2zgk8.js} +1 -1
- package/dist/client/assets/{quadrantDiagram-34T5L4WZ-CoQnj3kv.js → quadrantDiagram-34T5L4WZ-B5Vkk65i.js} +1 -1
- package/dist/client/assets/{requirementDiagram-MS252O5E-CdopMDtg.js → requirementDiagram-MS252O5E-D4EcF7kq.js} +1 -1
- package/dist/client/assets/{sankeyDiagram-XADWPNL6-DdR4zdh4.js → sankeyDiagram-XADWPNL6-DFk-RMV4.js} +1 -1
- package/dist/client/assets/{sequenceDiagram-FGHM5R23-NeYZWVQm.js → sequenceDiagram-FGHM5R23-B-beo9e0.js} +1 -1
- package/dist/client/assets/{stateDiagram-FHFEXIEX-D0CQGKV_.js → stateDiagram-FHFEXIEX-VDT0TOd7.js} +1 -1
- package/dist/client/assets/stateDiagram-v2-QKLJ7IA2-wHPBl_p1.js +1 -0
- package/dist/client/assets/{timeline-definition-GMOUNBTQ-Bz2b3nfQ.js → timeline-definition-GMOUNBTQ-By4DMNqG.js} +1 -1
- package/dist/client/assets/{vennDiagram-DHZGUBPP-CVO2Ja80.js → vennDiagram-DHZGUBPP-DzlBrijd.js} +1 -1
- package/dist/client/assets/{wardley-RL74JXVD-Ba_GKs5u.js → wardley-RL74JXVD-BHSHTMU6.js} +1 -1
- package/dist/client/assets/{wardleyDiagram-NUSXRM2D-yP3xvrPy.js → wardleyDiagram-NUSXRM2D-COB-cWHQ.js} +1 -1
- package/dist/client/assets/{xychartDiagram-5P7HB3ND-BLSs6w4C.js → xychartDiagram-5P7HB3ND-C-GVSBHd.js} +1 -1
- package/dist/client/index.html +2 -2
- package/dist/fleet-plugins/file-explorer/routes.mjs +132 -13
- package/dist/fleet-plugins/ledger/routes.mjs +223 -16
- package/dist/fleet-plugins/quota/routes.mjs +33 -2
- package/dist/fleet-plugins/scuttlebutt/routes.mjs +5 -5
- package/dist/fleet-plugins/terminal/routes.mjs +653 -79
- package/dist/fleet.mjs +383 -66
- package/package.json +1 -1
- package/dist/client/assets/channel-CAhLkt5l.js +0 -1
- package/dist/client/assets/classDiagram-6PBFFD2Q-BSvLoE2t.js +0 -1
- package/dist/client/assets/classDiagram-v2-HSJHXN6E-BSvLoE2t.js +0 -1
- package/dist/client/assets/clone-o26VS_sk.js +0 -1
- package/dist/client/assets/index-C-3spb_b.js +0 -465
- package/dist/client/assets/index-FU1PGEfG.css +0 -1
- 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
|
|
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
|
|
29761
|
-
if (
|
|
29762
|
-
|
|
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
|
|
29769
|
-
if (
|
|
29770
|
-
|
|
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
|
|
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
|
|
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" ? {
|
|
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
|
}
|
|
@@ -46291,6 +46487,13 @@ function agentLaunchProviderFromModel(model) {
|
|
|
46291
46487
|
function isAgentLaunchProvider(value) {
|
|
46292
46488
|
return value === "claude" || GATEWAY_PROVIDERS.includes(value);
|
|
46293
46489
|
}
|
|
46490
|
+
function agentLaunchProviderFromCliId(cliId) {
|
|
46491
|
+
if (!cliId) return void 0;
|
|
46492
|
+
if (cliId === "claude-gateway" || cliId === "claude") return "claude";
|
|
46493
|
+
const separator = cliId.indexOf(GATEWAY_MODEL_SEPARATOR);
|
|
46494
|
+
const candidate = separator > 0 ? cliId.slice(0, separator) : cliId;
|
|
46495
|
+
return GATEWAY_PROVIDERS.includes(candidate) ? candidate : void 0;
|
|
46496
|
+
}
|
|
46294
46497
|
var BACKGROUND_PENDING_TTL_MS = 30 * 6e4;
|
|
46295
46498
|
var EMPTY_SETTLED_AGENT_IDS = /* @__PURE__ */ new Set();
|
|
46296
46499
|
function createConsoleObservabilityStore(deps = {}) {
|
|
@@ -46497,6 +46700,25 @@ function createConsoleObservabilityStore(deps = {}) {
|
|
|
46497
46700
|
clearTerminalSessionBackgroundPending(session);
|
|
46498
46701
|
return toTerminalSessionInfo(session);
|
|
46499
46702
|
}
|
|
46703
|
+
function setTerminalSessionChatActive(sessionId, active) {
|
|
46704
|
+
const session = terminalSessionsById.get(sessionId);
|
|
46705
|
+
if (!session) return null;
|
|
46706
|
+
if (session.chatActive === true === active) return null;
|
|
46707
|
+
if (active) session.chatActive = true;
|
|
46708
|
+
else {
|
|
46709
|
+
delete session.chatActive;
|
|
46710
|
+
delete session.chatWorking;
|
|
46711
|
+
}
|
|
46712
|
+
return toTerminalSessionInfo(session);
|
|
46713
|
+
}
|
|
46714
|
+
function setTerminalSessionChatWorking(sessionId, working) {
|
|
46715
|
+
const session = terminalSessionsById.get(sessionId);
|
|
46716
|
+
if (!session || session.chatActive !== true) return null;
|
|
46717
|
+
if (session.chatWorking === true === working) return toTerminalSessionInfo(session);
|
|
46718
|
+
if (working) session.chatWorking = true;
|
|
46719
|
+
else delete session.chatWorking;
|
|
46720
|
+
return toTerminalSessionInfo(session);
|
|
46721
|
+
}
|
|
46500
46722
|
function renameTerminalSession(sessionId, rawLabel) {
|
|
46501
46723
|
const session = terminalSessionsById.get(sessionId);
|
|
46502
46724
|
if (!session) return null;
|
|
@@ -46609,6 +46831,8 @@ function createConsoleObservabilityStore(deps = {}) {
|
|
|
46609
46831
|
setTerminalSessionBackgroundPending,
|
|
46610
46832
|
getTerminalSessionSettledAgentIds,
|
|
46611
46833
|
setTerminalSessionModelActivity,
|
|
46834
|
+
setTerminalSessionChatActive,
|
|
46835
|
+
setTerminalSessionChatWorking,
|
|
46612
46836
|
transitionTerminalSessionToDormant,
|
|
46613
46837
|
removeTerminalSession,
|
|
46614
46838
|
registerTerminalRuntimeSession,
|
|
@@ -46632,6 +46856,8 @@ function toTerminalSessionInfo(state) {
|
|
|
46632
46856
|
...state.modelActivity ? { modelActivity: state.modelActivity } : {},
|
|
46633
46857
|
...state.attentionPending === true ? { attentionPending: true } : {},
|
|
46634
46858
|
...state.backgroundPending === true ? { backgroundPending: true } : {},
|
|
46859
|
+
...state.chatActive === true ? { chatActive: true } : {},
|
|
46860
|
+
...state.chatWorking === true ? { chatWorking: true } : {},
|
|
46635
46861
|
createdAt: state.createdAt,
|
|
46636
46862
|
theaterId: state.theaterId,
|
|
46637
46863
|
registrationId: state.registrationId,
|
|
@@ -46765,18 +46991,38 @@ function readAnalysisProviderSession(value) {
|
|
|
46765
46991
|
};
|
|
46766
46992
|
}
|
|
46767
46993
|
var MAX_TOOL_DETAIL_CHARS = 160;
|
|
46994
|
+
var MAX_TOOL_RESULT_CHARS = 120;
|
|
46768
46995
|
var MAX_TEXT_CHARS = 6e4;
|
|
46769
|
-
|
|
46996
|
+
var WRITE_TOOLS = /* @__PURE__ */ new Set(["Write", "Edit", "MultiEdit", "NotebookEdit"]);
|
|
46997
|
+
var CONTENT_RESULT_TOOLS = /* @__PURE__ */ new Set([
|
|
46998
|
+
"Read",
|
|
46999
|
+
"NotebookRead",
|
|
47000
|
+
"Glob",
|
|
47001
|
+
"Grep",
|
|
47002
|
+
"WebFetch",
|
|
47003
|
+
"WebSearch",
|
|
47004
|
+
"Task",
|
|
47005
|
+
"Agent"
|
|
47006
|
+
]);
|
|
47007
|
+
var PATH_KEYS = ["file_path", "path", "notebook_path"];
|
|
47008
|
+
function chatReplayFromTranscriptLine(raw, options = {}) {
|
|
46770
47009
|
let line;
|
|
46771
47010
|
try {
|
|
46772
47011
|
line = JSON.parse(raw);
|
|
46773
47012
|
} catch {
|
|
46774
|
-
return [];
|
|
47013
|
+
return { events: [] };
|
|
46775
47014
|
}
|
|
47015
|
+
const parsedAt = typeof line.timestamp === "string" ? Date.parse(line.timestamp) : Number.NaN;
|
|
47016
|
+
const events = eventsFromTranscriptLine(line, options);
|
|
47017
|
+
return Number.isFinite(parsedAt) ? { at: parsedAt, events } : { events };
|
|
47018
|
+
}
|
|
47019
|
+
function eventsFromTranscriptLine(line, options) {
|
|
46776
47020
|
if (line.isMeta === true || line.isSidechain === true || line.isCompactSummary === true) return [];
|
|
46777
47021
|
const at = typeof line.timestamp === "string" ? Date.parse(line.timestamp) : Number.NaN;
|
|
46778
47022
|
const atField = Number.isFinite(at) ? { at } : {};
|
|
46779
47023
|
if (line.type === "user") {
|
|
47024
|
+
const results = toolResultsFrom(line.message?.content, options);
|
|
47025
|
+
if (results.length > 0) return results;
|
|
46780
47026
|
const text2 = readUserText(line.message?.content);
|
|
46781
47027
|
return text2 ? [{ kind: "dispatch", text: text2, ...atField }] : [];
|
|
46782
47028
|
}
|
|
@@ -46789,7 +47035,17 @@ function chatEventsFromSdkMessage(message, options = {}) {
|
|
|
46789
47035
|
if (message.type === "stream_event") {
|
|
46790
47036
|
const inner = message.event;
|
|
46791
47037
|
if (!inner || typeof inner !== "object") return [];
|
|
46792
|
-
|
|
47038
|
+
const innerType = inner.type;
|
|
47039
|
+
if (innerType === "content_block_start") {
|
|
47040
|
+
const block = inner.content_block;
|
|
47041
|
+
if (!block || typeof block !== "object") return [];
|
|
47042
|
+
const start = block;
|
|
47043
|
+
if (start.type !== "tool_use") return [];
|
|
47044
|
+
if (typeof start.id !== "string" || start.id.length === 0) return [];
|
|
47045
|
+
if (typeof start.name !== "string" || start.name.length === 0) return [];
|
|
47046
|
+
return [{ kind: "tool-start", id: start.id, name: start.name }];
|
|
47047
|
+
}
|
|
47048
|
+
if (innerType !== "content_block_delta") return [];
|
|
46793
47049
|
const delta = inner.delta;
|
|
46794
47050
|
if (!delta || typeof delta !== "object") return [];
|
|
46795
47051
|
const text2 = delta;
|
|
@@ -46802,6 +47058,10 @@ function chatEventsFromSdkMessage(message, options = {}) {
|
|
|
46802
47058
|
const body = message.message;
|
|
46803
47059
|
return eventsFromAssistantContent(body?.content, options);
|
|
46804
47060
|
}
|
|
47061
|
+
if (message.type === "user") {
|
|
47062
|
+
const body = message.message;
|
|
47063
|
+
return toolResultsFrom(body?.content, options);
|
|
47064
|
+
}
|
|
46805
47065
|
if (message.type === "result") {
|
|
46806
47066
|
const durationMs = message.duration_ms;
|
|
46807
47067
|
const ok = message.is_error !== true;
|
|
@@ -46825,11 +47085,37 @@ function eventsFromAssistantContent(content, options) {
|
|
|
46825
47085
|
continue;
|
|
46826
47086
|
}
|
|
46827
47087
|
if (block.type === "tool_use" && typeof block.name === "string" && block.name.length > 0) {
|
|
46828
|
-
|
|
47088
|
+
const change = changeFromToolInput(block.name, block.input, options);
|
|
47089
|
+
events.push({
|
|
47090
|
+
kind: "tool",
|
|
47091
|
+
name: block.name,
|
|
47092
|
+
detail: summarizeToolInput(block.input, options),
|
|
47093
|
+
...typeof block.id === "string" && block.id.length > 0 ? { id: block.id } : {},
|
|
47094
|
+
...pathIsOutsideCwd(block.input, options.cwd) ? { outside: true } : {},
|
|
47095
|
+
...change ? { change } : {}
|
|
47096
|
+
});
|
|
46829
47097
|
}
|
|
46830
47098
|
}
|
|
46831
47099
|
return events;
|
|
46832
47100
|
}
|
|
47101
|
+
function toolResultsFrom(content, options) {
|
|
47102
|
+
if (!Array.isArray(content)) return [];
|
|
47103
|
+
const events = [];
|
|
47104
|
+
for (const block of content) {
|
|
47105
|
+
if (!block || typeof block !== "object" || block.type !== "tool_result") continue;
|
|
47106
|
+
if (typeof block.tool_use_id !== "string" || block.tool_use_id.length === 0) continue;
|
|
47107
|
+
const ok = block.is_error !== true;
|
|
47108
|
+
const tool = options.toolNames?.get(block.tool_use_id);
|
|
47109
|
+
const quiet = ok && tool !== void 0 && (CONTENT_RESULT_TOOLS.has(tool) || WRITE_TOOLS.has(tool));
|
|
47110
|
+
events.push({
|
|
47111
|
+
kind: "tool-result",
|
|
47112
|
+
id: block.tool_use_id,
|
|
47113
|
+
ok,
|
|
47114
|
+
summary: quiet ? "" : summarizeToolResult(block.content, options)
|
|
47115
|
+
});
|
|
47116
|
+
}
|
|
47117
|
+
return events;
|
|
47118
|
+
}
|
|
46833
47119
|
function readUserText(content) {
|
|
46834
47120
|
if (typeof content === "string") return normalizeDispatchText(content);
|
|
46835
47121
|
if (!Array.isArray(content)) return null;
|
|
@@ -46849,16 +47135,107 @@ function normalizeDispatchText(text2) {
|
|
|
46849
47135
|
function summarizeToolInput(input, options = {}) {
|
|
46850
47136
|
if (!input || typeof input !== "object" || Array.isArray(input)) return "";
|
|
46851
47137
|
const record7 = input;
|
|
46852
|
-
for (const key of ["
|
|
47138
|
+
for (const key of PATH_KEYS.concat(["command", "pattern", "url", "query", "description", "prompt", "subject"])) {
|
|
46853
47139
|
const value = record7[key];
|
|
46854
47140
|
if (typeof value === "string" && value.trim().length > 0) {
|
|
46855
47141
|
const flat = value.replace(/\s+/g, " ").trim();
|
|
46856
|
-
const shown = key
|
|
47142
|
+
const shown = PATH_KEYS.includes(key) ? displayPath(flat, options.cwd) : normalizePathTokens(flat, options.cwd);
|
|
46857
47143
|
return shown.length > MAX_TOOL_DETAIL_CHARS ? `${shown.slice(0, MAX_TOOL_DETAIL_CHARS - 1)}\u2026` : shown;
|
|
46858
47144
|
}
|
|
46859
47145
|
}
|
|
46860
47146
|
return "";
|
|
46861
47147
|
}
|
|
47148
|
+
function summarizeToolResult(content, options = {}) {
|
|
47149
|
+
const text2 = readResultText(content);
|
|
47150
|
+
if (text2 === null) return "";
|
|
47151
|
+
const first = text2.split("\n").map((line) => line.trim()).find((line) => line.length > 0);
|
|
47152
|
+
if (first === void 0) return "";
|
|
47153
|
+
const flat = normalizePathTokens(first.replace(/\s+/g, " ").trim(), options.cwd);
|
|
47154
|
+
const masked = maskSecrets(abbreviateAbsolutePaths(flat));
|
|
47155
|
+
return masked.length > MAX_TOOL_RESULT_CHARS ? `${masked.slice(0, MAX_TOOL_RESULT_CHARS - 1)}\u2026` : masked;
|
|
47156
|
+
}
|
|
47157
|
+
var QUOTED_ABSOLUTE_PATH = /(['"`])((?:[A-Za-z]:[\\/]|\\\\|\/)[^'"`\n]*)\1/g;
|
|
47158
|
+
var BARE_ABSOLUTE_PATH = /(?<![^\s'"`([{=<])(?:[A-Za-z]:[\\/]|\\\\|\/)[^\s'"`,;:()[\]<>]+/g;
|
|
47159
|
+
function abbreviateAbsolutePaths(value) {
|
|
47160
|
+
return value.replace(QUOTED_ABSOLUTE_PATH, (_match, quote, path46) => `${quote}${foldPath(path46)}${quote}`).replace(BARE_ABSOLUTE_PATH, (match) => foldPath(match));
|
|
47161
|
+
}
|
|
47162
|
+
function foldPath(path46) {
|
|
47163
|
+
const segments = path46.split(/[\\/]/).filter((segment) => segment.length > 0 && !/^[A-Za-z]:$/.test(segment));
|
|
47164
|
+
if (segments.length === 0) return path46;
|
|
47165
|
+
return `\u2026/${segments.slice(-2).join("/")}`;
|
|
47166
|
+
}
|
|
47167
|
+
function readResultText(content) {
|
|
47168
|
+
if (typeof content === "string") return content;
|
|
47169
|
+
if (!Array.isArray(content)) return null;
|
|
47170
|
+
const parts = [];
|
|
47171
|
+
for (const block of content) {
|
|
47172
|
+
if (block?.type === "text" && typeof block.text === "string") parts.push(block.text);
|
|
47173
|
+
}
|
|
47174
|
+
return parts.length > 0 ? parts.join("\n") : null;
|
|
47175
|
+
}
|
|
47176
|
+
function maskSecrets(value) {
|
|
47177
|
+
return value.replace(/\b(sk|pk|rk)-[A-Za-z0-9_-]{16,}/g, "$1-\u2026").replace(/\b(gh[pousr]|xox[baprs])_[A-Za-z0-9_-]{16,}/g, "$1_\u2026").replace(/\bAKIA[0-9A-Z]{12,}/g, "AKIA\u2026").replace(/\b(?:Bearer|Authorization:)\s+[A-Za-z0-9._~+/=-]{16,}/gi, "Bearer \u2026").replace(/\beyJ[A-Za-z0-9._-]{24,}/g, "eyJ\u2026");
|
|
47178
|
+
}
|
|
47179
|
+
function changeFromToolInput(name, input, options = {}) {
|
|
47180
|
+
if (!WRITE_TOOLS.has(name)) return null;
|
|
47181
|
+
if (!input || typeof input !== "object" || Array.isArray(input)) return null;
|
|
47182
|
+
const record7 = input;
|
|
47183
|
+
const raw = PATH_KEYS.map((key) => record7[key]).find((value) => typeof value === "string" && value.trim().length > 0) ?? null;
|
|
47184
|
+
if (raw === null) return null;
|
|
47185
|
+
const file2 = displayPath(raw.trim(), options.cwd);
|
|
47186
|
+
if (name === "Write") {
|
|
47187
|
+
return { file: file2, added: lineCount(record7.content), removed: 0 };
|
|
47188
|
+
}
|
|
47189
|
+
if (name === "Edit") {
|
|
47190
|
+
return { file: file2, added: lineCount(record7.new_string), removed: lineCount(record7.old_string) };
|
|
47191
|
+
}
|
|
47192
|
+
if (name === "MultiEdit") {
|
|
47193
|
+
let added = 0;
|
|
47194
|
+
let removed = 0;
|
|
47195
|
+
const edits = Array.isArray(record7.edits) ? record7.edits : [];
|
|
47196
|
+
for (const edit of edits) {
|
|
47197
|
+
if (!edit || typeof edit !== "object") continue;
|
|
47198
|
+
const entry = edit;
|
|
47199
|
+
added += lineCount(entry.new_string);
|
|
47200
|
+
removed += lineCount(entry.old_string);
|
|
47201
|
+
}
|
|
47202
|
+
return { file: file2, added, removed };
|
|
47203
|
+
}
|
|
47204
|
+
return { file: file2, added: 0, removed: 0 };
|
|
47205
|
+
}
|
|
47206
|
+
function lineCount(value) {
|
|
47207
|
+
if (typeof value !== "string" || value.length === 0) return 0;
|
|
47208
|
+
return value.replace(/\n$/, "").split("\n").length;
|
|
47209
|
+
}
|
|
47210
|
+
function pathIsOutsideCwd(input, cwd) {
|
|
47211
|
+
if (!cwd || !input || typeof input !== "object" || Array.isArray(input)) return false;
|
|
47212
|
+
const record7 = input;
|
|
47213
|
+
for (const key of PATH_KEYS) {
|
|
47214
|
+
const value = record7[key];
|
|
47215
|
+
if (typeof value !== "string" || value.trim().length === 0) continue;
|
|
47216
|
+
const normalized = resolveDotSegments(value.trim().replace(/\\/g, "/"));
|
|
47217
|
+
if (!normalized.startsWith("/") && !/^[A-Za-z]:\//.test(normalized)) return false;
|
|
47218
|
+
const root = resolveDotSegments(cwd.replace(/\\/g, "/")).replace(/\/+$/, "");
|
|
47219
|
+
if (root.length <= 1) return false;
|
|
47220
|
+
return normalized !== root && !normalized.startsWith(`${root}/`);
|
|
47221
|
+
}
|
|
47222
|
+
return false;
|
|
47223
|
+
}
|
|
47224
|
+
function resolveDotSegments(path46) {
|
|
47225
|
+
if (!path46.includes("./") && !path46.endsWith("/.") && !path46.endsWith("/..")) return path46;
|
|
47226
|
+
const parts = path46.split("/");
|
|
47227
|
+
const out = [];
|
|
47228
|
+
for (const part of parts) {
|
|
47229
|
+
if (part === ".") continue;
|
|
47230
|
+
if (part === "..") {
|
|
47231
|
+
if (out.length > 1 || out.length === 1 && out[0] !== "") out.pop();
|
|
47232
|
+
continue;
|
|
47233
|
+
}
|
|
47234
|
+
out.push(part);
|
|
47235
|
+
}
|
|
47236
|
+
const joined = out.join("/");
|
|
47237
|
+
return joined.length > 0 ? joined : "/";
|
|
47238
|
+
}
|
|
46862
47239
|
function normalizePathTokens(value, cwd) {
|
|
46863
47240
|
let result = value;
|
|
46864
47241
|
if (cwd) {
|
|
@@ -46870,10 +47247,10 @@ function normalizePathTokens(value, cwd) {
|
|
|
46870
47247
|
return result;
|
|
46871
47248
|
}
|
|
46872
47249
|
function displayPath(value, cwd) {
|
|
46873
|
-
const normalized = value.replace(/\\/g, "/");
|
|
47250
|
+
const normalized = resolveDotSegments(value.replace(/\\/g, "/"));
|
|
46874
47251
|
if (!normalized.startsWith("/") && !/^[A-Za-z]:\//.test(normalized)) return value;
|
|
46875
47252
|
if (cwd) {
|
|
46876
|
-
const root = cwd.replace(/\\/g, "/").replace(/\/+$/, "");
|
|
47253
|
+
const root = resolveDotSegments(cwd.replace(/\\/g, "/")).replace(/\/+$/, "");
|
|
46877
47254
|
if (normalized === root) return ".";
|
|
46878
47255
|
if (normalized.startsWith(`${root}/`)) return normalized.slice(root.length + 1);
|
|
46879
47256
|
}
|
|
@@ -46886,13 +47263,17 @@ function capText(text2) {
|
|
|
46886
47263
|
|
|
46887
47264
|
// ../fleet-plugins/terminal/server/agent-api/chat-session.ts
|
|
46888
47265
|
var JOURNAL_CAP = 2e3;
|
|
47266
|
+
var TOOL_NAME_CAP = 500;
|
|
46889
47267
|
var AgentChatSession = class {
|
|
46890
47268
|
operationId;
|
|
46891
47269
|
seed;
|
|
46892
47270
|
createSdk;
|
|
46893
47271
|
sdk = null;
|
|
46894
47272
|
sdkFlight = null;
|
|
46895
|
-
/**
|
|
47273
|
+
/**
|
|
47274
|
+
* resume 좌표는 트랜스크립트 파일명이 말하는 세션 id다 — 캡처 id는 드리프트할 수 있다.
|
|
47275
|
+
* `fresh`는 아직 세션이 없으므로 null로 출발하고, 첫 SDK 메시지의 session_id가 이 자리를 채운다.
|
|
47276
|
+
*/
|
|
46896
47277
|
latestSessionId;
|
|
46897
47278
|
journal = [];
|
|
46898
47279
|
seq = 0;
|
|
@@ -46900,27 +47281,52 @@ var AgentChatSession = class {
|
|
|
46900
47281
|
turnFlight = Promise.resolve();
|
|
46901
47282
|
pendingTurns = 0;
|
|
46902
47283
|
disposed = false;
|
|
47284
|
+
/**
|
|
47285
|
+
* tool_use id → 도구 이름. 결과 블록은 자기가 어떤 도구의 결말인지 모르는데, 무엇을 요약해도
|
|
47286
|
+
* 되는지는 도구가 정한다(읽기·쓰기 계열의 성공 결과는 내용이라 싣지 않는다). 긴 세션에서
|
|
47287
|
+
* 무한히 자라지 않게 상한을 두고 오래된 것부터 버린다 — 결과는 호출 직후에 오므로 잃을 게 없다.
|
|
47288
|
+
*/
|
|
47289
|
+
toolNames = /* @__PURE__ */ new Map();
|
|
46903
47290
|
constructor(operationId, seed, createSdk) {
|
|
46904
47291
|
this.operationId = operationId;
|
|
46905
47292
|
this.seed = seed;
|
|
46906
47293
|
this.createSdk = createSdk;
|
|
46907
|
-
this.latestSessionId = path19__default.basename(seed.transcriptPath, ".jsonl");
|
|
47294
|
+
this.latestSessionId = seed.origin.kind === "resume" ? path19__default.basename(seed.origin.transcriptPath, ".jsonl") : null;
|
|
46908
47295
|
}
|
|
46909
47296
|
get busy() {
|
|
46910
47297
|
return this.pendingTurns > 0;
|
|
46911
47298
|
}
|
|
46912
47299
|
async replayTranscript() {
|
|
47300
|
+
if (this.seed.origin.kind === "fresh") return;
|
|
47301
|
+
const transcriptPath = this.seed.origin.transcriptPath;
|
|
46913
47302
|
this.push({ kind: "replay-start" });
|
|
46914
47303
|
let turns = 0;
|
|
47304
|
+
let turnAt = null;
|
|
47305
|
+
let lastAt = null;
|
|
47306
|
+
const closeReplayedTurn = () => {
|
|
47307
|
+
if (turnAt !== null && lastAt !== null && lastAt > turnAt) {
|
|
47308
|
+
this.push({ kind: "turn-end", ok: true, durationMs: lastAt - turnAt });
|
|
47309
|
+
}
|
|
47310
|
+
turnAt = null;
|
|
47311
|
+
lastAt = null;
|
|
47312
|
+
};
|
|
46915
47313
|
try {
|
|
46916
|
-
const raw = await promises.readFile(
|
|
47314
|
+
const raw = await promises.readFile(transcriptPath, "utf8");
|
|
46917
47315
|
for (const line of raw.split("\n")) {
|
|
46918
47316
|
if (line.trim().length === 0) continue;
|
|
46919
|
-
|
|
46920
|
-
|
|
47317
|
+
const mapped = chatReplayFromTranscriptLine(line, { cwd: this.seed.cwd, toolNames: this.toolNames });
|
|
47318
|
+
for (const event of mapped.events) {
|
|
47319
|
+
if (event.kind === "dispatch") {
|
|
47320
|
+
closeReplayedTurn();
|
|
47321
|
+
turns += 1;
|
|
47322
|
+
turnAt = mapped.at ?? null;
|
|
47323
|
+
}
|
|
47324
|
+
this.rememberTool(event);
|
|
46921
47325
|
this.push(event);
|
|
46922
47326
|
}
|
|
47327
|
+
if (mapped.events.length > 0 && mapped.at !== void 0) lastAt = mapped.at;
|
|
46923
47328
|
}
|
|
47329
|
+
closeReplayedTurn();
|
|
46924
47330
|
} catch {
|
|
46925
47331
|
this.push({ kind: "error", code: "chat_replay_unavailable" });
|
|
46926
47332
|
}
|
|
@@ -46938,6 +47344,13 @@ var AgentChatSession = class {
|
|
|
46938
47344
|
* 턴을 직렬화해 실행한다. 반환은 큐 등록 시점이다 — 진행·실패는 저널 이벤트로 전달된다.
|
|
46939
47345
|
* 실패한 턴은 반드시 run.close()로 슬롯을 반납한다(스파이크에서 실증한 함정).
|
|
46940
47346
|
*/
|
|
47347
|
+
/**
|
|
47348
|
+
* 활동축이 이 세션의 턴을 받을 수 있는지 미리 확인한다. 큐에 넣은 뒤에는 HTTP 응답이 이미
|
|
47349
|
+
* 떠났으므로, 거절은 요청 경계에서만 시끄러울 수 있다.
|
|
47350
|
+
*/
|
|
47351
|
+
canReportActivity() {
|
|
47352
|
+
return this.seed.canReportActivity();
|
|
47353
|
+
}
|
|
46941
47354
|
send(text2) {
|
|
46942
47355
|
if (this.disposed) return;
|
|
46943
47356
|
this.pendingTurns += 1;
|
|
@@ -46954,6 +47367,16 @@ var AgentChatSession = class {
|
|
|
46954
47367
|
await this.turnFlight.catch(() => void 0);
|
|
46955
47368
|
this.listeners.clear();
|
|
46956
47369
|
}
|
|
47370
|
+
/** 도구 이벤트가 지나갈 때 id→이름을 적어 둔다. 결과 요약 정책이 이 축 위에서 결정된다. */
|
|
47371
|
+
rememberTool(event) {
|
|
47372
|
+
if (event.kind !== "tool" && event.kind !== "tool-start") return;
|
|
47373
|
+
if (event.id === void 0) return;
|
|
47374
|
+
this.toolNames.set(event.id, event.name);
|
|
47375
|
+
if (this.toolNames.size > TOOL_NAME_CAP) {
|
|
47376
|
+
const oldest = this.toolNames.keys().next();
|
|
47377
|
+
if (!oldest.done) this.toolNames.delete(oldest.value);
|
|
47378
|
+
}
|
|
47379
|
+
}
|
|
46957
47380
|
push(event) {
|
|
46958
47381
|
const entry = { seq: ++this.seq, event };
|
|
46959
47382
|
this.journal.push(entry);
|
|
@@ -46995,18 +47418,24 @@ var AgentChatSession = class {
|
|
|
46995
47418
|
/**
|
|
46996
47419
|
* 원 트랜스크립트를 격리 config dir의 같은 projects/<인코딩된 cwd>/ 아래로 복사한다.
|
|
46997
47420
|
* 인코딩 규칙을 재구현하지 않는다 — 원 경로의 부모 디렉터리 이름이 곧 그 인코딩이다.
|
|
47421
|
+
* 채팅으로 태어난 세션에는 복사할 원본이 없다 — SDK가 자기 dir 안에 스스로 만든다.
|
|
46998
47422
|
*/
|
|
46999
47423
|
async copyTranscriptIntoConfigDir(configDir) {
|
|
47000
|
-
|
|
47424
|
+
if (this.seed.origin.kind === "fresh") return;
|
|
47425
|
+
const projectDirName = path19__default.basename(path19__default.dirname(this.seed.origin.transcriptPath));
|
|
47001
47426
|
const dest = path19__default.join(configDir, "projects", projectDirName, `${this.latestSessionId}.jsonl`);
|
|
47002
47427
|
await promises.mkdir(path19__default.dirname(dest), { recursive: true, mode: 448 });
|
|
47003
|
-
await promises.copyFile(this.seed.transcriptPath, dest);
|
|
47428
|
+
await promises.copyFile(this.seed.origin.transcriptPath, dest);
|
|
47004
47429
|
}
|
|
47005
47430
|
async runTurn(text2) {
|
|
47006
47431
|
if (this.disposed) return;
|
|
47007
47432
|
this.push({ kind: "dispatch", text: text2, at: Date.now() });
|
|
47008
47433
|
this.push({ kind: "turn-start", at: Date.now() });
|
|
47009
|
-
this.
|
|
47434
|
+
if (!this.seed.reportActivity(true)) {
|
|
47435
|
+
this.push({ kind: "error", code: "chat_activity_unavailable" });
|
|
47436
|
+
this.push({ kind: "turn-end", ok: false });
|
|
47437
|
+
return;
|
|
47438
|
+
}
|
|
47010
47439
|
let sawResult = false;
|
|
47011
47440
|
try {
|
|
47012
47441
|
const sdk = await this.ensureSdk();
|
|
@@ -47015,7 +47444,9 @@ var AgentChatSession = class {
|
|
|
47015
47444
|
model: this.seed.model,
|
|
47016
47445
|
...this.seed.effort ? { effort: this.seed.effort } : {},
|
|
47017
47446
|
cwd: this.seed.cwd,
|
|
47018
|
-
resume
|
|
47447
|
+
// 채팅으로 태어난 세션의 첫 턴에는 이어붙일 좌표가 없다 — resume 없이 시작하고,
|
|
47448
|
+
// SDK가 돌려주는 session_id가 그 자리를 채운다(그다음 턴부터는 resume이 선다).
|
|
47449
|
+
...this.latestSessionId ? { resume: this.latestSessionId } : {},
|
|
47019
47450
|
permissionMode: "bypassPermissions",
|
|
47020
47451
|
// 스트리밍 감각의 근거 — 글자 단위 text_delta를 받으려면 부분 메시지가 필요하다.
|
|
47021
47452
|
includePartialMessages: true
|
|
@@ -47025,9 +47456,10 @@ var AgentChatSession = class {
|
|
|
47025
47456
|
if (typeof message.session_id === "string" && message.session_id.length > 0) {
|
|
47026
47457
|
this.latestSessionId = message.session_id;
|
|
47027
47458
|
}
|
|
47028
|
-
for (const event of chatEventsFromSdkMessage(message, { cwd: this.seed.cwd })) {
|
|
47459
|
+
for (const event of chatEventsFromSdkMessage(message, { cwd: this.seed.cwd, toolNames: this.toolNames })) {
|
|
47029
47460
|
if (event.kind === "turn-end") sawResult = true;
|
|
47030
|
-
|
|
47461
|
+
this.rememberTool(event);
|
|
47462
|
+
if (event.kind === "text-delta" || event.kind === "tool-start") this.pushEphemeral(event);
|
|
47031
47463
|
else this.push(event);
|
|
47032
47464
|
}
|
|
47033
47465
|
}
|
|
@@ -47040,7 +47472,7 @@ var AgentChatSession = class {
|
|
|
47040
47472
|
this.push({ kind: "error", code: "chat_turn_failed" });
|
|
47041
47473
|
if (!sawResult) this.push({ kind: "turn-end", ok: false });
|
|
47042
47474
|
} finally {
|
|
47043
|
-
this.
|
|
47475
|
+
this.seed.reportActivity(false);
|
|
47044
47476
|
}
|
|
47045
47477
|
}
|
|
47046
47478
|
/**
|
|
@@ -47049,15 +47481,19 @@ var AgentChatSession = class {
|
|
|
47049
47481
|
*/
|
|
47050
47482
|
async writeBackTranscript() {
|
|
47051
47483
|
const sdk = this.sdk;
|
|
47052
|
-
if (!sdk) return;
|
|
47053
|
-
const
|
|
47054
|
-
const
|
|
47484
|
+
if (!sdk || !this.latestSessionId) return;
|
|
47485
|
+
const sessionId = this.latestSessionId;
|
|
47486
|
+
const projectDirName = await this.resolveProjectDirName(sdk.configDir);
|
|
47487
|
+
if (!projectDirName) return;
|
|
47488
|
+
const source = path19__default.join(sdk.configDir, "projects", projectDirName, `${sessionId}.jsonl`);
|
|
47055
47489
|
const sourceStat = await promises.stat(source).catch(() => null);
|
|
47056
47490
|
if (!sourceStat?.isFile()) return;
|
|
47057
|
-
const
|
|
47491
|
+
const destDir = this.seed.origin.kind === "resume" ? path19__default.dirname(this.seed.origin.transcriptPath) : path19__default.join(this.seed.origin.transcriptRoot, projectDirName);
|
|
47492
|
+
const dest = path19__default.join(destDir, `${sessionId}.jsonl`);
|
|
47058
47493
|
const destStat = await promises.stat(dest).catch(() => null);
|
|
47059
47494
|
if (destStat?.isFile() && destStat.size > sourceStat.size) return;
|
|
47060
47495
|
try {
|
|
47496
|
+
if (this.seed.origin.kind === "fresh") await promises.mkdir(destDir, { recursive: true, mode: 448 });
|
|
47061
47497
|
await promises.copyFile(source, dest);
|
|
47062
47498
|
} catch {
|
|
47063
47499
|
this.push({ kind: "error", code: "chat_writeback_failed" });
|
|
@@ -47065,12 +47501,25 @@ var AgentChatSession = class {
|
|
|
47065
47501
|
}
|
|
47066
47502
|
this.seed.onProviderSessionUpdate({
|
|
47067
47503
|
provider: "claude",
|
|
47068
|
-
sessionId
|
|
47504
|
+
sessionId,
|
|
47069
47505
|
transcriptPath: dest,
|
|
47070
47506
|
source: "chat-mode",
|
|
47071
47507
|
capturedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
47072
47508
|
});
|
|
47073
47509
|
}
|
|
47510
|
+
/**
|
|
47511
|
+
* 이 세션의 트랜스크립트가 앉은 projects 디렉터리 이름. resume은 원 경로가 이미 말해 주고,
|
|
47512
|
+
* fresh는 SDK가 자기 dir 안에 만든 이름을 읽는다 — cwd 인코딩 규칙을 재구현하지 않기 위해서다.
|
|
47513
|
+
* 격리 dir은 이 세션 전용이라 그 아래 projects 항목은 하나뿐이며, 여럿이면 무엇이 우리 것인지
|
|
47514
|
+
* 말할 수 없으므로 되쓰지 않는다(잘못된 뿌리에 남의 세션을 심는 것보다 낫다).
|
|
47515
|
+
*/
|
|
47516
|
+
async resolveProjectDirName(configDir) {
|
|
47517
|
+
if (this.seed.origin.kind === "resume") return path19__default.basename(path19__default.dirname(this.seed.origin.transcriptPath));
|
|
47518
|
+
const entries = await promises.readdir(path19__default.join(configDir, "projects"), { withFileTypes: true }).catch(() => null);
|
|
47519
|
+
if (!entries) return null;
|
|
47520
|
+
const dirs = entries.filter((entry) => entry.isDirectory());
|
|
47521
|
+
return dirs.length === 1 ? dirs[0]?.name ?? null : null;
|
|
47522
|
+
}
|
|
47074
47523
|
};
|
|
47075
47524
|
var AgentChatRegistry = class {
|
|
47076
47525
|
sessions = /* @__PURE__ */ new Map();
|
|
@@ -47300,6 +47749,15 @@ function registerTerminalSettingsRoutes(ctx, deps) {
|
|
|
47300
47749
|
));
|
|
47301
47750
|
return true;
|
|
47302
47751
|
}
|
|
47752
|
+
if ("compactCeiling" in update) {
|
|
47753
|
+
const stored = deps.aiGatewayStore.writeCompactCeiling(update.compactCeiling);
|
|
47754
|
+
ctx.host.http.writeJson(res, 200, toTerminalSettingsState(
|
|
47755
|
+
deps.globalOptionsService.load(),
|
|
47756
|
+
stored,
|
|
47757
|
+
deps.wireLogRuntime.enabled()
|
|
47758
|
+
));
|
|
47759
|
+
return true;
|
|
47760
|
+
}
|
|
47303
47761
|
const updated = deps.globalOptionsService.update((current) => ({ ...current, ...update }));
|
|
47304
47762
|
ctx.host.http.writeJson(res, 200, toTerminalSettingsState(
|
|
47305
47763
|
updated,
|
|
@@ -47326,7 +47784,8 @@ function toTerminalSettingsState(data, aiGateway, wireLogEnabled2) {
|
|
|
47326
47784
|
} : null,
|
|
47327
47785
|
aiGatewayCatalog: buildAiGatewayCatalog(),
|
|
47328
47786
|
cursorDiagnosticsEnabled: aiGateway.cursorDiagnosticsEnabled === true,
|
|
47329
|
-
wireLogEnabled: wireLogEnabled2
|
|
47787
|
+
wireLogEnabled: wireLogEnabled2,
|
|
47788
|
+
compactCeiling: aiGateway.compactCeiling ?? null
|
|
47330
47789
|
};
|
|
47331
47790
|
}
|
|
47332
47791
|
function resolveAgentIdleDormantMinutes(data) {
|
|
@@ -47353,6 +47812,11 @@ function parseTerminalSettingsBody(value) {
|
|
|
47353
47812
|
if (keys[0] === "wireLogEnabled") {
|
|
47354
47813
|
return typeof body.wireLogEnabled === "boolean" ? { wireLogEnabled: body.wireLogEnabled } : null;
|
|
47355
47814
|
}
|
|
47815
|
+
if (keys[0] === "compactCeiling") {
|
|
47816
|
+
if (body.compactCeiling === null) return { compactCeiling: void 0 };
|
|
47817
|
+
const ceiling = normalizeCompactCeiling(body.compactCeiling);
|
|
47818
|
+
return ceiling === void 0 ? null : { compactCeiling: ceiling };
|
|
47819
|
+
}
|
|
47356
47820
|
return null;
|
|
47357
47821
|
}
|
|
47358
47822
|
function isAgentIdleDormantMinutes(value) {
|
|
@@ -47407,7 +47871,13 @@ var OPERATION_DELETED_EVENT_CHANNEL = "operation:deleted";
|
|
|
47407
47871
|
var OPERATION_PURGED_EVENT_CHANNEL = "operation:purged";
|
|
47408
47872
|
var TERMINAL_PLUGIN_ID = "terminal";
|
|
47409
47873
|
var CHAT_MODE_PAYLOAD_KEY = "chatMode";
|
|
47874
|
+
var CHAT_BORN_PAYLOAD_KEY = "chatBorn";
|
|
47410
47875
|
var CHAT_SUPPORTED_CLI_ID = "claude-gateway";
|
|
47876
|
+
function resolveClaudeProjectsRoot() {
|
|
47877
|
+
const configured = process4.env.CLAUDE_CONFIG_DIR;
|
|
47878
|
+
const configDir = configured && configured.length > 0 ? configured : path19__default.join(os3__default.homedir(), ".claude");
|
|
47879
|
+
return path19__default.join(configDir, "projects");
|
|
47880
|
+
}
|
|
47411
47881
|
async function registerAgentRoutes(ctx, terminalRuntime, deps) {
|
|
47412
47882
|
const api = await createAgentApi(ctx, terminalRuntime, deps);
|
|
47413
47883
|
terminalRuntime.registerLaunchResolver(AGENT_OPERATION_TYPE, api.launch);
|
|
@@ -47450,7 +47920,10 @@ function buildAgentLaunchKindBackfillPatch(operation) {
|
|
|
47450
47920
|
function buildAgentLaunchProviderBackfillPatch(operation) {
|
|
47451
47921
|
if (operation.pluginId !== TERMINAL_PLUGIN_ID || operation.type !== AGENT_OPERATION_TYPE) return null;
|
|
47452
47922
|
if (isAgentLaunchProvider(operation.payload[AGENT_LAUNCH_PROVIDER_PAYLOAD_KEY])) return null;
|
|
47453
|
-
|
|
47923
|
+
const cliId = typeof operation.payload.cliId === "string" ? operation.payload.cliId : void 0;
|
|
47924
|
+
const provider = agentLaunchProviderFromCliId(cliId);
|
|
47925
|
+
if (!provider) return null;
|
|
47926
|
+
return { payload: { ...operation.payload, [AGENT_LAUNCH_PROVIDER_PAYLOAD_KEY]: provider } };
|
|
47454
47927
|
}
|
|
47455
47928
|
function buildGatewayLoadoutTools(deps) {
|
|
47456
47929
|
const readAiGatewaySettings = deps.readAiGatewaySettings;
|
|
@@ -47713,6 +48186,15 @@ async function createAgentApi(ctx, terminalRuntime, deps) {
|
|
|
47713
48186
|
const prompt = typeof body?.prompt === "string" ? sanitizeLaunchPrompt(body.prompt) : void 0;
|
|
47714
48187
|
const attachmentIds = readAttachmentIds(body?.attachmentIds, res);
|
|
47715
48188
|
if (attachmentIds === false) return true;
|
|
48189
|
+
if (body?.viewMode !== void 0 && body.viewMode !== "terminal" && body.viewMode !== "chat") {
|
|
48190
|
+
ctx.host.http.writeJson(res, 400, { error: "invalid_view_mode" });
|
|
48191
|
+
return true;
|
|
48192
|
+
}
|
|
48193
|
+
const chatBorn = body?.viewMode === "chat";
|
|
48194
|
+
if (chatBorn && cliId !== CHAT_SUPPORTED_CLI_ID) {
|
|
48195
|
+
ctx.host.http.writeJson(res, 409, { error: "chat_unsupported" });
|
|
48196
|
+
return true;
|
|
48197
|
+
}
|
|
47716
48198
|
const cwd = ctx.host.paths.resolveTheaterPath(theaterId);
|
|
47717
48199
|
if (!cwd) {
|
|
47718
48200
|
ctx.host.http.writeJson(res, 404, { error: "theater_not_found" });
|
|
@@ -47732,7 +48214,8 @@ async function createAgentApi(ctx, terminalRuntime, deps) {
|
|
|
47732
48214
|
await createSession(cwd, theaterId, cliId, res, {
|
|
47733
48215
|
...launchOptions,
|
|
47734
48216
|
...composedPrompt ? { prompt: composedPrompt } : {},
|
|
47735
|
-
...attachmentIds.length > 0 ? { attachmentIds } : {}
|
|
48217
|
+
...attachmentIds.length > 0 ? { attachmentIds } : {},
|
|
48218
|
+
...chatBorn ? { chatBorn: true } : {}
|
|
47736
48219
|
});
|
|
47737
48220
|
} catch (error51) {
|
|
47738
48221
|
if (attachmentIds.length > 0) launchAttachments.unreserve(attachmentIds);
|
|
@@ -47805,13 +48288,44 @@ async function createAgentApi(ctx, terminalRuntime, deps) {
|
|
|
47805
48288
|
}
|
|
47806
48289
|
return methodNotAllowed2(res);
|
|
47807
48290
|
}
|
|
48291
|
+
async function startChatBornSession(sessionId, res, launchOptions) {
|
|
48292
|
+
const rollback = (status, error51) => {
|
|
48293
|
+
if (launchOptions.attachmentIds && launchOptions.attachmentIds.length > 0) {
|
|
48294
|
+
launchAttachments.unreserve(launchOptions.attachmentIds);
|
|
48295
|
+
}
|
|
48296
|
+
ctx.host.operations.delete(sessionId);
|
|
48297
|
+
observability.removeTerminalSession(sessionId);
|
|
48298
|
+
ctx.host.http.writeJson(res, status, { error: error51 });
|
|
48299
|
+
};
|
|
48300
|
+
const node = ctx.host.operations.get(sessionId);
|
|
48301
|
+
if (!node) return rollback(500, "session_not_found");
|
|
48302
|
+
observability.updateTerminalSessionStatus(sessionId, "dormant");
|
|
48303
|
+
const activated = observability.setTerminalSessionChatActive(sessionId, true);
|
|
48304
|
+
if (activated) observability.notifySessionUpdated(activated);
|
|
48305
|
+
const seed = await resolveChatSeed(node);
|
|
48306
|
+
if (!seed.ok) return rollback(seed.status, seed.error);
|
|
48307
|
+
let chat;
|
|
48308
|
+
try {
|
|
48309
|
+
chat = await chatRegistry.ensure(sessionId, () => seed.seed);
|
|
48310
|
+
} catch {
|
|
48311
|
+
return rollback(503, "chat_unavailable");
|
|
48312
|
+
}
|
|
48313
|
+
if (launchOptions.prompt) chat.send(launchOptions.prompt);
|
|
48314
|
+
if (launchOptions.attachmentIds && launchOptions.attachmentIds.length > 0) {
|
|
48315
|
+
launchAttachments.bind(sessionId, launchOptions.attachmentIds);
|
|
48316
|
+
if (!ctx.host.operations.get(sessionId)) launchAttachments.releaseSession(sessionId);
|
|
48317
|
+
}
|
|
48318
|
+
const created = observability.getTerminalSessionInfo(sessionId);
|
|
48319
|
+
if (created) observability.notifySessionUpdated(created);
|
|
48320
|
+
ctx.host.http.writeJson(res, 200, created ?? { sessionId });
|
|
48321
|
+
}
|
|
47808
48322
|
async function createSession(cwd, theaterId, cliId, res, launchOptions = {}) {
|
|
47809
48323
|
const meta3 = (await buildAgentCliLaunchMetadata()).find((entry) => entry.id === cliId);
|
|
47810
48324
|
if (!meta3 || !meta3.available || !meta3.signedIn) {
|
|
47811
48325
|
if (launchOptions.attachmentIds && launchOptions.attachmentIds.length > 0) {
|
|
47812
48326
|
launchAttachments.unreserve(launchOptions.attachmentIds);
|
|
47813
48327
|
}
|
|
47814
|
-
ctx.host.http.writeJson(res, 409, { error: "
|
|
48328
|
+
ctx.host.http.writeJson(res, 409, { error: meta3 && !meta3.available ? "agent_cli_not_installed" : "agent_cli_signed_out" });
|
|
47815
48329
|
return;
|
|
47816
48330
|
}
|
|
47817
48331
|
const sessionId = crypto5.randomUUID();
|
|
@@ -47832,10 +48346,17 @@ async function createAgentApi(ctx, terminalRuntime, deps) {
|
|
|
47832
48346
|
// Claude Code의 resume가 launch 좌표를 자체 복원한다고 가정하지 않는다 — 정규화된
|
|
47833
48347
|
// 최초 선택을 Operation에 남겨 dormant·Console 재시작 뒤에도 같은 인자로 재개한다.
|
|
47834
48348
|
...launchOptions.model ? { launchModel: launchOptions.model } : {},
|
|
47835
|
-
...launchOptions.effort ? { launchEffort: launchOptions.effort } : {}
|
|
48349
|
+
...launchOptions.effort ? { launchEffort: launchOptions.effort } : {},
|
|
48350
|
+
// 채팅으로 태어난 Operation은 두 마커를 함께 진다. chatMode가 뷰를 가르고, chatBorn이
|
|
48351
|
+
// "transcript 부재는 상실이 아니라 아직 첫 턴 전"이라는 뜻을 durable하게 남긴다.
|
|
48352
|
+
...launchOptions.chatBorn ? { [CHAT_MODE_PAYLOAD_KEY]: true, [CHAT_BORN_PAYLOAD_KEY]: true } : {}
|
|
47836
48353
|
},
|
|
47837
48354
|
createdAt: session.createdAt
|
|
47838
48355
|
});
|
|
48356
|
+
if (launchOptions.chatBorn) {
|
|
48357
|
+
await startChatBornSession(sessionId, res, launchOptions);
|
|
48358
|
+
return;
|
|
48359
|
+
}
|
|
47839
48360
|
try {
|
|
47840
48361
|
await terminalRuntime.attach({
|
|
47841
48362
|
cwd,
|
|
@@ -47880,7 +48401,7 @@ async function createAgentApi(ctx, terminalRuntime, deps) {
|
|
|
47880
48401
|
}
|
|
47881
48402
|
pendingRuntimeSessions.delete(sessionId);
|
|
47882
48403
|
observability.updateTerminalSessionStatus(sessionId, "error");
|
|
47883
|
-
ctx.host.http.writeJson(res, 503, { error:
|
|
48404
|
+
ctx.host.http.writeJson(res, 503, { error: classifyLaunchSpawnFailure(error51) });
|
|
47884
48405
|
}
|
|
47885
48406
|
}
|
|
47886
48407
|
async function handleResume(req, res, sessionId) {
|
|
@@ -47911,6 +48432,8 @@ async function createAgentApi(ctx, terminalRuntime, deps) {
|
|
|
47911
48432
|
const cleared = { ...ctx.host.operations.get(sessionId)?.payload ?? node.payload };
|
|
47912
48433
|
delete cleared[CHAT_MODE_PAYLOAD_KEY];
|
|
47913
48434
|
ctx.host.operations.patch(sessionId, { payload: cleared });
|
|
48435
|
+
const releasedOnResume = observability.setTerminalSessionChatActive(sessionId, false);
|
|
48436
|
+
if (releasedOnResume) observability.notifySessionUpdated(releasedOnResume);
|
|
47914
48437
|
resumeNode = ctx.host.operations.get(sessionId) ?? node;
|
|
47915
48438
|
if (!fresh) resumeProviderSession = readProviderSession(resumeNode.payload) ?? providerSession;
|
|
47916
48439
|
}
|
|
@@ -48038,6 +48561,11 @@ async function createAgentApi(ctx, terminalRuntime, deps) {
|
|
|
48038
48561
|
}
|
|
48039
48562
|
try {
|
|
48040
48563
|
const chat = await chatRegistry.ensure(sessionId, () => seed.seed);
|
|
48564
|
+
if (!chat.canReportActivity()) {
|
|
48565
|
+
settleAttachments(false);
|
|
48566
|
+
ctx.host.http.writeJson(res, 503, { error: "chat_activity_unavailable" });
|
|
48567
|
+
return true;
|
|
48568
|
+
}
|
|
48041
48569
|
chat.send(composeLaunchPromptWithAttachments(text2.trim(), attachmentPaths));
|
|
48042
48570
|
} catch {
|
|
48043
48571
|
settleAttachments(false);
|
|
@@ -48115,6 +48643,8 @@ async function createAgentApi(ctx, terminalRuntime, deps) {
|
|
|
48115
48643
|
const cleared = { ...ctx.host.operations.get(sessionId)?.payload ?? node.payload };
|
|
48116
48644
|
delete cleared[CHAT_MODE_PAYLOAD_KEY];
|
|
48117
48645
|
ctx.host.operations.patch(sessionId, { payload: cleared });
|
|
48646
|
+
const released = observability.setTerminalSessionChatActive(sessionId, false);
|
|
48647
|
+
if (released) observability.notifySessionUpdated(released);
|
|
48118
48648
|
ctx.host.http.writeJson(res, 200, { ok: true });
|
|
48119
48649
|
return true;
|
|
48120
48650
|
}
|
|
@@ -48140,6 +48670,8 @@ async function createAgentApi(ctx, terminalRuntime, deps) {
|
|
|
48140
48670
|
}
|
|
48141
48671
|
}
|
|
48142
48672
|
ctx.host.operations.patch(sessionId, { payload: { ...node.payload, [CHAT_MODE_PAYLOAD_KEY]: true } });
|
|
48673
|
+
const activated = observability.setTerminalSessionChatActive(sessionId, true);
|
|
48674
|
+
if (activated) observability.notifySessionUpdated(activated);
|
|
48143
48675
|
if (live) {
|
|
48144
48676
|
terminalRuntime.invalidateTicketsForSession(sessionId);
|
|
48145
48677
|
terminalRuntime.terminate(sessionId);
|
|
@@ -48215,9 +48747,11 @@ async function createAgentApi(ctx, terminalRuntime, deps) {
|
|
|
48215
48747
|
return { ok: false, status: 409, error: "chat_unsupported" };
|
|
48216
48748
|
}
|
|
48217
48749
|
const providerSession = readProviderSession(node.payload);
|
|
48218
|
-
|
|
48219
|
-
const
|
|
48220
|
-
|
|
48750
|
+
const transcriptPath = providerSession?.transcriptPath ? await resolveTranscriptPath(providerSession.transcriptPath, node.ts.createdAt) : null;
|
|
48751
|
+
const chatBorn = node.payload[CHAT_BORN_PAYLOAD_KEY] === true;
|
|
48752
|
+
const neverStarted = chatBorn && !providerSession;
|
|
48753
|
+
if (!transcriptPath && !neverStarted) return { ok: false, status: 409, error: "chat_transcript_missing" };
|
|
48754
|
+
const sessionOrigin = transcriptPath ? { kind: "resume", transcriptPath } : { kind: "fresh", transcriptRoot: resolveClaudeProjectsRoot() };
|
|
48221
48755
|
const origin = ctx.host.server.origin();
|
|
48222
48756
|
if (!origin) return { ok: false, status: 503, error: "chat_gateway_unavailable" };
|
|
48223
48757
|
const cwd = readPayloadString(node.payload, "cwd") || ctx.host.paths.resolveTheaterPath(node.theaterId);
|
|
@@ -48231,11 +48765,18 @@ async function createAgentApi(ctx, terminalRuntime, deps) {
|
|
|
48231
48765
|
model,
|
|
48232
48766
|
...effort ? { effort } : {},
|
|
48233
48767
|
cwd,
|
|
48234
|
-
|
|
48768
|
+
origin: sessionOrigin,
|
|
48235
48769
|
onProviderSessionUpdate: (updated) => {
|
|
48236
48770
|
const operation = ctx.host.operations.get(node.id);
|
|
48237
48771
|
if (operation) ctx.host.operations.patch(node.id, { payload: { ...operation.payload, providerSession: updated } });
|
|
48238
48772
|
observability.updateTerminalSessionProviderSession(node.id, updated);
|
|
48773
|
+
},
|
|
48774
|
+
canReportActivity: () => observability.getTerminalSessionInfo(node.id)?.chatActive === true,
|
|
48775
|
+
reportActivity: (working) => {
|
|
48776
|
+
const updated = observability.setTerminalSessionChatWorking(node.id, working);
|
|
48777
|
+
if (!updated) return false;
|
|
48778
|
+
observability.notifySessionUpdated(updated);
|
|
48779
|
+
return true;
|
|
48239
48780
|
}
|
|
48240
48781
|
}
|
|
48241
48782
|
};
|
|
@@ -48385,7 +48926,12 @@ async function createAgentApi(ctx, terminalRuntime, deps) {
|
|
|
48385
48926
|
terminalRuntime.invalidateTicketsForSession(operationId);
|
|
48386
48927
|
observability.notifySessionUpdated(dormant);
|
|
48387
48928
|
const exitCwd = readPayloadString(ctx.host.operations.get(operationId)?.payload ?? {}, "cwd") ?? "";
|
|
48388
|
-
ctx.host.operations.patch(operationId, {
|
|
48929
|
+
ctx.host.operations.patch(operationId, {
|
|
48930
|
+
payload: {
|
|
48931
|
+
...toOperationPayload(ctx.host.operations.get(operationId)?.payload, exitCwd, dormant, providerSession, observability.getDurableOperation(operationId)?.providerTitle),
|
|
48932
|
+
restoredDormant: true
|
|
48933
|
+
}
|
|
48934
|
+
});
|
|
48389
48935
|
}
|
|
48390
48936
|
} else {
|
|
48391
48937
|
observability.removeTerminalSession(operationId);
|
|
@@ -48492,10 +49038,24 @@ async function createAgentApi(ctx, terminalRuntime, deps) {
|
|
|
48492
49038
|
for (const operation of ctx.host.operations.list()) {
|
|
48493
49039
|
if (operation.pluginId !== ctx.pluginId || operation.type !== AGENT_OPERATION_TYPE) continue;
|
|
48494
49040
|
const providerSession = readProviderSession(operation.payload);
|
|
48495
|
-
|
|
49041
|
+
const chatBorn = operation.payload[CHAT_BORN_PAYLOAD_KEY] === true;
|
|
49042
|
+
if (observability.getTerminalSessionInfo(operation.id)) continue;
|
|
49043
|
+
if (!providerSession && !chatBorn) {
|
|
49044
|
+
ctx.host.operations.patch(operation.id, { payload: { ...operation.payload, restoredDormant: true } });
|
|
49045
|
+
continue;
|
|
49046
|
+
}
|
|
48496
49047
|
const dormant = injectOperation(operation);
|
|
49048
|
+
if (operation.payload[CHAT_MODE_PAYLOAD_KEY] === true) {
|
|
49049
|
+
const adopted = observability.setTerminalSessionChatActive(operation.id, true);
|
|
49050
|
+
if (adopted) observability.notifySessionUpdated(adopted);
|
|
49051
|
+
}
|
|
48497
49052
|
const cwd = readPayloadString(operation.payload, "cwd") || (ctx.host.paths.resolveTheaterPath(operation.theaterId) ?? "");
|
|
48498
|
-
ctx.host.operations.patch(operation.id, {
|
|
49053
|
+
ctx.host.operations.patch(operation.id, {
|
|
49054
|
+
payload: {
|
|
49055
|
+
...toOperationPayload(operation.payload, cwd, dormant, providerSession, observability.getDurableOperation(operation.id)?.providerTitle),
|
|
49056
|
+
restoredDormant: true
|
|
49057
|
+
}
|
|
49058
|
+
});
|
|
48499
49059
|
}
|
|
48500
49060
|
}
|
|
48501
49061
|
function backfillAgentOperationLaunchAxes() {
|
|
@@ -48544,7 +49104,7 @@ function createTerminalWikiToolSpecs(fleetDataDir) {
|
|
|
48544
49104
|
}
|
|
48545
49105
|
function toOperationPayload(existing, cwd, session, providerSession, providerTitle) {
|
|
48546
49106
|
const payload = { ...existing ?? {} };
|
|
48547
|
-
for (const key of ["cwd", "cliId", "launchKindId", "cliLabel", "providerSession", "labelSource", "providerTitle"]) {
|
|
49107
|
+
for (const key of ["cwd", "cliId", "launchKindId", "cliLabel", "providerSession", "labelSource", "providerTitle", "restoredDormant"]) {
|
|
48548
49108
|
delete payload[key];
|
|
48549
49109
|
}
|
|
48550
49110
|
return {
|
|
@@ -48630,6 +49190,12 @@ function readHookPrompt(value) {
|
|
|
48630
49190
|
return void 0;
|
|
48631
49191
|
}
|
|
48632
49192
|
}
|
|
49193
|
+
function classifyLaunchSpawnFailure(error51) {
|
|
49194
|
+
const code = error51?.code;
|
|
49195
|
+
if (code === "ENOENT") return "agent_cli_binary_missing";
|
|
49196
|
+
if (code === "EACCES" || code === "EPERM") return "agent_cli_not_executable";
|
|
49197
|
+
return "terminal_unavailable";
|
|
49198
|
+
}
|
|
48633
49199
|
var DEFAULT_MAX_READ = 4 * 1024 * 1024;
|
|
48634
49200
|
var DEFAULT_MAX_REFRESH = 32 * 1024 * 1024;
|
|
48635
49201
|
var CONTINUITY_BYTES = 4 * 1024;
|
|
@@ -50129,6 +50695,7 @@ function formatSignInFailureMessage(displayName, status) {
|
|
|
50129
50695
|
var OPERATION_RESTORED_EVENT_CHANNEL2 = "operation:restored";
|
|
50130
50696
|
var RESTORED_DORMANT_PAYLOAD_KEY = "restoredDormant";
|
|
50131
50697
|
function registerShellRoutes(ctx, runtime) {
|
|
50698
|
+
markRestoredShellOperations(ctx);
|
|
50132
50699
|
const unsubscribeRestore = ctx.host.events.subscribe(OPERATION_RESTORED_EVENT_CHANNEL2, (payload) => {
|
|
50133
50700
|
if (!isRestoredShellEvent(payload, ctx.pluginId)) return;
|
|
50134
50701
|
const operation = ctx.host.operations.get(payload.operationId);
|
|
@@ -50229,6 +50796,13 @@ function registerShellRoutes(ctx, runtime) {
|
|
|
50229
50796
|
{ method: "POST", path: "/:operationId/relaunch", summary: "Relaunch a dormant Shell session.", category: "Terminal Plugin", gate: "origin-write", transport: "http" }
|
|
50230
50797
|
]);
|
|
50231
50798
|
}
|
|
50799
|
+
function markRestoredShellOperations(ctx) {
|
|
50800
|
+
for (const operation of ctx.host.operations.list()) {
|
|
50801
|
+
if (operation.pluginId !== ctx.pluginId || operation.type !== "shell") continue;
|
|
50802
|
+
if (operation.payload[RESTORED_DORMANT_PAYLOAD_KEY] === true) continue;
|
|
50803
|
+
ctx.host.operations.patch(operation.id, { payload: { ...operation.payload, [RESTORED_DORMANT_PAYLOAD_KEY]: true } });
|
|
50804
|
+
}
|
|
50805
|
+
}
|
|
50232
50806
|
function isRestoredShellEvent(value, pluginId) {
|
|
50233
50807
|
if (!value || typeof value !== "object") return false;
|
|
50234
50808
|
const event = value;
|