codeep 1.1.6 → 1.1.8

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 { AgentActions } from './components/AgentActions.js';
38
39
  import { createActionLog } from './utils/tools.js';
39
40
  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,10 +269,6 @@ 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);
276
272
  // Add user message
277
273
  const userMessage = {
278
274
  role: 'user',
@@ -287,7 +283,6 @@ export const App = () => {
287
283
  dryRun,
288
284
  onIteration: (iteration, message) => {
289
285
  setAgentIteration(iteration);
290
- updateSpinner(`Step ${iteration}`, dryRun);
291
286
  },
292
287
  onToolCall: (tool) => {
293
288
  // Create action log with content for live code preview
@@ -330,8 +325,7 @@ export const App = () => {
330
325
  }
331
326
  return updated;
332
327
  });
333
- // Use console.log with chalk for agent actions - no Ink re-rendering!
334
- logAction(actionLog.type, actionLog.target, actionLog.result, actionLog.details);
328
+ // Actions are now displayed via AgentActions component with Static
335
329
  },
336
330
  onThinking: (text) => {
337
331
  // Strip <think> and <tool_call> tags from thinking text
@@ -357,11 +351,7 @@ export const App = () => {
357
351
  reads: result.actions.filter(a => a.type === 'read').length,
358
352
  errors: result.actions.filter(a => a.result === 'error').length,
359
353
  };
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)
354
+ // Add agent summary as assistant message
365
355
  const summaryMessage = {
366
356
  role: 'assistant',
367
357
  content: result.finalResponse || formatAgentResult(result),
@@ -381,13 +371,9 @@ export const App = () => {
381
371
  }
382
372
  catch (error) {
383
373
  const err = error;
384
- setAgentRunning(false);
385
- stopSpinner();
386
374
  notify(`Agent error: ${err.message}`);
387
375
  }
388
376
  finally {
389
- setAgentRunning(false);
390
- stopSpinner();
391
377
  setIsAgentRunning(false);
392
378
  setAbortController(null);
393
379
  setAgentThinking('');
@@ -1398,7 +1384,7 @@ export const App = () => {
1398
1384
  // Helper to check if we're showing an inline menu
1399
1385
  const isInlineMenu = ['help', 'status', 'settings', 'sessions', 'sessions-delete',
1400
1386
  'logout', 'search', 'export', 'model', 'provider', 'protocol', 'language'].includes(screen);
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) => {
1387
+ 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 }), isAgentRunning && (_jsx(AgentActions, { actions: agentActions, isRunning: isAgentRunning, currentStep: agentIteration, dryRun: agentDryRun })), 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) => {
1402
1388
  const actionColor = change.action === 'delete' ? 'red' : change.action === 'edit' ? 'yellow' : 'green';
1403
1389
  const actionLabel = change.action === 'delete' ? 'DELETE' : change.action === 'edit' ? 'EDIT' : 'CREATE';
1404
1390
  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));
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Agent Actions component using Static to prevent re-rendering/jumping
3
+ */
4
+ import React from 'react';
5
+ import { ActionLog } from '../utils/tools';
6
+ interface AgentActionsProps {
7
+ actions: ActionLog[];
8
+ isRunning: boolean;
9
+ currentStep: number;
10
+ dryRun?: boolean;
11
+ }
12
+ /**
13
+ * Agent Actions display using Static component
14
+ *
15
+ * Static renders items once and never re-renders them,
16
+ * preventing terminal jumping when new actions are added.
17
+ */
18
+ export declare const AgentActions: React.FC<AgentActionsProps>;
19
+ export {};
@@ -0,0 +1,121 @@
1
+ import { jsxs as _jsxs, jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
2
+ /**
3
+ * Agent Actions component using Static to prevent re-rendering/jumping
4
+ */
5
+ import { useState, useEffect, memo } from 'react';
6
+ import { Box, Text, Static } from 'ink';
7
+ // Spinner frames
8
+ const SPINNER_FRAMES = ['/', '-', '\\', '|'];
9
+ /**
10
+ * Isolated spinner - doesn't cause parent re-renders
11
+ */
12
+ const Spinner = memo(({ color = '#f02a30' }) => {
13
+ const [frame, setFrame] = useState(0);
14
+ useEffect(() => {
15
+ const timer = setInterval(() => {
16
+ setFrame(f => (f + 1) % SPINNER_FRAMES.length);
17
+ }, 100);
18
+ return () => clearInterval(timer);
19
+ }, []);
20
+ return _jsxs(Text, { color: color, children: ["[", SPINNER_FRAMES[frame], "]"] });
21
+ });
22
+ Spinner.displayName = 'Spinner';
23
+ /**
24
+ * Format action for display
25
+ */
26
+ function formatAction(action) {
27
+ const filename = action.target.split('/').pop() || action.target;
28
+ const lineCount = action.details ? action.details.split('\n').length : 0;
29
+ const lineInfo = lineCount > 0 ? ` (${lineCount} lines)` : '';
30
+ switch (action.type) {
31
+ case 'write':
32
+ return {
33
+ icon: action.result === 'success' ? '✓' : '✗',
34
+ color: action.result === 'success' ? 'green' : 'red',
35
+ text: `Created ${filename}${lineInfo}`,
36
+ };
37
+ case 'edit':
38
+ return {
39
+ icon: action.result === 'success' ? '✓' : '✗',
40
+ color: action.result === 'success' ? 'yellow' : 'red',
41
+ text: `Edited ${filename}${lineInfo}`,
42
+ };
43
+ case 'read':
44
+ return {
45
+ icon: '→',
46
+ color: 'blue',
47
+ text: `Reading ${filename}`,
48
+ };
49
+ case 'delete':
50
+ return {
51
+ icon: action.result === 'success' ? '✓' : '✗',
52
+ color: 'red',
53
+ text: `Deleted ${filename}`,
54
+ };
55
+ case 'command':
56
+ const cmd = action.target.length > 30 ? action.target.slice(0, 30) + '...' : action.target;
57
+ return {
58
+ icon: action.result === 'success' ? '✓' : '✗',
59
+ color: action.result === 'success' ? 'magenta' : 'red',
60
+ text: `Ran \`${cmd}\``,
61
+ };
62
+ case 'search':
63
+ return {
64
+ icon: '→',
65
+ color: 'cyan',
66
+ text: `Searching ${filename}`,
67
+ };
68
+ case 'mkdir':
69
+ return {
70
+ icon: action.result === 'success' ? '✓' : '✗',
71
+ color: 'blue',
72
+ text: `Created dir ${filename}`,
73
+ };
74
+ case 'fetch':
75
+ return {
76
+ icon: '→',
77
+ color: 'cyan',
78
+ text: `Fetching ${filename}`,
79
+ };
80
+ case 'list':
81
+ return {
82
+ icon: '→',
83
+ color: 'gray',
84
+ text: `Listing ${filename}`,
85
+ };
86
+ default:
87
+ return {
88
+ icon: '◦',
89
+ color: 'white',
90
+ text: `${action.type}: ${filename}`,
91
+ };
92
+ }
93
+ }
94
+ /**
95
+ * Single action line component
96
+ */
97
+ const ActionLine = memo(({ action }) => {
98
+ const { icon, color, text } = formatAction(action);
99
+ return (_jsxs(Text, { children: [_jsx(Text, { color: color, children: icon }), _jsxs(Text, { children: [" ", text] })] }));
100
+ });
101
+ ActionLine.displayName = 'ActionLine';
102
+ /**
103
+ * Agent Actions display using Static component
104
+ *
105
+ * Static renders items once and never re-renders them,
106
+ * preventing terminal jumping when new actions are added.
107
+ */
108
+ export const AgentActions = memo(({ actions, isRunning, currentStep, dryRun, }) => {
109
+ const color = dryRun ? 'yellow' : '#f02a30';
110
+ const label = dryRun ? 'DRY RUN' : 'AGENT';
111
+ // Get completed actions (all except potentially the last one if still pending)
112
+ const completedActions = actions.filter(a => a.result === 'success' || a.result === 'error');
113
+ // Current action (last one if result is pending or the running state)
114
+ const currentAction = actions.length > 0 ? actions[actions.length - 1] : null;
115
+ const isCurrentPending = currentAction && currentAction.result !== 'success' && currentAction.result !== 'error';
116
+ if (!isRunning && actions.length === 0) {
117
+ return null;
118
+ }
119
+ return (_jsxs(Box, { flexDirection: "column", marginY: 1, children: [_jsx(Static, { items: completedActions.map((a, i) => ({ ...a, id: `action-${i}-${a.timestamp}` })), children: (action) => (_jsx(ActionLine, { action: action }, action.id)) }), isRunning && (_jsxs(Box, { children: [_jsx(Spinner, { color: color }), _jsxs(Text, { color: color, bold: true, children: [" ", label, " "] }), _jsxs(Text, { color: "cyan", children: ["Step ", currentStep] }), currentAction && (_jsxs(_Fragment, { children: [_jsx(Text, { color: "gray", children: " | " }), _jsx(Text, { children: formatAction(currentAction).text })] }))] }))] }));
120
+ });
121
+ AgentActions.displayName = 'AgentActions';
@@ -686,8 +686,6 @@ export async function runAgent(prompt, projectContext, options = {}) {
686
686
  // Actually execute the tool
687
687
  toolResult = executeTool(toolCall, projectContext.root || process.cwd());
688
688
  }
689
- // Debug
690
- process.stderr.write(`[AGENT DEBUG] Tool executed: ${toolCall.tool}, calling onToolResult: ${!!opts.onToolResult}\n`);
691
689
  opts.onToolResult?.(toolResult, toolCall);
692
690
  // Log action
693
691
  const actionLog = createActionLog(toolCall, toolResult);
@@ -70,8 +70,6 @@ export function setAgentRunning(running, dryRun = false) {
70
70
  * Log agent action
71
71
  */
72
72
  export function logAction(type, target, result, details) {
73
- // Debug - use stderr to bypass Ink
74
- process.stderr.write(`[DEBUG] logAction called: ${type} ${target} ${result}\n`);
75
73
  stopSpinner(); // Stop spinner before logging
76
74
  const filename = target.split('/').pop() || target;
77
75
  const lineCount = details ? details.split('\n').length : 0;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codeep",
3
- "version": "1.1.6",
3
+ "version": "1.1.8",
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",