Files
connectai/tests/wikiSave.test.ts
T
koriweb 5feacb4799 v2.2.308~310: Standing Rules + 조사 파이프라인 + LM Studio 추론 노출 수리
v2.2.308 — Standing Rules (Correction Loop ④): 행동/스타일 교정의 세션 영속화
- 행동 지적 감지("또 ~하네", "하지 말라고 했잖아" 등 5종) → LLM 이 명령형 규칙으로
  정규화 → .astra/growth/standing-rules.json 즉시 저장 → 매 턴 보호 구역 주입.
  self-reflection 이 컨텍스트 창(단기 기억)에 갇혀 새 세션에서 증발하던 문제 해결.
- 중복 지적은 hits 증가(토큰 자카드), 상한 10개 초과 시 자동 은퇴, 재지적 시 부활.
- "Astra: 상시 행동 규칙" 커맨드 — 활성/은퇴 규칙 + 실제 주입 블록 열람(도달 증거).

v2.2.309 — 조사 파이프라인: 파일명만 보고 상상하는 헛조사 4중 차단
- <investigate_files path focus> 액션: 폴더의 텍스트 파일을 코드가 강제 정독해
  파일별 노트 주입(Map-Reduce). 내용 해시 캐시(.astra/cache/investigate)로 재조사
  시 재사용 — 온디맨드 지식화.
- 조사 증거 게이트(행동 제약) + Hollow Investigation 감지(list만 하고 read 0회로
  파일 서술 시 경고 footer — continuation 경로 포함) + actionStats turn 추적.
- g1nation.investigationModel: 조사형 요청만 상위 모델(예: claude-code:sonnet) 라우팅.

v2.2.310 — LM Studio LSEP 합성 추론 구분자 처리
- 일부 모델 조합에서 추론이 여는 마커 없이 content 앞에 흐르고
  __LM_STUDIO_INTERNAL_LSEP_SYNTHETIC_REASONING_END_<hex>__ 로만 경계 표시 →
  생각 과정 전체가 채팅에 노출되던 문제.
- LiveReasoningFilter: 마커 감지 시 streamReplace 신호로 화면 즉시 리셋(토큰 분절
  대응 holdback 포함), sanitizeAssistantContent: 마커 이전 추론 최종 제거(이중 방어).

기타: tests/wikiSave.test.ts 상대경로 테스트 Windows 호환 수정(드라이브 문자).
검증: 전체 테스트 926건 통과 (신규 39건: standingRules 15 + investigationPipeline 16 + LSEP 8).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 18:18:49 +09:00

87 lines
3.6 KiB
TypeScript

/**
* v2.2.273 — 지식 문서 로컬 저장 (순수 로직: 파일명 안전화 + 저장 폴더 우선순위).
*/
import * as path from 'path';
import { sanitizeWikiFileName, pickWikiDir } from '../src/features/datacollect/wikiSave';
describe('sanitizeWikiFileName', () => {
test('금지 문자 치환 + .md 보장', () => {
const f = sanitizeWikiFileName('회의록 a/b:c*d?e<f>g|h 2026-07-03');
expect(f).not.toMatch(/[\\/:*?"<>|]/);
expect(f.endsWith('.md')).toBe(true);
expect(f).toContain('회의록');
});
test('빈 제목 → untitled, 120자 캡', () => {
expect(sanitizeWikiFileName('')).toMatch(/^untitled_\d+\.md$/);
expect(sanitizeWikiFileName('가'.repeat(300)).length).toBeLessThanOrEqual(124);
});
test('.md 중복 방지', () => {
expect(sanitizeWikiFileName('문서.md')).toBe('문서.md');
});
});
describe('pickWikiDir — 저장 폴더 우선순위', () => {
const abs = path.resolve('E:/커스텀/위키');
test('① 설정 절대경로 최우선', () => {
const r = pickWikiDir(abs, 'E:/brain', 'E:/ws');
expect(r).toEqual({ dir: abs, label: '설정 폴더' });
});
test('② 설정 없으면 두뇌/Datacollect_Wiki', () => {
const r = pickWikiDir('', 'E:/brain', 'E:/ws');
expect(r!.label).toBe('두뇌');
expect(r!.dir).toBe(path.join('E:/brain', 'Datacollect_Wiki'));
});
test('③ 두뇌 없으면 워크스페이스/.astra/wiki', () => {
const r = pickWikiDir('', '', 'E:/ws');
expect(r!.label).toBe('워크스페이스');
expect(r!.dir).toBe(path.join('E:/ws', '.astra', 'wiki'));
});
test('[v2.2.304] 상대경로 설정은 두뇌 루트 기준으로 해석 (이식성)', () => {
const r = pickWikiDir('상대/경로', '/brain', null);
expect(r!.label).toBe('설정 폴더(두뇌 기준)');
expect(r!.dir.replace(/\\/g, '/')).toContain('/brain/상대/경로');
});
test('[v2.2.304] ../ 상대경로로 두뇌 밖 형제 폴더도 지정 가능', () => {
const r = pickWikiDir('../../Premium/자료', '/Wiki/10_Wiki/Topics', null);
// Windows에서는 path.resolve가 드라이브 문자를 붙이므로(E:/Wiki/...) 끝부분만 검증
expect(r!.dir.replace(/\\/g, '/')).toMatch(/\/Wiki\/Premium\/자료$/);
});
test('상대경로인데 두뇌도 없으면 다음 후보(워크스페이스)로', () => {
const r = pickWikiDir('상대/경로', '', '/ws');
expect(r!.label).toBe('워크스페이스');
});
test('④ 전부 없으면 null', () => {
expect(pickWikiDir('', '', null)).toBeNull();
});
});
describe('pickWikiDir — 이메일 지식 문서 별도 관리 (kind=email)', () => {
test('기본 폴더가 Email_Wiki 로 분리 — 일반(Datacollect_Wiki)과 다름', () => {
const email = pickWikiDir('', 'E:/brain', 'E:/ws', 'email');
const general = pickWikiDir('', 'E:/brain', 'E:/ws', 'general');
expect(email!.dir).toBe(path.join('E:/brain', 'Email_Wiki'));
expect(general!.dir).toBe(path.join('E:/brain', 'Datacollect_Wiki'));
expect(email!.dir).not.toBe(general!.dir);
});
test('이메일 전용 설정 경로가 최우선', () => {
const abs = path.resolve('E:/이메일위키');
const r = pickWikiDir(abs, 'E:/brain', 'E:/ws', 'email');
expect(r).toEqual({ dir: abs, label: '설정 폴더' });
});
test('두뇌 없으면 워크스페이스 .astra/wiki/email', () => {
const r = pickWikiDir('', '', 'E:/ws', 'email');
expect(r!.dir).toBe(path.join('E:/ws', '.astra', 'wiki', 'email'));
});
});