d3ro-voice/apps/desktop/src/main/ipc/input-telemetry-handlers.ts
Yun Chan 5c11ee2fde
Some checks failed
deploy-site / deploy (push) Failing after 33s
portable-unsigned / portable-windows (push) Failing after 4m7s
release / release-windows (push) Failing after 3m16s
release: ship v1.5.0 with on-device writing suggestions
Adds next-sentence suggestions while typing, weekly input insights and a
personal phrase memory to the desktop app, and fixes custom instructions so
they process the text instead of inserting the instruction's own wording.
Local model requests are now bounded and individually cancellable.

Bumps the product version to 1.5.0 (Android/iOS build 1050000), refreshes the
landing and web download links, and records the new INPUT feature rows and the
open verification gaps in the infrastructure map.
2026-09-23 16:04:27 +09:00

164 lines
4.7 KiB
TypeScript

// src/main/ipc/input-telemetry-handlers.ts
// 입력 텔레메트리 수집 동의 · 리포트 · 개인 문구 관리.
import { ipcMain } from 'electron'
import { IPC_CHANNELS } from '@d3ro/core/ipc-channels'
import { ipcSuccess, ipcError, ErrorCode } from '@d3ro/core/errors'
import { getInputTelemetryService } from '../services/InputTelemetryService'
import { getPersonalGraphService } from '../services/PersonalGraphService'
import { getSuggestionService } from '../services/SuggestionService'
export interface SetInputTelemetryEnabledParams {
enabled: boolean
}
export interface SetInputTelemetryPausedParams {
paused: boolean
}
export interface InputSummaryParams {
days?: number
}
export interface InputPhrasesParams {
limit?: number
}
export interface DeletePhraseParams {
id: string
}
export function registerInputTelemetryHandlers(): void {
ipcMain.handle(IPC_CHANNELS.INPUT_TELEMETRY.GET_STATE, async () => {
try {
return ipcSuccess(getInputTelemetryService().getState())
} catch (error) {
return ipcError(
ErrorCode.InputTelemetryConfigFailed,
error instanceof Error ? error.message : String(error)
)
}
})
ipcMain.handle(
IPC_CHANNELS.INPUT_TELEMETRY.SET_ENABLED,
async (_event, params: SetInputTelemetryEnabledParams) => {
try {
getInputTelemetryService().setEnabled(params.enabled === true)
// 동의를 끄면 제안도 더 이상 입력 맥락을 받을 수 없다.
if (params.enabled !== true) getSuggestionService().applyConfig()
return ipcSuccess(getInputTelemetryService().getState())
} catch (error) {
return ipcError(
ErrorCode.InputTelemetryConfigFailed,
error instanceof Error ? error.message : String(error)
)
}
}
)
ipcMain.handle(
IPC_CHANNELS.INPUT_TELEMETRY.SET_PAUSED,
async (_event, params: SetInputTelemetryPausedParams) => {
try {
getInputTelemetryService().setPaused(params.paused === true)
return ipcSuccess(getInputTelemetryService().getState())
} catch (error) {
return ipcError(
ErrorCode.InputTelemetryConfigFailed,
error instanceof Error ? error.message : String(error)
)
}
}
)
ipcMain.handle(
IPC_CHANNELS.INPUT_TELEMETRY.GET_SUMMARY,
async (_event, params?: InputSummaryParams) => {
try {
return ipcSuccess(getInputTelemetryService().getSummary(params?.days ?? 7))
} catch (error) {
return ipcError(
ErrorCode.DBQueryFailed,
error instanceof Error ? error.message : String(error)
)
}
}
)
ipcMain.handle(IPC_CHANNELS.INPUT_TELEMETRY.GET_PRIVACY_RECEIPT, async () => {
try {
return ipcSuccess(getInputTelemetryService().getPrivacyReceipt())
} catch (error) {
return ipcError(
ErrorCode.DBQueryFailed,
error instanceof Error ? error.message : String(error)
)
}
})
ipcMain.handle(
IPC_CHANNELS.INPUT_TELEMETRY.GET_PHRASES,
async (_event, params?: InputPhrasesParams) => {
try {
return ipcSuccess(getInputTelemetryService().listPhrases(params?.limit ?? 100))
} catch (error) {
return ipcError(
ErrorCode.DBQueryFailed,
error instanceof Error ? error.message : String(error)
)
}
}
)
ipcMain.handle(
IPC_CHANNELS.INPUT_TELEMETRY.DELETE_PHRASE,
async (_event, params: DeletePhraseParams) => {
try {
return ipcSuccess(getInputTelemetryService().deletePhrase(params.id))
} catch (error) {
return ipcError(
ErrorCode.DBWriteFailed,
error instanceof Error ? error.message : String(error)
)
}
}
)
ipcMain.handle(IPC_CHANNELS.INPUT_TELEMETRY.GET_GRAPH, async () => {
try {
return ipcSuccess(getPersonalGraphService().getStats())
} catch (error) {
return ipcError(
ErrorCode.DBQueryFailed,
error instanceof Error ? error.message : String(error)
)
}
})
ipcMain.handle(
IPC_CHANNELS.INPUT_TELEMETRY.QUERY_GRAPH,
async (_event, params: { text: string; limit?: number }) => {
try {
return ipcSuccess(getPersonalGraphService().query(params.text, params.limit ?? 12))
} catch (error) {
return ipcError(
ErrorCode.DBQueryFailed,
error instanceof Error ? error.message : String(error)
)
}
}
)
ipcMain.handle(IPC_CHANNELS.INPUT_TELEMETRY.CLEAR_ALL, async () => {
try {
getInputTelemetryService().clearAll()
return ipcSuccess(undefined)
} catch (error) {
return ipcError(
ErrorCode.DBWriteFailed,
error instanceof Error ? error.message : String(error)
)
}
})
}