mirror of
https://github.com/stablyai/orca.git
synced 2026-10-24 16:03:45 +00:00
fix(agent-hooks): keep startup reconciliation install-only
This commit is contained in:
@@ -46,6 +46,7 @@ import {
|
||||
installManagedAgentHooks,
|
||||
removeManagedAgentHooksAsync,
|
||||
resolveStartupManagedHookAction,
|
||||
shouldInstallStartupManagedAgentHook,
|
||||
shouldContinueManagedHookStartup
|
||||
} from './managed-agent-hook-controls'
|
||||
|
||||
@@ -292,6 +293,41 @@ describe('startup managed hook reconciliation (STA-5679)', () => {
|
||||
expect(resolveStartupManagedHookAction(null)).toBe('install')
|
||||
})
|
||||
|
||||
it('only allows startup installs for globally enabled and agent-enabled hooks', () => {
|
||||
expect(shouldInstallStartupManagedAgentHook({ agentStatusHooksEnabled: false }, 'codex')).toBe(
|
||||
false
|
||||
)
|
||||
expect(
|
||||
shouldInstallStartupManagedAgentHook(
|
||||
{ agentStatusHooksEnabled: true, disabledTuiAgents: ['codex'] },
|
||||
'codex'
|
||||
)
|
||||
).toBe(false)
|
||||
expect(
|
||||
shouldInstallStartupManagedAgentHook(
|
||||
{ agentStatusHooksEnabled: true, disabledTuiAgents: ['claude'] },
|
||||
'codex'
|
||||
)
|
||||
).toBe(true)
|
||||
})
|
||||
|
||||
it('does not remove disabled agents during startup install reconciliation', async () => {
|
||||
const settings = {
|
||||
agentStatusHooksEnabled: true,
|
||||
agentCmdOverrides: {},
|
||||
disabledTuiAgents: ['claude' as const]
|
||||
}
|
||||
mocks.detect.mockResolvedValue({ codex: { state: 'found' } })
|
||||
|
||||
await installManagedAgentHooks(settings, {
|
||||
shouldContinue: (agent) => shouldContinueManagedHookStartup(false, settings, agent)
|
||||
})
|
||||
|
||||
expect(mocks.removeClaude).not.toHaveBeenCalled()
|
||||
expect(mocks.installClaude).not.toHaveBeenCalled()
|
||||
expect(mocks.installCodex).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
|
||||
it('still removes through the explicit Settings toggle', async () => {
|
||||
// Anchors the assertion above: the removers really are wired, so 'skip' is a behavioral
|
||||
// difference rather than a vacuous constant.
|
||||
|
||||
@@ -54,6 +54,16 @@ export function resolveStartupManagedHookAction(
|
||||
return isAgentStatusHooksEnabled(settings) ? 'install' : 'skip'
|
||||
}
|
||||
|
||||
export function shouldInstallStartupManagedAgentHook(
|
||||
settings: ManagedHookSettings,
|
||||
agent: AgentHookTarget
|
||||
): boolean {
|
||||
return (
|
||||
resolveStartupManagedHookAction(settings) === 'install' &&
|
||||
!normalizeDisabledTuiAgents(settings?.disabledTuiAgents).includes(agent)
|
||||
)
|
||||
}
|
||||
|
||||
export function shouldContinueManagedHookStartup(
|
||||
isQuitting: boolean,
|
||||
settings: ManagedHookSettings,
|
||||
|
||||
+19
-14
@@ -89,10 +89,11 @@ import {
|
||||
sweepRestoredSubagentsWithoutLiveAgent
|
||||
} from './agent-hooks/restored-subagent-liveness-sweep'
|
||||
import {
|
||||
applyAgentStatusHooksEnabled,
|
||||
installManagedAgentHooks,
|
||||
isAgentStatusHooksEnabled,
|
||||
removeManagedAgentHooksAsync,
|
||||
resolveStartupManagedHookAction,
|
||||
shouldInstallStartupManagedAgentHook,
|
||||
shouldContinueManagedHookStartup
|
||||
} from './agent-hooks/managed-agent-hook-controls'
|
||||
import { initCohortClassifier } from './telemetry/cohort-classifier'
|
||||
@@ -3089,25 +3090,29 @@ void app.whenReady().then(async () => {
|
||||
// ordered before managed-hook reconciliation — an incapable host must re-arm
|
||||
// and complete the legacy real-home sweep first — but awaiting it inline
|
||||
// stalled app init behind that session, so chain instead of blocking.
|
||||
const realHomeCodexHookState = codexRuntimeHome.isHostSystemDefaultRealHomeSelected()
|
||||
? ensureRealHomeCodexHookState({
|
||||
hooksEnabled: isAgentStatusHooksEnabled(store.getSettings()),
|
||||
userDataPath: app.getPath('userData')
|
||||
}).catch((error: unknown) => {
|
||||
console.warn('[codex-real-home-hooks] startup ensure failed:', error)
|
||||
})
|
||||
: Promise.resolve()
|
||||
const startupManagedHookSettings = store.getSettings()
|
||||
const shouldReconcileStartupManagedHooks =
|
||||
shouldInstallManagedHooks(is.dev) &&
|
||||
resolveStartupManagedHookAction(startupManagedHookSettings) === 'install'
|
||||
const realHomeCodexHookState =
|
||||
shouldReconcileStartupManagedHooks &&
|
||||
shouldInstallStartupManagedAgentHook(startupManagedHookSettings, 'codex') &&
|
||||
codexRuntimeHome.isHostSystemDefaultRealHomeSelected()
|
||||
? ensureRealHomeCodexHookState({
|
||||
hooksEnabled: true,
|
||||
userDataPath: app.getPath('userData')
|
||||
}).catch((error: unknown) => {
|
||||
console.warn('[codex-real-home-hooks] startup ensure failed:', error)
|
||||
})
|
||||
: Promise.resolve()
|
||||
// Why skip rather than remove when the off switch is set: the hook files are user-global but this
|
||||
// decision reads only THIS profile's settings, so removing here deletes the hooks every other Orca
|
||||
// instance depends on (STA-5679). Skipping already keeps removed hooks from reappearing on launch.
|
||||
if (
|
||||
shouldInstallManagedHooks(is.dev) &&
|
||||
resolveStartupManagedHookAction(store.getSettings()) === 'install'
|
||||
) {
|
||||
if (shouldReconcileStartupManagedHooks) {
|
||||
const managedHookStore = store
|
||||
void realHomeCodexHookState
|
||||
.then(() =>
|
||||
applyAgentStatusHooksEnabled(true, managedHookStore.getSettings(), {
|
||||
installManagedAgentHooks(managedHookStore.getSettings(), {
|
||||
shouldHydrateShellPath: app.isPackaged,
|
||||
onInstallError: recordManagedHookInstallFailure,
|
||||
shouldContinue: (agent) => {
|
||||
|
||||
Reference in New Issue
Block a user