codeep 1.0.51 → 1.0.53

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,7 +35,7 @@ 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 { AgentProgress, AgentSummary } from './components/AgentProgress.js';
38
+ import { AgentProgress, AgentSummary, LiveCodeStream } from './components/AgentProgress.js';
39
39
  import { createActionLog } from './utils/tools.js';
40
40
  export const App = () => {
41
41
  const { exit } = useApp();
@@ -1330,7 +1330,7 @@ export const App = () => {
1330
1330
  return (_jsx(LanguageSelect, { onClose: () => setScreen('chat'), notify: notify }));
1331
1331
  }
1332
1332
  // Main chat screen
1333
- return (_jsxs(Box, { flexDirection: "column", children: [messages.length === 0 && !isLoading && _jsx(Logo, {}), messages.length === 0 && !isLoading && (_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(MessageList, { messages: messages, streamingContent: streamingContent, scrollOffset: 0, terminalHeight: stdout.rows || 24 }, sessionId), isLoading && !isAgentRunning && _jsx(Loading, { isStreaming: !!streamingContent }), isAgentRunning && (_jsx(AgentProgress, { isRunning: true, iteration: agentIteration, maxIterations: 50, actions: agentActions, currentThinking: agentThinking, dryRun: agentDryRun })), !isAgentRunning && agentResult && (_jsx(AgentSummary, { success: agentResult.success, iterations: agentResult.iterations, actions: agentActions, error: agentResult.error, aborted: agentResult.aborted })), 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) => {
1333
+ return (_jsxs(Box, { flexDirection: "column", children: [messages.length === 0 && !isLoading && _jsx(Logo, {}), messages.length === 0 && !isLoading && (_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(MessageList, { messages: messages, streamingContent: streamingContent, scrollOffset: 0, terminalHeight: stdout.rows || 24 }, sessionId), isLoading && !isAgentRunning && _jsx(Loading, { isStreaming: !!streamingContent }), isAgentRunning && (_jsx(LiveCodeStream, { actions: agentActions, isRunning: true })), isAgentRunning && (_jsx(AgentProgress, { isRunning: true, iteration: agentIteration, maxIterations: 50, actions: agentActions, currentThinking: agentThinking, dryRun: agentDryRun })), !isAgentRunning && agentResult && (_jsx(AgentSummary, { success: agentResult.success, iterations: agentResult.iterations, actions: agentActions, error: agentResult.error, aborted: agentResult.aborted })), 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) => {
1334
1334
  const actionColor = change.action === 'delete' ? 'red' : change.action === 'edit' ? 'yellow' : 'green';
1335
1335
  const actionLabel = change.action === 'delete' ? 'DELETE' : change.action === 'edit' ? 'EDIT' : 'CREATE';
1336
1336
  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));
@@ -12,6 +12,16 @@ interface AgentProgressProps {
12
12
  dryRun?: boolean;
13
13
  }
14
14
  export declare const AgentProgress: React.FC<AgentProgressProps>;
15
+ /**
16
+ * Live Code Stream component - shows ALL code being written/edited by agent
17
+ * Displayed ABOVE the AgentProgress component
18
+ * Enhanced with better syntax highlighting and visual organization
19
+ */
20
+ interface LiveCodeStreamProps {
21
+ actions: ActionLog[];
22
+ isRunning: boolean;
23
+ }
24
+ export declare const LiveCodeStream: React.FC<LiveCodeStreamProps>;
15
25
  /**
16
26
  * Agent summary component - shown when agent completes
17
27
  */
@@ -40,29 +40,140 @@ export const AgentProgress = ({ isRunning, iteration, maxIterations, actions, cu
40
40
  deleted: actions.filter(a => a.type === 'delete' && a.result === 'success').length,
41
41
  };
42
42
  const totalFileChanges = fileChanges.created + fileChanges.modified + fileChanges.deleted;
43
- return (_jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: dryRun ? 'yellow' : '#f02a30', padding: 1, marginY: 1, children: [_jsx(Box, { children: isRunning ? (_jsxs(_Fragment, { children: [_jsxs(Text, { color: dryRun ? 'yellow' : '#f02a30', children: ["[", SPINNER_FRAMES[spinnerFrame], "]"] }), _jsxs(Text, { color: dryRun ? 'yellow' : '#f02a30', bold: true, children: [' ', dryRun ? 'DRY RUN' : 'AGENT', ' '] }), _jsx(Text, { color: "gray", children: "|" }), _jsxs(Text, { color: "cyan", children: [" step ", iteration] }), _jsx(Text, { color: "gray", children: " | " }), actionCounts.reads > 0 && _jsxs(Text, { color: "blue", children: [actionCounts.reads, "R "] }), actionCounts.writes > 0 && _jsxs(Text, { color: "green", children: [actionCounts.writes, "W "] }), actionCounts.edits > 0 && _jsxs(Text, { color: "yellow", children: [actionCounts.edits, "E "] }), actionCounts.commands > 0 && _jsxs(Text, { color: "magenta", children: [actionCounts.commands, "C "] }), actionCounts.searches > 0 && _jsxs(Text, { color: "cyan", children: [actionCounts.searches, "S "] }), actions.length === 0 && _jsx(Text, { color: "gray", children: "0 actions" })] })) : (_jsxs(_Fragment, { children: [_jsx(Text, { color: "green", bold: true, children: "[DONE] " }), _jsx(Text, { children: "Agent completed" }), _jsx(Text, { color: "gray", children: " | " }), _jsxs(Text, { color: "white", children: [actions.length, " actions"] })] })) }), isRunning && currentAction && (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsxs(Box, { children: [_jsx(Text, { color: "white", bold: true, children: "Now: " }), _jsxs(Text, { color: getActionColor(currentAction.type), children: [getActionLabel(currentAction.type), " "] }), _jsx(Text, { color: "white", children: formatTarget(currentAction.target) })] }), (currentAction.type === 'write' || currentAction.type === 'edit') && currentAction.details && (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsxs(Box, { children: [_jsx(Text, { color: "cyan", bold: true, children: "\uD83D\uDCDD Live Code:" }), _jsxs(Text, { color: "gray", children: [" ", currentAction.target.split('/').pop()] }), _jsxs(Text, { color: "gray", dimColor: true, children: [" (", currentAction.details.split('\n').length, " lines)"] })] }), _jsx(Box, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1, marginTop: 0, children: currentAction.details.split('\n').map((line, i) => (_jsxs(Text, { children: [_jsxs(Text, { color: "gray", dimColor: true, children: [String(i + 1).padStart(3, ' '), " \u2502 "] }), _jsx(Text, { color: getCodeColor(line), children: line })] }, i))) })] }))] })), _jsx(Text, { color: "gray", children: '─'.repeat(50) }), recentActions.length > 1 && (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { color: "gray", dimColor: true, children: "Recent:" }), recentActions.slice(0, -1).map((action, i) => (_jsx(ActionItem, { action: action }, i)))] })), isRunning && totalFileChanges > 0 && (_jsxs(Box, { marginTop: 1, children: [_jsx(Text, { color: "gray", children: "Changes: " }), fileChanges.created > 0 && _jsxs(Text, { color: "green", children: ["+", fileChanges.created, " "] }), fileChanges.modified > 0 && _jsxs(Text, { color: "yellow", children: ["~", fileChanges.modified, " "] }), fileChanges.deleted > 0 && _jsxs(Text, { color: "red", children: ["-", fileChanges.deleted] })] })), isRunning && currentThinking && (_jsx(Box, { marginTop: 1, children: _jsxs(Text, { color: "gray", wrap: "truncate-end", children: ["> ", currentThinking.slice(0, 80), currentThinking.length > 80 ? '...' : ''] }) })), isRunning && (_jsxs(Box, { marginTop: 1, children: [_jsx(Text, { color: "gray", children: "Press " }), _jsx(Text, { color: "#f02a30", children: "Esc" }), _jsx(Text, { color: "gray", children: " to stop" })] })), !isRunning && totalFileChanges > 0 && (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsx(Text, { bold: true, children: "File Changes:" }), fileChanges.created > 0 && (_jsxs(Text, { color: "green", children: [" + ", fileChanges.created, " file(s) created"] })), fileChanges.modified > 0 && (_jsxs(Text, { color: "yellow", children: [" ~ ", fileChanges.modified, " file(s) modified"] })), fileChanges.deleted > 0 && (_jsxs(Text, { color: "red", children: [" - ", fileChanges.deleted, " file(s) deleted"] }))] }))] }));
43
+ return (_jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: dryRun ? 'yellow' : '#f02a30', padding: 1, marginY: 1, children: [_jsx(Box, { children: isRunning ? (_jsxs(_Fragment, { children: [_jsxs(Text, { color: dryRun ? 'yellow' : '#f02a30', children: ["[", SPINNER_FRAMES[spinnerFrame], "]"] }), _jsxs(Text, { color: dryRun ? 'yellow' : '#f02a30', bold: true, children: [' ', dryRun ? 'DRY RUN' : 'AGENT', ' '] }), _jsx(Text, { color: "gray", children: "|" }), _jsxs(Text, { color: "cyan", children: [" step ", iteration] }), _jsx(Text, { color: "gray", children: " | " }), actionCounts.reads > 0 && _jsxs(Text, { color: "blue", children: [actionCounts.reads, "R "] }), actionCounts.writes > 0 && _jsxs(Text, { color: "green", children: [actionCounts.writes, "W "] }), actionCounts.edits > 0 && _jsxs(Text, { color: "yellow", children: [actionCounts.edits, "E "] }), actionCounts.commands > 0 && _jsxs(Text, { color: "magenta", children: [actionCounts.commands, "C "] }), actionCounts.searches > 0 && _jsxs(Text, { color: "cyan", children: [actionCounts.searches, "S "] }), actions.length === 0 && _jsx(Text, { color: "gray", children: "0 actions" })] })) : (_jsxs(_Fragment, { children: [_jsx(Text, { color: "green", bold: true, children: "[DONE] " }), _jsx(Text, { children: "Agent completed" }), _jsx(Text, { color: "gray", children: " | " }), _jsxs(Text, { color: "white", children: [actions.length, " actions"] })] })) }), isRunning && currentAction && (_jsxs(Box, { marginTop: 1, children: [_jsx(Text, { color: "white", bold: true, children: "Now: " }), _jsxs(Text, { color: getActionColor(currentAction.type), children: [getActionLabel(currentAction.type), " "] }), _jsx(Text, { color: "white", children: formatTarget(currentAction.target) })] })), _jsx(Text, { color: "gray", children: '─'.repeat(50) }), recentActions.length > 1 && (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { color: "gray", dimColor: true, children: "Recent:" }), recentActions.slice(0, -1).map((action, i) => (_jsx(ActionItem, { action: action }, i)))] })), isRunning && totalFileChanges > 0 && (_jsxs(Box, { marginTop: 1, children: [_jsx(Text, { color: "gray", children: "Changes: " }), fileChanges.created > 0 && _jsxs(Text, { color: "green", children: ["+", fileChanges.created, " "] }), fileChanges.modified > 0 && _jsxs(Text, { color: "yellow", children: ["~", fileChanges.modified, " "] }), fileChanges.deleted > 0 && _jsxs(Text, { color: "red", children: ["-", fileChanges.deleted] })] })), isRunning && currentThinking && (_jsx(Box, { marginTop: 1, children: _jsxs(Text, { color: "gray", wrap: "truncate-end", children: ["> ", currentThinking.slice(0, 80), currentThinking.length > 80 ? '...' : ''] }) })), isRunning && (_jsxs(Box, { marginTop: 1, children: [_jsx(Text, { color: "gray", children: "Press " }), _jsx(Text, { color: "#f02a30", children: "Esc" }), _jsx(Text, { color: "gray", children: " to stop" })] })), !isRunning && totalFileChanges > 0 && (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsx(Text, { bold: true, children: "File Changes:" }), fileChanges.created > 0 && (_jsxs(Text, { color: "green", children: [" + ", fileChanges.created, " file(s) created"] })), fileChanges.modified > 0 && (_jsxs(Text, { color: "yellow", children: [" ~ ", fileChanges.modified, " file(s) modified"] })), fileChanges.deleted > 0 && (_jsxs(Text, { color: "red", children: [" - ", fileChanges.deleted, " file(s) deleted"] }))] }))] }));
44
44
  };
45
- // Helper function for syntax highlighting
46
- const getCodeColor = (line) => {
45
+ // Get file extension for language detection
46
+ const getFileExtension = (filename) => {
47
+ const parts = filename.split('.');
48
+ return parts.length > 1 ? parts[parts.length - 1].toLowerCase() : '';
49
+ };
50
+ // Get language label from extension
51
+ const getLanguageLabel = (ext) => {
52
+ const langMap = {
53
+ 'js': 'JavaScript',
54
+ 'jsx': 'React JSX',
55
+ 'ts': 'TypeScript',
56
+ 'tsx': 'React TSX',
57
+ 'html': 'HTML',
58
+ 'css': 'CSS',
59
+ 'scss': 'SCSS',
60
+ 'json': 'JSON',
61
+ 'md': 'Markdown',
62
+ 'py': 'Python',
63
+ 'rb': 'Ruby',
64
+ 'go': 'Go',
65
+ 'rs': 'Rust',
66
+ 'java': 'Java',
67
+ 'kt': 'Kotlin',
68
+ 'swift': 'Swift',
69
+ 'php': 'PHP',
70
+ 'sql': 'SQL',
71
+ 'sh': 'Shell',
72
+ 'bash': 'Bash',
73
+ 'yml': 'YAML',
74
+ 'yaml': 'YAML',
75
+ 'xml': 'XML',
76
+ 'vue': 'Vue',
77
+ 'svelte': 'Svelte',
78
+ };
79
+ return langMap[ext] || ext.toUpperCase();
80
+ };
81
+ // Enhanced syntax highlighting with more colors
82
+ const getCodeColor = (line, ext) => {
47
83
  const trimmed = line.trim();
48
- // Comments
49
- if (trimmed.startsWith('//') || trimmed.startsWith('#') || trimmed.startsWith('/*') || trimmed.startsWith('*')) {
84
+ // Empty lines
85
+ if (!trimmed)
86
+ return 'gray';
87
+ // Comments - multiple styles
88
+ if (trimmed.startsWith('//') || trimmed.startsWith('#') || trimmed.startsWith('/*') ||
89
+ trimmed.startsWith('*') || trimmed.startsWith('<!--') || trimmed.startsWith('"""') ||
90
+ trimmed.startsWith("'''")) {
50
91
  return 'gray';
51
92
  }
52
- // Keywords
53
- if (/^(import|export|const|let|var|function|class|interface|type|return|if|else|for|while|async|await)\b/.test(trimmed)) {
93
+ // Import/export statements
94
+ if (/^(import|export|from|require)\b/.test(trimmed)) {
54
95
  return 'magenta';
55
96
  }
56
- // HTML tags
57
- if (trimmed.startsWith('<') && (trimmed.includes('>') || trimmed.includes('/>'))) {
97
+ // Function/class definitions
98
+ if (/^(function|class|interface|type|enum|const\s+\w+\s*=\s*(\(|async)|def |class |fn |func |pub fn)\b/.test(trimmed)) {
99
+ return 'yellow';
100
+ }
101
+ // Control flow keywords
102
+ if (/^(if|else|for|while|switch|case|try|catch|finally|return|throw|break|continue|async|await)\b/.test(trimmed)) {
103
+ return 'blue';
104
+ }
105
+ // Variable declarations
106
+ if (/^(const|let|var|val|mut)\b/.test(trimmed)) {
107
+ return 'cyan';
108
+ }
109
+ // HTML/JSX tags
110
+ if ((ext === 'html' || ext === 'jsx' || ext === 'tsx' || ext === 'vue' || ext === 'svelte') &&
111
+ (trimmed.startsWith('<') || trimmed.startsWith('</'))) {
112
+ return 'cyan';
113
+ }
114
+ // CSS selectors and properties
115
+ if ((ext === 'css' || ext === 'scss') && (trimmed.includes('{') || trimmed.includes(':'))) {
116
+ return 'green';
117
+ }
118
+ // JSON keys
119
+ if (ext === 'json' && trimmed.includes(':')) {
58
120
  return 'cyan';
59
121
  }
60
- // Strings
61
- if (trimmed.includes('"') || trimmed.includes("'") || trimmed.includes('`')) {
122
+ // Strings (but not the whole line)
123
+ if (/["'`]/.test(trimmed)) {
62
124
  return 'green';
63
125
  }
64
126
  return 'white';
65
127
  };
128
+ // Check if line is a section separator (empty or comment-only)
129
+ const isSectionBreak = (line, prevLine) => {
130
+ const trimmed = line.trim();
131
+ const prevTrimmed = prevLine?.trim() || '';
132
+ // Empty line after non-empty line
133
+ if (!trimmed && prevTrimmed)
134
+ return true;
135
+ // Comment after code
136
+ if ((trimmed.startsWith('//') || trimmed.startsWith('#') || trimmed.startsWith('/*')) &&
137
+ prevTrimmed && !prevTrimmed.startsWith('//') && !prevTrimmed.startsWith('#')) {
138
+ return true;
139
+ }
140
+ return false;
141
+ };
142
+ export const LiveCodeStream = ({ actions, isRunning }) => {
143
+ // Find the current write/edit action with code content
144
+ const currentAction = actions.length > 0 ? actions[actions.length - 1] : null;
145
+ // Only show for write/edit actions with content
146
+ if (!isRunning || !currentAction)
147
+ return null;
148
+ if (currentAction.type !== 'write' && currentAction.type !== 'edit')
149
+ return null;
150
+ if (!currentAction.details)
151
+ return null;
152
+ const code = currentAction.details;
153
+ const fullPath = currentAction.target;
154
+ const filename = fullPath.split('/').pop() || fullPath;
155
+ const ext = getFileExtension(filename);
156
+ const langLabel = getLanguageLabel(ext);
157
+ const allLines = code.split('\n');
158
+ const totalLines = allLines.length;
159
+ const actionLabel = currentAction.type === 'write' ? '✨ Creating' : '✏️ Editing';
160
+ const actionColor = currentAction.type === 'write' ? 'green' : 'yellow';
161
+ // Calculate code stats
162
+ const nonEmptyLines = allLines.filter(l => l.trim()).length;
163
+ const commentLines = allLines.filter(l => {
164
+ const t = l.trim();
165
+ return t.startsWith('//') || t.startsWith('#') || t.startsWith('/*') || t.startsWith('*');
166
+ }).length;
167
+ return (_jsxs(Box, { flexDirection: "column", marginY: 1, children: [_jsxs(Box, { flexDirection: "row", justifyContent: "space-between", children: [_jsxs(Box, { children: [_jsxs(Text, { color: actionColor, bold: true, children: [actionLabel, " "] }), _jsx(Text, { color: "white", bold: true, children: filename })] }), _jsxs(Box, { children: [_jsxs(Text, { color: "gray", children: [langLabel, " \u2022 "] }), _jsx(Text, { color: "cyan", children: totalLines }), _jsx(Text, { color: "gray", children: " lines" }), commentLines > 0 && (_jsxs(_Fragment, { children: [_jsx(Text, { color: "gray", children: " \u2022 " }), _jsxs(Text, { color: "gray", dimColor: true, children: [commentLines, " comments"] })] }))] })] }), fullPath !== filename && (_jsxs(Text, { color: "gray", dimColor: true, children: [" \uD83D\uDCC1 ", fullPath] })), _jsx(Text, { color: actionColor, children: '┌' + '─'.repeat(78) + '┐' }), _jsx(Box, { flexDirection: "column", children: allLines.map((line, i) => {
168
+ const lineNum = i + 1;
169
+ const prevLine = i > 0 ? allLines[i - 1] : null;
170
+ const showSeparator = isSectionBreak(line, prevLine);
171
+ const lineColor = getCodeColor(line, ext);
172
+ // Zebra striping for better readability (subtle)
173
+ const isEvenLine = i % 2 === 0;
174
+ return (_jsxs(Box, { flexDirection: "column", children: [showSeparator && i > 0 && (_jsx(Text, { color: "gray", dimColor: true, children: '│' + ' '.repeat(78) + '│' })), _jsxs(Text, { children: [_jsx(Text, { color: actionColor, children: "\u2502" }), _jsx(Text, { color: isEvenLine ? 'gray' : 'white', dimColor: !isEvenLine, children: String(lineNum).padStart(4, ' ') }), _jsx(Text, { color: "gray", dimColor: true, children: " \u2502 " }), _jsx(Text, { color: lineColor, children: line.slice(0, 70) }), line.length > 70 && _jsx(Text, { color: "gray", children: "\u2026" }), line.length <= 70 && _jsx(Text, { children: ' '.repeat(Math.max(0, 70 - line.length)) }), _jsx(Text, { color: actionColor, children: "\u2502" })] })] }, i));
175
+ }) }), _jsx(Text, { color: actionColor, children: '└' + '─'.repeat(78) + '┘' })] }));
176
+ };
66
177
  // Helper functions for action display
67
178
  const getActionColor = (type) => {
68
179
  switch (type) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codeep",
3
- "version": "1.0.51",
3
+ "version": "1.0.53",
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",