@jun133/kitty 0.0.10 → 0.0.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +95 -90
- package/dist/{App-6FETP3LH.mjs → App-V6SLDWQH.mjs} +39 -5
- package/dist/chunk-4HIVDFN5.mjs +823 -0
- package/dist/{chunk-ELBEXOR7.mjs → chunk-MV5BYUNW.mjs} +293 -1
- package/dist/{chunk-6NJJLOY3.mjs → chunk-TISOA5U6.mjs} +85 -3
- package/dist/{chunk-YSWK3BGL.mjs → chunk-TOBF3KV3.mjs} +1 -1
- package/dist/cli.js +491 -45
- package/dist/cli.js.map +1 -1
- package/dist/{interactive-KLW4JL7R.mjs → interactive-WYSTB4UQ.mjs} +3 -3
- package/dist/{oneShot-YHDMPFQM.mjs → oneShot-INJ27LNB.mjs} +2 -2
- package/dist/tui.mjs +90 -10
- package/package.json +1 -1
- package/dist/chunk-DFDOKON5.mjs +0 -530
|
@@ -3225,6 +3225,9 @@ var DIFF_MAX_CHARS = 3e3;
|
|
|
3225
3225
|
var OUTPUT_MAX_CHARS = 1500;
|
|
3226
3226
|
var SKILL_BODY_MAX_CHARS = 16e3;
|
|
3227
3227
|
function projectToolResultForModel(input) {
|
|
3228
|
+
if (input.result.metadata?.outputGovernance) {
|
|
3229
|
+
return input.result.metadata.outputGovernance.projection;
|
|
3230
|
+
}
|
|
3228
3231
|
const parsed = parseObject(input.result.output);
|
|
3229
3232
|
if (!input.result.ok) {
|
|
3230
3233
|
return projectFailure(input.toolName, input.result.output, parsed);
|
|
@@ -3328,6 +3331,11 @@ function projectWrite(payload) {
|
|
|
3328
3331
|
]);
|
|
3329
3332
|
}
|
|
3330
3333
|
function projectBash(payload) {
|
|
3334
|
+
const governance = readObject(payload.outputGovernance);
|
|
3335
|
+
const projection = readString(governance?.projection);
|
|
3336
|
+
if (projection) {
|
|
3337
|
+
return projection;
|
|
3338
|
+
}
|
|
3331
3339
|
const exitCode = readNumber(payload.exitCode);
|
|
3332
3340
|
const durationMs = readNumber(payload.durationMs);
|
|
3333
3341
|
const status = readString(payload.status);
|
|
@@ -4320,6 +4328,251 @@ function pathDepth(relativePath) {
|
|
|
4320
4328
|
return relativePath.split("/").filter(Boolean).length;
|
|
4321
4329
|
}
|
|
4322
4330
|
|
|
4331
|
+
// src/tools/outputKernel/classifier.ts
|
|
4332
|
+
function classifyToolOutput(source) {
|
|
4333
|
+
const output = source.output.trim();
|
|
4334
|
+
if (!output) {
|
|
4335
|
+
return "empty";
|
|
4336
|
+
}
|
|
4337
|
+
const command = (source.command ?? "").toLowerCase();
|
|
4338
|
+
const text = output.toLowerCase();
|
|
4339
|
+
if (looksLikeGitDiff(command, text)) {
|
|
4340
|
+
return "git_diff";
|
|
4341
|
+
}
|
|
4342
|
+
if (looksLikeSearch(command)) {
|
|
4343
|
+
return "search";
|
|
4344
|
+
}
|
|
4345
|
+
if (looksLikeTypecheck(command, text)) {
|
|
4346
|
+
return "typecheck";
|
|
4347
|
+
}
|
|
4348
|
+
if (looksLikeTest(command, text)) {
|
|
4349
|
+
return "test";
|
|
4350
|
+
}
|
|
4351
|
+
if (looksLikeBuild(command, text)) {
|
|
4352
|
+
return "build";
|
|
4353
|
+
}
|
|
4354
|
+
return "generic";
|
|
4355
|
+
}
|
|
4356
|
+
function looksLikeGitDiff(command, text) {
|
|
4357
|
+
return /\bgit\s+(diff|show)\b/.test(command) || text.includes("diff --git ");
|
|
4358
|
+
}
|
|
4359
|
+
function looksLikeSearch(command) {
|
|
4360
|
+
return /(^|\s)(rg|grep)(\s|$)/.test(command);
|
|
4361
|
+
}
|
|
4362
|
+
function looksLikeTypecheck(command, text) {
|
|
4363
|
+
return /\b(tsc|typecheck|mypy)\b/.test(command) || /\b(error|warning)\s+ts\d+:/i.test(text);
|
|
4364
|
+
}
|
|
4365
|
+
function looksLikeTest(command, text) {
|
|
4366
|
+
return /\b(test|vitest|jest|pytest|playwright|node --test)\b/.test(command) || /\b(test result|tests? failed|tests? passed|failing tests?|failures?)\b/.test(text);
|
|
4367
|
+
}
|
|
4368
|
+
function looksLikeBuild(command, text) {
|
|
4369
|
+
return /\b(build|compile|cargo check|cargo clippy|npm run build|pnpm build)\b/.test(command) || /\b(compilation failed|build failed|compiled successfully|error\[e\d+\])\b/.test(text);
|
|
4370
|
+
}
|
|
4371
|
+
|
|
4372
|
+
// src/tools/outputKernel/metrics.ts
|
|
4373
|
+
function estimateTextTokens(value) {
|
|
4374
|
+
const trimmed = value.trim();
|
|
4375
|
+
if (!trimmed) {
|
|
4376
|
+
return 0;
|
|
4377
|
+
}
|
|
4378
|
+
return Math.max(1, Math.ceil(trimmed.length / 4));
|
|
4379
|
+
}
|
|
4380
|
+
function computeSavings(input) {
|
|
4381
|
+
const rawChars = input.raw.length;
|
|
4382
|
+
const projectedChars = input.projected.length;
|
|
4383
|
+
const rawTokens = estimateTextTokens(input.raw);
|
|
4384
|
+
const projectedTokens = estimateTextTokens(input.projected);
|
|
4385
|
+
const savedTokens = Math.max(0, rawTokens - projectedTokens);
|
|
4386
|
+
const savingsRatio = rawTokens > 0 ? Math.round(savedTokens / rawTokens * 1e4) / 1e4 : 0;
|
|
4387
|
+
return {
|
|
4388
|
+
rawChars,
|
|
4389
|
+
projectedChars,
|
|
4390
|
+
rawTokens,
|
|
4391
|
+
projectedTokens,
|
|
4392
|
+
savedTokens,
|
|
4393
|
+
savingsRatio
|
|
4394
|
+
};
|
|
4395
|
+
}
|
|
4396
|
+
|
|
4397
|
+
// src/tools/outputKernel/projectors/shared.ts
|
|
4398
|
+
function buildHeader(source, label) {
|
|
4399
|
+
return [
|
|
4400
|
+
`${source.toolName}: ${label}`,
|
|
4401
|
+
source.exitCode === void 0 ? void 0 : `exit=${source.exitCode ?? "null"}`,
|
|
4402
|
+
source.durationMs === void 0 ? void 0 : `duration=${source.durationMs}ms`,
|
|
4403
|
+
source.status ? `status=${source.status}` : void 0
|
|
4404
|
+
].filter(Boolean).join(" ");
|
|
4405
|
+
}
|
|
4406
|
+
function splitOutputLines(value) {
|
|
4407
|
+
return value.split(/\r?\n/).map((line) => line.trimEnd());
|
|
4408
|
+
}
|
|
4409
|
+
function dedupeProjectedLines(lines) {
|
|
4410
|
+
const seen = /* @__PURE__ */ new Set();
|
|
4411
|
+
const result = [];
|
|
4412
|
+
for (const rawLine of lines) {
|
|
4413
|
+
const line = truncateText(rawLine.trim(), 260);
|
|
4414
|
+
if (!line || seen.has(line)) {
|
|
4415
|
+
continue;
|
|
4416
|
+
}
|
|
4417
|
+
seen.add(line);
|
|
4418
|
+
result.push(line);
|
|
4419
|
+
}
|
|
4420
|
+
return result;
|
|
4421
|
+
}
|
|
4422
|
+
|
|
4423
|
+
// src/tools/outputKernel/projectors/diagnostic.ts
|
|
4424
|
+
var STRUCTURED_MAX_LINES = 28;
|
|
4425
|
+
function buildDiagnosticProjection(source, label) {
|
|
4426
|
+
const lines = splitOutputLines(source.output);
|
|
4427
|
+
const evidence = lines.filter(isDiagnosticEvidenceLine).slice(0, STRUCTURED_MAX_LINES);
|
|
4428
|
+
const summaryLines = lines.filter(isSummaryLine).slice(0, 8);
|
|
4429
|
+
return dedupeProjectedLines([
|
|
4430
|
+
buildHeader(source, label),
|
|
4431
|
+
...summaryLines,
|
|
4432
|
+
...evidence
|
|
4433
|
+
]).join("\n");
|
|
4434
|
+
}
|
|
4435
|
+
function isDiagnosticEvidenceLine(line) {
|
|
4436
|
+
return /(^|\b)(error|warning|fail|failed|failure|panic|exception|traceback|expected|received|cannot find|not assignable|mismatched|undefined|denied)(\b|:)/i.test(line) || /^\s*(at\s|file\s|src\/|tests?\/|[A-Za-z]:\\|\.\/)/.test(line) || /\(\d+,\d+\):\s+(error|warning)\s+/i.test(line) || /error\[e\d+\]/i.test(line);
|
|
4437
|
+
}
|
|
4438
|
+
function isSummaryLine(line) {
|
|
4439
|
+
return /\b(\d+\s+(passed|failed|skipped|errors?|warnings?)|test result|found \d+ errors?|failed tests?|build failed|compiled successfully)\b/i.test(line);
|
|
4440
|
+
}
|
|
4441
|
+
|
|
4442
|
+
// src/tools/outputKernel/projectors/gitDiff.ts
|
|
4443
|
+
var DIFF_MAX_FILES = 24;
|
|
4444
|
+
function buildGitDiffProjection(source) {
|
|
4445
|
+
const lines = splitOutputLines(source.output);
|
|
4446
|
+
const files = lines.filter((line) => line.startsWith("diff --git ")).map((line) => line.replace(/^diff --git a\//, "").replace(/ b\//, " -> ")).slice(0, DIFF_MAX_FILES);
|
|
4447
|
+
const stats = lines.filter((line) => /(\d+ files? changed|\d+ insertions?\(\+\)|\d+ deletions?\(-\))/.test(line)).slice(0, 8);
|
|
4448
|
+
const hunks = lines.filter((line) => line.startsWith("@@") || line.startsWith("+++ ") || line.startsWith("--- ")).slice(0, 18).map((line) => truncateText(line, 220));
|
|
4449
|
+
return [
|
|
4450
|
+
buildHeader(source, "git diff"),
|
|
4451
|
+
files.length > 0 ? `files: ${files.join(", ")}` : void 0,
|
|
4452
|
+
...stats,
|
|
4453
|
+
...hunks
|
|
4454
|
+
].filter((line) => Boolean(line)).join("\n");
|
|
4455
|
+
}
|
|
4456
|
+
|
|
4457
|
+
// src/tools/outputKernel/projectors/generic.ts
|
|
4458
|
+
var GENERIC_MAX_CHARS = 1500;
|
|
4459
|
+
function projectEmptyOutput(source) {
|
|
4460
|
+
return {
|
|
4461
|
+
mode: "empty",
|
|
4462
|
+
projection: buildHeader(source, "no output"),
|
|
4463
|
+
degraded: false,
|
|
4464
|
+
reason: "empty_output"
|
|
4465
|
+
};
|
|
4466
|
+
}
|
|
4467
|
+
function projectGenericOutput(source, reason = "generic_output") {
|
|
4468
|
+
return {
|
|
4469
|
+
mode: "generic",
|
|
4470
|
+
projection: buildGenericPreview(source),
|
|
4471
|
+
degraded: false,
|
|
4472
|
+
reason
|
|
4473
|
+
};
|
|
4474
|
+
}
|
|
4475
|
+
function projectStructuredOutput(source, body) {
|
|
4476
|
+
const trimmed = body.trim();
|
|
4477
|
+
if (!trimmed) {
|
|
4478
|
+
return {
|
|
4479
|
+
mode: "generic",
|
|
4480
|
+
projection: buildGenericPreview(source),
|
|
4481
|
+
degraded: true,
|
|
4482
|
+
reason: "structured_projection_empty"
|
|
4483
|
+
};
|
|
4484
|
+
}
|
|
4485
|
+
return {
|
|
4486
|
+
mode: "structured",
|
|
4487
|
+
projection: trimmed,
|
|
4488
|
+
degraded: false,
|
|
4489
|
+
reason: "structured_projection"
|
|
4490
|
+
};
|
|
4491
|
+
}
|
|
4492
|
+
function buildGenericPreview(source) {
|
|
4493
|
+
return [
|
|
4494
|
+
buildHeader(source, "output"),
|
|
4495
|
+
truncateText(source.output.trim(), GENERIC_MAX_CHARS)
|
|
4496
|
+
].filter(Boolean).join("\n");
|
|
4497
|
+
}
|
|
4498
|
+
|
|
4499
|
+
// src/tools/outputKernel/projectors/search.ts
|
|
4500
|
+
var SEARCH_MAX_MATCHES = 24;
|
|
4501
|
+
function buildSearchProjection(source) {
|
|
4502
|
+
const nonEmptyLines = splitOutputLines(source.output).filter((line) => line.trim().length > 0);
|
|
4503
|
+
const matches = nonEmptyLines.slice(0, SEARCH_MAX_MATCHES).map((line) => truncateText(line, 220));
|
|
4504
|
+
const omitted = Math.max(0, nonEmptyLines.length - matches.length);
|
|
4505
|
+
return [
|
|
4506
|
+
buildHeader(source, "search"),
|
|
4507
|
+
`matches shown: ${matches.length}${omitted > 0 ? `, omitted: ${omitted}` : ""}`,
|
|
4508
|
+
...matches
|
|
4509
|
+
].join("\n");
|
|
4510
|
+
}
|
|
4511
|
+
|
|
4512
|
+
// src/tools/outputKernel/projectors/recovery.ts
|
|
4513
|
+
function appendRecoveryHint(projection, governance) {
|
|
4514
|
+
if (!governance.recoveryHint) {
|
|
4515
|
+
return projection;
|
|
4516
|
+
}
|
|
4517
|
+
if (projection.includes(governance.recoveryHint)) {
|
|
4518
|
+
return projection;
|
|
4519
|
+
}
|
|
4520
|
+
return `${projection.trimEnd()}
|
|
4521
|
+
${governance.recoveryHint}`;
|
|
4522
|
+
}
|
|
4523
|
+
|
|
4524
|
+
// src/tools/outputKernel/projectors.ts
|
|
4525
|
+
function projectOutputByKind(kind, source) {
|
|
4526
|
+
switch (kind) {
|
|
4527
|
+
case "empty":
|
|
4528
|
+
return projectEmptyOutput(source);
|
|
4529
|
+
case "test":
|
|
4530
|
+
return projectStructuredOutput(source, buildDiagnosticProjection(source, "test"));
|
|
4531
|
+
case "build":
|
|
4532
|
+
return projectStructuredOutput(source, buildDiagnosticProjection(source, "build"));
|
|
4533
|
+
case "typecheck":
|
|
4534
|
+
return projectStructuredOutput(source, buildDiagnosticProjection(source, "typecheck"));
|
|
4535
|
+
case "search":
|
|
4536
|
+
return projectStructuredOutput(source, buildSearchProjection(source));
|
|
4537
|
+
case "git_diff":
|
|
4538
|
+
return projectStructuredOutput(source, buildGitDiffProjection(source));
|
|
4539
|
+
case "generic":
|
|
4540
|
+
return projectGenericOutput(source);
|
|
4541
|
+
}
|
|
4542
|
+
}
|
|
4543
|
+
|
|
4544
|
+
// src/tools/outputKernel/index.ts
|
|
4545
|
+
function governToolOutput(source) {
|
|
4546
|
+
const kind = classifyToolOutput(source);
|
|
4547
|
+
const projected = projectOutputByKind(kind, source);
|
|
4548
|
+
const recoveryHint = source.outputPath ? `[full output: ${source.outputPath}]` : void 0;
|
|
4549
|
+
const projection = appendRecoveryHint(projected.projection, {
|
|
4550
|
+
outputPath: source.outputPath,
|
|
4551
|
+
recoveryHint
|
|
4552
|
+
});
|
|
4553
|
+
const metrics = computeSavings({
|
|
4554
|
+
raw: source.output,
|
|
4555
|
+
projected: projection
|
|
4556
|
+
});
|
|
4557
|
+
return {
|
|
4558
|
+
version: 1,
|
|
4559
|
+
kind,
|
|
4560
|
+
mode: projected.mode,
|
|
4561
|
+
projection,
|
|
4562
|
+
rawChars: source.outputChars ?? metrics.rawChars,
|
|
4563
|
+
projectedChars: metrics.projectedChars,
|
|
4564
|
+
rawTokens: metrics.rawTokens,
|
|
4565
|
+
projectedTokens: metrics.projectedTokens,
|
|
4566
|
+
savedTokens: metrics.savedTokens,
|
|
4567
|
+
savingsRatio: metrics.savingsRatio,
|
|
4568
|
+
truncated: Boolean(source.truncated),
|
|
4569
|
+
outputPath: source.outputPath,
|
|
4570
|
+
recoveryHint,
|
|
4571
|
+
degraded: projected.degraded,
|
|
4572
|
+
reason: projected.reason
|
|
4573
|
+
};
|
|
4574
|
+
}
|
|
4575
|
+
|
|
4323
4576
|
// src/tools/bash.ts
|
|
4324
4577
|
var SHELL_RUNTIME = getShellRuntimeInfo();
|
|
4325
4578
|
var bashToolDefinition = {
|
|
@@ -4369,6 +4622,18 @@ var bashToolDefinition = {
|
|
|
4369
4622
|
}
|
|
4370
4623
|
});
|
|
4371
4624
|
const status = result.aborted ? "aborted" : result.stalled ? "stalled" : result.timedOut ? "timed_out" : result.exitCode === 0 ? "completed" : "failed";
|
|
4625
|
+
const outputGovernance = governToolOutput({
|
|
4626
|
+
toolName: "bash",
|
|
4627
|
+
command,
|
|
4628
|
+
status,
|
|
4629
|
+
exitCode: result.exitCode,
|
|
4630
|
+
durationMs: result.durationMs,
|
|
4631
|
+
output: result.output,
|
|
4632
|
+
outputPath: result.outputPath,
|
|
4633
|
+
truncated: result.truncated,
|
|
4634
|
+
outputChars: result.outputChars,
|
|
4635
|
+
outputBytes: result.outputBytes
|
|
4636
|
+
});
|
|
4372
4637
|
const metadata = {
|
|
4373
4638
|
runtime: {
|
|
4374
4639
|
status,
|
|
@@ -4381,7 +4646,8 @@ var bashToolDefinition = {
|
|
|
4381
4646
|
truncated: result.truncated,
|
|
4382
4647
|
outputPath: result.outputPath,
|
|
4383
4648
|
outputPreview: result.output
|
|
4384
|
-
}
|
|
4649
|
+
},
|
|
4650
|
+
outputGovernance
|
|
4385
4651
|
};
|
|
4386
4652
|
return okResult(
|
|
4387
4653
|
JSON.stringify(
|
|
@@ -4396,6 +4662,7 @@ var bashToolDefinition = {
|
|
|
4396
4662
|
outputPath: result.outputPath,
|
|
4397
4663
|
outputChars: result.outputChars,
|
|
4398
4664
|
outputBytes: result.outputBytes,
|
|
4665
|
+
outputGovernance,
|
|
4399
4666
|
output: truncateText(result.output, 4e3),
|
|
4400
4667
|
...status === "completed" ? {} : {
|
|
4401
4668
|
shell: shell.shell,
|
|
@@ -5916,6 +6183,31 @@ async function processToolCallBatch(input) {
|
|
|
5916
6183
|
changedPathCount: metadata?.changedPaths?.length ?? 0
|
|
5917
6184
|
}
|
|
5918
6185
|
});
|
|
6186
|
+
if (metadata?.outputGovernance) {
|
|
6187
|
+
await recordObservabilityEvent(projectContext.stateRootDir, {
|
|
6188
|
+
event: "tool.output",
|
|
6189
|
+
status: result.ok ? "completed" : "failed",
|
|
6190
|
+
sessionId: session.id,
|
|
6191
|
+
identityKind: identity.kind,
|
|
6192
|
+
identityName: identity.name,
|
|
6193
|
+
toolName: toolCall.function.name,
|
|
6194
|
+
durationMs,
|
|
6195
|
+
details: {
|
|
6196
|
+
kind: metadata.outputGovernance.kind,
|
|
6197
|
+
mode: metadata.outputGovernance.mode,
|
|
6198
|
+
rawChars: metadata.outputGovernance.rawChars,
|
|
6199
|
+
projectedChars: metadata.outputGovernance.projectedChars,
|
|
6200
|
+
rawTokens: metadata.outputGovernance.rawTokens,
|
|
6201
|
+
projectedTokens: metadata.outputGovernance.projectedTokens,
|
|
6202
|
+
savedTokens: metadata.outputGovernance.savedTokens,
|
|
6203
|
+
savingsRatio: metadata.outputGovernance.savingsRatio,
|
|
6204
|
+
truncated: metadata.outputGovernance.truncated,
|
|
6205
|
+
outputPath: metadata.outputGovernance.outputPath,
|
|
6206
|
+
degraded: metadata.outputGovernance.degraded,
|
|
6207
|
+
reason: metadata.outputGovernance.reason
|
|
6208
|
+
}
|
|
6209
|
+
});
|
|
6210
|
+
}
|
|
5919
6211
|
if (result.ok) {
|
|
5920
6212
|
options.callbacks?.onToolResult?.(toolCall.function.name, result.output);
|
|
5921
6213
|
} else {
|
|
@@ -23,7 +23,7 @@ import {
|
|
|
23
23
|
terminatePid,
|
|
24
24
|
writeStderrLine,
|
|
25
25
|
writeStdoutLine
|
|
26
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-MV5BYUNW.mjs";
|
|
27
27
|
import {
|
|
28
28
|
PRESERVED_PROJECT_STATE_ENTRY_NAMES,
|
|
29
29
|
PROJECT_STATE_DIR_NAME,
|
|
@@ -326,6 +326,7 @@ function buildRuntimeScene(status) {
|
|
|
326
326
|
nextAction: readNextAction(status, blockedExecutions, watchExecutions),
|
|
327
327
|
blocked: readBlocked(blockedExecutions),
|
|
328
328
|
cost: readCost(status),
|
|
329
|
+
toolOutputs: readToolOutputs(status),
|
|
329
330
|
recovery: readRecovery(status, executions),
|
|
330
331
|
skills: {
|
|
331
332
|
ready: status.skills.ready,
|
|
@@ -412,6 +413,23 @@ function readCost(status) {
|
|
|
412
413
|
const usageText = latest?.usage ? readUsageCost(latest.usage) : latest ? "provider usage unavailable" : "no model request yet";
|
|
413
414
|
return `${budgetText}; ${layoutText}; ${usageText}`;
|
|
414
415
|
}
|
|
416
|
+
function readToolOutputs(status) {
|
|
417
|
+
const recent = status.toolOutputs.recent;
|
|
418
|
+
if (recent.length === 0) {
|
|
419
|
+
return "no tool output governance yet";
|
|
420
|
+
}
|
|
421
|
+
const saved = recent.reduce((total, item) => total + (item.savedTokens ?? 0), 0);
|
|
422
|
+
const truncated = recent.filter((item) => item.truncated).length;
|
|
423
|
+
const degraded = recent.filter((item) => item.degraded).length;
|
|
424
|
+
const best = recent.filter((item) => typeof item.savedTokens === "number").sort((a, b) => (b.savedTokens ?? 0) - (a.savedTokens ?? 0))[0];
|
|
425
|
+
return [
|
|
426
|
+
`${recent.length} recent`,
|
|
427
|
+
`${saved} tokens saved est.`,
|
|
428
|
+
truncated > 0 ? `${truncated} recoverable` : void 0,
|
|
429
|
+
degraded > 0 ? `${degraded} degraded` : void 0,
|
|
430
|
+
best ? `top=${best.toolName ?? "tool"}:${best.kind ?? "output"}` : void 0
|
|
431
|
+
].filter(Boolean).join("; ");
|
|
432
|
+
}
|
|
415
433
|
function readStableRatio(stableChars, volatileChars) {
|
|
416
434
|
const total = stableChars + volatileChars;
|
|
417
435
|
return total > 0 ? `${Math.round(stableChars / total * 100)}%` : "unknown";
|
|
@@ -825,13 +843,14 @@ async function buildRuntimeStatus(rootDir) {
|
|
|
825
843
|
const sessionStore = new SessionStore(paths.sessionsDir, {
|
|
826
844
|
memorySessionsDir: paths.sessionMemoryDir
|
|
827
845
|
});
|
|
828
|
-
const [sessionRead, memoryAssets, control, projectMap, projectContext, modelRequests] = await Promise.all([
|
|
846
|
+
const [sessionRead, memoryAssets, control, projectMap, projectContext, modelRequests, toolOutputs] = await Promise.all([
|
|
829
847
|
sessionStore.listReadable?.(DEFAULT_RECENT_LIMIT) ?? sessionStore.list(DEFAULT_RECENT_LIMIT).then((sessions2) => ({ sessions: sessions2, skipped: [] })),
|
|
830
848
|
listRuntimeMemoryAssets(paths.rootDir),
|
|
831
849
|
readControlPlaneStatus(paths.rootDir),
|
|
832
850
|
buildProjectMap(paths.rootDir),
|
|
833
851
|
loadProjectContext(paths.rootDir, { projectDocMaxBytes: 24576 }),
|
|
834
|
-
readRecentModelRequests(paths.observabilityEventsDir)
|
|
852
|
+
readRecentModelRequests(paths.observabilityEventsDir),
|
|
853
|
+
readRecentToolOutputs(paths.observabilityEventsDir)
|
|
835
854
|
]);
|
|
836
855
|
const sessions = sessionRead.sessions.map(summarizeSession);
|
|
837
856
|
const taskLifecycle = sessions[0] ? readTaskLifecycleStatus(paths.rootDir, sessions[0].id) : void 0;
|
|
@@ -852,6 +871,9 @@ async function buildRuntimeStatus(rootDir) {
|
|
|
852
871
|
modelRequests: {
|
|
853
872
|
recent: modelRequests
|
|
854
873
|
},
|
|
874
|
+
toolOutputs: {
|
|
875
|
+
recent: toolOutputs
|
|
876
|
+
},
|
|
855
877
|
taskLifecycle,
|
|
856
878
|
executions: control.executions,
|
|
857
879
|
wakeSignals: control.wakeSignals
|
|
@@ -926,6 +948,25 @@ async function readRecentModelRequests(eventsDir) {
|
|
|
926
948
|
}
|
|
927
949
|
return records.slice(-DEFAULT_RECENT_LIMIT).reverse();
|
|
928
950
|
}
|
|
951
|
+
async function readRecentToolOutputs(eventsDir) {
|
|
952
|
+
const files = await fs7.readdir(eventsDir).catch(() => []);
|
|
953
|
+
const jsonlFiles = files.filter((file) => file.endsWith(".jsonl")).sort().slice(-3);
|
|
954
|
+
const records = [];
|
|
955
|
+
for (const file of jsonlFiles) {
|
|
956
|
+
const content = await fs7.readFile(path6.join(eventsDir, file), "utf8").catch(() => "");
|
|
957
|
+
for (const line of content.split(/\r?\n/)) {
|
|
958
|
+
if (!line.trim()) {
|
|
959
|
+
continue;
|
|
960
|
+
}
|
|
961
|
+
const record = parseObservabilityRecord(line);
|
|
962
|
+
if (!record || record.event !== "tool.output") {
|
|
963
|
+
continue;
|
|
964
|
+
}
|
|
965
|
+
records.push(summarizeToolOutput(record));
|
|
966
|
+
}
|
|
967
|
+
}
|
|
968
|
+
return records.slice(-DEFAULT_RECENT_LIMIT).reverse();
|
|
969
|
+
}
|
|
929
970
|
function parseObservabilityRecord(line) {
|
|
930
971
|
try {
|
|
931
972
|
const parsed = JSON.parse(line);
|
|
@@ -946,6 +987,25 @@ function summarizeModelRequest(record) {
|
|
|
946
987
|
usage
|
|
947
988
|
};
|
|
948
989
|
}
|
|
990
|
+
function summarizeToolOutput(record) {
|
|
991
|
+
const details = record.details ?? {};
|
|
992
|
+
return {
|
|
993
|
+
timestamp: record.timestamp,
|
|
994
|
+
toolName: record.toolName,
|
|
995
|
+
kind: readString(details.kind),
|
|
996
|
+
mode: readString(details.mode),
|
|
997
|
+
rawChars: readNumber(details.rawChars),
|
|
998
|
+
projectedChars: readNumber(details.projectedChars),
|
|
999
|
+
rawTokens: readNumber(details.rawTokens),
|
|
1000
|
+
projectedTokens: readNumber(details.projectedTokens),
|
|
1001
|
+
savedTokens: readNumber(details.savedTokens),
|
|
1002
|
+
savingsRatio: readNumber(details.savingsRatio),
|
|
1003
|
+
truncated: details.truncated === true,
|
|
1004
|
+
outputPath: readString(details.outputPath),
|
|
1005
|
+
degraded: details.degraded === true,
|
|
1006
|
+
reason: readString(details.reason)
|
|
1007
|
+
};
|
|
1008
|
+
}
|
|
949
1009
|
function readUsageSummary(value) {
|
|
950
1010
|
if (!value || typeof value !== "object") {
|
|
951
1011
|
return void 0;
|
|
@@ -967,6 +1027,9 @@ function readUsageSummary(value) {
|
|
|
967
1027
|
function readNumber(value) {
|
|
968
1028
|
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
969
1029
|
}
|
|
1030
|
+
function readString(value) {
|
|
1031
|
+
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
1032
|
+
}
|
|
970
1033
|
function summarizeSkills(skills) {
|
|
971
1034
|
const summaries = skills.map((skill) => ({
|
|
972
1035
|
name: skill.name,
|
|
@@ -1062,6 +1125,7 @@ function formatRuntimeStatusText(status) {
|
|
|
1062
1125
|
lines.push(`- Skills: ${status.scene.skills.ready}/${status.scene.skills.total} ready; ${status.scene.skills.nextAction}`);
|
|
1063
1126
|
lines.push(`- Memory: ${status.scene.memory.assets} asset(s), session=${status.scene.memory.latestSessionMemory ? "yes" : "no"}; ${status.scene.memory.nextAction}`);
|
|
1064
1127
|
lines.push(`- Cost: ${status.scene.cost}`);
|
|
1128
|
+
lines.push(`- Tool output: ${status.scene.toolOutputs}`);
|
|
1065
1129
|
lines.push(`- Recovery: ${status.scene.recovery}`);
|
|
1066
1130
|
lines.push("");
|
|
1067
1131
|
lines.push("Current workspace:");
|
|
@@ -1173,6 +1237,24 @@ function formatRuntimeStatusText(status) {
|
|
|
1173
1237
|
].filter(Boolean).join(" "));
|
|
1174
1238
|
}
|
|
1175
1239
|
}
|
|
1240
|
+
if (status.toolOutputs.recent.length > 0) {
|
|
1241
|
+
lines.push("");
|
|
1242
|
+
lines.push("Recent tool output:");
|
|
1243
|
+
for (const output of status.toolOutputs.recent.slice(0, 5)) {
|
|
1244
|
+
lines.push([
|
|
1245
|
+
output.toolName ?? "tool",
|
|
1246
|
+
output.kind ? `kind=${output.kind}` : void 0,
|
|
1247
|
+
output.mode ? `mode=${output.mode}` : void 0,
|
|
1248
|
+
output.rawTokens === void 0 ? void 0 : `raw=${output.rawTokens}`,
|
|
1249
|
+
output.projectedTokens === void 0 ? void 0 : `projected=${output.projectedTokens}`,
|
|
1250
|
+
output.savedTokens === void 0 ? void 0 : `saved=${output.savedTokens}`,
|
|
1251
|
+
output.savingsRatio === void 0 ? void 0 : `savedRatio=${Math.round(output.savingsRatio * 100)}%`,
|
|
1252
|
+
output.truncated ? "recoverable=yes" : void 0,
|
|
1253
|
+
output.degraded ? "degraded=yes" : void 0,
|
|
1254
|
+
output.outputPath ? `full=${truncateCliValue(output.outputPath, 80)}` : void 0
|
|
1255
|
+
].filter(Boolean).join(" "));
|
|
1256
|
+
}
|
|
1257
|
+
}
|
|
1176
1258
|
if (status.executions.active.length > 0) {
|
|
1177
1259
|
lines.push("");
|
|
1178
1260
|
lines.push("Active executions:");
|