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.
- package/dist/app/index.d.ts.map +1 -1
- package/dist/app/index.js +5 -0
- package/dist/app/index.js.map +1 -1
- package/dist/cmd/index.d.ts +0 -5
- package/dist/cmd/index.d.ts.map +1 -1
- package/dist/cmd/index.js +36 -56
- package/dist/cmd/index.js.map +1 -1
- package/dist/session/index.d.ts +5 -21
- package/dist/session/index.d.ts.map +1 -1
- package/dist/session/index.js +26 -22
- package/dist/session/index.js.map +1 -1
- package/dist/tools/nwt.d.ts +5 -0
- package/dist/tools/nwt.d.ts.map +1 -1
- package/dist/tools/nwt.js +68 -0
- package/dist/tools/nwt.js.map +1 -1
- package/dist/tui/app.js +1 -1
- package/dist/tui/app.js.map +1 -1
- package/dist/tui/components/ChatList.d.ts +1 -1
- package/dist/tui/components/ChatList.d.ts.map +1 -1
- package/dist/tui/components/ChatList.js +5 -3
- package/dist/tui/components/ChatList.js.map +1 -1
- package/dist/tui/components/ChatMessage.d.ts +1 -1
- package/dist/tui/components/ChatMessage.d.ts.map +1 -1
- package/dist/tui/components/ChatMessage.js +4 -2
- package/dist/tui/components/ChatMessage.js.map +1 -1
- package/dist/tui/components/Header.d.ts +1 -1
- package/dist/tui/components/Header.d.ts.map +1 -1
- package/dist/tui/components/Header.js +5 -3
- package/dist/tui/components/Header.js.map +1 -1
- package/dist/tui/components/StatusBar.d.ts +1 -1
- package/dist/tui/components/StatusBar.d.ts.map +1 -1
- package/dist/tui/components/StatusBar.js +4 -2
- package/dist/tui/components/StatusBar.js.map +1 -1
- package/dist/tui/components/Thinking.d.ts +2 -1
- package/dist/tui/components/Thinking.d.ts.map +1 -1
- package/dist/tui/components/Thinking.js +5 -1
- package/dist/tui/components/Thinking.js.map +1 -1
- package/dist/tui/components/UserInput.d.ts +1 -1
- package/dist/tui/components/UserInput.d.ts.map +1 -1
- package/dist/tui/components/UserInput.js +5 -22
- package/dist/tui/components/UserInput.js.map +1 -1
- package/package.json +1 -1
- package/src/app/index.ts +6 -0
- package/src/cmd/index.tsx +38 -51
- package/src/session/index.ts +28 -22
- package/src/tools/nwt.ts +68 -0
- package/src/tui/app.tsx +1 -1
- package/src/tui/components/ChatList.tsx +4 -4
- package/src/tui/components/ChatMessage.tsx +2 -2
- package/src/tui/components/Header.tsx +3 -3
- package/src/tui/components/StatusBar.tsx +2 -2
- package/src/tui/components/Thinking.tsx +7 -1
- package/src/tui/components/UserInput.tsx +8 -24
- package/dist/app/agent.d.ts +0 -31
- package/dist/app/agent.d.ts.map +0 -1
- package/dist/app/agent.js +0 -106
- package/dist/app/agent.js.map +0 -1
- package/dist/tui/input.d.ts +0 -13
- package/dist/tui/input.d.ts.map +0 -1
- package/dist/tui/input.js +0 -47
- package/dist/tui/input.js.map +0 -1
- package/dist/tui/output.d.ts +0 -44
- package/dist/tui/output.d.ts.map +0 -1
- package/dist/tui/output.js +0 -202
- package/dist/tui/output.js.map +0 -1
- package/dist/tui/repl.d.ts +0 -15
- package/dist/tui/repl.d.ts.map +0 -1
- package/dist/tui/repl.js +0 -162
- package/dist/tui/repl.js.map +0 -1
- package/install.bat +0 -63
- package/install.ps1 +0 -217
- package/install.sh +0 -113
- package/src/tui/input.ts +0 -53
- package/src/tui/output.ts +0 -235
- 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
|
-
}
|