docs: record 2026-08-22 session upgrades in memo
This commit is contained in:
@@ -330,3 +330,184 @@ handler와 preview 양쪽의 `occurrences === 0` 경로에 적용. 기존 "not f
|
||||
- LSP 실서버 통합 테스트 (실제 tsserver/pyright 띄워서 검증)
|
||||
- task store 영속화 (세션에 task 저장)
|
||||
- 멘션 피커 열린 상태에서 Escape 인터럽트 우선순위 조정(엣지 케이스)
|
||||
|
||||
---
|
||||
|
||||
## 2026-08-21 세션: 마우스 개선, 병렬 툴 실행 검증, 드래그 복사, 색상 조정
|
||||
|
||||
시작점: `dfaf8d1`. 검증: build ✓ · **303 tests** 통과.
|
||||
|
||||
### 마우스 스크롤/선택 — Claude Code 스타일로 개선 (e3520b8에서 이어서)
|
||||
|
||||
**이전 상태**: `/mouse on` 해야 휠 작동, 마우스 모드 켜면 터미널 텍스트 선택 불가.
|
||||
|
||||
**변경**:
|
||||
- 마우스 모드 **기본 ON** (`?1002h` 버튼+드래그 추적)
|
||||
- Shift+클릭/드래그: 터미널 네이티브 텍스트 선택 동작
|
||||
- `mouseInput.ts`: SGR-1006 전체 파싱 (버튼, 좌표, 누름/해제, Shift/Meta/Ctrl 수정키)
|
||||
- `logicalButton()` 내보내기 추가
|
||||
- `/mouse` 명령 메시지 업데이트
|
||||
|
||||
### 마우스 드래그로 카피 — 인앱 텍스트 선택 + OSC 52 클립보드
|
||||
|
||||
**추가 구현**:
|
||||
- `selectionStart`/`selectionEnd` 상태로 드래그 범위 추적 (1-based content row)
|
||||
- 왼쪽 클릭: 선택 시작, 드래그: 범위 갱신, 릴리즈: 선택 텍스트를 `extractSelectionText()`로 추출
|
||||
- `extractSelectionText()`: HistoryItem에서 plain text 추출, row 범위로 자르기
|
||||
- 릴리즈 시 `copyToClipboard()` (OSC 52) 호출 + "Copied N line(s)" 노티스
|
||||
- Shift+클릭/드래그는 기존대로 터미널 네이티브 선택으로 패스스루
|
||||
|
||||
### 병렬 툴 실행 검증
|
||||
|
||||
**`runToolBatch` 디버그 로그 추가**:
|
||||
- `[runToolBatch] N tool(s): parallel|sequential | tool1, tool2...` 형식으로 stderr 출력
|
||||
- 병렬 테스트 2개 추가 (loop.test.ts):
|
||||
- "runs multiple read-only tools in parallel": 3개 read_file 200ms씩 → 병렬 실행 확인
|
||||
- "runs mixed read+write tool calls sequentially": read_file + edit_file → 순차 실행 확인 (305ms)
|
||||
|
||||
**결과**: 클라우드 모델에서 read-only 툴은 `Promise.all` 병렬 실행, mutating 툴 섞이면 순차. 로컬 모델은 보통 툴콜 1개씩만 보내서 병렬의 이점을 못 누름.
|
||||
|
||||
### 100 리밋 iteration 검토
|
||||
|
||||
- `DEFAULT_MAX_ITERATIONS = 100` (이전 50에서 상향)
|
||||
- `locode config set maxIterations <number>`로 조절 가능
|
||||
- 출력이 띄엄띄엄한 원인: 모델이 툴콜 1개씩만 보내서 매 요청마다 왕복 시간 + 컨텍스트 증가
|
||||
|
||||
### `gateAndRun` 에러 로깅 추가
|
||||
|
||||
- `RESOLVE ERROR`: 툴 인자 파싱/검증 실패 시 stderr 로그
|
||||
- `RUN ERROR`: 툴 실행 중 에러 시 stderr 로그
|
||||
|
||||
### DiffView 삭제 라인 색상 조정
|
||||
|
||||
- `DIFF_REMOVE_HEX`: `#f85149` (붉은색) → `#e8904e` (주황색)
|
||||
- 어두운 터미널 배경에서 가독성 개선
|
||||
|
||||
### 파일 인코딩 정리
|
||||
- `loop.ts`, `loop.test.ts`, `App.tsx` CRLF→LF 변환 (`sed -i 's/\r$//'`)
|
||||
|
||||
---
|
||||
|
||||
## 2026-08-22 세션: 15개 업그레이드 (시스템 프롬프트, 멀티라인, /undo, thinking, 성능 등)
|
||||
|
||||
시작점: `5c3fcfd`. 종료점: `5065990`. 검증: typecheck ✓ · build 289.56 KB · **322 tests** 통과 (시작 303 → +19).
|
||||
|
||||
### 커밋
|
||||
|
||||
| # | 항목 | 난이도 | 효과 | 로컬 특화 |
|
||||
|---|---|:---:|:---:|:---:|
|
||||
| 1 | 시스템 프롬프트 대폭 강화 | 중 | 대 | ★★★ |
|
||||
| 2 | 멀티라인 입력 (Shift+Enter) + 브래킷 페이스트 | 중 | 대 | |
|
||||
| 3 | `/undo` 명령 — 마지막 턴 롤백 | 중 | 대 | |
|
||||
| 4 | `/dashboard` 비용/지연 | — | — | 이미 구현됨 |
|
||||
| 5 | 컨텍스트 사용률 진행 바 | — | — | 이미 구현됨 |
|
||||
| 6 | 추론(thinking) 토큰 지원 | 중 | 대 | ★★ |
|
||||
| 7 | `@` 멘션 퍼지 매칭 + 캐시 TTL | 하 | 중 | |
|
||||
| 8 | readFile 바이너리 가드 + 대용량 보호 | 하 | 대 | |
|
||||
| 9 | writeFile 원자 쓰기 (temp→rename) | 하 | 대 | |
|
||||
| 10 | bash 문자열 누적 O(n²)→O(n) | 하 | 중 | |
|
||||
| 11 | estimateTokens 정규식 고속화 | 하 | 중 | ★ |
|
||||
| 12 | handleCompletedMessage any→Record | 하 | 품질 | |
|
||||
| 13 | 세션 복원 시 권한 상태 보존 | 중 | 중 | |
|
||||
| 14 | 컨텍스트 윈도우 병렬 감지 | 하 | 중 | ★ |
|
||||
| 15 | 스트리밍 텍스트 누적 O(n²)→O(n) | 하 | 중 | |
|
||||
|
||||
### 상세
|
||||
|
||||
#### #1 시스템 프롬프트 대폭 강화 (`systemPrompt.ts`)
|
||||
|
||||
기존 22줄(5개 제네릭 가이드) → 100줄+ 구조화된 프롬프트:
|
||||
- **도구 분류**: Read-only / Mutating (requires confirmation) 그룹별 나열
|
||||
- **핵심 원칙 7개**: inspect before answering, prefer small edits, one tool per response in fallback, preserve existing style, keep answers concise, recovery over retry, respect confirmation
|
||||
- **도구 사용 가이드**: 각 도구별 "use when..." 지시 (read_file, edit_file, bash, agent, task 등)
|
||||
- **로컬 모델 지침**: 작은 컨텍스트 윈도우, 툴콜 불안정성, 빈 응답 대응, 출력 길이 제한
|
||||
- **안전 가이드**: .git 수정 금지, 대규모 삭제 시 확인, bash 읽기 선호
|
||||
- **서브에이전트 프롬프트**: `buildSystemPrompt` 재사용으로 자동 적용
|
||||
- **테스트**: 12개 신규 (systemPrompt.test.ts)
|
||||
|
||||
#### #2 멀티라인 입력 + 브래킷 페이스트 (`ChatInput.tsx`)
|
||||
|
||||
- **Shift+Enter**: 줄바꿈 삽입 (기존 Enter=제출 유지)
|
||||
- **multiline 모드**: 텍스트에 `\n` 포함 시 Enter→줄바꿈, Ctrl+Enter→강제 제출
|
||||
- **브래킷 페이스트** (`\x1b[200~`…`\x1b[201~`): 터미널에서 붙여넣기 시 여러 줄 그대로 삽입
|
||||
- **CRLF→LF 변환**: 붙여넣은 텍스트의 `\r\n`을 `\n`으로 정규화
|
||||
- `useCallback`으로 `maybeHandlePaste` 최적화, `pasteBufferRef`/`inPasteRef`로 청크 버퍼링
|
||||
|
||||
#### #3 `/undo` 명령 (`session.ts`, `App.tsx`, `HistoryItemView.tsx`)
|
||||
|
||||
- `undoLastTurn(session)`: 마지막 user 메시지부터 끝까지 제거, 컨텍스트 토큰 재계산
|
||||
- 파일시스템 변경은 롤백 안 함 (soft undo)
|
||||
- 제거된 메시지 수 반환 → "Undid last turn (removed N messages)"
|
||||
- `/undo` 슬래시 명령 + 도움말에 추가
|
||||
- **테스트**: 7개 (session.test.ts) — no user messages, 단일 턴, 툴결과 포함, 이전 턴 보존 등
|
||||
|
||||
#### #6 추론(thinking) 토큰 지원 (`events.ts`, `loop.ts`, `App.tsx`, `types.ts`, `HistoryItemView.tsx`)
|
||||
|
||||
- `AgentEvent`에 `thinking_delta` / `thinking_done` 이벤트 추가
|
||||
- 스트리밍 루프에서 `delta.reasoning_content` 캡처 (DeepSeek, QwQ 등)
|
||||
- `fullThinking` 누적 → `thinking_done` 이벤트로 방출
|
||||
- UI: dimmed 보더 + "Thinking:" 레이블로 렌더링
|
||||
- `itemToLines`에 thinking 종류 추가 (선택 텍스트)
|
||||
|
||||
#### #7 @ 멘션 퍼지 매칭 (`ChatInput.tsx`)
|
||||
|
||||
- **퍼지 매치**: `fuzzyMatch()` — 정확한 부분문자열 매치 우선, 실패 시 문자 순서 매치 (예: "ut" → "utils/")
|
||||
- **정렬**: 정확 매치 우선, 그 다음 길이순
|
||||
- **캐시 TTL**: `filesCachedAt` 상태 추가, 5분 후 리글로브
|
||||
- **`.gitignore` 준수**: `fast-glob`의 `gitignore: true` 옵션 (타입 제한으로 제외, `ignore`로 대체)
|
||||
|
||||
#### #8 readFile 바이너리 가드 (`readFile.ts`)
|
||||
|
||||
- `MAX_FILE_SIZE = 10 MB` — `stat()` 사전 체크, 초과 시 에러 메시지
|
||||
- `BINARY_EXTENSIONS` Set (30+ 확장자) — 확장자 기반 바이너리 감지
|
||||
- null-byte 휴리스틱 (8KB 스캔) — 확장자 없는 바이너리 파일 감지
|
||||
- `content.split("\n")` → `content.split(/\r?\n/)` — CRLF 호환
|
||||
|
||||
#### #9 writeFile 원자 쓰기 (`writeFile.ts`)
|
||||
|
||||
- `randomUUID()`로 임시 파일명 생성 → `writeFile` → `rename`
|
||||
- 실패 시 `unlink`로 임시 파일 정리
|
||||
- `readExisting` catch에서 `err.code === 'ENOENT'` 명시적 체크 (다른 에러는 재throw)
|
||||
|
||||
#### #10 bash 문자열 누적 (`bash.ts`)
|
||||
|
||||
- `let stdout = ""` → `const stdoutChunks: string[] = []`
|
||||
- `stdout += d.toString()` → `stdoutChunks.push(d.toString())`
|
||||
- 최종 `stdoutChunks.join("")` / `stderrChunks.join("")`
|
||||
- O(n²) 문자열 누적 → O(n) 배열 push + join
|
||||
|
||||
#### #11 estimateTokens 정규식 고속화 (`tokens.ts`)
|
||||
|
||||
- per-character `weightedChars` 루프 → 정규식 벌크 카운팅:
|
||||
- CJK: `/[\u3040-\u30ff\u3400-\u9fff\uac00-\ud7af\u1100-\u11ff]/gu` → ×2.4
|
||||
- Dense symbols: `/[!-\/:-@[-\`{-~]/g` → ×1.15
|
||||
- 나머지: ×1
|
||||
- `isCjk()` / `isDenseSymbol()` 헬퍼 제거
|
||||
|
||||
#### #12 handleCompletedMessage 타입 (`loop.ts`)
|
||||
|
||||
- `message: any` → `message: Record<string, unknown>`
|
||||
- 런타임 동작은 동일 (속성 접근 시 any와 호환)
|
||||
|
||||
#### #13 세션 복원 권한 보존 (`session.ts`, `sessionStore.ts`)
|
||||
|
||||
- `SessionRecord`에 `allowedTools?: string[]` 선택적 필드 추가
|
||||
- `toSessionRecord()`: `session.permissions.listAllowed()` 저장
|
||||
- `createSessionFromRecord()`: `record.allowedTools` 복원 → `session.permissions.allowForSession()`
|
||||
- `/perm`에서 "이 세션에서 허용"한 도구가 세션 재개 후에도 유지
|
||||
|
||||
#### #14 컨텍스트 윈도우 병렬 감지 (`contextWindow.ts`)
|
||||
|
||||
- `detectContextWindow`: 순차 `await Ollama → await LM Studio` → `Promise.allSettled([Ollama, LM Studio])`
|
||||
- 감지 지연 반감 (Ollama가 안 돌아도 LM Studio 결과 즉시 사용)
|
||||
- `ollama.status === "fulfilled" && ollama.value !== null` 패턴으로 null 결과 필터링
|
||||
|
||||
#### #15 스트리밍 텍스트 누적 O(n²)→O(n) (`loop.ts`)
|
||||
|
||||
- `fullText += delta.content` → `textChunks.push(delta.content)`
|
||||
- 스트림 루프 후 `fullText = textChunks.join("")`
|
||||
- 에러 핸들러에서도 `textChunks.join("")`로 부분 텍스트 복구
|
||||
|
||||
### 인코딩 메모
|
||||
- `session.ts`, `App.tsx`, `HistoryItemView.tsx` CRLF → Python 바이너리 편집으로 교체
|
||||
- `ChatInput.tsx`, `systemPrompt.ts` LF → write_file/edit_file 사용
|
||||
|
||||
Reference in New Issue
Block a user