Files
04931df162 MUL-8174: fix OpenCode resume after host clock rollback (#9460)
* fix(opencode): retire future-dated resume sessions (MUL-8174)

Co-authored-by: multica-agent <[email protected]>

* fix(opencode): check resume clocks across CLI versions

Co-authored-by: multica-agent <[email protected]>

---------

Co-authored-by: Sol-Boy <[email protected]>
Co-authored-by: multica-agent <[email protected]>
2026-10-23 14:41:13 +08:00

41 lines
1.5 KiB
Go

package daemon
import (
"context"
"errors"
"log/slog"
"github.com/multica-ai/multica/server/internal/daemon/execenv"
"github.com/multica-ai/multica/server/pkg/agent"
)
// gateOpenCodeResumeToSaneClock returns the retired pointer before changing
// either prompt carrier. Callers must persist it even if fresh launch fails.
func gateOpenCodeResumeToSaneClock(ctx context.Context, task *Task, taskCtx *execenv.TaskContextForEnv, provider string, cfg agent.Config, cwd string, mcpConfig []byte, taskLog *slog.Logger) string {
if provider != "opencode" || task.PriorSessionID == "" {
return ""
}
var customArgs []string
if task.Agent != nil {
customArgs = task.Agent.CustomArgs
}
err := agent.CheckOpenCodeResumeClock(ctx, cfg, agent.ExecOptions{
Cwd: cwd, ResumeSessionID: task.PriorSessionID, CustomArgs: customArgs, McpConfig: mcpConfig,
})
if err == nil {
taskLog.Debug("OpenCode resume clock checked", "resume_clock_check", "verified")
return ""
}
if !errors.Is(err, agent.ErrOpenCodeClockSkew) {
taskLog.Warn("OpenCode resume clock check unavailable; continuing existing resume behavior", "resume_clock_check", "unverified", "reason", err)
return ""
}
retired := task.PriorSessionID
task.PriorSessionID = ""
task.PriorSessionResumeUnavailable = true
taskCtx.PriorSessionResumed = false
taskCtx.PriorSessionResumeUnavailable = true
taskLog.Warn("OpenCode session has future timestamps; starting a fresh session", "resume_clock_check", "unsafe", "retired_session_id", retired)
return retired
}