gencode-ai 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (274) hide show
  1. package/.env.example +11 -0
  2. package/CLAUDE.md +70 -0
  3. package/LICENSE +21 -0
  4. package/README.md +117 -0
  5. package/dist/agent/agent.d.ts +84 -0
  6. package/dist/agent/agent.d.ts.map +1 -0
  7. package/dist/agent/agent.js +233 -0
  8. package/dist/agent/agent.js.map +1 -0
  9. package/dist/agent/index.d.ts +6 -0
  10. package/dist/agent/index.d.ts.map +1 -0
  11. package/dist/agent/index.js +6 -0
  12. package/dist/agent/index.js.map +1 -0
  13. package/dist/agent/types.d.ts +47 -0
  14. package/dist/agent/types.d.ts.map +1 -0
  15. package/dist/agent/types.js +5 -0
  16. package/dist/agent/types.js.map +1 -0
  17. package/dist/cli/components/App.d.ts +14 -0
  18. package/dist/cli/components/App.d.ts.map +1 -0
  19. package/dist/cli/components/App.js +395 -0
  20. package/dist/cli/components/App.js.map +1 -0
  21. package/dist/cli/components/CommandSuggestions.d.ts +13 -0
  22. package/dist/cli/components/CommandSuggestions.d.ts.map +1 -0
  23. package/dist/cli/components/CommandSuggestions.js +32 -0
  24. package/dist/cli/components/CommandSuggestions.js.map +1 -0
  25. package/dist/cli/components/Header.d.ts +9 -0
  26. package/dist/cli/components/Header.d.ts.map +1 -0
  27. package/dist/cli/components/Header.js +13 -0
  28. package/dist/cli/components/Header.js.map +1 -0
  29. package/dist/cli/components/Input.d.ts +13 -0
  30. package/dist/cli/components/Input.d.ts.map +1 -0
  31. package/dist/cli/components/Input.js +27 -0
  32. package/dist/cli/components/Input.js.map +1 -0
  33. package/dist/cli/components/Logo.d.ts +2 -0
  34. package/dist/cli/components/Logo.d.ts.map +1 -0
  35. package/dist/cli/components/Logo.js +8 -0
  36. package/dist/cli/components/Logo.js.map +1 -0
  37. package/dist/cli/components/Messages.d.ts +37 -0
  38. package/dist/cli/components/Messages.d.ts.map +1 -0
  39. package/dist/cli/components/Messages.js +106 -0
  40. package/dist/cli/components/Messages.js.map +1 -0
  41. package/dist/cli/components/ModelSelector.d.ts +13 -0
  42. package/dist/cli/components/ModelSelector.d.ts.map +1 -0
  43. package/dist/cli/components/ModelSelector.js +72 -0
  44. package/dist/cli/components/ModelSelector.js.map +1 -0
  45. package/dist/cli/components/Spinner.d.ts +12 -0
  46. package/dist/cli/components/Spinner.d.ts.map +1 -0
  47. package/dist/cli/components/Spinner.js +45 -0
  48. package/dist/cli/components/Spinner.js.map +1 -0
  49. package/dist/cli/components/index.d.ts +12 -0
  50. package/dist/cli/components/index.d.ts.map +1 -0
  51. package/dist/cli/components/index.js +12 -0
  52. package/dist/cli/components/index.js.map +1 -0
  53. package/dist/cli/components/theme.d.ts +31 -0
  54. package/dist/cli/components/theme.d.ts.map +1 -0
  55. package/dist/cli/components/theme.js +36 -0
  56. package/dist/cli/components/theme.js.map +1 -0
  57. package/dist/cli/index-legacy.d.ts +7 -0
  58. package/dist/cli/index-legacy.d.ts.map +1 -0
  59. package/dist/cli/index-legacy.js +431 -0
  60. package/dist/cli/index-legacy.js.map +1 -0
  61. package/dist/cli/index.d.ts +7 -0
  62. package/dist/cli/index.d.ts.map +1 -0
  63. package/dist/cli/index.js +116 -0
  64. package/dist/cli/index.js.map +1 -0
  65. package/dist/cli/ink-cli.d.ts +7 -0
  66. package/dist/cli/ink-cli.d.ts.map +1 -0
  67. package/dist/cli/ink-cli.js +105 -0
  68. package/dist/cli/ink-cli.js.map +1 -0
  69. package/dist/cli/session-picker.d.ts +16 -0
  70. package/dist/cli/session-picker.d.ts.map +1 -0
  71. package/dist/cli/session-picker.js +280 -0
  72. package/dist/cli/session-picker.js.map +1 -0
  73. package/dist/cli/ui.d.ts +61 -0
  74. package/dist/cli/ui.d.ts.map +1 -0
  75. package/dist/cli/ui.js +364 -0
  76. package/dist/cli/ui.js.map +1 -0
  77. package/dist/config/index.d.ts +7 -0
  78. package/dist/config/index.d.ts.map +1 -0
  79. package/dist/config/index.js +6 -0
  80. package/dist/config/index.js.map +1 -0
  81. package/dist/config/manager.d.ts +31 -0
  82. package/dist/config/manager.d.ts.map +1 -0
  83. package/dist/config/manager.js +65 -0
  84. package/dist/config/manager.js.map +1 -0
  85. package/dist/config/types.d.ts +22 -0
  86. package/dist/config/types.d.ts.map +1 -0
  87. package/dist/config/types.js +6 -0
  88. package/dist/config/types.js.map +1 -0
  89. package/dist/index.d.ts +12 -0
  90. package/dist/index.d.ts.map +1 -0
  91. package/dist/index.js +21 -0
  92. package/dist/index.js.map +1 -0
  93. package/dist/memory/index.d.ts +10 -0
  94. package/dist/memory/index.d.ts.map +1 -0
  95. package/dist/memory/index.js +9 -0
  96. package/dist/memory/index.js.map +1 -0
  97. package/dist/memory/init.d.ts +20 -0
  98. package/dist/memory/init.d.ts.map +1 -0
  99. package/dist/memory/init.js +332 -0
  100. package/dist/memory/init.js.map +1 -0
  101. package/dist/memory/manager.d.ts +85 -0
  102. package/dist/memory/manager.d.ts.map +1 -0
  103. package/dist/memory/manager.js +234 -0
  104. package/dist/memory/manager.js.map +1 -0
  105. package/dist/memory/types.d.ts +74 -0
  106. package/dist/memory/types.d.ts.map +1 -0
  107. package/dist/memory/types.js +6 -0
  108. package/dist/memory/types.js.map +1 -0
  109. package/dist/permissions/index.d.ts +7 -0
  110. package/dist/permissions/index.d.ts.map +1 -0
  111. package/dist/permissions/index.js +6 -0
  112. package/dist/permissions/index.js.map +1 -0
  113. package/dist/permissions/manager.d.ts +32 -0
  114. package/dist/permissions/manager.d.ts.map +1 -0
  115. package/dist/permissions/manager.js +79 -0
  116. package/dist/permissions/manager.js.map +1 -0
  117. package/dist/permissions/types.d.ts +14 -0
  118. package/dist/permissions/types.d.ts.map +1 -0
  119. package/dist/permissions/types.js +17 -0
  120. package/dist/permissions/types.js.map +1 -0
  121. package/dist/providers/anthropic.d.ts +20 -0
  122. package/dist/providers/anthropic.d.ts.map +1 -0
  123. package/dist/providers/anthropic.js +185 -0
  124. package/dist/providers/anthropic.js.map +1 -0
  125. package/dist/providers/gemini.d.ts +21 -0
  126. package/dist/providers/gemini.d.ts.map +1 -0
  127. package/dist/providers/gemini.js +241 -0
  128. package/dist/providers/gemini.js.map +1 -0
  129. package/dist/providers/index.d.ts +34 -0
  130. package/dist/providers/index.d.ts.map +1 -0
  131. package/dist/providers/index.js +72 -0
  132. package/dist/providers/index.js.map +1 -0
  133. package/dist/providers/openai.d.ts +19 -0
  134. package/dist/providers/openai.d.ts.map +1 -0
  135. package/dist/providers/openai.js +221 -0
  136. package/dist/providers/openai.js.map +1 -0
  137. package/dist/providers/types.d.ts +125 -0
  138. package/dist/providers/types.d.ts.map +1 -0
  139. package/dist/providers/types.js +6 -0
  140. package/dist/providers/types.js.map +1 -0
  141. package/dist/session/index.d.ts +6 -0
  142. package/dist/session/index.d.ts.map +1 -0
  143. package/dist/session/index.js +6 -0
  144. package/dist/session/index.js.map +1 -0
  145. package/dist/session/manager.d.ts +101 -0
  146. package/dist/session/manager.d.ts.map +1 -0
  147. package/dist/session/manager.js +295 -0
  148. package/dist/session/manager.js.map +1 -0
  149. package/dist/session/types.d.ts +39 -0
  150. package/dist/session/types.d.ts.map +1 -0
  151. package/dist/session/types.js +10 -0
  152. package/dist/session/types.js.map +1 -0
  153. package/dist/tools/builtin/bash.d.ts +7 -0
  154. package/dist/tools/builtin/bash.d.ts.map +1 -0
  155. package/dist/tools/builtin/bash.js +80 -0
  156. package/dist/tools/builtin/bash.js.map +1 -0
  157. package/dist/tools/builtin/edit.d.ts +7 -0
  158. package/dist/tools/builtin/edit.d.ts.map +1 -0
  159. package/dist/tools/builtin/edit.js +32 -0
  160. package/dist/tools/builtin/edit.js.map +1 -0
  161. package/dist/tools/builtin/glob.d.ts +7 -0
  162. package/dist/tools/builtin/glob.d.ts.map +1 -0
  163. package/dist/tools/builtin/glob.js +36 -0
  164. package/dist/tools/builtin/glob.js.map +1 -0
  165. package/dist/tools/builtin/grep.d.ts +7 -0
  166. package/dist/tools/builtin/grep.d.ts.map +1 -0
  167. package/dist/tools/builtin/grep.js +59 -0
  168. package/dist/tools/builtin/grep.js.map +1 -0
  169. package/dist/tools/builtin/read.d.ts +7 -0
  170. package/dist/tools/builtin/read.d.ts.map +1 -0
  171. package/dist/tools/builtin/read.js +29 -0
  172. package/dist/tools/builtin/read.js.map +1 -0
  173. package/dist/tools/builtin/write.d.ts +7 -0
  174. package/dist/tools/builtin/write.d.ts.map +1 -0
  175. package/dist/tools/builtin/write.js +24 -0
  176. package/dist/tools/builtin/write.js.map +1 -0
  177. package/dist/tools/index.d.ts +38 -0
  178. package/dist/tools/index.d.ts.map +1 -0
  179. package/dist/tools/index.js +32 -0
  180. package/dist/tools/index.js.map +1 -0
  181. package/dist/tools/registry.d.ts +22 -0
  182. package/dist/tools/registry.d.ts.map +1 -0
  183. package/dist/tools/registry.js +71 -0
  184. package/dist/tools/registry.js.map +1 -0
  185. package/dist/tools/types.d.ts +62 -0
  186. package/dist/tools/types.d.ts.map +1 -0
  187. package/dist/tools/types.js +126 -0
  188. package/dist/tools/types.js.map +1 -0
  189. package/docs/README.md +16 -0
  190. package/docs/proposals/0001-web-fetch-tool.md +293 -0
  191. package/docs/proposals/0002-web-search-tool.md +306 -0
  192. package/docs/proposals/0003-task-subagents.md +333 -0
  193. package/docs/proposals/0004-plan-mode.md +338 -0
  194. package/docs/proposals/0005-todo-system.md +299 -0
  195. package/docs/proposals/0006-memory-system.md +539 -0
  196. package/docs/proposals/0007-context-management.md +429 -0
  197. package/docs/proposals/0008-checkpointing.md +327 -0
  198. package/docs/proposals/0009-hooks-system.md +343 -0
  199. package/docs/proposals/0010-mcp-integration.md +382 -0
  200. package/docs/proposals/0011-custom-commands.md +374 -0
  201. package/docs/proposals/0012-ask-user-question.md +317 -0
  202. package/docs/proposals/0013-multi-edit-tool.md +345 -0
  203. package/docs/proposals/0014-lsp-tool.md +478 -0
  204. package/docs/proposals/0015-ls-tool.md +407 -0
  205. package/docs/proposals/0016-kill-shell-tool.md +455 -0
  206. package/docs/proposals/0017-background-tasks.md +489 -0
  207. package/docs/proposals/0018-parallel-tool-execution.md +415 -0
  208. package/docs/proposals/0019-session-enhancements.md +462 -0
  209. package/docs/proposals/0020-session-summarization.md +447 -0
  210. package/docs/proposals/0021-skills-system.md +409 -0
  211. package/docs/proposals/0022-plugin-system.md +467 -0
  212. package/docs/proposals/0023-permission-enhancements.md +470 -0
  213. package/docs/proposals/0024-keyboard-shortcuts.md +443 -0
  214. package/docs/proposals/0025-cost-tracking.md +447 -0
  215. package/docs/proposals/0026-git-integration.md +475 -0
  216. package/docs/proposals/0027-enhanced-read-tool.md +514 -0
  217. package/docs/proposals/0028-enhanced-bash-tool.md +511 -0
  218. package/docs/proposals/0029-notebook-edit-tool.md +413 -0
  219. package/docs/proposals/0030-plugin-marketplace.md +360 -0
  220. package/docs/proposals/0031-command-suggestions.md +295 -0
  221. package/docs/proposals/0032-ide-integrations.md +328 -0
  222. package/docs/proposals/0033-enterprise-deployment.md +221 -0
  223. package/docs/proposals/0034-sandboxing.md +273 -0
  224. package/docs/proposals/0035-auto-updater.md +311 -0
  225. package/docs/proposals/0036-enhanced-glob-tool.md +267 -0
  226. package/docs/proposals/0037-enhanced-grep-tool.md +360 -0
  227. package/docs/proposals/0038-interactive-cli-ui.md +373 -0
  228. package/docs/proposals/0039-streaming-enhancements.md +359 -0
  229. package/docs/proposals/0040-multi-provider-enhancements.md +369 -0
  230. package/docs/proposals/README.md +84 -0
  231. package/docs/proposals/TEMPLATE.md +57 -0
  232. package/docs/proposals/research/claude-code-research.md +307 -0
  233. package/examples/agent-demo.ts +115 -0
  234. package/examples/basic.ts +166 -0
  235. package/package.json +50 -0
  236. package/src/agent/agent.ts +276 -0
  237. package/src/agent/index.ts +6 -0
  238. package/src/agent/types.ts +62 -0
  239. package/src/cli/components/App.tsx +565 -0
  240. package/src/cli/components/CommandSuggestions.tsx +58 -0
  241. package/src/cli/components/Header.tsx +36 -0
  242. package/src/cli/components/Input.tsx +60 -0
  243. package/src/cli/components/Logo.tsx +16 -0
  244. package/src/cli/components/Messages.tsx +210 -0
  245. package/src/cli/components/ModelSelector.tsx +135 -0
  246. package/src/cli/components/Spinner.tsx +72 -0
  247. package/src/cli/components/index.ts +21 -0
  248. package/src/cli/components/theme.ts +36 -0
  249. package/src/cli/index.tsx +136 -0
  250. package/src/config/index.ts +7 -0
  251. package/src/config/manager.ts +77 -0
  252. package/src/config/types.ts +25 -0
  253. package/src/index.ts +86 -0
  254. package/src/permissions/index.ts +7 -0
  255. package/src/permissions/manager.ts +97 -0
  256. package/src/permissions/types.ts +29 -0
  257. package/src/providers/anthropic.ts +224 -0
  258. package/src/providers/gemini.ts +295 -0
  259. package/src/providers/index.ts +97 -0
  260. package/src/providers/openai.ts +261 -0
  261. package/src/providers/types.ts +181 -0
  262. package/src/session/index.ts +6 -0
  263. package/src/session/manager.ts +354 -0
  264. package/src/session/types.ts +49 -0
  265. package/src/tools/builtin/bash.ts +92 -0
  266. package/src/tools/builtin/edit.ts +37 -0
  267. package/src/tools/builtin/glob.ts +42 -0
  268. package/src/tools/builtin/grep.ts +67 -0
  269. package/src/tools/builtin/read.ts +34 -0
  270. package/src/tools/builtin/write.ts +27 -0
  271. package/src/tools/index.ts +36 -0
  272. package/src/tools/registry.ts +83 -0
  273. package/src/tools/types.ts +172 -0
  274. package/tsconfig.json +21 -0
@@ -0,0 +1,443 @@
1
+ # Proposal: Keyboard Shortcuts
2
+
3
+ - **Proposal ID**: 0024
4
+ - **Author**: mycode team
5
+ - **Status**: Draft
6
+ - **Created**: 2025-01-15
7
+ - **Updated**: 2025-01-15
8
+
9
+ ## Summary
10
+
11
+ Implement a keyboard shortcuts system for common CLI operations, providing power users with efficient navigation and control. Shortcuts enable quick access to commands, history, and UI controls without typing full commands.
12
+
13
+ ## Motivation
14
+
15
+ Currently, mycode requires typing full commands for all operations:
16
+
17
+ 1. **Slow navigation**: Must type /sessions, /resume, etc.
18
+ 2. **No quick actions**: Can't quickly cancel, retry, or navigate
19
+ 3. **Limited editing**: Basic readline only
20
+ 4. **No vim/emacs mode**: Power users miss modal editing
21
+ 5. **Inefficient workflow**: Many keystrokes for common operations
22
+
23
+ Keyboard shortcuts enable faster, more efficient interaction.
24
+
25
+ ## Claude Code Reference
26
+
27
+ Claude Code provides several keyboard shortcuts:
28
+
29
+ ### Known Shortcuts
30
+ | Shortcut | Action |
31
+ |----------|--------|
32
+ | Ctrl+C | Cancel current operation |
33
+ | Ctrl+D | Exit (EOF) |
34
+ | Ctrl+L | Clear screen |
35
+ | Up/Down | Navigate history |
36
+ | Tab | Autocomplete |
37
+ | Escape | Cancel input / Exit mode |
38
+
39
+ ### Expected Features
40
+ - Command history navigation
41
+ - Input line editing
42
+ - Quick command access
43
+ - Mode switching
44
+ - Context-sensitive shortcuts
45
+
46
+ ## Detailed Design
47
+
48
+ ### API Design
49
+
50
+ ```typescript
51
+ // src/cli/shortcuts/types.ts
52
+ interface KeyBinding {
53
+ key: string; // e.g., "ctrl+r", "meta+enter"
54
+ action: string; // Action identifier
55
+ context?: ShortcutContext;
56
+ description: string;
57
+ }
58
+
59
+ type ShortcutContext =
60
+ | 'input' // During user input
61
+ | 'running' // While agent is running
62
+ | 'permission' // During permission prompt
63
+ | 'menu' // In menu/selection mode
64
+ | 'global'; // Always active
65
+
66
+ interface ShortcutConfig {
67
+ bindings: KeyBinding[];
68
+ enableVimMode: boolean;
69
+ enableEmacsMode: boolean;
70
+ }
71
+
72
+ interface ShortcutAction {
73
+ id: string;
74
+ name: string;
75
+ handler: (context: ActionContext) => Promise<void>;
76
+ }
77
+
78
+ interface ActionContext {
79
+ input: string;
80
+ cursorPosition: number;
81
+ session: Session;
82
+ isRunning: boolean;
83
+ }
84
+ ```
85
+
86
+ ### Shortcut Manager
87
+
88
+ ```typescript
89
+ // src/cli/shortcuts/manager.ts
90
+ class ShortcutManager {
91
+ private bindings: Map<string, KeyBinding[]> = new Map();
92
+ private actions: Map<string, ShortcutAction> = new Map();
93
+ private currentContext: ShortcutContext = 'input';
94
+ private vimMode: VimMode | null = null;
95
+
96
+ constructor(config?: Partial<ShortcutConfig>) {
97
+ this.loadDefaultBindings();
98
+ if (config?.enableVimMode) {
99
+ this.vimMode = new VimMode();
100
+ }
101
+ }
102
+
103
+ private loadDefaultBindings(): void {
104
+ const defaults: KeyBinding[] = [
105
+ // Global
106
+ { key: 'ctrl+c', action: 'cancel', context: 'global', description: 'Cancel operation' },
107
+ { key: 'ctrl+d', action: 'exit', context: 'global', description: 'Exit mycode' },
108
+ { key: 'ctrl+l', action: 'clear', context: 'global', description: 'Clear screen' },
109
+
110
+ // Input mode
111
+ { key: 'up', action: 'history_prev', context: 'input', description: 'Previous history' },
112
+ { key: 'down', action: 'history_next', context: 'input', description: 'Next history' },
113
+ { key: 'ctrl+r', action: 'history_search', context: 'input', description: 'Search history' },
114
+ { key: 'tab', action: 'autocomplete', context: 'input', description: 'Autocomplete' },
115
+ { key: 'ctrl+a', action: 'line_start', context: 'input', description: 'Go to line start' },
116
+ { key: 'ctrl+e', action: 'line_end', context: 'input', description: 'Go to line end' },
117
+ { key: 'ctrl+w', action: 'delete_word', context: 'input', description: 'Delete word' },
118
+ { key: 'ctrl+u', action: 'delete_line', context: 'input', description: 'Delete to start' },
119
+ { key: 'meta+enter', action: 'submit_multiline', context: 'input', description: 'Submit multiline' },
120
+
121
+ // Running mode
122
+ { key: 'ctrl+c', action: 'abort', context: 'running', description: 'Abort agent' },
123
+ { key: 'escape', action: 'interrupt', context: 'running', description: 'Interrupt gracefully' },
124
+
125
+ // Permission mode
126
+ { key: '1', action: 'allow_once', context: 'permission', description: 'Allow once' },
127
+ { key: '2', action: 'allow_session', context: 'permission', description: 'Allow for session' },
128
+ { key: '3', action: 'allow_always', context: 'permission', description: 'Always allow' },
129
+ { key: '4', action: 'deny', context: 'permission', description: 'Deny' },
130
+ { key: 'y', action: 'allow_once', context: 'permission', description: 'Yes (allow once)' },
131
+ { key: 'n', action: 'deny', context: 'permission', description: 'No (deny)' },
132
+
133
+ // Quick commands
134
+ { key: 'ctrl+s', action: 'save_session', context: 'input', description: 'Save session' },
135
+ { key: 'ctrl+n', action: 'new_session', context: 'input', description: 'New session' },
136
+ { key: 'ctrl+o', action: 'open_session', context: 'input', description: 'Open session picker' },
137
+ { key: 'f1', action: 'help', context: 'global', description: 'Show help' },
138
+ ];
139
+
140
+ for (const binding of defaults) {
141
+ this.addBinding(binding);
142
+ }
143
+ }
144
+
145
+ registerAction(action: ShortcutAction): void {
146
+ this.actions.set(action.id, action);
147
+ }
148
+
149
+ addBinding(binding: KeyBinding): void {
150
+ const existing = this.bindings.get(binding.key) || [];
151
+ existing.push(binding);
152
+ this.bindings.set(binding.key, existing);
153
+ }
154
+
155
+ setContext(context: ShortcutContext): void {
156
+ this.currentContext = context;
157
+ }
158
+
159
+ async handleKeypress(key: KeypressEvent): Promise<boolean> {
160
+ // Normalize key
161
+ const keyStr = this.normalizeKey(key);
162
+
163
+ // Check vim mode first
164
+ if (this.vimMode) {
165
+ const handled = await this.vimMode.handleKey(key);
166
+ if (handled) return true;
167
+ }
168
+
169
+ // Find matching bindings
170
+ const bindings = this.bindings.get(keyStr) || [];
171
+ const matching = bindings.filter(b =>
172
+ b.context === this.currentContext || b.context === 'global'
173
+ );
174
+
175
+ if (matching.length === 0) return false;
176
+
177
+ // Execute first matching action
178
+ const binding = matching[0];
179
+ const action = this.actions.get(binding.action);
180
+ if (action) {
181
+ await action.handler(this.getContext());
182
+ return true;
183
+ }
184
+
185
+ return false;
186
+ }
187
+
188
+ private normalizeKey(event: KeypressEvent): string {
189
+ const parts: string[] = [];
190
+ if (event.ctrl) parts.push('ctrl');
191
+ if (event.meta) parts.push('meta');
192
+ if (event.shift && event.name.length > 1) parts.push('shift');
193
+ parts.push(event.name.toLowerCase());
194
+ return parts.join('+');
195
+ }
196
+
197
+ listBindings(context?: ShortcutContext): KeyBinding[] {
198
+ const all = Array.from(this.bindings.values()).flat();
199
+ return context
200
+ ? all.filter(b => b.context === context || b.context === 'global')
201
+ : all;
202
+ }
203
+ }
204
+ ```
205
+
206
+ ### Vim Mode
207
+
208
+ ```typescript
209
+ // src/cli/shortcuts/vim-mode.ts
210
+ type VimState = 'normal' | 'insert' | 'visual' | 'command';
211
+
212
+ class VimMode {
213
+ private state: VimState = 'insert';
214
+ private commandBuffer: string = '';
215
+ private registerContent: string = '';
216
+
217
+ handleKey(event: KeypressEvent): boolean {
218
+ switch (this.state) {
219
+ case 'insert':
220
+ return this.handleInsertMode(event);
221
+ case 'normal':
222
+ return this.handleNormalMode(event);
223
+ case 'visual':
224
+ return this.handleVisualMode(event);
225
+ case 'command':
226
+ return this.handleCommandMode(event);
227
+ }
228
+ }
229
+
230
+ private handleInsertMode(event: KeypressEvent): boolean {
231
+ if (event.name === 'escape') {
232
+ this.state = 'normal';
233
+ return true;
234
+ }
235
+ return false; // Let normal input handling take over
236
+ }
237
+
238
+ private handleNormalMode(event: KeypressEvent): boolean {
239
+ const key = event.name;
240
+
241
+ // Mode transitions
242
+ if (key === 'i') { this.state = 'insert'; return true; }
243
+ if (key === 'a') { this.state = 'insert'; /* move cursor right */ return true; }
244
+ if (key === 'v') { this.state = 'visual'; return true; }
245
+ if (key === ':') { this.state = 'command'; this.commandBuffer = ''; return true; }
246
+
247
+ // Navigation
248
+ if (key === 'h') { /* move left */ return true; }
249
+ if (key === 'j') { /* history next */ return true; }
250
+ if (key === 'k') { /* history prev */ return true; }
251
+ if (key === 'l') { /* move right */ return true; }
252
+ if (key === 'w') { /* word forward */ return true; }
253
+ if (key === 'b') { /* word back */ return true; }
254
+ if (key === '0') { /* line start */ return true; }
255
+ if (key === '$') { /* line end */ return true; }
256
+
257
+ // Editing
258
+ if (key === 'x') { /* delete char */ return true; }
259
+ if (key === 'd') { /* start delete */ return true; }
260
+ if (key === 'y') { /* start yank */ return true; }
261
+ if (key === 'p') { /* paste */ return true; }
262
+ if (key === 'u') { /* undo */ return true; }
263
+
264
+ return false;
265
+ }
266
+
267
+ private handleCommandMode(event: KeypressEvent): boolean {
268
+ if (event.name === 'escape') {
269
+ this.state = 'normal';
270
+ this.commandBuffer = '';
271
+ return true;
272
+ }
273
+
274
+ if (event.name === 'return') {
275
+ this.executeCommand(this.commandBuffer);
276
+ this.state = 'normal';
277
+ this.commandBuffer = '';
278
+ return true;
279
+ }
280
+
281
+ this.commandBuffer += event.sequence;
282
+ return true;
283
+ }
284
+
285
+ private executeCommand(cmd: string): void {
286
+ switch (cmd) {
287
+ case 'w': /* save */ break;
288
+ case 'q': /* quit */ break;
289
+ case 'wq': /* save and quit */ break;
290
+ case 'help': /* show help */ break;
291
+ }
292
+ }
293
+
294
+ getState(): VimState {
295
+ return this.state;
296
+ }
297
+
298
+ getModeIndicator(): string {
299
+ const indicators = {
300
+ insert: '-- INSERT --',
301
+ normal: '-- NORMAL --',
302
+ visual: '-- VISUAL --',
303
+ command: `:${this.commandBuffer}`
304
+ };
305
+ return indicators[this.state];
306
+ }
307
+ }
308
+ ```
309
+
310
+ ### File Changes
311
+
312
+ | File | Action | Description |
313
+ |------|--------|-------------|
314
+ | `src/cli/shortcuts/types.ts` | Create | Type definitions |
315
+ | `src/cli/shortcuts/manager.ts` | Create | Shortcut management |
316
+ | `src/cli/shortcuts/vim-mode.ts` | Create | Vim mode support |
317
+ | `src/cli/shortcuts/actions.ts` | Create | Built-in actions |
318
+ | `src/cli/shortcuts/index.ts` | Create | Module exports |
319
+ | `src/cli/index.ts` | Modify | Integrate shortcuts |
320
+ | `src/cli/input.ts` | Modify | Key handling |
321
+
322
+ ## User Experience
323
+
324
+ ### Help Display
325
+ ```
326
+ User: (presses F1 or /shortcuts)
327
+
328
+ Keyboard Shortcuts:
329
+ ┌────────────────────────────────────────────────────────────┐
330
+ │ Global │
331
+ │ Ctrl+C Cancel/abort current operation │
332
+ │ Ctrl+D Exit mycode │
333
+ │ Ctrl+L Clear screen │
334
+ │ F1 Show this help │
335
+ │ │
336
+ │ Input Mode │
337
+ │ Up/Down Navigate command history │
338
+ │ Ctrl+R Search history │
339
+ │ Tab Autocomplete commands │
340
+ │ Ctrl+A/E Go to start/end of line │
341
+ │ Meta+Enter Submit multiline input │
342
+ │ Ctrl+S Save current session │
343
+ │ Ctrl+N New session │
344
+ │ Ctrl+O Open session picker │
345
+ │ │
346
+ │ Permission Prompt │
347
+ │ 1/y Allow once │
348
+ │ 2 Allow for session │
349
+ │ 3 Always allow │
350
+ │ 4/n Deny │
351
+ └────────────────────────────────────────────────────────────┘
352
+
353
+ Vim mode: Disabled (enable in settings)
354
+ ```
355
+
356
+ ### Vim Mode Indicator
357
+ ```
358
+ ┌─ mycode ──────────────────────────────────────────────────┐
359
+ │ > type your message here_ │
360
+ │ │
361
+ │ -- INSERT -- │
362
+ └───────────────────────────────────────────────────────────┘
363
+
364
+ (press Escape)
365
+
366
+ ┌─ mycode ──────────────────────────────────────────────────┐
367
+ │ > type your message here │
368
+ │ ^ │
369
+ │ -- NORMAL -- │
370
+ └───────────────────────────────────────────────────────────┘
371
+ ```
372
+
373
+ ### History Search (Ctrl+R)
374
+ ```
375
+ (reverse-i-search)`auth': /sessions --tag authentication
376
+
377
+ Press Enter to select, Ctrl+R for next match, Esc to cancel
378
+ ```
379
+
380
+ ## Alternatives Considered
381
+
382
+ ### Alternative 1: Mouse-based UI
383
+ Add clickable UI elements.
384
+
385
+ **Pros**: Discoverable
386
+ **Cons**: Requires terminal mouse support
387
+ **Decision**: Deferred - Can add alongside shortcuts
388
+
389
+ ### Alternative 2: Command Palette
390
+ VS Code-style command palette.
391
+
392
+ **Pros**: Discoverable, searchable
393
+ **Cons**: More complex UI
394
+ **Decision**: Consider for future
395
+
396
+ ### Alternative 3: No Vim Mode
397
+ Skip vim/emacs modes.
398
+
399
+ **Pros**: Simpler
400
+ **Cons**: Power users miss it
401
+ **Decision**: Rejected - Vim mode is expected
402
+
403
+ ## Security Considerations
404
+
405
+ 1. **Input Validation**: Validate shortcut configurations
406
+ 2. **No Injection**: Shortcuts can't execute arbitrary commands
407
+ 3. **Confirmation**: Dangerous actions still require confirmation
408
+ 4. **Escape Hatch**: Always allow Ctrl+C to abort
409
+
410
+ ## Testing Strategy
411
+
412
+ 1. **Unit Tests**:
413
+ - Key normalization
414
+ - Binding matching
415
+ - Action execution
416
+ - Vim mode state machine
417
+
418
+ 2. **Integration Tests**:
419
+ - Full input handling
420
+ - Context switching
421
+ - History navigation
422
+
423
+ 3. **Manual Testing**:
424
+ - Various terminal emulators
425
+ - Key combinations
426
+ - Vim workflow
427
+
428
+ ## Migration Path
429
+
430
+ 1. **Phase 1**: Basic shortcuts (Ctrl+C, arrows, etc.)
431
+ 2. **Phase 2**: History search
432
+ 3. **Phase 3**: Vim mode
433
+ 4. **Phase 4**: Customization
434
+ 5. **Phase 5**: Emacs mode
435
+
436
+ No breaking changes - enhances existing input.
437
+
438
+ ## References
439
+
440
+ - [readline - Node.js](https://nodejs.org/api/readline.html)
441
+ - [Vim Commands Cheat Sheet](https://vim.rtorr.com/)
442
+ - [GNU Readline](https://tiswww.case.edu/php/chet/readline/readline.html)
443
+ - [Inquirer.js](https://github.com/SBoudrias/Inquirer.js)