codeep 1.1.36 → 1.2.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/README.md +90 -4
- package/dist/api/index.js +64 -2
- package/dist/renderer/App.d.ts +5 -0
- package/dist/renderer/App.js +164 -227
- package/dist/renderer/components/Export.d.ts +22 -0
- package/dist/renderer/components/Export.js +64 -0
- package/dist/renderer/components/Help.js +5 -1
- package/dist/renderer/components/Logout.d.ts +29 -0
- package/dist/renderer/components/Logout.js +91 -0
- package/dist/renderer/components/Search.d.ts +30 -0
- package/dist/renderer/components/Search.js +83 -0
- package/dist/renderer/components/Settings.js +20 -0
- package/dist/renderer/components/Status.d.ts +6 -0
- package/dist/renderer/components/Status.js +20 -1
- package/dist/renderer/main.js +296 -142
- package/dist/utils/agent.d.ts +5 -0
- package/dist/utils/agent.js +238 -3
- package/dist/utils/agent.test.d.ts +1 -0
- package/dist/utils/agent.test.js +250 -0
- package/dist/utils/diffPreview.js +104 -35
- package/dist/utils/gitignore.d.ts +24 -0
- package/dist/utils/gitignore.js +161 -0
- package/dist/utils/gitignore.test.d.ts +1 -0
- package/dist/utils/gitignore.test.js +167 -0
- package/dist/utils/skills.d.ts +21 -0
- package/dist/utils/skills.js +51 -0
- package/dist/utils/smartContext.js +8 -0
- package/dist/utils/smartContext.test.d.ts +1 -0
- package/dist/utils/smartContext.test.js +382 -0
- package/dist/utils/tokenTracker.d.ts +52 -0
- package/dist/utils/tokenTracker.js +86 -0
- package/dist/utils/tools.d.ts +16 -0
- package/dist/utils/tools.js +146 -19
- package/dist/utils/tools.test.d.ts +1 -0
- package/dist/utils/tools.test.js +664 -0
- package/package.json +1 -1
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Logout panel component
|
|
3
|
+
*/
|
|
4
|
+
import { fg, style } from '../ansi.js';
|
|
5
|
+
// Primary color: #f02a30 (Codeep red)
|
|
6
|
+
const PRIMARY_COLOR = fg.rgb(240, 42, 48);
|
|
7
|
+
/**
|
|
8
|
+
* Render inline logout picker
|
|
9
|
+
*/
|
|
10
|
+
export function renderLogoutPanel(screen, startY, width, state) {
|
|
11
|
+
let y = startY;
|
|
12
|
+
// Separator line
|
|
13
|
+
screen.horizontalLine(y++, '─', fg.cyan);
|
|
14
|
+
// Title
|
|
15
|
+
screen.writeLine(y++, 'Select provider to logout:', fg.cyan + style.bold);
|
|
16
|
+
y++;
|
|
17
|
+
if (state.logoutProviders.length === 0) {
|
|
18
|
+
screen.writeLine(y++, 'No providers configured.', fg.yellow);
|
|
19
|
+
screen.writeLine(y++, 'Press Escape to go back.', fg.gray);
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
// Provider options
|
|
23
|
+
for (let i = 0; i < state.logoutProviders.length; i++) {
|
|
24
|
+
const provider = state.logoutProviders[i];
|
|
25
|
+
const isSelected = i === state.logoutIndex;
|
|
26
|
+
const prefix = isSelected ? '→ ' : ' ';
|
|
27
|
+
screen.write(0, y, prefix, isSelected ? fg.green : '');
|
|
28
|
+
screen.write(2, y, provider.name, isSelected ? fg.green + style.bold : fg.white);
|
|
29
|
+
if (provider.isCurrent) {
|
|
30
|
+
screen.write(2 + provider.name.length + 1, y, '(current)', fg.cyan);
|
|
31
|
+
}
|
|
32
|
+
y++;
|
|
33
|
+
}
|
|
34
|
+
// "All" option
|
|
35
|
+
const allIndex = state.logoutProviders.length;
|
|
36
|
+
const isAllSelected = state.logoutIndex === allIndex;
|
|
37
|
+
screen.write(0, y, isAllSelected ? '→ ' : ' ', isAllSelected ? fg.red : '');
|
|
38
|
+
screen.write(2, y, 'Logout from all providers', isAllSelected ? fg.red + style.bold : fg.yellow);
|
|
39
|
+
y++;
|
|
40
|
+
// "Cancel" option
|
|
41
|
+
const cancelIndex = state.logoutProviders.length + 1;
|
|
42
|
+
const isCancelSelected = state.logoutIndex === cancelIndex;
|
|
43
|
+
screen.write(0, y, isCancelSelected ? '→ ' : ' ', isCancelSelected ? fg.blue : '');
|
|
44
|
+
screen.write(2, y, 'Cancel', isCancelSelected ? fg.blue + style.bold : fg.gray);
|
|
45
|
+
y++;
|
|
46
|
+
y++;
|
|
47
|
+
screen.writeLine(y, '↑↓ Navigate • Enter Select • Esc Cancel', fg.gray);
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Handle logout picker keys
|
|
51
|
+
*/
|
|
52
|
+
export function handleLogoutKey(event, state, callbacks) {
|
|
53
|
+
// Options: providers + "all" + "cancel"
|
|
54
|
+
const totalOptions = state.logoutProviders.length + 2;
|
|
55
|
+
if (event.key === 'escape') {
|
|
56
|
+
state.logoutOpen = false;
|
|
57
|
+
state.logoutCallback = null;
|
|
58
|
+
callbacks.onRender();
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
if (event.key === 'up') {
|
|
62
|
+
state.logoutIndex = Math.max(0, state.logoutIndex - 1);
|
|
63
|
+
callbacks.onRender();
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
if (event.key === 'down') {
|
|
67
|
+
state.logoutIndex = Math.min(totalOptions - 1, state.logoutIndex + 1);
|
|
68
|
+
callbacks.onRender();
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
if (event.key === 'enter') {
|
|
72
|
+
const callback = state.logoutCallback;
|
|
73
|
+
state.logoutOpen = false;
|
|
74
|
+
state.logoutCallback = null;
|
|
75
|
+
let result = null;
|
|
76
|
+
if (state.logoutIndex < state.logoutProviders.length) {
|
|
77
|
+
result = state.logoutProviders[state.logoutIndex].id;
|
|
78
|
+
}
|
|
79
|
+
else if (state.logoutIndex === state.logoutProviders.length) {
|
|
80
|
+
result = 'all';
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
result = null; // Cancel
|
|
84
|
+
}
|
|
85
|
+
callbacks.onRender();
|
|
86
|
+
if (callback) {
|
|
87
|
+
callback(result);
|
|
88
|
+
}
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Search panel component
|
|
3
|
+
*/
|
|
4
|
+
import { Screen } from '../Screen';
|
|
5
|
+
import { KeyEvent } from '../Input';
|
|
6
|
+
export interface SearchResult {
|
|
7
|
+
role: string;
|
|
8
|
+
messageIndex: number;
|
|
9
|
+
matchedText: string;
|
|
10
|
+
}
|
|
11
|
+
export interface SearchState {
|
|
12
|
+
searchOpen: boolean;
|
|
13
|
+
searchQuery: string;
|
|
14
|
+
searchResults: SearchResult[];
|
|
15
|
+
searchIndex: number;
|
|
16
|
+
searchCallback: ((messageIndex: number) => void) | null;
|
|
17
|
+
}
|
|
18
|
+
export interface SearchCallbacks {
|
|
19
|
+
onClose: () => void;
|
|
20
|
+
onRender: () => void;
|
|
21
|
+
onResult: (messageIndex: number) => void;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Render inline search panel
|
|
25
|
+
*/
|
|
26
|
+
export declare function renderSearchPanel(screen: Screen, startY: number, width: number, availableHeight: number, state: SearchState): void;
|
|
27
|
+
/**
|
|
28
|
+
* Handle search key events
|
|
29
|
+
*/
|
|
30
|
+
export declare function handleSearchKey(event: KeyEvent, state: SearchState, callbacks: SearchCallbacks): void;
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Search panel component
|
|
3
|
+
*/
|
|
4
|
+
import { fg, style } from '../ansi.js';
|
|
5
|
+
// Primary color: #f02a30 (Codeep red)
|
|
6
|
+
const PRIMARY_COLOR = fg.rgb(240, 42, 48);
|
|
7
|
+
/**
|
|
8
|
+
* Render inline search panel
|
|
9
|
+
*/
|
|
10
|
+
export function renderSearchPanel(screen, startY, width, availableHeight, state) {
|
|
11
|
+
let y = startY;
|
|
12
|
+
// Separator line
|
|
13
|
+
screen.horizontalLine(y++, '\u2500', PRIMARY_COLOR);
|
|
14
|
+
// Title
|
|
15
|
+
screen.writeLine(y++, 'Search Results', PRIMARY_COLOR + style.bold);
|
|
16
|
+
// Query
|
|
17
|
+
screen.write(0, y, 'Query: ', fg.white);
|
|
18
|
+
screen.write(7, y, `"${state.searchQuery}"`, fg.cyan);
|
|
19
|
+
if (state.searchResults.length > 0) {
|
|
20
|
+
screen.write(9 + state.searchQuery.length, y, ` (${state.searchResults.length} ${state.searchResults.length === 1 ? 'result' : 'results'})`, fg.gray);
|
|
21
|
+
}
|
|
22
|
+
y++;
|
|
23
|
+
y++;
|
|
24
|
+
if (state.searchResults.length === 0) {
|
|
25
|
+
screen.writeLine(y++, 'No results found.', fg.yellow);
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
const maxVisible = availableHeight - 6;
|
|
29
|
+
const visibleStart = Math.max(0, state.searchIndex - Math.floor(maxVisible / 2));
|
|
30
|
+
const visibleResults = state.searchResults.slice(visibleStart, visibleStart + maxVisible);
|
|
31
|
+
for (let i = 0; i < visibleResults.length; i++) {
|
|
32
|
+
const result = visibleResults[i];
|
|
33
|
+
const actualIndex = visibleStart + i;
|
|
34
|
+
const isSelected = actualIndex === state.searchIndex;
|
|
35
|
+
const prefix = isSelected ? '\u25B8 ' : ' ';
|
|
36
|
+
const roleColor = result.role === 'user' ? fg.green : fg.blue;
|
|
37
|
+
// First line: role and message number
|
|
38
|
+
screen.write(0, y, prefix, isSelected ? PRIMARY_COLOR : '');
|
|
39
|
+
screen.write(2, y, `[${result.role.toUpperCase()}]`, roleColor + style.bold);
|
|
40
|
+
screen.write(2 + result.role.length + 2, y, ` Message #${result.messageIndex + 1}`, fg.gray);
|
|
41
|
+
y++;
|
|
42
|
+
// Second line: matched text (truncated)
|
|
43
|
+
const maxTextWidth = width - 4;
|
|
44
|
+
const matchedText = result.matchedText.length > maxTextWidth
|
|
45
|
+
? result.matchedText.slice(0, maxTextWidth - 3) + '...'
|
|
46
|
+
: result.matchedText;
|
|
47
|
+
screen.writeLine(y, ' ' + matchedText, fg.white);
|
|
48
|
+
y++;
|
|
49
|
+
if (i < visibleResults.length - 1)
|
|
50
|
+
y++; // spacing between results
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
// Footer
|
|
54
|
+
y = startY + availableHeight - 1;
|
|
55
|
+
screen.writeLine(y, '\u2191\u2193 Navigate \u2022 Enter Jump to message \u2022 Esc Close', fg.gray);
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Handle search key events
|
|
59
|
+
*/
|
|
60
|
+
export function handleSearchKey(event, state, callbacks) {
|
|
61
|
+
if (event.key === 'escape') {
|
|
62
|
+
callbacks.onClose();
|
|
63
|
+
callbacks.onRender();
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
if (event.key === 'up') {
|
|
67
|
+
state.searchIndex = Math.max(0, state.searchIndex - 1);
|
|
68
|
+
callbacks.onRender();
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
if (event.key === 'down') {
|
|
72
|
+
state.searchIndex = Math.min(state.searchResults.length - 1, state.searchIndex + 1);
|
|
73
|
+
callbacks.onRender();
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
if (event.key === 'enter' && state.searchResults.length > 0) {
|
|
77
|
+
const selectedResult = state.searchResults[state.searchIndex];
|
|
78
|
+
callbacks.onClose();
|
|
79
|
+
callbacks.onRender();
|
|
80
|
+
callbacks.onResult(selectedResult.messageIndex);
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
@@ -122,6 +122,26 @@ export const SETTINGS = [
|
|
|
122
122
|
{ value: false, label: 'Off' },
|
|
123
123
|
],
|
|
124
124
|
},
|
|
125
|
+
{
|
|
126
|
+
key: 'agentAutoCommit',
|
|
127
|
+
label: 'Agent Auto-Commit',
|
|
128
|
+
getValue: () => config.get('agentAutoCommit'),
|
|
129
|
+
type: 'select',
|
|
130
|
+
options: [
|
|
131
|
+
{ value: true, label: 'On' },
|
|
132
|
+
{ value: false, label: 'Off' },
|
|
133
|
+
],
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
key: 'agentAutoCommitBranch',
|
|
137
|
+
label: 'Auto-Commit on New Branch',
|
|
138
|
+
getValue: () => config.get('agentAutoCommitBranch'),
|
|
139
|
+
type: 'select',
|
|
140
|
+
options: [
|
|
141
|
+
{ value: true, label: 'On' },
|
|
142
|
+
{ value: false, label: 'Off' },
|
|
143
|
+
],
|
|
144
|
+
},
|
|
125
145
|
{
|
|
126
146
|
key: 'agentMaxFixAttempts',
|
|
127
147
|
label: 'Agent Max Fix Attempts',
|
|
@@ -11,6 +11,12 @@ export interface StatusInfo {
|
|
|
11
11
|
hasWriteAccess: boolean;
|
|
12
12
|
sessionId: string;
|
|
13
13
|
messageCount: number;
|
|
14
|
+
tokenStats?: {
|
|
15
|
+
totalTokens: number;
|
|
16
|
+
promptTokens: number;
|
|
17
|
+
completionTokens: number;
|
|
18
|
+
requestCount: number;
|
|
19
|
+
};
|
|
14
20
|
}
|
|
15
21
|
/**
|
|
16
22
|
* Render status screen
|
|
@@ -38,8 +38,27 @@ export function renderStatusScreen(screen, status) {
|
|
|
38
38
|
const valueColor = item.color || fg.white;
|
|
39
39
|
screen.write(4 + labelWidth, y, item.value, valueColor);
|
|
40
40
|
}
|
|
41
|
+
// Token usage
|
|
42
|
+
if (status.tokenStats && status.tokenStats.requestCount > 0) {
|
|
43
|
+
const tokenY = contentStartY + items.length + 2;
|
|
44
|
+
screen.write(4, tokenY, 'Token Usage', fg.yellow + style.bold);
|
|
45
|
+
const fmt = (n) => n < 1000 ? n.toString() : (n / 1000).toFixed(1) + 'K';
|
|
46
|
+
const tokenItems = [
|
|
47
|
+
{ label: 'Requests', value: status.tokenStats.requestCount.toString() },
|
|
48
|
+
{ label: 'Prompt', value: fmt(status.tokenStats.promptTokens) },
|
|
49
|
+
{ label: 'Completion', value: fmt(status.tokenStats.completionTokens) },
|
|
50
|
+
{ label: 'Total', value: fmt(status.tokenStats.totalTokens) },
|
|
51
|
+
];
|
|
52
|
+
for (let i = 0; i < tokenItems.length; i++) {
|
|
53
|
+
const item = tokenItems[i];
|
|
54
|
+
const y = tokenY + 1 + i;
|
|
55
|
+
screen.write(4, y, item.label + ':', fg.gray);
|
|
56
|
+
screen.write(4 + labelWidth, y, item.value, fg.white);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
41
59
|
// System info
|
|
42
|
-
const
|
|
60
|
+
const tokenSectionHeight = (status.tokenStats && status.tokenStats.requestCount > 0) ? 7 : 0;
|
|
61
|
+
const sysInfoY = contentStartY + items.length + 2 + tokenSectionHeight;
|
|
43
62
|
screen.write(4, sysInfoY, 'System', fg.yellow + style.bold);
|
|
44
63
|
const sysItems = [
|
|
45
64
|
{ label: 'Platform', value: process.platform },
|