codeep 1.1.36 → 1.2.1

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.
Files changed (36) hide show
  1. package/README.md +90 -4
  2. package/dist/api/index.js +64 -2
  3. package/dist/renderer/App.d.ts +5 -0
  4. package/dist/renderer/App.js +164 -227
  5. package/dist/renderer/components/Export.d.ts +22 -0
  6. package/dist/renderer/components/Export.js +64 -0
  7. package/dist/renderer/components/Help.js +5 -1
  8. package/dist/renderer/components/Logout.d.ts +29 -0
  9. package/dist/renderer/components/Logout.js +91 -0
  10. package/dist/renderer/components/Search.d.ts +30 -0
  11. package/dist/renderer/components/Search.js +83 -0
  12. package/dist/renderer/components/Settings.js +20 -0
  13. package/dist/renderer/components/Status.d.ts +6 -0
  14. package/dist/renderer/components/Status.js +20 -1
  15. package/dist/renderer/main.js +316 -141
  16. package/dist/utils/agent.d.ts +5 -0
  17. package/dist/utils/agent.js +238 -3
  18. package/dist/utils/agent.test.d.ts +1 -0
  19. package/dist/utils/agent.test.js +250 -0
  20. package/dist/utils/diffPreview.js +104 -35
  21. package/dist/utils/gitignore.d.ts +24 -0
  22. package/dist/utils/gitignore.js +161 -0
  23. package/dist/utils/gitignore.test.d.ts +1 -0
  24. package/dist/utils/gitignore.test.js +167 -0
  25. package/dist/utils/skills.d.ts +21 -0
  26. package/dist/utils/skills.js +51 -0
  27. package/dist/utils/smartContext.js +8 -0
  28. package/dist/utils/smartContext.test.d.ts +1 -0
  29. package/dist/utils/smartContext.test.js +382 -0
  30. package/dist/utils/tokenTracker.d.ts +52 -0
  31. package/dist/utils/tokenTracker.js +86 -0
  32. package/dist/utils/tools.d.ts +16 -0
  33. package/dist/utils/tools.js +146 -19
  34. package/dist/utils/tools.test.d.ts +1 -0
  35. package/dist/utils/tools.test.js +664 -0
  36. 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 sysInfoY = contentStartY + items.length + 2;
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 },