fix(coding-agent): corrected context file preview to read from raw object
- Fixed context file preview in inspector panel to read content from raw object instead of async file reads. - Added slash commands to extensions inspector panel for visibility and management. - Extracted getContextFileContent helper method for type-safe content extraction.
This commit is contained in:
@@ -1,8 +1,10 @@
|
||||
# Changelog
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### Added
|
||||
|
||||
- Added slash commands to the extensions inspector panel for visibility and management
|
||||
- Added support for file-based slash commands from `commands/` directories
|
||||
- Added `$ARGUMENTS` placeholder for slash command argument substitution, aligning with Claude and Codex conventions
|
||||
|
||||
@@ -12,6 +14,7 @@
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed context file preview in inspector panel to display content correctly instead of attempting async file reads
|
||||
- Fixed Linux ARM64 installs failing on fresh Debian when the `sharp` module is unavailable during session image compression
|
||||
|
||||
## [3.20.1] - 2026-01-06
|
||||
|
||||
+23
-20
@@ -68,7 +68,7 @@ export class InspectorPanel implements Component {
|
||||
|
||||
switch (ext.kind) {
|
||||
case "context-file":
|
||||
content = this.renderFilePreview(ext.path, width);
|
||||
content = this.renderFilePreview(ext.raw, width);
|
||||
break;
|
||||
case "tool":
|
||||
content = this.renderToolArgs(ext.raw, width);
|
||||
@@ -91,37 +91,40 @@ export class InspectorPanel implements Component {
|
||||
return lines;
|
||||
}
|
||||
|
||||
private renderFilePreview(path: string, width: number): string[] {
|
||||
private renderFilePreview(raw: unknown, width: number): string[] {
|
||||
const lines: string[] = [];
|
||||
lines.push(theme.fg("muted", "Preview:"));
|
||||
lines.push(theme.fg("dim", theme.boxSharp.horizontal.repeat(Math.min(width - 2, 40))));
|
||||
|
||||
try {
|
||||
const content = Bun.file(path).text();
|
||||
// Note: async call to sync context - will show empty on first render
|
||||
// This is acceptable for preview which can populate on next render
|
||||
if (typeof content === "object" && "then" in content) {
|
||||
content.then((text: string) => {
|
||||
const fileLines = text.split("\n").slice(0, 20);
|
||||
const content = this.getContextFileContent(raw);
|
||||
if (!content) {
|
||||
lines.push(theme.fg("dim", " (no content)"));
|
||||
lines.push("");
|
||||
return lines;
|
||||
}
|
||||
|
||||
for (const line of fileLines) {
|
||||
const highlighted = this.highlightMarkdown(line);
|
||||
lines.push(truncateToWidth(highlighted, width - 2));
|
||||
}
|
||||
const fileLines = content.split("\n");
|
||||
for (const line of fileLines.slice(0, 20)) {
|
||||
const highlighted = this.highlightMarkdown(line);
|
||||
lines.push(truncateToWidth(highlighted, width - 2));
|
||||
}
|
||||
|
||||
if (text.split("\n").length > 20) {
|
||||
lines.push(theme.fg("dim", "(truncated at line 20)"));
|
||||
}
|
||||
});
|
||||
}
|
||||
} catch (err) {
|
||||
lines.push(theme.fg("error", `Failed to read file: ${err instanceof Error ? err.message : String(err)}`));
|
||||
if (fileLines.length > 20) {
|
||||
lines.push(theme.fg("dim", "(truncated at line 20)"));
|
||||
}
|
||||
|
||||
lines.push("");
|
||||
return lines;
|
||||
}
|
||||
|
||||
private getContextFileContent(raw: unknown): string | null {
|
||||
if (raw && typeof raw === "object" && "content" in raw) {
|
||||
const content = (raw as { content?: unknown }).content;
|
||||
return typeof content === "string" ? content : null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private highlightMarkdown(line: string): string {
|
||||
// Basic markdown syntax highlighting
|
||||
let highlighted = line;
|
||||
|
||||
@@ -10,6 +10,7 @@ import type { MCPServer } from "../../../../capability/mcp";
|
||||
import type { Prompt } from "../../../../capability/prompt";
|
||||
import type { Rule } from "../../../../capability/rule";
|
||||
import type { Skill } from "../../../../capability/skill";
|
||||
import type { SlashCommand } from "../../../../capability/slash-command";
|
||||
import type { CustomTool } from "../../../../capability/tool";
|
||||
import type { SourceMeta } from "../../../../capability/types";
|
||||
import {
|
||||
@@ -192,6 +193,17 @@ export function loadAllExtensions(cwd?: string, disabledIds?: string[]): Extensi
|
||||
// Capability may not be registered
|
||||
}
|
||||
|
||||
// Load slash commands
|
||||
try {
|
||||
const commands = loadSync<SlashCommand>("slash-commands", loadOpts);
|
||||
addItems(commands.all, "slash-command", {
|
||||
getDescription: () => undefined,
|
||||
getTrigger: (c) => `/${c.name}`,
|
||||
});
|
||||
} catch {
|
||||
// Capability may not be registered
|
||||
}
|
||||
|
||||
// Load hooks
|
||||
try {
|
||||
const hooks = loadSync<Hook>("hooks", loadOpts);
|
||||
|
||||
Reference in New Issue
Block a user