@jun133/kitty 0.0.11 → 0.0.13
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-6NJJLOY3.mjs → chunk-6WGSABUQ.mjs} +107 -9
- package/dist/{chunk-YSWK3BGL.mjs → chunk-DWGFLIQA.mjs} +1 -1
- package/dist/{chunk-ELBEXOR7.mjs → chunk-MMIH75OY.mjs} +294 -1
- package/dist/cli.js +514 -51
- package/dist/cli.js.map +1 -1
- package/dist/{interactive-KLW4JL7R.mjs → interactive-RSJ35TB5.mjs} +3 -3
- package/dist/{oneShot-YHDMPFQM.mjs → oneShot-7P5FDWFX.mjs} +2 -2
- package/dist/tui.mjs +90 -10
- package/package.json +1 -1
- package/dist/chunk-DFDOKON5.mjs +0 -530
|
@@ -23,7 +23,7 @@ import {
|
|
|
23
23
|
terminatePid,
|
|
24
24
|
writeStderrLine,
|
|
25
25
|
writeStdoutLine
|
|
26
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-MMIH75OY.mjs";
|
|
27
27
|
import {
|
|
28
28
|
PRESERVED_PROJECT_STATE_ENTRY_NAMES,
|
|
29
29
|
PROJECT_STATE_DIR_NAME,
|
|
@@ -315,7 +315,7 @@ async function terminateProcesses(processes, cwd) {
|
|
|
315
315
|
|
|
316
316
|
// src/runtime/scene.ts
|
|
317
317
|
function buildRuntimeScene(status) {
|
|
318
|
-
const executions = status
|
|
318
|
+
const executions = readSceneExecutions(status);
|
|
319
319
|
const blockedExecutions = executions.filter((execution) => execution.risk === "blocked");
|
|
320
320
|
const watchExecutions = executions.filter((execution) => execution.risk === "watch");
|
|
321
321
|
const activeBackground = executions.filter((execution) => execution.kind === "background");
|
|
@@ -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,
|
|
@@ -345,6 +346,19 @@ function buildRuntimeScene(status) {
|
|
|
345
346
|
executions
|
|
346
347
|
};
|
|
347
348
|
}
|
|
349
|
+
function readSceneExecutions(status) {
|
|
350
|
+
const byId = /* @__PURE__ */ new Map();
|
|
351
|
+
for (const execution of status.executions.active) {
|
|
352
|
+
byId.set(execution.id, buildExecutionScene(execution));
|
|
353
|
+
}
|
|
354
|
+
for (const execution of status.executions.recent) {
|
|
355
|
+
const scene = buildExecutionScene(execution);
|
|
356
|
+
if (scene.risk !== "none" && !byId.has(scene.id)) {
|
|
357
|
+
byId.set(scene.id, scene);
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
return [...byId.values()];
|
|
361
|
+
}
|
|
348
362
|
function buildExecutionScene(execution) {
|
|
349
363
|
const risk = readExecutionRisk(execution);
|
|
350
364
|
return {
|
|
@@ -359,9 +373,6 @@ function buildExecutionScene(execution) {
|
|
|
359
373
|
};
|
|
360
374
|
}
|
|
361
375
|
function buildHeadline(status, blockedExecutions, watchExecutions) {
|
|
362
|
-
if (!status.sessions.latest) {
|
|
363
|
-
return "No active session yet.";
|
|
364
|
-
}
|
|
365
376
|
if (blockedExecutions.length > 0) {
|
|
366
377
|
return `${blockedExecutions.length} execution(s) need attention.`;
|
|
367
378
|
}
|
|
@@ -371,6 +382,9 @@ function buildHeadline(status, blockedExecutions, watchExecutions) {
|
|
|
371
382
|
if (status.executions.active.length > 0) {
|
|
372
383
|
return `${status.executions.active.length} execution(s) are running.`;
|
|
373
384
|
}
|
|
385
|
+
if (!status.sessions.latest) {
|
|
386
|
+
return "No active session yet.";
|
|
387
|
+
}
|
|
374
388
|
return "Ready to continue the latest session.";
|
|
375
389
|
}
|
|
376
390
|
function readFocus(status) {
|
|
@@ -412,6 +426,23 @@ function readCost(status) {
|
|
|
412
426
|
const usageText = latest?.usage ? readUsageCost(latest.usage) : latest ? "provider usage unavailable" : "no model request yet";
|
|
413
427
|
return `${budgetText}; ${layoutText}; ${usageText}`;
|
|
414
428
|
}
|
|
429
|
+
function readToolOutputs(status) {
|
|
430
|
+
const recent = status.toolOutputs.recent;
|
|
431
|
+
if (recent.length === 0) {
|
|
432
|
+
return "no tool output governance yet";
|
|
433
|
+
}
|
|
434
|
+
const saved = recent.reduce((total, item) => total + (item.savedTokens ?? 0), 0);
|
|
435
|
+
const truncated = recent.filter((item) => item.truncated).length;
|
|
436
|
+
const degraded = recent.filter((item) => item.degraded).length;
|
|
437
|
+
const best = recent.filter((item) => typeof item.savedTokens === "number").sort((a, b) => (b.savedTokens ?? 0) - (a.savedTokens ?? 0))[0];
|
|
438
|
+
return [
|
|
439
|
+
`${recent.length} recent`,
|
|
440
|
+
`${saved} tokens saved est.`,
|
|
441
|
+
truncated > 0 ? `${truncated} recoverable` : void 0,
|
|
442
|
+
degraded > 0 ? `${degraded} degraded` : void 0,
|
|
443
|
+
best ? `top=${best.toolName ?? "tool"}:${best.kind ?? "output"}` : void 0
|
|
444
|
+
].filter(Boolean).join("; ");
|
|
445
|
+
}
|
|
415
446
|
function readStableRatio(stableChars, volatileChars) {
|
|
416
447
|
const total = stableChars + volatileChars;
|
|
417
448
|
return total > 0 ? `${Math.round(stableChars / total * 100)}%` : "unknown";
|
|
@@ -825,13 +856,14 @@ async function buildRuntimeStatus(rootDir) {
|
|
|
825
856
|
const sessionStore = new SessionStore(paths.sessionsDir, {
|
|
826
857
|
memorySessionsDir: paths.sessionMemoryDir
|
|
827
858
|
});
|
|
828
|
-
const [sessionRead, memoryAssets, control, projectMap, projectContext, modelRequests] = await Promise.all([
|
|
859
|
+
const [sessionRead, memoryAssets, control, projectMap, projectContext, modelRequests, toolOutputs] = await Promise.all([
|
|
829
860
|
sessionStore.listReadable?.(DEFAULT_RECENT_LIMIT) ?? sessionStore.list(DEFAULT_RECENT_LIMIT).then((sessions2) => ({ sessions: sessions2, skipped: [] })),
|
|
830
861
|
listRuntimeMemoryAssets(paths.rootDir),
|
|
831
862
|
readControlPlaneStatus(paths.rootDir),
|
|
832
863
|
buildProjectMap(paths.rootDir),
|
|
833
864
|
loadProjectContext(paths.rootDir, { projectDocMaxBytes: 24576 }),
|
|
834
|
-
readRecentModelRequests(paths.observabilityEventsDir)
|
|
865
|
+
readRecentModelRequests(paths.observabilityEventsDir),
|
|
866
|
+
readRecentToolOutputs(paths.observabilityEventsDir)
|
|
835
867
|
]);
|
|
836
868
|
const sessions = sessionRead.sessions.map(summarizeSession);
|
|
837
869
|
const taskLifecycle = sessions[0] ? readTaskLifecycleStatus(paths.rootDir, sessions[0].id) : void 0;
|
|
@@ -852,6 +884,9 @@ async function buildRuntimeStatus(rootDir) {
|
|
|
852
884
|
modelRequests: {
|
|
853
885
|
recent: modelRequests
|
|
854
886
|
},
|
|
887
|
+
toolOutputs: {
|
|
888
|
+
recent: toolOutputs
|
|
889
|
+
},
|
|
855
890
|
taskLifecycle,
|
|
856
891
|
executions: control.executions,
|
|
857
892
|
wakeSignals: control.wakeSignals
|
|
@@ -926,6 +961,25 @@ async function readRecentModelRequests(eventsDir) {
|
|
|
926
961
|
}
|
|
927
962
|
return records.slice(-DEFAULT_RECENT_LIMIT).reverse();
|
|
928
963
|
}
|
|
964
|
+
async function readRecentToolOutputs(eventsDir) {
|
|
965
|
+
const files = await fs7.readdir(eventsDir).catch(() => []);
|
|
966
|
+
const jsonlFiles = files.filter((file) => file.endsWith(".jsonl")).sort().slice(-3);
|
|
967
|
+
const records = [];
|
|
968
|
+
for (const file of jsonlFiles) {
|
|
969
|
+
const content = await fs7.readFile(path6.join(eventsDir, file), "utf8").catch(() => "");
|
|
970
|
+
for (const line of content.split(/\r?\n/)) {
|
|
971
|
+
if (!line.trim()) {
|
|
972
|
+
continue;
|
|
973
|
+
}
|
|
974
|
+
const record = parseObservabilityRecord(line);
|
|
975
|
+
if (!record || record.event !== "tool.output") {
|
|
976
|
+
continue;
|
|
977
|
+
}
|
|
978
|
+
records.push(summarizeToolOutput(record));
|
|
979
|
+
}
|
|
980
|
+
}
|
|
981
|
+
return records.slice(-DEFAULT_RECENT_LIMIT).reverse();
|
|
982
|
+
}
|
|
929
983
|
function parseObservabilityRecord(line) {
|
|
930
984
|
try {
|
|
931
985
|
const parsed = JSON.parse(line);
|
|
@@ -946,6 +1000,25 @@ function summarizeModelRequest(record) {
|
|
|
946
1000
|
usage
|
|
947
1001
|
};
|
|
948
1002
|
}
|
|
1003
|
+
function summarizeToolOutput(record) {
|
|
1004
|
+
const details = record.details ?? {};
|
|
1005
|
+
return {
|
|
1006
|
+
timestamp: record.timestamp,
|
|
1007
|
+
toolName: record.toolName,
|
|
1008
|
+
kind: readString(details.kind),
|
|
1009
|
+
mode: readString(details.mode),
|
|
1010
|
+
rawChars: readNumber(details.rawChars),
|
|
1011
|
+
projectedChars: readNumber(details.projectedChars),
|
|
1012
|
+
rawTokens: readNumber(details.rawTokens),
|
|
1013
|
+
projectedTokens: readNumber(details.projectedTokens),
|
|
1014
|
+
savedTokens: readNumber(details.savedTokens),
|
|
1015
|
+
savingsRatio: readNumber(details.savingsRatio),
|
|
1016
|
+
truncated: details.truncated === true,
|
|
1017
|
+
outputPath: readString(details.outputPath),
|
|
1018
|
+
degraded: details.degraded === true,
|
|
1019
|
+
reason: readString(details.reason)
|
|
1020
|
+
};
|
|
1021
|
+
}
|
|
949
1022
|
function readUsageSummary(value) {
|
|
950
1023
|
if (!value || typeof value !== "object") {
|
|
951
1024
|
return void 0;
|
|
@@ -967,6 +1040,9 @@ function readUsageSummary(value) {
|
|
|
967
1040
|
function readNumber(value) {
|
|
968
1041
|
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
969
1042
|
}
|
|
1043
|
+
function readString(value) {
|
|
1044
|
+
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
1045
|
+
}
|
|
970
1046
|
function summarizeSkills(skills) {
|
|
971
1047
|
const summaries = skills.map((skill) => ({
|
|
972
1048
|
name: skill.name,
|
|
@@ -1062,11 +1138,15 @@ function formatRuntimeStatusText(status) {
|
|
|
1062
1138
|
lines.push(`- Skills: ${status.scene.skills.ready}/${status.scene.skills.total} ready; ${status.scene.skills.nextAction}`);
|
|
1063
1139
|
lines.push(`- Memory: ${status.scene.memory.assets} asset(s), session=${status.scene.memory.latestSessionMemory ? "yes" : "no"}; ${status.scene.memory.nextAction}`);
|
|
1064
1140
|
lines.push(`- Cost: ${status.scene.cost}`);
|
|
1141
|
+
lines.push(`- Tool output: ${status.scene.toolOutputs}`);
|
|
1065
1142
|
lines.push(`- Recovery: ${status.scene.recovery}`);
|
|
1066
1143
|
lines.push("");
|
|
1067
1144
|
lines.push("Current workspace:");
|
|
1068
1145
|
lines.push(`- Focus: ${status.scene.focus}`);
|
|
1069
1146
|
lines.push(`- Session: ${readSessionLine(status)}`);
|
|
1147
|
+
if (status.sessions.skipped > 0) {
|
|
1148
|
+
lines.push(`- Sessions: ${status.sessions.total} total, ${status.sessions.skipped} skipped`);
|
|
1149
|
+
}
|
|
1070
1150
|
lines.push(`- Next: ${status.scene.nextAction}`);
|
|
1071
1151
|
lines.push(`- Blocked: ${status.scene.blocked}`);
|
|
1072
1152
|
lines.push(`- Context budget: ${readContextBudgetLine(status)}`);
|
|
@@ -1173,9 +1253,27 @@ function formatRuntimeStatusText(status) {
|
|
|
1173
1253
|
].filter(Boolean).join(" "));
|
|
1174
1254
|
}
|
|
1175
1255
|
}
|
|
1176
|
-
if (status.
|
|
1256
|
+
if (status.toolOutputs.recent.length > 0) {
|
|
1257
|
+
lines.push("");
|
|
1258
|
+
lines.push("Recent tool output:");
|
|
1259
|
+
for (const output of status.toolOutputs.recent.slice(0, 5)) {
|
|
1260
|
+
lines.push([
|
|
1261
|
+
output.toolName ?? "tool",
|
|
1262
|
+
output.kind ? `kind=${output.kind}` : void 0,
|
|
1263
|
+
output.mode ? `mode=${output.mode}` : void 0,
|
|
1264
|
+
output.rawTokens === void 0 ? void 0 : `raw=${output.rawTokens}`,
|
|
1265
|
+
output.projectedTokens === void 0 ? void 0 : `projected=${output.projectedTokens}`,
|
|
1266
|
+
output.savedTokens === void 0 ? void 0 : `saved=${output.savedTokens}`,
|
|
1267
|
+
output.savingsRatio === void 0 ? void 0 : `savedRatio=${Math.round(output.savingsRatio * 100)}%`,
|
|
1268
|
+
output.truncated ? "recoverable=yes" : void 0,
|
|
1269
|
+
output.degraded ? "degraded=yes" : void 0,
|
|
1270
|
+
output.outputPath ? `full=${truncateCliValue(output.outputPath, 80)}` : void 0
|
|
1271
|
+
].filter(Boolean).join(" "));
|
|
1272
|
+
}
|
|
1273
|
+
}
|
|
1274
|
+
if (status.scene.executions.length > 0) {
|
|
1177
1275
|
lines.push("");
|
|
1178
|
-
lines.push("
|
|
1276
|
+
lines.push("Scene executions:");
|
|
1179
1277
|
for (const execution of status.scene.executions) {
|
|
1180
1278
|
lines.push([
|
|
1181
1279
|
execution.id,
|
|
@@ -1034,6 +1034,7 @@ function buildToolBlock() {
|
|
|
1034
1034
|
function buildCommunicationBlock() {
|
|
1035
1035
|
return [
|
|
1036
1036
|
"Always reply in Simplified Chinese.",
|
|
1037
|
+
"No Markdown in user-facing conversational replies; prefer plain text whenever possible.",
|
|
1037
1038
|
"Provide concise progress updates during multi-step work.",
|
|
1038
1039
|
"Make every sentence carry decision, execution, evidence, or understanding.",
|
|
1039
1040
|
"Claim changed files, passed commands, and successful tools only when tool evidence supports them.",
|
|
@@ -3225,6 +3226,9 @@ var DIFF_MAX_CHARS = 3e3;
|
|
|
3225
3226
|
var OUTPUT_MAX_CHARS = 1500;
|
|
3226
3227
|
var SKILL_BODY_MAX_CHARS = 16e3;
|
|
3227
3228
|
function projectToolResultForModel(input) {
|
|
3229
|
+
if (input.result.metadata?.outputGovernance) {
|
|
3230
|
+
return input.result.metadata.outputGovernance.projection;
|
|
3231
|
+
}
|
|
3228
3232
|
const parsed = parseObject(input.result.output);
|
|
3229
3233
|
if (!input.result.ok) {
|
|
3230
3234
|
return projectFailure(input.toolName, input.result.output, parsed);
|
|
@@ -3328,6 +3332,11 @@ function projectWrite(payload) {
|
|
|
3328
3332
|
]);
|
|
3329
3333
|
}
|
|
3330
3334
|
function projectBash(payload) {
|
|
3335
|
+
const governance = readObject(payload.outputGovernance);
|
|
3336
|
+
const projection = readString(governance?.projection);
|
|
3337
|
+
if (projection) {
|
|
3338
|
+
return projection;
|
|
3339
|
+
}
|
|
3331
3340
|
const exitCode = readNumber(payload.exitCode);
|
|
3332
3341
|
const durationMs = readNumber(payload.durationMs);
|
|
3333
3342
|
const status = readString(payload.status);
|
|
@@ -4320,6 +4329,251 @@ function pathDepth(relativePath) {
|
|
|
4320
4329
|
return relativePath.split("/").filter(Boolean).length;
|
|
4321
4330
|
}
|
|
4322
4331
|
|
|
4332
|
+
// src/tools/outputKernel/classifier.ts
|
|
4333
|
+
function classifyToolOutput(source) {
|
|
4334
|
+
const output = source.output.trim();
|
|
4335
|
+
if (!output) {
|
|
4336
|
+
return "empty";
|
|
4337
|
+
}
|
|
4338
|
+
const command = (source.command ?? "").toLowerCase();
|
|
4339
|
+
const text = output.toLowerCase();
|
|
4340
|
+
if (looksLikeGitDiff(command, text)) {
|
|
4341
|
+
return "git_diff";
|
|
4342
|
+
}
|
|
4343
|
+
if (looksLikeSearch(command)) {
|
|
4344
|
+
return "search";
|
|
4345
|
+
}
|
|
4346
|
+
if (looksLikeTypecheck(command, text)) {
|
|
4347
|
+
return "typecheck";
|
|
4348
|
+
}
|
|
4349
|
+
if (looksLikeTest(command, text)) {
|
|
4350
|
+
return "test";
|
|
4351
|
+
}
|
|
4352
|
+
if (looksLikeBuild(command, text)) {
|
|
4353
|
+
return "build";
|
|
4354
|
+
}
|
|
4355
|
+
return "generic";
|
|
4356
|
+
}
|
|
4357
|
+
function looksLikeGitDiff(command, text) {
|
|
4358
|
+
return /\bgit\s+(diff|show)\b/.test(command) || text.includes("diff --git ");
|
|
4359
|
+
}
|
|
4360
|
+
function looksLikeSearch(command) {
|
|
4361
|
+
return /(^|\s)(rg|grep)(\s|$)/.test(command);
|
|
4362
|
+
}
|
|
4363
|
+
function looksLikeTypecheck(command, text) {
|
|
4364
|
+
return /\b(tsc|typecheck|mypy)\b/.test(command) || /\b(error|warning)\s+ts\d+:/i.test(text);
|
|
4365
|
+
}
|
|
4366
|
+
function looksLikeTest(command, text) {
|
|
4367
|
+
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);
|
|
4368
|
+
}
|
|
4369
|
+
function looksLikeBuild(command, text) {
|
|
4370
|
+
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);
|
|
4371
|
+
}
|
|
4372
|
+
|
|
4373
|
+
// src/tools/outputKernel/metrics.ts
|
|
4374
|
+
function estimateTextTokens(value) {
|
|
4375
|
+
const trimmed = value.trim();
|
|
4376
|
+
if (!trimmed) {
|
|
4377
|
+
return 0;
|
|
4378
|
+
}
|
|
4379
|
+
return Math.max(1, Math.ceil(trimmed.length / 4));
|
|
4380
|
+
}
|
|
4381
|
+
function computeSavings(input) {
|
|
4382
|
+
const rawChars = input.raw.length;
|
|
4383
|
+
const projectedChars = input.projected.length;
|
|
4384
|
+
const rawTokens = estimateTextTokens(input.raw);
|
|
4385
|
+
const projectedTokens = estimateTextTokens(input.projected);
|
|
4386
|
+
const savedTokens = Math.max(0, rawTokens - projectedTokens);
|
|
4387
|
+
const savingsRatio = rawTokens > 0 ? Math.round(savedTokens / rawTokens * 1e4) / 1e4 : 0;
|
|
4388
|
+
return {
|
|
4389
|
+
rawChars,
|
|
4390
|
+
projectedChars,
|
|
4391
|
+
rawTokens,
|
|
4392
|
+
projectedTokens,
|
|
4393
|
+
savedTokens,
|
|
4394
|
+
savingsRatio
|
|
4395
|
+
};
|
|
4396
|
+
}
|
|
4397
|
+
|
|
4398
|
+
// src/tools/outputKernel/projectors/shared.ts
|
|
4399
|
+
function buildHeader(source, label) {
|
|
4400
|
+
return [
|
|
4401
|
+
`${source.toolName}: ${label}`,
|
|
4402
|
+
source.exitCode === void 0 ? void 0 : `exit=${source.exitCode ?? "null"}`,
|
|
4403
|
+
source.durationMs === void 0 ? void 0 : `duration=${source.durationMs}ms`,
|
|
4404
|
+
source.status ? `status=${source.status}` : void 0
|
|
4405
|
+
].filter(Boolean).join(" ");
|
|
4406
|
+
}
|
|
4407
|
+
function splitOutputLines(value) {
|
|
4408
|
+
return value.split(/\r?\n/).map((line) => line.trimEnd());
|
|
4409
|
+
}
|
|
4410
|
+
function dedupeProjectedLines(lines) {
|
|
4411
|
+
const seen = /* @__PURE__ */ new Set();
|
|
4412
|
+
const result = [];
|
|
4413
|
+
for (const rawLine of lines) {
|
|
4414
|
+
const line = truncateText(rawLine.trim(), 260);
|
|
4415
|
+
if (!line || seen.has(line)) {
|
|
4416
|
+
continue;
|
|
4417
|
+
}
|
|
4418
|
+
seen.add(line);
|
|
4419
|
+
result.push(line);
|
|
4420
|
+
}
|
|
4421
|
+
return result;
|
|
4422
|
+
}
|
|
4423
|
+
|
|
4424
|
+
// src/tools/outputKernel/projectors/diagnostic.ts
|
|
4425
|
+
var STRUCTURED_MAX_LINES = 28;
|
|
4426
|
+
function buildDiagnosticProjection(source, label) {
|
|
4427
|
+
const lines = splitOutputLines(source.output);
|
|
4428
|
+
const evidence = lines.filter(isDiagnosticEvidenceLine).slice(0, STRUCTURED_MAX_LINES);
|
|
4429
|
+
const summaryLines = lines.filter(isSummaryLine).slice(0, 8);
|
|
4430
|
+
return dedupeProjectedLines([
|
|
4431
|
+
buildHeader(source, label),
|
|
4432
|
+
...summaryLines,
|
|
4433
|
+
...evidence
|
|
4434
|
+
]).join("\n");
|
|
4435
|
+
}
|
|
4436
|
+
function isDiagnosticEvidenceLine(line) {
|
|
4437
|
+
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);
|
|
4438
|
+
}
|
|
4439
|
+
function isSummaryLine(line) {
|
|
4440
|
+
return /\b(\d+\s+(passed|failed|skipped|errors?|warnings?)|test result|found \d+ errors?|failed tests?|build failed|compiled successfully)\b/i.test(line);
|
|
4441
|
+
}
|
|
4442
|
+
|
|
4443
|
+
// src/tools/outputKernel/projectors/gitDiff.ts
|
|
4444
|
+
var DIFF_MAX_FILES = 24;
|
|
4445
|
+
function buildGitDiffProjection(source) {
|
|
4446
|
+
const lines = splitOutputLines(source.output);
|
|
4447
|
+
const files = lines.filter((line) => line.startsWith("diff --git ")).map((line) => line.replace(/^diff --git a\//, "").replace(/ b\//, " -> ")).slice(0, DIFF_MAX_FILES);
|
|
4448
|
+
const stats = lines.filter((line) => /(\d+ files? changed|\d+ insertions?\(\+\)|\d+ deletions?\(-\))/.test(line)).slice(0, 8);
|
|
4449
|
+
const hunks = lines.filter((line) => line.startsWith("@@") || line.startsWith("+++ ") || line.startsWith("--- ")).slice(0, 18).map((line) => truncateText(line, 220));
|
|
4450
|
+
return [
|
|
4451
|
+
buildHeader(source, "git diff"),
|
|
4452
|
+
files.length > 0 ? `files: ${files.join(", ")}` : void 0,
|
|
4453
|
+
...stats,
|
|
4454
|
+
...hunks
|
|
4455
|
+
].filter((line) => Boolean(line)).join("\n");
|
|
4456
|
+
}
|
|
4457
|
+
|
|
4458
|
+
// src/tools/outputKernel/projectors/generic.ts
|
|
4459
|
+
var GENERIC_MAX_CHARS = 1500;
|
|
4460
|
+
function projectEmptyOutput(source) {
|
|
4461
|
+
return {
|
|
4462
|
+
mode: "empty",
|
|
4463
|
+
projection: buildHeader(source, "no output"),
|
|
4464
|
+
degraded: false,
|
|
4465
|
+
reason: "empty_output"
|
|
4466
|
+
};
|
|
4467
|
+
}
|
|
4468
|
+
function projectGenericOutput(source, reason = "generic_output") {
|
|
4469
|
+
return {
|
|
4470
|
+
mode: "generic",
|
|
4471
|
+
projection: buildGenericPreview(source),
|
|
4472
|
+
degraded: false,
|
|
4473
|
+
reason
|
|
4474
|
+
};
|
|
4475
|
+
}
|
|
4476
|
+
function projectStructuredOutput(source, body) {
|
|
4477
|
+
const trimmed = body.trim();
|
|
4478
|
+
if (!trimmed) {
|
|
4479
|
+
return {
|
|
4480
|
+
mode: "generic",
|
|
4481
|
+
projection: buildGenericPreview(source),
|
|
4482
|
+
degraded: true,
|
|
4483
|
+
reason: "structured_projection_empty"
|
|
4484
|
+
};
|
|
4485
|
+
}
|
|
4486
|
+
return {
|
|
4487
|
+
mode: "structured",
|
|
4488
|
+
projection: trimmed,
|
|
4489
|
+
degraded: false,
|
|
4490
|
+
reason: "structured_projection"
|
|
4491
|
+
};
|
|
4492
|
+
}
|
|
4493
|
+
function buildGenericPreview(source) {
|
|
4494
|
+
return [
|
|
4495
|
+
buildHeader(source, "output"),
|
|
4496
|
+
truncateText(source.output.trim(), GENERIC_MAX_CHARS)
|
|
4497
|
+
].filter(Boolean).join("\n");
|
|
4498
|
+
}
|
|
4499
|
+
|
|
4500
|
+
// src/tools/outputKernel/projectors/search.ts
|
|
4501
|
+
var SEARCH_MAX_MATCHES = 24;
|
|
4502
|
+
function buildSearchProjection(source) {
|
|
4503
|
+
const nonEmptyLines = splitOutputLines(source.output).filter((line) => line.trim().length > 0);
|
|
4504
|
+
const matches = nonEmptyLines.slice(0, SEARCH_MAX_MATCHES).map((line) => truncateText(line, 220));
|
|
4505
|
+
const omitted = Math.max(0, nonEmptyLines.length - matches.length);
|
|
4506
|
+
return [
|
|
4507
|
+
buildHeader(source, "search"),
|
|
4508
|
+
`matches shown: ${matches.length}${omitted > 0 ? `, omitted: ${omitted}` : ""}`,
|
|
4509
|
+
...matches
|
|
4510
|
+
].join("\n");
|
|
4511
|
+
}
|
|
4512
|
+
|
|
4513
|
+
// src/tools/outputKernel/projectors/recovery.ts
|
|
4514
|
+
function appendRecoveryHint(projection, governance) {
|
|
4515
|
+
if (!governance.recoveryHint) {
|
|
4516
|
+
return projection;
|
|
4517
|
+
}
|
|
4518
|
+
if (projection.includes(governance.recoveryHint)) {
|
|
4519
|
+
return projection;
|
|
4520
|
+
}
|
|
4521
|
+
return `${projection.trimEnd()}
|
|
4522
|
+
${governance.recoveryHint}`;
|
|
4523
|
+
}
|
|
4524
|
+
|
|
4525
|
+
// src/tools/outputKernel/projectors.ts
|
|
4526
|
+
function projectOutputByKind(kind, source) {
|
|
4527
|
+
switch (kind) {
|
|
4528
|
+
case "empty":
|
|
4529
|
+
return projectEmptyOutput(source);
|
|
4530
|
+
case "test":
|
|
4531
|
+
return projectStructuredOutput(source, buildDiagnosticProjection(source, "test"));
|
|
4532
|
+
case "build":
|
|
4533
|
+
return projectStructuredOutput(source, buildDiagnosticProjection(source, "build"));
|
|
4534
|
+
case "typecheck":
|
|
4535
|
+
return projectStructuredOutput(source, buildDiagnosticProjection(source, "typecheck"));
|
|
4536
|
+
case "search":
|
|
4537
|
+
return projectStructuredOutput(source, buildSearchProjection(source));
|
|
4538
|
+
case "git_diff":
|
|
4539
|
+
return projectStructuredOutput(source, buildGitDiffProjection(source));
|
|
4540
|
+
case "generic":
|
|
4541
|
+
return projectGenericOutput(source);
|
|
4542
|
+
}
|
|
4543
|
+
}
|
|
4544
|
+
|
|
4545
|
+
// src/tools/outputKernel/index.ts
|
|
4546
|
+
function governToolOutput(source) {
|
|
4547
|
+
const kind = classifyToolOutput(source);
|
|
4548
|
+
const projected = projectOutputByKind(kind, source);
|
|
4549
|
+
const recoveryHint = source.outputPath ? `[full output: ${source.outputPath}]` : void 0;
|
|
4550
|
+
const projection = appendRecoveryHint(projected.projection, {
|
|
4551
|
+
outputPath: source.outputPath,
|
|
4552
|
+
recoveryHint
|
|
4553
|
+
});
|
|
4554
|
+
const metrics = computeSavings({
|
|
4555
|
+
raw: source.output,
|
|
4556
|
+
projected: projection
|
|
4557
|
+
});
|
|
4558
|
+
return {
|
|
4559
|
+
version: 1,
|
|
4560
|
+
kind,
|
|
4561
|
+
mode: projected.mode,
|
|
4562
|
+
projection,
|
|
4563
|
+
rawChars: source.outputChars ?? metrics.rawChars,
|
|
4564
|
+
projectedChars: metrics.projectedChars,
|
|
4565
|
+
rawTokens: metrics.rawTokens,
|
|
4566
|
+
projectedTokens: metrics.projectedTokens,
|
|
4567
|
+
savedTokens: metrics.savedTokens,
|
|
4568
|
+
savingsRatio: metrics.savingsRatio,
|
|
4569
|
+
truncated: Boolean(source.truncated),
|
|
4570
|
+
outputPath: source.outputPath,
|
|
4571
|
+
recoveryHint,
|
|
4572
|
+
degraded: projected.degraded,
|
|
4573
|
+
reason: projected.reason
|
|
4574
|
+
};
|
|
4575
|
+
}
|
|
4576
|
+
|
|
4323
4577
|
// src/tools/bash.ts
|
|
4324
4578
|
var SHELL_RUNTIME = getShellRuntimeInfo();
|
|
4325
4579
|
var bashToolDefinition = {
|
|
@@ -4369,6 +4623,18 @@ var bashToolDefinition = {
|
|
|
4369
4623
|
}
|
|
4370
4624
|
});
|
|
4371
4625
|
const status = result.aborted ? "aborted" : result.stalled ? "stalled" : result.timedOut ? "timed_out" : result.exitCode === 0 ? "completed" : "failed";
|
|
4626
|
+
const outputGovernance = governToolOutput({
|
|
4627
|
+
toolName: "bash",
|
|
4628
|
+
command,
|
|
4629
|
+
status,
|
|
4630
|
+
exitCode: result.exitCode,
|
|
4631
|
+
durationMs: result.durationMs,
|
|
4632
|
+
output: result.output,
|
|
4633
|
+
outputPath: result.outputPath,
|
|
4634
|
+
truncated: result.truncated,
|
|
4635
|
+
outputChars: result.outputChars,
|
|
4636
|
+
outputBytes: result.outputBytes
|
|
4637
|
+
});
|
|
4372
4638
|
const metadata = {
|
|
4373
4639
|
runtime: {
|
|
4374
4640
|
status,
|
|
@@ -4381,7 +4647,8 @@ var bashToolDefinition = {
|
|
|
4381
4647
|
truncated: result.truncated,
|
|
4382
4648
|
outputPath: result.outputPath,
|
|
4383
4649
|
outputPreview: result.output
|
|
4384
|
-
}
|
|
4650
|
+
},
|
|
4651
|
+
outputGovernance
|
|
4385
4652
|
};
|
|
4386
4653
|
return okResult(
|
|
4387
4654
|
JSON.stringify(
|
|
@@ -4396,6 +4663,7 @@ var bashToolDefinition = {
|
|
|
4396
4663
|
outputPath: result.outputPath,
|
|
4397
4664
|
outputChars: result.outputChars,
|
|
4398
4665
|
outputBytes: result.outputBytes,
|
|
4666
|
+
outputGovernance,
|
|
4399
4667
|
output: truncateText(result.output, 4e3),
|
|
4400
4668
|
...status === "completed" ? {} : {
|
|
4401
4669
|
shell: shell.shell,
|
|
@@ -5916,6 +6184,31 @@ async function processToolCallBatch(input) {
|
|
|
5916
6184
|
changedPathCount: metadata?.changedPaths?.length ?? 0
|
|
5917
6185
|
}
|
|
5918
6186
|
});
|
|
6187
|
+
if (metadata?.outputGovernance) {
|
|
6188
|
+
await recordObservabilityEvent(projectContext.stateRootDir, {
|
|
6189
|
+
event: "tool.output",
|
|
6190
|
+
status: result.ok ? "completed" : "failed",
|
|
6191
|
+
sessionId: session.id,
|
|
6192
|
+
identityKind: identity.kind,
|
|
6193
|
+
identityName: identity.name,
|
|
6194
|
+
toolName: toolCall.function.name,
|
|
6195
|
+
durationMs,
|
|
6196
|
+
details: {
|
|
6197
|
+
kind: metadata.outputGovernance.kind,
|
|
6198
|
+
mode: metadata.outputGovernance.mode,
|
|
6199
|
+
rawChars: metadata.outputGovernance.rawChars,
|
|
6200
|
+
projectedChars: metadata.outputGovernance.projectedChars,
|
|
6201
|
+
rawTokens: metadata.outputGovernance.rawTokens,
|
|
6202
|
+
projectedTokens: metadata.outputGovernance.projectedTokens,
|
|
6203
|
+
savedTokens: metadata.outputGovernance.savedTokens,
|
|
6204
|
+
savingsRatio: metadata.outputGovernance.savingsRatio,
|
|
6205
|
+
truncated: metadata.outputGovernance.truncated,
|
|
6206
|
+
outputPath: metadata.outputGovernance.outputPath,
|
|
6207
|
+
degraded: metadata.outputGovernance.degraded,
|
|
6208
|
+
reason: metadata.outputGovernance.reason
|
|
6209
|
+
}
|
|
6210
|
+
});
|
|
6211
|
+
}
|
|
5919
6212
|
if (result.ok) {
|
|
5920
6213
|
options.callbacks?.onToolResult?.(toolCall.function.name, result.output);
|
|
5921
6214
|
} else {
|