codeep 1.2.77 → 1.2.78

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.
@@ -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
- // Spinner frames for animation
14
- const SPINNER_FRAMES = ['⣾', '⣽', '⣻', '⢿', '⡿', '⣟', '⣯', '⣷'];
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
- // Separator
1299
- this.screen.horizontalLine(separatorLine, '─', fg.gray);
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,22 +1468,23 @@ 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.writeLine(y, agentText, PRIMARY_COLOR);
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
- this.screen.writeLine(y, `${spinner} ${message}...`, PRIMARY_COLOR);
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
  }
@@ -1890,15 +1906,15 @@ export class App {
1890
1906
  acc.errors++;
1891
1907
  return acc;
1892
1908
  }, { reads: 0, writes: 0, edits: 0, deletes: 0, commands: 0, searches: 0, errors: 0 });
1893
- // Top border with title
1894
- const title = ` ${spinner} AGENT `;
1909
+ // Top border: gradient line with gradient title embedded
1910
+ const titleInner = ` ${spinner} AGENT `;
1895
1911
  const titlePadLeft = 2;
1896
- const titlePadRight = width - titlePadLeft - title.length - 1;
1897
- this.screen.write(0, y, '─'.repeat(titlePadLeft), PRIMARY_COLOR);
1898
- this.screen.write(titlePadLeft, y, title, PRIMARY_COLOR + style.bold);
1899
- this.screen.write(titlePadLeft + title.length, y, '─'.repeat(Math.max(0, titlePadRight)), PRIMARY_COLOR);
1912
+ const lineLeft = gradientLine(titlePadLeft, GRADIENT_STOPS);
1913
+ const titleColored = gradientText(titleInner, GRADIENT_STOPS) + style.bold;
1914
+ const lineRight = gradientLine(Math.max(0, width - titlePadLeft - titleInner.length - 1), GRADIENT_STOPS);
1915
+ this.screen.write(0, y, lineLeft + titleColored + lineRight);
1900
1916
  y++;
1901
- // Current action line (clear first to avoid stale text from longer previous paths)
1917
+ // Current action line
1902
1918
  this.screen.writeLine(y, '');
1903
1919
  if (this.agentWaitingForAI) {
1904
1920
  this.screen.write(1, y, 'Thinking...', fg.gray);
@@ -1916,7 +1932,7 @@ export class App {
1916
1932
  this.screen.write(1, y, 'Starting...', fg.gray);
1917
1933
  }
1918
1934
  y++;
1919
- // Stats line: Files and step info (clear line first to avoid stale text)
1935
+ // Stats + 8-bit progress bar line
1920
1936
  this.screen.writeLine(y, '');
1921
1937
  let x = 1;
1922
1938
  // File changes
@@ -1950,19 +1966,42 @@ export class App {
1950
1966
  this.screen.write(x, y, txt, fg.cyan);
1951
1967
  x += txt.length + 1;
1952
1968
  }
1953
- // Step info on the right
1954
- const stepText = this.agentMaxIterations > 0
1955
- ? `step ${this.agentIteration}/${this.agentMaxIterations}`
1956
- : `step ${this.agentIteration}`;
1957
- this.screen.write(width - stepText.length - 1, y, stepText, fg.gray);
1969
+ // 8-bit gradient progress bar (right side, if max iterations known)
1970
+ if (this.agentMaxIterations > 0) {
1971
+ const barWidth = 14;
1972
+ const progress = Math.min(this.agentIteration / this.agentMaxIterations, 1);
1973
+ const filled = Math.round(progress * barWidth);
1974
+ // Use block chars: █▓▒░ for gradient fill effect
1975
+ const BLOCKS = ['░', '▒', '▓', '█'];
1976
+ let bar = '';
1977
+ for (let i = 0; i < barWidth; i++) {
1978
+ if (i < filled - 1)
1979
+ bar += '█';
1980
+ else if (i === filled - 1)
1981
+ bar += '▓';
1982
+ else if (i === filled)
1983
+ bar += '▒';
1984
+ else
1985
+ bar += '░';
1986
+ }
1987
+ const barColored = gradientText(bar, GRADIENT_STOPS);
1988
+ const stepText = `${this.agentIteration}/${this.agentMaxIterations}`;
1989
+ const barX = width - barWidth - stepText.length - 3;
1990
+ this.screen.write(barX, y, barColored);
1991
+ this.screen.write(width - stepText.length - 1, y, stepText, fg.gray);
1992
+ }
1993
+ else {
1994
+ const stepText = `step ${this.agentIteration}`;
1995
+ this.screen.write(width - stepText.length - 1, y, stepText, fg.gray);
1996
+ }
1958
1997
  y++;
1959
- // Bottom border with help
1998
+ // Bottom border with help text
1960
1999
  const helpText = ' Esc to stop ';
1961
2000
  const helpPadLeft = Math.floor((width - helpText.length) / 2);
1962
- const helpPadRight = Math.ceil((width - helpText.length) / 2);
1963
- this.screen.write(0, y, '─'.repeat(helpPadLeft), fg.gray);
2001
+ const helpPadRight = Math.max(0, width - helpPadLeft - helpText.length);
2002
+ this.screen.write(0, y, gradientLine(helpPadLeft, GRADIENT_STOPS_DIM));
1964
2003
  this.screen.write(helpPadLeft, y, helpText, fg.gray);
1965
- this.screen.write(helpPadLeft + helpText.length, y, '─'.repeat(helpPadRight), fg.gray);
2004
+ this.screen.write(helpPadLeft + helpText.length, y, gradientLine(helpPadRight, GRADIENT_STOPS_DIM));
1966
2005
  }
1967
2006
  /**
1968
2007
  * Get color for action type
@@ -2016,29 +2055,44 @@ export class App {
2016
2055
  * Render status bar
2017
2056
  */
2018
2057
  renderStatusBar(y, width) {
2019
- let leftText = '';
2020
- let rightText = '';
2058
+ // Clear the line first
2059
+ this.screen.writeLine(y, '');
2021
2060
  if (this.notification) {
2022
- leftText = ` ${this.notification}`;
2023
- }
2024
- else {
2025
- const stats = this.options.getStatus().tokenStats;
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}`;
2061
+ // Notification: gradient colored, full width
2062
+ const notifText = ` ${this.notification}`;
2063
+ this.screen.write(0, y, gradientText(notifText, GRADIENT_STOPS));
2064
+ return;
2030
2065
  }
2066
+ const status = this.options.getStatus();
2067
+ const stats = status.tokenStats;
2068
+ const tokenInfo = stats && stats.totalTokens > 0
2069
+ ? ` ${stats.totalTokens < 1000 ? stats.totalTokens : (stats.totalTokens / 1000).toFixed(1) + 'K'} tok`
2070
+ : '';
2071
+ // Left: message count (gray) + token info (dim)
2072
+ const msgPart = ` ${this.messages.length} msg`;
2073
+ this.screen.write(0, y, msgPart, fg.gray);
2074
+ if (tokenInfo) {
2075
+ this.screen.write(msgPart.length, y, tokenInfo, fg.gray + style.dim);
2076
+ }
2077
+ // Center: model name with gradient
2078
+ const modelName = status.model || '';
2079
+ if (modelName) {
2080
+ const modelColored = gradientText(modelName, GRADIENT_STOPS);
2081
+ const modelX = Math.floor((width - modelName.length) / 2);
2082
+ this.screen.write(modelX, y, modelColored);
2083
+ }
2084
+ // Right: context hint (gray)
2085
+ let rightText;
2031
2086
  if (this.isStreaming) {
2032
- rightText = 'Streaming... (Esc to cancel)';
2087
+ rightText = 'Esc cancel ';
2033
2088
  }
2034
2089
  else if (this.isLoading) {
2035
- rightText = 'Thinking...';
2090
+ rightText = 'working... ';
2036
2091
  }
2037
2092
  else {
2038
- rightText = 'Enter send | /help commands';
2093
+ rightText = '/help ';
2039
2094
  }
2040
- const padding = ' '.repeat(Math.max(0, width - leftText.length - rightText.length));
2041
- this.screen.writeLine(y, leftText + padding + rightText, fg.gray);
2095
+ this.screen.write(width - rightText.length, y, rightText, fg.gray);
2042
2096
  }
2043
2097
  /**
2044
2098
  * Get visible messages (including streaming)
@@ -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
@@ -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.77",
3
+ "version": "1.2.78",
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",