()
| 1913 | }) |
| 1914 | |
| 1915 | const run = async () => { |
| 1916 | if (running) { |
| 1917 | return |
| 1918 | } |
| 1919 | |
| 1920 | running = true |
| 1921 | runPhase = undefined |
| 1922 | notifySessionStateChanged('running') |
| 1923 | idleTimeout.stop() |
| 1924 | |
| 1925 | headlessProfilerCheckpoint('run_entry') |
| 1926 | // TODO(custom-tool-refactor): Should move to the init message, like browser |
| 1927 | |
| 1928 | await updateSdkMcp() |
| 1929 | headlessProfilerCheckpoint('after_updateSdkMcp') |
| 1930 | |
| 1931 | // Resolve deferred plugin installation (CLAUDE_CODE_SYNC_PLUGIN_INSTALL). |
| 1932 | // The promise was started eagerly so installation overlaps with other init. |
| 1933 | // Awaiting here guarantees plugins are available before the first ask(). |
| 1934 | // If CLAUDE_CODE_SYNC_PLUGIN_INSTALL_TIMEOUT_MS is set, races against that |
| 1935 | // deadline and proceeds without plugins on timeout (logging an error). |
| 1936 | if (pluginInstallPromise) { |
| 1937 | const timeoutMs = parseInt( |
| 1938 | process.env.CLAUDE_CODE_SYNC_PLUGIN_INSTALL_TIMEOUT_MS || '', |
| 1939 | 10, |
| 1940 | ) |
| 1941 | if (timeoutMs > 0) { |
| 1942 | const timeout = sleep(timeoutMs).then(() => 'timeout' as const) |
| 1943 | const result = await Promise.race([pluginInstallPromise, timeout]) |
| 1944 | if (result === 'timeout') { |
| 1945 | logError( |
| 1946 | new Error( |
| 1947 | `CLAUDE_CODE_SYNC_PLUGIN_INSTALL: plugin installation timed out after ${timeoutMs}ms`, |
| 1948 | ), |
| 1949 | ) |
| 1950 | logEvent('tengu_sync_plugin_install_timeout', { |
| 1951 | timeout_ms: timeoutMs, |
| 1952 | }) |
| 1953 | } |
| 1954 | } else { |
| 1955 | await pluginInstallPromise |
| 1956 | } |
| 1957 | pluginInstallPromise = null |
| 1958 | |
| 1959 | // Refresh commands, agents, and hooks now that plugins are installed |
| 1960 | await refreshPluginState() |
| 1961 | |
| 1962 | // Set up hot-reload for plugin hooks now that the initial install is done. |
| 1963 | // In sync-install mode, setup.ts skips this to avoid racing with the install. |
| 1964 | const { setupPluginHookHotReload } = await import( |
| 1965 | '../utils/plugins/loadPluginHooks.js' |
| 1966 | ) |
| 1967 | setupPluginHookHotReload() |
| 1968 | } |
| 1969 | |
| 1970 | // Only main-thread commands (agentId===undefined) — subagent |
| 1971 | // notifications are drained by the subagent's mid-turn gate in query.ts. |
| 1972 | // Defined outside the try block so it's accessible in the post-finally |
no test coverage detected