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
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ Works with any CLI agent. Built for local worktree-based development.
| **Sentry エラー監視統合** | 自前の Sentry プロジェクトと連携可能。`.env` に `SENTRY_DSN_DESKTOP` を設定するだけで本番ビルドのクラッシュ・エラーを自動収集 | [#26](https://github.com/MocA-Love/superset/pull/26) | 2026-03-30 |
| **デスクトップ安定性修正** | シェル履歴サジェストが表示されないバグ(useEffect 依存配列の問題)、アプリ終了時の napi_fatal_error クラッシュ(SQLite 未クローズ)、webview パーキング後の getURL() エラー、サイドバーリサイズが webview 上で効かない問題を修正 | [#26](https://github.com/MocA-Love/superset/pull/26) | 2026-03-30 |
| **Review パネル強化** | GitHub Actions チェックを展開してジョブ内ステップの進捗を表示。レビューコメントを展開して Markdown レンダリング全文表示(GitHub Alerts 対応)。コメントのファイルパス+行番号クリックでエディタの該当行にジャンプ | [#27](https://github.com/MocA-Love/superset/pull/27) | 2026-03-30 |
| **サジェストバグ修正** | サジェストドロップダウンがターミナル下部からはみ出す問題を修正(上側表示に切替)。Agent(workspaceRun)操作中にサジェストが表示される問題を修正 | [#31](https://github.com/MocA-Love/superset/pull/31) | 2026-03-30 |

## Fork のビルド方法 (macOS)

Expand Down
20 changes: 19 additions & 1 deletion apps/desktop/src/main/lib/shell-history.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,21 @@ let cachedHistory: string[] | null = null;
let lastReadTime = 0;
const CACHE_TTL_MS = 30_000;

const META_MARKER = 0x83;

function decodeMetafied(buffer: Buffer): string {
const decoded: number[] = [];
for (let i = 0; i < buffer.length; i++) {
if (buffer[i] === META_MARKER && i + 1 < buffer.length) {
decoded.push(buffer[i + 1] ^ 0x20);
i++;
} else {
decoded.push(buffer[i]);
}
}
return Buffer.from(decoded).toString("utf-8");
}

function parseZshHistory(content: string): string[] {
const entries: string[] = [];
for (const line of content.split("\n")) {
Expand Down Expand Up @@ -35,7 +50,10 @@ async function readHistoryFile(): Promise<string[]> {
const zshPath = `${home}/.zsh_history`;
try {
await access(zshPath, constants.R_OK);
const content = await readFile(zshPath, "utf-8");
const buffer = await readFile(zshPath);
const content = buffer.includes(META_MARKER)
? decodeMetafied(buffer)
: buffer.toString("utf-8");
return parseZshHistory(content);
} catch {
// zsh history not available
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -342,7 +342,8 @@ export const Terminal = ({ paneId, tabId, workspaceId }: TerminalProps) => {
!isRestoredMode &&
!connectionError &&
!exitStatus &&
!isAlternateScreenRef.current,
!isWorkspaceRunPane,
isAlternateScreenRef,
onAcceptWrite: handleSuggestionWrite,
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,16 @@ export function TerminalSuggestion({
}
}, [selectedIndex]);

// Don't render in alternate screen (TUI apps like Claude Code)
if (xterm.buffer.active.type === "alternate") return null;

const dims = getCellDimensions(xterm);
if (!dims) return null;

const cursorX = xterm.buffer.active.cursorX;
const cursorY = xterm.buffer.active.cursorY;
const terminalWidth = xterm.cols * dims.width;
const terminalHeight = xterm.rows * dims.height;

const rawDropdownLeft =
TERMINAL_PADDING + Math.max(0, cursorX - prefix.length) * dims.width;
Expand All @@ -62,9 +66,24 @@ export function TerminalSuggestion({
rawDropdownLeft,
TERMINAL_PADDING + terminalWidth - dropdownMaxWidth,
);
const dropdownTop = TERMINAL_PADDING + (cursorY + 1) * dims.height;

const listMaxHeight = MAX_VISIBLE_ITEMS * ITEM_HEIGHT;
// Estimate total dropdown height: preview + list + footer
const PREVIEW_HEIGHT = 30;
const FOOTER_HEIGHT = 24;
const dropdownHeight =
PREVIEW_HEIGHT +
Math.min(suggestions.length, MAX_VISIBLE_ITEMS) * ITEM_HEIGHT +
FOOTER_HEIGHT;

const belowCursorTop = TERMINAL_PADDING + (cursorY + 1) * dims.height;
const spaceBelow = terminalHeight + TERMINAL_PADDING * 2 - belowCursorTop;

// If not enough space below, show above the cursor
const dropdownTop =
spaceBelow >= dropdownHeight
? belowCursorTop
: Math.max(0, TERMINAL_PADDING + cursorY * dims.height - dropdownHeight);
Comment thread
MocA-Love marked this conversation as resolved.
const selected = suggestions[selectedIndex] ?? "";
const suffix = selected.startsWith(prefix)
? selected.slice(prefix.length)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -492,6 +492,7 @@ export function useTerminalLifecycle({
useTabsStore.getState().setPaneStatus(paneId, "idle");
}
} else if (
!isAlternateScreenRef.current &&
domEvent.key.length === 1 &&
!domEvent.ctrlKey &&
!domEvent.metaKey
Expand Down Expand Up @@ -740,7 +741,9 @@ export function useTerminalLifecycle({
);
const cleanupPaste = setupPasteHandler(xterm, {
onPaste: (text) => {
commandBufferRef.current += text;
if (!isAlternateScreenRef.current) {
commandBufferRef.current += text;
}
},
onWrite: handleWrite,
isBracketedPasteEnabled: () => isBracketedPasteRef.current,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import type { ActiveSuggestionHandle } from "../helpers";
export interface UseTerminalSuggestionOptions {
commandBufferRef: React.MutableRefObject<string>;
enabled: boolean;
isAlternateScreenRef: React.MutableRefObject<boolean>;
onAcceptWrite: (data: string) => void;
}

Expand All @@ -22,6 +23,7 @@ const FETCH_DEBOUNCE_MS = 80;
export function useTerminalSuggestion({
commandBufferRef,
enabled,
isAlternateScreenRef,
onAcceptWrite,
}: UseTerminalSuggestionOptions): UseTerminalSuggestionReturn {
const [historySuggestions, setHistorySuggestions] = useState<string[]>(EMPTY);
Expand All @@ -46,7 +48,7 @@ export function useTerminalSuggestion({
// Single stable effect — mount once
useEffect(() => {
const id = setInterval(() => {
if (!enabledRef.current) {
if (!enabledRef.current || isAlternateScreenRef.current) {
if (lastPrefixRef.current !== "") {
lastPrefixRef.current = "";
setTrackedInput("");
Expand Down Expand Up @@ -75,7 +77,7 @@ export function useTerminalSuggestion({
const prefix = current;
fetchTimerRef.current = setTimeout(async () => {
fetchTimerRef.current = null;
if (!enabledRef.current) return;
if (!enabledRef.current || isAlternateScreenRef.current) return;
try {
const result = await electronTrpcClient.terminal.getSuggestions.query(
{
Expand All @@ -97,8 +99,7 @@ export function useTerminalSuggestion({
clearTimeout(fetchTimerRef.current);
}
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
}, [commandBufferRef, isAlternateScreenRef]);

const displaySuggestions = historySuggestions;

Expand Down
Loading