@staticpayload/zai-code 1.2.15 → 1.4.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.
- package/README.md +85 -154
- package/dist/apply.d.ts.map +1 -1
- package/dist/apply.js +43 -16
- package/dist/apply.js.map +1 -1
- package/dist/auth.d.ts.map +1 -1
- package/dist/auth.js +5 -1
- package/dist/auth.js.map +1 -1
- package/dist/commands.d.ts.map +1 -1
- package/dist/commands.js +1021 -47
- package/dist/commands.js.map +1 -1
- package/dist/context/context_builder.d.ts.map +1 -1
- package/dist/context/context_builder.js +18 -3
- package/dist/context/context_builder.js.map +1 -1
- package/dist/context/project_memory.d.ts +2 -2
- package/dist/context/project_memory.d.ts.map +1 -1
- package/dist/context/project_memory.js +14 -4
- package/dist/context/project_memory.js.map +1 -1
- package/dist/doctor.d.ts.map +1 -1
- package/dist/doctor.js +51 -7
- package/dist/doctor.js.map +1 -1
- package/dist/history.d.ts.map +1 -1
- package/dist/history.js +13 -8
- package/dist/history.js.map +1 -1
- package/dist/mode_prompts.d.ts.map +1 -1
- package/dist/mode_prompts.js +25 -22
- package/dist/mode_prompts.js.map +1 -1
- package/dist/orchestrator.d.ts.map +1 -1
- package/dist/orchestrator.js +69 -11
- package/dist/orchestrator.js.map +1 -1
- package/dist/planner.js +18 -18
- package/dist/planner.js.map +1 -1
- package/dist/rollback.d.ts +1 -0
- package/dist/rollback.d.ts.map +1 -1
- package/dist/rollback.js +28 -4
- package/dist/rollback.js.map +1 -1
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +22 -9
- package/dist/runtime.js.map +1 -1
- package/dist/session.d.ts +1 -0
- package/dist/session.d.ts.map +1 -1
- package/dist/session.js +8 -1
- package/dist/session.js.map +1 -1
- package/dist/settings.d.ts +1 -0
- package/dist/settings.d.ts.map +1 -1
- package/dist/settings.js +8 -3
- package/dist/settings.js.map +1 -1
- package/dist/shell.d.ts.map +1 -1
- package/dist/shell.js +85 -14
- package/dist/shell.js.map +1 -1
- package/dist/task_runner.d.ts.map +1 -1
- package/dist/task_runner.js +20 -2
- package/dist/task_runner.js.map +1 -1
- package/dist/tui.d.ts.map +1 -1
- package/dist/tui.js +566 -88
- package/dist/tui.js.map +1 -1
- package/dist/ui.d.ts +7 -0
- package/dist/ui.d.ts.map +1 -1
- package/dist/ui.js +113 -11
- package/dist/ui.js.map +1 -1
- package/dist/workspace.d.ts.map +1 -1
- package/dist/workspace.js +6 -0
- package/dist/workspace.js.map +1 -1
- package/dist/workspace_model.d.ts +1 -1
- package/dist/workspace_model.d.ts.map +1 -1
- package/dist/workspace_model.js +8 -1
- package/dist/workspace_model.js.map +1 -1
- package/package.json +4 -2
package/dist/tui.js
CHANGED
|
@@ -39,33 +39,125 @@ const session_1 = require("./session");
|
|
|
39
39
|
const orchestrator_1 = require("./orchestrator");
|
|
40
40
|
const git_1 = require("./git");
|
|
41
41
|
const settings_1 = require("./settings");
|
|
42
|
+
const workspace_model_1 = require("./workspace_model");
|
|
42
43
|
const agents_1 = require("./agents");
|
|
43
|
-
// Command definitions
|
|
44
|
+
// Command definitions with categories and shortcuts
|
|
44
45
|
const COMMANDS = [
|
|
45
|
-
|
|
46
|
-
{ name: '
|
|
47
|
-
{ name: '
|
|
48
|
-
{ name: '
|
|
49
|
-
{ name: '
|
|
50
|
-
|
|
51
|
-
{ name: '
|
|
52
|
-
{ name: '
|
|
53
|
-
{ name: '
|
|
54
|
-
{ name: '
|
|
55
|
-
{ name: '
|
|
56
|
-
{ name: '
|
|
57
|
-
{ name: '
|
|
46
|
+
// Quick actions (most used)
|
|
47
|
+
{ name: 'do', description: 'Quick: plan + generate', category: 'quick', shortcut: 'Ctrl+D' },
|
|
48
|
+
{ name: 'run', description: 'Auto: plan + generate + apply', category: 'quick', shortcut: 'Ctrl+R' },
|
|
49
|
+
{ name: 'ask', description: 'Quick question', category: 'quick', shortcut: 'Ctrl+A' },
|
|
50
|
+
{ name: 'fix', description: 'Debug mode task', category: 'quick', shortcut: 'Ctrl+F' },
|
|
51
|
+
// Workflow
|
|
52
|
+
{ name: 'plan', description: 'Generate execution plan', category: 'workflow', shortcut: 'Ctrl+P' },
|
|
53
|
+
{ name: 'generate', description: 'Create file changes', category: 'workflow', shortcut: 'Ctrl+G' },
|
|
54
|
+
{ name: 'diff', description: 'Review pending changes', category: 'workflow' },
|
|
55
|
+
{ name: 'apply', description: 'Apply changes', category: 'workflow' },
|
|
56
|
+
{ name: 'undo', description: 'Rollback last operation', category: 'workflow', shortcut: 'Ctrl+Z' },
|
|
57
|
+
{ name: 'retry', description: 'Retry last failed operation', category: 'workflow' },
|
|
58
|
+
{ name: 'clear', description: 'Clear current task', category: 'workflow' },
|
|
59
|
+
// Files
|
|
60
|
+
{ name: 'open', description: 'Add file to context', category: 'files' },
|
|
61
|
+
{ name: 'close', description: 'Remove file from context', category: 'files' },
|
|
62
|
+
{ name: 'files', description: 'List open files', category: 'files' },
|
|
63
|
+
{ name: 'search', description: 'Search files', category: 'files' },
|
|
64
|
+
{ name: 'read', description: 'View file contents', category: 'files' },
|
|
65
|
+
{ name: 'tree', description: 'Show file tree', category: 'files' },
|
|
66
|
+
// Modes
|
|
67
|
+
{ name: 'mode', description: 'Set mode (edit/ask/auto/debug)', category: 'modes' },
|
|
68
|
+
{ name: 'model', description: 'Select AI model', category: 'modes' },
|
|
69
|
+
{ name: 'dry-run', description: 'Toggle dry-run mode', category: 'modes' },
|
|
70
|
+
// Git
|
|
71
|
+
{ name: 'git', description: 'Git operations', category: 'git' },
|
|
72
|
+
{ name: 'commit', description: 'AI-powered commit', category: 'git' },
|
|
73
|
+
// System
|
|
74
|
+
{ name: 'help', description: 'Show all commands', category: 'system' },
|
|
75
|
+
{ name: 'settings', description: 'Open settings menu', category: 'system' },
|
|
76
|
+
{ name: 'status', description: 'Show session status', category: 'system' },
|
|
77
|
+
{ name: 'doctor', description: 'System health check', category: 'system' },
|
|
78
|
+
{ name: 'version', description: 'Show version', category: 'system' },
|
|
79
|
+
{ name: 'reset', description: 'Reset session', category: 'system' },
|
|
80
|
+
{ name: 'exit', description: 'Exit zcode', category: 'system', shortcut: 'Ctrl+C' },
|
|
58
81
|
];
|
|
59
|
-
//
|
|
82
|
+
// Smart suggestions based on context
|
|
83
|
+
function getSmartSuggestions() {
|
|
84
|
+
const session = (0, session_1.getSession)();
|
|
85
|
+
const suggestions = [];
|
|
86
|
+
// Based on current state
|
|
87
|
+
if (session.pendingActions || session.lastDiff) {
|
|
88
|
+
suggestions.push('/diff - Review changes');
|
|
89
|
+
suggestions.push('/apply - Apply changes');
|
|
90
|
+
}
|
|
91
|
+
else if (session.lastPlan && session.lastPlan.length > 0) {
|
|
92
|
+
suggestions.push('/generate - Create changes');
|
|
93
|
+
}
|
|
94
|
+
else if (session.currentIntent) {
|
|
95
|
+
suggestions.push('/plan - Create plan');
|
|
96
|
+
}
|
|
97
|
+
// Based on mode
|
|
98
|
+
if (session.mode === 'edit' && !session.currentIntent) {
|
|
99
|
+
suggestions.push('Type a task to get started');
|
|
100
|
+
}
|
|
101
|
+
// Git suggestions
|
|
102
|
+
const gitInfo = (0, git_1.getGitInfo)(session.workingDirectory);
|
|
103
|
+
if (gitInfo.isRepo && gitInfo.isDirty) {
|
|
104
|
+
suggestions.push('/commit - Commit changes');
|
|
105
|
+
}
|
|
106
|
+
return suggestions.slice(0, 3);
|
|
107
|
+
}
|
|
108
|
+
// Spinner frames for loading animation
|
|
109
|
+
const SPINNER_FRAMES = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
|
|
110
|
+
const PROGRESS_CHARS = ['▱', '▰'];
|
|
111
|
+
// Get contextual placeholder based on mode
|
|
112
|
+
function getPlaceholder() {
|
|
113
|
+
const session = (0, session_1.getSession)();
|
|
114
|
+
const mode = session.mode;
|
|
115
|
+
switch (mode) {
|
|
116
|
+
case 'auto':
|
|
117
|
+
return 'Type a task to execute automatically...';
|
|
118
|
+
case 'ask':
|
|
119
|
+
return 'Ask a question about your code...';
|
|
120
|
+
case 'debug':
|
|
121
|
+
return 'Describe the bug or error...';
|
|
122
|
+
case 'review':
|
|
123
|
+
return 'What would you like reviewed?';
|
|
124
|
+
case 'explain':
|
|
125
|
+
return 'What would you like explained?';
|
|
126
|
+
default:
|
|
127
|
+
if (session.pendingActions)
|
|
128
|
+
return '/apply to execute, /diff to review';
|
|
129
|
+
if (session.lastPlan?.length)
|
|
130
|
+
return '/generate to create changes';
|
|
131
|
+
if (session.currentIntent)
|
|
132
|
+
return '/plan to create execution plan';
|
|
133
|
+
return 'Describe what you want to build...';
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
// Recent commands history
|
|
137
|
+
const commandHistory = [];
|
|
138
|
+
let historyIndex = -1;
|
|
139
|
+
// ASCII Logo - cleaner, more modern
|
|
60
140
|
const ASCII_LOGO = `
|
|
61
|
-
{bold}{
|
|
62
|
-
{bold}{blue-fg}
|
|
63
|
-
{bold}{blue-fg}
|
|
64
|
-
{bold}{blue-fg}
|
|
65
|
-
{bold}{blue-fg}
|
|
66
|
-
{bold}{blue-fg}
|
|
141
|
+
{bold}{cyan-fg}╭─────────────────────────────────────╮{/cyan-fg}{/bold}
|
|
142
|
+
{bold}{cyan-fg}│{/cyan-fg} {blue-fg}███████{/blue-fg} {cyan-fg}█████{/cyan-fg} {blue-fg}██{/blue-fg} {cyan-fg}code{/cyan-fg} {cyan-fg}│{/cyan-fg}{/bold}
|
|
143
|
+
{bold}{cyan-fg}│{/cyan-fg} {blue-fg}███{/blue-fg} {cyan-fg}██{/cyan-fg} {cyan-fg}██{/cyan-fg} {blue-fg}██{/blue-fg} {gray-fg}v1.3.0{/gray-fg} {cyan-fg}│{/cyan-fg}{/bold}
|
|
144
|
+
{bold}{cyan-fg}│{/cyan-fg} {blue-fg}███{/blue-fg} {cyan-fg}█████{/cyan-fg} {blue-fg}██{/blue-fg} {cyan-fg}│{/cyan-fg}{/bold}
|
|
145
|
+
{bold}{cyan-fg}│{/cyan-fg} {blue-fg}███{/blue-fg} {cyan-fg}██{/cyan-fg} {cyan-fg}██{/cyan-fg} {blue-fg}██{/blue-fg} {gray-fg}AI-native{/gray-fg} {cyan-fg}│{/cyan-fg}{/bold}
|
|
146
|
+
{bold}{cyan-fg}│{/cyan-fg} {blue-fg}███████{/blue-fg} {cyan-fg}██{/cyan-fg} {cyan-fg}██{/cyan-fg} {blue-fg}██{/blue-fg} {gray-fg}code editor{/gray-fg}{cyan-fg}│{/cyan-fg}{/bold}
|
|
147
|
+
{bold}{cyan-fg}╰─────────────────────────────────────╯{/cyan-fg}{/bold}
|
|
67
148
|
`;
|
|
68
|
-
const MINIMAL_LOGO = '{bold}{blue-fg}
|
|
149
|
+
const MINIMAL_LOGO = '{bold}{blue-fg}⚡{/blue-fg} {cyan-fg}zai·code{/cyan-fg}{/bold} {gray-fg}AI-native code editor{/gray-fg}';
|
|
150
|
+
// Welcome tips - rotate through these
|
|
151
|
+
const WELCOME_TIPS = [
|
|
152
|
+
'Type a task naturally, like "add error handling to auth.ts"',
|
|
153
|
+
'Use /do <task> for quick plan+generate in one step',
|
|
154
|
+
'Use /run <task> for full auto execution (YOLO mode)',
|
|
155
|
+
'Press Ctrl+P to quickly plan, Ctrl+G to generate',
|
|
156
|
+
'Use /ask for quick questions without changing mode',
|
|
157
|
+
'Try /fix <problem> to quickly debug issues',
|
|
158
|
+
'/commit generates AI-powered commit messages',
|
|
159
|
+
'Use /mode auto for autonomous execution',
|
|
160
|
+
];
|
|
69
161
|
async function startTUI(options) {
|
|
70
162
|
const { projectName, restored, onExit } = options;
|
|
71
163
|
const session = (0, session_1.getSession)();
|
|
@@ -82,22 +174,31 @@ async function startTUI(options) {
|
|
|
82
174
|
fullUnicode: true,
|
|
83
175
|
dockBorders: true,
|
|
84
176
|
autoPadding: true,
|
|
85
|
-
warnings: false,
|
|
177
|
+
warnings: false,
|
|
86
178
|
});
|
|
87
|
-
// Theme colors
|
|
179
|
+
// Theme colors - modern dark theme
|
|
88
180
|
const theme = {
|
|
89
181
|
bg: 'black',
|
|
90
182
|
fg: 'white',
|
|
91
183
|
border: 'blue',
|
|
92
184
|
highlight: 'cyan',
|
|
185
|
+
accent: 'magenta',
|
|
186
|
+
success: 'green',
|
|
187
|
+
warning: 'yellow',
|
|
188
|
+
error: 'red',
|
|
93
189
|
gray: 'gray'
|
|
94
190
|
};
|
|
191
|
+
// State for spinner and processing
|
|
192
|
+
let spinnerInterval = null;
|
|
193
|
+
let spinnerFrame = 0;
|
|
194
|
+
let isProcessing = false;
|
|
195
|
+
let currentTip = Math.floor(Math.random() * WELCOME_TIPS.length);
|
|
95
196
|
// Header with logo
|
|
96
197
|
const header = blessed.box({
|
|
97
198
|
top: 0,
|
|
98
199
|
left: 0,
|
|
99
200
|
width: '100%',
|
|
100
|
-
height: (0, settings_1.shouldShowLogo)() ?
|
|
201
|
+
height: (0, settings_1.shouldShowLogo)() ? 9 : 2,
|
|
101
202
|
tags: true,
|
|
102
203
|
content: (0, settings_1.shouldShowLogo)() ? ASCII_LOGO : MINIMAL_LOGO,
|
|
103
204
|
style: {
|
|
@@ -105,25 +206,87 @@ async function startTUI(options) {
|
|
|
105
206
|
bg: theme.bg,
|
|
106
207
|
},
|
|
107
208
|
});
|
|
108
|
-
//
|
|
209
|
+
// Quick actions bar - keyboard shortcuts
|
|
210
|
+
const quickActions = blessed.box({
|
|
211
|
+
top: (0, settings_1.shouldShowLogo)() ? 9 : 2,
|
|
212
|
+
left: 0,
|
|
213
|
+
width: '100%',
|
|
214
|
+
height: 1,
|
|
215
|
+
tags: true,
|
|
216
|
+
content: '{gray-fg}Quick:{/gray-fg} {cyan-fg}^D{/cyan-fg}do {cyan-fg}^R{/cyan-fg}run {cyan-fg}^P{/cyan-fg}plan {cyan-fg}^G{/cyan-fg}gen {cyan-fg}^Z{/cyan-fg}undo',
|
|
217
|
+
style: {
|
|
218
|
+
fg: theme.fg,
|
|
219
|
+
bg: theme.bg,
|
|
220
|
+
},
|
|
221
|
+
padding: { left: 1 },
|
|
222
|
+
});
|
|
223
|
+
// Context/status line
|
|
224
|
+
const contextTop = (0, settings_1.shouldShowLogo)() ? 10 : 3;
|
|
225
|
+
const contextLine = blessed.box({
|
|
226
|
+
top: contextTop,
|
|
227
|
+
left: 0,
|
|
228
|
+
width: '100%',
|
|
229
|
+
height: 1,
|
|
230
|
+
tags: true,
|
|
231
|
+
style: {
|
|
232
|
+
fg: theme.fg,
|
|
233
|
+
bg: theme.bg,
|
|
234
|
+
},
|
|
235
|
+
padding: { left: 1 },
|
|
236
|
+
});
|
|
237
|
+
// Update context line with current state
|
|
238
|
+
function updateContextLine() {
|
|
239
|
+
const gitInfo = (0, git_1.getGitInfo)(session.workingDirectory);
|
|
240
|
+
const model = (0, settings_1.getModel)();
|
|
241
|
+
const mode = session.mode;
|
|
242
|
+
const intent = (0, session_1.getIntent)();
|
|
243
|
+
const fileCount = session.openFiles.length;
|
|
244
|
+
let parts = [];
|
|
245
|
+
parts.push(`{bold}${projectName}{/bold}`);
|
|
246
|
+
if (gitInfo.isRepo) {
|
|
247
|
+
const dirty = gitInfo.isDirty ? '{yellow-fg}*{/yellow-fg}' : '';
|
|
248
|
+
parts.push(`{gray-fg}git:{/gray-fg}${gitInfo.branch}${dirty}`);
|
|
249
|
+
}
|
|
250
|
+
const modeColors = {
|
|
251
|
+
'auto': 'magenta', 'edit': 'cyan', 'ask': 'green',
|
|
252
|
+
'debug': 'red', 'review': 'yellow', 'explain': 'blue'
|
|
253
|
+
};
|
|
254
|
+
const modeColor = modeColors[mode] || 'cyan';
|
|
255
|
+
parts.push(`{${modeColor}-fg}${mode}{/${modeColor}-fg}`);
|
|
256
|
+
parts.push(`{gray-fg}${model}{/gray-fg}`);
|
|
257
|
+
if (fileCount > 0)
|
|
258
|
+
parts.push(`{gray-fg}${fileCount} file(s){/gray-fg}`);
|
|
259
|
+
if (intent) {
|
|
260
|
+
const truncated = intent.length > 30 ? intent.substring(0, 30) + '...' : intent;
|
|
261
|
+
parts.push(`{yellow-fg}→ ${truncated}{/yellow-fg}`);
|
|
262
|
+
}
|
|
263
|
+
contextLine.setContent(parts.join(' {gray-fg}│{/gray-fg} '));
|
|
264
|
+
}
|
|
265
|
+
// Tips section - smart suggestions
|
|
266
|
+
const tipsTop = contextTop + 1;
|
|
109
267
|
const tips = blessed.box({
|
|
110
|
-
top:
|
|
268
|
+
top: tipsTop,
|
|
111
269
|
left: 0,
|
|
112
270
|
width: '100%',
|
|
113
|
-
height:
|
|
271
|
+
height: 2,
|
|
114
272
|
tags: true,
|
|
115
|
-
content: `{bold}Tips for getting started:{/bold}
|
|
116
|
-
1. Type a task or question to begin.
|
|
117
|
-
2. Use {bold}/commands{/bold} for direct actions.
|
|
118
|
-
3. {bold}/help{/bold} for more information.`,
|
|
119
273
|
style: {
|
|
120
274
|
fg: theme.fg,
|
|
121
275
|
bg: theme.bg,
|
|
122
276
|
},
|
|
123
277
|
padding: { left: 1 },
|
|
124
278
|
});
|
|
279
|
+
function updateTips() {
|
|
280
|
+
const smartSuggestions = getSmartSuggestions();
|
|
281
|
+
if (smartSuggestions.length > 0) {
|
|
282
|
+
tips.setContent(`{gray-fg}💡 ${smartSuggestions.join(' │ ')}{/gray-fg}`);
|
|
283
|
+
}
|
|
284
|
+
else {
|
|
285
|
+
tips.setContent(`{gray-fg}💡 ${WELCOME_TIPS[currentTip]}{/gray-fg}`);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
125
288
|
// Warning box (if in home directory)
|
|
126
|
-
const warningTop =
|
|
289
|
+
const warningTop = tipsTop + 2;
|
|
127
290
|
const warning = blessed.box({
|
|
128
291
|
top: warningTop,
|
|
129
292
|
left: 0,
|
|
@@ -147,30 +310,15 @@ async function startTUI(options) {
|
|
|
147
310
|
// Check warnings
|
|
148
311
|
const gitInfo = (0, git_1.getGitInfo)(session.workingDirectory);
|
|
149
312
|
if (session.workingDirectory === require('os').homedir()) {
|
|
150
|
-
warning.setContent('
|
|
313
|
+
warning.setContent('{yellow-fg}⚠{/yellow-fg} Running in home directory. Consider using a project directory.');
|
|
151
314
|
warning.show();
|
|
152
315
|
}
|
|
153
316
|
else if (!gitInfo.isRepo) {
|
|
154
|
-
warning.setContent('Not a git repository. Changes cannot be tracked.');
|
|
317
|
+
warning.setContent('{yellow-fg}⚠{/yellow-fg} Not a git repository. Changes cannot be tracked.');
|
|
155
318
|
warning.show();
|
|
156
319
|
}
|
|
157
|
-
// Context line (Using: X files)
|
|
158
|
-
const contextTop = warning.hidden ? warningTop : warningTop + 3;
|
|
159
|
-
const context = blessed.box({
|
|
160
|
-
top: contextTop,
|
|
161
|
-
left: 0,
|
|
162
|
-
width: '100%',
|
|
163
|
-
height: 1,
|
|
164
|
-
tags: true,
|
|
165
|
-
content: `{bold}${projectName}{/bold} · ${session.openFiles.length || 0} file(s) in context`,
|
|
166
|
-
style: {
|
|
167
|
-
fg: theme.fg,
|
|
168
|
-
bg: theme.bg,
|
|
169
|
-
},
|
|
170
|
-
padding: { left: 1 },
|
|
171
|
-
});
|
|
172
320
|
// Main output area
|
|
173
|
-
const outputTop =
|
|
321
|
+
const outputTop = warning.hidden ? warningTop : warningTop + 3;
|
|
174
322
|
const output = blessed.log({
|
|
175
323
|
top: outputTop,
|
|
176
324
|
left: 0,
|
|
@@ -192,7 +340,38 @@ async function startTUI(options) {
|
|
|
192
340
|
},
|
|
193
341
|
padding: { left: 1, right: 1 },
|
|
194
342
|
});
|
|
195
|
-
//
|
|
343
|
+
// Processing spinner indicator
|
|
344
|
+
const processingIndicator = blessed.box({
|
|
345
|
+
bottom: 5,
|
|
346
|
+
right: 2,
|
|
347
|
+
width: 25,
|
|
348
|
+
height: 1,
|
|
349
|
+
tags: true,
|
|
350
|
+
style: {
|
|
351
|
+
fg: theme.highlight,
|
|
352
|
+
bg: theme.bg,
|
|
353
|
+
},
|
|
354
|
+
hidden: true,
|
|
355
|
+
});
|
|
356
|
+
function startSpinner(message = 'Processing') {
|
|
357
|
+
isProcessing = true;
|
|
358
|
+
processingIndicator.show();
|
|
359
|
+
spinnerInterval = setInterval(() => {
|
|
360
|
+
spinnerFrame = (spinnerFrame + 1) % SPINNER_FRAMES.length;
|
|
361
|
+
processingIndicator.setContent(`{cyan-fg}${SPINNER_FRAMES[spinnerFrame]} ${message}...{/cyan-fg}`);
|
|
362
|
+
screen.render();
|
|
363
|
+
}, 80);
|
|
364
|
+
}
|
|
365
|
+
function stopSpinner() {
|
|
366
|
+
isProcessing = false;
|
|
367
|
+
if (spinnerInterval) {
|
|
368
|
+
clearInterval(spinnerInterval);
|
|
369
|
+
spinnerInterval = null;
|
|
370
|
+
}
|
|
371
|
+
processingIndicator.hide();
|
|
372
|
+
screen.render();
|
|
373
|
+
}
|
|
374
|
+
// Input box container with mode indicator
|
|
196
375
|
const inputContainer = blessed.box({
|
|
197
376
|
bottom: 2,
|
|
198
377
|
left: 0,
|
|
@@ -209,18 +388,30 @@ async function startTUI(options) {
|
|
|
209
388
|
},
|
|
210
389
|
},
|
|
211
390
|
});
|
|
212
|
-
//
|
|
213
|
-
const
|
|
391
|
+
// Mode indicator icon
|
|
392
|
+
const modeIndicator = blessed.text({
|
|
214
393
|
parent: inputContainer,
|
|
215
394
|
left: 1,
|
|
216
395
|
top: 0,
|
|
217
|
-
content: `{bold}{blue-fg}❯{/blue-fg}{/bold}`,
|
|
218
396
|
tags: true,
|
|
219
397
|
style: {
|
|
220
398
|
bg: theme.bg
|
|
221
399
|
}
|
|
222
400
|
});
|
|
223
|
-
|
|
401
|
+
function updateModeIndicator() {
|
|
402
|
+
const mode = session.mode;
|
|
403
|
+
const modeColors = {
|
|
404
|
+
'auto': 'magenta', 'edit': 'cyan', 'ask': 'green',
|
|
405
|
+
'debug': 'red', 'review': 'yellow', 'explain': 'blue'
|
|
406
|
+
};
|
|
407
|
+
const color = modeColors[mode] || 'cyan';
|
|
408
|
+
const icons = {
|
|
409
|
+
'auto': '⚡', 'edit': '❯', 'ask': '?', 'debug': '🔧', 'review': '👁', 'explain': '📖'
|
|
410
|
+
};
|
|
411
|
+
const icon = icons[mode] || '❯';
|
|
412
|
+
modeIndicator.setContent(`{bold}{${color}-fg}${icon}{/${color}-fg}{/bold}`);
|
|
413
|
+
}
|
|
414
|
+
// Input textbox
|
|
224
415
|
const input = blessed.textbox({
|
|
225
416
|
parent: inputContainer,
|
|
226
417
|
left: 3,
|
|
@@ -235,9 +426,28 @@ async function startTUI(options) {
|
|
|
235
426
|
bg: theme.bg,
|
|
236
427
|
},
|
|
237
428
|
});
|
|
238
|
-
//
|
|
239
|
-
|
|
240
|
-
|
|
429
|
+
// Placeholder text
|
|
430
|
+
const placeholder = blessed.text({
|
|
431
|
+
parent: inputContainer,
|
|
432
|
+
left: 4,
|
|
433
|
+
top: 0,
|
|
434
|
+
tags: true,
|
|
435
|
+
style: {
|
|
436
|
+
fg: theme.gray,
|
|
437
|
+
bg: theme.bg,
|
|
438
|
+
},
|
|
439
|
+
});
|
|
440
|
+
function updatePlaceholder() {
|
|
441
|
+
const val = input.getValue();
|
|
442
|
+
if (!val || val.length === 0) {
|
|
443
|
+
placeholder.setContent(`{gray-fg}${getPlaceholder()}{/gray-fg}`);
|
|
444
|
+
placeholder.show();
|
|
445
|
+
}
|
|
446
|
+
else {
|
|
447
|
+
placeholder.hide();
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
// Status bar at bottom - more informative
|
|
241
451
|
const statusBar = blessed.box({
|
|
242
452
|
bottom: 0,
|
|
243
453
|
left: 0,
|
|
@@ -250,31 +460,44 @@ async function startTUI(options) {
|
|
|
250
460
|
},
|
|
251
461
|
padding: { left: 1, right: 1 },
|
|
252
462
|
});
|
|
253
|
-
// Update status bar
|
|
463
|
+
// Update status bar with state
|
|
254
464
|
function updateStatusBar() {
|
|
255
465
|
const model = (0, settings_1.getModel)();
|
|
256
466
|
const mode = (0, session_1.getSession)().mode;
|
|
257
467
|
const gitStatus = gitInfo.isRepo ? `${gitInfo.branch}${gitInfo.isDirty ? '*' : ''}` : 'no-git';
|
|
258
|
-
const
|
|
468
|
+
const dryRun = session.dryRun ? ' {yellow-fg}[DRY]{/yellow-fg}' : '';
|
|
469
|
+
// State indicator
|
|
470
|
+
let state = '{green-fg}ready{/green-fg}';
|
|
471
|
+
if (session.pendingActions || session.lastDiff) {
|
|
472
|
+
state = '{yellow-fg}pending{/yellow-fg}';
|
|
473
|
+
}
|
|
474
|
+
else if (session.lastPlan && session.lastPlan.length > 0) {
|
|
475
|
+
state = '{cyan-fg}planned{/cyan-fg}';
|
|
476
|
+
}
|
|
477
|
+
else if (session.currentIntent) {
|
|
478
|
+
state = '{blue-fg}intent{/blue-fg}';
|
|
479
|
+
}
|
|
480
|
+
const left = `{bold}[${mode}]{/bold} ${state}${dryRun}`;
|
|
259
481
|
const center = `${gitStatus}`;
|
|
260
|
-
const right = `{cyan-fg}${model}{/cyan-fg}`;
|
|
482
|
+
const right = `{cyan-fg}${model}{/cyan-fg} {gray-fg}/help{/gray-fg}`;
|
|
261
483
|
const width = screen.width || 80;
|
|
262
|
-
const padding = Math.max(0, Math.floor((width -
|
|
484
|
+
const padding = Math.max(0, Math.floor((width - 50) / 2));
|
|
263
485
|
statusBar.setContent(`${left}${' '.repeat(padding)}${center}${' '.repeat(padding)}${right}`);
|
|
264
486
|
}
|
|
265
|
-
// Command palette -
|
|
487
|
+
// Command palette - enhanced
|
|
266
488
|
const palette = blessed.list({
|
|
267
489
|
bottom: 5,
|
|
268
490
|
left: 1,
|
|
269
|
-
width:
|
|
270
|
-
height:
|
|
491
|
+
width: 55,
|
|
492
|
+
height: 12,
|
|
271
493
|
tags: true,
|
|
272
|
-
keys: false,
|
|
273
|
-
mouse: false,
|
|
274
|
-
interactive: false,
|
|
494
|
+
keys: false,
|
|
495
|
+
mouse: false,
|
|
496
|
+
interactive: false,
|
|
275
497
|
border: {
|
|
276
498
|
type: 'line',
|
|
277
499
|
},
|
|
500
|
+
label: ' Commands ',
|
|
278
501
|
style: {
|
|
279
502
|
fg: theme.fg,
|
|
280
503
|
bg: theme.bg,
|
|
@@ -290,44 +513,105 @@ async function startTUI(options) {
|
|
|
290
513
|
},
|
|
291
514
|
hidden: true,
|
|
292
515
|
});
|
|
516
|
+
// File autocomplete
|
|
517
|
+
const fileAutocomplete = blessed.list({
|
|
518
|
+
bottom: 5,
|
|
519
|
+
left: 1,
|
|
520
|
+
width: 60,
|
|
521
|
+
height: 10,
|
|
522
|
+
tags: true,
|
|
523
|
+
keys: false,
|
|
524
|
+
mouse: false,
|
|
525
|
+
interactive: false,
|
|
526
|
+
border: {
|
|
527
|
+
type: 'line',
|
|
528
|
+
},
|
|
529
|
+
label: ' Files ',
|
|
530
|
+
style: {
|
|
531
|
+
fg: theme.fg,
|
|
532
|
+
bg: theme.bg,
|
|
533
|
+
border: {
|
|
534
|
+
fg: theme.success,
|
|
535
|
+
bg: theme.bg
|
|
536
|
+
},
|
|
537
|
+
selected: {
|
|
538
|
+
bg: theme.success,
|
|
539
|
+
fg: theme.bg,
|
|
540
|
+
bold: true,
|
|
541
|
+
},
|
|
542
|
+
},
|
|
543
|
+
hidden: true,
|
|
544
|
+
});
|
|
293
545
|
// Add all elements to screen
|
|
294
546
|
screen.append(header);
|
|
547
|
+
screen.append(quickActions);
|
|
548
|
+
screen.append(contextLine);
|
|
295
549
|
screen.append(tips);
|
|
296
550
|
screen.append(warning);
|
|
297
|
-
screen.append(context);
|
|
298
551
|
screen.append(output);
|
|
552
|
+
screen.append(processingIndicator);
|
|
299
553
|
screen.append(inputContainer);
|
|
300
554
|
screen.append(statusBar);
|
|
301
555
|
screen.append(palette);
|
|
556
|
+
screen.append(fileAutocomplete);
|
|
302
557
|
// Initial render
|
|
558
|
+
updateContextLine();
|
|
559
|
+
updateTips();
|
|
303
560
|
updateStatusBar();
|
|
561
|
+
updateModeIndicator();
|
|
562
|
+
updatePlaceholder();
|
|
304
563
|
input.focus();
|
|
305
564
|
screen.render();
|
|
306
|
-
//
|
|
565
|
+
// Welcome messages
|
|
307
566
|
if (restored) {
|
|
308
|
-
output.log('{
|
|
567
|
+
output.log('{green-fg}✓{/green-fg} Session restored');
|
|
568
|
+
if (session.currentIntent) {
|
|
569
|
+
output.log(`{gray-fg} Task: ${session.currentIntent.substring(0, 60)}...{/gray-fg}`);
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
else {
|
|
573
|
+
output.log('{cyan-fg}Welcome to zai·code!{/cyan-fg} {gray-fg}Type a task or /help{/gray-fg}');
|
|
309
574
|
}
|
|
310
575
|
// agents.md notice
|
|
311
576
|
if ((0, agents_1.hasAgentsConfig)(session.workingDirectory)) {
|
|
312
|
-
output.log('{green-fg}
|
|
577
|
+
output.log('{green-fg}✓{/green-fg} agents.md detected');
|
|
313
578
|
}
|
|
579
|
+
output.log('');
|
|
314
580
|
// --- LOGIC ---
|
|
315
581
|
let showPalette = false;
|
|
582
|
+
let showFileAutocomplete = false;
|
|
583
|
+
let autocompleteFiles = [];
|
|
316
584
|
function updatePalette(filter) {
|
|
317
585
|
const query = filter.replace(/^\//, '').toLowerCase();
|
|
318
|
-
const filtered = COMMANDS.filter(c => c.name.startsWith(query));
|
|
319
|
-
|
|
320
|
-
|
|
586
|
+
const filtered = COMMANDS.filter(c => c.name.startsWith(query) || c.description.toLowerCase().includes(query));
|
|
587
|
+
const items = filtered.slice(0, 10).map(c => {
|
|
588
|
+
const shortcut = c.shortcut ? ` {gray-fg}${c.shortcut}{/gray-fg}` : '';
|
|
589
|
+
return `{bold}{cyan-fg}/${c.name}{/cyan-fg}{/bold} ${c.description}${shortcut}`;
|
|
590
|
+
});
|
|
591
|
+
palette.setItems(items);
|
|
321
592
|
if (filtered.length > 0) {
|
|
322
593
|
palette.select(0);
|
|
323
594
|
}
|
|
324
595
|
}
|
|
596
|
+
function updateFileAutocomplete(query) {
|
|
597
|
+
const ws = (0, workspace_model_1.getWorkspace)(session.workingDirectory);
|
|
598
|
+
ws.indexFileTree();
|
|
599
|
+
const files = ws.getFileIndex();
|
|
600
|
+
const pattern = query.toLowerCase();
|
|
601
|
+
autocompleteFiles = files
|
|
602
|
+
.filter(f => f.path.toLowerCase().includes(pattern))
|
|
603
|
+
.slice(0, 10)
|
|
604
|
+
.map(f => f.path);
|
|
605
|
+
fileAutocomplete.setItems(autocompleteFiles.map(f => `{green-fg}📄{/green-fg} ${f}`));
|
|
606
|
+
if (autocompleteFiles.length > 0) {
|
|
607
|
+
fileAutocomplete.select(0);
|
|
608
|
+
}
|
|
609
|
+
}
|
|
325
610
|
function togglePalette(show, filter = '/') {
|
|
326
611
|
showPalette = show;
|
|
327
612
|
if (show) {
|
|
328
613
|
updatePalette(filter);
|
|
329
614
|
palette.show();
|
|
330
|
-
// CRITICAL: Do NOT focus palette. Keep input focused.
|
|
331
615
|
screen.render();
|
|
332
616
|
}
|
|
333
617
|
else {
|
|
@@ -335,11 +619,33 @@ async function startTUI(options) {
|
|
|
335
619
|
screen.render();
|
|
336
620
|
}
|
|
337
621
|
}
|
|
622
|
+
function toggleFileAutocomplete(show, query = '') {
|
|
623
|
+
showFileAutocomplete = show;
|
|
624
|
+
if (show && query) {
|
|
625
|
+
updateFileAutocomplete(query);
|
|
626
|
+
fileAutocomplete.show();
|
|
627
|
+
screen.render();
|
|
628
|
+
}
|
|
629
|
+
else {
|
|
630
|
+
fileAutocomplete.hide();
|
|
631
|
+
screen.render();
|
|
632
|
+
}
|
|
633
|
+
}
|
|
338
634
|
// Process input
|
|
339
635
|
async function processInput(value) {
|
|
340
636
|
if (!value.trim())
|
|
341
637
|
return;
|
|
342
|
-
|
|
638
|
+
// Add to command history
|
|
639
|
+
commandHistory.unshift(value);
|
|
640
|
+
if (commandHistory.length > 50)
|
|
641
|
+
commandHistory.pop();
|
|
642
|
+
historyIndex = -1;
|
|
643
|
+
// Format input display
|
|
644
|
+
const isCommand = value.startsWith('/');
|
|
645
|
+
const inputDisplay = isCommand
|
|
646
|
+
? `{cyan-fg}❯{/cyan-fg} {bold}${value}{/bold}`
|
|
647
|
+
: `{cyan-fg}❯{/cyan-fg} ${value}`;
|
|
648
|
+
output.log(inputDisplay);
|
|
343
649
|
screen.render();
|
|
344
650
|
const trimmed = value.trim();
|
|
345
651
|
if (trimmed === '/exit' || trimmed === 'exit' || trimmed === 'quit') {
|
|
@@ -370,21 +676,47 @@ async function startTUI(options) {
|
|
|
370
676
|
screen.render();
|
|
371
677
|
};
|
|
372
678
|
try {
|
|
373
|
-
|
|
374
|
-
|
|
679
|
+
// Determine spinner message based on input
|
|
680
|
+
let spinnerMsg = 'Processing';
|
|
681
|
+
if (trimmed.startsWith('/plan') || trimmed === '/p')
|
|
682
|
+
spinnerMsg = 'Planning';
|
|
683
|
+
else if (trimmed.startsWith('/generate') || trimmed === '/g')
|
|
684
|
+
spinnerMsg = 'Generating';
|
|
685
|
+
else if (trimmed.startsWith('/apply') || trimmed === '/a')
|
|
686
|
+
spinnerMsg = 'Applying';
|
|
687
|
+
else if (trimmed.startsWith('/do '))
|
|
688
|
+
spinnerMsg = 'Executing';
|
|
689
|
+
else if (trimmed.startsWith('/run '))
|
|
690
|
+
spinnerMsg = 'Running';
|
|
691
|
+
else if (trimmed.startsWith('/ask') || trimmed.startsWith('/commit'))
|
|
692
|
+
spinnerMsg = 'Thinking';
|
|
693
|
+
else if (!trimmed.startsWith('/'))
|
|
694
|
+
spinnerMsg = 'Thinking';
|
|
695
|
+
startSpinner(spinnerMsg);
|
|
375
696
|
await (0, orchestrator_1.orchestrate)(value);
|
|
697
|
+
stopSpinner();
|
|
376
698
|
}
|
|
377
699
|
catch (e) {
|
|
378
|
-
|
|
700
|
+
stopSpinner();
|
|
701
|
+
output.log(`{red-fg}✗ Error: ${e?.message || e}{/red-fg}`);
|
|
379
702
|
}
|
|
380
703
|
console.log = originalLog;
|
|
381
704
|
console.error = originalError;
|
|
382
705
|
console.warn = originalWarn;
|
|
706
|
+
// Update all UI elements
|
|
707
|
+
updateContextLine();
|
|
708
|
+
updateTips();
|
|
383
709
|
updateStatusBar();
|
|
710
|
+
updateModeIndicator();
|
|
711
|
+
updatePlaceholder();
|
|
712
|
+
// Rotate tip
|
|
713
|
+
currentTip = (currentTip + 1) % WELCOME_TIPS.length;
|
|
714
|
+
output.log('');
|
|
384
715
|
screen.render();
|
|
385
716
|
}
|
|
386
717
|
// Input events
|
|
387
718
|
input.on('focus', () => {
|
|
719
|
+
updatePlaceholder();
|
|
388
720
|
screen.render();
|
|
389
721
|
});
|
|
390
722
|
input.on('blur', () => {
|
|
@@ -393,13 +725,15 @@ async function startTUI(options) {
|
|
|
393
725
|
// Manual keypress handling for Palette interaction
|
|
394
726
|
input.on('keypress', (ch, key) => {
|
|
395
727
|
if (!key) {
|
|
728
|
+
updatePlaceholder();
|
|
396
729
|
screen.render();
|
|
397
730
|
return;
|
|
398
731
|
}
|
|
399
732
|
if (key.name === 'escape') {
|
|
400
|
-
if (showPalette)
|
|
733
|
+
if (showPalette)
|
|
401
734
|
togglePalette(false);
|
|
402
|
-
|
|
735
|
+
if (showFileAutocomplete)
|
|
736
|
+
toggleFileAutocomplete(false);
|
|
403
737
|
screen.render();
|
|
404
738
|
return;
|
|
405
739
|
}
|
|
@@ -409,6 +743,11 @@ async function startTUI(options) {
|
|
|
409
743
|
screen.render();
|
|
410
744
|
return;
|
|
411
745
|
}
|
|
746
|
+
if (showFileAutocomplete) {
|
|
747
|
+
fileAutocomplete.down(1);
|
|
748
|
+
screen.render();
|
|
749
|
+
return;
|
|
750
|
+
}
|
|
412
751
|
}
|
|
413
752
|
if (key.name === 'up') {
|
|
414
753
|
if (showPalette) {
|
|
@@ -416,16 +755,62 @@ async function startTUI(options) {
|
|
|
416
755
|
screen.render();
|
|
417
756
|
return;
|
|
418
757
|
}
|
|
758
|
+
if (showFileAutocomplete) {
|
|
759
|
+
fileAutocomplete.up(1);
|
|
760
|
+
screen.render();
|
|
761
|
+
return;
|
|
762
|
+
}
|
|
763
|
+
// Command history navigation
|
|
764
|
+
if (commandHistory.length > 0 && historyIndex < commandHistory.length - 1) {
|
|
765
|
+
historyIndex++;
|
|
766
|
+
input.setValue(commandHistory[historyIndex]);
|
|
767
|
+
updatePlaceholder();
|
|
768
|
+
screen.render();
|
|
769
|
+
return;
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
// Tab completion for files
|
|
773
|
+
if (key.name === 'tab') {
|
|
774
|
+
if (showFileAutocomplete && autocompleteFiles.length > 0) {
|
|
775
|
+
const selectedIndex = fileAutocomplete.selected || 0;
|
|
776
|
+
const selectedFile = autocompleteFiles[selectedIndex];
|
|
777
|
+
if (selectedFile) {
|
|
778
|
+
const currentVal = input.getValue();
|
|
779
|
+
const parts = currentVal.split(' ');
|
|
780
|
+
parts[parts.length - 1] = selectedFile;
|
|
781
|
+
input.setValue(parts.join(' '));
|
|
782
|
+
toggleFileAutocomplete(false);
|
|
783
|
+
updatePlaceholder();
|
|
784
|
+
screen.render();
|
|
785
|
+
}
|
|
786
|
+
return;
|
|
787
|
+
}
|
|
419
788
|
}
|
|
420
789
|
// Check input content on next tick to see if we should show palette
|
|
421
790
|
setImmediate(() => {
|
|
422
791
|
const val = input.getValue();
|
|
792
|
+
updatePlaceholder();
|
|
423
793
|
if (val && val.startsWith('/')) {
|
|
794
|
+
toggleFileAutocomplete(false);
|
|
424
795
|
togglePalette(true, val);
|
|
796
|
+
// Check for file commands that need autocomplete
|
|
797
|
+
const fileCommands = ['/open ', '/read ', '/cat ', '/close '];
|
|
798
|
+
for (const cmd of fileCommands) {
|
|
799
|
+
if (val.startsWith(cmd)) {
|
|
800
|
+
const query = val.substring(cmd.length);
|
|
801
|
+
if (query.length > 0) {
|
|
802
|
+
togglePalette(false);
|
|
803
|
+
toggleFileAutocomplete(true, query);
|
|
804
|
+
}
|
|
805
|
+
break;
|
|
806
|
+
}
|
|
807
|
+
}
|
|
425
808
|
}
|
|
426
809
|
else {
|
|
427
810
|
if (showPalette)
|
|
428
811
|
togglePalette(false);
|
|
812
|
+
if (showFileAutocomplete)
|
|
813
|
+
toggleFileAutocomplete(false);
|
|
429
814
|
}
|
|
430
815
|
screen.render();
|
|
431
816
|
});
|
|
@@ -436,24 +821,48 @@ async function startTUI(options) {
|
|
|
436
821
|
if (showPalette && inputValue.startsWith('/')) {
|
|
437
822
|
const selectedIndex = palette.selected || 0;
|
|
438
823
|
const filter = inputValue.replace(/^\//, '').toLowerCase();
|
|
439
|
-
const filteredCommands = COMMANDS.filter(c => c.name.startsWith(filter));
|
|
824
|
+
const filteredCommands = COMMANDS.filter(c => c.name.startsWith(filter) || c.description.toLowerCase().includes(filter));
|
|
440
825
|
if (filteredCommands[selectedIndex]) {
|
|
441
|
-
// Check if command needs arguments
|
|
442
826
|
const cmd = filteredCommands[selectedIndex];
|
|
443
|
-
const
|
|
444
|
-
if (
|
|
445
|
-
// Command needs args - autocomplete and wait for user to type args
|
|
827
|
+
const needsArgs = ['mode', 'model', 'open', 'read', 'cat', 'close', 'do', 'run', 'ask', 'fix', 'exec', 'search'].includes(cmd.name);
|
|
828
|
+
if (needsArgs && !inputValue.includes(' ')) {
|
|
446
829
|
input.setValue('/' + cmd.name + ' ');
|
|
447
830
|
togglePalette(false);
|
|
448
831
|
input.focus();
|
|
832
|
+
updatePlaceholder();
|
|
449
833
|
screen.render();
|
|
450
834
|
return;
|
|
451
835
|
}
|
|
452
836
|
}
|
|
453
837
|
}
|
|
838
|
+
// Handle file autocomplete selection
|
|
839
|
+
if (showFileAutocomplete && autocompleteFiles.length > 0) {
|
|
840
|
+
const selectedIndex = fileAutocomplete.selected || 0;
|
|
841
|
+
const selectedFile = autocompleteFiles[selectedIndex];
|
|
842
|
+
if (selectedFile) {
|
|
843
|
+
const currentVal = inputValue;
|
|
844
|
+
const parts = currentVal.split(' ');
|
|
845
|
+
parts[parts.length - 1] = selectedFile;
|
|
846
|
+
const newValue = parts.join(' ');
|
|
847
|
+
input.clearValue();
|
|
848
|
+
toggleFileAutocomplete(false);
|
|
849
|
+
togglePalette(false);
|
|
850
|
+
updatePlaceholder();
|
|
851
|
+
screen.render();
|
|
852
|
+
if (newValue && newValue.trim()) {
|
|
853
|
+
await processInput(newValue);
|
|
854
|
+
}
|
|
855
|
+
input.focus();
|
|
856
|
+
updatePlaceholder();
|
|
857
|
+
screen.render();
|
|
858
|
+
return;
|
|
859
|
+
}
|
|
860
|
+
}
|
|
454
861
|
// Clear input and palette before processing
|
|
455
862
|
input.clearValue();
|
|
456
863
|
togglePalette(false);
|
|
864
|
+
toggleFileAutocomplete(false);
|
|
865
|
+
updatePlaceholder();
|
|
457
866
|
screen.render();
|
|
458
867
|
// Process the input
|
|
459
868
|
if (inputValue && inputValue.trim()) {
|
|
@@ -461,6 +870,7 @@ async function startTUI(options) {
|
|
|
461
870
|
}
|
|
462
871
|
// Refocus input for next command
|
|
463
872
|
input.focus();
|
|
873
|
+
updatePlaceholder();
|
|
464
874
|
screen.render();
|
|
465
875
|
});
|
|
466
876
|
// SETTINGS MODAL
|
|
@@ -586,6 +996,74 @@ async function startTUI(options) {
|
|
|
586
996
|
onExit?.();
|
|
587
997
|
return process.exit(0);
|
|
588
998
|
});
|
|
999
|
+
// Quick action shortcuts
|
|
1000
|
+
screen.key(['C-d'], async () => {
|
|
1001
|
+
// Quick /do - need to prompt for task
|
|
1002
|
+
input.setValue('/do ');
|
|
1003
|
+
input.focus();
|
|
1004
|
+
updatePlaceholder();
|
|
1005
|
+
screen.render();
|
|
1006
|
+
});
|
|
1007
|
+
screen.key(['C-r'], async () => {
|
|
1008
|
+
// Quick /run
|
|
1009
|
+
input.setValue('/run ');
|
|
1010
|
+
input.focus();
|
|
1011
|
+
updatePlaceholder();
|
|
1012
|
+
screen.render();
|
|
1013
|
+
});
|
|
1014
|
+
screen.key(['C-p'], async () => {
|
|
1015
|
+
// Quick /plan
|
|
1016
|
+
if (screen.focused === input && !input.getValue()) {
|
|
1017
|
+
input.clearValue();
|
|
1018
|
+
togglePalette(false);
|
|
1019
|
+
updatePlaceholder();
|
|
1020
|
+
screen.render();
|
|
1021
|
+
await processInput('/plan');
|
|
1022
|
+
input.focus();
|
|
1023
|
+
updatePlaceholder();
|
|
1024
|
+
screen.render();
|
|
1025
|
+
}
|
|
1026
|
+
});
|
|
1027
|
+
screen.key(['C-g'], async () => {
|
|
1028
|
+
// Quick /generate
|
|
1029
|
+
if (screen.focused === input && !input.getValue()) {
|
|
1030
|
+
input.clearValue();
|
|
1031
|
+
togglePalette(false);
|
|
1032
|
+
updatePlaceholder();
|
|
1033
|
+
screen.render();
|
|
1034
|
+
await processInput('/generate');
|
|
1035
|
+
input.focus();
|
|
1036
|
+
updatePlaceholder();
|
|
1037
|
+
screen.render();
|
|
1038
|
+
}
|
|
1039
|
+
});
|
|
1040
|
+
screen.key(['C-z'], async () => {
|
|
1041
|
+
// Quick /undo
|
|
1042
|
+
if (screen.focused === input && !input.getValue()) {
|
|
1043
|
+
input.clearValue();
|
|
1044
|
+
togglePalette(false);
|
|
1045
|
+
updatePlaceholder();
|
|
1046
|
+
screen.render();
|
|
1047
|
+
await processInput('/undo');
|
|
1048
|
+
input.focus();
|
|
1049
|
+
updatePlaceholder();
|
|
1050
|
+
screen.render();
|
|
1051
|
+
}
|
|
1052
|
+
});
|
|
1053
|
+
screen.key(['C-a'], async () => {
|
|
1054
|
+
// Quick /ask
|
|
1055
|
+
input.setValue('/ask ');
|
|
1056
|
+
input.focus();
|
|
1057
|
+
updatePlaceholder();
|
|
1058
|
+
screen.render();
|
|
1059
|
+
});
|
|
1060
|
+
screen.key(['C-f'], async () => {
|
|
1061
|
+
// Quick /fix
|
|
1062
|
+
input.setValue('/fix ');
|
|
1063
|
+
input.focus();
|
|
1064
|
+
updatePlaceholder();
|
|
1065
|
+
screen.render();
|
|
1066
|
+
});
|
|
589
1067
|
screen.key(['q'], () => {
|
|
590
1068
|
// Only quit if not focused on input
|
|
591
1069
|
if (screen.focused !== input) {
|