feat: implement hooks, plugins, session forks, and vim motions

Add 4 major features to codetyper-cli:

- Hooks System: Lifecycle hooks (PreToolUse, PostToolUse, SessionStart,
  SessionEnd, UserPromptSubmit, Stop) with exit code control flow
- Plugin System: Custom tools, commands, and hooks via plugin manifest
- Session Forking: Snapshots, rewind, fork, and switch between branches
- Vim Motions: Normal/Insert/Command/Visual modes with keyboard navigation

New files:
- src/types/{hooks,plugin,session-fork,vim}.ts
- src/constants/{hooks,plugin,session-fork,vim}.ts
- src/services/{hooks-service,plugin-loader,plugin-service,session-fork-service}.ts
- src/stores/vim-store.ts (vanilla)
- src/tui/hooks/{useVimMode,useVimStore,useTodoStore,useThemeStore}.ts
- src/tui/components/VimStatusLine.tsx

Modified:
- src/services/agent.ts (hook integration)
- src/tools/index.ts (plugin tool registration)
- src/stores/{todo-store,theme-store}.ts (converted to vanilla)
- TUI components (updated hook imports)
This commit is contained in:
2026-01-31 22:22:04 -05:00
parent 37d4a43154
commit a3c407d89a
56 changed files with 7507 additions and 90 deletions

View File

@@ -5,6 +5,12 @@
*/
import type { AgentConfig } from "@/types/agent-config";
import type { PastedImage } from "@/types/image";
export interface SubmitOptions {
/** Pasted images to include with the message */
images?: PastedImage[];
}
export interface AppProps {
/** Unique session identifier */
@@ -18,7 +24,7 @@ export interface AppProps {
/** Application version */
version: string;
/** Called when user submits a message */
onSubmit: (message: string) => Promise<void>;
onSubmit: (message: string, options?: SubmitOptions) => Promise<void>;
/** Called when user exits the application */
onExit: () => void;
/** Called when user executes a slash command */

View File

@@ -2,6 +2,8 @@
* Interface for tracking pasted content with virtual text
*/
import type { PastedImage } from "@/types/image";
export interface PastedContent {
/** Unique identifier for the pasted block */
id: string;
@@ -22,9 +24,12 @@ export interface PasteState {
pastedBlocks: Map<string, PastedContent>;
/** Counter for generating unique IDs */
pasteCounter: number;
/** List of pasted images */
pastedImages: PastedImage[];
}
export const createInitialPasteState = (): PasteState => ({
pastedBlocks: new Map(),
pasteCounter: 0,
pastedImages: [],
});