diff --git a/src/cli/print.ts b/src/cli/print.ts index 0166cec94..6cddf7b08 100644 --- a/src/cli/print.ts +++ b/src/cli/print.ts @@ -321,11 +321,8 @@ import { } from 'src/utils/queryProfiler.js' import { asSessionId } from 'src/types/ids.js' import { - commitAutonomyQueuedPrompt, - createAutonomyQueuedPrompt, createAutonomyQueuedPromptIfNoActiveSource, createProactiveAutonomyCommands, - markAutonomyRunCancelled, markAutonomyRunFailed, } from 'src/utils/autonomyRuns.js' import { @@ -333,7 +330,6 @@ import { claimConsumableQueuedAutonomyCommands, finalizeAutonomyCommandsForTurn, } from 'src/utils/autonomyQueueLifecycle.js' -import { prepareAutonomyTurnPrompt } from 'src/utils/autonomyAuthority.js' import { jsonStringify } from '../utils/slowOperations.js' import { skillChangeDetector } from '../utils/skills/skillChangeDetector.js' import { getCommands, clearCommandsCache } from '../commands.js' @@ -2827,17 +2823,22 @@ function runHeadlessStreaming( onFire: prompt => { if (inputClosed) return void (async () => { - const prepared = await prepareAutonomyTurnPrompt({ + // Use the prompt itself as the dedup source: legacy KAIROS-style + // cron entries fire the same prompt repeatedly, and without a + // dedicated task id the prompt text is what uniquely identifies + // the entry. Without source-dedup, repeated fires would stack + // additional runs while an earlier one is still active. Match the + // onFireTask branch below to keep the two paths consistent. + const command = await createAutonomyQueuedPromptIfNoActiveSource({ basePrompt: prompt, trigger: 'scheduled-task', currentDir: cwd(), - }) - if (inputClosed) return - const command = await commitAutonomyQueuedPrompt({ - prepared, - currentDir: cwd(), + sourceId: prompt, + sourceLabel: prompt, workload: WORKLOAD_CRON, + shouldCreate: () => !inputClosed, }) + if (!command) return if (inputClosed) { await cancelQueuedAutonomyCommands({ commands: [command] }) return diff --git a/src/services/compact/postCompactCleanup.ts b/src/services/compact/postCompactCleanup.ts index aa789f05b..a98806c4e 100644 --- a/src/services/compact/postCompactCleanup.ts +++ b/src/services/compact/postCompactCleanup.ts @@ -69,6 +69,12 @@ export function runPostCompactCleanup(querySource?: QuerySource): void { // cacheUtils resets. See compactConversation() for full rationale. clearBetaTracingState() if (feature('COMMIT_ATTRIBUTION')) { + // Intentionally fire-and-forget: the file-content cache sweep is a + // best-effort memory release whose completion no caller depends on. + // Keeping `runPostCompactCleanup` synchronous lets compaction call sites + // (REPL post-compact handler, /compact command, autoCompact) finish their + // own state transitions without an extra microtask round-trip — the sweep + // catches up on the next event-loop tick. void import('../../utils/attributionHooks.js').then(m => m.sweepFileContentCache(), ) diff --git a/src/utils/autonomyFlows.ts b/src/utils/autonomyFlows.ts index f15867a33..01334937e 100644 --- a/src/utils/autonomyFlows.ts +++ b/src/utils/autonomyFlows.ts @@ -170,6 +170,12 @@ function isManagedFlowStatusActive(status: AutonomyFlowStatus): boolean { function selectPersistedAutonomyFlows( flows: AutonomyFlowRecord[], ): AutonomyFlowRecord[] { + // Two-phase sort. Phase 1: priority sort (active flows first, then by + // updatedAt desc) selects the AUTONOMY_FLOWS_MAX most-relevant records to + // retain — active flows are guaranteed a slot before any inactive flow is + // considered. Phase 2: re-sort the retained slice by updatedAt desc only, + // so the persisted file is in plain reverse-chronological order regardless + // of activity status. Listings/UI consume the persisted order directly. const retained = flows .slice() .map(cloneFlowRecord) diff --git a/tests/integration/autonomy-lifecycle-user-flow.test.ts b/tests/integration/autonomy-lifecycle-user-flow.test.ts index 2cf6a654f..b9e7bd172 100644 --- a/tests/integration/autonomy-lifecycle-user-flow.test.ts +++ b/tests/integration/autonomy-lifecycle-user-flow.test.ts @@ -42,8 +42,8 @@ async function runAutonomyCli(args: string[]): Promise { proc.exited, ]) - expect(stderr).toBe('') - expect(exitCode).toBe(0) + expect(stderr, `unexpected stderr output:\n${stderr}`).toBe('') + expect(exitCode, `non-zero exit ${exitCode}; stderr:\n${stderr}`).toBe(0) return stdout }