feat(V2-1b): packages/core 추출 — 공유 타입/에러/채널/유틸 분리
packages/core (@d3ro/core) 신규 생성:
- types.ts, errors.ts, ipc-channels.ts, constants.ts (shared에서 이동)
- utils/meeting-markdown.ts, utils/markdown-to-docx.ts (main/utils에서 이동)
- subpath exports 정의 (./types, ./errors, ./ipc-channels, ./constants,
./utils/meeting-markdown, ./utils/markdown-to-docx)
- src/index.ts barrel export 추가
- docx를 core 자체 dependency로 선언
apps/desktop 연결:
- package.json에 @d3ro/core: '*' dep 추가
- tsconfig.node/web.json paths에 @d3ro/core/* 추가
- electron.vite.config.ts 3개 섹션 alias 추가 (main/preload/renderer)
- externalizeDepsPlugin exclude에 @d3ro/core (workspace 소스 번들 대상)
- vitest.config.ts alias 추가
일괄 치환 (79 파일, 167건):
- @shared/{types,errors,ipc-channels,constants} → @d3ro/core/*
- static/dynamic import + type expression import 모두 포함
- MeetingModeService.ts의 ../utils/* 상대 경로 → @d3ro/core/utils/*
- @shared/theme-vars는 V2-1c 범위로 남김 (WindowManager만 사용)
M1 수정 포함:
- electron.vite.config.ts의 resolve('src/shared') → resolve(__dirname, ...)
CWD 독립적으로 동작하도록 견고화
검증:
- typecheck 통과
- build 통과 (main+preload+renderer)
- dev 런타임 → DB/핫키/Ollama 모두 정상, 기존 데이터 연속성 유지
This commit is contained in:
parent
a4cb4c0805
commit
3b0eb3393b
95 changed files with 315 additions and 212 deletions
|
|
@ -157,7 +157,7 @@ async function initPopupWindows(): Promise<void> {
|
|||
unregisterPopupNavKeys()
|
||||
} else {
|
||||
const instructions = getCustomInstructionService().getAll()
|
||||
const activeId = configGet('activeInstructionId' as keyof import('@shared/types').AppConfig) as unknown as string
|
||||
const activeId = configGet('activeInstructionId' as keyof import('@d3ro/core/types').AppConfig) as unknown as string
|
||||
showCommandPopup(instructions as unknown as Array<Record<string, unknown>>, activeId || null)
|
||||
registerPopupNavKeys('command')
|
||||
}
|
||||
|
|
@ -345,12 +345,12 @@ function setupCommandPopupIPC(): void {
|
|||
|
||||
if (data.id) {
|
||||
// 명령어 선택 → 활성 명령어로 설정
|
||||
configSet('activeInstructionId' as keyof import('@shared/types').AppConfig, data.id as never)
|
||||
configSet('activeInstructionId' as keyof import('@d3ro/core/types').AppConfig, data.id as never)
|
||||
configSet('defaultLLMAction', 'custom')
|
||||
logger.info(`Active command set: ${data.name} (${data.id})`)
|
||||
} else {
|
||||
// 선택 해제 → 명령어 없음 (원본 삽입)
|
||||
configSet('activeInstructionId' as keyof import('@shared/types').AppConfig, '' as never)
|
||||
configSet('activeInstructionId' as keyof import('@d3ro/core/types').AppConfig, '' as never)
|
||||
configSet('defaultLLMAction', 'none')
|
||||
logger.info('Active command cleared (none)')
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
// src/main/ipc/audio-handlers.ts
|
||||
|
||||
import { ipcMain } from 'electron'
|
||||
import { IPC_CHANNELS } from '@shared/ipc-channels'
|
||||
import { ipcSuccess, ipcError, ErrorCode } from '@shared/errors'
|
||||
import { IPC_CHANNELS } from '@d3ro/core/ipc-channels'
|
||||
import { ipcSuccess, ipcError, ErrorCode } from '@d3ro/core/errors'
|
||||
import { getAudioCaptureService, calculateRMS } from '../services/AudioCaptureService'
|
||||
import { getMainWindow } from '../windows/WindowManager'
|
||||
import { configGet, configSet } from '../services/ConfigService'
|
||||
import { getLogger } from '../services/LoggerService'
|
||||
import type { SetDeviceParams } from '@shared/types'
|
||||
import type { SetDeviceParams } from '@d3ro/core/types'
|
||||
|
||||
const logger = getLogger('audio-handlers')
|
||||
|
||||
|
|
|
|||
|
|
@ -2,10 +2,10 @@
|
|||
// Phase 10.1: Live Caption IPC 핸들러
|
||||
|
||||
import { ipcMain, session, desktopCapturer } from 'electron'
|
||||
import { IPC_CHANNELS } from '@shared/ipc-channels'
|
||||
import { ipcSuccess, ipcError, ErrorCode } from '@shared/errors'
|
||||
import { IPC_CHANNELS } from '@d3ro/core/ipc-channels'
|
||||
import { ipcSuccess, ipcError, ErrorCode } from '@d3ro/core/errors'
|
||||
import { getCaptionService } from '../services/CaptionService'
|
||||
import type { CaptionConfig } from '@shared/types'
|
||||
import type { CaptionConfig } from '@d3ro/core/types'
|
||||
|
||||
export function registerCaptionHandlers(): void {
|
||||
// 시스템 오디오 루프백: setDisplayMediaRequestHandler로 audio: 'loopback' 설정
|
||||
|
|
|
|||
|
|
@ -2,15 +2,15 @@
|
|||
// Phase 10.4: Multi-LLM Chain IPC 핸들러
|
||||
|
||||
import { ipcMain } from 'electron'
|
||||
import { IPC_CHANNELS } from '@shared/ipc-channels'
|
||||
import { ipcSuccess, ipcError, ErrorCode, D3ROError } from '@shared/errors'
|
||||
import { IPC_CHANNELS } from '@d3ro/core/ipc-channels'
|
||||
import { ipcSuccess, ipcError, ErrorCode, D3ROError } from '@d3ro/core/errors'
|
||||
import { getChainService } from '../services/ChainService'
|
||||
import type {
|
||||
CreateChainParams,
|
||||
UpdateChainParams,
|
||||
DeleteChainParams,
|
||||
ExecuteChainParams
|
||||
} from '@shared/types'
|
||||
} from '@d3ro/core/types'
|
||||
|
||||
export function registerChainHandlers(): void {
|
||||
ipcMain.handle(IPC_CHANNELS.CHAIN.GET_ALL, async () => {
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
// src/main/ipc/config-handlers.ts
|
||||
|
||||
import { ipcMain, BrowserWindow } from 'electron'
|
||||
import { IPC_CHANNELS } from '@shared/ipc-channels'
|
||||
import { ipcSuccess, ipcError, ErrorCode } from '@shared/errors'
|
||||
import { IPC_CHANNELS } from '@d3ro/core/ipc-channels'
|
||||
import { ipcSuccess, ipcError, ErrorCode } from '@d3ro/core/errors'
|
||||
import { configGet, configSet, configGetAll, configReset } from '../services/ConfigService'
|
||||
import { getAutoLaunchService } from '../services/AutoLaunchService'
|
||||
import { reapplyThemeToAllPopups } from '../windows/WindowManager'
|
||||
|
|
@ -22,7 +22,7 @@ import type {
|
|||
SetAutoLaunchParams,
|
||||
SetCloseToTrayParams,
|
||||
AppConfig
|
||||
} from '@shared/types'
|
||||
} from '@d3ro/core/types'
|
||||
|
||||
export function registerConfigHandlers(): void {
|
||||
ipcMain.handle(IPC_CHANNELS.CONFIG.GET, async (_event, params: ConfigGetParams) => {
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@
|
|||
// Phase 10.2 스크린 컨텍스트 IPC 핸들러
|
||||
|
||||
import { ipcMain } from 'electron'
|
||||
import { IPC_CHANNELS } from '@shared/ipc-channels'
|
||||
import { ipcSuccess, ipcError, ErrorCode } from '@shared/errors'
|
||||
import { IPC_CHANNELS } from '@d3ro/core/ipc-channels'
|
||||
import { ipcSuccess, ipcError, ErrorCode } from '@d3ro/core/errors'
|
||||
import { getScreenContextService } from '../services/ScreenContextService'
|
||||
|
||||
export function registerContextHandlers(): void {
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
// src/main/ipc/dictionary-handlers.ts
|
||||
|
||||
import { ipcMain } from 'electron'
|
||||
import { IPC_CHANNELS } from '@shared/ipc-channels'
|
||||
import { ipcSuccess, ipcError, ErrorCode } from '@shared/errors'
|
||||
import { IPC_CHANNELS } from '@d3ro/core/ipc-channels'
|
||||
import { ipcSuccess, ipcError, ErrorCode } from '@d3ro/core/errors'
|
||||
import { getDictionaryService } from '../services/DictionaryService'
|
||||
import type {
|
||||
DictionaryQueryParams,
|
||||
|
|
@ -10,7 +10,7 @@ import type {
|
|||
DictionaryUpdateParams,
|
||||
DictionaryDeleteParams,
|
||||
DictionarySearchParams
|
||||
} from '@shared/types'
|
||||
} from '@d3ro/core/types'
|
||||
|
||||
export function registerDictionaryHandlers(): void {
|
||||
ipcMain.handle(IPC_CHANNELS.DICTIONARY.GET_ALL, async (_event, params: DictionaryQueryParams) => {
|
||||
|
|
|
|||
|
|
@ -2,11 +2,11 @@
|
|||
// Phase 12.1: 파일 전사 IPC 핸들러
|
||||
|
||||
import { ipcMain, dialog } from 'electron'
|
||||
import { IPC_CHANNELS } from '@shared/ipc-channels'
|
||||
import { ErrorCode, ipcSuccess, ipcError } from '@shared/errors'
|
||||
import { IPC_CHANNELS } from '@d3ro/core/ipc-channels'
|
||||
import { ErrorCode, ipcSuccess, ipcError } from '@d3ro/core/errors'
|
||||
import { getFileTranscriptionService } from '../services/FileTranscriptionService'
|
||||
import { getLogger } from '../services/LoggerService'
|
||||
import type { FileTranscriptionStartParams } from '@shared/types'
|
||||
import type { FileTranscriptionStartParams } from '@d3ro/core/types'
|
||||
|
||||
const logger = getLogger('file-transcription-handlers')
|
||||
|
||||
|
|
|
|||
|
|
@ -1,15 +1,15 @@
|
|||
// src/main/ipc/history-handlers.ts
|
||||
|
||||
import { ipcMain } from 'electron'
|
||||
import { IPC_CHANNELS } from '@shared/ipc-channels'
|
||||
import { ipcSuccess, ipcError, ErrorCode } from '@shared/errors'
|
||||
import { IPC_CHANNELS } from '@d3ro/core/ipc-channels'
|
||||
import { ipcSuccess, ipcError, ErrorCode } from '@d3ro/core/errors'
|
||||
import { getHistoryService } from '../services/HistoryService'
|
||||
import type {
|
||||
HistoryQueryParams,
|
||||
HistoryGetByIdParams,
|
||||
HistoryDeleteParams,
|
||||
HistorySearchParams
|
||||
} from '@shared/types'
|
||||
} from '@d3ro/core/types'
|
||||
|
||||
export function registerHistoryHandlers(): void {
|
||||
ipcMain.handle(IPC_CHANNELS.HISTORY.GET_ALL, async (_event, params: HistoryQueryParams) => {
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
// src/main/ipc/hotkey-handlers.ts
|
||||
|
||||
import { ipcMain } from 'electron'
|
||||
import { IPC_CHANNELS } from '@shared/ipc-channels'
|
||||
import { ipcSuccess, ipcError, ErrorCode } from '@shared/errors'
|
||||
import { IPC_CHANNELS } from '@d3ro/core/ipc-channels'
|
||||
import { ipcSuccess, ipcError, ErrorCode } from '@d3ro/core/errors'
|
||||
import { getHotkeyService } from '../services/HotkeyService'
|
||||
import { configGet, configSet } from '../services/ConfigService'
|
||||
import type { SetHotkeyParams, SetEnabledParams } from '@shared/types'
|
||||
import type { SetHotkeyParams, SetEnabledParams } from '@d3ro/core/types'
|
||||
|
||||
export function registerHotkeyHandlers(): void {
|
||||
ipcMain.handle(IPC_CHANNELS.HOTKEY.GET_DICTATION_SHORTCUT, async () => {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
// src/main/ipc/instruction-handlers.ts
|
||||
|
||||
import { ipcMain } from 'electron'
|
||||
import { ipcSuccess, ipcError, ErrorCode } from '@shared/errors'
|
||||
import { ipcSuccess, ipcError, ErrorCode } from '@d3ro/core/errors'
|
||||
import { getCustomInstructionService } from '../services/CustomInstructionService'
|
||||
import type { CustomInstruction } from '../services/CustomInstructionService'
|
||||
|
||||
|
|
|
|||
|
|
@ -2,15 +2,15 @@
|
|||
// Phase 11: 라이센스 IPC 핸들러
|
||||
|
||||
import { ipcMain, BrowserWindow } from 'electron'
|
||||
import { IPC_CHANNELS } from '@shared/ipc-channels'
|
||||
import { ipcSuccess, ipcError, ErrorCode } from '@shared/errors'
|
||||
import { IPC_CHANNELS } from '@d3ro/core/ipc-channels'
|
||||
import { ipcSuccess, ipcError, ErrorCode } from '@d3ro/core/errors'
|
||||
import { getLicenseService } from '../services/LicenseService'
|
||||
import type {
|
||||
ActivateLicenseParams,
|
||||
UpgradePromptEvent,
|
||||
LicenseInfo,
|
||||
} from '@shared/types'
|
||||
import { Feature } from '@shared/types'
|
||||
} from '@d3ro/core/types'
|
||||
import { Feature } from '@d3ro/core/types'
|
||||
|
||||
/** 업그레이드 유도 이벤트를 모든 렌더러에 broadcast */
|
||||
function broadcastUpgradePrompt(event: UpgradePromptEvent): void {
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
// src/main/ipc/llm-handlers.ts
|
||||
|
||||
import { ipcMain } from 'electron'
|
||||
import { IPC_CHANNELS } from '@shared/ipc-channels'
|
||||
import { ipcSuccess, ipcError, ErrorCode } from '@shared/errors'
|
||||
import { IPC_CHANNELS } from '@d3ro/core/ipc-channels'
|
||||
import { ipcSuccess, ipcError, ErrorCode } from '@d3ro/core/errors'
|
||||
import { getLocalLLMService } from '../services/LocalLLMService'
|
||||
import { configGet, configSet } from '../services/ConfigService'
|
||||
import { getMainWindow } from '../windows/WindowManager'
|
||||
import type { SetLLMModelParams, SetServerUrlParams, LLMProcessParams } from '@shared/types'
|
||||
import type { SetLLMModelParams, SetServerUrlParams, LLMProcessParams } from '@d3ro/core/types'
|
||||
|
||||
export function registerLLMHandlers(): void {
|
||||
// LLM 가용성 변경 시 렌더러에 상태 전파
|
||||
|
|
|
|||
|
|
@ -2,15 +2,15 @@
|
|||
// Phase 14.5: Meeting Document Template IPC 핸들러
|
||||
|
||||
import { ipcMain } from 'electron'
|
||||
import { IPC_CHANNELS } from '@shared/ipc-channels'
|
||||
import { ErrorCode, ipcSuccess, ipcError } from '@shared/errors'
|
||||
import { IPC_CHANNELS } from '@d3ro/core/ipc-channels'
|
||||
import { ErrorCode, ipcSuccess, ipcError } from '@d3ro/core/errors'
|
||||
import { getMeetingDocTemplateService } from '../services/MeetingDocTemplateService'
|
||||
import { getLogger } from '../services/LoggerService'
|
||||
import type {
|
||||
CreateMeetingDocTemplateParams,
|
||||
UpdateMeetingDocTemplateParams,
|
||||
DeleteMeetingDocTemplateParams,
|
||||
} from '@shared/types'
|
||||
} from '@d3ro/core/types'
|
||||
|
||||
const logger = getLogger('meeting-doc-template-handlers')
|
||||
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@
|
|||
// Phase 14 / 14.5: Meeting Mode IPC 핸들러
|
||||
|
||||
import { ipcMain } from 'electron'
|
||||
import { IPC_CHANNELS } from '@shared/ipc-channels'
|
||||
import { ErrorCode, ipcSuccess, ipcError } from '@shared/errors'
|
||||
import { IPC_CHANNELS } from '@d3ro/core/ipc-channels'
|
||||
import { ErrorCode, ipcSuccess, ipcError } from '@d3ro/core/errors'
|
||||
import { getMeetingModeService } from '../services/MeetingModeService'
|
||||
import { getLogger } from '../services/LoggerService'
|
||||
import type {
|
||||
|
|
@ -15,7 +15,7 @@ import type {
|
|||
MeetingGenerateDocParams,
|
||||
MeetingExportFormat,
|
||||
MeetingChatSendParams,
|
||||
} from '@shared/types'
|
||||
} from '@d3ro/core/types'
|
||||
|
||||
const logger = getLogger('meeting-mode-handlers')
|
||||
|
||||
|
|
|
|||
|
|
@ -2,11 +2,11 @@
|
|||
// Phase 12.2: 회의록 요약 IPC 핸들러
|
||||
|
||||
import { ipcMain } from 'electron'
|
||||
import { IPC_CHANNELS } from '@shared/ipc-channels'
|
||||
import { ErrorCode, ipcSuccess, ipcError } from '@shared/errors'
|
||||
import { IPC_CHANNELS } from '@d3ro/core/ipc-channels'
|
||||
import { ErrorCode, ipcSuccess, ipcError } from '@d3ro/core/errors'
|
||||
import { getMeetingSummaryService } from '../services/MeetingSummaryService'
|
||||
import { getLogger } from '../services/LoggerService'
|
||||
import type { MeetingSummarizeParams, MeetingSummaryGetParams, MeetingSummaryExportParams } from '@shared/types'
|
||||
import type { MeetingSummarizeParams, MeetingSummaryGetParams, MeetingSummaryExportParams } from '@d3ro/core/types'
|
||||
|
||||
const logger = getLogger('meeting-summary-handlers')
|
||||
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@
|
|||
// Phase 10.3: 음성 메모 태그 IPC 핸들러
|
||||
|
||||
import { ipcMain } from 'electron'
|
||||
import { IPC_CHANNELS } from '@shared/ipc-channels'
|
||||
import { ipcSuccess, ipcError, ErrorCode, D3ROError } from '@shared/errors'
|
||||
import { IPC_CHANNELS } from '@d3ro/core/ipc-channels'
|
||||
import { ipcSuccess, ipcError, ErrorCode, D3ROError } from '@d3ro/core/errors'
|
||||
import { getMemoService } from '../services/MemoService'
|
||||
import type {
|
||||
GetTagsParams,
|
||||
|
|
@ -11,7 +11,7 @@ import type {
|
|||
RemoveTagParams,
|
||||
SearchByTagParams,
|
||||
ExportMemoParams
|
||||
} from '@shared/types'
|
||||
} from '@d3ro/core/types'
|
||||
|
||||
export function registerMemoHandlers(): void {
|
||||
ipcMain.handle(IPC_CHANNELS.MEMO.GET_TAGS, async (_event, params: GetTagsParams) => {
|
||||
|
|
|
|||
|
|
@ -2,11 +2,11 @@
|
|||
// Phase 13.2: 로컬 RAG IPC 핸들러
|
||||
|
||||
import { ipcMain, dialog } from 'electron'
|
||||
import { IPC_CHANNELS } from '@shared/ipc-channels'
|
||||
import { ErrorCode, ipcSuccess, ipcError } from '@shared/errors'
|
||||
import { IPC_CHANNELS } from '@d3ro/core/ipc-channels'
|
||||
import { ErrorCode, ipcSuccess, ipcError } from '@d3ro/core/errors'
|
||||
import { getRAGService } from '../services/RAGService'
|
||||
import { getLogger } from '../services/LoggerService'
|
||||
import type { RAGQueryParams, RAGRemoveDocumentParams } from '@shared/types'
|
||||
import type { RAGQueryParams, RAGRemoveDocumentParams } from '@d3ro/core/types'
|
||||
|
||||
const logger = getLogger('rag-handlers')
|
||||
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
// src/main/ipc/stt-handlers.ts
|
||||
|
||||
import { ipcMain } from 'electron'
|
||||
import { IPC_CHANNELS } from '@shared/ipc-channels'
|
||||
import { ipcSuccess, ipcError, ErrorCode } from '@shared/errors'
|
||||
import { IPC_CHANNELS } from '@d3ro/core/ipc-channels'
|
||||
import { ipcSuccess, ipcError, ErrorCode } from '@d3ro/core/errors'
|
||||
import { getLocalSTTService } from '../services/LocalSTTService'
|
||||
import { configGet, configSet } from '../services/ConfigService'
|
||||
import type { SetSTTModelParams, SetSTTLanguageParams } from '@shared/types'
|
||||
import type { SetSTTModelParams, SetSTTLanguageParams } from '@d3ro/core/types'
|
||||
|
||||
export function registerSTTHandlers(): void {
|
||||
ipcMain.handle(IPC_CHANNELS.STT.GET_STATUS, async () => {
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
// src/main/ipc/system-handlers.ts
|
||||
|
||||
import { ipcMain, app, systemPreferences } from 'electron'
|
||||
import { IPC_CHANNELS } from '@shared/ipc-channels'
|
||||
import { ipcSuccess } from '@shared/errors'
|
||||
import type { PermissionStatus, PlaySoundParams, SetSoundEnabledParams } from '@shared/types'
|
||||
import { IPC_CHANNELS } from '@d3ro/core/ipc-channels'
|
||||
import { ipcSuccess } from '@d3ro/core/errors'
|
||||
import type { PermissionStatus, PlaySoundParams, SetSoundEnabledParams } from '@d3ro/core/types'
|
||||
import { getSoundEffectService } from '../services/SoundEffectService'
|
||||
|
||||
export function registerSystemHandlers(): void {
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@
|
|||
// Phase 12.3: 딕테이션 템플릿 IPC 핸들러
|
||||
|
||||
import { ipcMain } from 'electron'
|
||||
import { IPC_CHANNELS } from '@shared/ipc-channels'
|
||||
import { ErrorCode, ipcSuccess, ipcError } from '@shared/errors'
|
||||
import { IPC_CHANNELS } from '@d3ro/core/ipc-channels'
|
||||
import { ErrorCode, ipcSuccess, ipcError } from '@d3ro/core/errors'
|
||||
import { getDictationTemplateService } from '../services/DictationTemplateService'
|
||||
import { getLogger } from '../services/LoggerService'
|
||||
import type {
|
||||
|
|
@ -12,7 +12,7 @@ import type {
|
|||
DeleteTemplateParams,
|
||||
StartTemplateSessionParams,
|
||||
SetFieldValueParams,
|
||||
} from '@shared/types'
|
||||
} from '@d3ro/core/types'
|
||||
|
||||
const logger = getLogger('template-handlers')
|
||||
|
||||
|
|
@ -33,7 +33,7 @@ export function registerTemplateHandlers(): void {
|
|||
// 라이센스 체크
|
||||
try {
|
||||
const { getLicenseService } = await import('../services/LicenseService')
|
||||
const { Feature } = await import('@shared/types')
|
||||
const { Feature } = await import('@d3ro/core/types')
|
||||
const license = getLicenseService()
|
||||
const access = license.canUse(Feature.DICTATION_TEMPLATE)
|
||||
if (!access.allowed) {
|
||||
|
|
|
|||
|
|
@ -2,11 +2,11 @@
|
|||
// Phase 13.3: OS 자동화 IPC 핸들러
|
||||
|
||||
import { ipcMain } from 'electron'
|
||||
import { IPC_CHANNELS } from '@shared/ipc-channels'
|
||||
import { ErrorCode, ipcSuccess, ipcError } from '@shared/errors'
|
||||
import { IPC_CHANNELS } from '@d3ro/core/ipc-channels'
|
||||
import { ErrorCode, ipcSuccess, ipcError } from '@d3ro/core/errors'
|
||||
import { getVoiceActionService } from '../services/VoiceActionService'
|
||||
import { getLogger } from '../services/LoggerService'
|
||||
import type { VoiceActionExecuteParams } from '@shared/types'
|
||||
import type { VoiceActionExecuteParams } from '@d3ro/core/types'
|
||||
|
||||
const logger = getLogger('voice-action-handlers')
|
||||
|
||||
|
|
|
|||
|
|
@ -2,10 +2,10 @@
|
|||
// Phase 10.5: 음성 단축키 IPC 핸들러
|
||||
|
||||
import { ipcMain } from 'electron'
|
||||
import { IPC_CHANNELS } from '@shared/ipc-channels'
|
||||
import { ipcSuccess, ipcError, ErrorCode } from '@shared/errors'
|
||||
import { IPC_CHANNELS } from '@d3ro/core/ipc-channels'
|
||||
import { ipcSuccess, ipcError, ErrorCode } from '@d3ro/core/errors'
|
||||
import { getVoiceCommandService } from '../services/VoiceCommandService'
|
||||
import type { SetVoiceCommandKeywordsParams, SetVoiceCommandEnabledParams } from '@shared/types'
|
||||
import type { SetVoiceCommandKeywordsParams, SetVoiceCommandEnabledParams } from '@d3ro/core/types'
|
||||
|
||||
export function registerVoiceCommandHandlers(): void {
|
||||
const CH = IPC_CHANNELS.VOICE_COMMAND
|
||||
|
|
|
|||
|
|
@ -2,11 +2,11 @@
|
|||
// Phase 13.1: 음성 대화 모드 IPC 핸들러
|
||||
|
||||
import { ipcMain } from 'electron'
|
||||
import { IPC_CHANNELS } from '@shared/ipc-channels'
|
||||
import { ErrorCode, ipcSuccess, ipcError } from '@shared/errors'
|
||||
import { IPC_CHANNELS } from '@d3ro/core/ipc-channels'
|
||||
import { ErrorCode, ipcSuccess, ipcError } from '@d3ro/core/errors'
|
||||
import { getVoiceConversationService } from '../services/VoiceConversationService'
|
||||
import { getLogger } from '../services/LoggerService'
|
||||
import type { ConversationSendParams } from '@shared/types'
|
||||
import type { ConversationSendParams } from '@d3ro/core/types'
|
||||
|
||||
const logger = getLogger('voice-conversation-handlers')
|
||||
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
// src/main/ipc/voice-handlers.ts
|
||||
|
||||
import { ipcMain } from 'electron'
|
||||
import { IPC_CHANNELS } from '@shared/ipc-channels'
|
||||
import { ipcSuccess, ipcError, ErrorCode } from '@shared/errors'
|
||||
import { IPC_CHANNELS } from '@d3ro/core/ipc-channels'
|
||||
import { ipcSuccess, ipcError, ErrorCode } from '@d3ro/core/errors'
|
||||
import { getVoiceModeService } from '../services/VoiceModeService'
|
||||
import type { StartRecordingParams, StopRecordingParams, CancelRecordingParams, SetVoiceModeParams } from '@shared/types'
|
||||
import type { StartRecordingParams, StopRecordingParams, CancelRecordingParams, SetVoiceModeParams } from '@d3ro/core/types'
|
||||
|
||||
export function registerVoiceHandlers(): void {
|
||||
ipcMain.handle(IPC_CHANNELS.VOICE.START_RECORDING, async (_event, params: StartRecordingParams) => {
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
// src/main/ipc/window-handlers.ts
|
||||
|
||||
import { ipcMain, shell } from 'electron'
|
||||
import { IPC_CHANNELS } from '@shared/ipc-channels'
|
||||
import { ipcSuccess } from '@shared/errors'
|
||||
import { IPC_CHANNELS } from '@d3ro/core/ipc-channels'
|
||||
import { ipcSuccess } from '@d3ro/core/errors'
|
||||
import { getMainWindow, hideResultPopup, hideRecordingTip } from '../windows/WindowManager'
|
||||
|
||||
export function registerWindowHandlers(): void {
|
||||
|
|
|
|||
|
|
@ -10,9 +10,9 @@ import type { Readable } from 'stream'
|
|||
import { getLogger } from './LoggerService'
|
||||
import { configGet } from './ConfigService'
|
||||
import { getSoxPath } from '../utils/paths'
|
||||
import type { AudioDevice } from '@shared/types'
|
||||
import { AUDIO_FORMAT, TIMING } from '@shared/constants'
|
||||
import { D3ROError, ErrorCode } from '@shared/errors'
|
||||
import type { AudioDevice } from '@d3ro/core/types'
|
||||
import { AUDIO_FORMAT, TIMING } from '@d3ro/core/constants'
|
||||
import { D3ROError, ErrorCode } from '@d3ro/core/errors'
|
||||
|
||||
const logger = getLogger('AudioCaptureService')
|
||||
|
||||
|
|
|
|||
|
|
@ -15,14 +15,14 @@ import {
|
|||
hideCaptionOverlay,
|
||||
sendToCaptionOverlay,
|
||||
} from '../windows/WindowManager'
|
||||
import { IPC_CHANNELS } from '@shared/ipc-channels'
|
||||
import { D3ROError, ErrorCode } from '@shared/errors'
|
||||
import { IPC_CHANNELS } from '@d3ro/core/ipc-channels'
|
||||
import { D3ROError, ErrorCode } from '@d3ro/core/errors'
|
||||
import type {
|
||||
CaptionState,
|
||||
CaptionSegment,
|
||||
CaptionConfig,
|
||||
CaptionSessionSummary,
|
||||
} from '@shared/types'
|
||||
} from '@d3ro/core/types'
|
||||
import { getMainWindow } from '../windows/WindowManager'
|
||||
|
||||
const logger = getLogger('CaptionService')
|
||||
|
|
@ -139,7 +139,7 @@ class CaptionService extends EventEmitter {
|
|||
this._totalFrameCount = 0
|
||||
|
||||
// ConfigService에서 저장된 오디오 소스 읽기
|
||||
const savedSource = configGet('captionAudioSource' as keyof import('@shared/types').AppConfig) as unknown as string
|
||||
const savedSource = configGet('captionAudioSource' as keyof import('@d3ro/core/types').AppConfig) as unknown as string
|
||||
if (savedSource && (savedSource === 'mic' || savedSource === 'system' || savedSource === 'both')) {
|
||||
this._config.audioSource = savedSource as 'mic' | 'system' | 'both'
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,8 +8,8 @@ import { configGet } from './ConfigService'
|
|||
import { getCustomInstructionService } from './CustomInstructionService'
|
||||
import { getLocalLLMService } from './LocalLLMService'
|
||||
import { getMainWindow } from '../windows/WindowManager'
|
||||
import { IPC_CHANNELS } from '@shared/ipc-channels'
|
||||
import { D3ROError, ErrorCode } from '@shared/errors'
|
||||
import { IPC_CHANNELS } from '@d3ro/core/ipc-channels'
|
||||
import { D3ROError, ErrorCode } from '@d3ro/core/errors'
|
||||
import type {
|
||||
LLMChain,
|
||||
ChainStep,
|
||||
|
|
@ -17,7 +17,7 @@ import type {
|
|||
UpdateChainParams,
|
||||
ChainProgress,
|
||||
ChainExecutionResult
|
||||
} from '@shared/types'
|
||||
} from '@d3ro/core/types'
|
||||
|
||||
const logger = getLogger('chain-service')
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
// electron-store 기반 설정 관리. 설계서 02의 AppConfig 타입 사용.
|
||||
|
||||
import { EventEmitter } from 'events'
|
||||
import type { AppConfig, ConfigChangedEvent } from '@shared/types'
|
||||
import type { AppConfig, ConfigChangedEvent } from '@d3ro/core/types'
|
||||
import { getLogger } from './LoggerService'
|
||||
|
||||
const logger = getLogger('ConfigService')
|
||||
|
|
|
|||
|
|
@ -7,8 +7,8 @@ import { nanoid } from 'nanoid'
|
|||
import Store from 'electron-store'
|
||||
import { getLogger } from './LoggerService'
|
||||
import { getMainWindow } from '../windows/WindowManager'
|
||||
import { IPC_CHANNELS } from '@shared/ipc-channels'
|
||||
import { D3ROError, ErrorCode } from '@shared/errors'
|
||||
import { IPC_CHANNELS } from '@d3ro/core/ipc-channels'
|
||||
import { D3ROError, ErrorCode } from '@d3ro/core/errors'
|
||||
import type {
|
||||
DictationTemplate,
|
||||
TemplateField,
|
||||
|
|
@ -18,7 +18,7 @@ import type {
|
|||
TemplateSessionCompletedEvent,
|
||||
CreateTemplateParams,
|
||||
UpdateTemplateParams,
|
||||
} from '@shared/types'
|
||||
} from '@d3ro/core/types'
|
||||
|
||||
const logger = getLogger('DictationTemplateService')
|
||||
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ import type {
|
|||
DictionaryAddParams,
|
||||
DictionaryUpdateParams,
|
||||
DictionarySearchParams
|
||||
} from '@shared/types'
|
||||
} from '@d3ro/core/types'
|
||||
|
||||
const logger = getLogger('DictionaryService')
|
||||
|
||||
|
|
|
|||
|
|
@ -13,15 +13,15 @@ import { getHistoryService } from './HistoryService'
|
|||
import { configGet } from './ConfigService'
|
||||
import { getFfmpegPath } from '../utils/paths'
|
||||
import { getMainWindow } from '../windows/WindowManager'
|
||||
import { IPC_CHANNELS } from '@shared/ipc-channels'
|
||||
import { D3ROError, ErrorCode } from '@shared/errors'
|
||||
import { IPC_CHANNELS } from '@d3ro/core/ipc-channels'
|
||||
import { D3ROError, ErrorCode } from '@d3ro/core/errors'
|
||||
import type {
|
||||
FileTranscriptionState,
|
||||
FileTranscriptionProgress,
|
||||
FileTranscriptionResult,
|
||||
FileTranscriptionSegment,
|
||||
FileTranscriptionStateInfo,
|
||||
} from '@shared/types'
|
||||
} from '@d3ro/core/types'
|
||||
|
||||
const logger = getLogger('FileTranscriptionService')
|
||||
|
||||
|
|
@ -75,7 +75,7 @@ class FileTranscriptionService extends EventEmitter {
|
|||
// 라이센스 체크
|
||||
try {
|
||||
const { getLicenseService } = await import('./LicenseService')
|
||||
const { Feature } = await import('@shared/types')
|
||||
const { Feature } = await import('@d3ro/core/types')
|
||||
const license = getLicenseService()
|
||||
const access = license.canUse(Feature.FILE_TRANSCRIPTION)
|
||||
if (!access.allowed) {
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ import type {
|
|||
HistoryPage,
|
||||
HistorySearchParams,
|
||||
StatsSummary
|
||||
} from '@shared/types'
|
||||
} from '@d3ro/core/types'
|
||||
|
||||
const logger = getLogger('HistoryService')
|
||||
|
||||
|
|
|
|||
|
|
@ -7,9 +7,9 @@ import { uIOhook, UiohookKey } from 'uiohook-napi'
|
|||
import type { UiohookKeyboardEvent } from 'uiohook-napi'
|
||||
import { getLogger } from './LoggerService'
|
||||
import { configGet } from './ConfigService'
|
||||
import { D3ROError, ErrorCode } from '@shared/errors'
|
||||
import { TIMING } from '@shared/constants'
|
||||
import type { HotkeyBinding } from '@shared/types'
|
||||
import { D3ROError, ErrorCode } from '@d3ro/core/errors'
|
||||
import { TIMING } from '@d3ro/core/constants'
|
||||
import type { HotkeyBinding } from '@d3ro/core/types'
|
||||
|
||||
const logger = getLogger('HotkeyService')
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import { eq, and } from 'drizzle-orm'
|
|||
import { getLogger } from './LoggerService'
|
||||
import { getDatabase } from '../db'
|
||||
import { dailyUsage } from '../db/schema'
|
||||
import { D3ROError, ErrorCode } from '@shared/errors'
|
||||
import { D3ROError, ErrorCode } from '@d3ro/core/errors'
|
||||
import type {
|
||||
LicenseTier,
|
||||
LicenseInfo,
|
||||
|
|
@ -17,8 +17,8 @@ import type {
|
|||
UpgradePromptEvent,
|
||||
ActivateLicenseResult,
|
||||
TierComparison,
|
||||
} from '@shared/types'
|
||||
import { Feature } from '@shared/types'
|
||||
} from '@d3ro/core/types'
|
||||
import { Feature } from '@d3ro/core/types'
|
||||
|
||||
const logger = getLogger('license')
|
||||
|
||||
|
|
|
|||
|
|
@ -8,8 +8,8 @@ import * as fs from 'fs'
|
|||
import * as path from 'path'
|
||||
import { getLogger } from './LoggerService'
|
||||
import { configGet } from './ConfigService'
|
||||
import { D3ROError, ErrorCode } from '@shared/errors'
|
||||
import type { LLMStatus, LLMModel, LLMAction, LLMConnectionState } from '@shared/types'
|
||||
import { D3ROError, ErrorCode } from '@d3ro/core/errors'
|
||||
import type { LLMStatus, LLMModel, LLMAction, LLMConnectionState } from '@d3ro/core/types'
|
||||
|
||||
const logger = getLogger('LocalLLMService')
|
||||
|
||||
|
|
@ -410,7 +410,7 @@ class LocalLLMService extends EventEmitter {
|
|||
// Phase 11: LLM 처리 쿼터 체크
|
||||
try {
|
||||
const { getLicenseService } = await import('./LicenseService')
|
||||
const { Feature } = await import('@shared/types')
|
||||
const { Feature } = await import('@d3ro/core/types')
|
||||
const license = getLicenseService()
|
||||
const access = license.canUse(Feature.LLM_PROCESS)
|
||||
if (!access.allowed) {
|
||||
|
|
|
|||
|
|
@ -8,8 +8,8 @@ import { type ChildProcess, spawn } from 'child_process'
|
|||
import { getLogger } from './LoggerService'
|
||||
import { configGet } from './ConfigService'
|
||||
import { getSidecarCommand } from '../utils/paths'
|
||||
import { D3ROError, ErrorCode } from '@shared/errors'
|
||||
import type { STTModel, STTStatus, STTEngineState } from '@shared/types'
|
||||
import { D3ROError, ErrorCode } from '@d3ro/core/errors'
|
||||
import type { STTModel, STTStatus, STTEngineState } from '@d3ro/core/types'
|
||||
|
||||
// ── 내부 타입 정의 ────────────────────────────────────────
|
||||
|
||||
|
|
|
|||
|
|
@ -5,13 +5,13 @@ import { EventEmitter } from 'events'
|
|||
import { nanoid } from 'nanoid'
|
||||
import Store from 'electron-store'
|
||||
import { getLogger } from './LoggerService'
|
||||
import { D3ROError, ErrorCode } from '@shared/errors'
|
||||
import { D3ROError, ErrorCode } from '@d3ro/core/errors'
|
||||
import type {
|
||||
MeetingDocTemplate,
|
||||
CreateMeetingDocTemplateParams,
|
||||
UpdateMeetingDocTemplateParams,
|
||||
MeetingDocTemplateType,
|
||||
} from '@shared/types'
|
||||
} from '@d3ro/core/types'
|
||||
|
||||
const logger = getLogger('MeetingDocTemplateService')
|
||||
|
||||
|
|
|
|||
|
|
@ -12,8 +12,8 @@ import { configGet, configSet } from './ConfigService'
|
|||
import { getMainWindow } from '../windows/WindowManager'
|
||||
import { getDatabase } from '../db'
|
||||
import { meetingSessions, meetingMemos, meetingDocuments } from '../db/schema'
|
||||
import { IPC_CHANNELS } from '@shared/ipc-channels'
|
||||
import { D3ROError, ErrorCode } from '@shared/errors'
|
||||
import { IPC_CHANNELS } from '@d3ro/core/ipc-channels'
|
||||
import { D3ROError, ErrorCode } from '@d3ro/core/errors'
|
||||
import {
|
||||
parseMinutes,
|
||||
buildExportMarkdown,
|
||||
|
|
@ -21,8 +21,8 @@ import {
|
|||
formatTime,
|
||||
formatDateFile,
|
||||
formatDateRange,
|
||||
} from '../utils/meeting-markdown'
|
||||
import { markdownToDocx } from '../utils/markdown-to-docx'
|
||||
} from '@d3ro/core/utils/meeting-markdown'
|
||||
import { markdownToDocx } from '@d3ro/core/utils/markdown-to-docx'
|
||||
import type {
|
||||
MeetingModeState,
|
||||
MeetingMemo,
|
||||
|
|
@ -39,7 +39,7 @@ import type {
|
|||
MeetingExportFormat,
|
||||
MeetingDocGeneratingProgress,
|
||||
CaptionSegment,
|
||||
} from '@shared/types'
|
||||
} from '@d3ro/core/types'
|
||||
|
||||
const logger = getLogger('MeetingModeService')
|
||||
|
||||
|
|
@ -145,7 +145,7 @@ class MeetingModeService extends EventEmitter {
|
|||
|
||||
// 회의 모드는 마이크 캡처 강제 — ConfigService 값도 임시 변경
|
||||
// (CaptionService.start()가 ConfigService에서 다시 읽기 때문)
|
||||
type AppConfigKey = keyof import('@shared/types').AppConfig
|
||||
type AppConfigKey = keyof import('@d3ro/core/types').AppConfig
|
||||
const prevAudioSource = configGet('captionAudioSource' as AppConfigKey) as unknown as string
|
||||
configSet('captionAudioSource' as AppConfigKey, 'mic' as never)
|
||||
|
||||
|
|
|
|||
|
|
@ -12,9 +12,9 @@ import { getLocalLLMService } from './LocalLLMService'
|
|||
import { getDatabase } from '../db'
|
||||
import { history } from '../db/schema'
|
||||
import { getMainWindow } from '../windows/WindowManager'
|
||||
import { IPC_CHANNELS } from '@shared/ipc-channels'
|
||||
import { D3ROError, ErrorCode } from '@shared/errors'
|
||||
import type { MeetingSummaryResult, MeetingSummaryProgress } from '@shared/types'
|
||||
import { IPC_CHANNELS } from '@d3ro/core/ipc-channels'
|
||||
import { D3ROError, ErrorCode } from '@d3ro/core/errors'
|
||||
import type { MeetingSummaryResult, MeetingSummaryProgress } from '@d3ro/core/types'
|
||||
|
||||
const logger = getLogger('MeetingSummaryService')
|
||||
|
||||
|
|
@ -41,7 +41,7 @@ class MeetingSummaryService extends EventEmitter {
|
|||
// 라이센스 체크
|
||||
try {
|
||||
const { getLicenseService } = await import('./LicenseService')
|
||||
const { Feature } = await import('@shared/types')
|
||||
const { Feature } = await import('@d3ro/core/types')
|
||||
const license = getLicenseService()
|
||||
const access = license.canUse(Feature.MEETING_SUMMARY)
|
||||
if (!access.allowed) {
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import { getDatabase } from '../db'
|
|||
import { memoTags, history } from '../db/schema'
|
||||
import type { MemoTagRow } from '../db/schema'
|
||||
import { getLogger } from './LoggerService'
|
||||
import { D3ROError, ErrorCode } from '@shared/errors'
|
||||
import { D3ROError, ErrorCode } from '@d3ro/core/errors'
|
||||
import type {
|
||||
MemoTag,
|
||||
TagCount,
|
||||
|
|
@ -18,7 +18,7 @@ import type {
|
|||
ExportMemoParams,
|
||||
HistoryEntry,
|
||||
HistoryPage
|
||||
} from '@shared/types'
|
||||
} from '@d3ro/core/types'
|
||||
|
||||
const logger = getLogger('MemoService')
|
||||
|
||||
|
|
|
|||
|
|
@ -13,15 +13,15 @@ import { configGet } from './ConfigService'
|
|||
import { getDatabase } from '../db'
|
||||
import { ragDocuments, ragChunks } from '../db/schema'
|
||||
import { getMainWindow } from '../windows/WindowManager'
|
||||
import { IPC_CHANNELS } from '@shared/ipc-channels'
|
||||
import { D3ROError, ErrorCode } from '@shared/errors'
|
||||
import { IPC_CHANNELS } from '@d3ro/core/ipc-channels'
|
||||
import { D3ROError, ErrorCode } from '@d3ro/core/errors'
|
||||
import type {
|
||||
RAGDocument,
|
||||
RAGQueryResult,
|
||||
RAGState,
|
||||
RAGStateInfo,
|
||||
RAGIndexProgress,
|
||||
} from '@shared/types'
|
||||
} from '@d3ro/core/types'
|
||||
|
||||
const logger = getLogger('RAGService')
|
||||
|
||||
|
|
@ -74,7 +74,7 @@ class RAGService extends EventEmitter {
|
|||
// 라이센스 체크
|
||||
try {
|
||||
const { getLicenseService } = await import('./LicenseService')
|
||||
const { Feature } = await import('@shared/types')
|
||||
const { Feature } = await import('@d3ro/core/types')
|
||||
const license = getLicenseService()
|
||||
const access = license.canUse(Feature.LOCAL_RAG)
|
||||
if (!access.allowed) {
|
||||
|
|
|
|||
|
|
@ -5,8 +5,8 @@
|
|||
import { clipboard } from 'electron'
|
||||
import { getLogger } from './LoggerService'
|
||||
import { configGet, configSet } from './ConfigService'
|
||||
import { D3ROError, ErrorCode } from '@shared/errors'
|
||||
import type { ScreenContext, CaptureContextResult } from '@shared/types'
|
||||
import { D3ROError, ErrorCode } from '@d3ro/core/errors'
|
||||
import type { ScreenContext, CaptureContextResult } from '@d3ro/core/types'
|
||||
|
||||
const logger = getLogger('screen-context')
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import { EventEmitter } from 'events'
|
|||
import { spawn, type ChildProcess } from 'child_process'
|
||||
import { getLogger } from './LoggerService'
|
||||
import { configGet } from './ConfigService'
|
||||
import { D3ROError, ErrorCode } from '@shared/errors'
|
||||
import { D3ROError, ErrorCode } from '@d3ro/core/errors'
|
||||
|
||||
const logger = getLogger('TTSPlaybackService')
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
import { EventEmitter } from 'events'
|
||||
import { clipboard } from 'electron'
|
||||
import { getLogger } from './LoggerService'
|
||||
import { D3ROError, ErrorCode } from '@shared/errors'
|
||||
import { D3ROError, ErrorCode } from '@d3ro/core/errors'
|
||||
|
||||
const logger = getLogger('TextInsertService')
|
||||
|
||||
|
|
|
|||
|
|
@ -10,8 +10,8 @@ import { getLogger } from './LoggerService'
|
|||
import { getLocalLLMService } from './LocalLLMService'
|
||||
import { configGet } from './ConfigService'
|
||||
import { getMainWindow } from '../windows/WindowManager'
|
||||
import { IPC_CHANNELS } from '@shared/ipc-channels'
|
||||
import { D3ROError, ErrorCode } from '@shared/errors'
|
||||
import { IPC_CHANNELS } from '@d3ro/core/ipc-channels'
|
||||
import { D3ROError, ErrorCode } from '@d3ro/core/errors'
|
||||
import type {
|
||||
VoiceActionPlan,
|
||||
VoiceActionPreset,
|
||||
|
|
@ -19,7 +19,7 @@ import type {
|
|||
VoiceActionPlannedEvent,
|
||||
VoiceActionExecutedEvent,
|
||||
VoiceActionErrorEvent,
|
||||
} from '@shared/types'
|
||||
} from '@d3ro/core/types'
|
||||
|
||||
const logger = getLogger('VoiceActionService')
|
||||
|
||||
|
|
@ -112,7 +112,7 @@ class VoiceActionService extends EventEmitter {
|
|||
// 라이센스 체크
|
||||
try {
|
||||
const { getLicenseService } = await import('./LicenseService')
|
||||
const { Feature } = await import('@shared/types')
|
||||
const { Feature } = await import('@d3ro/core/types')
|
||||
const license = getLicenseService()
|
||||
const access = license.canUse(Feature.OS_AUTOMATION)
|
||||
if (!access.allowed) {
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import type {
|
|||
VoiceCommandKeyword,
|
||||
VoiceCommandMatch,
|
||||
KeywordMatchMode
|
||||
} from '@shared/types'
|
||||
} from '@d3ro/core/types'
|
||||
|
||||
const logger = getLogger('voice-command')
|
||||
|
||||
|
|
|
|||
|
|
@ -11,8 +11,8 @@ import { getAudioCaptureService } from './AudioCaptureService'
|
|||
import { getTTSPlaybackService } from './TTSPlaybackService'
|
||||
import { configGet } from './ConfigService'
|
||||
import { getMainWindow } from '../windows/WindowManager'
|
||||
import { IPC_CHANNELS } from '@shared/ipc-channels'
|
||||
import { D3ROError, ErrorCode } from '@shared/errors'
|
||||
import { IPC_CHANNELS } from '@d3ro/core/ipc-channels'
|
||||
import { D3ROError, ErrorCode } from '@d3ro/core/errors'
|
||||
import type {
|
||||
ConversationState,
|
||||
ConversationMessage,
|
||||
|
|
@ -20,7 +20,7 @@ import type {
|
|||
ConversationAssistantDelta,
|
||||
ConversationAssistantMessage,
|
||||
ConversationError,
|
||||
} from '@shared/types'
|
||||
} from '@d3ro/core/types'
|
||||
|
||||
const logger = getLogger('VoiceConversationService')
|
||||
|
||||
|
|
@ -67,7 +67,7 @@ class VoiceConversationService extends EventEmitter {
|
|||
// 라이센스 체크
|
||||
try {
|
||||
const { getLicenseService } = await import('./LicenseService')
|
||||
const { Feature } = await import('@shared/types')
|
||||
const { Feature } = await import('@d3ro/core/types')
|
||||
const license = getLicenseService()
|
||||
const access = license.canUse(Feature.VOICE_CONVERSATION)
|
||||
if (!access.allowed) {
|
||||
|
|
|
|||
|
|
@ -17,10 +17,10 @@ import type { HotkeyConfig } from './HotkeyService'
|
|||
import { configGet } from './ConfigService'
|
||||
import { getTextInsertService } from './TextInsertService'
|
||||
import { getLocalLLMService } from './LocalLLMService'
|
||||
import { D3ROError, ErrorCode } from '@shared/errors'
|
||||
import { TIMING } from '@shared/constants'
|
||||
import { RecognitionState, AudioState } from '@shared/types'
|
||||
import type { VoiceMode, VoiceState } from '@shared/types'
|
||||
import { D3ROError, ErrorCode } from '@d3ro/core/errors'
|
||||
import { TIMING } from '@d3ro/core/constants'
|
||||
import { RecognitionState, AudioState } from '@d3ro/core/types'
|
||||
import type { VoiceMode, VoiceState } from '@d3ro/core/types'
|
||||
import {
|
||||
showRecordingTip,
|
||||
hideRecordingTip,
|
||||
|
|
@ -28,7 +28,7 @@ import {
|
|||
sendAudioLevelToTip,
|
||||
showResultPopup,
|
||||
} from '../windows/WindowManager'
|
||||
import type { ScreenContext } from '@shared/types'
|
||||
import type { ScreenContext } from '@d3ro/core/types'
|
||||
|
||||
const logger = getLogger('VoiceModeService')
|
||||
|
||||
|
|
@ -189,7 +189,7 @@ class VoiceModeService extends EventEmitter {
|
|||
// Phase 11: 라이센스 쿼터 체크
|
||||
try {
|
||||
const { getLicenseService } = await import('./LicenseService')
|
||||
const { Feature } = await import('@shared/types')
|
||||
const { Feature } = await import('@d3ro/core/types')
|
||||
const license = getLicenseService()
|
||||
const access = license.canUse(Feature.DICTATION)
|
||||
if (!access.allowed) {
|
||||
|
|
@ -220,7 +220,7 @@ class VoiceModeService extends EventEmitter {
|
|||
const { getScreenContextService } = await import('./ScreenContextService')
|
||||
const ctx = getScreenContextService()
|
||||
if (ctx.isEnabled()) {
|
||||
const captureSelected = configGet('screenContextEnabled' as keyof import('@shared/types').AppConfig) as unknown as boolean
|
||||
const captureSelected = configGet('screenContextEnabled' as keyof import('@d3ro/core/types').AppConfig) as unknown as boolean
|
||||
const result = await ctx.captureContext(captureSelected)
|
||||
screenContext = result.context
|
||||
logger.info(`Screen context captured: ${screenContext.appName ?? 'unknown'}`)
|
||||
|
|
@ -555,7 +555,7 @@ class VoiceModeService extends EventEmitter {
|
|||
if (action === 'chain') {
|
||||
try {
|
||||
const { getChainService } = await import('./ChainService')
|
||||
const activeChainId = configGet('activeChainId' as keyof import('@shared/types').AppConfig) as unknown as string
|
||||
const activeChainId = configGet('activeChainId' as keyof import('@d3ro/core/types').AppConfig) as unknown as string
|
||||
if (activeChainId) {
|
||||
const chainResult = await getChainService().execute(activeChainId, contextPrefix + transcribedText)
|
||||
if (this._isInTerminalState()) return
|
||||
|
|
@ -572,7 +572,7 @@ class VoiceModeService extends EventEmitter {
|
|||
|
||||
// 음성 단축키 오버라이드 또는 활성 명령어
|
||||
const effectiveInstructionId = overrideInstructionId
|
||||
?? (configGet('activeInstructionId' as keyof import('@shared/types').AppConfig) as unknown as string)
|
||||
?? (configGet('activeInstructionId' as keyof import('@d3ro/core/types').AppConfig) as unknown as string)
|
||||
|
||||
if (action === 'custom' || overrideInstructionId) {
|
||||
let customPrompt = contextPrefix + transcribedText
|
||||
|
|
|
|||
|
|
@ -3,9 +3,9 @@
|
|||
// 서비스에서 기능 사용 전 호출하여 접근 권한 확인 + 쿼터 차단
|
||||
|
||||
import { getLicenseService } from '../services/LicenseService'
|
||||
import { D3ROError, ErrorCode } from '@shared/errors'
|
||||
import type { FeatureAccess } from '@shared/types'
|
||||
import { Feature } from '@shared/types'
|
||||
import { D3ROError, ErrorCode } from '@d3ro/core/errors'
|
||||
import type { FeatureAccess } from '@d3ro/core/types'
|
||||
import { Feature } from '@d3ro/core/types'
|
||||
|
||||
/**
|
||||
* 기능 접근 권한을 확인하고, 불가 시 D3ROError를 throw한다.
|
||||
|
|
|
|||
|
|
@ -1,31 +0,0 @@
|
|||
// src/main/utils/markdown-to-docx.ts
|
||||
// Phase 14.5: 마크다운 → DOCX 변환 유틸리티
|
||||
|
||||
import { Document, Packer, Paragraph, TextRun, HeadingLevel } from 'docx'
|
||||
|
||||
export async function markdownToDocx(markdown: string, title: string): Promise<Buffer> {
|
||||
const paragraphs: Paragraph[] = []
|
||||
|
||||
// 타이틀 추가
|
||||
paragraphs.push(new Paragraph({ text: title, heading: HeadingLevel.TITLE }))
|
||||
|
||||
// 줄 단위 파싱
|
||||
for (const line of markdown.split('\n')) {
|
||||
if (line.startsWith('## ')) {
|
||||
paragraphs.push(new Paragraph({ text: line.slice(3), heading: HeadingLevel.HEADING_2 }))
|
||||
} else if (line.startsWith('### ')) {
|
||||
paragraphs.push(new Paragraph({ text: line.slice(4), heading: HeadingLevel.HEADING_3 }))
|
||||
} else if (line.startsWith('# ')) {
|
||||
paragraphs.push(new Paragraph({ text: line.slice(2), heading: HeadingLevel.HEADING_1 }))
|
||||
} else if (line.startsWith('- [ ] ')) {
|
||||
paragraphs.push(new Paragraph({ text: `\u2610 ${line.slice(6)}`, bullet: { level: 0 } }))
|
||||
} else if (line.startsWith('- ') || line.startsWith('* ')) {
|
||||
paragraphs.push(new Paragraph({ text: line.slice(2), bullet: { level: 0 } }))
|
||||
} else if (line.trim()) {
|
||||
paragraphs.push(new Paragraph({ children: [new TextRun(line)] }))
|
||||
}
|
||||
}
|
||||
|
||||
const doc = new Document({ sections: [{ children: paragraphs }] })
|
||||
return Buffer.from(await Packer.toBuffer(doc))
|
||||
}
|
||||
|
|
@ -1,116 +0,0 @@
|
|||
// src/main/utils/meeting-markdown.ts
|
||||
// Phase 14.5: MeetingModeService에서 추출한 마크다운 유틸리티
|
||||
|
||||
import type { MeetingMinutes, MeetingSessionDetail } from '@shared/types'
|
||||
|
||||
export function formatTime(ms: number): string {
|
||||
const totalSeconds = Math.floor(ms / 1000)
|
||||
const minutes = Math.floor(totalSeconds / 60)
|
||||
const seconds = totalSeconds % 60
|
||||
return `${String(minutes).padStart(2, '0')}:${String(seconds).padStart(2, '0')}`
|
||||
}
|
||||
|
||||
export function formatDateFile(epochMs: number): string {
|
||||
const d = new Date(epochMs)
|
||||
return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}_${String(d.getHours()).padStart(2, '0')}${String(d.getMinutes()).padStart(2, '0')}`
|
||||
}
|
||||
|
||||
export function formatDateRange(startedAt: number, endedAt: number | null): string {
|
||||
const fmt = (ts: number): string => {
|
||||
const d = new Date(ts)
|
||||
return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')} ${String(d.getHours()).padStart(2, '0')}:${String(d.getMinutes()).padStart(2, '0')}`
|
||||
}
|
||||
if (!endedAt) return fmt(startedAt)
|
||||
return `${fmt(startedAt)} ~ ${new Date(endedAt).getHours()}:${String(new Date(endedAt).getMinutes()).padStart(2, '0')}`
|
||||
}
|
||||
|
||||
export function parseMinutes(markdown: string): MeetingMinutes {
|
||||
const minutes: MeetingMinutes = {
|
||||
summary: '',
|
||||
decisions: [],
|
||||
actionItems: [],
|
||||
timeline: [],
|
||||
}
|
||||
|
||||
const sections = markdown.split(/^## /m)
|
||||
for (const section of sections) {
|
||||
const lines = section.trim().split('\n')
|
||||
const heading = lines[0]?.toLowerCase() ?? ''
|
||||
const body = lines.slice(1).join('\n').trim()
|
||||
|
||||
if (heading.includes('요약') || heading.includes('summary')) {
|
||||
minutes.summary = body
|
||||
} else if (heading.includes('결정') || heading.includes('decision')) {
|
||||
minutes.decisions = body
|
||||
.split('\n')
|
||||
.filter((l) => l.startsWith('-') || l.startsWith('*'))
|
||||
.map((l) => l.replace(/^[-*]\s*/, '').trim())
|
||||
} else if (heading.includes('할 일') || heading.includes('action')) {
|
||||
minutes.actionItems = body
|
||||
.split('\n')
|
||||
.filter((l) => l.startsWith('-') || l.startsWith('*'))
|
||||
.map((l) => {
|
||||
const text = l.replace(/^[-*]\s*(\[.\]\s*)?/, '').trim()
|
||||
return { task: text }
|
||||
})
|
||||
} else if (heading.includes('타임라인') || heading.includes('timeline')) {
|
||||
const tableRows = body
|
||||
.split('\n')
|
||||
.filter((l) => l.includes('|') && !l.includes('---'))
|
||||
for (const row of tableRows) {
|
||||
const cells = row.split('|').map((c) => c.trim()).filter(Boolean)
|
||||
if (cells.length >= 2) {
|
||||
minutes.timeline.push({
|
||||
time: cells[0],
|
||||
content: cells[1],
|
||||
type: cells[1].includes('📝') ? 'memo' : 'transcript',
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return minutes
|
||||
}
|
||||
|
||||
export function buildExportMarkdown(session: MeetingSessionDetail): string {
|
||||
const durationMin = session.durationMs ? Math.round(session.durationMs / 60000) : 0
|
||||
const memoTable = session.memos.length > 0
|
||||
? `## 참석자 메모\n\n| 시간 | 메모 |\n|------|------|\n${session.memos.map((m) => `| ${formatTime(m.timestampMs)} | ${m.content} |`).join('\n')}`
|
||||
: ''
|
||||
|
||||
return `# 회의록 — ${session.title ?? '무제 회의'}
|
||||
|
||||
- **일시**: ${formatDateRange(session.startedAt, session.endedAt)}
|
||||
- **소요 시간**: ${durationMin}분
|
||||
- **STT 모델**: ${session.sttModel ?? '-'}
|
||||
- **LLM 모델**: ${session.llmModel ?? '-'}
|
||||
|
||||
---
|
||||
|
||||
${session.minutesMarkdown ?? '회의록이 생성되지 않았습니다.'}
|
||||
|
||||
---
|
||||
|
||||
${memoTable}
|
||||
|
||||
---
|
||||
|
||||
## 원문 전사
|
||||
|
||||
${session.rawTranscript ?? '(없음)'}
|
||||
`
|
||||
}
|
||||
|
||||
/** 간단한 마크다운→HTML 변환 (PDF 생성용) */
|
||||
export function markdownToSimpleHtml(md: string): string {
|
||||
return md
|
||||
.replace(/^### (.+)$/gm, '<h3>$1</h3>')
|
||||
.replace(/^## (.+)$/gm, '<h2>$1</h2>')
|
||||
.replace(/^# (.+)$/gm, '<h1>$1</h1>')
|
||||
.replace(/^\- \[.\] (.+)$/gm, '<li>$1</li>')
|
||||
.replace(/^\- (.+)$/gm, '<li>$1</li>')
|
||||
.replace(/^\* (.+)$/gm, '<li>$1</li>')
|
||||
.replace(/\n{2,}/g, '</p><p>')
|
||||
.replace(/^(?!<[h|l|t|p])/gm, '')
|
||||
}
|
||||
|
|
@ -4,7 +4,7 @@
|
|||
import { BrowserWindow, shell, screen, ipcMain, Menu } from 'electron'
|
||||
import { join } from 'path'
|
||||
import { is } from '@electron-toolkit/utils'
|
||||
import { WINDOW_SIZE } from '@shared/constants'
|
||||
import { WINDOW_SIZE } from '@d3ro/core/constants'
|
||||
import { getLogger } from '../services/LoggerService'
|
||||
import { getIsQuitting } from '../lifecycle'
|
||||
import { configGet } from '../services/ConfigService'
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
// contextBridge로 렌더러에 노출할 API 정의
|
||||
|
||||
import { contextBridge, ipcRenderer } from 'electron'
|
||||
import { IPC_CHANNELS } from '@shared/ipc-channels'
|
||||
import { IPC_CHANNELS } from '@d3ro/core/ipc-channels'
|
||||
import type {
|
||||
AudioDevice,
|
||||
SetDeviceParams,
|
||||
|
|
@ -166,9 +166,9 @@ import type {
|
|||
MeetingChatSendParams,
|
||||
MeetingChatDelta,
|
||||
DiarizeSessionParams,
|
||||
} from '@shared/types'
|
||||
import { Feature } from '@shared/types'
|
||||
import type { IPCResult } from '@shared/errors'
|
||||
} from '@d3ro/core/types'
|
||||
import { Feature } from '@d3ro/core/types'
|
||||
import type { IPCResult } from '@d3ro/core/errors'
|
||||
|
||||
type Unsubscribe = () => void
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import { I18nProvider } from './i18n'
|
|||
import { AppLayout } from './components/AppLayout'
|
||||
import { UpgradePromptModal } from './components/UpgradePromptModal'
|
||||
import { startSystemAudioCapture, stopSystemAudioCapture } from './utils/systemAudioCapture'
|
||||
import type { ThemeMode, ConfigChangedEvent } from '@shared/types'
|
||||
import type { ThemeMode, ConfigChangedEvent } from '@d3ro/core/types'
|
||||
|
||||
export function App(): React.ReactElement {
|
||||
const [themeMode, setThemeMode] = useState<ThemeMode>('auto')
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ import { StatusBar } from './StatusBar'
|
|||
import { d3roPalette, d3roFontMono, d3roTypo, d3roShadow, d3roRadius } from '../theme'
|
||||
import { useI18n } from '../i18n'
|
||||
import type { TranslationKey } from '../i18n'
|
||||
import type { LicenseTier } from '@shared/types'
|
||||
import type { LicenseTier } from '@d3ro/core/types'
|
||||
|
||||
type Route = 'dashboard' | 'history' | 'dictionary' | 'commands' | 'conversation' | 'knowledge' | 'meeting'
|
||||
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ import type {
|
|||
FileTranscriptionProgress,
|
||||
FileTranscriptionResult,
|
||||
FileTranscriptionState,
|
||||
} from '@shared/types'
|
||||
} from '@d3ro/core/types'
|
||||
|
||||
const SUPPORTED_EXTENSIONS = [
|
||||
'.mp3', '.wav', '.m4a', '.ogg', '.flac', '.wma', '.aac',
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ import {
|
|||
} from '@mui/material'
|
||||
import { d3roPalette } from '../theme'
|
||||
import { useI18n } from '../i18n'
|
||||
import type { HotkeyBinding } from '@shared/types'
|
||||
import type { HotkeyBinding } from '@d3ro/core/types'
|
||||
|
||||
// ── 키 이름 매핑 (Windows) ──────────────────────────────
|
||||
const KEY_DISPLAY_MAP: Record<number, string> = {
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ import CancelIcon from '@mui/icons-material/Cancel'
|
|||
import { MetalCard, PhosphorText, Led, ScreenPanel, PhysicalButton } from './ds'
|
||||
import { d3roPalette, d3roFontMono, d3roTypo, d3roRadius, d3roShadow } from '../theme'
|
||||
import { useI18n } from '../i18n'
|
||||
import type { LicenseInfo, LicenseTier, TierComparison, UsageQuota } from '@shared/types'
|
||||
import type { LicenseInfo, LicenseTier, TierComparison, UsageQuota } from '@d3ro/core/types'
|
||||
|
||||
interface LicenseModalProps {
|
||||
open: boolean
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ import type {
|
|||
UsageQuota,
|
||||
TierComparison,
|
||||
ActivateLicenseResult,
|
||||
} from '@shared/types'
|
||||
} from '@d3ro/core/types'
|
||||
|
||||
export function LicenseTab(): React.ReactElement {
|
||||
const { t } = useI18n()
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ import { d3roPalette, d3roFontMono, d3roShadow } from '../theme'
|
|||
import { Led } from './ds'
|
||||
import { HotkeyRecordModal } from './HotkeyRecordModal'
|
||||
import { useI18n } from '../i18n'
|
||||
import type { HotkeyBinding, AudioDevice } from '@shared/types'
|
||||
import type { HotkeyBinding, AudioDevice } from '@d3ro/core/types'
|
||||
|
||||
interface OnboardingModalProps {
|
||||
open: boolean
|
||||
|
|
@ -47,7 +47,7 @@ export function OnboardingModal({ open, onClose }: OnboardingModalProps): React.
|
|||
|
||||
const handleFinish = () => {
|
||||
// 온보딩 완료 플래그 저장
|
||||
window.electronAPI.config.set({ key: 'onboardingCompleted' as keyof import('@shared/types').AppConfig, value: true as never })
|
||||
window.electronAPI.config.set({ key: 'onboardingCompleted' as keyof import('@d3ro/core/types').AppConfig, value: true as never })
|
||||
onClose()
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import LockIcon from '@mui/icons-material/Lock'
|
|||
import { d3roPalette, d3roFontMono, d3roTypo, d3roRadius } from '../theme'
|
||||
import { useProFeature } from '../hooks/useProFeature'
|
||||
import { useI18n } from '../i18n'
|
||||
import type { Feature } from '@shared/types'
|
||||
import type { Feature } from '@d3ro/core/types'
|
||||
|
||||
interface ProBadgeProps {
|
||||
feature: Feature
|
||||
|
|
|
|||
|
|
@ -36,8 +36,8 @@ import { HotkeyRecordModal } from './HotkeyRecordModal'
|
|||
import { LicenseTab } from './LicenseTab'
|
||||
import { useI18n, LOCALE_META } from '../i18n'
|
||||
import type { Locale } from '../i18n'
|
||||
import type { ThemeMode, AppConfig, HotkeyBinding, AudioDevice } from '@shared/types'
|
||||
import { Feature } from '@shared/types'
|
||||
import type { ThemeMode, AppConfig, HotkeyBinding, AudioDevice } from '@d3ro/core/types'
|
||||
import { Feature } from '@d3ro/core/types'
|
||||
|
||||
interface SettingsModalProps {
|
||||
open: boolean
|
||||
|
|
@ -840,7 +840,7 @@ export function SettingsModal({ open, onClose }: SettingsModalProps): React.Reac
|
|||
size="small"
|
||||
onClick={() => {
|
||||
window.electronAPI.config.set({
|
||||
key: 'onboardingCompleted' as keyof import('@shared/types').AppConfig,
|
||||
key: 'onboardingCompleted' as keyof import('@d3ro/core/types').AppConfig,
|
||||
value: false as never,
|
||||
})
|
||||
onClose()
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import { Led } from './ds'
|
|||
import { d3roPalette, d3roFontMono, d3roTypo, d3roShadow, d3roRadius } from '../theme'
|
||||
import { OllamaGuideModal } from './OllamaGuideModal'
|
||||
import { useI18n } from '../i18n'
|
||||
import type { LLMStatus } from '@shared/types'
|
||||
import type { LLMStatus } from '@d3ro/core/types'
|
||||
|
||||
export function StatusBar(): React.ReactElement {
|
||||
const { t } = useI18n()
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import { MetalCard, PhosphorText, Led, PhysicalButton } from './ds'
|
|||
import { PageHeader, EmptyStateCard } from './shared'
|
||||
import { d3roPalette, d3roFontMono, d3roTypo, d3roRadius } from '../theme'
|
||||
import { useI18n } from '../i18n'
|
||||
import type { DictationTemplate, TemplateField, TemplateSessionInfo } from '@shared/types'
|
||||
import type { DictationTemplate, TemplateField, TemplateSessionInfo } from '@d3ro/core/types'
|
||||
|
||||
export function TemplateSection(): React.ReactElement {
|
||||
const { t } = useI18n()
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ import LockIcon from '@mui/icons-material/Lock'
|
|||
import CheckCircleOutlineIcon from '@mui/icons-material/CheckCircleOutline'
|
||||
import { d3roPalette, d3roFontMono, d3roTypo, d3roRadius, d3roShadow } from '../theme'
|
||||
import { useI18n } from '../i18n'
|
||||
import type { UpgradePromptEvent, UsageQuota } from '@shared/types'
|
||||
import type { UpgradePromptEvent, UsageQuota } from '@d3ro/core/types'
|
||||
|
||||
export function UpgradePromptModal(): React.ReactElement {
|
||||
const { t } = useI18n()
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import { ExportMenu } from './ExportMenu'
|
|||
import { PhysicalButton } from '../ds/PhysicalButton'
|
||||
import { d3roPalette, d3roTypo } from '../../theme'
|
||||
import { useI18n } from '../../i18n'
|
||||
import type { MeetingExportFormat } from '@shared/types'
|
||||
import type { MeetingExportFormat } from '@d3ro/core/types'
|
||||
|
||||
interface DocumentTabDoc {
|
||||
id: string
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import FileDownloadIcon from '@mui/icons-material/FileDownload'
|
|||
import { PhysicalButton } from '../ds/PhysicalButton'
|
||||
import { d3roPalette, d3roTypo, d3roFontMono, d3roRadius, d3roShadow } from '../../theme'
|
||||
import { useI18n } from '../../i18n'
|
||||
import type { MeetingExportFormat } from '@shared/types'
|
||||
import type { MeetingExportFormat } from '@d3ro/core/types'
|
||||
|
||||
interface ExportMenuProps {
|
||||
onExport: (format: MeetingExportFormat) => void
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import { PhosphorText } from '../ds/PhosphorText'
|
|||
import { PhysicalButton } from '../ds/PhysicalButton'
|
||||
import { d3roPalette, d3roFontMono, d3roTypo, d3roShadow } from '../../theme'
|
||||
import { useI18n } from '../../i18n'
|
||||
import type { MeetingChatMessage } from '@shared/types'
|
||||
import type { MeetingChatMessage } from '@d3ro/core/types'
|
||||
|
||||
interface MeetingChatPanelProps {
|
||||
sessionId: string
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ import type {
|
|||
MeetingDocument,
|
||||
MeetingDocTemplate,
|
||||
MeetingExportFormat,
|
||||
} from '@shared/types'
|
||||
} from '@d3ro/core/types'
|
||||
|
||||
interface MeetingDetailTabsProps {
|
||||
detail: MeetingSessionDetail
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ import { MetalCard, Led } from '../ds'
|
|||
import { d3roPalette, d3roFontMono, d3roTypo, d3roRadius } from '../../theme'
|
||||
import { useI18n } from '../../i18n'
|
||||
import { formatDuration } from '../../utils/formatters'
|
||||
import type { HistoryEntry, MemoTag, MeetingSummaryResult } from '@shared/types'
|
||||
import type { HistoryEntry, MemoTag, MeetingSummaryResult } from '@d3ro/core/types'
|
||||
|
||||
interface HistoryEntryCardProps {
|
||||
entry: HistoryEntry
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@
|
|||
// Pro feature gating hook: checks access, subscribes to tier changes
|
||||
|
||||
import { useState, useEffect, useCallback } from 'react'
|
||||
import { Feature } from '@shared/types'
|
||||
import type { FeatureAccess } from '@shared/types'
|
||||
import { Feature } from '@d3ro/core/types'
|
||||
import type { FeatureAccess } from '@d3ro/core/types'
|
||||
|
||||
interface UseProFeatureResult {
|
||||
/** Feature is unlocked for current tier */
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ import { PageHeader, EmptyStateCard } from '../components/shared'
|
|||
import { d3roPalette, d3roFontMono, d3roTypo, d3roRadius } from '../theme'
|
||||
import { useI18n } from '../i18n'
|
||||
import { TemplateSection } from '../components/TemplateSection'
|
||||
import type { VoiceCommandRule, VoiceCommandKeyword, KeywordMatchMode, LLMChain, ChainStep } from '@shared/types'
|
||||
import type { VoiceCommandRule, VoiceCommandKeyword, KeywordMatchMode, LLMChain, ChainStep } from '@d3ro/core/types'
|
||||
|
||||
interface CustomInstruction {
|
||||
id: string
|
||||
|
|
@ -69,10 +69,10 @@ export function CommandsPage(): React.ReactElement {
|
|||
const newId = activeId === id ? null : id
|
||||
setActiveId(newId)
|
||||
if (newId) {
|
||||
window.electronAPI.config.set({ key: 'activeInstructionId' as keyof import('@shared/types').AppConfig, value: newId as never })
|
||||
window.electronAPI.config.set({ key: 'activeInstructionId' as keyof import('@d3ro/core/types').AppConfig, value: newId as never })
|
||||
window.electronAPI.config.set({ key: 'defaultLLMAction', value: 'custom' })
|
||||
} else {
|
||||
window.electronAPI.config.set({ key: 'activeInstructionId' as keyof import('@shared/types').AppConfig, value: '' as never })
|
||||
window.electronAPI.config.set({ key: 'activeInstructionId' as keyof import('@d3ro/core/types').AppConfig, value: '' as never })
|
||||
window.electronAPI.config.set({ key: 'defaultLLMAction', value: 'none' })
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import { d3roPalette, d3roTypo } from '../theme'
|
|||
import { useI18n } from '../i18n'
|
||||
import { formatRecordingTime, formatRecordingTimeUnit, formatNumber, getDateKey } from '../utils/formatters'
|
||||
import { FileDropZone } from '../components/FileDropZone'
|
||||
import type { StatsSummary, HistoryEntry, HotkeyBinding, CaptionState, LicenseTier, UsageQuota } from '@shared/types'
|
||||
import type { StatsSummary, HistoryEntry, HotkeyBinding, CaptionState, LicenseTier, UsageQuota } from '@d3ro/core/types'
|
||||
|
||||
// ── 메인 컴포넌트 ─────────────────────────────────────
|
||||
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import { MetalCard, PhosphorText } from '../components/ds'
|
|||
import { PageHeader, SearchInput, EmptyStateCard } from '../components/shared'
|
||||
import { d3roPalette, d3roFontMono, d3roTypo } from '../theme'
|
||||
import { useI18n } from '../i18n'
|
||||
import type { DictionaryEntry, DictionaryPage as DictPageData } from '@shared/types'
|
||||
import type { DictionaryEntry, DictionaryPage as DictPageData } from '@d3ro/core/types'
|
||||
|
||||
const PAGE_SIZE = 50
|
||||
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import { d3roPalette, d3roTypo, d3roFontMono, d3roRadius } from '../theme'
|
|||
import { useI18n } from '../i18n'
|
||||
import { getDateKey } from '../utils/formatters'
|
||||
import { EmptyStateCard, SearchInput, PageHeader, HistoryEntryCard } from '../components/shared'
|
||||
import type { HistoryEntry, HistoryPage as HistoryPageData, TagCount } from '@shared/types'
|
||||
import type { HistoryEntry, HistoryPage as HistoryPageData, TagCount } from '@d3ro/core/types'
|
||||
|
||||
const PAGE_SIZE = 50
|
||||
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ import { MetalCard, PhosphorText, Led, PhysicalButton, ScreenPanel } from '../co
|
|||
import { PageHeader, EmptyStateCard } from '../components/shared'
|
||||
import { d3roPalette, d3roFontMono, d3roTypo } from '../theme'
|
||||
import { useI18n } from '../i18n'
|
||||
import type { RAGDocument, RAGQueryResult, RAGIndexProgress } from '@shared/types'
|
||||
import type { RAGDocument, RAGQueryResult, RAGIndexProgress } from '@d3ro/core/types'
|
||||
|
||||
export function KnowledgeBasePage(): React.ReactElement {
|
||||
const { t } = useI18n()
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ import type {
|
|||
MeetingProcessingProgress,
|
||||
CaptionSegment,
|
||||
MeetingMemo,
|
||||
} from '@shared/types'
|
||||
} from '@d3ro/core/types'
|
||||
|
||||
type MeetingView = 'list' | 'recording' | 'detail'
|
||||
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ import type {
|
|||
ConversationState,
|
||||
ConversationMessage,
|
||||
ConversationAssistantDelta,
|
||||
} from '@shared/types'
|
||||
} from '@d3ro/core/types'
|
||||
|
||||
export function VoiceConversationPage(): React.ReactElement {
|
||||
const { t } = useI18n()
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
// CSS Custom Properties 기반: d3roPalette가 var()를 사용하여 테마 전환 시 자동 반응.
|
||||
|
||||
import { createTheme, type Theme } from '@mui/material/styles'
|
||||
import type { ThemeMode } from '@shared/types'
|
||||
import type { ThemeMode } from '@d3ro/core/types'
|
||||
|
||||
// ── 테마 키 타입 ────────────────────────────────────────────
|
||||
type ThemeKey = 'dark' | 'light' | 'nord' | 'solarized' | 'catppuccin' | 'dracula'
|
||||
|
|
|
|||
|
|
@ -1,58 +0,0 @@
|
|||
// src/shared/constants.ts
|
||||
|
||||
/** 타이밍 상수 (Speakly 리버스엔지니어링 기반) */
|
||||
export const TIMING = {
|
||||
/** 더블프레스 감지 간격 (ms) */
|
||||
DOUBLE_PRESS_DURATION: 300,
|
||||
|
||||
/** 최소 녹음 시간 (ms) — 이하 자동 취소 */
|
||||
MIN_AUDIO_DURATION: 700,
|
||||
|
||||
/** 녹음 후 STT 대기 시간 (ms) */
|
||||
POST_RECORDING_WAIT: 4000,
|
||||
|
||||
/** 녹음 후 STT 대기 (버퍼 있을 때) (ms) */
|
||||
POST_RECORDING_WAIT_BUFFERED: 6000,
|
||||
|
||||
/** STT 아이들 타임아웃 (ms) */
|
||||
STT_IDLE_TIMEOUT: 30000,
|
||||
|
||||
/** 절대 최대 대기 시간 (ms) */
|
||||
ABSOLUTE_MAX_WAIT: 120000,
|
||||
|
||||
/** 오디오 레벨 전송 간격 (ms) */
|
||||
AUDIO_LEVEL_INTERVAL: 100,
|
||||
|
||||
/** 서비스 종료 타임아웃 (ms) */
|
||||
SERVICE_DESTROY_TIMEOUT: 3000,
|
||||
|
||||
/** 사이드카 헬스체크 지연 (ms) */
|
||||
SIDECAR_HEALTH_DELAY: 3000,
|
||||
|
||||
/** LLM 요청 타임아웃 (ms) */
|
||||
LLM_REQUEST_TIMEOUT: 30000
|
||||
} as const
|
||||
|
||||
/** 웨이브 바 상수 (RecordingTip) */
|
||||
export const WAVE_BAR = {
|
||||
COUNT: 9,
|
||||
ANIMATION_INTERVAL: 100,
|
||||
|
||||
/** 코사인 분포 가중치 (Speakly 패턴) */
|
||||
COS_WEIGHTS: Array.from({ length: 9 }, (_, i) => Math.cos((i - 4) * (Math.PI / 9)))
|
||||
} as const
|
||||
|
||||
/** 오디오 포맷 */
|
||||
export const AUDIO_FORMAT = {
|
||||
SAMPLE_RATE: 16000,
|
||||
CHANNELS: 1,
|
||||
BIT_DEPTH: 16,
|
||||
BYTES_PER_SAMPLE: 2
|
||||
} as const
|
||||
|
||||
/** 윈도우 크기 */
|
||||
export const WINDOW_SIZE = {
|
||||
MAIN: { width: 1104, height: 816 },
|
||||
RECORDING_TIP: { width: 280, height: 80 },
|
||||
RESULT_POPUP: { width: 400, height: 200 }
|
||||
} as const
|
||||
|
|
@ -1,256 +0,0 @@
|
|||
// src/shared/errors.ts
|
||||
|
||||
export enum ErrorCode {
|
||||
// === Success ===
|
||||
Success = 0,
|
||||
|
||||
// === STT (100-199) ===
|
||||
STTEngineNotInstalled = 100,
|
||||
STTModelNotFound = 101,
|
||||
STTModelNotLoaded = 102,
|
||||
STTModelLoadFailed = 103,
|
||||
STTModelDownloadFailed = 104,
|
||||
STTModelDownloadCancelled = 105,
|
||||
STTTranscriptionFailed = 110,
|
||||
STTTranscriptionTimeout = 111,
|
||||
STTTranscriptionCancelled = 112,
|
||||
STTNoAudioData = 113,
|
||||
STTAudioTooShort = 114,
|
||||
STTLanguageNotSupported = 120,
|
||||
STTSidecarSpawnFailed = 130,
|
||||
STTSidecarCrashed = 131,
|
||||
STTSidecarCommunicationFailed = 132,
|
||||
STTGPUNotAvailable = 140,
|
||||
|
||||
// === TTS (200-299) ===
|
||||
TTSEngineNotInstalled = 200,
|
||||
TTSVoiceNotFound = 201,
|
||||
TTSVoiceNotLoaded = 202,
|
||||
TTSVoiceLoadFailed = 203,
|
||||
TTSVoiceDownloadFailed = 204,
|
||||
TTSSynthesisFailed = 210,
|
||||
TTSPlaybackFailed = 211,
|
||||
TTSPlaybackInterrupted = 212,
|
||||
TTSTextTooLong = 220,
|
||||
TTSTextEmpty = 221,
|
||||
|
||||
// === LLM / Ollama (300-399) ===
|
||||
LLMServerUnreachable = 300,
|
||||
LLMServerConnectionFailed = 301,
|
||||
LLMServerTimeout = 302,
|
||||
LLMModelNotFound = 310,
|
||||
LLMModelNotLoaded = 311,
|
||||
LLMModelLoadFailed = 312,
|
||||
LLMModelPullFailed = 313,
|
||||
LLMModelPullCancelled = 314,
|
||||
LLMProcessingFailed = 320,
|
||||
LLMProcessingTimeout = 321,
|
||||
LLMProcessingCancelled = 322,
|
||||
LLMResponseParseFailed = 323,
|
||||
LLMInvalidAction = 330,
|
||||
LLMPromptTooLong = 331,
|
||||
|
||||
// === Audio (400-499) ===
|
||||
AudioDeviceNotFound = 400,
|
||||
AudioDeviceAccessDenied = 401,
|
||||
AudioDeviceBusy = 402,
|
||||
AudioCaptureStartFailed = 410,
|
||||
AudioCaptureStopFailed = 411,
|
||||
AudioCaptureFailed = 412,
|
||||
AudioNoPermission = 420,
|
||||
AudioStreamError = 430,
|
||||
AudioBufferOverflow = 431,
|
||||
|
||||
// === Hotkey (500-599) ===
|
||||
HotkeyRegistrationFailed = 500,
|
||||
HotkeyConflict = 501,
|
||||
HotkeySystemReserved = 502,
|
||||
HotkeyHookInitFailed = 510,
|
||||
HotkeyHookCrashed = 511,
|
||||
|
||||
// === TextInsert (600-699) ===
|
||||
TextInsertFailed = 600,
|
||||
TextInsertClipboardSaveFailed = 601,
|
||||
TextInsertClipboardRestoreFailed = 602,
|
||||
TextInsertKeySimulationFailed = 603,
|
||||
TextInsertNoActiveWindow = 610,
|
||||
TextInsertTargetAppNotResponding = 611,
|
||||
|
||||
// === History / Dictionary / DB (700-799) ===
|
||||
DBOpenFailed = 700,
|
||||
DBMigrationFailed = 701,
|
||||
DBQueryFailed = 702,
|
||||
DBWriteFailed = 703,
|
||||
HistoryNotFound = 710,
|
||||
HistoryExportFailed = 711,
|
||||
DictionaryNotFound = 720,
|
||||
DictionaryDuplicate = 721,
|
||||
DictionaryImportFailed = 722,
|
||||
DictionaryExportFailed = 723,
|
||||
DictionaryImportInvalidFormat = 724,
|
||||
|
||||
// === Phase 10: Memo Tags (730-739) ===
|
||||
MemoTagDuplicate = 730,
|
||||
MemoTagNotFound = 731,
|
||||
MemoExportFailed = 732,
|
||||
|
||||
// === Phase 10: Voice Commands (740-749) ===
|
||||
VoiceCommandMatchFailed = 740,
|
||||
VoiceCommandNotFound = 741,
|
||||
|
||||
// === Phase 10: Screen Context (750-759) ===
|
||||
ContextCaptureFailed = 750,
|
||||
ContextSelectedTextFailed = 751,
|
||||
|
||||
// === Phase 10: LLM Chain (760-769) ===
|
||||
ChainNotFound = 760,
|
||||
ChainExecutionFailed = 761,
|
||||
ChainStepFailed = 762,
|
||||
ChainCancelled = 763,
|
||||
|
||||
// === Phase 10: Live Caption (770-779) ===
|
||||
CaptionStartFailed = 770,
|
||||
CaptionAlreadyActive = 771,
|
||||
CaptionSTTFailed = 772,
|
||||
|
||||
// === Phase 12: File Transcription (780-784) ===
|
||||
FileTranscriptionFFmpegFailed = 780,
|
||||
FileTranscriptionInvalidFormat = 781,
|
||||
FileTranscriptionChunkFailed = 782,
|
||||
FileTranscriptionCancelled = 783,
|
||||
FileTranscriptionFileTooLarge = 784,
|
||||
|
||||
// === Phase 12: Meeting Summary (785-789) ===
|
||||
MeetingSummaryGenerationFailed = 785,
|
||||
MeetingSummaryNoTranscript = 786,
|
||||
MeetingSummaryExportFailed = 787,
|
||||
|
||||
// === Phase 12: Dictation Template (790-794) ===
|
||||
TemplateNotFound = 790,
|
||||
TemplateSessionAlreadyActive = 791,
|
||||
TemplateSessionNotActive = 792,
|
||||
TemplateFieldRecordingFailed = 793,
|
||||
TemplateInvalidFormat = 794,
|
||||
|
||||
// === Phase 13: Voice Conversation (795-799) ===
|
||||
ConversationSessionAlreadyActive = 795,
|
||||
ConversationNoActiveSession = 796,
|
||||
ConversationTTSFailed = 797,
|
||||
ConversationLLMFailed = 798,
|
||||
|
||||
// === Phase 13: Local RAG (870-874) ===
|
||||
RAGDocumentNotFound = 870,
|
||||
RAGIndexingFailed = 871,
|
||||
RAGEmbeddingFailed = 872,
|
||||
RAGQueryFailed = 873,
|
||||
RAGUnsupportedFormat = 874,
|
||||
|
||||
// === Phase 13: Voice Action (875-879) ===
|
||||
VoiceActionPlanFailed = 875,
|
||||
VoiceActionExecutionFailed = 876,
|
||||
VoiceActionBlocked = 877,
|
||||
VoiceActionInvalidPlan = 878,
|
||||
|
||||
// === Phase 14: Meeting Mode (880-889) ===
|
||||
MeetingAlreadyRecording = 880,
|
||||
MeetingNotRecording = 881,
|
||||
MeetingProcessingFailed = 882,
|
||||
MeetingSessionNotFound = 883,
|
||||
MeetingExportFailed = 884,
|
||||
MeetingPdfFailed = 885,
|
||||
MeetingDocumentNotFound = 886,
|
||||
MeetingDocGenerationFailed = 887,
|
||||
MeetingDocExportFailed = 888,
|
||||
MeetingTranscriptUpdateFailed = 889,
|
||||
MeetingDocTemplateNotFound = 890,
|
||||
MeetingDocTemplateBuiltinDelete = 891,
|
||||
MeetingDocxExportFailed = 892,
|
||||
MeetingPolishFailed = 893,
|
||||
MeetingChatFailed = 894,
|
||||
DiarizationFailed = 895,
|
||||
DiarizationModelNotLoaded = 896,
|
||||
DiarizationTokenRequired = 897,
|
||||
|
||||
// === Config (800-849) ===
|
||||
ConfigReadFailed = 800,
|
||||
ConfigWriteFailed = 801,
|
||||
ConfigInvalidValue = 802,
|
||||
ConfigKeyNotFound = 803,
|
||||
ConfigResetFailed = 804,
|
||||
ConfigMigrationFailed = 810,
|
||||
|
||||
// === License (850-869) ===
|
||||
LicenseKeyInvalid = 850,
|
||||
LicenseKeyExpired = 851,
|
||||
LicenseActivationFailed = 852,
|
||||
LicenseDeactivationFailed = 853,
|
||||
LicenseMachineIdMismatch = 854,
|
||||
LicenseOfflineGraceExpired = 855,
|
||||
LicenseVerificationFailed = 856,
|
||||
FeatureNotAvailable = 860,
|
||||
QuotaExceeded = 861,
|
||||
TierRequired = 862,
|
||||
|
||||
// === System / Window (900-999) ===
|
||||
WindowCreationFailed = 900,
|
||||
WindowNotFound = 901,
|
||||
TrayCreationFailed = 910,
|
||||
NotificationFailed = 920,
|
||||
PermissionDenied = 930,
|
||||
ExternalOpenFailed = 940,
|
||||
SoundPlayFailed = 950,
|
||||
AppAlreadyRunning = 960,
|
||||
UnknownError = 999
|
||||
}
|
||||
|
||||
/**
|
||||
* D3RO-VOICE 표준 에러 객체 (Speakly NXError 패턴)
|
||||
*/
|
||||
export class D3ROError extends Error {
|
||||
readonly code: ErrorCode
|
||||
readonly details?: Record<string, unknown>
|
||||
|
||||
constructor(code: ErrorCode, message: string, details?: Record<string, unknown>) {
|
||||
super(message)
|
||||
this.name = 'D3ROError'
|
||||
this.code = code
|
||||
this.details = details
|
||||
}
|
||||
|
||||
toJSON(): D3ROErrorJSON {
|
||||
return {
|
||||
code: this.code,
|
||||
message: this.message,
|
||||
details: this.details
|
||||
}
|
||||
}
|
||||
|
||||
static fromJSON(json: D3ROErrorJSON): D3ROError {
|
||||
return new D3ROError(json.code, json.message, json.details)
|
||||
}
|
||||
}
|
||||
|
||||
export interface D3ROErrorJSON {
|
||||
code: ErrorCode
|
||||
message: string
|
||||
details?: Record<string, unknown>
|
||||
}
|
||||
|
||||
/**
|
||||
* IPC 핸들러에서 사용하는 표준 응답 래퍼.
|
||||
*/
|
||||
export type IPCResult<T> =
|
||||
| { success: true; data: T }
|
||||
| { success: false; error: D3ROErrorJSON }
|
||||
|
||||
export function ipcSuccess<T>(data: T): IPCResult<T> {
|
||||
return { success: true, data }
|
||||
}
|
||||
|
||||
export function ipcError<T>(
|
||||
code: ErrorCode,
|
||||
message: string,
|
||||
details?: Record<string, unknown>
|
||||
): IPCResult<T> {
|
||||
return { success: false, error: { code, message, details } }
|
||||
}
|
||||
|
|
@ -1,381 +0,0 @@
|
|||
// src/shared/ipc-channels.ts
|
||||
// IPC 채널명 중앙 정의 — 모든 채널명은 이 파일에서만 정의한다.
|
||||
|
||||
export const IPC_CHANNELS = {
|
||||
VOICE: {
|
||||
START_RECORDING: 'voice:startRecording',
|
||||
STOP_RECORDING: 'voice:stopRecording',
|
||||
CANCEL_RECORDING: 'voice:cancelRecording',
|
||||
GET_STATE: 'voice:getState',
|
||||
SET_MODE: 'voice:setMode',
|
||||
GET_MODE: 'voice:getMode',
|
||||
// Main → Renderer events
|
||||
STATE_CHANGED: 'voice:stateChanged',
|
||||
TRANSCRIPTION_DELTA: 'voice:transcriptionDelta',
|
||||
TRANSCRIPTION_COMPLETE: 'voice:transcriptionComplete',
|
||||
ERROR: 'voice:error',
|
||||
AUDIO_LEVEL: 'voice:audioLevel'
|
||||
},
|
||||
|
||||
AUDIO: {
|
||||
GET_DEVICES: 'audio:getDevices',
|
||||
GET_SELECTED_DEVICE: 'audio:getSelectedDevice',
|
||||
SET_SELECTED_DEVICE: 'audio:setSelectedDevice',
|
||||
TEST_DEVICE: 'audio:testDevice',
|
||||
// Main → Renderer events
|
||||
DEVICE_CHANGED: 'audio:deviceChanged'
|
||||
},
|
||||
|
||||
STT: {
|
||||
GET_STATUS: 'stt:getStatus',
|
||||
GET_MODELS: 'stt:getModels',
|
||||
GET_ACTIVE_MODEL: 'stt:getActiveModel',
|
||||
SET_MODEL: 'stt:setModel',
|
||||
DOWNLOAD_MODEL: 'stt:downloadModel',
|
||||
CANCEL_DOWNLOAD: 'stt:cancelDownload',
|
||||
GET_LANGUAGE: 'stt:getLanguage',
|
||||
SET_LANGUAGE: 'stt:setLanguage',
|
||||
// Main → Renderer events
|
||||
STATUS_CHANGED: 'stt:statusChanged',
|
||||
DOWNLOAD_PROGRESS: 'stt:downloadProgress'
|
||||
},
|
||||
|
||||
TTS: {
|
||||
SPEAK: 'tts:speak',
|
||||
STOP: 'tts:stop',
|
||||
GET_VOICES: 'tts:getVoices',
|
||||
GET_ACTIVE_VOICE: 'tts:getActiveVoice',
|
||||
SET_VOICE: 'tts:setVoice',
|
||||
GET_STATUS: 'tts:getStatus',
|
||||
DOWNLOAD_VOICE: 'tts:downloadVoice',
|
||||
// Main → Renderer events
|
||||
STATUS_CHANGED: 'tts:statusChanged',
|
||||
SPEAKING_STATE_CHANGED: 'tts:speakingStateChanged'
|
||||
},
|
||||
|
||||
LLM: {
|
||||
GET_STATUS: 'llm:getStatus',
|
||||
GET_MODELS: 'llm:getModels',
|
||||
GET_ACTIVE_MODEL: 'llm:getActiveModel',
|
||||
SET_MODEL: 'llm:setModel',
|
||||
PROCESS: 'llm:process',
|
||||
CANCEL_PROCESS: 'llm:cancelProcess',
|
||||
GET_SERVER_URL: 'llm:getServerUrl',
|
||||
SET_SERVER_URL: 'llm:setServerUrl',
|
||||
PULL_MODEL: 'llm:pullModel',
|
||||
// Main → Renderer events
|
||||
STATUS_CHANGED: 'llm:statusChanged',
|
||||
PROCESS_PROGRESS: 'llm:processProgress',
|
||||
PULL_PROGRESS: 'llm:pullProgress'
|
||||
},
|
||||
|
||||
HOTKEY: {
|
||||
GET_DICTATION_SHORTCUT: 'hotkey:getDictationShortcut',
|
||||
SET_DICTATION_SHORTCUT: 'hotkey:setDictationShortcut',
|
||||
GET_HANDS_FREE_SHORTCUT: 'hotkey:getHandsFreeShortcut',
|
||||
SET_HANDS_FREE_SHORTCUT: 'hotkey:setHandsFreeShortcut',
|
||||
GET_COMMAND_SHORTCUT: 'hotkey:getCommandShortcut',
|
||||
SET_COMMAND_SHORTCUT: 'hotkey:setCommandShortcut',
|
||||
GET_CAPTION_SHORTCUT: 'hotkey:getCaptionShortcut',
|
||||
SET_CAPTION_SHORTCUT: 'hotkey:setCaptionShortcut',
|
||||
IS_ENABLED: 'hotkey:isEnabled',
|
||||
SET_ENABLED: 'hotkey:setEnabled',
|
||||
START_RECORDING: 'hotkey:startRecording',
|
||||
STOP_RECORDING: 'hotkey:stopRecording',
|
||||
// Main → Renderer events
|
||||
TRIGGERED: 'hotkey:triggered',
|
||||
RECORDING_RESULT: 'hotkey:recordingResult'
|
||||
},
|
||||
|
||||
CONFIG: {
|
||||
GET: 'config:get',
|
||||
SET: 'config:set',
|
||||
GET_ALL: 'config:getAll',
|
||||
RESET: 'config:reset',
|
||||
GET_THEME: 'config:getTheme',
|
||||
SET_THEME: 'config:setTheme',
|
||||
GET_LANGUAGE: 'config:getLanguage',
|
||||
SET_LANGUAGE: 'config:setLanguage',
|
||||
GET_AUTO_LAUNCH: 'config:getAutoLaunch',
|
||||
SET_AUTO_LAUNCH: 'config:setAutoLaunch',
|
||||
GET_CLOSE_TO_TRAY: 'config:getCloseToTray',
|
||||
SET_CLOSE_TO_TRAY: 'config:setCloseToTray',
|
||||
// Main → Renderer events
|
||||
CHANGED: 'config:changed'
|
||||
},
|
||||
|
||||
HISTORY: {
|
||||
GET_ALL: 'history:getAll',
|
||||
GET_BY_ID: 'history:getById',
|
||||
DELETE: 'history:delete',
|
||||
DELETE_ALL: 'history:deleteAll',
|
||||
SEARCH: 'history:search',
|
||||
EXPORT: 'history:export',
|
||||
// Main → Renderer events
|
||||
ADDED: 'history:added'
|
||||
},
|
||||
|
||||
DICTIONARY: {
|
||||
GET_ALL: 'dictionary:getAll',
|
||||
ADD: 'dictionary:add',
|
||||
UPDATE: 'dictionary:update',
|
||||
DELETE: 'dictionary:delete',
|
||||
IMPORT: 'dictionary:import',
|
||||
EXPORT: 'dictionary:export',
|
||||
SEARCH: 'dictionary:search'
|
||||
},
|
||||
|
||||
WINDOW: {
|
||||
MINIMIZE: 'window:minimize',
|
||||
MAXIMIZE: 'window:maximize',
|
||||
CLOSE: 'window:close',
|
||||
IS_MAXIMIZED: 'window:isMaximized',
|
||||
SHOW_RECORDING_TIP: 'window:showRecordingTip',
|
||||
HIDE_RECORDING_TIP: 'window:hideRecordingTip',
|
||||
SHOW_RESULT_POPUP: 'window:showResultPopup',
|
||||
HIDE_RESULT_POPUP: 'window:hideResultPopup',
|
||||
TIP_MEASURED: 'window:tipMeasured',
|
||||
// Main → Renderer events
|
||||
TIP_STATE_CHANGED: 'window:tipStateChanged',
|
||||
TIP_PREPARE: 'window:tipPrepare',
|
||||
TIP_SHOW: 'window:tipShow'
|
||||
},
|
||||
|
||||
SYSTEM: {
|
||||
GET_PLATFORM: 'system:getPlatform',
|
||||
GET_VERSION: 'system:getVersion',
|
||||
CHECK_MIC_PERMISSION: 'system:checkMicPermission',
|
||||
REQUEST_MIC_PERMISSION: 'system:requestMicPermission',
|
||||
SHOW_NOTIFICATION: 'system:showNotification',
|
||||
OPEN_EXTERNAL: 'system:openExternal',
|
||||
GET_ACTIVE_APP: 'system:getActiveApp',
|
||||
INSERT_TEXT: 'system:insertText',
|
||||
PLAY_SOUND: 'system:playSound',
|
||||
SET_SOUND_ENABLED: 'system:setSoundEnabled',
|
||||
IS_SOUND_ENABLED: 'system:isSoundEnabled'
|
||||
},
|
||||
|
||||
STATS: {
|
||||
GET_SUMMARY: 'stats:getSummary',
|
||||
GET_DAILY: 'stats:getDaily',
|
||||
GET_WEEKLY: 'stats:getWeekly',
|
||||
// Main → Renderer events
|
||||
UPDATED: 'stats:updated'
|
||||
},
|
||||
|
||||
// ── Phase 10: Memo Tags (10.3) ──
|
||||
MEMO: {
|
||||
GET_TAGS: 'memo:getTags',
|
||||
ADD_TAG: 'memo:addTag',
|
||||
REMOVE_TAG: 'memo:removeTag',
|
||||
GET_ALL_TAGS: 'memo:getAllTags',
|
||||
SEARCH_BY_TAG: 'memo:searchByTag',
|
||||
EXPORT: 'memo:export',
|
||||
},
|
||||
|
||||
// ── Phase 10: Voice Commands (10.5) ──
|
||||
VOICE_COMMAND: {
|
||||
GET_ALL: 'voiceCommand:getAll',
|
||||
SET_KEYWORDS: 'voiceCommand:setKeywords',
|
||||
SET_ENABLED: 'voiceCommand:setEnabled',
|
||||
IS_ENABLED: 'voiceCommand:isEnabled',
|
||||
// Main → Renderer events
|
||||
MATCHED: 'voiceCommand:matched',
|
||||
},
|
||||
|
||||
// ── Phase 10: Screen Context (10.2) ──
|
||||
CONTEXT: {
|
||||
CAPTURE: 'context:capture',
|
||||
GET_CONFIG: 'context:getConfig',
|
||||
SET_ENABLED: 'context:setEnabled',
|
||||
IS_ENABLED: 'context:isEnabled',
|
||||
},
|
||||
|
||||
// ── Phase 10: LLM Chain (10.4) ──
|
||||
CHAIN: {
|
||||
GET_ALL: 'chain:getAll',
|
||||
CREATE: 'chain:create',
|
||||
UPDATE: 'chain:update',
|
||||
DELETE: 'chain:delete',
|
||||
EXECUTE: 'chain:execute',
|
||||
// Main → Renderer events
|
||||
PROGRESS: 'chain:progress',
|
||||
},
|
||||
|
||||
// ── Phase 10: Live Caption (10.1) ──
|
||||
CAPTION: {
|
||||
START: 'caption:start',
|
||||
STOP: 'caption:stop',
|
||||
GET_STATE: 'caption:getState',
|
||||
SET_CONFIG: 'caption:setConfig',
|
||||
GET_CONFIG: 'caption:getConfig',
|
||||
/** 렌더러 → 메인: 시스템 오디오 PCM 데이터 전달 */
|
||||
SYSTEM_AUDIO_DATA: 'caption:systemAudioData',
|
||||
// Main → Renderer events
|
||||
SEGMENT: 'caption:segment',
|
||||
DELTA: 'caption:delta',
|
||||
STATE_CHANGED: 'caption:stateChanged',
|
||||
SESSION_SAVED: 'caption:sessionSaved',
|
||||
/** 메인 → 렌더러: 시스템 오디오 캡처 시작/정지 요청 */
|
||||
START_SYSTEM_AUDIO: 'caption:startSystemAudio',
|
||||
STOP_SYSTEM_AUDIO: 'caption:stopSystemAudio',
|
||||
},
|
||||
|
||||
// ── Phase 12: File Transcription (12.1) ──
|
||||
FILE_TRANSCRIPTION: {
|
||||
START: 'fileTranscription:start',
|
||||
CANCEL: 'fileTranscription:cancel',
|
||||
GET_STATE: 'fileTranscription:getState',
|
||||
// Main → Renderer events
|
||||
PROGRESS: 'fileTranscription:progress',
|
||||
COMPLETE: 'fileTranscription:complete',
|
||||
ERROR: 'fileTranscription:error',
|
||||
},
|
||||
|
||||
// ── Phase 12: Meeting Summary (12.2) ──
|
||||
MEETING_SUMMARY: {
|
||||
SUMMARIZE: 'meetingSummary:summarize',
|
||||
GET_SUMMARY: 'meetingSummary:getSummary',
|
||||
EXPORT_MARKDOWN: 'meetingSummary:exportMarkdown',
|
||||
// Main → Renderer events
|
||||
SUMMARY_READY: 'meetingSummary:summaryReady',
|
||||
SUMMARY_PROGRESS: 'meetingSummary:progress',
|
||||
},
|
||||
|
||||
// ── Phase 12: Dictation Templates (12.3) ──
|
||||
DICTATION_TEMPLATE: {
|
||||
GET_ALL: 'dictationTemplate:getAll',
|
||||
CREATE: 'dictationTemplate:create',
|
||||
UPDATE: 'dictationTemplate:update',
|
||||
DELETE: 'dictationTemplate:delete',
|
||||
START_SESSION: 'dictationTemplate:startSession',
|
||||
CANCEL_SESSION: 'dictationTemplate:cancelSession',
|
||||
GET_SESSION_STATE: 'dictationTemplate:getSessionState',
|
||||
SET_FIELD_VALUE: 'dictationTemplate:setFieldValue',
|
||||
// Main → Renderer events
|
||||
SESSION_STATE_CHANGED: 'dictationTemplate:sessionStateChanged',
|
||||
FIELD_COMPLETED: 'dictationTemplate:fieldCompleted',
|
||||
SESSION_COMPLETED: 'dictationTemplate:sessionCompleted',
|
||||
},
|
||||
|
||||
// ── Phase 13: Voice Conversation (13.1) ──
|
||||
VOICE_CONVERSATION: {
|
||||
START_SESSION: 'voiceConversation:startSession',
|
||||
STOP_SESSION: 'voiceConversation:stopSession',
|
||||
SEND_MESSAGE: 'voiceConversation:sendMessage',
|
||||
GET_STATE: 'voiceConversation:getState',
|
||||
GET_HISTORY: 'voiceConversation:getHistory',
|
||||
CLEAR_HISTORY: 'voiceConversation:clearHistory',
|
||||
CANCEL_RESPONSE: 'voiceConversation:cancelResponse',
|
||||
// Main → Renderer events
|
||||
STATE_CHANGED: 'voiceConversation:stateChanged',
|
||||
USER_MESSAGE: 'voiceConversation:userMessage',
|
||||
ASSISTANT_DELTA: 'voiceConversation:assistantDelta',
|
||||
ASSISTANT_MESSAGE: 'voiceConversation:assistantMessage',
|
||||
TTS_STARTED: 'voiceConversation:ttsStarted',
|
||||
TTS_FINISHED: 'voiceConversation:ttsFinished',
|
||||
ERROR: 'voiceConversation:error',
|
||||
},
|
||||
|
||||
// ── Phase 13: Local RAG (13.2) ──
|
||||
RAG: {
|
||||
ADD_DOCUMENT: 'rag:addDocument',
|
||||
REMOVE_DOCUMENT: 'rag:removeDocument',
|
||||
GET_DOCUMENTS: 'rag:getDocuments',
|
||||
QUERY: 'rag:query',
|
||||
GET_STATE: 'rag:getState',
|
||||
REINDEX: 'rag:reindex',
|
||||
// Main → Renderer events
|
||||
INDEX_PROGRESS: 'rag:indexProgress',
|
||||
INDEX_COMPLETE: 'rag:indexComplete',
|
||||
QUERY_RESULT: 'rag:queryResult',
|
||||
},
|
||||
|
||||
// ── Phase 13: Voice Action / OS Automation (13.3) ──
|
||||
VOICE_ACTION: {
|
||||
EXECUTE: 'voiceAction:execute',
|
||||
GET_PRESETS: 'voiceAction:getPresets',
|
||||
GET_HISTORY: 'voiceAction:getHistory',
|
||||
CLEAR_HISTORY: 'voiceAction:clearHistory',
|
||||
SET_ENABLED: 'voiceAction:setEnabled',
|
||||
IS_ENABLED: 'voiceAction:isEnabled',
|
||||
// Main → Renderer events
|
||||
ACTION_PLANNED: 'voiceAction:actionPlanned',
|
||||
ACTION_EXECUTED: 'voiceAction:actionExecuted',
|
||||
ACTION_ERROR: 'voiceAction:actionError',
|
||||
},
|
||||
|
||||
// ── Phase 14: Meeting Mode ──
|
||||
MEETING_MODE: {
|
||||
START_RECORDING: 'meetingMode:startRecording',
|
||||
STOP_RECORDING: 'meetingMode:stopRecording',
|
||||
ADD_MEMO: 'meetingMode:addMemo',
|
||||
GET_STATE: 'meetingMode:getState',
|
||||
GET_SESSIONS: 'meetingMode:getSessions',
|
||||
GET_SESSION: 'meetingMode:getSession',
|
||||
DELETE_SESSION: 'meetingMode:deleteSession',
|
||||
UPDATE_TITLE: 'meetingMode:updateTitle',
|
||||
EXPORT_PDF: 'meetingMode:exportPdf',
|
||||
EXPORT_MARKDOWN: 'meetingMode:exportMarkdown',
|
||||
// Phase 14.5: 문서 생성/편집/내보내기
|
||||
UPDATE_TRANSCRIPT: 'meetingMode:updateTranscript',
|
||||
GENERATE_DOCUMENT: 'meetingMode:generateDocument',
|
||||
GET_DOCUMENTS: 'meetingMode:getDocuments',
|
||||
UPDATE_DOCUMENT: 'meetingMode:updateDocument',
|
||||
DELETE_DOCUMENT: 'meetingMode:deleteDocument',
|
||||
EXPORT_DOCUMENT: 'meetingMode:exportDocument',
|
||||
EXPORT_TRANSCRIPT: 'meetingMode:exportTranscript',
|
||||
EDIT_SEGMENT: 'meetingMode:editSegment',
|
||||
// Main → Renderer events
|
||||
STATE_CHANGED: 'meetingMode:stateChanged',
|
||||
SEGMENT: 'meetingMode:segment',
|
||||
PROCESSING_PROGRESS: 'meetingMode:processingProgress',
|
||||
SESSION_COMPLETED: 'meetingMode:sessionCompleted',
|
||||
DOC_GENERATING_PROGRESS: 'meetingMode:docGeneratingProgress',
|
||||
POLISH_TRANSCRIPT: 'meetingMode:polishTranscript',
|
||||
DIARIZE: 'meetingMode:diarize',
|
||||
DIARIZATION_PROGRESS: 'meetingMode:diarizationProgress',
|
||||
ERROR: 'meetingMode:error',
|
||||
},
|
||||
|
||||
// ── Phase 14.5: Meeting Document Templates ──
|
||||
MEETING_DOC_TEMPLATE: {
|
||||
GET_ALL: 'meetingDocTemplate:getAll',
|
||||
CREATE: 'meetingDocTemplate:create',
|
||||
UPDATE: 'meetingDocTemplate:update',
|
||||
DELETE: 'meetingDocTemplate:delete',
|
||||
},
|
||||
|
||||
// ── Phase 15: Meeting AI Chat ──
|
||||
MEETING_CHAT: {
|
||||
SEND: 'meetingChat:send',
|
||||
CANCEL: 'meetingChat:cancel',
|
||||
CLEAR: 'meetingChat:clear',
|
||||
DELTA: 'meetingChat:delta',
|
||||
MESSAGE: 'meetingChat:message',
|
||||
ERROR: 'meetingChat:error',
|
||||
},
|
||||
|
||||
// ── Phase 11: License & Monetization ──
|
||||
LICENSE: {
|
||||
GET_INFO: 'license:getInfo',
|
||||
ACTIVATE: 'license:activate',
|
||||
DEACTIVATE: 'license:deactivate',
|
||||
CHECK_FEATURE: 'license:checkFeature',
|
||||
GET_USAGE: 'license:getUsage',
|
||||
GET_ALL_USAGE: 'license:getAllUsage',
|
||||
GET_TIER_COMPARISON: 'license:getTierComparison',
|
||||
// Main → Renderer events
|
||||
UPGRADE_PROMPT: 'license:upgradePrompt',
|
||||
TIER_CHANGED: 'license:tierChanged',
|
||||
},
|
||||
} as const
|
||||
|
||||
// 타입 유틸리티: 채널명 유니온 추출
|
||||
type NestedValues<T> = T extends Record<string, infer V>
|
||||
? V extends string
|
||||
? V
|
||||
: NestedValues<V>
|
||||
: never
|
||||
|
||||
export type IPCChannel = NestedValues<typeof IPC_CHANNELS>
|
||||
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue