codeep 1.2.77 → 1.2.79
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/renderer/App.js +106 -59
- package/dist/renderer/ansi.d.ts +11 -0
- package/dist/renderer/ansi.js +42 -0
- package/package.json +1 -1
package/dist/renderer/App.js
CHANGED
|
@@ -4,14 +4,29 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import { Screen } from './Screen.js';
|
|
6
6
|
import { Input, LineEditor } from './Input.js';
|
|
7
|
-
import { fg, style, stringWidth } from './ansi.js';
|
|
7
|
+
import { fg, style, stringWidth, gradientText, gradientLine } from './ansi.js';
|
|
8
8
|
import { SYNTAX, highlightCode } from './highlight.js';
|
|
9
9
|
import { handleInlineStatusKey, handleInlineHelpKey, handleMenuKey, handleInlinePermissionKey, handleInlineSessionPickerKey, handleInlineConfirmKey, handleLoginKey, } from './handlers.js';
|
|
10
10
|
import clipboardy from 'clipboardy';
|
|
11
11
|
// Primary color: #f02a30 (Codeep red)
|
|
12
12
|
const PRIMARY_COLOR = fg.rgb(240, 42, 48);
|
|
13
|
-
//
|
|
14
|
-
|
|
13
|
+
// Gradient stops: deep red → codeep red → orange → amber
|
|
14
|
+
// Used for separator lines and accent elements
|
|
15
|
+
const GRADIENT_STOPS = [
|
|
16
|
+
[160, 20, 30], // deep red
|
|
17
|
+
[240, 42, 48], // Codeep red
|
|
18
|
+
[240, 100, 30], // orange-red
|
|
19
|
+
[240, 160, 20], // amber
|
|
20
|
+
];
|
|
21
|
+
// Dimmer gradient for subtle separators (half brightness)
|
|
22
|
+
const GRADIENT_STOPS_DIM = [
|
|
23
|
+
[80, 10, 15],
|
|
24
|
+
[140, 25, 28],
|
|
25
|
+
[140, 60, 18],
|
|
26
|
+
[140, 90, 12],
|
|
27
|
+
];
|
|
28
|
+
// 8-bit block spinner frames
|
|
29
|
+
const SPINNER_FRAMES = ['▖', '▘', '▝', '▗', '▌', '▀', '▐', '▄'];
|
|
15
30
|
// ASCII Logo
|
|
16
31
|
const LOGO_LINES = [
|
|
17
32
|
' ██████╗ ██████╗ ██████╗ ███████╗███████╗██████╗ ',
|
|
@@ -1295,8 +1310,8 @@ export class App {
|
|
|
1295
1310
|
}
|
|
1296
1311
|
y++;
|
|
1297
1312
|
}
|
|
1298
|
-
//
|
|
1299
|
-
this.screen.
|
|
1313
|
+
// Gradient separator
|
|
1314
|
+
this.screen.writeRaw(separatorLine, gradientLine(width, GRADIENT_STOPS_DIM));
|
|
1300
1315
|
// Input (don't render cursor when menu/settings is open)
|
|
1301
1316
|
this.renderInput(inputLine, width, this.menuOpen || this.settingsOpen);
|
|
1302
1317
|
// Status bar
|
|
@@ -1453,39 +1468,41 @@ export class App {
|
|
|
1453
1468
|
this.screen.showCursor(false);
|
|
1454
1469
|
return;
|
|
1455
1470
|
}
|
|
1456
|
-
// Agent running state - show special prompt
|
|
1471
|
+
// Agent running state - show special prompt with gradient
|
|
1457
1472
|
if (this.isAgentRunning) {
|
|
1458
1473
|
const spinner = SPINNER_FRAMES[this.spinnerFrame];
|
|
1459
1474
|
const stepLabel = this.agentMaxIterations > 0
|
|
1460
1475
|
? `step ${this.agentIteration}/${this.agentMaxIterations}`
|
|
1461
1476
|
: `step ${this.agentIteration}`;
|
|
1462
1477
|
const agentText = `${spinner} Agent working... ${stepLabel} | ${this.agentActions.length} actions (Esc to stop)`;
|
|
1463
|
-
this.screen.
|
|
1478
|
+
this.screen.write(0, y, gradientText(agentText, GRADIENT_STOPS) + style.bold);
|
|
1464
1479
|
this.screen.showCursor(false);
|
|
1465
1480
|
return;
|
|
1466
1481
|
}
|
|
1467
|
-
// Loading/streaming state with animated spinner
|
|
1482
|
+
// Loading/streaming state with animated spinner + gradient
|
|
1468
1483
|
if (this.isLoading || this.isStreaming) {
|
|
1469
1484
|
const spinner = SPINNER_FRAMES[this.spinnerFrame];
|
|
1470
|
-
const message = this.isStreaming ? 'Writing' : 'Thinking';
|
|
1471
|
-
|
|
1485
|
+
const message = this.isStreaming ? 'Writing...' : 'Thinking...';
|
|
1486
|
+
const spinnerText = `${spinner} ${message}`;
|
|
1487
|
+
this.screen.write(0, y, gradientText(spinnerText, GRADIENT_STOPS));
|
|
1472
1488
|
this.screen.showCursor(false);
|
|
1473
1489
|
return;
|
|
1474
1490
|
}
|
|
1475
|
-
// Build prompt prefix
|
|
1491
|
+
// Build prompt prefix
|
|
1476
1492
|
const lines = inputValue.split('\n');
|
|
1477
1493
|
const lineCount = lines.length;
|
|
1478
|
-
|
|
1479
|
-
const
|
|
1494
|
+
// ❯ for normal, ❯❯ for multiline, [n] for multi-line with count
|
|
1495
|
+
const promptSymbol = lineCount > 1 ? `[${lineCount}] ❯ ` : this.isMultilineMode ? '❯❯ ' : '❯ ';
|
|
1496
|
+
const maxInputWidth = width - promptSymbol.length - 1;
|
|
1480
1497
|
// Show placeholder when input is empty
|
|
1481
1498
|
if (!inputValue) {
|
|
1482
|
-
this.screen.write(0, y,
|
|
1499
|
+
this.screen.write(0, y, promptSymbol, PRIMARY_COLOR);
|
|
1483
1500
|
const placeholder = this.isMultilineMode
|
|
1484
|
-
? 'Multi-line mode
|
|
1485
|
-
: '
|
|
1486
|
-
this.screen.write(
|
|
1501
|
+
? 'Multi-line mode Enter=newline · Esc=send'
|
|
1502
|
+
: 'Message or /command';
|
|
1503
|
+
this.screen.write(promptSymbol.length, y, placeholder, fg.gray + style.dim);
|
|
1487
1504
|
if (!hideCursor) {
|
|
1488
|
-
this.screen.setCursor(
|
|
1505
|
+
this.screen.setCursor(promptSymbol.length, y);
|
|
1489
1506
|
this.screen.showCursor(true);
|
|
1490
1507
|
}
|
|
1491
1508
|
else {
|
|
@@ -1496,14 +1513,13 @@ export class App {
|
|
|
1496
1513
|
// For multi-line content, show the last line being edited
|
|
1497
1514
|
const lastLine = lines[lines.length - 1];
|
|
1498
1515
|
const displayInput = lineCount > 1 ? lastLine : inputValue;
|
|
1499
|
-
// Cursor position within the last line
|
|
1500
1516
|
const charsBeforeLastLine = lineCount > 1 ? inputValue.lastIndexOf('\n') + 1 : 0;
|
|
1501
1517
|
const cursorInLine = cursorPos - charsBeforeLastLine;
|
|
1502
1518
|
let displayValue;
|
|
1503
1519
|
let cursorX;
|
|
1504
1520
|
if (displayInput.length <= maxInputWidth) {
|
|
1505
1521
|
displayValue = displayInput;
|
|
1506
|
-
cursorX =
|
|
1522
|
+
cursorX = promptSymbol.length + Math.max(0, cursorInLine);
|
|
1507
1523
|
}
|
|
1508
1524
|
else {
|
|
1509
1525
|
const effectiveCursor = Math.max(0, cursorInLine);
|
|
@@ -1515,9 +1531,11 @@ export class App {
|
|
|
1515
1531
|
else {
|
|
1516
1532
|
displayValue = displayInput.slice(0, maxInputWidth);
|
|
1517
1533
|
}
|
|
1518
|
-
cursorX =
|
|
1534
|
+
cursorX = promptSymbol.length + (effectiveCursor - visibleStart);
|
|
1519
1535
|
}
|
|
1520
|
-
|
|
1536
|
+
// Prompt symbol in primary color, input text in white
|
|
1537
|
+
this.screen.write(0, y, promptSymbol, PRIMARY_COLOR);
|
|
1538
|
+
this.screen.write(promptSymbol.length, y, displayValue, fg.white);
|
|
1521
1539
|
// Hide cursor when menu/settings is open
|
|
1522
1540
|
if (hideCursor) {
|
|
1523
1541
|
this.screen.showCursor(false);
|
|
@@ -1890,15 +1908,15 @@ export class App {
|
|
|
1890
1908
|
acc.errors++;
|
|
1891
1909
|
return acc;
|
|
1892
1910
|
}, { reads: 0, writes: 0, edits: 0, deletes: 0, commands: 0, searches: 0, errors: 0 });
|
|
1893
|
-
// Top border with title
|
|
1894
|
-
const
|
|
1911
|
+
// Top border: gradient line with gradient title embedded
|
|
1912
|
+
const titleInner = ` ${spinner} AGENT `;
|
|
1895
1913
|
const titlePadLeft = 2;
|
|
1896
|
-
const
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
this.screen.write(
|
|
1914
|
+
const lineLeft = gradientLine(titlePadLeft, GRADIENT_STOPS);
|
|
1915
|
+
const titleColored = gradientText(titleInner, GRADIENT_STOPS) + style.bold;
|
|
1916
|
+
const lineRight = gradientLine(Math.max(0, width - titlePadLeft - titleInner.length - 1), GRADIENT_STOPS);
|
|
1917
|
+
this.screen.write(0, y, lineLeft + titleColored + lineRight);
|
|
1900
1918
|
y++;
|
|
1901
|
-
// Current action line
|
|
1919
|
+
// Current action line
|
|
1902
1920
|
this.screen.writeLine(y, '');
|
|
1903
1921
|
if (this.agentWaitingForAI) {
|
|
1904
1922
|
this.screen.write(1, y, 'Thinking...', fg.gray);
|
|
@@ -1916,7 +1934,7 @@ export class App {
|
|
|
1916
1934
|
this.screen.write(1, y, 'Starting...', fg.gray);
|
|
1917
1935
|
}
|
|
1918
1936
|
y++;
|
|
1919
|
-
// Stats
|
|
1937
|
+
// Stats + 8-bit progress bar line
|
|
1920
1938
|
this.screen.writeLine(y, '');
|
|
1921
1939
|
let x = 1;
|
|
1922
1940
|
// File changes
|
|
@@ -1950,19 +1968,42 @@ export class App {
|
|
|
1950
1968
|
this.screen.write(x, y, txt, fg.cyan);
|
|
1951
1969
|
x += txt.length + 1;
|
|
1952
1970
|
}
|
|
1953
|
-
//
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1971
|
+
// 8-bit gradient progress bar (right side, if max iterations known)
|
|
1972
|
+
if (this.agentMaxIterations > 0) {
|
|
1973
|
+
const barWidth = 14;
|
|
1974
|
+
const progress = Math.min(this.agentIteration / this.agentMaxIterations, 1);
|
|
1975
|
+
const filled = Math.round(progress * barWidth);
|
|
1976
|
+
// Use block chars: █▓▒░ for gradient fill effect
|
|
1977
|
+
const BLOCKS = ['░', '▒', '▓', '█'];
|
|
1978
|
+
let bar = '';
|
|
1979
|
+
for (let i = 0; i < barWidth; i++) {
|
|
1980
|
+
if (i < filled - 1)
|
|
1981
|
+
bar += '█';
|
|
1982
|
+
else if (i === filled - 1)
|
|
1983
|
+
bar += '▓';
|
|
1984
|
+
else if (i === filled)
|
|
1985
|
+
bar += '▒';
|
|
1986
|
+
else
|
|
1987
|
+
bar += '░';
|
|
1988
|
+
}
|
|
1989
|
+
const barColored = gradientText(bar, GRADIENT_STOPS);
|
|
1990
|
+
const stepText = `${this.agentIteration}/${this.agentMaxIterations}`;
|
|
1991
|
+
const barX = width - barWidth - stepText.length - 3;
|
|
1992
|
+
this.screen.write(barX, y, barColored);
|
|
1993
|
+
this.screen.write(width - stepText.length - 1, y, stepText, fg.gray);
|
|
1994
|
+
}
|
|
1995
|
+
else {
|
|
1996
|
+
const stepText = `step ${this.agentIteration}`;
|
|
1997
|
+
this.screen.write(width - stepText.length - 1, y, stepText, fg.gray);
|
|
1998
|
+
}
|
|
1958
1999
|
y++;
|
|
1959
|
-
// Bottom border with help
|
|
2000
|
+
// Bottom border with help text
|
|
1960
2001
|
const helpText = ' Esc to stop ';
|
|
1961
2002
|
const helpPadLeft = Math.floor((width - helpText.length) / 2);
|
|
1962
|
-
const helpPadRight = Math.
|
|
1963
|
-
this.screen.write(0, y,
|
|
2003
|
+
const helpPadRight = Math.max(0, width - helpPadLeft - helpText.length);
|
|
2004
|
+
this.screen.write(0, y, gradientLine(helpPadLeft, GRADIENT_STOPS_DIM));
|
|
1964
2005
|
this.screen.write(helpPadLeft, y, helpText, fg.gray);
|
|
1965
|
-
this.screen.write(helpPadLeft + helpText.length, y,
|
|
2006
|
+
this.screen.write(helpPadLeft + helpText.length, y, gradientLine(helpPadRight, GRADIENT_STOPS_DIM));
|
|
1966
2007
|
}
|
|
1967
2008
|
/**
|
|
1968
2009
|
* Get color for action type
|
|
@@ -2016,29 +2057,35 @@ export class App {
|
|
|
2016
2057
|
* Render status bar
|
|
2017
2058
|
*/
|
|
2018
2059
|
renderStatusBar(y, width) {
|
|
2019
|
-
|
|
2020
|
-
|
|
2060
|
+
// Clear the line first
|
|
2061
|
+
this.screen.writeLine(y, '');
|
|
2021
2062
|
if (this.notification) {
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
const tokenInfo = stats && stats.totalTokens > 0
|
|
2027
|
-
? ` | ${stats.totalTokens < 1000 ? stats.totalTokens : (stats.totalTokens / 1000).toFixed(1) + 'K'} tokens`
|
|
2028
|
-
: '';
|
|
2029
|
-
leftText = ` ${this.messages.length} messages${tokenInfo}`;
|
|
2030
|
-
}
|
|
2031
|
-
if (this.isStreaming) {
|
|
2032
|
-
rightText = 'Streaming... (Esc to cancel)';
|
|
2033
|
-
}
|
|
2034
|
-
else if (this.isLoading) {
|
|
2035
|
-
rightText = 'Thinking...';
|
|
2063
|
+
// Notification: gradient colored, full width
|
|
2064
|
+
const notifText = ` ${this.notification}`;
|
|
2065
|
+
this.screen.write(0, y, gradientText(notifText, GRADIENT_STOPS));
|
|
2066
|
+
return;
|
|
2036
2067
|
}
|
|
2037
|
-
|
|
2038
|
-
|
|
2068
|
+
const status = this.options.getStatus();
|
|
2069
|
+
const stats = status.tokenStats;
|
|
2070
|
+
// Left segment: msg count · token count
|
|
2071
|
+
const msgCount = `${this.messages.length} msg`;
|
|
2072
|
+
const tokenStr = stats && stats.totalTokens > 0
|
|
2073
|
+
? `${stats.totalTokens < 1000 ? stats.totalTokens : (stats.totalTokens / 1000).toFixed(1) + 'K'} tok`
|
|
2074
|
+
: '';
|
|
2075
|
+
const leftParts = [msgCount, tokenStr].filter(Boolean);
|
|
2076
|
+
const leftText = ' ' + leftParts.join(' · ');
|
|
2077
|
+
this.screen.write(0, y, leftText, fg.gray + style.dim);
|
|
2078
|
+
// Center: model name with gradient (only if it fits)
|
|
2079
|
+
const modelName = status.model || '';
|
|
2080
|
+
if (modelName && width > 40) {
|
|
2081
|
+
const modelX = Math.floor((width - modelName.length) / 2);
|
|
2082
|
+
this.screen.write(modelX, y, gradientText(modelName, GRADIENT_STOPS));
|
|
2083
|
+
}
|
|
2084
|
+
// Right: Esc hint only when active, nothing when idle
|
|
2085
|
+
if (this.isStreaming || this.isLoading) {
|
|
2086
|
+
const rightText = 'Esc ';
|
|
2087
|
+
this.screen.write(width - rightText.length, y, rightText, fg.gray + style.dim);
|
|
2039
2088
|
}
|
|
2040
|
-
const padding = ' '.repeat(Math.max(0, width - leftText.length - rightText.length));
|
|
2041
|
-
this.screen.writeLine(y, leftText + padding + rightText, fg.gray);
|
|
2042
2089
|
}
|
|
2043
2090
|
/**
|
|
2044
2091
|
* Get visible messages (including streaming)
|
package/dist/renderer/ansi.d.ts
CHANGED
|
@@ -81,6 +81,17 @@ export declare const style: {
|
|
|
81
81
|
* Helper to create styled text
|
|
82
82
|
*/
|
|
83
83
|
export declare function styled(text: string, ...styles: string[]): string;
|
|
84
|
+
/**
|
|
85
|
+
* Render text with a horizontal RGB gradient across multiple color stops.
|
|
86
|
+
* Each character gets its own fg.rgb() code.
|
|
87
|
+
* Stops: array of [r,g,b] colors distributed evenly across the text.
|
|
88
|
+
*/
|
|
89
|
+
export declare function gradientText(text: string, stops: Array<[number, number, number]>): string;
|
|
90
|
+
/**
|
|
91
|
+
* Render a full-width separator line with a gradient.
|
|
92
|
+
* Uses the given char (default '─') repeated across width.
|
|
93
|
+
*/
|
|
94
|
+
export declare function gradientLine(width: number, stops: Array<[number, number, number]>, char?: string): string;
|
|
84
95
|
/**
|
|
85
96
|
* Get terminal display width of a single character
|
|
86
97
|
* CJK, fullwidth, and emoji characters take 2 columns
|
package/dist/renderer/ansi.js
CHANGED
|
@@ -101,6 +101,48 @@ export function styled(text, ...styles) {
|
|
|
101
101
|
return text;
|
|
102
102
|
return styles.join('') + text + style.reset;
|
|
103
103
|
}
|
|
104
|
+
/**
|
|
105
|
+
* Interpolate between two RGB colors at position t (0..1)
|
|
106
|
+
*/
|
|
107
|
+
function lerpColor(from, to, t) {
|
|
108
|
+
return [
|
|
109
|
+
Math.round(from[0] + (to[0] - from[0]) * t),
|
|
110
|
+
Math.round(from[1] + (to[1] - from[1]) * t),
|
|
111
|
+
Math.round(from[2] + (to[2] - from[2]) * t),
|
|
112
|
+
];
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Render text with a horizontal RGB gradient across multiple color stops.
|
|
116
|
+
* Each character gets its own fg.rgb() code.
|
|
117
|
+
* Stops: array of [r,g,b] colors distributed evenly across the text.
|
|
118
|
+
*/
|
|
119
|
+
export function gradientText(text, stops) {
|
|
120
|
+
if (stops.length === 0)
|
|
121
|
+
return text;
|
|
122
|
+
if (stops.length === 1)
|
|
123
|
+
return fg.rgb(...stops[0]) + text + style.reset;
|
|
124
|
+
const chars = [...text]; // handle multi-byte / emoji
|
|
125
|
+
const len = chars.length;
|
|
126
|
+
if (len === 0)
|
|
127
|
+
return text;
|
|
128
|
+
let result = '';
|
|
129
|
+
for (let i = 0; i < len; i++) {
|
|
130
|
+
const t = len === 1 ? 0 : i / (len - 1);
|
|
131
|
+
// Which segment between stops?
|
|
132
|
+
const seg = Math.min(Math.floor(t * (stops.length - 1)), stops.length - 2);
|
|
133
|
+
const segT = t * (stops.length - 1) - seg;
|
|
134
|
+
const [r, g, b] = lerpColor(stops[seg], stops[seg + 1], segT);
|
|
135
|
+
result += fg.rgb(r, g, b) + chars[i];
|
|
136
|
+
}
|
|
137
|
+
return result + style.reset;
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Render a full-width separator line with a gradient.
|
|
141
|
+
* Uses the given char (default '─') repeated across width.
|
|
142
|
+
*/
|
|
143
|
+
export function gradientLine(width, stops, char = '─') {
|
|
144
|
+
return gradientText(char.repeat(width), stops);
|
|
145
|
+
}
|
|
104
146
|
/**
|
|
105
147
|
* Get terminal display width of a single character
|
|
106
148
|
* CJK, fullwidth, and emoji characters take 2 columns
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "codeep",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.79",
|
|
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",
|