Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 32 additions & 4 deletions plugins/codex-zcode-bridge/dist/bridge.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -26069,6 +26069,29 @@ function displayText(value, limit) {
function oneLine(value, limit) {
return displayText(value.replace(/\s+/gu, " "), limit);
}
function truncatedOneLine(value, limit) {
const text = oneLine(value, limit + 1);
return text.length > limit ? `${text.slice(0, limit - 1).trimEnd()}\u2026` : text;
}
function testCommandLabel(value) {
let command = oneLine(value, 2e3);
const segments = command.split(/\s*&&\s*/u);
if (segments.length > 1) command = segments.at(-1) ?? command;
command = command.replace(/^['"]+|['"]+$/gu, "").trim();
const dotnet = command.match(/\bdotnet\s+test\s+([^\s]+)(.*)$/iu);
if (dotnet) {
const project = (dotnet[1] ?? "").split(/[\\/]/u).at(-1)?.replace(/\.csproj$/iu, "") ?? "project";
const filterTail = dotnet[2]?.match(/--filter(?:=|\s+)(.+)$/iu)?.[1]?.replace(/["']+$/gu, "").trim();
const filter = filterTail?.includes("~") ? filterTail.slice(filterTail.lastIndexOf("~") + 1) : filterTail;
return `dotnet test ${project}${filter ? ` \xB7 filter ${oneLine(filter, 64)}` : ""}`;
}
const packageScript = command.match(/\b(npm|pnpm|yarn)\s+(?:(run)\s+)?([A-Za-z0-9:_-]+)\b/iu);
if (packageScript) {
return `${packageScript[1]} ${packageScript[2] ? "run " : ""}${packageScript[3]}`;
}
const tokens = command.match(/(?:"[^"]*"|'[^']*'|[^\s]+)/gu) ?? [];
return tokens.slice(0, 2).map((token) => token.replace(/^['"]|['"]$/gu, "")).join(" ").slice(0, 96);
}
function renderTaskFeedback(snapshot) {
const terminalLabel = snapshot.status === "waiting_for_master" ? "WAITING_FOR_MASTER" : ["completed", "failed", "cancelled"].includes(snapshot.status) ? snapshot.status.toUpperCase() : null;
const lines = [`\u25A3 ZCode \xB7 ${snapshot.task_id}${terminalLabel ? ` \xB7 ${terminalLabel}` : ""}`];
Expand Down Expand Up @@ -26101,14 +26124,19 @@ function renderTaskFeedback(snapshot) {
const result = snapshot.result;
if (result) {
lines.push("", "Agent report:");
const summary = oneLine(result.summary, 800);
const summary = truncatedOneLine(result.summary, 220);
if (summary) lines.push(summary);
lines.push(`Changed: ${result.files_changed.length} files`);
const changedCount = result.files_changed.length;
lines.push(`Changed: ${changedCount} ${changedCount === 1 ? "file" : "files"}`);
for (const test of result.tests.slice(0, 3)) {
lines.push(`Tests: ${oneLine(test.command, 240)} \xB7 reported ${test.status}`);
lines.push(`Tests: ${testCommandLabel(test.command)} \xB7 reported ${test.status}`);
}
if (result.tests.length > 3) lines.push(`Tests: ${result.tests.length - 3} more reported`);
if (result.issues.length) lines.push(`Issues: ${result.issues.length} reported`);
if (result.issues.length) {
const issue2 = truncatedOneLine(result.issues[0] ?? "", 140);
lines.push(`! ${result.issues.length} reported ${result.issues.length === 1 ? "issue" : "issues"}${issue2 ? ` \xB7 ${issue2}` : ""}`);
if (result.issues.length > 1) lines.push(`! ${result.issues.length - 1} more reported issues`);
}
if (result.duration_ms !== null) lines.push(`Duration: ${formatDuration(result.duration_ms)}`);
}
return lines.join("\n");
Expand Down
47 changes: 43 additions & 4 deletions src/feedback/renderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,40 @@ function oneLine(value: string, limit: number): string {
return displayText(value.replace(/\s+/gu, " "), limit);
}

function truncatedOneLine(value: string, limit: number): string {
const text = oneLine(value, limit + 1);
return text.length > limit ? `${text.slice(0, limit - 1).trimEnd()}…` : text;
}

function testCommandLabel(value: string): string {
let command = oneLine(value, 2_000);

// Host shells often wrap the actual test command with environment setup.
// Keep only the final command segment so HOME/TEMP assignments and wrapper
// flags do not dominate the native transcript.
const segments = command.split(/\s*&&\s*/u);
if (segments.length > 1) command = segments.at(-1) ?? command;
command = command.replace(/^['"]+|['"]+$/gu, "").trim();

const dotnet = command.match(/\bdotnet\s+test\s+([^\s]+)(.*)$/iu);
if (dotnet) {
const project = (dotnet[1] ?? "").split(/[\\/]/u).at(-1)?.replace(/\.csproj$/iu, "") ?? "project";
const filterTail = dotnet[2]?.match(/--filter(?:=|\s+)(.+)$/iu)?.[1]?.replace(/["']+$/gu, "").trim();
const filter = filterTail?.includes("~") ? filterTail.slice(filterTail.lastIndexOf("~") + 1) : filterTail;
return `dotnet test ${project}${filter ? ` · filter ${oneLine(filter, 64)}` : ""}`;
}

const packageScript = command.match(/\b(npm|pnpm|yarn)\s+(?:(run)\s+)?([A-Za-z0-9:_-]+)\b/iu);
if (packageScript) {
return `${packageScript[1]} ${packageScript[2] ? "run " : ""}${packageScript[3]}`;
}

// Unknown commands are represented by their executable and first operand;
// avoid echoing arbitrary shell arguments into the user-facing renderer.
const tokens = command.match(/(?:"[^"]*"|'[^']*'|[^\s]+)/gu) ?? [];
return tokens.slice(0, 2).map((token) => token.replace(/^['"]|['"]$/gu, "")).join(" ").slice(0, 96);
}

/** Render the v0.1 snapshot as concise native transcript text. */
export function renderTaskFeedback(snapshot: TaskFeedbackSnapshotV01): string {
const terminalLabel = snapshot.status === "waiting_for_master"
Expand Down Expand Up @@ -50,14 +84,19 @@ export function renderTaskFeedback(snapshot: TaskFeedbackSnapshotV01): string {
const result = snapshot.result;
if (result) {
lines.push("", "Agent report:");
const summary = oneLine(result.summary, 800);
const summary = truncatedOneLine(result.summary, 220);
if (summary) lines.push(summary);
lines.push(`Changed: ${result.files_changed.length} files`);
const changedCount = result.files_changed.length;
lines.push(`Changed: ${changedCount} ${changedCount === 1 ? "file" : "files"}`);
for (const test of result.tests.slice(0, 3)) {
lines.push(`Tests: ${oneLine(test.command, 240)} · reported ${test.status}`);
lines.push(`Tests: ${testCommandLabel(test.command)} · reported ${test.status}`);
}
if (result.tests.length > 3) lines.push(`Tests: ${result.tests.length - 3} more reported`);
if (result.issues.length) lines.push(`Issues: ${result.issues.length} reported`);
if (result.issues.length) {
const issue = truncatedOneLine(result.issues[0] ?? "", 140);
lines.push(`! ${result.issues.length} reported ${result.issues.length === 1 ? "issue" : "issues"}${issue ? ` · ${issue}` : ""}`);
if (result.issues.length > 1) lines.push(`! ${result.issues.length - 1} more reported issues`);
}
if (result.duration_ms !== null) lines.push(`Duration: ${formatDuration(result.duration_ms)}`);
}

Expand Down
26 changes: 25 additions & 1 deletion test/task-feedback.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,12 +125,36 @@ test("renderer labels report claims and avoids unsupported activity or verificat
const output = renderTaskFeedback(snapshot);
assert.match(output, /Bridge task completed/);
assert.match(output, /Agent report:/);
assert.match(output, /Changed: 1 files/);
assert.match(output, /Changed: 1 file/u);
assert.match(output, /npm test · reported passed/);
assert.match(output, /Duration: 3m 42s/);
assert.doesNotMatch(output, /\bverified\b|\baccepted\b|host acceptance|review pass|must not leak/iu);
});

test("renderer shortens wrapped test commands and long report text", () => {
const longSummary = "Monotonic cleanup deadline implemented. ".repeat(12);
const snapshot = buildTaskFeedbackSnapshotV01({
status: status({ status: "completed", finished_at: FINISH }),
events: [event("report_ready")],
result: result({
summary: longSummary,
tests: [{
command: 'cmd.exe /d /s /c "set HOME=C:\\Users\\Sandy&& set TEMP=C:\\Temp&& dotnet test tests\\LumeCAE.RadianceAdapter.Tests\\LumeCAE.RadianceAdapter.Tests.csproj --no-restore --filter FullyQualifiedName~RadianceDeadlineTests"',
status: "passed",
details: "9/9 passed",
}],
issues: ["Git Bash rewrites cmd.exe switches; the command was rerun with MSYS_NO_PATHCONV=1."],
}),
});

const output = renderTaskFeedback(snapshot);
assert.match(output, /dotnet test LumeCAE\.RadianceAdapter\.Tests · filter RadianceDeadlineTests · reported passed/u);
assert.match(output, /! 1 reported issue · Git Bash rewrites cmd\.exe switches/u);
assert.match(output, /…/u);
assert.doesNotMatch(output, /cmd\.exe \/d|HOME=|TEMP=|9\/9 passed/u);
assert.ok(output.length < 600, `expected concise output, got ${output.length} characters`);
});

test("renderer has Bridge-derived text for every task lifecycle status", () => {
const cases = [
["queued", "○ Queued"],
Expand Down
Loading