v2.2.268-291: /email 통합(브리핑·스캔·워처) + stocks 자동편입·매수알림 + 지식문서·메신저 중앙화
[/email — Gmail + 클래식 Outlook (신규 기능군)]
- 기본 명령: brief(PM 업무 허브 대시보드)·list·read·wikify·reply(Drafts만)·open(Outlook 창 열기)
- Gmail: 자체 OAuth gmail.readonly 스코프 추가 (재연결 1회 필요) / Outlook: COM(PowerShell), 전 계정(Store)·하위 폴더(120개 가드) 수집, To/CC 판별
- 브리핑: 상태 3분류(결정/회신/확인만)·P등급 영향·프로젝트 위험도·Today Focus·오늘 완료 예상·기간 명시 시 표시 범위 제한
- 영속 상태(email_state.json): 회신대기/공넘김 상태머신, 창 밖 미회신 보존, done old N 일괄정리
- 워처: 주기 자동 수집 + 미회신 임계 알림(기본 끔) + 데일리 브리핑 '답할 이메일' 섹션
- 전체 스캔(/email scan): 자동 위키화(회차 15건·레지스트리·파일삭제 감지 재생성)·진행 표시(streamProgress)
- 자동발신 필터 확장(Confluence·AWS·광고·[Notification]) + 라벨 오타 후처리(polishBriefLabels)
[/stocks]
- discover 자동 편입(stocks.json) + 매수권장가 224일선 자동 산출
- 매수사정권 진입 전이 감지 → 텔레그램 1회 알림 (직전신호 추적)
- 버그 수정: '미충족'이 .includes('충족')에 오탐되던 필터 판정
[지식 문서 파이프라인 통일 (wikiFormat/wikiSave)]
- PC 로컬 직접 저장 (NAS 볼륨 미아 문제 해소) — 설정 폴더 → 두뇌 → 워크스페이스
- 이메일 전용 Email_Wiki 분리(email.wikifySavePath) + 봉투(frontmatter) 자동 통일
- 정본 프롬프트 단일 빌더(buildKnowledgeWikiPrompt) — web/email 래퍼화, 템플릿 fetch 일원화
- 이메일 문서 시점 3중 방어: 기준시점 헤더·제목=메일 최신일·날짜 없는 현재형 금지
- docs/WIKI_DOC_PIPELINE.md 개발 규약
[텔레그램 메신저 중앙화 (messageFormat)]
- 단일 렌더러 renderTelegram — 5개 발신 빌더(주식보고·매수시그널·Top5·데일리·미회신) 통일
- 주식 보고 시각 하드코딩 제거(messenger.stocksReportTimes CSV) + 알림 토글 2종
- 설정 패널 '메신저' 탭 신설 · '이메일' 토글 섹션(Gmail/Outlook on/off)
테스트 803개 통과 (이메일 상태머신·CC판별·포맷·매수전이·봉투 등 60+ 신규)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,56 @@
|
||||
/**
|
||||
* v2.2.284 — 텔레그램 중앙 포맷 (renderTelegram / parseTimesCsv).
|
||||
* 위키 포맷처럼 메시지 포맷도 단일 모듈 — 모든 발신 빌더가 이 규약을 공유한다.
|
||||
*/
|
||||
import { renderTelegram, parseTimesCsv, tgWho, tgSubject, tgCut } from '../src/integrations/telegram/messageFormat';
|
||||
|
||||
describe('renderTelegram — 모바일 규약', () => {
|
||||
test('헤더·번호 항목·보조줄·잘림 표기·푸터', () => {
|
||||
const out = renderTelegram({
|
||||
emoji: '📧', title: '답할 이메일', count: 10,
|
||||
sections: [{
|
||||
count: 10, maxItems: 2,
|
||||
items: [
|
||||
{ main: '계약 검토', sub: '김성환 · 2일째' },
|
||||
{ main: '견적 문의', sub: '오실묵 · 1일째' },
|
||||
{ main: '세번째', sub: 'x' },
|
||||
],
|
||||
}],
|
||||
footer: '처리했으면 `/email done O번호`',
|
||||
});
|
||||
expect(out).toContain('📧 *답할 이메일* (10)');
|
||||
expect(out).toContain('1. 계약 검토');
|
||||
expect(out).toContain(' 김성환 · 2일째');
|
||||
expect(out).toContain('… 외 8건'); // count 기준 잘림 표기
|
||||
expect(out).toContain('_처리했으면');
|
||||
expect(out).not.toContain('세번째'); // maxItems 컷
|
||||
});
|
||||
|
||||
test('3,800자 캡', () => {
|
||||
const out = renderTelegram({
|
||||
emoji: 'x', title: 't',
|
||||
sections: [{ lines: Array.from({ length: 300 }, () => 'a'.repeat(40)) }],
|
||||
});
|
||||
expect(out.length).toBeLessThanOrEqual(3810);
|
||||
expect(out).toContain('…(잘림)');
|
||||
});
|
||||
|
||||
test('보조 유틸 — 발신자 괄호 제거·RE/FW 제거', () => {
|
||||
expect(tgWho('김성환(칼리버스-칼리버스)')).toBe('김성환');
|
||||
expect(tgSubject('RE: FW: 계약 검토의 건')).toBe('계약 검토의 건');
|
||||
expect(tgCut('12345', 3)).toBe('12…');
|
||||
});
|
||||
});
|
||||
|
||||
describe('parseTimesCsv — 발송 스케줄 파서', () => {
|
||||
test('정상 파싱 + 정렬', () => {
|
||||
expect(parseTimesCsv('15:00, 09:00')).toEqual([
|
||||
{ hour: 9, minute: 0 }, { hour: 15, minute: 0 },
|
||||
]);
|
||||
expect(parseTimesCsv('9:30')).toEqual([{ hour: 9, minute: 30 }]);
|
||||
});
|
||||
test('잘못된 토큰 무시·빈 값 → []', () => {
|
||||
expect(parseTimesCsv('25:00, abc, 12:60, 12:30')).toEqual([{ hour: 12, minute: 30 }]);
|
||||
expect(parseTimesCsv('')).toEqual([]);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user