feat: add pink-purple theme, fix image paste race condition, allow @/commands anywhere in input
- Add Pink Purple theme (hot pink/purple/magenta on dark plum background) - Fix race condition where clearPastedImages() in input-area ran before the async message handler could read the images, silently dropping them - Allow @ file picker and / command menu to trigger at any cursor position, not just when the input is empty - Update CHANGELOG and README with new changes
This commit is contained in:
@@ -1,14 +1,3 @@
|
||||
/**
|
||||
* Brain API Constants
|
||||
*
|
||||
* Configuration constants for the CodeTyper Brain service
|
||||
*/
|
||||
|
||||
/**
|
||||
* Feature flag to disable all Brain functionality.
|
||||
* Set to true to hide Brain menu, disable Brain API calls,
|
||||
* and remove Brain-related UI elements.
|
||||
*/
|
||||
export const BRAIN_DISABLED = true;
|
||||
|
||||
export const BRAIN_PROVIDER_NAME = "brain" as const;
|
||||
|
||||
@@ -20,6 +20,21 @@ export const COPILOT_MODELS_CACHE_TTL = 5 * 60 * 1000; // 5 minutes
|
||||
export const COPILOT_MAX_RETRIES = 3;
|
||||
export const COPILOT_INITIAL_RETRY_DELAY = 1000; // 1 second
|
||||
|
||||
// Streaming timeout and connection retry
|
||||
export const COPILOT_STREAM_TIMEOUT = 120_000; // 2 minutes
|
||||
export const COPILOT_CONNECTION_RETRY_DELAY = 2000; // 2 seconds
|
||||
|
||||
// Connection error patterns for retry logic
|
||||
export const CONNECTION_ERROR_PATTERNS = [
|
||||
/socket.*closed/i,
|
||||
/ECONNRESET/i,
|
||||
/ECONNREFUSED/i,
|
||||
/ETIMEDOUT/i,
|
||||
/network.*error/i,
|
||||
/fetch.*failed/i,
|
||||
/aborted/i,
|
||||
] as const;
|
||||
|
||||
// Default model
|
||||
export const COPILOT_DEFAULT_MODEL = "gpt-5-mini";
|
||||
|
||||
|
||||
180
src/constants/keybinds.ts
Normal file
180
src/constants/keybinds.ts
Normal file
@@ -0,0 +1,180 @@
|
||||
/**
|
||||
* Keybind Configuration
|
||||
*
|
||||
* Defines all configurable keybindings with defaults.
|
||||
* Modeled after OpenCode's keybind system with leader key support,
|
||||
* comma-separated alternatives, and `<leader>` prefix expansion.
|
||||
*
|
||||
* Format: "mod+key" or "mod+key,mod+key" for alternatives
|
||||
* Special: "<leader>key" expands to "${leader}+key"
|
||||
* "none" disables the binding
|
||||
*/
|
||||
|
||||
// ============================================================================
|
||||
// Keybind Action IDs
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* All possible keybind action identifiers.
|
||||
* These map 1:1 to the defaults below.
|
||||
*/
|
||||
export type KeybindAction =
|
||||
// Application
|
||||
| "app_exit"
|
||||
| "app_interrupt"
|
||||
|
||||
// Session / execution
|
||||
| "session_interrupt"
|
||||
| "session_abort_rollback"
|
||||
| "session_pause_resume"
|
||||
| "session_step_toggle"
|
||||
| "session_step_advance"
|
||||
|
||||
// Navigation & scrolling
|
||||
| "messages_page_up"
|
||||
| "messages_page_down"
|
||||
|
||||
// Mode switching
|
||||
| "mode_toggle"
|
||||
|
||||
// Input area
|
||||
| "input_submit"
|
||||
| "input_newline"
|
||||
| "input_clear"
|
||||
| "input_paste"
|
||||
|
||||
// Menus & pickers
|
||||
| "command_menu"
|
||||
| "file_picker"
|
||||
| "model_list"
|
||||
| "theme_list"
|
||||
| "agent_list"
|
||||
| "help_menu"
|
||||
|
||||
// Clipboard
|
||||
| "clipboard_copy"
|
||||
|
||||
// Sidebar / panels
|
||||
| "sidebar_toggle"
|
||||
| "activity_toggle";
|
||||
|
||||
// ============================================================================
|
||||
// Default Keybinds
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* Default leader key prefix (similar to vim leader or OpenCode's ctrl+x).
|
||||
*/
|
||||
export const DEFAULT_LEADER = "ctrl+x";
|
||||
|
||||
/**
|
||||
* Default keybindings for all actions.
|
||||
* Format: comma-separated list of key combos.
|
||||
* - `ctrl+c` — modifier + key
|
||||
* - `escape` — single key
|
||||
* - `<leader>q` — leader prefix + key (expands to e.g. `ctrl+x,q`)
|
||||
* - `none` — binding disabled
|
||||
*/
|
||||
export const DEFAULT_KEYBINDS: Readonly<Record<KeybindAction, string>> = {
|
||||
// Application
|
||||
app_exit: "ctrl+c",
|
||||
app_interrupt: "ctrl+c",
|
||||
|
||||
// Session / execution control
|
||||
session_interrupt: "escape",
|
||||
session_abort_rollback: "ctrl+z",
|
||||
session_pause_resume: "ctrl+p",
|
||||
session_step_toggle: "ctrl+shift+s",
|
||||
session_step_advance: "return",
|
||||
|
||||
// Navigation
|
||||
messages_page_up: "pageup",
|
||||
messages_page_down: "pagedown",
|
||||
|
||||
// Mode switching
|
||||
mode_toggle: "ctrl+e",
|
||||
|
||||
// Input area
|
||||
input_submit: "return",
|
||||
input_newline: "shift+return,ctrl+return",
|
||||
input_clear: "ctrl+c",
|
||||
input_paste: "ctrl+v",
|
||||
|
||||
// Menus & pickers
|
||||
command_menu: "/",
|
||||
file_picker: "@",
|
||||
model_list: "<leader>m",
|
||||
theme_list: "<leader>t",
|
||||
agent_list: "<leader>a",
|
||||
help_menu: "<leader>h",
|
||||
|
||||
// Clipboard
|
||||
clipboard_copy: "ctrl+y",
|
||||
|
||||
// Sidebar / panels
|
||||
sidebar_toggle: "<leader>b",
|
||||
activity_toggle: "<leader>s",
|
||||
} as const;
|
||||
|
||||
/**
|
||||
* Descriptions for each keybind action (used in help menus)
|
||||
*/
|
||||
export const KEYBIND_DESCRIPTIONS: Readonly<Record<KeybindAction, string>> = {
|
||||
app_exit: "Exit the application",
|
||||
app_interrupt: "Interrupt / abort current action",
|
||||
session_interrupt: "Cancel current operation",
|
||||
session_abort_rollback: "Abort with rollback",
|
||||
session_pause_resume: "Toggle pause/resume execution",
|
||||
session_step_toggle: "Toggle step-by-step mode",
|
||||
session_step_advance: "Advance one step",
|
||||
messages_page_up: "Scroll messages up by one page",
|
||||
messages_page_down: "Scroll messages down by one page",
|
||||
mode_toggle: "Toggle interaction mode (agent/ask/code-review)",
|
||||
input_submit: "Submit input",
|
||||
input_newline: "Insert newline in input",
|
||||
input_clear: "Clear input field",
|
||||
input_paste: "Paste from clipboard",
|
||||
command_menu: "Open command menu",
|
||||
file_picker: "Open file picker",
|
||||
model_list: "List available models",
|
||||
theme_list: "List available themes",
|
||||
agent_list: "List agents",
|
||||
help_menu: "Show help",
|
||||
clipboard_copy: "Copy selection to clipboard",
|
||||
sidebar_toggle: "Toggle sidebar panel",
|
||||
activity_toggle: "Toggle activity/status panel",
|
||||
} as const;
|
||||
|
||||
/**
|
||||
* Categories for grouping keybinds in the help menu
|
||||
*/
|
||||
export const KEYBIND_CATEGORIES: Readonly<
|
||||
Record<string, readonly KeybindAction[]>
|
||||
> = {
|
||||
Application: ["app_exit", "app_interrupt"],
|
||||
"Execution Control": [
|
||||
"session_interrupt",
|
||||
"session_abort_rollback",
|
||||
"session_pause_resume",
|
||||
"session_step_toggle",
|
||||
"session_step_advance",
|
||||
],
|
||||
Navigation: ["messages_page_up", "messages_page_down"],
|
||||
"Mode & Input": [
|
||||
"mode_toggle",
|
||||
"input_submit",
|
||||
"input_newline",
|
||||
"input_clear",
|
||||
"input_paste",
|
||||
],
|
||||
"Menus & Pickers": [
|
||||
"command_menu",
|
||||
"file_picker",
|
||||
"model_list",
|
||||
"theme_list",
|
||||
"agent_list",
|
||||
"help_menu",
|
||||
],
|
||||
Panels: ["sidebar_toggle", "activity_toggle"],
|
||||
Clipboard: ["clipboard_copy"],
|
||||
} as const;
|
||||
@@ -25,6 +25,36 @@ export const SKILL_DIRS = {
|
||||
PROJECT: ".codetyper/skills",
|
||||
} as const;
|
||||
|
||||
/**
|
||||
* External agent directories (relative to project root)
|
||||
* These directories may contain agent definition files from
|
||||
* various tools (Claude, GitHub Copilot, CodeTyper, etc.)
|
||||
*/
|
||||
export const EXTERNAL_AGENT_DIRS = {
|
||||
CLAUDE: ".claude",
|
||||
GITHUB: ".github",
|
||||
CODETYPER: ".codetyper",
|
||||
} as const;
|
||||
|
||||
/**
|
||||
* Recognized external agent file patterns
|
||||
*/
|
||||
export const EXTERNAL_AGENT_FILES = {
|
||||
/** File extensions recognized as agent definitions */
|
||||
EXTENSIONS: [".md", ".yaml", ".yml"],
|
||||
/** Known agent file names (case-insensitive) */
|
||||
KNOWN_FILES: [
|
||||
"AGENTS.md",
|
||||
"agents.md",
|
||||
"AGENT.md",
|
||||
"agent.md",
|
||||
"SKILL.md",
|
||||
"copilot-instructions.md",
|
||||
],
|
||||
/** Subdirectories to scan for agents */
|
||||
SUBDIRS: ["agents", "skills", "prompts"],
|
||||
} as const;
|
||||
|
||||
/**
|
||||
* Skill loading configuration
|
||||
*/
|
||||
@@ -89,8 +119,196 @@ export const BUILTIN_SKILLS = {
|
||||
REVIEW_PR: "review-pr",
|
||||
EXPLAIN: "explain",
|
||||
FEATURE_DEV: "feature-dev",
|
||||
TYPESCRIPT: "typescript",
|
||||
REACT: "react",
|
||||
CSS_SCSS: "css-scss",
|
||||
SECURITY: "security",
|
||||
CODE_AUDIT: "code-audit",
|
||||
RESEARCHER: "researcher",
|
||||
TESTING: "testing",
|
||||
PERFORMANCE: "performance",
|
||||
API_DESIGN: "api-design",
|
||||
DATABASE: "database",
|
||||
DEVOPS: "devops",
|
||||
ACCESSIBILITY: "accessibility",
|
||||
DOCUMENTATION: "documentation",
|
||||
REFACTORING: "refactoring",
|
||||
GIT_WORKFLOW: "git-workflow",
|
||||
NODE_BACKEND: "node-backend",
|
||||
} as const;
|
||||
|
||||
/**
|
||||
* Skill auto-detection keyword map.
|
||||
* Maps keywords found in user prompts to skill IDs.
|
||||
* Each entry: [keyword, skillId, category, weight]
|
||||
*/
|
||||
export const SKILL_DETECTION_KEYWORDS: ReadonlyArray<
|
||||
readonly [string, string, string, number]
|
||||
> = [
|
||||
// TypeScript
|
||||
["typescript", "typescript", "language", 0.9],
|
||||
["type error", "typescript", "language", 0.85],
|
||||
["ts error", "typescript", "language", 0.85],
|
||||
["generics", "typescript", "language", 0.8],
|
||||
["type system", "typescript", "language", 0.85],
|
||||
["interface", "typescript", "language", 0.5],
|
||||
["type alias", "typescript", "language", 0.8],
|
||||
[".ts", "typescript", "language", 0.4],
|
||||
[".tsx", "typescript", "language", 0.5],
|
||||
|
||||
// React
|
||||
["react", "react", "framework", 0.9],
|
||||
["component", "react", "framework", 0.5],
|
||||
["hooks", "react", "framework", 0.7],
|
||||
["usestate", "react", "framework", 0.9],
|
||||
["useeffect", "react", "framework", 0.9],
|
||||
["jsx", "react", "framework", 0.8],
|
||||
["tsx", "react", "framework", 0.7],
|
||||
["react component", "react", "framework", 0.95],
|
||||
["props", "react", "framework", 0.5],
|
||||
["useState", "react", "framework", 0.9],
|
||||
|
||||
// CSS/SCSS
|
||||
["css", "css-scss", "styling", 0.8],
|
||||
["scss", "css-scss", "styling", 0.9],
|
||||
["sass", "css-scss", "styling", 0.9],
|
||||
["styling", "css-scss", "styling", 0.6],
|
||||
["flexbox", "css-scss", "styling", 0.9],
|
||||
["grid layout", "css-scss", "styling", 0.85],
|
||||
["responsive", "css-scss", "styling", 0.6],
|
||||
["animation", "css-scss", "styling", 0.5],
|
||||
["tailwind", "css-scss", "styling", 0.7],
|
||||
|
||||
// Security
|
||||
["security", "security", "domain", 0.9],
|
||||
["vulnerability", "security", "domain", 0.95],
|
||||
["xss", "security", "domain", 0.95],
|
||||
["sql injection", "security", "domain", 0.95],
|
||||
["csrf", "security", "domain", 0.95],
|
||||
["authentication", "security", "domain", 0.6],
|
||||
["authorization", "security", "domain", 0.6],
|
||||
["owasp", "security", "domain", 0.95],
|
||||
["cve", "security", "domain", 0.9],
|
||||
["penetration", "security", "domain", 0.85],
|
||||
|
||||
// Code Audit
|
||||
["audit", "code-audit", "domain", 0.85],
|
||||
["code quality", "code-audit", "domain", 0.9],
|
||||
["tech debt", "code-audit", "domain", 0.9],
|
||||
["dead code", "code-audit", "domain", 0.9],
|
||||
["complexity", "code-audit", "domain", 0.6],
|
||||
["code smell", "code-audit", "domain", 0.9],
|
||||
["code review", "code-audit", "domain", 0.5],
|
||||
|
||||
// Research
|
||||
["research", "researcher", "workflow", 0.8],
|
||||
["find out", "researcher", "workflow", 0.5],
|
||||
["look up", "researcher", "workflow", 0.5],
|
||||
["documentation", "researcher", "workflow", 0.5],
|
||||
["best practice", "researcher", "workflow", 0.6],
|
||||
["compare", "researcher", "workflow", 0.4],
|
||||
|
||||
// Testing
|
||||
["test", "testing", "workflow", 0.5],
|
||||
["testing", "testing", "workflow", 0.8],
|
||||
["unit test", "testing", "workflow", 0.9],
|
||||
["integration test", "testing", "workflow", 0.9],
|
||||
["e2e", "testing", "workflow", 0.85],
|
||||
["tdd", "testing", "workflow", 0.9],
|
||||
["jest", "testing", "workflow", 0.85],
|
||||
["vitest", "testing", "workflow", 0.9],
|
||||
["playwright", "testing", "workflow", 0.9],
|
||||
["coverage", "testing", "workflow", 0.6],
|
||||
|
||||
// Performance
|
||||
["performance", "performance", "domain", 0.8],
|
||||
["optimization", "performance", "domain", 0.7],
|
||||
["optimize", "performance", "domain", 0.7],
|
||||
["slow", "performance", "domain", 0.5],
|
||||
["bundle size", "performance", "domain", 0.9],
|
||||
["memory leak", "performance", "domain", 0.9],
|
||||
["latency", "performance", "domain", 0.7],
|
||||
["profiling", "performance", "domain", 0.85],
|
||||
|
||||
// API Design
|
||||
["api", "api-design", "domain", 0.5],
|
||||
["endpoint", "api-design", "domain", 0.6],
|
||||
["rest", "api-design", "domain", 0.7],
|
||||
["graphql", "api-design", "domain", 0.9],
|
||||
["openapi", "api-design", "domain", 0.9],
|
||||
["swagger", "api-design", "domain", 0.9],
|
||||
|
||||
// Database
|
||||
["database", "database", "domain", 0.9],
|
||||
["sql", "database", "domain", 0.8],
|
||||
["query", "database", "domain", 0.4],
|
||||
["migration", "database", "domain", 0.7],
|
||||
["schema", "database", "domain", 0.7],
|
||||
["orm", "database", "domain", 0.85],
|
||||
["prisma", "database", "domain", 0.9],
|
||||
["drizzle", "database", "domain", 0.9],
|
||||
["postgres", "database", "domain", 0.9],
|
||||
["mysql", "database", "domain", 0.9],
|
||||
["mongodb", "database", "domain", 0.9],
|
||||
|
||||
// DevOps
|
||||
["devops", "devops", "domain", 0.9],
|
||||
["docker", "devops", "domain", 0.9],
|
||||
["ci/cd", "devops", "domain", 0.9],
|
||||
["pipeline", "devops", "domain", 0.7],
|
||||
["deploy", "devops", "domain", 0.7],
|
||||
["kubernetes", "devops", "domain", 0.95],
|
||||
["k8s", "devops", "domain", 0.95],
|
||||
["github actions", "devops", "domain", 0.9],
|
||||
|
||||
// Accessibility
|
||||
["accessibility", "accessibility", "domain", 0.95],
|
||||
["a11y", "accessibility", "domain", 0.95],
|
||||
["wcag", "accessibility", "domain", 0.95],
|
||||
["aria", "accessibility", "domain", 0.85],
|
||||
["screen reader", "accessibility", "domain", 0.9],
|
||||
|
||||
// Documentation
|
||||
["documentation", "documentation", "workflow", 0.7],
|
||||
["readme", "documentation", "workflow", 0.8],
|
||||
["jsdoc", "documentation", "workflow", 0.9],
|
||||
["document this", "documentation", "workflow", 0.7],
|
||||
|
||||
// Refactoring
|
||||
["refactor", "refactoring", "workflow", 0.9],
|
||||
["refactoring", "refactoring", "workflow", 0.9],
|
||||
["clean up", "refactoring", "workflow", 0.6],
|
||||
["restructure", "refactoring", "workflow", 0.7],
|
||||
["simplify", "refactoring", "workflow", 0.5],
|
||||
["solid principles", "refactoring", "workflow", 0.85],
|
||||
["design pattern", "refactoring", "workflow", 0.7],
|
||||
|
||||
// Git
|
||||
["git", "git-workflow", "tool", 0.5],
|
||||
["branch", "git-workflow", "tool", 0.4],
|
||||
["merge conflict", "git-workflow", "tool", 0.9],
|
||||
["rebase", "git-workflow", "tool", 0.85],
|
||||
["cherry-pick", "git-workflow", "tool", 0.9],
|
||||
|
||||
// Node.js Backend
|
||||
["express", "node-backend", "framework", 0.85],
|
||||
["fastify", "node-backend", "framework", 0.9],
|
||||
["middleware", "node-backend", "framework", 0.6],
|
||||
["api server", "node-backend", "framework", 0.8],
|
||||
["backend", "node-backend", "framework", 0.5],
|
||||
["server", "node-backend", "framework", 0.4],
|
||||
] as const;
|
||||
|
||||
/**
|
||||
* Minimum confidence for auto-detection to trigger
|
||||
*/
|
||||
export const SKILL_AUTO_DETECT_THRESHOLD = 0.6;
|
||||
|
||||
/**
|
||||
* Maximum number of skills to auto-activate per prompt
|
||||
*/
|
||||
export const SKILL_AUTO_DETECT_MAX = 3;
|
||||
|
||||
/**
|
||||
* Skill trigger patterns for common commands
|
||||
*/
|
||||
|
||||
@@ -790,6 +790,62 @@ const CARGDEV_CYBERPUNK_COLORS: ThemeColors = {
|
||||
headerGradient: ["#ff79c6", "#bd93f9", "#8be9fd"],
|
||||
};
|
||||
|
||||
const PINK_PURPLE_COLORS: ThemeColors = {
|
||||
primary: "#ff69b4",
|
||||
secondary: "#b47ee5",
|
||||
accent: "#e84393",
|
||||
|
||||
success: "#a3e048",
|
||||
error: "#ff4757",
|
||||
warning: "#ffa502",
|
||||
info: "#cf6fef",
|
||||
|
||||
text: "#f5e6f0",
|
||||
textDim: "#9a7aa0",
|
||||
textMuted: "#4a3050",
|
||||
|
||||
background: "#1a0a20",
|
||||
backgroundPanel: "#120818",
|
||||
backgroundElement: "#2a1535",
|
||||
|
||||
border: "#3d1f4e",
|
||||
borderFocus: "#ff69b4",
|
||||
borderWarning: "#ffa502",
|
||||
borderModal: "#b47ee5",
|
||||
|
||||
bgHighlight: "#2a1535",
|
||||
bgCursor: "#e84393",
|
||||
bgAdded: "#a3e048",
|
||||
bgRemoved: "#ff4757",
|
||||
|
||||
diffAdded: "#a3e048",
|
||||
diffRemoved: "#ff4757",
|
||||
diffContext: "#9a7aa0",
|
||||
diffHeader: "#f5e6f0",
|
||||
diffHunk: "#cf6fef",
|
||||
diffLineBgAdded: "#1a2d1a",
|
||||
diffLineBgRemoved: "#2d1a1a",
|
||||
diffLineText: "#f5e6f0",
|
||||
|
||||
roleUser: "#ff69b4",
|
||||
roleAssistant: "#b47ee5",
|
||||
roleSystem: "#ffa502",
|
||||
roleTool: "#cf6fef",
|
||||
|
||||
modeIdle: "#b47ee5",
|
||||
modeEditing: "#ff69b4",
|
||||
modeThinking: "#e84393",
|
||||
modeToolExecution: "#ffa502",
|
||||
modePermission: "#cf6fef",
|
||||
|
||||
toolPending: "#9a7aa0",
|
||||
toolRunning: "#ffa502",
|
||||
toolSuccess: "#a3e048",
|
||||
toolError: "#ff4757",
|
||||
|
||||
headerGradient: ["#ff69b4", "#e84393", "#b47ee5"],
|
||||
};
|
||||
|
||||
export const THEMES: Record<string, Theme> = {
|
||||
default: {
|
||||
name: "default",
|
||||
@@ -861,6 +917,11 @@ export const THEMES: Record<string, Theme> = {
|
||||
displayName: "Cargdev Cyberpunk",
|
||||
colors: CARGDEV_CYBERPUNK_COLORS,
|
||||
},
|
||||
"pink-purple": {
|
||||
name: "pink-purple",
|
||||
displayName: "Pink Purple",
|
||||
colors: PINK_PURPLE_COLORS,
|
||||
},
|
||||
};
|
||||
|
||||
export const THEME_NAMES = Object.keys(THEMES);
|
||||
|
||||
@@ -13,6 +13,12 @@ export type SchemaSkipKey = (typeof SCHEMA_SKIP_KEYS)[number];
|
||||
export const TOOL_NAMES = ["read", "glob", "grep"];
|
||||
|
||||
/**
|
||||
* Tools that can modify files
|
||||
* Tools that can modify files — used for tracking modified files in the TUI
|
||||
*/
|
||||
export const FILE_MODIFYING_TOOLS = ["write", "edit"] as const;
|
||||
export const FILE_MODIFYING_TOOLS = [
|
||||
"write",
|
||||
"edit",
|
||||
"multi_edit",
|
||||
"apply_patch",
|
||||
"bash",
|
||||
] as const;
|
||||
|
||||
Reference in New Issue
Block a user