codeep 1.0.132 → 1.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.
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 } from './utils/console.js';
41
41
  export const App = () => {
42
42
  const { exit } = useApp();
43
43
  const { stdout } = useStdout();
@@ -269,6 +269,9 @@ 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
+ startAgentSpinner('Starting...', dryRun);
272
275
  // Add user message
273
276
  const userMessage = {
274
277
  role: 'user',
@@ -283,6 +286,7 @@ export const App = () => {
283
286
  dryRun,
284
287
  onIteration: (iteration, message) => {
285
288
  setAgentIteration(iteration);
289
+ updateSpinner(`Step ${iteration}`, dryRun);
286
290
  },
287
291
  onToolCall: (tool) => {
288
292
  // Create action log with content for live code preview
@@ -325,46 +329,8 @@ export const App = () => {
325
329
  }
326
330
  return updated;
327
331
  });
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
- }
332
+ // Use console.log with chalk for agent actions - no Ink re-rendering!
333
+ logAction(actionLog.type, actionLog.target, actionLog.result, actionLog.details);
368
334
  },
369
335
  onThinking: (text) => {
370
336
  // Strip <think> and <tool_call> tags from thinking text
@@ -382,6 +348,7 @@ export const App = () => {
382
348
  setAgentResult(result);
383
349
  // Build action statistics
384
350
  const stats = {
351
+ iterations: result.iterations,
385
352
  created: result.actions.filter(a => a.type === 'write' && a.result === 'success').length,
386
353
  edited: result.actions.filter(a => a.type === 'edit' && a.result === 'success').length,
387
354
  deleted: result.actions.filter(a => a.type === 'delete' && a.result === 'success').length,
@@ -389,25 +356,13 @@ export const App = () => {
389
356
  reads: result.actions.filter(a => a.type === 'read').length,
390
357
  errors: result.actions.filter(a => a.result === 'error').length,
391
358
  };
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
359
+ // Log completion to console (chalk/ora)
360
+ logAgentComplete(stats, result.success);
361
+ logSeparator();
362
+ // Add agent summary as assistant message (without duplicate stats - they're in console)
408
363
  const summaryMessage = {
409
364
  role: 'assistant',
410
- content: (result.finalResponse || formatAgentResult(result)) + statsLine,
365
+ content: result.finalResponse || formatAgentResult(result),
411
366
  };
412
367
  setMessages(prev => [...prev, summaryMessage]);
413
368
  // Auto-save session
@@ -424,9 +379,11 @@ export const App = () => {
424
379
  }
425
380
  catch (error) {
426
381
  const err = error;
382
+ stopSpinner();
427
383
  notify(`Agent error: ${err.message}`);
428
384
  }
429
385
  finally {
386
+ stopSpinner();
430
387
  setIsAgentRunning(false);
431
388
  setAbortController(null);
432
389
  setAgentThinking('');
@@ -1437,7 +1394,7 @@ export const App = () => {
1437
1394
  // Helper to check if we're showing an inline menu
1438
1395
  const isInlineMenu = ['help', 'status', 'settings', 'sessions', 'sessions-delete',
1439
1396
  '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) => {
1397
+ 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
1398
  const actionColor = change.action === 'delete' ? 'red' : change.action === 'edit' ? 'yellow' : 'green';
1442
1399
  const actionLabel = change.action === 'delete' ? 'DELETE' : change.action === 'edit' ? 'EDIT' : 'CREATE';
1443
1400
  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,51 @@
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
+ * Log agent action
27
+ */
28
+ export declare function logAction(type: string, target: string, result: 'success' | 'error' | 'pending', details?: string): void;
29
+ /**
30
+ * Log agent step change
31
+ */
32
+ export declare function logStep(step: number, actionsCount: number, dryRun?: boolean): void;
33
+ /**
34
+ * Log agent completion
35
+ */
36
+ export declare function logAgentComplete(stats: {
37
+ iterations: number;
38
+ created: number;
39
+ edited: number;
40
+ deleted: number;
41
+ commands: number;
42
+ errors: number;
43
+ }, success?: boolean): void;
44
+ /**
45
+ * Log separator line
46
+ */
47
+ export declare function logSeparator(): void;
48
+ /**
49
+ * Log with brand color
50
+ */
51
+ export declare function logBrand(text: string): void;
@@ -0,0 +1,173 @@
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
+ /**
59
+ * Log agent action
60
+ */
61
+ export function logAction(type, target, result, details) {
62
+ stopSpinner(); // Stop spinner before logging
63
+ const filename = target.split('/').pop() || target;
64
+ const lineCount = details ? details.split('\n').length : 0;
65
+ let icon;
66
+ let color;
67
+ let verb;
68
+ switch (type) {
69
+ case 'write':
70
+ icon = result === 'success' ? '✓' : '✗';
71
+ color = result === 'success' ? chalk.green : chalk.red;
72
+ verb = 'Created';
73
+ break;
74
+ case 'edit':
75
+ icon = result === 'success' ? '✓' : '✗';
76
+ color = result === 'success' ? chalk.yellow : chalk.red;
77
+ verb = 'Edited';
78
+ break;
79
+ case 'delete':
80
+ icon = result === 'success' ? '✓' : '✗';
81
+ color = result === 'success' ? chalk.red : chalk.red;
82
+ verb = 'Deleted';
83
+ break;
84
+ case 'read':
85
+ icon = '→';
86
+ color = chalk.blue;
87
+ verb = 'Reading';
88
+ break;
89
+ case 'search':
90
+ icon = '→';
91
+ color = chalk.cyan;
92
+ verb = 'Searching';
93
+ break;
94
+ case 'command':
95
+ icon = result === 'success' ? '✓' : '✗';
96
+ color = result === 'success' ? chalk.magenta : chalk.red;
97
+ verb = 'Ran';
98
+ break;
99
+ case 'mkdir':
100
+ icon = result === 'success' ? '✓' : '✗';
101
+ color = result === 'success' ? chalk.blue : chalk.red;
102
+ verb = 'Created dir';
103
+ break;
104
+ case 'fetch':
105
+ icon = '→';
106
+ color = chalk.cyan;
107
+ verb = 'Fetching';
108
+ break;
109
+ case 'list':
110
+ icon = '→';
111
+ color = chalk.gray;
112
+ verb = 'Listing';
113
+ break;
114
+ default:
115
+ icon = '◦';
116
+ color = chalk.white;
117
+ verb = type;
118
+ }
119
+ // Format line count for write/edit
120
+ const lineInfo = (type === 'write' || type === 'edit') && lineCount > 0
121
+ ? chalk.gray(` (${lineCount} lines)`)
122
+ : '';
123
+ // Format command differently
124
+ const displayTarget = type === 'command'
125
+ ? chalk.gray(`\`${filename.length > 40 ? filename.slice(0, 40) + '...' : filename}\``)
126
+ : chalk.bold(filename);
127
+ console.log(`${color(icon)} ${verb} ${displayTarget}${lineInfo}`);
128
+ }
129
+ /**
130
+ * Log agent step change
131
+ */
132
+ export function logStep(step, actionsCount, dryRun = false) {
133
+ const prefix = dryRun ? chalk.yellow('[DRY RUN]') : brandRed('[AGENT]');
134
+ console.log(`${prefix} Step ${chalk.cyan(step)} | ${actionsCount} actions`);
135
+ }
136
+ /**
137
+ * Log agent completion
138
+ */
139
+ export function logAgentComplete(stats, success = true) {
140
+ stopSpinner();
141
+ console.log(''); // Empty line
142
+ const statParts = [];
143
+ if (stats.created > 0)
144
+ statParts.push(chalk.green(`+${stats.created} created`));
145
+ if (stats.edited > 0)
146
+ statParts.push(chalk.yellow(`~${stats.edited} edited`));
147
+ if (stats.deleted > 0)
148
+ statParts.push(chalk.red(`-${stats.deleted} deleted`));
149
+ if (stats.commands > 0)
150
+ statParts.push(chalk.magenta(`${stats.commands} commands`));
151
+ if (stats.errors > 0)
152
+ statParts.push(chalk.red(`${stats.errors} errors`));
153
+ const statsLine = statParts.length > 0 ? statParts.join(chalk.gray(' | ')) : chalk.gray('no changes');
154
+ if (success) {
155
+ console.log(`${chalk.green('✓')} Agent completed: ${chalk.bold(stats.iterations)} steps | ${statsLine}`);
156
+ }
157
+ else {
158
+ console.log(`${chalk.red('✗')} Agent failed: ${chalk.bold(stats.iterations)} steps | ${statsLine}`);
159
+ }
160
+ console.log(''); // Empty line
161
+ }
162
+ /**
163
+ * Log separator line
164
+ */
165
+ export function logSeparator() {
166
+ console.log(brandRed('─'.repeat(60)));
167
+ }
168
+ /**
169
+ * Log with brand color
170
+ */
171
+ export function logBrand(text) {
172
+ console.log(brandRed(text));
173
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codeep",
3
- "version": "1.0.132",
3
+ "version": "1.1.0",
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",