chore: fix lint baseline

This commit is contained in:
Federico Jaramillo Martinez
2026-05-07 23:43:10 +02:00
parent 1840ab3d7e
commit ef63a7a063
12 changed files with 66 additions and 34 deletions
+17 -4
View File
@@ -356,7 +356,9 @@ function parseFileTreeEntry(value: unknown): FileTreeEntry {
function parseFileContentResponse(value: unknown): FileContentResponse {
const record = requireRecord(value);
return { path: requireString(record, "path"), ...optionalField("language", optionalString(record, "language")), encoding: requireString(record, "encoding") as "utf8", size: requireNumber(record, "size"), modifiedAt: requireString(record, "modifiedAt"), content: requireString(record, "content"), truncated: requireBoolean(record, "truncated"), binary: requireBoolean(record, "binary") };
const encoding = requireString(record, "encoding");
if (encoding !== "utf8") throw new Error("Invalid file encoding");
return { path: requireString(record, "path"), ...optionalField("language", optionalString(record, "language")), encoding, size: requireNumber(record, "size"), modifiedAt: requireString(record, "modifiedAt"), content: requireString(record, "content"), truncated: requireBoolean(record, "truncated"), binary: requireBoolean(record, "binary") };
}
function parseGitStatusResponse(value: unknown): GitStatusResponse {
@@ -370,9 +372,20 @@ function parseGitStatusFile(value: unknown): GitStatusFile {
}
function parseGitFileState(value: unknown): GitFileState {
if (typeof value !== "string") throw new Error("Expected git file state");
if (!["unmodified", "modified", "added", "deleted", "renamed", "copied", "untracked", "ignored", "conflicted"].includes(value)) throw new Error("Invalid git file state");
return value as GitFileState;
switch (value) {
case "unmodified":
case "modified":
case "added":
case "deleted":
case "renamed":
case "copied":
case "untracked":
case "ignored":
case "conflicted":
return value;
default:
throw new Error("Invalid git file state");
}
}
function parseGitDiffResponse(value: unknown): GitDiffResponse {
+1 -1
View File
@@ -36,7 +36,7 @@ export function writeChatHistoryCache(sessionId: string, page: RawMessagePage):
}
export function mergeChatHistory(existing: RawMessagePage | undefined, incoming: RawMessagePage): RawMessagePage {
if (!existing || existing.total !== incoming.total) return incoming;
if (existing?.total !== incoming.total) return incoming;
const start = Math.min(existing.start, incoming.start);
const end = Math.max(existing.start + existing.messages.length, incoming.start + incoming.messages.length);
+3 -3
View File
@@ -26,7 +26,7 @@ export function normalizeMessage(message: unknown): ChatLine[] {
const parts = normalizeContent(getProperty(message, "content"), message);
const skillLines = role === "user" ? normalizeSkillInvocation(parts) : undefined;
if (skillLines !== undefined) return skillLines;
const source = normalizeSource(message, parts);
const source = normalizeSource(message);
if (role === "tool") return [{ role, parts, ...(source === undefined ? {} : { source }) }];
const visible = parts.filter((part) => part.type !== "empty");
@@ -44,7 +44,7 @@ function normalizeSkillInvocation(parts: ChatPart[]): ChatLine[] | undefined {
}
function parseSkillBlock(text: string): { name: string; location: string; content: string; userMessage?: string } | undefined {
const match = text.match(/^<skill name="([^"]+)" location="([^"]+)">\n([\s\S]*?)\n<\/skill>(?:\n\n([\s\S]+))?$/);
const match = /^<skill name="([^"]+)" location="([^"]+)">\n([\s\S]*?)\n<\/skill>(?:\n\n([\s\S]+))?$/.exec(text);
if (match === null) return undefined;
const userMessage = match[4]?.trim();
return {
@@ -55,7 +55,7 @@ function parseSkillBlock(text: string): { name: string; location: string; conten
};
}
function normalizeSource(message: unknown, _parts: ChatPart[]): ChatLine["source"] | undefined {
function normalizeSource(message: unknown): ChatLine["source"] | undefined {
const source = getString(message, "source");
if (source === "compaction" || source === "branch_summary") return source;
return undefined;
+2 -2
View File
@@ -86,11 +86,11 @@ export class ChatView extends LitElement {
const olderCount = this.messageStart;
const fullHistory = olderCount <= 0
? "full history loaded"
: `${olderCount} older not loaded · ${loadedPercent}% loaded`;
: `${String(olderCount)} older not loaded · ${String(loadedPercent)}% loaded`;
return html`
<div class="history-indicator">
<div>${fullHistory}</div>
<div>loaded scroll: ${this.loadedScrollPercent}% from top</div>
<div>loaded scroll: ${String(this.loadedScrollPercent)}% from top</div>
</div>
`;
}
+1
View File
@@ -97,6 +97,7 @@ const viewerTheme = EditorView.theme({
});
function languageExtensions(language: string | undefined): Extension[] {
if (language === undefined) return [];
switch (language) {
case "typescript": return [javascript({ typescript: true })];
case "javascript": return [javascript()];
+9 -7
View File
@@ -149,9 +149,7 @@ export class PiWebApp extends LitElement {
const workspace = this.state.selectedWorkspace;
if (!project || !workspace) return;
if (this.state.expandedDirs[path] !== undefined) {
const next = { ...this.state.expandedDirs };
delete next[path];
this.setState({ expandedDirs: next });
this.setState({ expandedDirs: omitKey(this.state.expandedDirs, path) });
return;
}
try {
@@ -231,7 +229,7 @@ export class PiWebApp extends LitElement {
}
private renderWorkspacePanel() {
return html`<workspace-panel .workspace=${this.state.selectedWorkspace} .tool=${this.state.workspaceTool} .fileTree=${this.state.fileTree} .expandedDirs=${this.state.expandedDirs} .selectedFilePath=${this.state.selectedFilePath} .selectedFileContent=${this.state.selectedFileContent} .fileTreeStale=${this.state.fileTreeStale} .gitStatus=${this.state.gitStatus} .selectedDiffPath=${this.state.selectedDiffPath} .selectedDiff=${this.state.selectedDiff} .gitStale=${this.state.gitStale} .onSelectTool=${(tool: "files" | "git") => this.selectWorkspaceTool(tool)} .onRefreshFiles=${() => this.refreshFiles()} .onExpandDir=${(path: string) => this.expandDir(path)} .onSelectFile=${(path: string) => this.selectFile(path)} .onRefreshGit=${() => this.refreshGit()} .onSelectDiff=${(path: string) => this.selectDiff(path)}></workspace-panel>`;
return html`<workspace-panel .workspace=${this.state.selectedWorkspace} .tool=${this.state.workspaceTool} .fileTree=${this.state.fileTree} .expandedDirs=${this.state.expandedDirs} .selectedFilePath=${this.state.selectedFilePath} .selectedFileContent=${this.state.selectedFileContent} .fileTreeStale=${this.state.fileTreeStale} .gitStatus=${this.state.gitStatus} .selectedDiffPath=${this.state.selectedDiffPath} .selectedDiff=${this.state.selectedDiff} .gitStale=${this.state.gitStale} .onSelectTool=${(tool: "files" | "git") => { this.selectWorkspaceTool(tool); }} .onRefreshFiles=${() => this.refreshFiles()} .onExpandDir=${(path: string) => this.expandDir(path)} .onSelectFile=${(path: string) => this.selectFile(path)} .onRefreshGit=${() => this.refreshGit()} .onSelectDiff=${(path: string) => this.selectDiff(path)}></workspace-panel>`;
}
override render() {
@@ -249,9 +247,9 @@ export class PiWebApp extends LitElement {
</aside>
<main class=${`${state.mainView}-view`}>
<div class="mobile-tabs">
<button class=${state.mainView === "chat" ? "selected" : ""} @click=${() => this.selectMainView("chat")}>Chat</button>
<button class=${state.mainView === "files" ? "selected" : ""} @click=${() => this.selectMainView("files")}>Files</button>
<button class=${state.mainView === "git" ? "selected" : ""} @click=${() => this.selectMainView("git")}>Git</button>
<button class=${state.mainView === "chat" ? "selected" : ""} @click=${() => { this.selectMainView("chat"); }}>Chat</button>
<button class=${state.mainView === "files" ? "selected" : ""} @click=${() => { this.selectMainView("files"); }}>Files</button>
<button class=${state.mainView === "git" ? "selected" : ""} @click=${() => { this.selectMainView("git"); }}>Git</button>
</div>
${state.error ? html`<div class="error">${state.error}</div>` : null}
${state.selectedSession ? html`
@@ -274,6 +272,10 @@ function isActive(status: AppState["status"]): boolean {
return status?.isStreaming === true || status?.isBashRunning === true || status?.isCompacting === true;
}
function omitKey<T>(record: Record<string, T>, keyToOmit: string): Record<string, T> {
return Object.fromEntries(Object.entries(record).filter(([key]) => key !== keyToOmit));
}
function nextFrame(): Promise<void> {
return new Promise((resolve) => requestAnimationFrame(() => { resolve(); }));
}
+1 -1
View File
@@ -208,7 +208,7 @@ export class PromptEditor extends LitElement {
function fileInsertText(path: string, pathMode: boolean, quoted: boolean): string {
const prefix = pathMode ? "" : "@";
if (!quoted && !path.includes(" ")) return `${prefix}${path}`;
return `${prefix}\"${path}\"`;
return `${prefix}"${path}"`;
}
function emptySlashCommands(): SlashCommand[] {
+26 -13
View File
@@ -29,8 +29,8 @@ export class WorkspacePanel extends LitElement {
return html`
<header>
<div class="tabs">
<button class=${this.tool === "files" ? "selected" : ""} @click=${() => this.onSelectTool("files")}>Files</button>
<button class=${this.tool === "git" ? "selected" : ""} @click=${() => this.onSelectTool("git")}>Git</button>
<button class=${this.tool === "files" ? "selected" : ""} @click=${() => { this.onSelectTool("files"); }}>Files</button>
<button class=${this.tool === "git" ? "selected" : ""} @click=${() => { this.onSelectTool("git"); }}>Git</button>
</div>
<small title=${this.workspace.path}>${this.workspace.label}</small>
</header>
@@ -58,19 +58,25 @@ export class WorkspacePanel extends LitElement {
private renderTreeEntry(entry: FileTreeEntry, depth: number): TemplateResult {
const children = this.expandedDirs[entry.path];
const hasChildren = children !== undefined;
return html`
<button class="row" style=${`--depth:${depth}`} @click=${() => entry.type === "directory" ? this.onExpandDir(entry.path) : this.onSelectFile(entry.path)}>
<span>${entry.type === "directory" ? (children ? "▾" : "▸") : "·"}</span>
<button class="row" style=${`--depth:${String(depth)}`} @click=${() => { this.selectTreeEntry(entry); }}>
<span>${entry.type === "directory" ? (hasChildren ? "▾" : "▸") : "·"}</span>
<span>${entry.name}</span>
</button>
${children ? children.map((child) => this.renderTreeEntry(child, depth + 1)) : null}
${hasChildren ? children.map((child) => this.renderTreeEntry(child, depth + 1)) : null}
`;
}
private selectTreeEntry(entry: FileTreeEntry): void {
if (entry.type === "directory") this.onExpandDir(entry.path);
else this.onSelectFile(entry.path);
}
private renderFileViewer() {
const file = this.selectedFileContent;
if (!this.selectedFilePath) return html`<p class="muted">Select a file.</p>`;
if (!file) return html`<p class="muted">Loading ${this.selectedFilePath}…</p>`;
if (this.selectedFilePath === undefined || this.selectedFilePath === "") return html`<p class="muted">Select a file.</p>`;
if (file === undefined) return html`<p class="muted">Loading ${this.selectedFilePath}…</p>`;
if (file.binary) return html`<p class="muted">Binary file: ${file.path}</p>`;
return html`
<div class="viewer-header"><strong>${file.path}</strong><small>${file.language ?? "text"}${file.truncated ? " · truncated" : ""}</small></div>
@@ -88,10 +94,10 @@ export class WorkspacePanel extends LitElement {
</section>
<section class="split">
<div class="list">
${status === undefined ? html`<p class="muted">No status loaded.</p>` : status.isGitRepo === false ? html`<p class="muted">Not a git repository.</p>` : html`
<p class="summary">${status.branch ?? "detached"}${status.ahead || status.behind ? ` · ↑${status.ahead ?? 0}${status.behind ?? 0}` : ""}</p>
${status === undefined ? html`<p class="muted">No status loaded.</p>` : !status.isGitRepo ? html`<p class="muted">Not a git repository.</p>` : html`
<p class="summary">${this.gitSummary(status)}</p>
${status.files.length === 0 ? html`<p class="muted">No changes.</p>` : status.files.map((file) => html`
<button class="row ${this.selectedDiffPath === file.path ? "selected" : ""}" @click=${() => this.onSelectDiff(file.path)}>
<button class="row ${this.selectedDiffPath === file.path ? "selected" : ""}" @click=${() => { this.onSelectDiff(file.path); }}>
<span>${stateLabel(file.index, file.workingTree)}</span>
<span>${file.path}</span>
</button>
@@ -106,15 +112,22 @@ export class WorkspacePanel extends LitElement {
}
private renderDiffViewer() {
if (!this.selectedDiffPath) return html`<p class="muted">Select a changed file.</p>`;
if (this.selectedDiffPath === undefined || this.selectedDiffPath === "") return html`<p class="muted">Select a changed file.</p>`;
const diff = this.selectedDiff;
if (!diff) return html`<p class="muted">Loading diff…</p>`;
if (diff === undefined) return html`<p class="muted">Loading diff…</p>`;
return html`
<div class="viewer-header"><strong>${diff.path ?? "diff"}</strong><small>${diff.staged ? "staged" : "unstaged"}${diff.truncated ? " · truncated" : ""}</small></div>
<code-viewer .content=${diff.diff || "No unstaged diff."}></code-viewer>
<code-viewer .content=${diff.diff !== "" ? diff.diff : "No unstaged diff."}></code-viewer>
`;
}
private gitSummary(status: GitStatusResponse): string {
const branch = status.branch ?? "detached";
const ahead = status.ahead ?? 0;
const behind = status.behind ?? 0;
return ahead === 0 && behind === 0 ? branch : `${branch} · ↑${String(ahead)}${String(behind)}`;
}
static override styles = workspacePanelStyles;
}
+1
View File
@@ -88,6 +88,7 @@ function parseStatus(raw: string): GitStatusResponse {
}
function stateFor(code: string | undefined): GitFileState {
if (code === undefined) return "unmodified";
switch (code) {
case ".": return "unmodified";
case "M": return "modified";
+3 -2
View File
@@ -41,7 +41,7 @@ function isProbablyBinary(buffer: Buffer): boolean {
function languageForPath(path: string): { language?: string } {
const ext = path.split(".").pop()?.toLowerCase();
const language = ext === undefined ? undefined : ({
const languages: Record<string, string | undefined> = {
ts: "typescript",
tsx: "typescript",
js: "javascript",
@@ -56,6 +56,7 @@ function languageForPath(path: string): { language?: string } {
sh: "shell",
yml: "yaml",
yaml: "yaml",
} as Record<string, string | undefined>)[ext];
};
const language = ext === undefined ? undefined : languages[ext];
return language === undefined ? {} : { language };
}