diff --git a/tui_gateway/entry.py b/tui_gateway/entry.py index 2c1804aac1..d3be53a6c4 100644 --- a/tui_gateway/entry.py +++ b/tui_gateway/entry.py @@ -175,8 +175,8 @@ def main(): # loaded once by ``_config_mtime`` elsewhere) and only pay the import # cost when there's actually MCP work to do. try: - from hermes_cli.config import load_config - _mcp_servers = (load_config() or {}).get("mcp_servers") + from hermes_cli.config import read_raw_config + _mcp_servers = (read_raw_config() or {}).get("mcp_servers") _has_mcp_servers = isinstance(_mcp_servers, dict) and len(_mcp_servers) > 0 except Exception: # Be conservative: if we can't decide, fall back to the old diff --git a/ui-tui/src/app/useSubmission.ts b/ui-tui/src/app/useSubmission.ts index ed86332b08..a7d2631dbd 100644 --- a/ui-tui/src/app/useSubmission.ts +++ b/ui-tui/src/app/useSubmission.ts @@ -127,9 +127,9 @@ export function useSubmission(opts: UseSubmissionOptions) { } // Plain prompts are the common path and should not pay an extra RPC - // before prompt.submit. File-drop detection can still run for inputs - // that contain an absolute/tilde path or file:// URI. - if (!looksLikeSlashCommand(text) && !/(?:^|\s)(?:file:\/\/|~\/|\/)[^\s]+/.test(text)) { + // before prompt.submit. File-drop detection still runs for absolute, + // tilde, file://, and explicit relative paths. + if (!looksLikeSlashCommand(text) && !/(?:^|\s)(?:file:\/\/|~\/|\.?\.\/|\/)[^\s]+/.test(text)) { return startSubmit(text, expand(text), showUserMessage) } diff --git a/ui-tui/src/lib/memoryMonitor.ts b/ui-tui/src/lib/memoryMonitor.ts index 41b357568f..e792df4cde 100644 --- a/ui-tui/src/lib/memoryMonitor.ts +++ b/ui-tui/src/lib/memoryMonitor.ts @@ -38,11 +38,16 @@ async function _ensureEvictInkCaches(): Promise<(level: 'all' | 'half') => unkno return _evictInkCaches } - _evictInkCachesPromise ??= import('@hermes/ink').then(mod => { - _evictInkCaches = mod.evictInkCaches as (level: 'all' | 'half') => unknown + _evictInkCachesPromise ??= import('@hermes/ink') + .then(mod => { + _evictInkCaches = mod.evictInkCaches as (level: 'all' | 'half') => unknown - return _evictInkCaches - }) + return _evictInkCaches + }) + .catch(err => { + _evictInkCachesPromise = null + throw err + }) return _evictInkCachesPromise } @@ -80,21 +85,22 @@ export function startMemoryMonitor({ // by the time a tick fires 10s after launch the app has already loaded // the same module, so this resolves instantly from the ESM cache. try { - const evictInkCaches = await _ensureEvictInkCaches() - evictInkCaches(level === 'critical' ? 'all' : 'half') - } catch { - // Best-effort: if the dynamic import fails for any reason we still - // continue to the heap dump below so the user gets diagnostics. + try { + const evictInkCaches = await _ensureEvictInkCaches() + evictInkCaches(level === 'critical' ? 'all' : 'half') + } catch { + // Best-effort: if the dynamic import fails for any reason we still + // continue to the heap dump below so the user gets diagnostics. + } + + dumped.add(level) + const dump = await performHeapDump(level === 'critical' ? 'auto-critical' : 'auto-high').catch(() => null) + const snap: MemorySnapshot = { heapUsed, level, rss } + + ;(level === 'critical' ? onCritical : onHigh)?.(snap, dump) + } finally { + inFlight.delete(level) } - - dumped.add(level) - const dump = await performHeapDump(level === 'critical' ? 'auto-critical' : 'auto-high').catch(() => null) - - inFlight.delete(level) - - const snap: MemorySnapshot = { heapUsed, level, rss } - - ;(level === 'critical' ? onCritical : onHigh)?.(snap, dump) } const handle = setInterval(() => void tick(), intervalMs)