Skip to content

fix(attach): fetch on-demand transcripts for untracked sessions - #1877

Open
Legonaftik wants to merge 1 commit into
entireio:mainfrom
Legonaftik:fix/opencode-attach-fetch-untracked
Open

fix(attach): fetch on-demand transcripts for untracked sessions#1877
Legonaftik wants to merge 1 commit into
entireio:mainfrom
Legonaftik:fix/opencode-attach-fetch-untracked

Conversation

@Legonaftik

@Legonaftik Legonaftik commented Jul 30, 2026

Copy link
Copy Markdown

Fixes #1876.

Problem

entire session attach <id> --agent opencode fails with transcript not found for OpenCode sessions Entire never tracked — e.g. sessions spawned by an external session host rather than a hooked terminal. resolveAndValidateTranscript only calls PrepareTranscript when the transcript file already exists under .entire/tmp, on the assumption that preparation "can't conjure a file that was never started". For OpenCode that assumption is false: its transcript is produced on demand by opencode export (fetchAndCacheExport), which works for any session in the opencode store, tracked or not. OpenCode also lacks a SessionBaseDirProvider, so the project-dir fallback can't help. Net effect: no way to attach the correct session when hooks didn't capture one.

Fix

  • New optional TranscriptFetcher agent capability (agent.go + AsTranscriptFetcher, type-assertion gated like SidecarImageProvider): the agent can materialize a session transcript on demand, including for sessions with no hook-cached file.
  • OpenCodeAgent.FetchTranscript implements it via the existing fetchAndCacheExport (which already honors ENTIRE_TEST_OPENCODE_MOCK_EXPORT).
  • resolveAndValidateTranscript consults the capability after the initial stat fails, before the project-dir search fallback. File-based agents are unaffected.

Out of scope (noted in the issue): session list enumeration from the opencode store — the attach path was the workflow blocker.

Testing

  • New regression test TestAttach_OpenCodeFetchesTranscriptForUntrackedSession: a session with no hook-cached export attaches successfully via the fetch path (mock-export mode), producing session state with a checkpoint id.
  • TestFetchTranscript_ValidatesSessionID / TestFetchTranscript_AttemptsExport for the new method.
  • go test ./cmd/entire/cli/... and golangci-lint run clean.

Verification (downstream)

The same scenario was exercised end-to-end against a real externally-hosted OpenCode session (opencode export succeeds, attach previously failed); with this change the fetch path materializes the transcript and attach proceeds.

Copilot AI review requested due to automatic review settings July 30, 2026 13:07
@Legonaftik
Legonaftik requested a review from a team as a code owner July 30, 2026 13:07
Sessions spawned outside a hooked terminal (e.g. by an external session
host) never get a hook-cached export under .entire/tmp, so
resolveAndValidateTranscript gave up: PrepareTranscript is only called
when the transcript file already exists, and OpenCode has no
SessionBaseDirProvider fallback search.

OpenCode can materialize any session's transcript via opencode export,
tracked or not. Add a TranscriptFetcher capability (agent can fetch a
transcript on demand), implement it on OpenCodeAgent via
fetchAndCacheExport, and consult it in resolveAndValidateTranscript
after the initial stat fails, before the project-dir search fallback.

Refs entireio#1876
@Legonaftik
Legonaftik force-pushed the fix/opencode-attach-fetch-untracked branch from ab7bc82 to 36724c8 Compare July 30, 2026 13:14

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes entire session attach <id> --agent opencode failing with “transcript not found” for OpenCode sessions that were never hook-tracked by allowing the OpenCode agent to materialize transcripts on demand during attach.

Changes:

  • Introduces an optional TranscriptFetcher agent capability and a helper AsTranscriptFetcher for type-assertion-based discovery.
  • Implements FetchTranscript for OpenCode via the existing fetchAndCacheExport (opencode export-backed).
  • Updates attach transcript resolution to attempt FetchTranscript after the initial transcript-path stat fails, and adds regression/unit tests around the new behavior.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
cmd/entire/cli/attach.go Adds a fetch-on-demand fallback (via TranscriptFetcher) to transcript resolution during attach.
cmd/entire/cli/attach_test.go Adds a regression test covering attach succeeding when OpenCode transcript must be fetched/materialized.
cmd/entire/cli/agent/opencode/lifecycle.go Implements FetchTranscript using fetchAndCacheExport.
cmd/entire/cli/agent/opencode/lifecycle_test.go Adds unit tests for FetchTranscript behavior (ID validation and export attempt).
cmd/entire/cli/agent/capabilities.go Adds AsTranscriptFetcher optional capability resolver.
cmd/entire/cli/agent/agent.go Defines the new TranscriptFetcher capability interface.

Comment thread cmd/entire/cli/attach.go
Comment on lines +813 to +817
// Agents that can materialize a transcript on demand (e.g. OpenCode via
// `opencode export`) can conjure one even when no hook-cached file exists,
// e.g. sessions spawned by an external host rather than a hooked terminal.
if fetcher, ok := agent.AsTranscriptFetcher(ag); ok {
fetched, fetchErr := fetcher.FetchTranscript(ctx, sessionID)
Comment on lines +402 to +417
func TestFetchTranscript_AttemptsExport(t *testing.T) {
t.Parallel()

// Without mock-export mode, FetchTranscript must attempt `opencode export`
// — proving it tries to materialize the transcript for sessions with no
// hook-cached file rather than stat-checking an existing one. Without a
// usable session the export fails, wrapped as "opencode export failed".
ag := &OpenCodeAgent{}
_, err := ag.FetchTranscript(context.Background(), "test-fetch-transcript-no-such-session")
if err == nil {
t.Fatal("expected error for nonexistent session, got nil")
}
if !strings.Contains(err.Error(), "opencode export failed") {
t.Errorf("expected 'opencode export failed' error, got: %v", err)
}
}
Comment on lines +1907 to +1913
// TestAttach_OpenCodeFetchesTranscriptForUntrackedSession is a regression test
// for sessions spawned outside a hooked terminal (e.g. by an external session
// host): no hook ever cached an export under .entire/tmp, and
// resolveAndValidateTranscript used to give up because PrepareTranscript was
// only called when the file already existed. OpenCode can materialize the
// transcript via `opencode export`, so attach now consults the
// TranscriptFetcher capability before failing.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

session attach cannot find transcripts for OpenCode sessions not spawned from a hooked terminal

2 participants