[P-Reinforce] Fix encoding, rebuild agent engine, and optimize looping
This commit is contained in:
+42
-33
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "connect-ai-lab",
|
||||
"displayName": "Connect AI",
|
||||
"description": "100% 로컬 AI 코딩 에이전트 — 파일 생성, 코드 편집, 터미널 실행을 오프라인으로. Ollama + Gemma/Llama/DeepSeek 지원.",
|
||||
"name": "g1nation",
|
||||
"displayName": "G1nation",
|
||||
"description": "100% local AI coding agent for VS Code. Create files, edit code, run commands, and work offline with Ollama or LM Studio.",
|
||||
"version": "2.2.15",
|
||||
"publisher": "connectailab",
|
||||
"license": "MIT",
|
||||
@@ -28,40 +28,38 @@
|
||||
"offline",
|
||||
"agent",
|
||||
"code-generation",
|
||||
"connect-ai-lab",
|
||||
"g1nation",
|
||||
"copilot"
|
||||
],
|
||||
"activationEvents": [
|
||||
"*"
|
||||
],
|
||||
"activationEvents": [],
|
||||
"main": "./out/extension.js",
|
||||
"contributes": {
|
||||
"commands": [
|
||||
{
|
||||
"command": "connect-ai-lab.newChat",
|
||||
"title": "Connect AI: New Chat",
|
||||
"command": "g1nation.newChat",
|
||||
"title": "G1nation: New Chat",
|
||||
"icon": "$(add)"
|
||||
},
|
||||
{
|
||||
"command": "connect-ai-lab.exportChat",
|
||||
"title": "Connect AI: Export Chat as Markdown"
|
||||
"command": "g1nation.exportChat",
|
||||
"title": "G1nation: Export Chat as Markdown"
|
||||
},
|
||||
{
|
||||
"command": "connect-ai-lab.explainSelection",
|
||||
"title": "Connect AI: Explain Selected Code"
|
||||
"command": "g1nation.explainSelection",
|
||||
"title": "G1nation: Explain Selected Code"
|
||||
},
|
||||
{
|
||||
"command": "connect-ai-lab.focusChat",
|
||||
"title": "Connect AI: Focus Chat Input"
|
||||
"command": "g1nation.focusChat",
|
||||
"title": "G1nation: Focus Chat Input"
|
||||
},
|
||||
{
|
||||
"command": "connect-ai-lab.showBrainNetwork",
|
||||
"title": "Connect AI: Show Brain Topology 🧠"
|
||||
"command": "g1nation.showBrainNetwork",
|
||||
"title": "G1nation: Show Brain Topology"
|
||||
}
|
||||
],
|
||||
"keybindings": [
|
||||
{
|
||||
"command": "connect-ai-lab.focusChat",
|
||||
"command": "g1nation.focusChat",
|
||||
"key": "cmd+l",
|
||||
"mac": "cmd+l"
|
||||
}
|
||||
@@ -69,7 +67,7 @@
|
||||
"menus": {
|
||||
"editor/context": [
|
||||
{
|
||||
"command": "connect-ai-lab.explainSelection",
|
||||
"command": "g1nation.explainSelection",
|
||||
"when": "editorHasSelection",
|
||||
"group": "1_modification"
|
||||
}
|
||||
@@ -78,43 +76,54 @@
|
||||
"viewsContainers": {
|
||||
"activitybar": [
|
||||
{
|
||||
"id": "connect-ai-lab-sidebar",
|
||||
"title": "Connect AI",
|
||||
"id": "g1nation-sidebar",
|
||||
"title": "G1nation",
|
||||
"icon": "$(hubot)"
|
||||
}
|
||||
]
|
||||
},
|
||||
"views": {
|
||||
"connect-ai-lab-sidebar": [
|
||||
"g1nation-sidebar": [
|
||||
{
|
||||
"type": "webview",
|
||||
"id": "connect-ai-lab-v2-view",
|
||||
"name": "Chat"
|
||||
"id": "g1nation-v2-view",
|
||||
"name": "Chat",
|
||||
"icon": "assets/icon.png"
|
||||
}
|
||||
]
|
||||
},
|
||||
"configuration": {
|
||||
"title": "Connect AI",
|
||||
"title": "G1nation",
|
||||
"properties": {
|
||||
"connectAiLab.ollamaUrl": {
|
||||
"g1nation.ollamaUrl": {
|
||||
"type": "string",
|
||||
"default": "http://127.0.0.1:11434",
|
||||
"description": "🤖 AI 서버 주소 (보통 자동으로 잡히니 건드리지 않아도 됩니다)"
|
||||
"description": "Base URL for Ollama or LM Studio. Default: http://127.0.0.1:11434"
|
||||
},
|
||||
"connectAiLab.defaultModel": {
|
||||
"g1nation.defaultModel": {
|
||||
"type": "string",
|
||||
"default": "gemma4:e2b",
|
||||
"description": "🧠 사용할 AI 모델 이름 (예: gemma4:e2b, llama3.3, deepseek-r1)"
|
||||
"description": "Default model name to use for chat requests."
|
||||
},
|
||||
"connectAiLab.requestTimeout": {
|
||||
"g1nation.requestTimeout": {
|
||||
"type": "number",
|
||||
"default": 300,
|
||||
"description": "⏱ AI 응답 대기 시간 (초, 기본 300초 = 5분)"
|
||||
"description": "Request timeout in seconds. Default: 300"
|
||||
},
|
||||
"connectAiLab.localBrainPath": {
|
||||
"g1nation.localBrainPath": {
|
||||
"type": "string",
|
||||
"default": "",
|
||||
"description": "📁 내 지식 폴더 경로 — 내 PC의 특정 폴더(예: 바탕화면/MyBrain)를 지정하면, 그 안의 .md 파일들이 AI의 지식이 됩니다. 비워두면 기본 폴더를 자동 생성합니다."
|
||||
"description": "Folder path for your local Second Brain knowledge base. Leave empty to use the default folder."
|
||||
},
|
||||
"g1nation.secondBrainRepo": {
|
||||
"type": "string",
|
||||
"default": "",
|
||||
"description": "Optional GitHub repository URL used for Second Brain sync."
|
||||
},
|
||||
"g1nation.autoPushBrain": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Automatically commit and push Second Brain changes after updates."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+101
@@ -0,0 +1,101 @@
|
||||
/**
|
||||
* ============================================================
|
||||
* Centralized Configuration (중앙 집중식 설정 관리)
|
||||
*
|
||||
* 모든 환경 설정(모델 이름, API 엔드포인트, 타임아웃, 보안 정책 등)
|
||||
* 을 한 곳에서 관리합니다. Single Source of Truth 원칙 적용.
|
||||
* ============================================================
|
||||
*/
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
import * as os from 'os';
|
||||
import * as path from 'path';
|
||||
|
||||
// ─── VS Code 설정에서 읽어오는 값 ───
|
||||
export function getConfig(): IAgentConfig {
|
||||
const cfg = vscode.workspace.getConfiguration('g1nation');
|
||||
return {
|
||||
ollamaBase: cfg.get<string>('ollamaUrl', 'http://127.0.0.1:11434'),
|
||||
defaultModel: cfg.get<string>('defaultModel', 'gemma4:e2b'),
|
||||
maxTreeFiles: cfg.get<number>('maxTreeFiles', 200),
|
||||
timeout: cfg.get<number>('requestTimeout', 300) * 1000,
|
||||
localBrainPath: cfg.get<string>('localBrainPath', '')
|
||||
};
|
||||
}
|
||||
|
||||
// ─── 에이전트 설정 인터페이스 ───
|
||||
export interface IAgentConfig {
|
||||
ollamaBase: string;
|
||||
defaultModel: string;
|
||||
maxTreeFiles: number;
|
||||
timeout: number;
|
||||
localBrainPath: string;
|
||||
}
|
||||
|
||||
// ─── 두뇌 폴더 경로 유틸리티 ───
|
||||
export function getBrainDir(): string {
|
||||
const { localBrainPath } = getConfig();
|
||||
if (localBrainPath && localBrainPath.trim() !== '') {
|
||||
if (localBrainPath.startsWith('~/')) {
|
||||
return path.join(os.homedir(), localBrainPath.substring(2));
|
||||
}
|
||||
return localBrainPath.trim();
|
||||
}
|
||||
return path.join(os.homedir(), '.g1nation-brain');
|
||||
}
|
||||
|
||||
export function isBrainDirExplicitlySet(): boolean {
|
||||
const { localBrainPath } = getConfig();
|
||||
return !!(localBrainPath && localBrainPath.trim() !== '');
|
||||
}
|
||||
|
||||
// ─── 보안 정책 (Security Policy) ───
|
||||
export const SECURITY_POLICY = {
|
||||
// 허용된 터미널 명령어 프리픽스 (Whitelist)
|
||||
allowedCommandPrefixes: [
|
||||
'npm', 'yarn', 'pnpm', 'npx',
|
||||
'node', 'ts-node',
|
||||
'git',
|
||||
'python', 'python3', 'pip', 'pip3',
|
||||
'docker', 'docker-compose',
|
||||
'ls', 'dir', 'cat', 'type',
|
||||
'echo', 'print',
|
||||
'cargo', 'go', 'rustc',
|
||||
'java', 'javac', 'mvn', 'gradle',
|
||||
'flutter', 'dart', 'pub',
|
||||
'webpack', 'vite', 'esbuild', 'parcel',
|
||||
'jest', 'mocha', 'vitest', 'cypress',
|
||||
'tsc', 'vue-tsc',
|
||||
],
|
||||
|
||||
// 절대 실행 금지 명령어 (Blacklist)
|
||||
forbiddenCommands: [
|
||||
'rm -rf', 'rm-rf', 'del /f', 'format',
|
||||
'mkfs', 'dd if=', ':(){ :|:& };:',
|
||||
'wget http', 'curl http', 'sudo',
|
||||
'chmod 777', 'chown root',
|
||||
],
|
||||
|
||||
// 민감한 파일 패턴 (파일 생성/수정 시 경고)
|
||||
sensitiveFilePatterns: [
|
||||
'.env', '.env.*',
|
||||
'id_rsa', 'id_ed25519',
|
||||
'.gitconfig', '.npmrc', '.pypirc',
|
||||
'credentials.json', 'service-account.json',
|
||||
],
|
||||
|
||||
// 파일 생성 시 최대 크기 (bytes)
|
||||
maxFileSize: 10 * 1024 * 1024, // 10MB
|
||||
|
||||
// 맥락 파일 최대 개수
|
||||
maxContextFiles: 200,
|
||||
};
|
||||
|
||||
// ─── 시스템 프롬프트 상수 ───
|
||||
export const MAX_CONTEXT_SIZE = 12_000;
|
||||
|
||||
export const EXCLUDED_DIRS = new Set([
|
||||
'node_modules', '.git', '.vscode', 'out', 'dist', 'build',
|
||||
'.next', '.cache', '__pycache__', '.DS_Store', 'coverage',
|
||||
'.turbo', '.nuxt', '.output', 'vendor', 'target'
|
||||
]);
|
||||
+668
-903
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,100 @@
|
||||
/**
|
||||
* ============================================================
|
||||
* Service Interfaces (서비스 인터페이스 정의)
|
||||
*
|
||||
* 각 서비스(Agent, Brain, FileSystem 등)의 추상화 인터페이스를 정의합니다.
|
||||
* 의존성 주입(DI)과 단위 테스트를 위해 필수적입니다.
|
||||
* ============================================================
|
||||
*/
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
|
||||
// ─── 에이전트 서비스 인터페이스 ───
|
||||
export interface IAgentService {
|
||||
/**
|
||||
* LLM에 프롬프트를 보내고 스트리밍 응답을 가져옴
|
||||
*/
|
||||
chat(prompt: string, context: string, model?: string): Promise<AsyncGenerator<string>>;
|
||||
|
||||
/**
|
||||
* 터미널 명령어 실행 (보안 정책 적용)
|
||||
*/
|
||||
runCommand(command: string): Promise<{ stdout: string; stderr: string }>;
|
||||
}
|
||||
|
||||
// ─── 파일 시스템 서비스 인터페이스 ───
|
||||
export interface IFileSystemService {
|
||||
/**
|
||||
* 파일 생성
|
||||
*/
|
||||
createFile(filePath: string, content: string): Promise<void>;
|
||||
|
||||
/**
|
||||
* 파일 읽기
|
||||
*/
|
||||
readFile(filePath: string): Promise<string>;
|
||||
|
||||
/**
|
||||
* 파일 수정
|
||||
*/
|
||||
editFile(filePath: string, find: string, replace: string): Promise<void>;
|
||||
|
||||
/**
|
||||
* 파일 삭제
|
||||
*/
|
||||
deleteFile(filePath: string): Promise<void>;
|
||||
|
||||
/**
|
||||
* 디렉토리 목록 조회
|
||||
*/
|
||||
listDirectory(dirPath: string): Promise<string[]>;
|
||||
}
|
||||
|
||||
// ─── 두뇌 서비스 인터페이스 ───
|
||||
export interface IBrainService {
|
||||
/**
|
||||
* 두뇌 폴더 경로 가져오기
|
||||
*/
|
||||
getBrainDir(): string;
|
||||
|
||||
/**
|
||||
* 두뇌 폴더가 명시적으로 설정되었는지 확인
|
||||
*/
|
||||
isBrainDirExplicitlySet(): boolean;
|
||||
|
||||
/**
|
||||
* 두뇌 폴더 내 파일 목록 조회
|
||||
*/
|
||||
getBrainFiles(): Promise<string[]>;
|
||||
|
||||
/**
|
||||
* 두뇌 파일 내용 읽기
|
||||
*/
|
||||
readBrainFile(fileName: string): Promise<string>;
|
||||
}
|
||||
|
||||
// ─── 웹뷰 서비스 인터페이스 ───
|
||||
export interface IWebviewService {
|
||||
/**
|
||||
* 웹뷰에 메시지 전송
|
||||
*/
|
||||
postMessage(message: any): void;
|
||||
|
||||
/**
|
||||
* 웹뷰에서 메시지 수신 핸들러 등록
|
||||
*/
|
||||
onDidReceiveMessage(callback: (message: any) => void): vscode.Disposable;
|
||||
}
|
||||
|
||||
// ─── HTTP 서비스 인터페이스 ───
|
||||
export interface IHttpService {
|
||||
/**
|
||||
* HTTP GET 요청
|
||||
*/
|
||||
get(url: string, options?: any): Promise<any>;
|
||||
|
||||
/**
|
||||
* HTTP POST 요청
|
||||
*/
|
||||
post(url: string, data: any, options?: any): Promise<any>;
|
||||
}
|
||||
Reference in New Issue
Block a user