@cdoing/cli 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 (118) hide show
  1. package/.cdoing/permissions.json +8 -0
  2. package/dist/callbacks.d.ts +17 -0
  3. package/dist/callbacks.d.ts.map +1 -0
  4. package/dist/callbacks.js +265 -0
  5. package/dist/callbacks.js.map +1 -0
  6. package/dist/chat.d.ts +27 -0
  7. package/dist/chat.d.ts.map +1 -0
  8. package/dist/chat.js +57 -0
  9. package/dist/chat.js.map +1 -0
  10. package/dist/commands.d.ts +22 -0
  11. package/dist/commands.d.ts.map +1 -0
  12. package/dist/commands.js +452 -0
  13. package/dist/commands.js.map +1 -0
  14. package/dist/config.d.ts +84 -0
  15. package/dist/config.d.ts.map +1 -0
  16. package/dist/config.js +427 -0
  17. package/dist/config.js.map +1 -0
  18. package/dist/help.d.ts +9 -0
  19. package/dist/help.d.ts.map +1 -0
  20. package/dist/help.js +167 -0
  21. package/dist/help.js.map +1 -0
  22. package/dist/history.d.ts +51 -0
  23. package/dist/history.d.ts.map +1 -0
  24. package/dist/history.js +207 -0
  25. package/dist/history.js.map +1 -0
  26. package/dist/index.d.ts +7 -0
  27. package/dist/index.d.ts.map +1 -0
  28. package/dist/index.js +220 -0
  29. package/dist/index.js.map +1 -0
  30. package/dist/oauth.d.ts +13 -0
  31. package/dist/oauth.d.ts.map +1 -0
  32. package/dist/oauth.js +182 -0
  33. package/dist/oauth.js.map +1 -0
  34. package/dist/review.d.ts +26 -0
  35. package/dist/review.d.ts.map +1 -0
  36. package/dist/review.js +198 -0
  37. package/dist/review.js.map +1 -0
  38. package/dist/serve.d.ts +23 -0
  39. package/dist/serve.d.ts.map +1 -0
  40. package/dist/serve.js +293 -0
  41. package/dist/serve.js.map +1 -0
  42. package/dist/tools.d.ts +14 -0
  43. package/dist/tools.d.ts.map +1 -0
  44. package/dist/tools.js +57 -0
  45. package/dist/tools.js.map +1 -0
  46. package/dist/ui/App.d.ts +24 -0
  47. package/dist/ui/App.d.ts.map +1 -0
  48. package/dist/ui/App.js +321 -0
  49. package/dist/ui/App.js.map +1 -0
  50. package/dist/ui/MessageList.d.ts +14 -0
  51. package/dist/ui/MessageList.d.ts.map +1 -0
  52. package/dist/ui/MessageList.js +147 -0
  53. package/dist/ui/MessageList.js.map +1 -0
  54. package/dist/ui/SessionBrowser.d.ts +18 -0
  55. package/dist/ui/SessionBrowser.d.ts.map +1 -0
  56. package/dist/ui/SessionBrowser.js +149 -0
  57. package/dist/ui/SessionBrowser.js.map +1 -0
  58. package/dist/ui/SetupWizard.d.ts +23 -0
  59. package/dist/ui/SetupWizard.d.ts.map +1 -0
  60. package/dist/ui/SetupWizard.js +402 -0
  61. package/dist/ui/SetupWizard.js.map +1 -0
  62. package/dist/ui/Spinner.d.ts +15 -0
  63. package/dist/ui/Spinner.d.ts.map +1 -0
  64. package/dist/ui/Spinner.js +111 -0
  65. package/dist/ui/Spinner.js.map +1 -0
  66. package/dist/ui/StatusBar.d.ts +16 -0
  67. package/dist/ui/StatusBar.d.ts.map +1 -0
  68. package/dist/ui/StatusBar.js +56 -0
  69. package/dist/ui/StatusBar.js.map +1 -0
  70. package/dist/ui/UserInput.d.ts +13 -0
  71. package/dist/ui/UserInput.d.ts.map +1 -0
  72. package/dist/ui/UserInput.js +872 -0
  73. package/dist/ui/UserInput.js.map +1 -0
  74. package/dist/ui/hooks/helpers.d.ts +55 -0
  75. package/dist/ui/hooks/helpers.d.ts.map +1 -0
  76. package/dist/ui/hooks/helpers.js +304 -0
  77. package/dist/ui/hooks/helpers.js.map +1 -0
  78. package/dist/ui/hooks/useAgent.d.ts +60 -0
  79. package/dist/ui/hooks/useAgent.d.ts.map +1 -0
  80. package/dist/ui/hooks/useAgent.js +213 -0
  81. package/dist/ui/hooks/useAgent.js.map +1 -0
  82. package/dist/ui/hooks/useChat.d.ts +74 -0
  83. package/dist/ui/hooks/useChat.d.ts.map +1 -0
  84. package/dist/ui/hooks/useChat.js +819 -0
  85. package/dist/ui/hooks/useChat.js.map +1 -0
  86. package/dist/ui/theme.d.ts +73 -0
  87. package/dist/ui/theme.d.ts.map +1 -0
  88. package/dist/ui/theme.js +214 -0
  89. package/dist/ui/theme.js.map +1 -0
  90. package/dist/ui/types.d.ts +37 -0
  91. package/dist/ui/types.d.ts.map +1 -0
  92. package/dist/ui/types.js +3 -0
  93. package/dist/ui/types.js.map +1 -0
  94. package/package.json +33 -0
  95. package/src/callbacks.ts +294 -0
  96. package/src/chat.ts +72 -0
  97. package/src/commands.ts +425 -0
  98. package/src/config.ts +462 -0
  99. package/src/help.ts +182 -0
  100. package/src/history.ts +205 -0
  101. package/src/index.ts +248 -0
  102. package/src/oauth.ts +164 -0
  103. package/src/review.ts +233 -0
  104. package/src/serve.ts +290 -0
  105. package/src/tools.ts +104 -0
  106. package/src/ui/App.tsx +426 -0
  107. package/src/ui/MessageList.tsx +222 -0
  108. package/src/ui/SessionBrowser.tsx +161 -0
  109. package/src/ui/SetupWizard.tsx +412 -0
  110. package/src/ui/Spinner.tsx +103 -0
  111. package/src/ui/StatusBar.tsx +106 -0
  112. package/src/ui/UserInput.tsx +954 -0
  113. package/src/ui/hooks/helpers.ts +271 -0
  114. package/src/ui/hooks/useAgent.ts +270 -0
  115. package/src/ui/hooks/useChat.ts +943 -0
  116. package/src/ui/theme.ts +326 -0
  117. package/src/ui/types.ts +41 -0
  118. package/tsconfig.json +18 -0
@@ -0,0 +1,872 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.UserInput = void 0;
37
+ const react_1 = __importStar(require("react"));
38
+ const ink_1 = require("ink");
39
+ const fs = __importStar(require("fs"));
40
+ const path = __importStar(require("path"));
41
+ const theme_1 = require("./theme");
42
+ const SLASH_COMMANDS = [
43
+ { cmd: "/help", desc: "Show help" },
44
+ { cmd: "/clear", desc: "Clear conversation" },
45
+ { cmd: "/new", desc: "New conversation" },
46
+ { cmd: "/ls", desc: "Browse sessions (interactive TUI)" },
47
+ { cmd: "/history", desc: "List saved conversations (text)" },
48
+ { cmd: "/resume", desc: "Resume a conversation" },
49
+ { cmd: "/fork", desc: "Fork current or given conversation" },
50
+ { cmd: "/delete", desc: "Delete a conversation" },
51
+ { cmd: "/config", desc: "View/update config" },
52
+ { cmd: "/model", desc: "Switch model" },
53
+ { cmd: "/provider", desc: "Switch provider" },
54
+ { cmd: "/mode", desc: "Change permission mode" },
55
+ { cmd: "/dir", desc: "Change working directory" },
56
+ { cmd: "/permissions", desc: "View/clear permissions" },
57
+ { cmd: "/memory", desc: "View/manage memory" },
58
+ { cmd: "/hooks", desc: "View configured hooks" },
59
+ { cmd: "/usage", desc: "Token usage" },
60
+ { cmd: "/compact", desc: "Compact context" },
61
+ { cmd: "/tasks", desc: "Show task list" },
62
+ { cmd: "/plan", desc: "Toggle plan mode" },
63
+ { cmd: "/effort", desc: "Set analysis depth" },
64
+ { cmd: "/btw", desc: "Ask without adding to history" },
65
+ { cmd: "/bg", desc: "Run prompt as background job" },
66
+ { cmd: "/jobs", desc: "Show background jobs" },
67
+ { cmd: "/rules", desc: "View project rules" },
68
+ { cmd: "/mcp", desc: "MCP server status / interactive picker" },
69
+ { cmd: "/context", desc: "List context providers" },
70
+ { cmd: "/queue", desc: "Show message queue" },
71
+ { cmd: "/theme", desc: "Switch theme (dark/light/auto)" },
72
+ { cmd: "/setup", desc: "View & change provider / model / API key" },
73
+ { cmd: "/doctor", desc: "Check system health" },
74
+ { cmd: "/init", desc: "Initialize project" },
75
+ { cmd: "/login", desc: "Open setup wizard to authenticate" },
76
+ { cmd: "/logout", desc: "Clear OAuth tokens" },
77
+ { cmd: "/auth-status", desc: "Show auth status" },
78
+ { cmd: "/exit", desc: "Quit" },
79
+ ];
80
+ const AT_PROVIDERS = [
81
+ { cmd: "@terminal", desc: "Recent terminal output" },
82
+ { cmd: "@url", desc: "Fetch a URL (@url https://...)" },
83
+ { cmd: "@tree", desc: "Project file tree" },
84
+ { cmd: "@codebase", desc: "Full codebase context" },
85
+ { cmd: "@clip", desc: "Paste clipboard content" },
86
+ { cmd: "@file", desc: "Include a file's contents (@file src/foo.ts)" },
87
+ ];
88
+ // Shell commands that always take a path argument (hardcoded core set)
89
+ const PATH_COMMANDS_CORE = new Set([
90
+ "cd", "ls", "ll", "la", "cat", "less", "more", "head", "tail",
91
+ "vim", "vi", "nvim", "nano", "code", "open",
92
+ "cp", "mv", "rm", "mkdir", "rmdir", "touch", "ln", "chmod", "chown",
93
+ "diff", "wc", "file", "stat", "find",
94
+ ]);
95
+ // Lazily resolved: all executable names found on $PATH
96
+ let _pathBinaries = null;
97
+ function getPathBinaries() {
98
+ if (_pathBinaries)
99
+ return _pathBinaries;
100
+ _pathBinaries = new Set(PATH_COMMANDS_CORE);
101
+ try {
102
+ const dirs = (process.env.PATH || "").split(path.delimiter).filter(Boolean);
103
+ for (const dir of dirs) {
104
+ try {
105
+ const entries = fs.readdirSync(dir);
106
+ for (const e of entries)
107
+ _pathBinaries.add(e);
108
+ }
109
+ catch { /* skip unreadable dir */ }
110
+ }
111
+ }
112
+ catch { /* ignore */ }
113
+ return _pathBinaries;
114
+ }
115
+ const TOOL_SUBCOMMANDS = {
116
+ npm: [
117
+ { cmd: "install", desc: "Install dependencies" },
118
+ { cmd: "install -g", desc: "Install package globally" },
119
+ { cmd: "run", desc: "Run a script" },
120
+ { cmd: "run dev", desc: "Start dev server" },
121
+ { cmd: "run build", desc: "Build project" },
122
+ { cmd: "run test", desc: "Run tests" },
123
+ { cmd: "run lint", desc: "Lint code" },
124
+ { cmd: "start", desc: "Start application" },
125
+ { cmd: "test", desc: "Run tests" },
126
+ { cmd: "publish", desc: "Publish package" },
127
+ { cmd: "update", desc: "Update dependencies" },
128
+ { cmd: "uninstall", desc: "Remove a package" },
129
+ { cmd: "ls", desc: "List installed packages" },
130
+ { cmd: "audit", desc: "Security audit" },
131
+ { cmd: "outdated", desc: "Show outdated packages" },
132
+ { cmd: "init", desc: "Create package.json" },
133
+ { cmd: "ci", desc: "Clean install" },
134
+ ],
135
+ npx: [
136
+ { cmd: "create-react-app", desc: "Create React app" },
137
+ { cmd: "create-next-app", desc: "Create Next.js app" },
138
+ { cmd: "tsc", desc: "TypeScript compiler" },
139
+ { cmd: "eslint", desc: "Run ESLint" },
140
+ { cmd: "prettier", desc: "Format code" },
141
+ ],
142
+ yarn: [
143
+ { cmd: "install", desc: "Install dependencies" },
144
+ { cmd: "add", desc: "Add a package" },
145
+ { cmd: "add -D", desc: "Add dev dependency" },
146
+ { cmd: "remove", desc: "Remove a package" },
147
+ { cmd: "run dev", desc: "Start dev server" },
148
+ { cmd: "run build", desc: "Build project" },
149
+ { cmd: "run test", desc: "Run tests" },
150
+ { cmd: "upgrade", desc: "Upgrade packages" },
151
+ { cmd: "workspace", desc: "Run command in workspace" },
152
+ { cmd: "workspaces", desc: "Run command in all workspaces" },
153
+ ],
154
+ pnpm: [
155
+ { cmd: "install", desc: "Install dependencies" },
156
+ { cmd: "add", desc: "Add a package" },
157
+ { cmd: "add -D", desc: "Add dev dependency" },
158
+ { cmd: "remove", desc: "Remove a package" },
159
+ { cmd: "run dev", desc: "Start dev server" },
160
+ { cmd: "run build", desc: "Build project" },
161
+ { cmd: "run test", desc: "Run tests" },
162
+ ],
163
+ git: [
164
+ { cmd: "status", desc: "Show working tree status" },
165
+ { cmd: "add .", desc: "Stage all changes" },
166
+ { cmd: "add -p", desc: "Interactive staging" },
167
+ { cmd: "commit -m", desc: "Commit with message" },
168
+ { cmd: "push", desc: "Push to remote" },
169
+ { cmd: "pull", desc: "Pull from remote" },
170
+ { cmd: "checkout", desc: "Switch branch / restore file" },
171
+ { cmd: "checkout -b", desc: "Create and switch branch" },
172
+ { cmd: "branch", desc: "List / create branches" },
173
+ { cmd: "branch -d", desc: "Delete branch" },
174
+ { cmd: "merge", desc: "Merge branch" },
175
+ { cmd: "rebase", desc: "Rebase onto branch" },
176
+ { cmd: "log --oneline", desc: "Compact commit log" },
177
+ { cmd: "diff", desc: "Show unstaged diff" },
178
+ { cmd: "diff --staged", desc: "Show staged diff" },
179
+ { cmd: "stash", desc: "Stash changes" },
180
+ { cmd: "stash pop", desc: "Apply stashed changes" },
181
+ { cmd: "fetch", desc: "Fetch from remote" },
182
+ { cmd: "remote -v", desc: "List remotes" },
183
+ { cmd: "clone", desc: "Clone repository" },
184
+ { cmd: "init", desc: "Initialize repository" },
185
+ { cmd: "reset --hard", desc: "Discard all local changes" },
186
+ { cmd: "cherry-pick", desc: "Apply specific commit" },
187
+ { cmd: "tag", desc: "Create / list tags" },
188
+ ],
189
+ gh: [
190
+ { cmd: "pr create", desc: "Create pull request" },
191
+ { cmd: "pr list", desc: "List pull requests" },
192
+ { cmd: "pr checkout", desc: "Check out pull request" },
193
+ { cmd: "pr merge", desc: "Merge pull request" },
194
+ { cmd: "issue create", desc: "Create issue" },
195
+ { cmd: "issue list", desc: "List issues" },
196
+ { cmd: "repo clone", desc: "Clone repository" },
197
+ { cmd: "run list", desc: "List workflow runs" },
198
+ { cmd: "run view", desc: "View workflow run" },
199
+ { cmd: "auth login", desc: "Authenticate with GitHub" },
200
+ ],
201
+ python: [
202
+ { cmd: "-m venv", desc: "Create virtual environment" },
203
+ { cmd: "-m pip install", desc: "Install packages" },
204
+ { cmd: "-m pip freeze", desc: "List installed packages" },
205
+ { cmd: "-m pytest", desc: "Run tests" },
206
+ { cmd: "-m http.server", desc: "Start HTTP server" },
207
+ { cmd: "-c", desc: "Execute inline code" },
208
+ ],
209
+ python3: [
210
+ { cmd: "-m venv", desc: "Create virtual environment" },
211
+ { cmd: "-m pip install", desc: "Install packages" },
212
+ { cmd: "-m pip freeze", desc: "List installed packages" },
213
+ { cmd: "-m pytest", desc: "Run tests" },
214
+ { cmd: "-m http.server", desc: "Start HTTP server" },
215
+ { cmd: "-c", desc: "Execute inline code" },
216
+ ],
217
+ pip: [
218
+ { cmd: "install", desc: "Install package" },
219
+ { cmd: "install -r requirements.txt", desc: "Install from requirements" },
220
+ { cmd: "uninstall", desc: "Uninstall package" },
221
+ { cmd: "list", desc: "List packages" },
222
+ { cmd: "freeze", desc: "Output installed packages" },
223
+ { cmd: "show", desc: "Show package info" },
224
+ { cmd: "search", desc: "Search PyPI" },
225
+ ],
226
+ pip3: [
227
+ { cmd: "install", desc: "Install package" },
228
+ { cmd: "install -r requirements.txt", desc: "Install from requirements" },
229
+ { cmd: "uninstall", desc: "Uninstall package" },
230
+ { cmd: "list", desc: "List packages" },
231
+ { cmd: "freeze", desc: "Output installed packages" },
232
+ ],
233
+ docker: [
234
+ { cmd: "ps", desc: "List running containers" },
235
+ { cmd: "ps -a", desc: "List all containers" },
236
+ { cmd: "images", desc: "List images" },
237
+ { cmd: "build -t", desc: "Build image" },
238
+ { cmd: "run", desc: "Run container" },
239
+ { cmd: "run -it", desc: "Run interactive container" },
240
+ { cmd: "exec -it", desc: "Exec into container" },
241
+ { cmd: "stop", desc: "Stop container" },
242
+ { cmd: "rm", desc: "Remove container" },
243
+ { cmd: "rmi", desc: "Remove image" },
244
+ { cmd: "pull", desc: "Pull image" },
245
+ { cmd: "push", desc: "Push image" },
246
+ { cmd: "logs", desc: "Show container logs" },
247
+ { cmd: "compose up", desc: "Start compose services" },
248
+ { cmd: "compose down", desc: "Stop compose services" },
249
+ { cmd: "compose build", desc: "Build compose services" },
250
+ ],
251
+ kubectl: [
252
+ { cmd: "get pods", desc: "List pods" },
253
+ { cmd: "get services", desc: "List services" },
254
+ { cmd: "get deployments", desc: "List deployments" },
255
+ { cmd: "describe pod", desc: "Describe pod" },
256
+ { cmd: "apply -f", desc: "Apply config file" },
257
+ { cmd: "delete -f", desc: "Delete from config file" },
258
+ { cmd: "logs", desc: "Print pod logs" },
259
+ { cmd: "exec -it", desc: "Exec into pod" },
260
+ { cmd: "port-forward", desc: "Forward port" },
261
+ { cmd: "rollout status", desc: "Check rollout status" },
262
+ { cmd: "scale", desc: "Scale deployment" },
263
+ ],
264
+ cargo: [
265
+ { cmd: "build", desc: "Build package" },
266
+ { cmd: "build --release", desc: "Build release" },
267
+ { cmd: "run", desc: "Run binary" },
268
+ { cmd: "test", desc: "Run tests" },
269
+ { cmd: "add", desc: "Add dependency" },
270
+ { cmd: "check", desc: "Type-check without build" },
271
+ { cmd: "fmt", desc: "Format code" },
272
+ { cmd: "clippy", desc: "Run linter" },
273
+ { cmd: "update", desc: "Update dependencies" },
274
+ { cmd: "publish", desc: "Publish crate" },
275
+ ],
276
+ go: [
277
+ { cmd: "run", desc: "Run Go program" },
278
+ { cmd: "build", desc: "Build package" },
279
+ { cmd: "test", desc: "Run tests" },
280
+ { cmd: "test ./...", desc: "Run all tests" },
281
+ { cmd: "mod tidy", desc: "Clean up modules" },
282
+ { cmd: "mod init", desc: "Initialize module" },
283
+ { cmd: "get", desc: "Add dependency" },
284
+ { cmd: "fmt", desc: "Format code" },
285
+ { cmd: "vet", desc: "Vet code" },
286
+ { cmd: "install", desc: "Install package" },
287
+ ],
288
+ turbo: [
289
+ { cmd: "run build", desc: "Build all packages" },
290
+ { cmd: "run dev", desc: "Dev all packages" },
291
+ { cmd: "run test", desc: "Test all packages" },
292
+ { cmd: "run lint", desc: "Lint all packages" },
293
+ { cmd: "prune", desc: "Prune for deployment" },
294
+ ],
295
+ bun: [
296
+ { cmd: "install", desc: "Install dependencies" },
297
+ { cmd: "add", desc: "Add a package" },
298
+ { cmd: "add -d", desc: "Add dev dependency" },
299
+ { cmd: "remove", desc: "Remove a package" },
300
+ { cmd: "run dev", desc: "Start dev server" },
301
+ { cmd: "run build", desc: "Build project" },
302
+ { cmd: "run test", desc: "Run tests" },
303
+ { cmd: "test", desc: "Run tests (built-in)" },
304
+ { cmd: "init", desc: "Create package.json" },
305
+ { cmd: "create", desc: "Create from template" },
306
+ { cmd: "upgrade", desc: "Upgrade packages" },
307
+ ],
308
+ deno: [
309
+ { cmd: "run", desc: "Run a script" },
310
+ { cmd: "test", desc: "Run tests" },
311
+ { cmd: "fmt", desc: "Format code" },
312
+ { cmd: "lint", desc: "Lint code" },
313
+ { cmd: "compile", desc: "Compile to executable" },
314
+ { cmd: "task", desc: "Run a task" },
315
+ { cmd: "install", desc: "Install dependency" },
316
+ { cmd: "check", desc: "Type-check" },
317
+ ],
318
+ make: [
319
+ { cmd: "all", desc: "Build all targets" },
320
+ { cmd: "clean", desc: "Clean build artifacts" },
321
+ { cmd: "install", desc: "Install" },
322
+ { cmd: "test", desc: "Run tests" },
323
+ { cmd: "build", desc: "Build" },
324
+ ],
325
+ cat: [
326
+ { cmd: "-n", desc: "Show line numbers" },
327
+ ],
328
+ ls: [
329
+ { cmd: "-la", desc: "Long format, show hidden" },
330
+ { cmd: "-lh", desc: "Long format, human sizes" },
331
+ { cmd: "-R", desc: "Recursive listing" },
332
+ { cmd: "-t", desc: "Sort by time" },
333
+ ],
334
+ grep: [
335
+ { cmd: "-r", desc: "Recursive search" },
336
+ { cmd: "-rn", desc: "Recursive with line numbers" },
337
+ { cmd: "-i", desc: "Case insensitive" },
338
+ { cmd: "-l", desc: "Files with matches only" },
339
+ { cmd: "-c", desc: "Count matches" },
340
+ ],
341
+ find: [
342
+ { cmd: ". -name", desc: "Find by name" },
343
+ { cmd: ". -type f", desc: "Find files only" },
344
+ { cmd: ". -type d", desc: "Find directories only" },
345
+ { cmd: ". -mtime", desc: "Find by modification time" },
346
+ ],
347
+ curl: [
348
+ { cmd: "-X GET", desc: "GET request" },
349
+ { cmd: "-X POST", desc: "POST request" },
350
+ { cmd: "-H", desc: "Add header" },
351
+ { cmd: "-d", desc: "Send data" },
352
+ { cmd: "-o", desc: "Save to file" },
353
+ { cmd: "-s", desc: "Silent mode" },
354
+ { cmd: "-v", desc: "Verbose output" },
355
+ ],
356
+ };
357
+ function readPathEntries(partial, workingDir, cmdPrefix) {
358
+ try {
359
+ const resolved = path.resolve(workingDir, partial);
360
+ const isDir = partial.endsWith("/") || partial === "";
361
+ const dir = isDir ? resolved : path.dirname(resolved);
362
+ const prefix = isDir ? "" : path.basename(resolved).toLowerCase();
363
+ if (!fs.existsSync(dir))
364
+ return [];
365
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
366
+ return entries
367
+ .filter((e) => !e.name.startsWith(".") || prefix.startsWith("."))
368
+ .filter((e) => prefix === "" || e.name.toLowerCase().startsWith(prefix))
369
+ .slice(0, 40)
370
+ .map((e) => {
371
+ const rel = path.join(path.relative(workingDir, dir), e.name);
372
+ const suffix = e.isDirectory() ? "/" : "";
373
+ return {
374
+ name: e.name + suffix,
375
+ isDir: e.isDirectory(),
376
+ full: cmdPrefix + rel + suffix,
377
+ };
378
+ });
379
+ }
380
+ catch {
381
+ return [];
382
+ }
383
+ }
384
+ function getProjectFiles(workingDir, partial) {
385
+ const results = [];
386
+ const IGNORE = new Set(["node_modules", "dist", ".git", ".next", "build", ".turbo", "coverage"]);
387
+ function walk(dir, prefix, depth) {
388
+ if (depth > 2)
389
+ return;
390
+ try {
391
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
392
+ for (const e of entries) {
393
+ if (IGNORE.has(e.name))
394
+ continue;
395
+ if (e.name.startsWith(".") && !partial.startsWith("."))
396
+ continue;
397
+ const rel = prefix ? `${prefix}/${e.name}` : e.name;
398
+ const matchStr = rel.toLowerCase();
399
+ const partialLower = partial.toLowerCase();
400
+ if (!partial || matchStr.includes(partialLower) || e.name.toLowerCase().startsWith(partialLower)) {
401
+ results.push({
402
+ cmd: "@file " + rel + (e.isDirectory() ? "/" : ""),
403
+ desc: e.isDirectory() ? "dir" : "file",
404
+ });
405
+ }
406
+ if (e.isDirectory())
407
+ walk(path.join(dir, e.name), rel, depth + 1);
408
+ if (results.length >= 30)
409
+ return;
410
+ }
411
+ }
412
+ catch { }
413
+ }
414
+ walk(workingDir, "", 0);
415
+ return results.slice(0, 20);
416
+ }
417
+ function getFirstPathCompletion(partial, workingDir) {
418
+ try {
419
+ const resolved = path.resolve(workingDir, partial);
420
+ const isDir = partial.endsWith("/") || partial === "";
421
+ const dir = isDir ? resolved : path.dirname(resolved);
422
+ const prefix = isDir ? "" : path.basename(resolved).toLowerCase();
423
+ if (!fs.existsSync(dir))
424
+ return "";
425
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
426
+ const match = entries.find((e) => !e.name.startsWith(".") && (prefix === "" || e.name.toLowerCase().startsWith(prefix)));
427
+ if (!match)
428
+ return "";
429
+ const rel = path.join(path.relative(workingDir, dir), match.name);
430
+ return rel + (match.isDirectory() ? "/" : "");
431
+ }
432
+ catch {
433
+ return "";
434
+ }
435
+ }
436
+ function computeGhost(line, history, workingDir) {
437
+ if (!line)
438
+ return null;
439
+ for (const h of history) {
440
+ if (h.startsWith(line) && h !== line)
441
+ return { suffix: h.slice(line.length), full: h };
442
+ }
443
+ if (line.startsWith("/")) {
444
+ const match = SLASH_COMMANDS.find((c) => c.cmd.startsWith(line) && c.cmd !== line);
445
+ if (match)
446
+ return { suffix: match.cmd.slice(line.length), full: match.cmd };
447
+ }
448
+ const atMatch = line.match(/@(\S*)$/);
449
+ if (atMatch) {
450
+ const atToken = "@" + atMatch[1];
451
+ const fileArgMatch = line.match(/@file\s+(\S*)$/);
452
+ if (fileArgMatch) {
453
+ const completed = getFirstPathCompletion(fileArgMatch[1], workingDir);
454
+ if (completed) {
455
+ const full = line.replace(/@file\s+\S*$/, "@file " + completed);
456
+ return { suffix: full.slice(line.length), full };
457
+ }
458
+ return null;
459
+ }
460
+ const match = AT_PROVIDERS.find((p) => p.cmd.startsWith(atToken) && p.cmd !== atToken);
461
+ if (match) {
462
+ const full = line.replace(/@\S*$/, match.cmd);
463
+ return { suffix: full.slice(line.length), full };
464
+ }
465
+ }
466
+ const shellPathMatch = line.match(/^(!?\w[\w\-]*\s+)(\S+)$/);
467
+ if (shellPathMatch) {
468
+ const prefix = shellPathMatch[1];
469
+ const partial = shellPathMatch[2];
470
+ const completed = getFirstPathCompletion(partial, workingDir);
471
+ if (completed && completed !== partial) {
472
+ const full = prefix + completed;
473
+ return { suffix: full.slice(line.length), full };
474
+ }
475
+ }
476
+ return null;
477
+ }
478
+ /**
479
+ * Detect if the current input is a shell command that wants path completions.
480
+ * Returns { cmdPrefix, partial } or null.
481
+ */
482
+ function detectPathContext(line) {
483
+ // Match: (optional !) + command + space + optional partial path
484
+ const m = line.match(/^(!?)(\w[\w\-]*)(\s+)(\S*)$/);
485
+ if (!m) {
486
+ // "cd " with trailing space, no path yet
487
+ const m2 = line.match(/^(!?)(\w[\w\-]*)(\s+)$/);
488
+ if (m2) {
489
+ const cmd = m2[2].toLowerCase();
490
+ if (PATH_COMMANDS_CORE.has(cmd) || getPathBinaries().has(cmd)) {
491
+ return { cmdPrefix: m2[1] + m2[2] + m2[3], partial: "" };
492
+ }
493
+ }
494
+ return null;
495
+ }
496
+ const cmd = m[2].toLowerCase();
497
+ // Only show path completions for core path commands or binaries on $PATH
498
+ // that are NOT tools with their own subcommand suggestions
499
+ if (TOOL_SUBCOMMANDS[cmd])
500
+ return null;
501
+ if (!PATH_COMMANDS_CORE.has(cmd) && !getPathBinaries().has(cmd))
502
+ return null;
503
+ return { cmdPrefix: m[1] + m[2] + m[3], partial: m[4] };
504
+ }
505
+ const PathMenu = ({ entries, selectedIdx, label }) => {
506
+ const t = (0, theme_1.getTheme)();
507
+ const termWidth = process.stdout.columns || 100;
508
+ const padWidth = 2;
509
+ const maxName = Math.max(...entries.map((e) => e.name.length), 4);
510
+ const colWidth = Math.min(maxName + padWidth, Math.floor(termWidth / 2));
511
+ const numCols = Math.max(1, Math.floor((termWidth - 4) / colWidth));
512
+ const rows = [];
513
+ for (let i = 0; i < entries.length; i += numCols) {
514
+ rows.push(entries.slice(i, i + numCols));
515
+ }
516
+ return (react_1.default.createElement(ink_1.Box, { flexDirection: "column", paddingLeft: 2 },
517
+ react_1.default.createElement(ink_1.Text, { dimColor: t.useDim, color: t.textDim }, label),
518
+ rows.map((row, rowIdx) => (react_1.default.createElement(ink_1.Box, { key: rowIdx, flexDirection: "row" }, row.map((e, colIdx) => {
519
+ const globalIdx = rowIdx * numCols + colIdx;
520
+ const isSelected = globalIdx === selectedIdx;
521
+ const padded = e.name.padEnd(colWidth);
522
+ return isSelected ? (react_1.default.createElement(ink_1.Text, { key: e.full, backgroundColor: t.selectedBg, color: t.selected === "white" ? "black" : t.selected }, padded)) : (react_1.default.createElement(ink_1.Text, { key: e.full, color: e.isDir ? t.accent : t.text }, padded));
523
+ })))),
524
+ react_1.default.createElement(ink_1.Text, { dimColor: t.useDim, color: t.textDim }, "Tab=cycle →=accept ESC=close")));
525
+ };
526
+ // ── Suggestion icon helpers ───────────────────────────────────────────────────
527
+ function getSuggestionColor(s) {
528
+ const t = (0, theme_1.getTheme)();
529
+ if (s.cmd.startsWith("@file"))
530
+ return t.suggestionFile;
531
+ if (s.cmd.startsWith("@"))
532
+ return t.suggestionProvider;
533
+ const toolMatch = s.cmd.match(/^!?(\w[\w-]*)\s/);
534
+ if (toolMatch && TOOL_SUBCOMMANDS[toolMatch[1].toLowerCase()])
535
+ return t.suggestionTool;
536
+ return t.suggestionDefault;
537
+ }
538
+ const UserInput = ({ isProcessing, queueLength: _queueLength, workingDir, permissionMode, onSubmit, onCancel, onModeChange, }) => {
539
+ const [input, setInput] = (0, react_1.useState)("");
540
+ const [history, setHistory] = (0, react_1.useState)([]);
541
+ const [historyIdx, setHistoryIdx] = (0, react_1.useState)(-1);
542
+ // Vertical dropdown for /commands and @providers
543
+ const [suggestions, setSuggestions] = (0, react_1.useState)([]);
544
+ const [selectedSuggestion, setSelectedSuggestion] = (0, react_1.useState)(-1);
545
+ // Horizontal zsh-style path menu
546
+ const [pathEntries, setPathEntries] = (0, react_1.useState)([]);
547
+ const [selectedPath, setSelectedPath] = (0, react_1.useState)(0);
548
+ const [pathContext, setPathContext] = (0, react_1.useState)(null);
549
+ // Inline ghost
550
+ const [ghost, setGhost] = (0, react_1.useState)(null);
551
+ // Counter for clipboard image placeholders
552
+ const imageCountRef = (0, react_1.useRef)(0);
553
+ const clearAll = () => {
554
+ setSuggestions([]);
555
+ setSelectedSuggestion(-1);
556
+ setPathEntries([]);
557
+ setSelectedPath(0);
558
+ setPathContext(null);
559
+ setGhost(null);
560
+ };
561
+ const updateAll = (0, react_1.useCallback)((line, hist) => {
562
+ // ── /commands dropdown ──
563
+ if (line.startsWith("/")) {
564
+ const matches = SLASH_COMMANDS.filter((c) => c.cmd.startsWith(line) && c.cmd !== line);
565
+ setSuggestions(matches);
566
+ setSelectedSuggestion(0);
567
+ setPathEntries([]);
568
+ setPathContext(null);
569
+ setGhost(computeGhost(line, hist, workingDir));
570
+ return;
571
+ }
572
+ // ── @provider / file dropdown ──
573
+ const atMatch = line.match(/@(\S*)$/);
574
+ if (atMatch) {
575
+ const partial = atMatch[1]; // everything after @
576
+ // Match providers
577
+ const providerMatches = AT_PROVIDERS.filter((p) => partial === "" || p.cmd.slice(1).toLowerCase().startsWith(partial.toLowerCase()));
578
+ // Project files — displayed as @path (inserted as @file path)
579
+ const fileMatches = getProjectFiles(workingDir, partial);
580
+ const combined = [...providerMatches, ...fileMatches].slice(0, 50);
581
+ setSuggestions(combined);
582
+ setSelectedSuggestion(0);
583
+ setPathEntries([]);
584
+ setPathContext(null);
585
+ setGhost(null);
586
+ return;
587
+ }
588
+ // ── Tool subcommand suggestions (npm, git, python, docker…) ──
589
+ // Matches: "npm " or "!git " or "npm ins" etc.
590
+ const toolMatch = line.match(/^!?(\w[\w-]*)(\s+)(\S*)$/);
591
+ if (toolMatch) {
592
+ const tool = toolMatch[1].toLowerCase();
593
+ const subcmdPartial = toolMatch[3].toLowerCase();
594
+ const subcmds = TOOL_SUBCOMMANDS[tool];
595
+ if (subcmds) {
596
+ const matches = subcmds.filter((s) => subcmdPartial === "" || s.cmd.toLowerCase().startsWith(subcmdPartial));
597
+ if (matches.length > 0) {
598
+ // Prefix each suggestion with the tool name so acceptSuggestion inserts correctly
599
+ const prefixed = matches.map((s) => ({
600
+ cmd: (line.startsWith("!") ? "!" : "") + tool + " " + s.cmd,
601
+ desc: s.desc,
602
+ }));
603
+ setSuggestions(prefixed.slice(0, 10));
604
+ setSelectedSuggestion(0);
605
+ setPathEntries([]);
606
+ setPathContext(null);
607
+ setGhost(null);
608
+ return;
609
+ }
610
+ }
611
+ }
612
+ // ── Path completion for shell commands (cd, ls, vim…) ──
613
+ const pc = detectPathContext(line);
614
+ if (pc) {
615
+ const entries = readPathEntries(pc.partial, workingDir, pc.cmdPrefix);
616
+ setSuggestions([]);
617
+ setSelectedSuggestion(-1);
618
+ setPathEntries(entries);
619
+ setSelectedPath(0);
620
+ setPathContext(pc);
621
+ setGhost(computeGhost(line, hist, workingDir));
622
+ return;
623
+ }
624
+ setSuggestions([]);
625
+ setSelectedSuggestion(-1);
626
+ setPathEntries([]);
627
+ setPathContext(null);
628
+ setGhost(computeGhost(line, hist, workingDir));
629
+ }, [workingDir]);
630
+ const acceptSuggestion = (0, react_1.useCallback)((chosen, submit = false) => {
631
+ let newVal;
632
+ if (chosen.cmd.startsWith("@")) {
633
+ newVal = input.replace(/@\S*$/, chosen.cmd);
634
+ // directories keep the "/" but no space — continue drilling in
635
+ if (!newVal.endsWith("/"))
636
+ newVal += " ";
637
+ }
638
+ else {
639
+ newVal = chosen.cmd + " ";
640
+ }
641
+ setInput(newVal);
642
+ if (submit) {
643
+ setHistory((h) => [newVal.trim(), ...h].slice(0, 200));
644
+ setHistoryIdx(-1);
645
+ setInput("");
646
+ clearAll();
647
+ onSubmit(newVal.trim());
648
+ }
649
+ else {
650
+ // re-run updateAll so directory drilldown populates new suggestions
651
+ updateAll(newVal, history);
652
+ }
653
+ }, [input, history, workingDir, onSubmit, updateAll]);
654
+ (0, ink_1.useInput)((char, key) => {
655
+ // Ctrl+L — clear screen
656
+ if (key.ctrl && char === "l") {
657
+ process.stdout.write("\x1b[2J\x1b[H");
658
+ return;
659
+ }
660
+ // Ctrl+V — paste from clipboard (text or image placeholder)
661
+ if (key.ctrl && char === "v") {
662
+ try {
663
+ const { execSync } = require("child_process");
664
+ // macOS: pbpaste, Linux: xclip -o or xsel -ob
665
+ let pasted = "";
666
+ try {
667
+ pasted = execSync("pbpaste", { encoding: "utf-8", timeout: 500 }).trim();
668
+ }
669
+ catch {
670
+ try {
671
+ pasted = execSync("xclip -o -selection clipboard", { encoding: "utf-8", timeout: 500 }).trim();
672
+ }
673
+ catch {
674
+ try {
675
+ pasted = execSync("xsel -ob", { encoding: "utf-8", timeout: 500 }).trim();
676
+ }
677
+ catch { /* no clipboard tool */ }
678
+ }
679
+ }
680
+ if (pasted) {
681
+ // Replace newlines with spaces for single-line input
682
+ const cleaned = pasted.replace(/\n/g, " ").replace(/\r/g, "");
683
+ const next = input + cleaned;
684
+ setInput(next);
685
+ updateAll(next, history);
686
+ }
687
+ else {
688
+ // Clipboard might contain an image — insert placeholder
689
+ imageCountRef.current += 1;
690
+ const placeholder = `[Image #${imageCountRef.current}]`;
691
+ const next = input + placeholder;
692
+ setInput(next);
693
+ updateAll(next, history);
694
+ }
695
+ }
696
+ catch { /* skip on any error */ }
697
+ return;
698
+ }
699
+ // Shift+Tab — cycle permission mode
700
+ if (char === "\x1b[Z") {
701
+ const modes = ["ask", "auto-edit", "auto"];
702
+ const idx = modes.indexOf(permissionMode);
703
+ const next = modes[(idx + 1) % modes.length];
704
+ onModeChange(next);
705
+ return;
706
+ }
707
+ // ESC
708
+ if (key.escape) {
709
+ if (suggestions.length > 0 || pathEntries.length > 0) {
710
+ clearAll();
711
+ return;
712
+ }
713
+ if (ghost) {
714
+ setGhost(null);
715
+ return;
716
+ }
717
+ if (isProcessing)
718
+ onCancel();
719
+ return;
720
+ }
721
+ // ── Path menu navigation — Tab cycles, → accepts, Enter always submits ──
722
+ if (pathEntries.length > 0) {
723
+ if (key.tab) {
724
+ const next = (selectedPath + 1) % pathEntries.length;
725
+ setSelectedPath(next);
726
+ const entry = pathEntries[next];
727
+ setGhost({ suffix: entry.full.slice(input.length), full: entry.full });
728
+ return;
729
+ }
730
+ if (key.rightArrow || (char === "\x05")) {
731
+ // → accepts the highlighted entry into the input
732
+ const entry = pathEntries[selectedPath];
733
+ if (entry) {
734
+ setInput(entry.full);
735
+ setPathEntries([]);
736
+ setPathContext(null);
737
+ setGhost(null);
738
+ if (entry.isDir)
739
+ updateAll(entry.full, history);
740
+ }
741
+ return;
742
+ }
743
+ if (key.upArrow) {
744
+ setSelectedPath((p) => (p - 1 + pathEntries.length) % pathEntries.length);
745
+ return;
746
+ }
747
+ if (key.downArrow) {
748
+ setSelectedPath((p) => (p + 1) % pathEntries.length);
749
+ return;
750
+ }
751
+ // Enter falls through to the normal submit logic below
752
+ }
753
+ // → accept ghost
754
+ if ((key.rightArrow || (char === "\x05")) && ghost && suggestions.length === 0 && pathEntries.length === 0) {
755
+ setInput(ghost.full);
756
+ setGhost(computeGhost(ghost.full, history, workingDir));
757
+ return;
758
+ }
759
+ // Tab — dropdown or ghost
760
+ if (key.tab) {
761
+ if (suggestions.length > 0) {
762
+ const idx = selectedSuggestion >= 0 ? selectedSuggestion : 0;
763
+ const chosen = suggestions[idx];
764
+ if (chosen)
765
+ acceptSuggestion(chosen);
766
+ }
767
+ else if (ghost) {
768
+ setInput(ghost.full);
769
+ setSuggestions([]);
770
+ setGhost(computeGhost(ghost.full, history, workingDir));
771
+ }
772
+ return;
773
+ }
774
+ // Dropdown navigation
775
+ if (suggestions.length > 0) {
776
+ if (key.upArrow) {
777
+ setSelectedSuggestion((s) => (s <= 0 ? suggestions.length - 1 : s - 1));
778
+ return;
779
+ }
780
+ if (key.downArrow) {
781
+ setSelectedSuggestion((s) => (s >= suggestions.length - 1 ? 0 : s + 1));
782
+ return;
783
+ }
784
+ if (key.return) {
785
+ const chosen = suggestions[selectedSuggestion >= 0 ? selectedSuggestion : 0];
786
+ if (chosen)
787
+ acceptSuggestion(chosen, chosen.cmd.startsWith("/"));
788
+ return;
789
+ }
790
+ }
791
+ else {
792
+ // History navigation
793
+ if (key.upArrow) {
794
+ const nextIdx = Math.min(historyIdx + 1, history.length - 1);
795
+ setHistoryIdx(nextIdx);
796
+ const val = history[nextIdx] || "";
797
+ setInput(val);
798
+ updateAll(val, history);
799
+ return;
800
+ }
801
+ if (key.downArrow) {
802
+ const nextIdx = Math.max(historyIdx - 1, -1);
803
+ setHistoryIdx(nextIdx);
804
+ const val = nextIdx >= 0 ? history[nextIdx] : "";
805
+ setInput(val);
806
+ updateAll(val, history);
807
+ return;
808
+ }
809
+ }
810
+ // Enter — submit
811
+ if (key.return) {
812
+ const trimmed = input.trim();
813
+ if (!trimmed)
814
+ return;
815
+ const newHistory = [trimmed, ...history].slice(0, 200);
816
+ clearAll();
817
+ setHistory(newHistory);
818
+ setHistoryIdx(-1);
819
+ setInput("");
820
+ onSubmit(trimmed);
821
+ return;
822
+ }
823
+ // Backspace
824
+ if (key.backspace || key.delete) {
825
+ const next = input.slice(0, -1);
826
+ setInput(next);
827
+ updateAll(next, history);
828
+ return;
829
+ }
830
+ // Regular character
831
+ if (char && !key.ctrl && !key.meta) {
832
+ const next = input + char;
833
+ setInput(next);
834
+ updateAll(next, history);
835
+ }
836
+ });
837
+ // Compute windowed suggestions (used in render)
838
+ const WINDOW = 8;
839
+ const sel = selectedSuggestion >= 0 ? selectedSuggestion : 0;
840
+ const windowStart = suggestions.length > 0
841
+ ? Math.max(0, Math.min(sel - Math.floor(WINDOW / 2), suggestions.length - WINDOW))
842
+ : 0;
843
+ const windowEnd = Math.min(windowStart + WINDOW, suggestions.length);
844
+ const visibleSuggestions = suggestions.slice(windowStart, windowEnd);
845
+ const t = (0, theme_1.getTheme)();
846
+ return (react_1.default.createElement(ink_1.Box, { flexDirection: "column" },
847
+ pathEntries.length > 0 ? (react_1.default.createElement(PathMenu, { entries: pathEntries, selectedIdx: selectedPath, label: pathContext?.partial === "" || pathContext?.partial == null ? "directory" : "matches" })) : null,
848
+ react_1.default.createElement(ink_1.Box, { borderStyle: "round", borderColor: t.border, flexDirection: "column", paddingLeft: 1, paddingRight: 1 },
849
+ suggestions.length > 0 ? (react_1.default.createElement(ink_1.Box, { flexDirection: "column" },
850
+ windowStart > 0 ? (react_1.default.createElement(ink_1.Text, { dimColor: t.useDim, color: t.textDim }, ` ▲ ${windowStart} more`)) : null,
851
+ visibleSuggestions.map((s, vi) => {
852
+ const gi = windowStart + vi;
853
+ const isSelected = gi === sel;
854
+ const display = s.cmd.startsWith("@file ") ? "@" + s.cmd.slice(6) : s.cmd;
855
+ const color = getSuggestionColor(s);
856
+ return isSelected ? (react_1.default.createElement(ink_1.Box, { key: s.cmd },
857
+ react_1.default.createElement(ink_1.Text, { color: t.selected, bold: true }, ` ${display}`),
858
+ s.desc && s.desc !== "file" && s.desc !== "dir" ? (react_1.default.createElement(ink_1.Text, { color: t.textDim }, ` ${s.desc}`)) : null)) : (react_1.default.createElement(ink_1.Box, { key: s.cmd },
859
+ react_1.default.createElement(ink_1.Text, { color: color, dimColor: t.useDim }, ` ${display}`)));
860
+ }),
861
+ windowEnd < suggestions.length ? (react_1.default.createElement(ink_1.Text, { dimColor: t.useDim, color: t.textDim }, ` ▼ ${suggestions.length - windowEnd} more`)) : null,
862
+ react_1.default.createElement(ink_1.Text, { dimColor: t.useDim, color: t.textDim }, ` ↑/↓ navigate Enter select Esc close ${sel + 1}/${suggestions.length}`))) : null,
863
+ react_1.default.createElement(ink_1.Box, null,
864
+ react_1.default.createElement(ink_1.Text, { color: t.accent }, "● "),
865
+ input.length > 0 ? react_1.default.createElement(ink_1.Text, null, input) : null,
866
+ react_1.default.createElement(ink_1.Text, { color: t.cursor }, "▊"),
867
+ input.length === 0 ? (react_1.default.createElement(ink_1.Text, { color: t.placeholder, dimColor: t.useDim }, "Ask anything, @ for context, / for commands, ! for shell")) : ghost && suggestions.length === 0 && pathEntries.length === 0 ? (react_1.default.createElement(ink_1.Text, { color: t.placeholder, dimColor: t.useDim }, ghost.suffix)) : null)),
868
+ react_1.default.createElement(ink_1.Box, { paddingLeft: 2 },
869
+ react_1.default.createElement(ink_1.Text, { color: t.accent, dimColor: t.useDim }, "Ctrl+V paste · Ctrl+L clear · Shift+Tab cycle mode"))));
870
+ };
871
+ exports.UserInput = UserInput;
872
+ //# sourceMappingURL=UserInput.js.map