thatgfsj-code 0.7.0 → 0.7.2

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 (75) hide show
  1. package/dist/app/index.d.ts.map +1 -1
  2. package/dist/app/index.js +5 -0
  3. package/dist/app/index.js.map +1 -1
  4. package/dist/cmd/index.d.ts +0 -5
  5. package/dist/cmd/index.d.ts.map +1 -1
  6. package/dist/cmd/index.js +36 -56
  7. package/dist/cmd/index.js.map +1 -1
  8. package/dist/session/index.d.ts +5 -21
  9. package/dist/session/index.d.ts.map +1 -1
  10. package/dist/session/index.js +26 -22
  11. package/dist/session/index.js.map +1 -1
  12. package/dist/tools/nwt.d.ts +5 -0
  13. package/dist/tools/nwt.d.ts.map +1 -1
  14. package/dist/tools/nwt.js +68 -0
  15. package/dist/tools/nwt.js.map +1 -1
  16. package/dist/tui/app.js +1 -1
  17. package/dist/tui/app.js.map +1 -1
  18. package/dist/tui/components/ChatList.d.ts +1 -1
  19. package/dist/tui/components/ChatList.d.ts.map +1 -1
  20. package/dist/tui/components/ChatList.js +5 -3
  21. package/dist/tui/components/ChatList.js.map +1 -1
  22. package/dist/tui/components/ChatMessage.d.ts +1 -1
  23. package/dist/tui/components/ChatMessage.d.ts.map +1 -1
  24. package/dist/tui/components/ChatMessage.js +4 -2
  25. package/dist/tui/components/ChatMessage.js.map +1 -1
  26. package/dist/tui/components/Header.d.ts +1 -1
  27. package/dist/tui/components/Header.d.ts.map +1 -1
  28. package/dist/tui/components/Header.js +5 -3
  29. package/dist/tui/components/Header.js.map +1 -1
  30. package/dist/tui/components/StatusBar.d.ts +1 -1
  31. package/dist/tui/components/StatusBar.d.ts.map +1 -1
  32. package/dist/tui/components/StatusBar.js +4 -2
  33. package/dist/tui/components/StatusBar.js.map +1 -1
  34. package/dist/tui/components/Thinking.d.ts +2 -1
  35. package/dist/tui/components/Thinking.d.ts.map +1 -1
  36. package/dist/tui/components/Thinking.js +5 -1
  37. package/dist/tui/components/Thinking.js.map +1 -1
  38. package/dist/tui/components/UserInput.d.ts +1 -1
  39. package/dist/tui/components/UserInput.d.ts.map +1 -1
  40. package/dist/tui/components/UserInput.js +5 -22
  41. package/dist/tui/components/UserInput.js.map +1 -1
  42. package/package.json +1 -1
  43. package/src/app/index.ts +6 -0
  44. package/src/cmd/index.tsx +38 -51
  45. package/src/session/index.ts +28 -22
  46. package/src/tools/nwt.ts +68 -0
  47. package/src/tui/app.tsx +1 -1
  48. package/src/tui/components/ChatList.tsx +4 -4
  49. package/src/tui/components/ChatMessage.tsx +2 -2
  50. package/src/tui/components/Header.tsx +3 -3
  51. package/src/tui/components/StatusBar.tsx +2 -2
  52. package/src/tui/components/Thinking.tsx +7 -1
  53. package/src/tui/components/UserInput.tsx +8 -24
  54. package/dist/app/agent.d.ts +0 -31
  55. package/dist/app/agent.d.ts.map +0 -1
  56. package/dist/app/agent.js +0 -106
  57. package/dist/app/agent.js.map +0 -1
  58. package/dist/tui/input.d.ts +0 -13
  59. package/dist/tui/input.d.ts.map +0 -1
  60. package/dist/tui/input.js +0 -47
  61. package/dist/tui/input.js.map +0 -1
  62. package/dist/tui/output.d.ts +0 -44
  63. package/dist/tui/output.d.ts.map +0 -1
  64. package/dist/tui/output.js +0 -202
  65. package/dist/tui/output.js.map +0 -1
  66. package/dist/tui/repl.d.ts +0 -15
  67. package/dist/tui/repl.d.ts.map +0 -1
  68. package/dist/tui/repl.js +0 -162
  69. package/dist/tui/repl.js.map +0 -1
  70. package/install.bat +0 -63
  71. package/install.ps1 +0 -217
  72. package/install.sh +0 -113
  73. package/src/tui/input.ts +0 -53
  74. package/src/tui/output.ts +0 -235
  75. package/src/tui/repl.ts +0 -181
package/install.ps1 DELETED
@@ -1,217 +0,0 @@
1
- # Thatgfsj Code Installer for Windows
2
- # Works on any Windows machine - auto-downloads Node.js if needed
3
- #
4
- # Usage:
5
- # irm https://raw.githubusercontent.com/Thatgfsj/thatgfsj-code/master/install.ps1 | iex
6
-
7
- $ErrorActionPreference = "Stop"
8
-
9
- function Log($msg) { Write-Host " $msg" -ForegroundColor Gray }
10
- function Step($msg) { Write-Host " > $msg" -ForegroundColor Cyan }
11
- function Ok($msg) { Write-Host " OK $msg" -ForegroundColor Green }
12
- function Fail($msg) { Write-Host " !! $msg" -ForegroundColor Red }
13
-
14
- Write-Host ""
15
- Write-Host " Thatgfsj Code Installer" -ForegroundColor Cyan
16
- Write-Host " ────────────────────────" -ForegroundColor DarkGray
17
- Write-Host ""
18
-
19
- # ── Helper: Refresh PATH from registry ────────────────────
20
-
21
- function Refresh-Path {
22
- $machinePath = [System.Environment]::GetEnvironmentVariable("Path", "Machine")
23
- $userPath = [System.Environment]::GetEnvironmentVariable("Path", "User")
24
- $env:Path = "$machinePath;$userPath"
25
- }
26
-
27
- # ── Helper: Download file with progress ───────────────────
28
-
29
- function Download-File {
30
- param($url, $dest)
31
- Log "Downloading $url ..."
32
- try {
33
- $wc = New-Object System.Net.WebClient
34
- $wc.DownloadFile($url, $dest)
35
- } catch {
36
- # Fallback to Invoke-WebRequest
37
- Invoke-WebRequest -Uri $url -OutFile $dest -UseBasicParsing
38
- }
39
- }
40
-
41
- # ── Helper: Install Node.js by downloading binary ─────────
42
-
43
- function Install-NodeJs-Binary {
44
- Log "Downloading Node.js LTS binary..."
45
-
46
- $nodeVersion = "v22.16.0"
47
- $arch = if ([Environment]::Is64BitOperatingSystem) { "x64" } else { "x86" }
48
- $filename = "node-$nodeVersion-win-$arch"
49
- $zipUrl = "https://nodejs.org/dist/$nodeVersion/$filename.zip"
50
-
51
- $tempDir = Join-Path $env:TEMP "gfcode-node-install"
52
- $zipFile = Join-Path $tempDir "$filename.zip"
53
- $extractDir = Join-Path $tempDir $filename
54
-
55
- # Clean up previous attempts
56
- if (Test-Path $tempDir) { Remove-Item $tempDir -Recurse -Force }
57
- New-Item -ItemType Directory -Path $tempDir -Force | Out-Null
58
-
59
- # Download
60
- Download-File $zipUrl $zipFile
61
-
62
- # Extract
63
- Log "Extracting..."
64
- Expand-Archive -Path $zipFile -DestinationPath $tempDir -Force
65
-
66
- # Move to install location
67
- $installBase = Join-Path $env:USERPROFILE ".gfcode-node"
68
- if (Test-Path $installBase) { Remove-Item $installBase -Recurse -Force }
69
- Move-Item $extractDir $installBase
70
-
71
- # Add to PATH (current session + user env)
72
- $nodeBin = $installBase
73
- $env:Path = "$nodeBin;$env:Path"
74
-
75
- # Persist to user PATH
76
- $userPath = [System.Environment]::GetEnvironmentVariable("Path", "User")
77
- if ($userPath -notlike "*$nodeBin*") {
78
- [System.Environment]::SetEnvironmentVariable("Path", "$nodeBin;$userPath", "User")
79
- }
80
-
81
- # Cleanup
82
- Remove-Item $tempDir -Recurse -Force -ErrorAction SilentlyContinue
83
-
84
- # Verify
85
- try {
86
- $ver = & "$nodeBin\node.exe" --version
87
- Ok "Node.js $ver (portable)"
88
- return $true
89
- } catch {
90
- return $false
91
- }
92
- }
93
-
94
- # ── Step 1: Check / Install Node.js ───────────────────────
95
-
96
- Step "Checking Node.js..."
97
-
98
- $nodeOk = $false
99
-
100
- # Check if node is available
101
- try {
102
- $ver = node --version 2>$null
103
- if ($ver) {
104
- $major = [int]($ver -replace 'v(\d+)\..*', '$1')
105
- if ($major -ge 18) {
106
- Ok "Node.js $ver"
107
- $nodeOk = $true
108
- } else {
109
- Log "Node.js $ver found but too old (need 18+)"
110
- }
111
- }
112
- } catch {}
113
-
114
- if (-not $nodeOk) {
115
- Log "Node.js 18+ not found."
116
-
117
- # Try 1: winget
118
- if (-not $nodeOk -and (Get-Command winget -ErrorAction SilentlyContinue)) {
119
- Log "Trying winget..."
120
- try {
121
- winget install OpenJS.NodeJS.LTS --accept-package-agreements --accept-source-agreements 2>&1 | Out-Null
122
- Refresh-Path
123
- $ver = node --version 2>$null
124
- if ($ver -and [int]($ver -replace 'v(\d+)\..*', '$1') -ge 18) {
125
- Ok "Node.js $ver via winget"
126
- $nodeOk = $true
127
- }
128
- } catch {}
129
- }
130
-
131
- # Try 2: choco
132
- if (-not $nodeOk -and (Get-Command choco -ErrorAction SilentlyContinue)) {
133
- Log "Trying Chocolatey..."
134
- try {
135
- choco install nodejs-lts -y 2>&1 | Out-Null
136
- Refresh-Path
137
- $ver = node --version 2>$null
138
- if ($ver -and [int]($ver -replace 'v(\d+)\..*', '$1') -ge 18) {
139
- Ok "Node.js $ver via Chocolatey"
140
- $nodeOk = $true
141
- }
142
- } catch {}
143
- }
144
-
145
- # Try 3: Direct download (works on any machine)
146
- if (-not $nodeOk) {
147
- $nodeOk = Install-NodeJs-Binary
148
- }
149
-
150
- if (-not $nodeOk) {
151
- Fail "Failed to install Node.js"
152
- Log "Please install manually: https://nodejs.org"
153
- exit 1
154
- }
155
- }
156
-
157
- # ── Step 2: Install gfcode via npm ────────────────────────
158
-
159
- Step "Installing thatgfsj-code..."
160
-
161
- $npmPath = Join-Path (Split-Path (Get-Command node).Source) "npm.cmd"
162
- $npmGlobalPrefix = & node -e "console.log(require('path').resolve(process.execPath, '..','..'))" 2>$null
163
- $npmBinDir = Join-Path $npmGlobalPrefix "bin"
164
-
165
- # Install globally
166
- $env:npm_config_prefix = $npmGlobalPrefix
167
- & node (Join-Path (Split-Path (Get-Command node).Source) "node_modules\npm\bin\npm-cli.js") install -g thatgfsj-code 2>&1 | Out-Null
168
-
169
- if ($LASTEXITCODE -ne 0) {
170
- # Fallback: try npm directly
171
- npm install -g thatgfsj-code 2>&1 | Out-Null
172
- }
173
-
174
- if ($LASTEXITCODE -ne 0) {
175
- Fail "npm install failed"
176
- exit 1
177
- }
178
-
179
- Ok "thatgfsj-code installed"
180
-
181
- # Make sure gfcode is in PATH for this session
182
- $npmBin = Join-Path $npmGlobalPrefix "bin"
183
- if (Test-Path $npmBin) {
184
- $env:Path = "$npmBin;$env:Path"
185
- }
186
-
187
- # ── Step 3: Verify ────────────────────────────────────────
188
-
189
- Step "Verifying..."
190
-
191
- $gfcodePath = Get-Command gfcode -ErrorAction SilentlyContinue
192
- if ($gfcodePath) {
193
- $cliVer = gfcode --version 2>$null
194
- Ok "gfcode v$cliVer"
195
- } else {
196
- # Try direct path
197
- $directPath = Join-Path $npmGlobalPrefix "bin\gfcode.cmd"
198
- if (Test-Path $directPath) {
199
- Ok "gfcode installed at $directPath"
200
- Log "You may need to restart your terminal."
201
- } else {
202
- Ok "gfcode installed (restart terminal if command not found)"
203
- }
204
- }
205
-
206
- # ── Done ──────────────────────────────────────────────────
207
-
208
- Write-Host ""
209
- Write-Host " ────────────────────────────────" -ForegroundColor DarkGray
210
- Write-Host " Done!" -ForegroundColor Green
211
- Write-Host ""
212
- Write-Host " Next steps:" -ForegroundColor White
213
- Write-Host " gfcode init " -ForegroundColor Cyan -NoNewline; Write-Host "# Configure API key" -ForegroundColor DarkGray
214
- Write-Host " gfcode " -ForegroundColor Cyan -NoNewline; Write-Host "# Start coding" -ForegroundColor DarkGray
215
- Write-Host ""
216
- Write-Host " Docs: https://github.com/Thatgfsj/thatgfsj-code" -ForegroundColor DarkGray
217
- Write-Host ""
package/install.sh DELETED
@@ -1,113 +0,0 @@
1
- #!/bin/bash
2
- # Thatgfsj Code Installer for macOS/Linux
3
- # Usage: curl -sL https://raw.githubusercontent.com/Thatgfsj/thatgfsj-code/main/install.sh | bash
4
-
5
- set -e
6
-
7
- # Colors
8
- RED='\033[0;31m'
9
- GREEN='\033[0;32m'
10
- YELLOW='\033[1;33m'
11
- CYAN='\033[0;36m'
12
- NC='\033[0m' # No Color
13
-
14
- echo ""
15
- echo -e "${CYAN} Thatgfsj Code 安装向导${NC}"
16
- echo -e "${CYAN} =======================${NC}"
17
- echo ""
18
-
19
- # ============== Step 1: Check Node.js ==============
20
- echo -e "${YELLOW}[*] 检查 Node.js...${NC}"
21
-
22
- if command -v node &> /dev/null; then
23
- NODE_VERSION=$(node --version)
24
- MAJOR_VERSION=$(echo $NODE_VERSION | cut -d'v' -f2 | cut -d'.' -f1)
25
- if [ "$MAJOR_VERSION" -ge 18 ]; then
26
- echo -e "${GREEN}[✓] Node.js $NODE_VERSION 已安装${NC}"
27
- else
28
- echo -e "${RED}[✗] Node.js 版本过低,需要 v18+${NC}"
29
- echo " 请访问 https://nodejs.org 升级"
30
- exit 1
31
- fi
32
- else
33
- echo -e "${YELLOW}[*] 未检测到 Node.js,开始安装...${NC}"
34
-
35
- # Try Homebrew (macOS)
36
- if command -v brew &> /dev/null; then
37
- echo -e "${YELLOW}[*] 使用 Homebrew 安装...${NC}"
38
- brew install node
39
- # Try apt (Ubuntu/Debian)
40
- elif command -v apt-get &> /dev/null; then
41
- echo -e "${YELLOW}[*] 使用 apt 安装...${NC}"
42
- curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
43
- sudo apt-get install -y nodejs
44
- # Try yum (CentOS/RHEL)
45
- elif command -v yum &> /dev/null; then
46
- echo -e "${YELLOW}[*] 使用 yum 安装...${NC}"
47
- curl -fsSL https://rpm.nodesource.com/setup_20.x | sudo bash -
48
- sudo yum install -y nodejs
49
- else
50
- echo -e "${RED}[✗] 未找到包管理器${NC}"
51
- echo " 请手动安装: https://nodejs.org"
52
- exit 1
53
- fi
54
- fi
55
-
56
- # ============== Step 2: Clone/Update ==============
57
- echo -e "${YELLOW}[*] 准备安装 Thatgfsj Code...${NC}"
58
-
59
- INSTALL_DIR="$HOME/thatgfsj-code"
60
-
61
- if [ -d "$INSTALL_DIR" ]; then
62
- echo -e "${YELLOW}[*] 检测到已有安装,正在更新...${NC}"
63
- cd "$INSTALL_DIR"
64
- git pull origin main 2>/dev/null || {
65
- echo -e "${YELLOW}[*] 更新失败,重新克隆...${NC}"
66
- rm -rf "$INSTALL_DIR"
67
- }
68
- fi
69
-
70
- if [ ! -d "$INSTALL_DIR" ]; then
71
- echo -e "${YELLOW}[*] 克隆仓库...${NC}"
72
- git clone https://github.com/Thatgfsj/thatgfsj-code.git "$INSTALL_DIR"
73
- fi
74
-
75
- cd "$INSTALL_DIR"
76
-
77
- if [ ! -f "package.json" ]; then
78
- echo -e "${RED}[✗] 安装目录无效${NC}"
79
- exit 1
80
- fi
81
-
82
- echo -e "${GREEN}[✓] 代码准备完成: $INSTALL_DIR${NC}"
83
-
84
- # ============== Step 3: Install Dependencies ==============
85
- echo -e "${YELLOW}[*] 安装依赖...${NC}"
86
-
87
- npm install
88
- npm run build
89
-
90
- echo -e "${GREEN}[✓] 依赖安装完成${NC}"
91
-
92
- # ============== Step 4: Link Command ==============
93
- echo -e "${YELLOW}[*] 设置命令...${NC}"
94
-
95
- npm link
96
-
97
- echo -e "${GREEN}[✓] 命令 'gfcode' 已可用${NC}"
98
-
99
- # ============== Done ==============
100
- echo ""
101
- echo -e "${CYAN} ======================================${NC}"
102
- echo -e "${GREEN} 安装完成!${NC}"
103
- echo -e "${CYAN} ======================================${NC}"
104
- echo ""
105
- echo -e " ${WHITE}使用方法:${NC}"
106
- echo -e " gfcode init - 重新配置"
107
- echo -e " gfcode - 启动交互模式"
108
- echo -e " gfcode '你的问题' - 直接提问"
109
- echo -e " gfcode explain '代码' - 解释代码"
110
- echo -e " gfcode debug '代码' - 调试代码"
111
- echo ""
112
- echo -e " 文档: ${CYAN}https://github.com/Thatgfsj/thatgfsj-code${NC}"
113
- echo ""
package/src/tui/input.ts DELETED
@@ -1,53 +0,0 @@
1
- /**
2
- * REPL Input Handler
3
- */
4
-
5
- import readline from 'readline';
6
- import chalk from 'chalk';
7
-
8
- export class REPLInput {
9
- private rl: readline.Interface;
10
- private history: string[] = [];
11
- private historyIndex: number = -1;
12
-
13
- constructor() {
14
- this.rl = readline.createInterface({
15
- input: process.stdin,
16
- output: process.stdout,
17
- completer: this.completer.bind(this),
18
- historySize: 100,
19
- tabSize: 4,
20
- });
21
-
22
- this.rl.on('SIGINT', () => {
23
- process.stdout.write(chalk.gray('\n Goodbye! 👋\n'));
24
- process.exit(0);
25
- });
26
-
27
- this.rl.on('line', (line) => {
28
- if (line.trim()) {
29
- this.history.push(line);
30
- if (this.history.length > 100) this.history.shift();
31
- }
32
- this.historyIndex = this.history.length;
33
- });
34
- }
35
-
36
- async prompt(prefix: string = chalk.cyan('❯ ')): Promise<string> {
37
- return new Promise((resolve) => {
38
- this.rl.question(prefix, (answer) => {
39
- resolve(answer);
40
- });
41
- });
42
- }
43
-
44
- close(): void {
45
- this.rl.close();
46
- }
47
-
48
- private completer(line: string): [string[], string] {
49
- const commands = ['exit', 'quit', 'clear', 'help', 'tools', 'model'];
50
- const hits = commands.filter(c => c.startsWith(line.toLowerCase()));
51
- return [hits.length ? hits : [], line];
52
- }
53
- }
package/src/tui/output.ts DELETED
@@ -1,235 +0,0 @@
1
- /**
2
- * REPL Output - Clean terminal UI
3
- * Inspired by opencode: simple indentation for streaming, clean boundaries
4
- */
5
-
6
- import chalk from 'chalk';
7
- import ora, { Ora } from 'ora';
8
-
9
- export class REPLOutput {
10
- private spinner: Ora | null = null;
11
-
12
- // ── Banner ──────────────────────────────────────────────
13
-
14
- printBanner(): void {
15
- console.log();
16
- console.log(chalk.cyan.bold(' ⚡ Thatgfsj Code') + chalk.gray(' v0.5.0'));
17
- console.log(chalk.gray(' AI Coding Assistant'));
18
- console.log(chalk.gray(' ' + '─'.repeat(52)));
19
- console.log();
20
- }
21
-
22
- // ── Prompt ──────────────────────────────────────────────
23
-
24
- getPrompt(): string {
25
- return chalk.cyan.bold('❯ ');
26
- }
27
-
28
- // ── User Input ──────────────────────────────────────────
29
-
30
- printUserInput(input: string): void {
31
- console.log();
32
- console.log(chalk.bold(' You'));
33
- console.log(chalk.gray(' ' + '─'.repeat(40)));
34
- for (const line of input.split('\n')) {
35
- console.log(' ' + line);
36
- }
37
- console.log();
38
- }
39
-
40
- // ── Assistant Streaming ─────────────────────────────────
41
-
42
- /**
43
- * Begin assistant response - just print the header
44
- */
45
- beginAssistant(): void {
46
- console.log(chalk.bold(' AI'));
47
- console.log(chalk.gray(' ' + '─'.repeat(40)));
48
- }
49
-
50
- /**
51
- * Write streaming chunk - output as-is with indent.
52
- * The chunk already contains proper newlines from the AI.
53
- */
54
- writeChunk(chunk: string): void {
55
- // Indent each line by 2 spaces
56
- const lines = chunk.split('\n');
57
- for (let i = 0; i < lines.length; i++) {
58
- if (lines[i]) {
59
- process.stdout.write(' ' + lines[i]);
60
- }
61
- if (i < lines.length - 1) {
62
- process.stdout.write('\n');
63
- }
64
- }
65
- }
66
-
67
- /**
68
- * End assistant response
69
- */
70
- endAssistant(): void {
71
- process.stdout.write('\n');
72
- console.log();
73
- }
74
-
75
- // ── Tool Calls ──────────────────────────────────────────
76
-
77
- printToolCall(name: string, args: string): void {
78
- console.log();
79
- console.log(chalk.yellow(' ⚙ ') + chalk.bold(name));
80
-
81
- if (args) {
82
- try {
83
- const obj = JSON.parse(args);
84
- for (const [key, val] of Object.entries(obj)) {
85
- let display: string;
86
- if (typeof val === 'string') {
87
- display = val.length > 100 ? val.slice(0, 100) + '...' : val;
88
- } else {
89
- display = JSON.stringify(val);
90
- if (display.length > 100) display = display.slice(0, 100) + '...';
91
- }
92
- console.log(chalk.gray(' ' + key + ': ') + display);
93
- }
94
- } catch {
95
- const display = args.length > 120 ? args.slice(0, 120) + '...' : args;
96
- console.log(chalk.gray(' ') + display);
97
- }
98
- }
99
- }
100
-
101
- printToolResult(output: string, isError = false): void {
102
- if (!output) return;
103
-
104
- const lines = output.split('\n');
105
- const maxLines = 20;
106
- const display = lines.slice(0, maxLines);
107
-
108
- for (const line of display) {
109
- if (isError) {
110
- console.log(chalk.red(' ✖ ') + line);
111
- } else {
112
- console.log(chalk.gray(' │ ') + line);
113
- }
114
- }
115
-
116
- if (lines.length > maxLines) {
117
- console.log(chalk.gray(' │ ') + chalk.dim(`... +${lines.length - maxLines} more lines`));
118
- }
119
- }
120
-
121
- printToolEnd(): void {
122
- console.log();
123
- }
124
-
125
- // ── Thinking ────────────────────────────────────────────
126
-
127
- startThinking(): void {
128
- this.spinner = ora({
129
- text: chalk.gray('Thinking'),
130
- color: 'cyan',
131
- spinner: 'dots',
132
- }).start();
133
- }
134
-
135
- startExecuting(toolName: string): void {
136
- this.spinner = ora({
137
- text: chalk.gray(`Executing ${chalk.yellow(toolName)}`),
138
- color: 'cyan',
139
- spinner: 'dots',
140
- }).start();
141
- }
142
-
143
- stopThinking(): void {
144
- if (this.spinner) {
145
- this.spinner.stop();
146
- this.spinner = null;
147
- }
148
- }
149
-
150
- stopThinkingFail(msg: string): void {
151
- if (this.spinner) {
152
- this.spinner.fail(chalk.red(msg));
153
- this.spinner = null;
154
- }
155
- }
156
-
157
- // ── Messages ────────────────────────────────────────────
158
-
159
- info(msg: string): void {
160
- console.log(chalk.gray(' ') + msg);
161
- }
162
-
163
- success(msg: string): void {
164
- console.log(chalk.green(' ✅ ') + msg);
165
- }
166
-
167
- error(msg: string): void {
168
- console.log();
169
- console.log(chalk.red(' Error'));
170
- console.log(chalk.red(' ' + '─'.repeat(40)));
171
- for (const line of msg.split('\n')) {
172
- console.log(chalk.red(' ') + line);
173
- }
174
- console.log();
175
- }
176
-
177
- warning(msg: string): void {
178
- console.log(chalk.yellow(' ⚠ ') + msg);
179
- }
180
-
181
- dim(msg: string): void {
182
- console.log(chalk.dim(' ' + msg));
183
- }
184
-
185
- // ── Layout ──────────────────────────────────────────────
186
-
187
- divider(): void {
188
- console.log(chalk.gray(' ' + '─'.repeat(52)));
189
- }
190
-
191
- spacer(): void {
192
- console.log();
193
- }
194
-
195
- clear(): void {
196
- console.clear();
197
- }
198
-
199
- // ── Sections ────────────────────────────────────────────
200
-
201
- section(title: string, items: Array<{ label: string; value: string }>): void {
202
- console.log();
203
- console.log(chalk.bold(' ' + title));
204
- console.log(chalk.gray(' ' + '─'.repeat(40)));
205
- for (const item of items) {
206
- console.log(' ' + chalk.gray(item.label.padEnd(14)) + item.value);
207
- }
208
- console.log();
209
- }
210
-
211
- // ── Help ────────────────────────────────────────────────
212
-
213
- printHelp(): void {
214
- console.log();
215
- console.log(chalk.bold(' Commands'));
216
- console.log(chalk.gray(' ' + '─'.repeat(40)));
217
- const cmds: [string, string][] = [
218
- ['help', 'Show this help'],
219
- ['tools', 'List available tools'],
220
- ['model', 'Show current model info'],
221
- ['clear', 'Clear screen'],
222
- ['exit', 'Exit'],
223
- ];
224
- for (const [cmd, desc] of cmds) {
225
- console.log(' ' + chalk.cyan(cmd.padEnd(14)) + chalk.gray(desc));
226
- }
227
- console.log();
228
- console.log(chalk.bold(' Keyboard'));
229
- console.log(chalk.gray(' ' + '─'.repeat(40)));
230
- console.log(' ' + chalk.cyan('↑ / ↓'.padEnd(14)) + chalk.gray('Browse command history'));
231
- console.log(' ' + chalk.cyan('Tab'.padEnd(14)) + chalk.gray('Auto-complete'));
232
- console.log(' ' + chalk.cyan('Ctrl+C'.padEnd(14)) + chalk.gray('Exit'));
233
- console.log();
234
- }
235
- }