fix(cli-run): rely on continuation markers for completion
Use hook-written continuation marker state to gate run completion checks and remove the noisy event-stream shutdown timeout log in run mode.
This commit is contained in:
@@ -1,5 +1,9 @@
|
||||
import type { PluginInput } from "@opencode-ai/plugin"
|
||||
|
||||
import {
|
||||
clearContinuationMarker,
|
||||
setContinuationMarkerSource,
|
||||
} from "../../features/run-continuation-state"
|
||||
import { log } from "../../shared/logger"
|
||||
|
||||
const HOOK_NAME = "stop-continuation-guard"
|
||||
@@ -13,12 +17,13 @@ export interface StopContinuationGuard {
|
||||
}
|
||||
|
||||
export function createStopContinuationGuardHook(
|
||||
_ctx: PluginInput
|
||||
ctx: PluginInput
|
||||
): StopContinuationGuard {
|
||||
const stoppedSessions = new Set<string>()
|
||||
|
||||
const stop = (sessionID: string): void => {
|
||||
stoppedSessions.add(sessionID)
|
||||
setContinuationMarkerSource(ctx.directory, sessionID, "stop", "stopped", "continuation stopped")
|
||||
log(`[${HOOK_NAME}] Continuation stopped for session`, { sessionID })
|
||||
}
|
||||
|
||||
@@ -28,6 +33,7 @@ export function createStopContinuationGuardHook(
|
||||
|
||||
const clear = (sessionID: string): void => {
|
||||
stoppedSessions.delete(sessionID)
|
||||
setContinuationMarkerSource(ctx.directory, sessionID, "stop", "idle")
|
||||
log(`[${HOOK_NAME}] Continuation guard cleared for session`, { sessionID })
|
||||
}
|
||||
|
||||
@@ -42,6 +48,7 @@ export function createStopContinuationGuardHook(
|
||||
const sessionInfo = props?.info as { id?: string } | undefined
|
||||
if (sessionInfo?.id) {
|
||||
clear(sessionInfo.id)
|
||||
clearContinuationMarker(ctx.directory, sessionInfo.id)
|
||||
log(`[${HOOK_NAME}] Session deleted: cleaned up`, { sessionID: sessionInfo.id })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,28 @@
|
||||
import { describe, expect, test } from "bun:test"
|
||||
import { afterEach, describe, expect, test } from "bun:test"
|
||||
import { mkdtempSync, rmSync } from "node:fs"
|
||||
import { join } from "node:path"
|
||||
import { tmpdir } from "node:os"
|
||||
import { readContinuationMarker } from "../../features/run-continuation-state"
|
||||
import { createStopContinuationGuardHook } from "./index"
|
||||
|
||||
describe("stop-continuation-guard", () => {
|
||||
const tempDirs: string[] = []
|
||||
|
||||
function createTempDir(): string {
|
||||
const directory = mkdtempSync(join(tmpdir(), "omo-stop-guard-"))
|
||||
tempDirs.push(directory)
|
||||
return directory
|
||||
}
|
||||
|
||||
afterEach(() => {
|
||||
while (tempDirs.length > 0) {
|
||||
const directory = tempDirs.pop()
|
||||
if (directory) {
|
||||
rmSync(directory, { recursive: true, force: true })
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
function createMockPluginInput() {
|
||||
return {
|
||||
client: {
|
||||
@@ -9,13 +30,14 @@ describe("stop-continuation-guard", () => {
|
||||
showToast: async () => ({}),
|
||||
},
|
||||
},
|
||||
directory: "/tmp/test",
|
||||
} as never
|
||||
directory: createTempDir(),
|
||||
} as any
|
||||
}
|
||||
|
||||
test("should mark session as stopped", () => {
|
||||
// given - a guard hook with no stopped sessions
|
||||
const guard = createStopContinuationGuardHook(createMockPluginInput())
|
||||
const input = createMockPluginInput()
|
||||
const guard = createStopContinuationGuardHook(input)
|
||||
const sessionID = "test-session-1"
|
||||
|
||||
// when - we stop continuation for the session
|
||||
@@ -23,6 +45,9 @@ describe("stop-continuation-guard", () => {
|
||||
|
||||
// then - session should be marked as stopped
|
||||
expect(guard.isStopped(sessionID)).toBe(true)
|
||||
|
||||
const marker = readContinuationMarker(input.directory, sessionID)
|
||||
expect(marker?.sources.stop?.state).toBe("stopped")
|
||||
})
|
||||
|
||||
test("should return false for non-stopped sessions", () => {
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
import type { PluginInput } from "@opencode-ai/plugin"
|
||||
|
||||
import type { BackgroundManager } from "../../features/background-agent"
|
||||
import {
|
||||
clearContinuationMarker,
|
||||
} from "../../features/run-continuation-state"
|
||||
import { log } from "../../shared/logger"
|
||||
|
||||
import { DEFAULT_SKIP_AGENTS, HOOK_NAME } from "./constants"
|
||||
@@ -45,6 +48,7 @@ export function createTodoContinuationHandler(args: {
|
||||
if (event.type === "session.idle") {
|
||||
const sessionID = props?.sessionID as string | undefined
|
||||
if (!sessionID) return
|
||||
|
||||
await handleSessionIdle({
|
||||
ctx,
|
||||
sessionID,
|
||||
@@ -56,6 +60,13 @@ export function createTodoContinuationHandler(args: {
|
||||
return
|
||||
}
|
||||
|
||||
if (event.type === "session.deleted") {
|
||||
const sessionInfo = props?.info as { id?: string } | undefined
|
||||
if (sessionInfo?.id) {
|
||||
clearContinuationMarker(ctx.directory, sessionInfo.id)
|
||||
}
|
||||
}
|
||||
|
||||
handleNonIdleEvent({
|
||||
eventType: event.type,
|
||||
properties: props,
|
||||
|
||||
Reference in New Issue
Block a user