feat: consolidated and automate changelog management

- Added `rewrite-changelog.ts` and `fix-changelogs.ts` utilities to automate the consolidation of release notes using LLM-assisted processing.
- Updated multiple internal changelog files by consolidating redundant entries and improving phrasing for readability.
- Implemented `previewLine` utility in `coding-agent` to prevent visual spillover in status rows by managing text truncation and whitespace.
- Updated `package.json` with new workflow scripts for managing package-level change histories and documentation indexes.
This commit is contained in:
can1357
2026-06-27 03:08:52 +02:00
parent 3345085290
commit 5a044dc0da
49 changed files with 2219 additions and 1823 deletions
@@ -9,7 +9,7 @@ import { SessionManager } from "../../session/session-manager";
import templateCss from "./template.css" with { type: "text" };
import templateHtml from "./template.html" with { type: "text" };
import templateJs from "./template.js" with { type: "text" };
// Pre-built React tool renderers: built by `bun --cwd=packages/collab-web run build:tool-views`,
// Pre-built React tool renderers: built by `gen:tool-views` (`bun run gen:tool-views`),
// run automatically by root `prepare` on install and by `prepack` at publish.
import toolViewsJs from "./tool-views.generated.js" with { type: "text" };
import { webExportThemeVars } from "./web-palette";
@@ -2,8 +2,7 @@
* Harness documentation index for the `omp://` protocol.
*
* Compiled binaries and the prepacked npm bundle inline a compressed index from
* `docs-index.generated.txt` (populated by `scripts/generate-docs-index.ts
* --generate` at build time). The format is two lines:
* `docs-index.generated.txt` (populated by `gen:docs` at build time). The format is two lines:
* 1. a plain JSON array of the sorted doc file names, and
* 2. a base64 gzip blob of the index-aligned doc bodies (`string[]`).
* Listing/completion (`getDocFilenames`) parses only the small first line and
@@ -84,7 +83,7 @@ function getIndex(): DocsIndex {
if (decoded === null) {
throw new Error(
"Malformed embedded docs index (docs-index.generated.txt): non-empty payload without a newline separator. " +
"Rebuild with `bun --cwd=packages/coding-agent scripts/generate-docs-index.ts --generate`.",
"Rebuild with `bun run gen:docs`.",
);
}
index = decoded;
+8 -9
View File
@@ -18,6 +18,7 @@ import {
formatExpandHint,
formatMoreItems,
formatStatusIcon,
previewLine,
replaceTabs,
type ToolUIStatus,
truncateToWidth,
@@ -749,7 +750,7 @@ function renderAgentProgress(
const showBadge = settings.get("task.showResolvedModelBadge");
if (progress.status === "running") {
if (!description) {
const taskPreview = truncateToWidth(progress.assignment ?? progress.task, 40);
const taskPreview = previewLine(progress.assignment ?? progress.task, 40);
statusLine += ` ${theme.fg("muted", taskPreview)}`;
}
statusLine = appendAgentStats(statusLine, { ...progress, showResolvedModelBadge: showBadge }, theme);
@@ -767,7 +768,7 @@ function renderAgentProgress(
let toolLine = `${continuePrefix}${theme.tree.hook} ${theme.fg("muted", progress.currentTool)}`;
const toolDetail = progress.lastIntent ?? progress.currentToolArgs;
if (toolDetail) {
toolLine += `: ${theme.fg("dim", truncateToWidth(replaceTabs(toolDetail), 40))}`;
toolLine += `: ${theme.fg("dim", previewLine(toolDetail, 40))}`;
}
if (progress.currentToolStartMs) {
const elapsed = Date.now() - progress.currentToolStartMs;
@@ -782,7 +783,7 @@ function renderAgentProgress(
let toolLine = `${continuePrefix}${theme.tree.hook} ${theme.fg("dim", recent.tool)}`;
const toolDetail = progress.lastIntent ?? recent.args;
if (toolDetail) {
toolLine += `: ${theme.fg("dim", truncateToWidth(replaceTabs(toolDetail), 40))}`;
toolLine += `: ${theme.fg("dim", previewLine(toolDetail, 40))}`;
}
lines.push(toolLine);
}
@@ -796,12 +797,12 @@ function renderAgentProgress(
const waitLabel = remainingMs > 0 ? `in ${formatDuration(remainingMs)}` : "now";
const summary =
`retrying ${progress.retryState.attempt}/${progress.retryState.maxAttempts} ${waitLabel}: ` +
truncateToWidth(replaceTabs(progress.retryState.errorMessage), 60);
previewLine(progress.retryState.errorMessage, 60);
lines.push(`${continuePrefix}${theme.tree.hook} ${theme.fg("warning", summary)}`);
} else if (progress.retryFailure && progress.status !== "running") {
const summary = `auto-retry gave up after ${progress.retryFailure.attempt} attempt${
progress.retryFailure.attempt === 1 ? "" : "s"
}: ${truncateToWidth(replaceTabs(progress.retryFailure.errorMessage), 80)}`;
}: ${previewLine(progress.retryFailure.errorMessage, 80)}`;
lines.push(`${continuePrefix}${theme.tree.hook} ${theme.fg("error", summary)}`);
}
@@ -1064,7 +1065,7 @@ function renderAgentResult(
if (aborted && result.abortReason) {
lines.push(
`${continuePrefix}${theme.fg("error", theme.status.aborted)} ${theme.fg("dim", truncateToWidth(replaceTabs(result.abortReason), 80))}`,
`${continuePrefix}${theme.fg("error", theme.status.aborted)} ${theme.fg("dim", previewLine(result.abortReason, 80))}`,
);
}
// Check for review result (yield with review schema + report_finding)
@@ -1176,9 +1177,7 @@ function renderAgentResult(
// Error message
if (result.error && (!success || mergeFailed) && (!aborted || result.error !== result.abortReason)) {
lines.push(
`${continuePrefix}${theme.fg(mergeFailed ? "warning" : "error", truncateToWidth(replaceTabs(result.error), 70))}`,
);
lines.push(`${continuePrefix}${theme.fg(mergeFailed ? "warning" : "error", previewLine(result.error, 70))}`);
}
return lines;
@@ -99,6 +99,17 @@ export function getPreviewLines(text: string, maxLines: number, maxLineLen: numb
return lines.slice(0, maxLines).map(l => truncateToWidth(l.trim(), maxLineLen, ellipsis));
}
/**
* Collapse a possibly multi-line string into a single line, then truncate it to
* `maxWidth` display cells. {@link truncateToWidth} alone caps width but
* newlines are zero-width, so multi-line content (markdown briefs, tool args,
* provider errors) would otherwise spill a single status row across several
* visual lines. Whitespace runs collapse to one space, so tabs are handled too.
*/
export function previewLine(text: string, maxWidth: number, ellipsis?: Ellipsis): string {
return truncateToWidth(text.replace(/\s+/g, " ").trim(), maxWidth, ellipsis);
}
// =============================================================================
// URL Utilities
// =============================================================================