feat: v2.2.92 → v2.2.158 — god-file 분해 + Stocks feature + 대화 연속성
R56–R59: agent.ts 2731→1529줄 god-file 분해 (25 modules) · attrParsers + LLM 메서드 8개 (callNonStreaming, streamChatOnce 등) · executeActions 415줄 → 8 handler 그룹 (file/run/list/brain/calendar/sheets/tasks) · handlePrompt 1100줄 → 7 phase 모듈 (system prompt + budget + autoContinue 등) R50–R55: extension.ts 1145→349줄 (telegram/settings/provider commands 분리) Stocks feature 신규: /stocks slash command (v2.2.152~158) · .astra/stocks.json 저장소 + Yahoo Finance 현재가 갱신 · 8 키워드 필터 (ROE/성장성/유동성/수익성/영업효율/기술력/안정성/PBR) · Naver 시가총액 페이지 JSON API (m.stock.naver.com) 발굴 · LLM Top 5 매력도 분석 + Telegram 자동 보고서 · KST 09:00/15:00 watcher 자동 모니터링 대화 연속성 (v2.2.150~157): · [PRIOR TURN CONCLUSION] block 으로 직전 결론 anchor · thin follow-up 분류 → boilerplate 헤더 suppression · slash 명령 결과 chatHistory mirror (capture wrapper) · echo/parrot 금지 system prompt rule 기타: /stocks 슬래시 자동완성 dropdown UI, Naver JSON API 전환 (cheerio 제거) Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,73 @@
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import { validatePath } from '../../security';
|
||||
import { FileSystemError } from '../../core/errors';
|
||||
import { HandlerContext } from './types';
|
||||
|
||||
/**
|
||||
* `<create_file>` + `<edit_file>` action handler.
|
||||
*
|
||||
* AI 가 한 턴에 여러 개의 create/edit 태그를 내뱉을 수 있으므로, 각 태그마다
|
||||
* regex 로 잡아서 순서대로 처리한다. validatePath() 로 sandbox 보장 + 매 파일
|
||||
* 쓰기 전에 transactionManager.record() 로 롤백 지점 기록.
|
||||
*/
|
||||
export async function applyFileCreateEditActions(ctx: HandlerContext): Promise<void> {
|
||||
const { aiMessage, rootPath, activeBrainDir, report } = ctx;
|
||||
|
||||
// Action 1: Create File
|
||||
const createRegex = /<create_file\s+path=['"]?([^'"]+)['"]?>([\s\S]*?)<\/create_file>/gi;
|
||||
let match;
|
||||
while ((match = createRegex.exec(aiMessage)) !== null) {
|
||||
const relPath = match[1].trim();
|
||||
const content = match[2].trim();
|
||||
try {
|
||||
const absPath = validatePath(rootPath, relPath);
|
||||
await ctx.transactionManager.record(absPath);
|
||||
|
||||
fs.mkdirSync(path.dirname(absPath), { recursive: true });
|
||||
fs.writeFileSync(absPath, content, 'utf-8');
|
||||
|
||||
report.push(`✅ Created: ${relPath}`);
|
||||
ctx.setFirstCreated(absPath);
|
||||
if (absPath.startsWith(activeBrainDir)) ctx.markBrainModified();
|
||||
} catch (err: any) {
|
||||
throw new FileSystemError(`Failed to create file ${relPath}: ${err.message}`, relPath, err);
|
||||
}
|
||||
}
|
||||
|
||||
// Action 2: Edit File
|
||||
const editRegex = /<edit_file\s+path=['"]?([^'"]+)['"]?>([\s\S]*?)<\/edit_file>/gi;
|
||||
while ((match = editRegex.exec(aiMessage)) !== null) {
|
||||
const relPath = match[1].trim();
|
||||
const editContent = match[2].trim();
|
||||
try {
|
||||
const absPath = validatePath(rootPath, relPath);
|
||||
if (fs.existsSync(absPath)) {
|
||||
await ctx.transactionManager.record(absPath);
|
||||
|
||||
let currentContent = fs.readFileSync(absPath, 'utf-8');
|
||||
const searchMatch = editContent.match(/<search>([\s\S]*?)<\/search>\s*<replace>([\s\S]*?)<\/replace>/i);
|
||||
|
||||
if (searchMatch) {
|
||||
const searchStr = searchMatch[1];
|
||||
const replaceStr = searchMatch[2];
|
||||
if (currentContent.includes(searchStr)) {
|
||||
currentContent = currentContent.replace(searchStr, replaceStr);
|
||||
fs.writeFileSync(absPath, currentContent, 'utf-8');
|
||||
report.push(`📝 Updated: ${relPath}`);
|
||||
} else {
|
||||
report.push(`⚠️ Search string not found in ${relPath}`);
|
||||
}
|
||||
} else {
|
||||
fs.writeFileSync(absPath, editContent, 'utf-8');
|
||||
report.push(`📝 Updated (Full): ${relPath}`);
|
||||
}
|
||||
if (absPath.startsWith(activeBrainDir)) ctx.markBrainModified();
|
||||
} else {
|
||||
report.push(`❌ File not found: ${relPath}`);
|
||||
}
|
||||
} catch (err: any) {
|
||||
throw new FileSystemError(`Failed to edit file ${relPath}: ${err.message}`, relPath, err);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user