codeep 1.0.132 → 1.1.1

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/dist/app.js CHANGED
@@ -35,9 +35,9 @@ import { saveContext, loadContext, clearContext, mergeContext } from './utils/co
35
35
  import { performCodeReview, formatReviewResult } from './utils/codeReview.js';
36
36
  import { learnFromProject, addCustomRule, getLearningStatus } from './utils/learning.js';
37
37
  import { getAllSkills, findSkill, formatSkillsList, formatSkillHelp, generateSkillPrompt, saveCustomSkill, deleteCustomSkill, parseSkillChain, parseSkillArgs, searchSkills, trackSkillUsage, getSkillStats } from './utils/skills.js';
38
- import { AgentStatusBar } from './components/AgentProgress.js';
39
38
  import { createActionLog } from './utils/tools.js';
40
39
  import { scanProject, saveProjectIntelligence, loadProjectIntelligence, generateContextFromIntelligence } from './utils/projectIntelligence.js';
40
+ import { logAction, startAgentSpinner, updateSpinner, stopSpinner, logAgentComplete, logSeparator, setAgentRunning } from './utils/console.js';
41
41
  export const App = () => {
42
42
  const { exit } = useApp();
43
43
  const { stdout } = useStdout();
@@ -269,6 +269,10 @@ export const App = () => {
269
269
  setAgentResult(null);
270
270
  setAgentDryRun(dryRun);
271
271
  setAgentStreamingContent(''); // Reset streaming content
272
+ // Start console spinner for agent
273
+ logSeparator();
274
+ setAgentRunning(true, dryRun);
275
+ startAgentSpinner('Starting...', dryRun);
272
276
  // Add user message
273
277
  const userMessage = {
274
278
  role: 'user',
@@ -283,6 +287,7 @@ export const App = () => {
283
287
  dryRun,
284
288
  onIteration: (iteration, message) => {
285
289
  setAgentIteration(iteration);
290
+ updateSpinner(`Step ${iteration}`, dryRun);
286
291
  },
287
292
  onToolCall: (tool) => {
288
293
  // Create action log with content for live code preview
@@ -325,46 +330,8 @@ export const App = () => {
325
330
  }
326
331
  return updated;
327
332
  });
328
- // Add formatted action to streaming content (stays in chat)
329
- // NO CODE DISPLAY - just clean action lines to prevent terminal jumping
330
- const actionType = actionLog.type;
331
- const target = actionLog.target.split('/').pop() || actionLog.target; // Just filename
332
- const status = actionLog.result === 'success' ? '✓' : '✗';
333
- const failedText = actionLog.result === 'error' ? ' ✗' : '';
334
- // Count lines in content
335
- const lineCount = actionLog.details ? actionLog.details.split('\n').length : 0;
336
- let actionLine = '';
337
- if (actionType === 'write') {
338
- actionLine = `${status} Created **${target}**${lineCount > 0 ? ` (${lineCount} lines)` : ''}${failedText}`;
339
- }
340
- else if (actionType === 'edit') {
341
- actionLine = `${status} Edited **${target}**${lineCount > 0 ? ` (${lineCount} lines)` : ''}${failedText}`;
342
- }
343
- else if (actionType === 'read') {
344
- actionLine = `→ Reading **${target}**`;
345
- }
346
- else if (actionType === 'delete') {
347
- actionLine = `${status} Deleted **${target}**${failedText}`;
348
- }
349
- else if (actionType === 'command') {
350
- const cmd = actionLog.target.length > 40 ? actionLog.target.slice(0, 40) + '...' : actionLog.target;
351
- actionLine = `${status} Ran \`${cmd}\`${failedText}`;
352
- }
353
- else if (actionType === 'search') {
354
- actionLine = `→ Searching **${target}**`;
355
- }
356
- else if (actionType === 'mkdir') {
357
- actionLine = `${status} Created dir **${target}**`;
358
- }
359
- else if (actionType === 'fetch') {
360
- actionLine = `→ Fetching **${target}**`;
361
- }
362
- else if (actionType === 'list') {
363
- actionLine = `→ Listing **${target}**`;
364
- }
365
- if (actionLine) {
366
- setAgentStreamingContent(prev => prev + (prev ? '\n' : '') + actionLine);
367
- }
333
+ // Use console.log with chalk for agent actions - no Ink re-rendering!
334
+ logAction(actionLog.type, actionLog.target, actionLog.result, actionLog.details);
368
335
  },
369
336
  onThinking: (text) => {
370
337
  // Strip <think> and <tool_call> tags from thinking text
@@ -382,6 +349,7 @@ export const App = () => {
382
349
  setAgentResult(result);
383
350
  // Build action statistics
384
351
  const stats = {
352
+ iterations: result.iterations,
385
353
  created: result.actions.filter(a => a.type === 'write' && a.result === 'success').length,
386
354
  edited: result.actions.filter(a => a.type === 'edit' && a.result === 'success').length,
387
355
  deleted: result.actions.filter(a => a.type === 'delete' && a.result === 'success').length,
@@ -389,25 +357,14 @@ export const App = () => {
389
357
  reads: result.actions.filter(a => a.type === 'read').length,
390
358
  errors: result.actions.filter(a => a.result === 'error').length,
391
359
  };
392
- // Format statistics line
393
- const statParts = [];
394
- if (stats.created > 0)
395
- statParts.push(`+${stats.created} created`);
396
- if (stats.edited > 0)
397
- statParts.push(`~${stats.edited} edited`);
398
- if (stats.deleted > 0)
399
- statParts.push(`-${stats.deleted} deleted`);
400
- if (stats.commands > 0)
401
- statParts.push(`${stats.commands} commands`);
402
- if (stats.errors > 0)
403
- statParts.push(`${stats.errors} errors`);
404
- const statsLine = statParts.length > 0
405
- ? `\n\n---\n**${result.iterations} steps** | ${statParts.join(' | ')}`
406
- : '';
407
- // Add agent summary as assistant message with stats
360
+ // Log completion to console (chalk/ora)
361
+ setAgentRunning(false);
362
+ logAgentComplete(stats, result.success);
363
+ logSeparator();
364
+ // Add agent summary as assistant message (without duplicate stats - they're in console)
408
365
  const summaryMessage = {
409
366
  role: 'assistant',
410
- content: (result.finalResponse || formatAgentResult(result)) + statsLine,
367
+ content: result.finalResponse || formatAgentResult(result),
411
368
  };
412
369
  setMessages(prev => [...prev, summaryMessage]);
413
370
  // Auto-save session
@@ -424,9 +381,13 @@ export const App = () => {
424
381
  }
425
382
  catch (error) {
426
383
  const err = error;
384
+ setAgentRunning(false);
385
+ stopSpinner();
427
386
  notify(`Agent error: ${err.message}`);
428
387
  }
429
388
  finally {
389
+ setAgentRunning(false);
390
+ stopSpinner();
430
391
  setIsAgentRunning(false);
431
392
  setAbortController(null);
432
393
  setAgentThinking('');
@@ -1437,7 +1398,7 @@ export const App = () => {
1437
1398
  // Helper to check if we're showing an inline menu
1438
1399
  const isInlineMenu = ['help', 'status', 'settings', 'sessions', 'sessions-delete',
1439
1400
  'logout', 'search', 'export', 'model', 'provider', 'protocol', 'language'].includes(screen);
1440
- return (_jsxs(Box, { flexDirection: "column", children: [messages.length === 0 && !isLoading && _jsx(Logo, {}), messages.length === 0 && !isLoading && (_jsxs(Box, { flexDirection: "column", marginY: 1, children: [_jsx(Box, { justifyContent: "center", children: _jsxs(Text, { children: ["Connected to ", _jsx(Text, { color: "#f02a30", children: config.get('model') }), ". Type ", _jsx(Text, { color: "#f02a30", children: "/help" }), " for commands."] }) }), _jsx(Text, { children: " " }), _jsx(Box, { justifyContent: "center", children: _jsx(Text, { color: "cyan", bold: true, children: "Welcome to Codeep - Your AI Coding Assistant" }) }), _jsx(Text, { children: " " }), _jsxs(Box, { flexDirection: "column", paddingX: 2, children: [_jsxs(Text, { children: [_jsx(Text, { color: "#f02a30", children: "\u2022" }), " Ask questions about your code or request implementations"] }), _jsxs(Text, { children: [_jsx(Text, { color: "#f02a30", children: "\u2022" }), " Use ", _jsxs(Text, { color: "cyan", children: ["/agent ", '<task>'] }), " for autonomous task execution"] }), _jsxs(Text, { children: [_jsx(Text, { color: "#f02a30", children: "\u2022" }), " Type ", _jsx(Text, { color: "cyan", children: "/diff" }), " to review changes, ", _jsx(Text, { color: "cyan", children: "/commit" }), " to generate commit messages"] }), _jsxs(Text, { children: [_jsx(Text, { color: "#f02a30", children: "\u2022" }), " Configure settings with ", _jsx(Text, { color: "cyan", children: "/settings" }), " - enable Agent Mode for auto-execution"] })] }), _jsx(Text, { children: " " }), _jsx(Box, { justifyContent: "center", children: _jsx(Text, { color: "gray", children: "Start typing your message or use a command to begin..." }) }), _jsx(Text, { children: " " })] })), _jsx(MessageList, { messages: messages, streamingContent: streamingContent, agentStreamingContent: isAgentRunning ? agentStreamingContent : undefined }, sessionId), isLoading && !isAgentRunning && _jsx(Loading, { isStreaming: !!streamingContent }), isAgentRunning && (_jsx(AgentStatusBar, { iteration: agentIteration, actionsCount: agentActions.length, dryRun: agentDryRun, currentAction: agentActions.length > 0 ? `${agentActions[agentActions.length - 1].type}: ${agentActions[agentActions.length - 1].target.split('/').pop()}` : undefined })), pendingFileChanges.length > 0 && !isLoading && (_jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "#f02a30", padding: 1, marginY: 1, children: [_jsxs(Text, { color: "#f02a30", bold: true, children: ["\u2713 Detected ", pendingFileChanges.length, " file change(s):"] }), pendingFileChanges.map((change, i) => {
1401
+ return (_jsxs(Box, { flexDirection: "column", children: [messages.length === 0 && !isLoading && _jsx(Logo, {}), messages.length === 0 && !isLoading && (_jsxs(Box, { flexDirection: "column", marginY: 1, children: [_jsx(Box, { justifyContent: "center", children: _jsxs(Text, { children: ["Connected to ", _jsx(Text, { color: "#f02a30", children: config.get('model') }), ". Type ", _jsx(Text, { color: "#f02a30", children: "/help" }), " for commands."] }) }), _jsx(Text, { children: " " }), _jsx(Box, { justifyContent: "center", children: _jsx(Text, { color: "cyan", bold: true, children: "Welcome to Codeep - Your AI Coding Assistant" }) }), _jsx(Text, { children: " " }), _jsxs(Box, { flexDirection: "column", paddingX: 2, children: [_jsxs(Text, { children: [_jsx(Text, { color: "#f02a30", children: "\u2022" }), " Ask questions about your code or request implementations"] }), _jsxs(Text, { children: [_jsx(Text, { color: "#f02a30", children: "\u2022" }), " Use ", _jsxs(Text, { color: "cyan", children: ["/agent ", '<task>'] }), " for autonomous task execution"] }), _jsxs(Text, { children: [_jsx(Text, { color: "#f02a30", children: "\u2022" }), " Type ", _jsx(Text, { color: "cyan", children: "/diff" }), " to review changes, ", _jsx(Text, { color: "cyan", children: "/commit" }), " to generate commit messages"] }), _jsxs(Text, { children: [_jsx(Text, { color: "#f02a30", children: "\u2022" }), " Configure settings with ", _jsx(Text, { color: "cyan", children: "/settings" }), " - enable Agent Mode for auto-execution"] })] }), _jsx(Text, { children: " " }), _jsx(Box, { justifyContent: "center", children: _jsx(Text, { color: "gray", children: "Start typing your message or use a command to begin..." }) }), _jsx(Text, { children: " " })] })), _jsx(MessageList, { messages: messages, streamingContent: streamingContent }, sessionId), isLoading && !isAgentRunning && _jsx(Loading, { isStreaming: !!streamingContent }), pendingFileChanges.length > 0 && !isLoading && (_jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "#f02a30", padding: 1, marginY: 1, children: [_jsxs(Text, { color: "#f02a30", bold: true, children: ["\u2713 Detected ", pendingFileChanges.length, " file change(s):"] }), pendingFileChanges.map((change, i) => {
1441
1402
  const actionColor = change.action === 'delete' ? 'red' : change.action === 'edit' ? 'yellow' : 'green';
1442
1403
  const actionLabel = change.action === 'delete' ? 'DELETE' : change.action === 'edit' ? 'EDIT' : 'CREATE';
1443
1404
  return (_jsxs(Text, { children: ["\u2022 ", _jsxs(Text, { color: actionColor, children: ["[", actionLabel, "]"] }), " ", change.path, change.action !== 'delete' && change.content.includes('\n') && ` (${change.content.split('\n').length} lines)`] }, i));
@@ -3,7 +3,6 @@ import { Message } from '../config/index';
3
3
  interface MessageListProps {
4
4
  messages: Message[];
5
5
  streamingContent?: string;
6
- agentStreamingContent?: string;
7
6
  scrollOffset?: number;
8
7
  terminalHeight?: number;
9
8
  }
@@ -21,9 +21,9 @@ MemoizedMessage.displayName = 'MemoizedMessage';
21
21
  * NOTE: This is a temporary solution until we implement a custom renderer
22
22
  * like Claude CLI uses (DEC Mode 2026 / synchronized output).
23
23
  */
24
- export const MessageList = memo(({ messages, streamingContent, agentStreamingContent, }) => {
24
+ export const MessageList = memo(({ messages, streamingContent, }) => {
25
25
  // Memoize the messages array rendering
26
26
  const renderedMessages = useMemo(() => (messages.map((msg, index) => (_jsx(MemoizedMessage, { msg: msg, index: index }, `msg-${index}-${msg.role}`)))), [messages]);
27
- return (_jsxs(Box, { flexDirection: "column", children: [renderedMessages, streamingContent && (_jsx(StreamingMessage, { content: streamingContent })), agentStreamingContent && (_jsx(StreamingMessage, { content: `**Agent Actions:**\n${agentStreamingContent}` }))] }));
27
+ return (_jsxs(Box, { flexDirection: "column", children: [renderedMessages, streamingContent && (_jsx(StreamingMessage, { content: streamingContent }))] }));
28
28
  });
29
29
  MessageList.displayName = 'MessageList';
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Console output utilities using chalk and ora
3
+ * Used for agent streaming to avoid Ink re-rendering issues
4
+ */
5
+ /**
6
+ * Start agent spinner
7
+ */
8
+ export declare function startAgentSpinner(text?: string, dryRun?: boolean): void;
9
+ /**
10
+ * Update spinner text
11
+ */
12
+ export declare function updateSpinner(text: string, dryRun?: boolean): void;
13
+ /**
14
+ * Stop spinner with success
15
+ */
16
+ export declare function spinnerSuccess(text?: string): void;
17
+ /**
18
+ * Stop spinner with failure
19
+ */
20
+ export declare function spinnerFail(text?: string): void;
21
+ /**
22
+ * Stop spinner without status
23
+ */
24
+ export declare function stopSpinner(): void;
25
+ /**
26
+ * Set agent running state
27
+ */
28
+ export declare function setAgentRunning(running: boolean, dryRun?: boolean): void;
29
+ /**
30
+ * Log agent action
31
+ */
32
+ export declare function logAction(type: string, target: string, result: 'success' | 'error' | 'pending', details?: string): void;
33
+ /**
34
+ * Log agent step change
35
+ */
36
+ export declare function logStep(step: number, actionsCount: number, dryRun?: boolean): void;
37
+ /**
38
+ * Log agent completion
39
+ */
40
+ export declare function logAgentComplete(stats: {
41
+ iterations: number;
42
+ created: number;
43
+ edited: number;
44
+ deleted: number;
45
+ commands: number;
46
+ errors: number;
47
+ }, success?: boolean): void;
48
+ /**
49
+ * Log separator line
50
+ */
51
+ export declare function logSeparator(): void;
52
+ /**
53
+ * Log with brand color
54
+ */
55
+ export declare function logBrand(text: string): void;
@@ -0,0 +1,187 @@
1
+ /**
2
+ * Console output utilities using chalk and ora
3
+ * Used for agent streaming to avoid Ink re-rendering issues
4
+ */
5
+ import chalk from 'chalk';
6
+ import ora from 'ora';
7
+ // Brand color
8
+ const brandRed = chalk.hex('#f02a30');
9
+ // Current spinner instance
10
+ let currentSpinner = null;
11
+ /**
12
+ * Start agent spinner
13
+ */
14
+ export function startAgentSpinner(text = 'Agent working...', dryRun = false) {
15
+ stopSpinner();
16
+ const prefix = dryRun ? chalk.yellow('[DRY RUN]') : brandRed('[AGENT]');
17
+ currentSpinner = ora({
18
+ text: `${prefix} ${text}`,
19
+ color: dryRun ? 'yellow' : 'red',
20
+ }).start();
21
+ }
22
+ /**
23
+ * Update spinner text
24
+ */
25
+ export function updateSpinner(text, dryRun = false) {
26
+ if (currentSpinner) {
27
+ const prefix = dryRun ? chalk.yellow('[DRY RUN]') : brandRed('[AGENT]');
28
+ currentSpinner.text = `${prefix} ${text}`;
29
+ }
30
+ }
31
+ /**
32
+ * Stop spinner with success
33
+ */
34
+ export function spinnerSuccess(text) {
35
+ if (currentSpinner) {
36
+ currentSpinner.succeed(text);
37
+ currentSpinner = null;
38
+ }
39
+ }
40
+ /**
41
+ * Stop spinner with failure
42
+ */
43
+ export function spinnerFail(text) {
44
+ if (currentSpinner) {
45
+ currentSpinner.fail(text);
46
+ currentSpinner = null;
47
+ }
48
+ }
49
+ /**
50
+ * Stop spinner without status
51
+ */
52
+ export function stopSpinner() {
53
+ if (currentSpinner) {
54
+ currentSpinner.stop();
55
+ currentSpinner = null;
56
+ }
57
+ }
58
+ // Track if agent is running for auto-restart spinner
59
+ let agentRunning = false;
60
+ let lastDryRun = false;
61
+ /**
62
+ * Set agent running state
63
+ */
64
+ export function setAgentRunning(running, dryRun = false) {
65
+ agentRunning = running;
66
+ lastDryRun = dryRun;
67
+ }
68
+ /**
69
+ * Log agent action
70
+ */
71
+ export function logAction(type, target, result, details) {
72
+ stopSpinner(); // Stop spinner before logging
73
+ const filename = target.split('/').pop() || target;
74
+ const lineCount = details ? details.split('\n').length : 0;
75
+ let icon;
76
+ let color;
77
+ let verb;
78
+ switch (type) {
79
+ case 'write':
80
+ icon = result === 'success' ? '✓' : '✗';
81
+ color = result === 'success' ? chalk.green : chalk.red;
82
+ verb = 'Created';
83
+ break;
84
+ case 'edit':
85
+ icon = result === 'success' ? '✓' : '✗';
86
+ color = result === 'success' ? chalk.yellow : chalk.red;
87
+ verb = 'Edited';
88
+ break;
89
+ case 'delete':
90
+ icon = result === 'success' ? '✓' : '✗';
91
+ color = result === 'success' ? chalk.red : chalk.red;
92
+ verb = 'Deleted';
93
+ break;
94
+ case 'read':
95
+ icon = '→';
96
+ color = chalk.blue;
97
+ verb = 'Reading';
98
+ break;
99
+ case 'search':
100
+ icon = '→';
101
+ color = chalk.cyan;
102
+ verb = 'Searching';
103
+ break;
104
+ case 'command':
105
+ icon = result === 'success' ? '✓' : '✗';
106
+ color = result === 'success' ? chalk.magenta : chalk.red;
107
+ verb = 'Ran';
108
+ break;
109
+ case 'mkdir':
110
+ icon = result === 'success' ? '✓' : '✗';
111
+ color = result === 'success' ? chalk.blue : chalk.red;
112
+ verb = 'Created dir';
113
+ break;
114
+ case 'fetch':
115
+ icon = '→';
116
+ color = chalk.cyan;
117
+ verb = 'Fetching';
118
+ break;
119
+ case 'list':
120
+ icon = '→';
121
+ color = chalk.gray;
122
+ verb = 'Listing';
123
+ break;
124
+ default:
125
+ icon = '◦';
126
+ color = chalk.white;
127
+ verb = type;
128
+ }
129
+ // Format line count for write/edit
130
+ const lineInfo = (type === 'write' || type === 'edit') && lineCount > 0
131
+ ? chalk.gray(` (${lineCount} lines)`)
132
+ : '';
133
+ // Format command differently
134
+ const displayTarget = type === 'command'
135
+ ? chalk.gray(`\`${filename.length > 40 ? filename.slice(0, 40) + '...' : filename}\``)
136
+ : chalk.bold(filename);
137
+ console.log(`${color(icon)} ${verb} ${displayTarget}${lineInfo}`);
138
+ // Restart spinner if agent is still running
139
+ if (agentRunning) {
140
+ startAgentSpinner('Working...', lastDryRun);
141
+ }
142
+ }
143
+ /**
144
+ * Log agent step change
145
+ */
146
+ export function logStep(step, actionsCount, dryRun = false) {
147
+ const prefix = dryRun ? chalk.yellow('[DRY RUN]') : brandRed('[AGENT]');
148
+ console.log(`${prefix} Step ${chalk.cyan(step)} | ${actionsCount} actions`);
149
+ }
150
+ /**
151
+ * Log agent completion
152
+ */
153
+ export function logAgentComplete(stats, success = true) {
154
+ stopSpinner();
155
+ console.log(''); // Empty line
156
+ const statParts = [];
157
+ if (stats.created > 0)
158
+ statParts.push(chalk.green(`+${stats.created} created`));
159
+ if (stats.edited > 0)
160
+ statParts.push(chalk.yellow(`~${stats.edited} edited`));
161
+ if (stats.deleted > 0)
162
+ statParts.push(chalk.red(`-${stats.deleted} deleted`));
163
+ if (stats.commands > 0)
164
+ statParts.push(chalk.magenta(`${stats.commands} commands`));
165
+ if (stats.errors > 0)
166
+ statParts.push(chalk.red(`${stats.errors} errors`));
167
+ const statsLine = statParts.length > 0 ? statParts.join(chalk.gray(' | ')) : chalk.gray('no changes');
168
+ if (success) {
169
+ console.log(`${chalk.green('✓')} Agent completed: ${chalk.bold(stats.iterations)} steps | ${statsLine}`);
170
+ }
171
+ else {
172
+ console.log(`${chalk.red('✗')} Agent failed: ${chalk.bold(stats.iterations)} steps | ${statsLine}`);
173
+ }
174
+ console.log(''); // Empty line
175
+ }
176
+ /**
177
+ * Log separator line
178
+ */
179
+ export function logSeparator() {
180
+ console.log(brandRed('─'.repeat(60)));
181
+ }
182
+ /**
183
+ * Log with brand color
184
+ */
185
+ export function logBrand(text) {
186
+ console.log(brandRed(text));
187
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codeep",
3
- "version": "1.0.132",
3
+ "version": "1.1.1",
4
4
  "description": "AI-powered coding assistant built for the terminal. Multiple LLM providers, project-aware context, and a seamless development workflow.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -36,6 +36,8 @@
36
36
  },
37
37
  "homepage": "https://codeep.dev",
38
38
  "dependencies": {
39
+ "@types/prompts": "^2.4.9",
40
+ "chalk": "^5.6.2",
39
41
  "clipboardy": "^4.0.0",
40
42
  "conf": "^12.0.0",
41
43
  "ink": "^4.4.1",
@@ -43,7 +45,10 @@
43
45
  "ink-text-input": "^5.0.1",
44
46
  "keytar": "^7.9.0",
45
47
  "open": "^10.0.0",
46
- "react": "^18.2.0"
48
+ "ora": "^9.2.0",
49
+ "prompts": "^2.4.2",
50
+ "react": "^18.2.0",
51
+ "readline": "^1.3.0"
47
52
  },
48
53
  "devDependencies": {
49
54
  "@types/node": "^20.10.0",