refactor: reduce cyclomatic complexity of settings, tool data and layout sanitizers
Add characterization tests first, then split the hot spots into small helpers: - STT/TTS settings updates move to extensions/piagentui-speech-settings.ts (rule tables) - defaultExtractData is split into diff/diagnostic/output extractors - getToolSummaryCategory becomes an ordered rule table (toolSummary.ts) - sanitizePersistedTerminalLayoutMap is split per level - duplicated diff stats helpers are merged into utils/diffStats.ts
This commit is contained in:
1 parent
da09846708
commit
2d2cdf3b19
13 files changed
+962
-404
No files matched your search
@@ -21,6 +21,7 @@ import {
|
||||
type StoredSttSettings,
|
||||
type StoredTtsSettings,
|
||||
} from './piagentui-settings-store.js'
|
||||
import { applySttSettingsUpdate, applyTtsSettingsUpdate, isTtsResponseFormat } from './piagentui-speech-settings.js'
|
||||
import {
|
||||
buildExtensionCatalog,
|
||||
executeExtensionInstallCommand,
|
||||
@@ -774,56 +775,11 @@ export default function (pi: ExtensionAPI) {
|
||||
|
||||
function updateSttSettings(update: any): { ok: true; settings: SanitizedSttSettings } | { ok: false; error: string } {
|
||||
const current = getLocalSettings()
|
||||
const existing = current.stt || {}
|
||||
const next: StoredSttSettings = { ...existing }
|
||||
const result = applySttSettingsUpdate(current.stt || {}, update)
|
||||
if (!result.ok) return result
|
||||
|
||||
if (update.enabled !== undefined) next.enabled = update.enabled === true
|
||||
if (update.providerKind !== undefined) {
|
||||
if (update.providerKind !== 'openai' && update.providerKind !== 'openai-compatible') {
|
||||
return { ok: false, error: 'Invalid providerKind' }
|
||||
}
|
||||
next.providerKind = update.providerKind
|
||||
}
|
||||
if (update.mode !== undefined) {
|
||||
if (update.mode !== 'file' && update.mode !== 'realtime') return { ok: false, error: 'Invalid mode' }
|
||||
next.mode = update.mode
|
||||
}
|
||||
if (update.baseUrl !== undefined) {
|
||||
if (typeof update.baseUrl !== 'string' || !validateSttBaseUrl(update.baseUrl)) {
|
||||
return { ok: false, error: 'Invalid baseUrl' }
|
||||
}
|
||||
next.baseUrl = update.baseUrl.replace(/\/+$/, '')
|
||||
}
|
||||
if (update.apiKeyRequired !== undefined) next.apiKeyRequired = update.apiKeyRequired === true
|
||||
if (update.transcriptionEndpoint !== undefined) {
|
||||
if (typeof update.transcriptionEndpoint !== 'string' || !update.transcriptionEndpoint.startsWith('/')) {
|
||||
return { ok: false, error: 'Invalid transcriptionEndpoint' }
|
||||
}
|
||||
next.transcriptionEndpoint = update.transcriptionEndpoint
|
||||
}
|
||||
if (update.transcriptionModel !== undefined) {
|
||||
if (typeof update.transcriptionModel !== 'string' || !update.transcriptionModel.trim()) {
|
||||
return { ok: false, error: 'Invalid transcriptionModel' }
|
||||
}
|
||||
next.transcriptionModel = update.transcriptionModel.trim()
|
||||
}
|
||||
if (update.language !== undefined) {
|
||||
if (update.language === null || update.language === '') delete next.language
|
||||
else if (typeof update.language === 'string') next.language = update.language.trim()
|
||||
else return { ok: false, error: 'Invalid language' }
|
||||
}
|
||||
if (update.insertMode !== undefined) {
|
||||
if (update.insertMode !== 'append' && update.insertMode !== 'replace')
|
||||
return { ok: false, error: 'Invalid insertMode' }
|
||||
next.insertMode = update.insertMode
|
||||
}
|
||||
if (Object.prototype.hasOwnProperty.call(update, 'apiKey')) {
|
||||
if (update.apiKey === null) delete next.apiKey
|
||||
else if (typeof update.apiKey === 'string' && update.apiKey.trim()) next.apiKey = update.apiKey.trim()
|
||||
}
|
||||
|
||||
saveLocalSettings({ ...current, stt: next })
|
||||
return { ok: true, settings: sanitizeSttSettings(next) }
|
||||
saveLocalSettings({ ...current, stt: result.next })
|
||||
return { ok: true, settings: sanitizeSttSettings(result.next) }
|
||||
}
|
||||
|
||||
function getEffectiveTtsSettings(): StoredTtsSettings {
|
||||
@@ -857,62 +813,13 @@ export default function (pi: ExtensionAPI) {
|
||||
}
|
||||
}
|
||||
|
||||
function isTtsResponseFormat(value: unknown): value is NonNullable<StoredTtsSettings['responseFormat']> {
|
||||
return (
|
||||
value === 'mp3' || value === 'opus' || value === 'aac' || value === 'flac' || value === 'wav' || value === 'pcm'
|
||||
)
|
||||
}
|
||||
|
||||
function updateTtsSettings(update: any): { ok: true; settings: SanitizedTtsSettings } | { ok: false; error: string } {
|
||||
const current = getLocalSettings()
|
||||
const existing = current.tts || {}
|
||||
const next: StoredTtsSettings = { ...existing }
|
||||
const result = applyTtsSettingsUpdate(current.tts || {}, update)
|
||||
if (!result.ok) return result
|
||||
|
||||
if (update.enabled !== undefined) next.enabled = update.enabled === true
|
||||
if (update.providerKind !== undefined) {
|
||||
if (update.providerKind !== 'openai' && update.providerKind !== 'openai-compatible') {
|
||||
return { ok: false, error: 'Invalid providerKind' }
|
||||
}
|
||||
next.providerKind = update.providerKind
|
||||
}
|
||||
if (update.baseUrl !== undefined) {
|
||||
if (typeof update.baseUrl !== 'string' || !validateSttBaseUrl(update.baseUrl)) {
|
||||
return { ok: false, error: 'Invalid baseUrl' }
|
||||
}
|
||||
next.baseUrl = update.baseUrl.replace(/\/+$/, '')
|
||||
}
|
||||
if (update.apiKeyRequired !== undefined) next.apiKeyRequired = update.apiKeyRequired === true
|
||||
if (update.speechEndpoint !== undefined) {
|
||||
if (typeof update.speechEndpoint !== 'string' || !update.speechEndpoint.startsWith('/')) {
|
||||
return { ok: false, error: 'Invalid speechEndpoint' }
|
||||
}
|
||||
next.speechEndpoint = update.speechEndpoint
|
||||
}
|
||||
if (update.model !== undefined) {
|
||||
if (typeof update.model !== 'string' || !update.model.trim()) return { ok: false, error: 'Invalid model' }
|
||||
next.model = update.model.trim()
|
||||
}
|
||||
if (update.voice !== undefined) {
|
||||
if (typeof update.voice !== 'string' || !update.voice.trim()) return { ok: false, error: 'Invalid voice' }
|
||||
next.voice = update.voice.trim()
|
||||
}
|
||||
if (update.responseFormat !== undefined) {
|
||||
if (!isTtsResponseFormat(update.responseFormat)) return { ok: false, error: 'Invalid responseFormat' }
|
||||
next.responseFormat = update.responseFormat
|
||||
}
|
||||
if (update.speed !== undefined) {
|
||||
if (typeof update.speed !== 'number' || update.speed < 0.25 || update.speed > 4) {
|
||||
return { ok: false, error: 'Invalid speed' }
|
||||
}
|
||||
next.speed = update.speed
|
||||
}
|
||||
if (Object.prototype.hasOwnProperty.call(update, 'apiKey')) {
|
||||
if (update.apiKey === null) delete next.apiKey
|
||||
else if (typeof update.apiKey === 'string' && update.apiKey.trim()) next.apiKey = update.apiKey.trim()
|
||||
}
|
||||
|
||||
saveLocalSettings({ ...current, tts: next })
|
||||
return { ok: true, settings: sanitizeTtsSettings(next) }
|
||||
saveLocalSettings({ ...current, tts: result.next })
|
||||
return { ok: true, settings: sanitizeTtsSettings(result.next) }
|
||||
}
|
||||
|
||||
async function readRequestBuffer(req: http.IncomingMessage): Promise<Buffer> {
|
||||
|
||||
Reference in new issue
Block a user