feat: integrate Pi backend and Pi Web

This commit is contained in:
luckyyzh
2026-07-30 19:37:53 +08:00
commit 7392ab9dd7
1390 changed files with 337197 additions and 0 deletions
+73
View File
@@ -0,0 +1,73 @@
"use client";
import { useEffect } from "react";
// ---------------------------------------------------------------------------
// Module-level registry — ChatWindow registers the abort handler here so that
// the global Esc listener in AppShell can call it without prop-drilling.
// ---------------------------------------------------------------------------
let globalAbortHandler: (() => void) | null = null;
/**
* Register (or clear) the abort handler for the global Esc shortcut.
* Call this from ChatWindow whenever agentRunning or handleAbort changes.
*/
export function registerAbortHandler(handler: (() => void) | null): void {
globalAbortHandler = handler;
}
// ---------------------------------------------------------------------------
// Hook: global keyboard shortcuts
// ---------------------------------------------------------------------------
interface UseGlobalKeyboardShortcutsOptions {
/** Called when Ctrl+Alt+N is pressed. Receives current cwd. */
onNewSession?: (cwd: string) => void;
/** The currently selected project directory (sidebar cwd). */
activeCwd?: string | null;
}
/**
* Register global keyboard shortcuts for the application.
*
* Shortcuts handled here:
* Esc – stop the running agent (via module-level abort handler)
* Ctrl+Alt+N – create a new session in the active project directory
*
* Note: Esc inside <textarea> or <input> is deliberately NOT handled here.
* ChatInput manages its own Esc logic (closing slash / @ file menus, stopping
* the agent when no menu is open) because it needs intimate knowledge of menu
* state that is local to that component.
*/
export function useGlobalKeyboardShortcuts(
options: UseGlobalKeyboardShortcutsOptions,
): void {
const { onNewSession, activeCwd } = options;
useEffect(() => {
const handler = (e: KeyboardEvent): void => {
// ---- Esc: stop agent ----
if (e.key === "Escape") {
if (!globalAbortHandler) return;
const tag = (e.target as HTMLElement)?.tagName;
// Let textarea/input handle Esc internally (ChatInput menus / stop).
if (tag === "TEXTAREA" || tag === "INPUT") return;
e.preventDefault();
globalAbortHandler();
return;
}
// ---- Ctrl+Alt+N: new session ----
if (e.key === "n" && e.ctrlKey && e.altKey) {
if (!activeCwd || !onNewSession) return;
e.preventDefault();
onNewSession(activeCwd);
}
};
window.addEventListener("keydown", handler);
return () => window.removeEventListener("keydown", handler);
}, [activeCwd, onNewSession]);
}