0a97324f1b
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>
164 lines
9.3 KiB
TypeScript
164 lines
9.3 KiB
TypeScript
import * as fs from 'fs';
|
|
import * as path from 'path';
|
|
import { logError } from '../../utils';
|
|
import { extractPriorityPreviewFiles } from './projectEvidence';
|
|
|
|
/**
|
|
* "프로젝트 지식 (project knowledge overview)" 문서 빌드 + 디스크 쓰기.
|
|
*
|
|
* 흐름:
|
|
* 1) buildProjectKnowledgeMarkdown — localPathContext 를 받아 표준화된 Markdown
|
|
* overview 본문 생성 (pure).
|
|
* 2) writeProjectKnowledgeRecord — 그 본문을 `docs/records/<project>/development/`
|
|
* 아래에 일자/슬러그 파일명으로 저장.
|
|
* 3) buildProjectKnowledgeFallbackAnswer — 모델이 "추가 정보 필요" 류 회피 답변을
|
|
* 낼 때 덮어씌울 채팅용 답변 (markdown 초안 포함).
|
|
*
|
|
* Why one module: 셋 다 동일 helper (`getProjectDisplayName`, `extractPriority...`,
|
|
* Path 파싱) 를 공유하고, 동일 사용 흐름 (knowledge 작성 turn) 의 일부라서 묶어
|
|
* 두는 게 god-file 다이어트 + 응집도 모두에 유리.
|
|
*
|
|
* Note: writeProjectKnowledgeRecord 는 fs I/O 가 들어가지만 transactionManager
|
|
* 가 필요 없는 *append-only 신규 파일 생성* 경로 (덮어쓸 가능성 거의 0). 그래서
|
|
* 별도 transactional 처리 없이 pure-ish 모듈에 함께 둠.
|
|
*/
|
|
|
|
/** `ConnectAI` 디렉토리는 사용자가 `Astra` 로 부르므로 표시명 alias. 그 외는 그대로. */
|
|
export function getProjectDisplayName(projectPath: string): string {
|
|
const projectName = path.basename(projectPath);
|
|
return /^connectai$/i.test(projectName) ? 'Astra' : projectName;
|
|
}
|
|
|
|
/** localPathContext 의 `Path:` 라인 + tree + priority files 를 표준 markdown 으로 직렬화. */
|
|
export function buildProjectKnowledgeMarkdown(localPathContext: string): string {
|
|
const pathMatch = localPathContext.match(/Path:\s*(.+)/);
|
|
const projectPath = pathMatch?.[1]?.trim() || 'Unknown project path';
|
|
const projectDisplayName = getProjectDisplayName(projectPath);
|
|
const treeMatch = localPathContext.match(/Scanned tree:\n([\s\S]*?)(?:\nPriority file previews:|$)/);
|
|
const treePreview = treeMatch?.[1]?.trim().split('\n').slice(0, 80).join('\n') || '';
|
|
const priorityFiles = extractPriorityPreviewFiles(localPathContext);
|
|
|
|
return [
|
|
`# ${projectDisplayName} Project Knowledge Overview`,
|
|
'',
|
|
`Date: ${new Date().toISOString()}`,
|
|
`Project: ${projectDisplayName}`,
|
|
`Repository: \`${projectPath}\``,
|
|
'',
|
|
'## Purpose',
|
|
`${projectDisplayName}는 VS Code 안에서 로컬 AI 에이전트, Second Brain, 프로젝트 기록, 에이전트 스킬을 연결하는 개발 보조 프로젝트다.`,
|
|
'',
|
|
'## Confirmed Structure',
|
|
'- `src/agent.ts`: 에이전트 실행, 로컬 경로 프리플라이트, Second Brain Trace, 액션 실행 흐름의 중심.',
|
|
'- `src/sidebarProvider.ts`: Webview UI, 브레인/모델/프로젝트 선택, 프롬프트 전달, 기록 UI를 담당.',
|
|
'- `src/features/secondBrainTrace.ts`: Second Brain 검색 결과와 근거 정책을 구성.',
|
|
'- `src/features/projectChronicle/`: 프로젝트 기록을 Markdown으로 관리하는 Chronicle 기능.',
|
|
'- `src/core/`: 큐, 이벤트, 트랜잭션, 오류 처리 등 실행 안정성 계층.',
|
|
'- `tests/`: Second Brain, 로컬 경로 프리플라이트, Chronicle, 보안/트랜잭션 회귀 테스트.',
|
|
'',
|
|
'## Evidence Files',
|
|
...(priorityFiles.length ? priorityFiles.map((file) => `- \`${file}\``) : ['- 확인된 우선 파일 없음']),
|
|
'',
|
|
'## Scanned Tree Excerpt',
|
|
'```text',
|
|
treePreview || '(no scanned tree captured)',
|
|
'```',
|
|
'',
|
|
'## Current Knowledge Gap',
|
|
'- 전체 아키텍처는 파일 구조와 일부 프리뷰 기준으로 파악 가능하지만, 세부 동작 지식은 `src/agent.ts`, `src/sidebarProvider.ts`, `secondBrainTrace.ts`, `projectChronicle` 순서로 심화 분석해 보강해야 한다.',
|
|
'',
|
|
'## Next Records',
|
|
'- `agent.ts` 실행 흐름 상세 분석',
|
|
'- Second Brain Trace 검색 및 근거 정책 분석',
|
|
'- Project Chronicle 기록 생성 흐름 분석',
|
|
].join('\n');
|
|
}
|
|
|
|
/**
|
|
* 프로젝트 지식 markdown 을 `docs/records/<project>/development/<date>_<slug>_…md`
|
|
* 에 저장. Access 안 됐거나 projectPath 추출 실패 시 null. 쓰기 실패는 log 만
|
|
* 남기고 null 반환 (호출자가 fallback path 로 떨어지게).
|
|
*/
|
|
export function writeProjectKnowledgeRecord(
|
|
localPathContext: string,
|
|
): { filePath: string; relativePath: string } | null {
|
|
const pathMatch = localPathContext.match(/Path:\s*(.+)/);
|
|
const projectPath = pathMatch?.[1]?.trim();
|
|
if (!projectPath || !localPathContext.includes('Access: succeeded')) return null;
|
|
|
|
try {
|
|
const projectName = path.basename(projectPath);
|
|
const projectDisplayName = getProjectDisplayName(projectPath);
|
|
const today = new Date().toISOString().slice(0, 10);
|
|
const slug = projectDisplayName.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-|-$/g, '') || 'project';
|
|
const relativePath = path.join('docs', 'records', projectName, 'development', `${today}_${slug}_project_knowledge_overview.md`);
|
|
const filePath = path.join(projectPath, relativePath);
|
|
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
fs.writeFileSync(filePath, buildProjectKnowledgeMarkdown(localPathContext), 'utf8');
|
|
return { filePath, relativePath };
|
|
} catch (error: any) {
|
|
logError('Failed to write project knowledge record.', { error: error?.message || String(error) });
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 모델이 "추가 정보 필요" 류 회피 답변을 낼 때 덮어씌울 채팅용 답변. 사전
|
|
* 작성된 한국어 템플릿 안에 priorityFiles / treePreview / record 경로 만 동적으로
|
|
* 채워 넣는다.
|
|
*/
|
|
export function buildProjectKnowledgeFallbackAnswer(
|
|
localPathContext: string,
|
|
record?: { filePath: string; relativePath: string } | null,
|
|
): string {
|
|
const pathMatch = localPathContext.match(/Path:\s*(.+)/);
|
|
const projectPath = pathMatch?.[1]?.trim() || '제공된 로컬 프로젝트 경로';
|
|
const projectDisplayName = getProjectDisplayName(projectPath);
|
|
const treeMatch = localPathContext.match(/Scanned tree:\n([\s\S]*?)(?:\nPriority file previews:|$)/);
|
|
const treePreview = treeMatch?.[1]?.trim().split('\n').slice(0, 18).join('\n') || '';
|
|
const priorityMatches = extractPriorityPreviewFiles(localPathContext).slice(0, 10);
|
|
const priorityText = priorityMatches.length
|
|
? priorityMatches.map((file) => `- ${file}`).join('\n')
|
|
: '- package.json, src, docs, config 계열 파일을 우선 확인';
|
|
|
|
return [
|
|
'## 간단 요약',
|
|
'맞아요. 이 경우에는 추가 질문으로 멈출 필요 없이, 지금 확인된 로컬 프로젝트 구조를 기준으로 기본 프로젝트 지식을 바로 만들면 됩니다.',
|
|
'',
|
|
'## 기본 지식 생성 방향',
|
|
`대상 프로젝트는 \`${projectPath}\`입니다. 우선 MVP 지식은 “프로젝트 개요 + 주요 모듈 + 확인된 근거 파일 + 다음에 깊게 볼 영역” 형태로 만드는 것이 가장 안전합니다.`,
|
|
'',
|
|
'## 확인된 근거',
|
|
priorityText,
|
|
'',
|
|
treePreview ? `## 확인된 구조 일부\n\`\`\`text\n${treePreview}\n\`\`\`` : '',
|
|
'',
|
|
'## 바로 만들 지식 초안',
|
|
'```markdown',
|
|
`# ${projectDisplayName} Project Knowledge Overview`,
|
|
'',
|
|
'## Purpose',
|
|
`${projectDisplayName}는 VS Code 안에서 로컬 AI 에이전트, Second Brain, 프로젝트 기록, 에이전트 스킬을 연결하는 개발 보조 프로젝트다.`,
|
|
'',
|
|
'## Confirmed Structure',
|
|
'- `src/agent.ts`: 에이전트 실행, 로컬 경로 프리플라이트, Second Brain Trace, 액션 실행 흐름의 중심.',
|
|
'- `src/sidebarProvider.ts`: Webview UI, 브레인/모델/프로젝트 선택, 프롬프트 전달, 기록 UI를 담당.',
|
|
'- `src/features/secondBrainTrace.ts`: Second Brain 검색 결과와 근거 정책을 구성.',
|
|
'- `src/features/projectChronicle/`: 프로젝트 기록을 Markdown으로 관리하는 Chronicle 기능.',
|
|
'- `src/core/`: 큐, 이벤트, 트랜잭션, 오류 처리 등 실행 안정성 계층.',
|
|
'- `tests/`: Second Brain, 로컬 경로 프리플라이트, Chronicle, 보안/트랜잭션 회귀 테스트.',
|
|
'',
|
|
'## Current Knowledge Gap',
|
|
'- 전체 아키텍처는 파일 구조와 일부 프리뷰 기준으로 파악 가능하지만, 세부 동작 지식은 `src/agent.ts`, `src/sidebarProvider.ts`, `secondBrainTrace.ts`, `projectChronicle` 순서로 심화 분석해 보강해야 한다.',
|
|
'',
|
|
'## Recommended Next Record',
|
|
`- \`docs/records/${path.basename(projectPath)}/development/YYYY-MM-DD_${projectDisplayName.toLowerCase()}_project_knowledge_overview.md\``,
|
|
'```',
|
|
'',
|
|
'## 다음 액션',
|
|
record
|
|
? `프로젝트 지식 1번 문서를 생성했습니다: \`${record.filePath}\``
|
|
: '기본값으로는 위 초안을 프로젝트 지식 1번 문서로 저장하고, 그 다음 `agent.ts` 실행 흐름 지식을 별도 문서로 쪼개는 것이 좋습니다.',
|
|
].filter(Boolean).join('\n');
|
|
}
|