codeep 1.0.111 → 1.0.113

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
@@ -1,5 +1,5 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import React, { useState, useEffect, useCallback } from 'react';
2
+ import { useState, useEffect, useCallback } from 'react';
3
3
  import { Box, Text, useApp, useInput, useStdout } from 'ink';
4
4
  import clipboardy from 'clipboardy';
5
5
  import { logger } from './utils/logger.js';
@@ -163,16 +163,6 @@ export const App = () => {
163
163
  return () => clearTimeout(timer);
164
164
  }
165
165
  }, [notification, notificationDuration]);
166
- // Clear terminal when switching to fullscreen views (prevents ghost content from Static)
167
- const prevScreenRef = React.useRef(screen);
168
- useEffect(() => {
169
- const fullscreenViews = ['help', 'status', 'settings', 'sessions', 'search', 'export'];
170
- if (fullscreenViews.includes(screen) && prevScreenRef.current === 'chat') {
171
- // Clear screen when entering fullscreen view from chat
172
- stdout?.write('\x1b[2J\x1b[H');
173
- }
174
- prevScreenRef.current = screen;
175
- }, [screen, stdout]);
176
166
  // Handle keyboard shortcuts
177
167
  useInput((input, key) => {
178
168
  // Ctrl+L to clear chat (F5 doesn't work reliably in all terminals)
@@ -1400,7 +1390,7 @@ export const App = () => {
1400
1390
  // If we got here, we're in an unknown state - default to chat
1401
1391
  return null;
1402
1392
  }
1403
- 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, scrollOffset: 0, terminalHeight: stdout.rows || 24 }, sessionId), isLoading && !isAgentRunning && _jsx(Loading, { isStreaming: !!streamingContent }), isAgentRunning ? (_jsxs(Box, { flexDirection: "column", children: [_jsx(LiveCodeStream, { actions: agentActions, isRunning: true, terminalWidth: stdout?.columns || 80 }), _jsx(AgentProgress, { isRunning: true, iteration: agentIteration, maxIterations: 50, actions: agentActions, currentThinking: agentThinking, dryRun: agentDryRun })] }, "agent-running")) : agentResult ? (_jsx(Box, { flexDirection: "column", children: _jsx(AgentSummary, { success: agentResult.success, iterations: agentResult.iterations, actions: agentActions, error: agentResult.error, aborted: agentResult.aborted }) }, "agent-complete")) : null, 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) => {
1393
+ 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 ? (_jsxs(Box, { flexDirection: "column", children: [_jsx(LiveCodeStream, { actions: agentActions, isRunning: true, terminalWidth: stdout?.columns || 80 }), _jsx(AgentProgress, { isRunning: true, iteration: agentIteration, maxIterations: 50, actions: agentActions, currentThinking: agentThinking, dryRun: agentDryRun })] }, "agent-running")) : agentResult ? (_jsx(Box, { flexDirection: "column", children: _jsx(AgentSummary, { success: agentResult.success, iterations: agentResult.iterations, actions: agentActions, error: agentResult.error, aborted: agentResult.aborted }) }, "agent-complete")) : null, 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) => {
1404
1394
  const actionColor = change.action === 'delete' ? 'red' : change.action === 'edit' ? 'yellow' : 'green';
1405
1395
  const actionLabel = change.action === 'delete' ? 'DELETE' : change.action === 'edit' ? 'EDIT' : 'CREATE';
1406
1396
  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));
@@ -7,9 +7,16 @@ interface MessageListProps {
7
7
  terminalHeight?: number;
8
8
  }
9
9
  /**
10
- * Message list with optimized rendering
11
- * Uses Static component for stable scroll position
12
- * Uses content-based keys instead of index for better React reconciliation
10
+ * Message list WITHOUT Static component
11
+ *
12
+ * We removed the Static component because:
13
+ * - Static preserves content in terminal scroll history even after unmount
14
+ * - This causes ghost/duplicate content when switching screens
15
+ * - The trade-off is that messages will re-render on each update
16
+ * - We mitigate this with memoization at the individual message level
17
+ *
18
+ * NOTE: This is a temporary solution until we implement a custom renderer
19
+ * like Claude CLI uses (DEC Mode 2026 / synchronized output).
13
20
  */
14
21
  export declare const MessageList: React.FC<MessageListProps>;
15
22
  export {};
@@ -1,25 +1,29 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { memo } from 'react';
3
- import { Box, Static } from 'ink';
2
+ import { memo, useMemo } from 'react';
3
+ import { Box } from 'ink';
4
4
  import { MessageView } from './Message.js';
5
5
  import { StreamingMessage } from './StreamingMessage.js';
6
6
  /**
7
- * Generate unique key for message based on content and position
8
- * More stable than index-based keys
7
+ * Memoized individual message component
8
+ * Only re-renders when its specific content changes
9
9
  */
10
- const getMessageKey = (msg, index) => {
11
- // Use hash of first 50 chars + role + index for uniqueness
12
- const contentHash = msg.content.slice(0, 50).split('').reduce((acc, char) => {
13
- return ((acc << 5) - acc) + char.charCodeAt(0);
14
- }, 0);
15
- return `${msg.role}-${index}-${Math.abs(contentHash)}`;
16
- };
10
+ const MemoizedMessage = memo(({ msg }) => _jsx(MessageView, { role: msg.role, content: msg.content }), (prev, next) => prev.msg.content === next.msg.content && prev.msg.role === next.msg.role);
11
+ MemoizedMessage.displayName = 'MemoizedMessage';
17
12
  /**
18
- * Message list with optimized rendering
19
- * Uses Static component for stable scroll position
20
- * Uses content-based keys instead of index for better React reconciliation
13
+ * Message list WITHOUT Static component
14
+ *
15
+ * We removed the Static component because:
16
+ * - Static preserves content in terminal scroll history even after unmount
17
+ * - This causes ghost/duplicate content when switching screens
18
+ * - The trade-off is that messages will re-render on each update
19
+ * - We mitigate this with memoization at the individual message level
20
+ *
21
+ * NOTE: This is a temporary solution until we implement a custom renderer
22
+ * like Claude CLI uses (DEC Mode 2026 / synchronized output).
21
23
  */
22
24
  export const MessageList = memo(({ messages, streamingContent, }) => {
23
- return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Static, { items: messages, children: (msg, index) => (_jsx(MessageView, { role: msg.role, content: msg.content }, getMessageKey(msg, index))) }), streamingContent && (_jsx(StreamingMessage, { content: streamingContent }))] }));
25
+ // Memoize the messages array rendering
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 }))] }));
24
28
  });
25
29
  MessageList.displayName = 'MessageList';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codeep",
3
- "version": "1.0.111",
3
+ "version": "1.0.113",
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",