v2.8.0 — Code editor tab + context panel improvements
- Add 💻 코드 nav button; code mode shows aside + right-panel - Code mode left sidebar: 파일/모델/설정 tabs (file tree, model selector, Monaco settings) - Monaco editor settings restored from localStorage on init - Server log panel: collapsible (▾ toggle), height fixed to 50% of aside - Context panel compact layout: reduced padding/margins/min-heights throughout so all sections (시스템통계/에이전트컨텍스트/빠른작업/프로세스로그) fit without scrolling - POST /api/code/save, GET /api/code/files, GET /api/code/file, DELETE /api/code/file endpoints - Coder AI: glm-5.1:cloud default, auto-open generated code in Monaco tabs - Code folder browser with fixed-position dropdown (escape overflow clip) - Code editor terminal panel with PTY/xterm.js (Ctrl+` shortcut) - Remove canvas panel; restore chat terminal infrastructure Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+2
-2
@@ -23,7 +23,7 @@ function runPython(script: string, timeoutMs = 60_000): Promise<any> {
|
||||
env: { ...process.env },
|
||||
});
|
||||
let out = '';
|
||||
child.stdout.on('data', (d: Buffer) => { out += d.toString(); });
|
||||
child.stdout.on('data', (d: Buffer) => { out += d.toString('utf8'); });
|
||||
child.stderr.on('data', () => {});
|
||||
child.on('close', () => {
|
||||
try { resolve(JSON.parse(out || '{}')); } catch { resolve({ error: 'Failed to parse output', raw: out.slice(0, 500) }); }
|
||||
@@ -110,7 +110,7 @@ export const imageReadTool = {
|
||||
env: { ...process.env },
|
||||
});
|
||||
let out = '';
|
||||
child.stdout.on('data', (d: Buffer) => { out += d.toString(); });
|
||||
child.stdout.on('data', (d: Buffer) => { out += d.toString('utf8'); });
|
||||
child.on('close', () => {
|
||||
try { resolve(JSON.parse(out || '{}')); } catch { resolve({ error: 'Failed to parse OCR output' }); }
|
||||
});
|
||||
|
||||
+2
-2
@@ -113,10 +113,10 @@ export const pythonEvalTool = {
|
||||
}, timeoutSec * 1000);
|
||||
|
||||
child.stdout.on('data', (d: Buffer) => {
|
||||
stdout += d.toString();
|
||||
stdout += d.toString('utf8');
|
||||
if (stdout.length > 50_000) child.kill('SIGKILL');
|
||||
});
|
||||
child.stderr.on('data', (d: Buffer) => { stderr += d.toString(); });
|
||||
child.stderr.on('data', (d: Buffer) => { stderr += d.toString('utf8'); });
|
||||
child.on('close', (code: number | null) => {
|
||||
if (settled) return;
|
||||
settled = true;
|
||||
|
||||
@@ -135,6 +135,7 @@ export async function executeProposeRepair(args: ProposeRepairArgs): Promise<Too
|
||||
execSync(`git apply --check --whitespace=nowarn "${tmpPatch}"`, {
|
||||
cwd: root,
|
||||
stdio: 'pipe',
|
||||
encoding: 'utf8',
|
||||
});
|
||||
} catch (checkErr: any) {
|
||||
const details = String(checkErr?.stderr || checkErr?.stdout || checkErr?.message || 'unknown').trim();
|
||||
@@ -257,7 +258,7 @@ export async function applyApprovedRepair(repairId: string): Promise<ApplyRepair
|
||||
|
||||
// Step 1: Final check before apply
|
||||
try {
|
||||
execSync(`git apply --check --whitespace=nowarn "${tmpPatch}"`, { cwd: root, stdio: 'pipe' });
|
||||
execSync(`git apply --check --whitespace=nowarn "${tmpPatch}"`, { cwd: root, stdio: 'pipe', encoding: 'utf8' });
|
||||
} catch (checkErr: any) {
|
||||
const details = String(checkErr?.stderr || checkErr?.message || '').slice(0, 500);
|
||||
repair.status = 'failed';
|
||||
@@ -271,7 +272,7 @@ export async function applyApprovedRepair(repairId: string): Promise<ApplyRepair
|
||||
}
|
||||
|
||||
// Step 2: Apply the patch
|
||||
execSync(`git apply --whitespace=nowarn "${tmpPatch}"`, { cwd: root, stdio: 'pipe' });
|
||||
execSync(`git apply --whitespace=nowarn "${tmpPatch}"`, { cwd: root, stdio: 'pipe', encoding: 'utf8' });
|
||||
repair.status = 'approved';
|
||||
savePendingRepair(repair);
|
||||
|
||||
@@ -307,7 +308,7 @@ export async function applyApprovedRepair(repairId: string): Promise<ApplyRepair
|
||||
const revertPatch = path.join(os.tmpdir(), `smallclaw-repair-revert-${Date.now()}.patch`);
|
||||
try {
|
||||
fs.writeFileSync(revertPatch, repair.patch, 'utf-8');
|
||||
execSync(`git apply --reverse --whitespace=nowarn "${revertPatch}"`, { cwd: root, stdio: 'pipe' });
|
||||
execSync(`git apply --reverse --whitespace=nowarn "${revertPatch}"`, { cwd: root, stdio: 'pipe', encoding: 'utf8' });
|
||||
} catch {
|
||||
// Revert also failed — leave a note
|
||||
repair.buildOutput += '\n\n⚠️ Auto-revert also failed. Source may be in a modified state.';
|
||||
|
||||
+3
-3
@@ -43,7 +43,7 @@ async function convertAudioToWav(
|
||||
outputPath,
|
||||
]);
|
||||
let stderr = '';
|
||||
ffmpeg.stderr.on('data', (d: Buffer) => { stderr += d.toString(); });
|
||||
ffmpeg.stderr.on('data', (d: Buffer) => { stderr += d.toString('utf8'); });
|
||||
ffmpeg.on('close', (code) => {
|
||||
if (code === 0) resolve();
|
||||
else reject(new Error(`ffmpeg exited ${code}: ${stderr}`));
|
||||
@@ -85,8 +85,8 @@ export async function transcribeAudio(
|
||||
const whisper = spawn(config.whisperPath, args);
|
||||
let stdout = '';
|
||||
let stderr = '';
|
||||
whisper.stdout.on('data', (d: Buffer) => { stdout += d.toString(); });
|
||||
whisper.stderr.on('data', (d: Buffer) => { stderr += d.toString(); });
|
||||
whisper.stdout.on('data', (d: Buffer) => { stdout += d.toString('utf8'); });
|
||||
whisper.stderr.on('data', (d: Buffer) => { stderr += d.toString('utf8'); });
|
||||
whisper.on('close', (code) => {
|
||||
if (code !== 0) {
|
||||
reject(new Error(`whisper-cli exited ${code}: ${stderr.slice(0, 500)}`));
|
||||
|
||||
+2
-2
@@ -49,7 +49,7 @@ export async function synthesizeSpeech(text: string): Promise<Buffer> {
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
const piper = spawn(config.piperPath, piperArgs);
|
||||
let stderr = '';
|
||||
piper.stderr.on('data', (d: Buffer) => { stderr += d.toString(); });
|
||||
piper.stderr.on('data', (d: Buffer) => { stderr += d.toString('utf8'); });
|
||||
piper.stdin.write(truncatedText);
|
||||
piper.stdin.end();
|
||||
piper.on('close', (code) => {
|
||||
@@ -68,7 +68,7 @@ export async function synthesizeSpeech(text: string): Promise<Buffer> {
|
||||
oggPath,
|
||||
]);
|
||||
let stderr = '';
|
||||
ffmpeg.stderr.on('data', (d: Buffer) => { stderr += d.toString(); });
|
||||
ffmpeg.stderr.on('data', (d: Buffer) => { stderr += d.toString('utf8'); });
|
||||
ffmpeg.on('close', (code) => {
|
||||
if (code === 0) resolve();
|
||||
else reject(new Error(`ffmpeg exited ${code}: ${stderr}`));
|
||||
|
||||
Reference in New Issue
Block a user