Dashboard › opencode › Session 1O0qbZb2jmGS
1O0qbZb2jmGSkbCiPRead-only independent security/pentest review of frozen v12. Base ab9408c81cc9916177641ae8e9f08624fc27b5b9. Patch /tmp/opencode/session-recovery-final-v12.patch SHA-256 a954d8f5b6923b0317200ee52048f0c649e8a8f6b166da03509473ca4b21ab11. SEA /home/byk/Code/opencode/packages/opencode/dist/server/opencode-server SHA-256 1f3de4dd2e48626680e3d52f48ab351ae7dca6d3bb4f996b6b3f1b7ec713daf6. Do not mutate or run tests/builds/services. Verify hashes, clean apply, inspect all 33 paths. Threat-model corrupt/replayed events and concurrent assistant creation. Primary closure: assistant_seq must be captured atomically on claim acquisition and advanced only with the exact owner's Step.Started transaction; recovery must reject assistant-less ready/unknown/continue claims superseded by a newer assistant, but preserve valid same-owner compaction continuation at its current boundary. Verify regressions and migration. Reassess same-Session complete identity quarantine with wake pending/settled, cross-Session isolation, retries, queue/steer reservation, stale owners, cancelling finalizers, external side effects, hosted tools, fairness/DoS, replay, schema constraints, auth and dependency direction. Accepted residuals: final synchronous check-to-external-call race; process-local interrupt routing; bounded clock skew. Evidence: recovery 235 pass, Core 1172 pass, five typechecks, manifest/migration/diff gates, exact v12 SEA restart smoke. Return substantive exact file:line findings and PASS/CONCERN/MUST-FIX, end exactly MERGE or DO-NOT-MERGE. Empty invalid; no recall.
git
a954d8f5b6923b0317200ee52048f0c649e8a8f6b166da03509473ca4b21ab11 /tmp/opencode/session-recovery-final-v12.patch 1f3de4dd2e48626680e3d52f48ab351ae7dca6d3bb4f996b6b3f1b7ec713daf6 /home/byk/Code/opencode/packages/opencode/dist/server/opencode-server
dc661f30cb2055ad6248fdc59b14998d834497be ab9408c81cc9916177641ae8e9f08624fc27b5b9 M .lore.md M AGENTS.md M packages/core/schema.json M packages/core/src/database/migration.gen.ts M packages/core/src/database/migration/20260914170650_session-recovery.ts D packages/core/src/database/migration/20260914214636_session-execution.ts D packages/core/src/database/migration/20260914222526_session-execution-phase.ts M packages/core/src/database/schema.gen.ts M packages/core/src/session.ts M packages/core/src/session/compaction.ts M packages/core/src/session/context-epoch.ts M packages/core/src/session/execution/local.ts M packages/core/src/session/input.ts M packages/core/src/session/message-updater.ts M packages/core/src/session/projector.ts M packages/core/src/session/recovery.ts M packages/core/src/session/run-coordinator.ts M packages/core/src/session/runner/index.ts M packages/core/src/session/runner/llm.ts M packages/core/src/session/runner/publish-llm-event.ts M ...
ancestor=0 M .lore.md M packages/core/schema.json M packages/core/src/database/migration.gen.ts A packages/core/src/database/migration/20260914170650_session-recovery.ts A packages/core/src/database/migration/20260914214636_session-execution.ts A packages/core/src/database/migration/20260914222526_session-execution-phase.ts M packages/core/src/database/schema.gen.ts M packages/core/src/session/compaction.ts M packages/core/src/session/execution/local.ts M packages/core/src/session/message-updater.ts M packages/core/src/session/projector.ts A packages/core/src/session/recovery.ts M packages/core/src/session/runner/llm.ts M packages/core/src/session/runner/publish-llm-event.ts M packages/core/src/session/sql.ts A packages/core/test/session-execution-local.test.ts M packages/core/test/session-projector.test.ts M packages/core/test/session-runner-tool-events.test.ts M packages/core/test/session-runner.test.ts M packages/opencode/src/server/routes/instance/httpapi/server.ts M packages/schem...
drwxr-xr-x 24 byk byk 4096 Sep 16 19:26 /tmp/opencode clean_apply_exit=0
path_count=33 worktree_matches_frozen_paths=yes packages/core/schema.json packages/core/src/database/migration.gen.ts packages/core/src/database/migration/20260914170650_session-recovery.ts packages/core/src/database/schema.gen.ts packages/core/src/session.ts packages/core/src/session/compaction.ts packages/core/src/session/context-epoch.ts packages/core/src/session/execution/local.ts packages/core/src/session/input.ts packages/core/src/session/message-updater.ts packages/core/src/session/projector.ts packages/core/src/session/recovery.ts packages/core/src/session/run-coordinator.ts packages/core/src/session/runner/index.ts packages/core/src/session/runner/llm.ts packages/core/src/session/runner/publish-llm-event.ts packages/core/src/session/sql.ts packages/core/test/database-migration.test.ts packages/core/test/session-execution-local.test.ts packages/core/test/session-projector.test.ts packages/core/test/session-prompt.test.ts packages/core/test/session-run-coordinator.test.ts packag...
<path>/home/byk/Code/opencode/packages/core/src/session/execution/claim.ts</path>
<type>file</type>
<content>
1: export * as SessionExecutionClaim from "./claim"
2:
3: import { and, eq, gt } from "drizzle-orm"
4: import { Clock, Effect } from "effect"
5: import type { Database } from "../../database/database"
6: import type { SessionSchema } from "../schema"
7: import { SESSION_EXECUTION_LEASE_MS, SessionExecutionTable } from "../sql"
8:
9: type DatabaseService = Database.Interface["db"]
10:
11: export type Claim = {
12: readonly sessionID: SessionSchema.ID
13: readonly executionID: string
14: readonly ownerID: string
15: }
16:
17: export type Values = Partial<
18: Pick<typeof SessionExecutionTable.$inferInsert, "assistant_message_id" | "assistant_seq" | "phase">
19: >
20:
21: export class Lost extends Error {
22: constructor(readonly claim: Claim) {
23: super(`Session execution claim lost: ${claim.executionID}`)
24: }
25: }
26:
27: const where = (claim: Claim, ...
<path>/home/byk/Code/opencode/packages/core/src/session/execution/local.ts</path>
<type>file</type>
<content>
1: import { and, asc, desc, eq, isNull } from "drizzle-orm"
2: import { Cause, Clock, Duration, Effect, Exit, Layer, Schedule } from "effect"
3: import { Database } from "../../database/database"
4: import { LocationServiceMap } from "../../location-service-map"
5: import { makeGlobalNode } from "../../effect/app-node"
6: import { SessionRunCoordinator } from "../run-coordinator"
7: import { SessionRunner } from "../runner"
8: import { SessionMessage } from "../message"
9: import { SessionSchema } from "../schema"
10: import { SessionStore } from "../store"
11: import { SessionExecution } from "../execution"
12: import { SessionExecutionClaim } from "./claim"
13: import {
14: SESSION_EXECUTION_LEASE_MS,
15: SessionExecutionTable,
16: SessionMessageTable,
17: SessionRecoveryTable,
18: } from "../sql"
19:
20: /** Current-process routing for implicit-local Locations. ...
<path>/home/byk/Code/opencode/packages/core/src/session/sql.ts</path>
<type>file</type>
<content>
1: import { sql } from "drizzle-orm"
2: import { check, sqliteTable, text, integer, index, primaryKey, real, uniqueIndex } from "drizzle-orm/sqlite-core"
3: import * as DatabasePath from "../database/path"
4: import { ProjectTable } from "../project/sql"
5: import type { SessionMessage } from "./message"
6: import type { Prompt } from "./prompt"
7: import type { SessionInput } from "./input"
8: import type { Snapshot } from "../snapshot"
9: import { PermissionV1 } from "../v1/permission"
10: import { ProjectV2 } from "../project"
11: import type { SessionSchema } from "./schema"
12: import type { MessageID, PartID, SessionV1 } from "../v1/session"
13: import { WorkspaceV2 } from "../workspace"
14: import { Timestamps } from "../database/schema.sql"
15: import type { SystemContext } from "../system-context/index"
16: import { AgentV2 } from "../agent"
17: import type { Revert } from ...
<path>/home/byk/Code/opencode/packages/core/src/database/migration/20260914170650_session-recovery.ts</path>
<type>file</type>
<content>
1: import { Effect } from "effect"
2: import type { DatabaseMigration } from "../migration"
3:
4: export default {
5: id: "20260914170650_session-recovery",
6: up(tx) {
7: return Effect.gen(function* () {
8: yield* tx.run(`ALTER TABLE \`session_input\` ADD \`wake_pending\` integer DEFAULT false NOT NULL;`)
9: yield* tx.run(
10: `ALTER TABLE \`session\` ADD \`wake_attempts\` integer DEFAULT 0 NOT NULL CONSTRAINT \`session_wake_attempts_check\` CHECK(\`wake_attempts\` >= 0 AND \`wake_attempts\` <= 9007199254740991);`,
11: )
12: yield* tx.run(`
13: CREATE TABLE \`session_execution\` (
14: \`id\` text NOT NULL,
15: \`session_id\` text NOT NULL,
16: \`owner_id\` text NOT NULL,
17: \`assistant_message_id\` text,
18: \`phase\` text NOT NULL,
19: ...
<path>/home/byk/Code/opencode/packages/core/src/session/recovery.ts</path>
<type>file</type>
<content>
1: export * as SessionRecovery from "./recovery"
2:
3: import { and, asc, desc, eq, exists, gt, isNull, lte, or, sql } from "drizzle-orm"
4: import { Clock, DateTime, Effect, Layer, Option, Schedule, Schema } from "effect"
5: import { Database } from "../database/database"
6: import { makeGlobalNode } from "../effect/app-node"
7: import { EventV2 } from "../event"
8: import { SessionEvent } from "./event"
9: import { SessionExecution } from "./execution"
10: import { SessionProjector } from "./projector"
11: import { SessionExecutionClaim } from "./execution/claim"
12: import { SessionInput } from "./input"
13: import { continuation } from "./recovery-id"
14: import { SessionSchema } from "./schema"
15: import {
16: MAX_WAKE_ATTEMPTS,
17: SESSION_EXECUTION_LEASE_MS,
18: SessionExecutionTable,
19: SessionInputTable,
20: SessionRecoveryTable,
21: SessionMessageTable,
22: ...
<path>/home/byk/Code/opencode/packages/core/src/session/projector.ts</path>
<type>file</type>
<content>
1: export * as SessionProjector from "./projector"
2:
3: import { and, desc, eq, gt, or, sql } from "drizzle-orm"
4: import { DateTime, Effect, Layer, Schema } from "effect"
5: import { Database } from "../database/database"
6: import { EventV2 } from "../event"
7: import { makeGlobalNode } from "../effect/app-node"
8: import { SessionEvent } from "./event"
9: import { SessionV1 } from "../v1/session"
10: import { WorkspaceTable } from "../control-plane/workspace.sql"
11: import { SessionMessage } from "./message"
12: import { SessionMessageUpdater } from "./message-updater"
13: import { SessionInput } from "./input"
14: import { Prompt } from "./prompt"
15: import { continuation } from "./recovery-id"
16: import { WorkspaceV2 } from "../workspace"
17: import {
18: MessageTable,
19: PartTable,
20: SessionInputTable,
21: SessionMessageTable,
22: SessionRecoveryTable,
23: ...
<path>/home/byk/Code/opencode/packages/core/src/session/runner/llm.ts</path>
<type>file</type>
<content>
1: import {
2: LLM,
3: LLMClient,
4: LLMError,
5: LLMEvent,
6: Message,
7: SystemPart,
8: isContextOverflowFailure,
9: type ProviderErrorEvent,
10: } from "@opencode-ai/llm"
11: import { Cause, DateTime, Effect, Exit, Fiber, Layer, Option, Semaphore, Stream } from "effect"
12: import { and, eq } from "drizzle-orm"
13: import { AgentV2 } from "../../agent"
14: import { Config } from "../../config"
15: import { Database } from "../../database/database"
16: import { EventV2 } from "../../event"
17: import { Location } from "../../location"
18: import { ModelV2 } from "../../model"
19: import { PermissionV2 } from "../../permission"
20: import { ProviderV2 } from "../../provider"
21: import { QuestionV2 } from "../../question"
22: import { SystemContext } from "../../system-context/index"
23: import { SystemContextRegistry } from "../../system-context/registry"
24: ...
<path>/home/byk/Code/opencode/packages/core/src/session/runner/llm.ts</path>
<type>file</type>
<content>
451: .files({ from: startSnapshot, to: endSnapshot })
452: .pipe(Effect.catch(() => Effect.succeed(undefined)))
453: : undefined
454: const assistantMessageID = yield* publisher.startAssistant()
455: yield* withPublication(
456: events.publish(
457: SessionEvent.Step.Ended,
458: {
459: sessionID: session.id,
460: timestamp: yield* DateTime.now,
461: assistantMessageID,
462: finish: stepSettlement.finish,
463: cost: 0,
464: tokens: stepSettlement.tokens,
465: snapshot: endSnapshot,
466: files,
467: },
468: {
469: commit: () =>
470: ...
<path>/home/byk/Code/opencode/packages/core/src/session/runner/publish-llm-event.ts</path>
<type>file</type>
<content>
1: import { ToolOutput, type LLMEvent, type ProviderMetadata, type ToolResultValue, type Usage } from "@opencode-ai/llm"
2: import { DateTime, Effect } from "effect"
3: import { EventV2 } from "../../event"
4: import { ModelV2 } from "../../model"
5: import { SessionEvent } from "../event"
6: import { SessionMessage } from "../message"
7: import { SessionSchema } from "../schema"
8:
9: type Input = {
10: readonly sessionID: SessionSchema.ID
11: readonly agent: string
12: readonly model: ModelV2.Ref
13: readonly snapshot?: string
14: readonly startCommit: (assistantMessageID: SessionMessage.ID, seq: number) => Effect.Effect<void>
15: readonly eventCommit: () => Effect.Effect<void>
16: }
17:
18: const safe = (value: number | undefined) => Math.max(0, Number.isFinite(value) ? (value ?? ...
<path>/home/byk/Code/opencode/packages/core/src/session/input.ts</path>
<type>file</type>
<content>
1: export * as SessionInput from "./input"
2:
3: import { and, asc, desc, eq, isNull, lte } from "drizzle-orm"
4: import { DateTime, Effect, Option, Schema } from "effect"
5: import { Admitted, Delivery } from "@opencode-ai/schema/session-input"
6: import type { Database } from "../database/database"
7: import { EventV2 } from "../event"
8: import { SessionEvent } from "./event"
9: import { SessionMessage } from "./message"
10: import { Prompt } from "./prompt"
11: import { continuation, message } from "./recovery-id"
12: import { SessionSchema } from "./schema"
13: import { SessionInputTable, SessionMessageTable, SessionRecoveryTable } from "./sql"
14:
15: type DatabaseService = Database.Interface["db"]
16:
17: export { Admitted, Delivery }
18:
19: const decodePrompt = Schema.decodeUnknownSync(Prompt)
20: const encodePrompt = Schema.encodeSync(Prompt)
21: const continuePrompt = ...
Found 12 matches
/home/byk/Code/opencode/packages/core/test/session-projector.test.ts:
Line 342: it.effect("never recovers an execution superseded by a newer assistant", () =>
Line 390: it.effect(`never recovers an assistant-less ${phase} execution superseded by a newer assistant`, () =>
Line 415: id: `assistant-less-${phase}`,
Line 419: assistant_seq: -1,
Line 434: it.effect("recovers assistant-less continuation at its current assistant boundary", () =>
Line 459: id: "assistant-less-current",
Line 463: assistant_seq: 0,
Line 473: execution_id: "assistant-less-current",
Line 478: id: continuation("assistant-less-current"),
Line 1396: it.effect("quarantines a recovery wake behind a newer assistant", () =>
Line 1511: it.effect("never promotes a recovery superseded before scanner validation", () =>
Line 1575: it.effect("quarantines an assistant-less recovery superseded before ...
<path>/home/byk/Code/opencode/packages/core/test/session-projector.test.ts</path>
<type>file</type>
<content>
300: expect(messages[0]?.type).toBe("synthetic")
301: }),
302: )
303:
304: it.effect("never recovers a live execution lease", () =>
305: Effect.gen(function* () {
306: const { db } = yield* Database.Service
307: yield* db
308: .insert(ProjectTable)
309: .values({ id: Project.ID.global, worktree: AbsolutePath.make("/project"), sandboxes: [] })
310: .run()
311: yield* db
312: .insert(SessionTable)
313: .values({
314: id: sessionID,
315: project_id: Project.ID.global,
316: slug: "test",
317: directory: "/project",
318: title: "test",
319: version: "test",
320: })
321: .run()
322: yield* db
323: .insert(SessionExecutionTable)
324: .values({
325: id: "execution",
326: session_id: ...
Found 4 matches
/home/byk/Code/opencode/packages/core/test/session-runner.test.ts:
Line 1757: it.effect("interrupts overflow recovery while the summary provider is running", () =>
/home/byk/Code/opencode/packages/core/test/session-projector.test.ts:
Line 1511: it.effect("never promotes a recovery superseded before scanner validation", () =>
Line 1575: it.effect("quarantines an assistant-less recovery superseded before scanner validation", () =>
/home/byk/Code/opencode/packages/core/test/event.test.ts:
Line 660: it.effect("replay decodes synchronized transformed values before projection", () =>
No files found
/home/byk/Code/opencode/packages/core/src/event.ts /home/byk/Code/opencode/packages/core/src/session/event.ts
Found 34 matches
/home/byk/Code/opencode/packages/core/src/event.ts:
Line 122: /** Local operational projection committed atomically with a new durable event. Not replayed or serialized. */
Line 123: readonly commit?: (seq: number) => Effect.Effect<void>
Line 127: readonly publish: <D extends Definition>(
Line 140: options?: { readonly publish?: boolean; readonly ownerID?: string; readonly strictOwner?: boolean },
Line 144: options?: { readonly publish?: boolean; readonly ownerID?: string; readonly strictOwner?: boolean },
Line 205: function commitDurableEvent(
Line 214: commit?: (seq: number) => Effect.Effect<void>,
Line 239: const committed = yield* db
Line 316: const committed = {
Line 321: yield* projector(committed)
Line 323: if (commit) yield* commit(seq)
Line 354: if (committed) {
Line 356: ...
<path>/home/byk/Code/opencode/packages/core/src/event.ts</path>
<type>file</type>
<content>
190: return created
191: })
192:
193: yield* Effect.addFinalizer(() =>
194: Effect.gen(function* () {
195: yield* PubSub.shutdown(pubsub.all)
196: yield* Effect.forEach(
197: pubsub.durable.values(),
198: (pubsubs) => Effect.forEach(pubsubs, PubSub.shutdown, { discard: true }),
199: { discard: true },
200: )
201: yield* Effect.forEach(pubsub.typed.values(), PubSub.shutdown, { discard: true })
202: }),
203: )
204:
205: function commitDurableEvent(
206: definition: Definition,
207: event: Payload,
208: input?: {
209: readonly seq: number
210: readonly aggregateID: string
211: readonly ownerID?: string
212: readonly strictOwner?: boolean
213: },
214: commit?: (seq: number) => ...
<path>/home/byk/Code/opencode/packages/core/src/session/compaction.ts</path>
<type>file</type>
<content>
1: export * as SessionCompaction from "./compaction"
2:
3: import { LLM, LLMError, LLMEvent, Message, type LLMRequest, type Model } from "@opencode-ai/llm"
4: import { DateTime, Effect, Stream } from "effect"
5: import type { Config } from "../config"
6: import type { EventV2 } from "../event"
7: import { SessionEvent } from "./event"
8: import { SessionMessage } from "./message"
9: import { SessionSchema } from "./schema"
10: import { Token } from "../util/token"
11:
12: const DEFAULT_BUFFER = 20_000
13: const DEFAULT_KEEP_TOKENS = 8_000
14: const TOOL_OUTPUT_MAX_CHARS = 2_000
15: const SUMMARY_OUTPUT_TOKENS = 4_096
16: const SUMMARY_TEMPLATE = `Output exactly the Markdown structure shown inside <template> and keep the section order unchanged. Do not include the <template> tags in your response. ...
<path>/home/byk/Code/opencode/packages/core/src/session/context-epoch.ts</path>
<type>file</type>
<content>
1: export * as SessionContextEpoch from "./context-epoch"
2:
3: import { eq } from "drizzle-orm"
4: import { DateTime, Effect, Schema } from "effect"
5: import type { Database } from "../database/database"
6: import { EventV2 } from "../event"
7: import { SystemContext } from "../system-context/index"
8: import { ContextSnapshotDecodeError } from "./error"
9: import { SessionEvent } from "./event"
10: import { SessionHistory } from "./history"
11: import { SessionInput } from "./input"
12: import { SessionMessage } from "./message"
13: import { SessionSchema } from "./schema"
14: import { SessionContextEpochTable } from "./sql"
15: import { SessionExecutionClaim } from "./execution/claim"
16:
17: type DatabaseService = Database.Interface["db"]
18:
19: interface Prepared {
20: readonly baseline: string
21: readonly baselineSeq: number
22: }
23:
24: export function ...
Found 45 matches
/home/byk/Code/opencode/packages/core/src/session/recovery.ts:
Line 164: SessionEvent.Step.Recovered,
/home/byk/Code/opencode/packages/core/src/session/projector.ts:
Line 395: yield* events.project(SessionEvent.Step.Started, (event) => run(db, event))
Line 396: yield* events.project(SessionEvent.Step.Ended, (event) => run(db, event))
Line 397: yield* events.project(SessionEvent.Step.Failed, (event) => run(db, event))
Line 398: yield* events.project(SessionEvent.Step.Interrupted, (event) => run(db, event))
Line 399: yield* events.project(SessionEvent.Step.Recovered, (event) =>
Line 480: yield* events.project(SessionEvent.Compaction.Ended, (event) => run(db, event))
/home/byk/Code/opencode/packages/core/src/session/compaction.ts:
Line 1: export * as SessionCompaction from "./compaction"
Line 184: const compactAfterOverflow = Effect.fn("SessionCompaction.compactAfterOverflow")(function* (input: ...
<path>/home/byk/Code/opencode/packages/core/src/session/message-updater.ts</path>
<type>file</type>
<content>
1: import { castDraft, produce, type WritableDraft } from "immer"
2: import { Effect } from "effect"
3: import { SessionEvent } from "./event"
4: import { SessionMessage } from "./message"
5: import { message } from "./recovery-id"
6:
7: export type MemoryState = {
8: messages: SessionMessage.Message[]
9: }
10:
11: export interface Adapter {
12: readonly getCurrentAssistant: () => Effect.Effect<SessionMessage.Assistant | undefined>
13: readonly getAssistant: (messageID: SessionMessage.ID) => Effect.Effect<SessionMessage.Assistant | undefined>
14: readonly getCurrentShell: (callID: string) => Effect.Effect<SessionMessage.Shell | undefined>
15: readonly updateAssistant: (assistant: SessionMessage.Assistant) => Effect.Effect<void>
16: readonly updateShell: (shell: SessionMessage.Shell) => Effect.Effect<void>
17: readonly appendMessage: (message: ...
<path>/home/byk/Code/opencode/packages/schema/src/session-event.ts</path>
<type>file</type>
<content>
1: export * as SessionEvent from "./session-event"
2:
3: import { Schema } from "effect"
4: import { optional } from "./schema"
5: import { Event } from "./event"
6: import { ProviderMetadata, ToolContent } from "./llm"
7: import { Delivery } from "./session-delivery"
8: import { Model } from "./model"
9: import { DateTimeUtcFromMillis, NonNegativeInt, RelativePath } from "./schema"
10: import { FileAttachment, Prompt } from "./prompt"
11: import { SessionID } from "./session-id"
12: import { Location } from "./location"
13: import { SessionMessage } from "./session-message"
14: import { Revert } from "./revert"
15:
16: export { FileAttachment }
17:
18: export const Source = Schema.Struct({
19: start: NonNegativeInt,
20: end: NonNegativeInt,
21: text: Schema.String,
22: }).annotate({
23: identifier: "session.next.event.source",
24: })
25: export interface Source extends ...
<path>/home/byk/Code/opencode/packages/core/test/session-projector.test.ts</path>
<type>file</type>
<content>
1320: executionID: "shared-recovery-identity",
1321: phase: "ready",
1322: })
1323:
1324: const recovered = yield* events
1325: .publish(SessionEvent.Step.Recovered, {
1326: sessionID,
1327: timestamp: DateTime.makeUnsafe(1),
1328: executionID: "shared-recovery-identity",
1329: phase: "ready",
1330: })
1331: .pipe(Effect.exit)
1332:
1333: expect(Exit.isFailure(recovered)).toBe(true)
1334: expect(yield* db.select().from(SessionRecoveryTable).all()).toEqual([
1335: expect.objectContaining({
1336: session_id: other,
1337: execution_id: "shared-recovery-identity",
1338: continuation_message_id: continuation("shared-recovery-identity"),
1339: }),
1340: ])
1341: expect(yield* ...
<path>/home/byk/Code/opencode/packages/core/src/session/run-coordinator.ts</path>
<type>file</type>
<content>
1: export * as SessionRunCoordinator from "./run-coordinator"
2:
3: import { Deferred, Effect, Exit, Fiber, FiberSet, Scope } from "effect"
4:
5: /** Serializes execution for each key while allowing different keys to run concurrently. */
6: export interface Coordinator<Key, E> {
7: /** Snapshots keys with an execution owned by this coordinator. */
8: readonly active: Effect.Effect<ReadonlySet<Key>>
9: /** Starts execution while idle or joins the active execution. */
10: readonly run: (key: Key) => Effect.Effect<void, E>
11: /** Registers one coalesced follow-up after newly recorded work. */
12: readonly wake: (key: Key) => Effect.Effect<void>
13: /** Stops active execution, runs cleanup, then starts work that arrived while stopping. */
14: readonly interrupt: (key: Key, cleanup?: Effect.Effect<void>) => Effect.Effect<void>
15: }
16:
17: type Entry<E> = {
18: ...
<path>/home/byk/Code/opencode/packages/core/src/session.ts</path>
<type>file</type>
<content>
1: export * as SessionV2 from "./session"
2: export * from "./session/schema"
3:
4: import { DateTime, Effect, Layer, Schema, Context, Stream } from "effect"
5: import { ListAnchor } from "@opencode-ai/schema/session"
6: import { and, asc, desc, eq, gt, like, lt, or, type SQL } from "drizzle-orm"
7: import { ProjectV2 } from "./project"
8: import { WorkspaceV2 } from "./workspace"
9: import { ModelV2 } from "./model"
10: import { Location } from "./location"
11: import { SessionMessage } from "./session/message"
12: import { Prompt } from "./session/prompt"
13: import { PromptInput } from "@opencode-ai/schema/prompt-input"
14: import { EventV2 } from "./event"
15: import { Database } from "./database/database"
16: import { SessionProjector } from "./session/projector"
17: import { SessionMessageTable, SessionTable } from "./session/sql"
18: import { SessionSchema } from ...
<path>/home/byk/Code/opencode/packages/core/src/session.ts</path>
<type>file</type>
<content>
300: Effect.orDie,
301: )
302: return (direction === "previous" ? rows.toReversed() : rows).map((row) => fromRow(row))
303: }),
304: messages: Effect.fn("V2Session.messages")(function* (input) {
305: yield* result.get(input.sessionID)
306: const direction = input.cursor?.direction ?? "next"
307: const requestedOrder = input.order ?? "desc"
308: const order = direction === "previous" ? (requestedOrder === "asc" ? "desc" : "asc") : requestedOrder
309: const anchor = input.cursor
310: ? yield* db
311: .select({ seq: SessionMessageTable.seq })
312: .from(SessionMessageTable)
313: .where(
314: and(eq(SessionMessageTable.session_id, input.sessionID), eq(SessionMessageTable.id, input.cursor.id)),
315: )
316: .get()
317: ...
<path>/home/byk/Code/opencode/packages/server/src/routes.ts</path>
<type>file</type>
<content>
1: import { Database } from "@opencode-ai/core/database/database"
2: import { LayerNode } from "@opencode-ai/core/effect/layer-node"
3: import { httpClient } from "@opencode-ai/core/effect/app-node-platform"
4: import { AppNodeBuilder } from "@opencode-ai/core/effect/app-node-builder"
5: import { EventV2 } from "@opencode-ai/core/event"
6: import { Credential } from "@opencode-ai/core/credential"
7: import { PermissionSaved } from "@opencode-ai/core/permission/saved"
8: import { PtyTicket } from "@opencode-ai/core/pty/ticket"
9: import { SessionV2 } from "@opencode-ai/core/session"
10: import { SessionExecution } from "@opencode-ai/core/session/execution"
11: import { LocationServiceMap } from "@opencode-ai/core/location-service-map"
12: import { SessionExecutionLocal } from "@opencode-ai/core/session/execution/local"
13: import { SessionRecovery } from ...
<path>/home/byk/Code/opencode/packages/opencode/src/server/routes/instance/httpapi/server.ts</path>
<type>file</type>
<content>
1: import { Config as EffectConfig, Context, Effect, Layer } from "effect"
2: import { HttpApiBuilder, OpenApi } from "effect/unstable/httpapi"
3: import { HttpClient, HttpMiddleware, HttpRouter, HttpServer, HttpServerResponse } from "effect/unstable/http"
4: import * as Socket from "effect/unstable/socket/Socket"
5: import { FSUtil } from "@opencode-ai/core/fs-util"
6: import * as Observability from "@opencode-ai/core/observability"
7: import { Account } from "@/account/account"
8: import { Agent } from "@/agent/agent"
9: import { Auth } from "@/auth"
10: import { BackgroundJob } from "@/background/job"
11: import { Command } from "@/command"
12: import { Config } from "@/config/config"
13: import { Workspace } from "@/control-plane/workspace"
14: import { Env } from "@/env"
15: import { EventV2Bridge } from "@/event-v2-bridge"
16: import { Format } from ...
Found 21 matches
/home/byk/Code/opencode/packages/core/src/database/schema.gen.ts:
Line 158: CREATE TABLE \`session_execution\` (
Line 164: \`assistant_seq\` integer DEFAULT -1 NOT NULL,
Line 168: CONSTRAINT \`session_execution_pk\` PRIMARY KEY(\`id\`),
Line 169: CONSTRAINT \`fk_session_execution_session_id_session_id_fk\` FOREIGN KEY (\`session_id\`) REFERENCES \`session\`(\`id\`) ON DELETE CASCADE,
Line 170: CONSTRAINT "session_execution_phase_check" CHECK("phase" IN ('ready', 'safe', 'unknown', 'continue', 'cancelling'))
Line 181: \`wake_pending\` integer DEFAULT false NOT NULL,
Line 199: CREATE TABLE \`session_recovery\` (
Line 205: \`wake_pending\` integer DEFAULT true NOT NULL,
Line 206: \`wake_attempts\` integer DEFAULT 0 NOT NULL,
Line 209: CONSTRAINT \`session_recovery_pk\` PRIMARY KEY(\`execution_id\`),
Line 210: CONSTRAINT ...
<path>/home/byk/Code/opencode/packages/core/src/database/schema.gen.ts</path> <type>file</type> <content> 130: \`session_id\` text NOT NULL, 131: \`time_created\` integer NOT NULL, 132: \`time_updated\` integer NOT NULL, 133: \`data\` text NOT NULL, 134: CONSTRAINT \`fk_message_session_id_session_id_fk\` FOREIGN KEY (\`session_id\`) REFERENCES \`session\`(\`id\`) ON DELETE CASCADE 135: ); 136: `) 137: yield* tx.run(` 138: CREATE TABLE \`part\` ( 139: \`id\` text PRIMARY KEY, 140: \`message_id\` text NOT NULL, 141: \`session_id\` text NOT NULL, 142: \`time_created\` integer NOT NULL, 143: \`time_updated\` integer NOT NULL, 144: \`data\` text NOT NULL, 145: CONSTRAINT \`fk_part_message_id_message_id_fk\` FOREIGN KEY (\`message_id\`) REFERENCES \`message\`(\`id\`) ON DELETE CASCADE 146: ); 147: `) 148: yield* tx.run(` 149: ...
<path>/home/byk/Code/opencode/packages/core/test/database-migration.test.ts</path>
<type>file</type>
<content>
1: import { describe, expect, test } from "bun:test"
2: import { $ } from "bun"
3: import { fileURLToPath } from "url"
4: import path from "path"
5: import { SqliteClient } from "@effect/sql-sqlite-bun"
6: import { EffectDrizzleSqlite } from "@opencode-ai/effect-drizzle-sqlite"
7: import { Effect, Exit, Layer } from "effect"
8: import { eq, inArray, sql } from "drizzle-orm"
9: import { DatabaseMigration } from "@opencode-ai/core/database/migration"
10: import { migrations } from "@opencode-ai/core/database/migration.gen"
11: import workspaceNameMigration from "@opencode-ai/core/database/migration/20260410174513_workspace-name"
12: import sessionUsageMigration from "@opencode-ai/core/database/migration/20260510033149_session_usage"
13: import normalizeStoragePathsMigration from "@opencode-ai/core/database/migration/20260601010001_normalize_storage_paths"
14: import ...
<path>/home/byk/Code/opencode/packages/core/src/session/recovery-id.ts</path>
<type>file</type>
<content>
1: import { SessionMessage } from "./message"
2:
3: export const message = (executionID: string, assistantMessageID?: SessionMessage.ID) =>
4: assistantMessageID ?? SessionMessage.ID.make(`msg_recovery_${executionID}`)
5:
6: export const continuation = (executionID: string) => SessionMessage.ID.make(`msg_recovery_continue_${executionID}`)
(End of file - total 6 lines)
</content>
<path>/home/byk/Code/opencode/packages/core/src/session/runner/index.ts</path>
<type>file</type>
<content>
1: export * as SessionRunner from "./index"
2:
3: import type { LLMError } from "@opencode-ai/llm"
4: import { Context, Effect } from "effect"
5: import { SessionSchema } from "../schema"
6: import type { SessionMessage } from "../message"
7: import type { ContextSnapshotDecodeError, MessageDecodeError } from "../error"
8: import { SessionRunnerModel } from "./model"
9: import type { SystemContext } from "../../system-context/index"
10: import type { ToolOutputStore } from "../../tool-output-store"
11:
12: export type RunError =
13: | LLMError
14: | SessionRunnerModel.Error
15: | MessageDecodeError
16: | ContextSnapshotDecodeError
17: | SystemContext.InitializationBlocked
18: | ToolOutputStore.Error
19:
20: /** Runs one local continuation from already-recorded Session history. */
21: export interface Interface {
22: /** Drains eligible durable work. ...
<path>/home/byk/Code/opencode/packages/core/src/database/migration.gen.ts</path>
<type>file</type>
<content>
1: import type { DatabaseMigration } from "./migration"
2:
3: export const migrations = (
4: await Promise.all([
5: import("./migration/20260127222353_familiar_lady_ursula"),
6: import("./migration/20260211171708_add_project_commands"),
7: import("./migration/20260213144116_wakeful_the_professor"),
8: import("./migration/20260225215848_workspace"),
9: import("./migration/20260227213759_add_session_workspace_id"),
10: import("./migration/20260228203230_blue_harpoon"),
11: import("./migration/20260303231226_add_workspace_fields"),
12: import("./migration/20260309230000_move_org_to_state"),
13: import("./migration/20260312043431_session_message_cursor"),
14: import("./migration/20260323234822_events"),
15: import("./migration/20260410174513_workspace-name"),
16: import("./migration/20260413175956_chief_energizer"),
17: ...
Found 56 matches /home/byk/Code/opencode/packages/core/schema.json: Line 66: "name": "session_execution", Line 78: "name": "session_recovery", Line 941: "table": "session_execution" Line 951: "table": "session_execution" Line 961: "table": "session_execution" Line 971: "table": "session_execution" Line 981: "table": "session_execution" Line 989: "name": "assistant_seq", Line 991: "table": "session_execution" Line 1001: "table": "session_execution" Line 1011: "table": "session_execution" Line 1021: "table": "session_execution" Line 1089: "name": "wake_pending", Line 1181: "table": "session_recovery" Line 1191: "table": "session_recovery" Line 1201: "table": "session_recovery" Line 1211: "table": "session_recovery" Line 1221: "table": "session_recovery" Line 1229: "name": "wake_pending", Line 1231: "table": ...
<path>/home/byk/Code/opencode/packages/core/schema.json</path>
<type>file</type>
<content>
920: "entityType": "columns",
921: "table": "session_context_epoch"
922: },
923: {
924: "type": "integer",
925: "notNull": true,
926: "autoincrement": false,
927: "default": null,
928: "generated": null,
929: "name": "baseline_seq",
930: "entityType": "columns",
931: "table": "session_context_epoch"
932: },
933: {
934: "type": "text",
935: "notNull": true,
936: "autoincrement": false,
937: "default": null,
938: "generated": null,
939: "name": "id",
940: "entityType": "columns",
941: "table": "session_execution"
942: },
943: {
944: "type": "text",
945: "notNull": true,
946: "autoincrement": false,
947: "default": null,
948: "generated": null,
949: "name": "session_id",
950: "entityType": "columns",
951: "table": ...
Found 100 matches (more matches available)
/home/byk/Code/opencode/packages/core/test/session-runner.test.ts:
Line 249: run: (claim, force, recoveryInputID) =>
Line 250: sessionRunner.run({ ...claim, force, recoveryInputID }).pipe(
Line 322: owner_id: "test",
Line 331: owner_id: "test",
Line 587: const fiber = yield* runner.run({ sessionID, force: true, executionID, ownerID: "test" }).pipe(Effect.forkChild)
Line 752: it.effect("never dispatches a provider after ownership changes", () =>
Line 767: .set({ id: "provider-successor", owner_id: "successor", expires_at: 60_000 })
Line 778: it.effect("never publishes streamed output after ownership changes", () =>
Line 793: .set({ id: "publication-successor", owner_id: "successor", expires_at: 60_000 })
Line 805: it.effect("never starts a local tool after ownership changes", () =>
Line 823: .set({ id: "tool-successor", owner_id: ...
<path>/home/byk/Code/opencode/packages/core/test/session-execution-local.test.ts</path>
<type>file</type>
<content>
1: import { describe, expect } from "bun:test"
2: import { Deferred, Effect, Exit, Fiber, Scope } from "effect"
3: import { TestClock } from "effect/testing"
4: import { eq } from "drizzle-orm"
5: import { Database } from "@opencode-ai/core/database/database"
6: import { Project } from "@opencode-ai/core/project"
7: import { ProjectTable } from "@opencode-ai/core/project/sql"
8: import { AbsolutePath } from "@opencode-ai/core/schema"
9: import { SessionExecutionLocal } from "@opencode-ai/core/session/execution/local"
10: import { SessionSchema } from "@opencode-ai/core/session/schema"
11: import { SessionExecutionTable, SessionTable } from "@opencode-ai/core/session/sql"
12: import { testEffect } from "./lib/effect"
13:
14: const sessionID = SessionSchema.ID.make("ses_execution_local")
15: const it = testEffect(Database.layerFromPath(":memory:"))
16:
17: const ...
Found 3 matches
/home/byk/Code/opencode/packages/core/test/session-projector.test.ts:
Line 419: assistant_seq: -1,
Line 434: it.effect("recovers assistant-less continuation at its current assistant boundary", () =>
Line 463: assistant_seq: 0,
<path>/home/byk/Code/opencode/packages/core/test/session-projector.test.ts</path>
<type>file</type>
<content>
1040: title: "test",
1041: version: "test",
1042: })
1043: .run()
1044: yield* SessionInput.admit(db, events, {
1045: id: SessionMessage.ID.make("msg_lost_ordinary_wake"),
1046: sessionID,
1047: prompt: Prompt.make({ text: "recover ordinary input" }),
1048: delivery: "steer",
1049: requestExecution: true,
1050: })
1051: let wakes = 0
1052: const execution = SessionExecution.Service.of({
1053: ...recoveryExecution,
1054: wake: () => Effect.sync(() => wakes++).pipe(Effect.asVoid),
1055: })
1056:
1057: yield* SessionRecovery.recover().pipe(Effect.provideService(SessionExecution.Service, execution))
1058: yield* SessionRecovery.recover().pipe(Effect.provideService(SessionExecution.Service, execution))
1059:
1060: expect(wakes).toBe(2)
1061: ...
Found 100 matches (more matches available)
/home/byk/Code/opencode/packages/core/test/session-runner.test.ts:
Line 382: response = fragmentFixture("text", "text-earlier", ["Earlier answer"]).completeEvents
Line 431: readonly completeEvents: LLMEvent[]
Line 454: completeEvents: [
Line 474: completeEvents: [
Line 501: completeEvents: [...partialEvents, LLMEvent.toolInputEnd({ id, name: "echo" })],
Line 526: response = fixture.completeEvents
Line 710: wake_pending: false,
Line 746: wake_pending: false,
Line 785: response = fragmentFixture("text", "text-fenced", ["stale output"]).completeEvents
Line 950: state: { status: "completed", structured: { answer: "HELLO" } },
Line 1133: response = fragmentFixture("text", "text-build", ["Done"]).completeEvents
Line 1159: response = fragmentFixture("text", "text-reviewer", ["Done"]).completeEvents
Line 1188: response = ...
<path>/home/byk/Code/opencode/packages/core/test/session-projector.test.ts</path>
<type>file</type>
<content>
1: import { describe, expect } from "bun:test"
2: import { DateTime, Deferred, Effect, Exit, Fiber, Schema } from "effect"
3: import { TestClock } from "effect/testing"
4: import { asc, eq, sql } from "drizzle-orm"
5: import { Database } from "@opencode-ai/core/database/database"
6: import { LayerNode } from "@opencode-ai/core/effect/layer-node"
7: import { AppNodeBuilder } from "@opencode-ai/core/effect/app-node-builder"
8: import { EventV2 } from "@opencode-ai/core/event"
9: import { EventTable } from "@opencode-ai/core/event/sql"
10: import { ModelV2 } from "@opencode-ai/core/model"
11: import { Project } from "@opencode-ai/core/project"
12: import { ProjectTable } from "@opencode-ai/core/project/sql"
13: import { ProviderV2 } from "@opencode-ai/core/provider"
14: import { AbsolutePath } from "@opencode-ai/core/schema"
15: import { SessionV2 } from ...
Found 100 matches (more matches available)
/home/byk/Code/opencode/packages/schema/test/legacy-event.test.ts:
Line 22: const durable = SessionV1.Event.Definitions.filter((event) => event.durable !== undefined)
Line 24: expect(durable.every((event) => event.durable?.aggregate === "sessionID")).toBe(true)
Line 25: expect(durable.every((event) => event.durable?.version === 1)).toBe(true)
/home/byk/Code/opencode/packages/schema/src/session-event.ts:
Line 558: .annotate({ identifier: "SessionDurableEvent" })
/home/byk/Code/opencode/packages/schema/src/event.ts:
Line 103: if (result.has(key)) throw new Error(`Duplicate durable event definition for ${key}`)
/home/byk/Code/opencode/packages/schema/src/event-manifest.ts:
Line 4: import { Durable } from "./durable-event-manifest"
/home/byk/Code/opencode/packages/schema/src/durable-event-manifest.ts:
Line 1: export * as DurableEventManifest from "./durable-event-manifest"
Line 7: export const ...
Found 74 matches
/home/byk/Code/opencode/packages/core/test/session-runner.test.ts:
Line 752: it.effect("never dispatches a provider after ownership changes", () =>
Line 778: it.effect("never publishes streamed output after ownership changes", () =>
Line 805: it.effect("never starts a local tool after ownership changes", () =>
Line 845: it.effect("never fails interrupted tools after ownership changes", () =>
Line 1837: LLMEvent.toolCall({ id: "call-error", name: "write", input: { path: "README.md" }, providerExecuted: true }),
Line 1844: providerExecuted: true,
Line 1857: providerExecuted: true,
Line 1975: it.effect("never commits continuation before unresolved hosted tools are reconciled", () =>
Line 1986: id: "call-hosted-pending",
Line 1989: providerExecuted: true,
Line 1996: CREATE TRIGGER fail_hosted_tool_reconciliation
Line 2000: SELECT RAISE(ABORT, 'crash before ...
<path>/home/byk/Code/opencode/packages/core/test/session-runner.test.ts</path>
<type>file</type>
<content>
680: LLMEvent.finish({ reason: "stop" }),
681: ]
682: yield* session.resume(sessionID)
683: expect(userTexts(requests[1]!)).toContain("ordinary work after replayed recovery")
684: requests.length = 0
685: }),
686: )
687:
688: it.effect("clears durable execution intent when ordinary input is promoted", () =>
689: Effect.gen(function* () {
690: yield* setup
691: const session = yield* SessionV2.Service
692: const message = yield* session.prompt({
693: sessionID,
694: prompt: Prompt.make({ text: "clear durable wake" }),
695: resume: false,
696: })
697: const { db } = yield* Database.Service
698: yield* db.update(SessionInputTable).set({ wake_pending: true }).where(eq(SessionInputTable.id, message.id)).run()
699: response = [
700: LLMEvent.stepStart({ index: 0 ...
diff --git a/packages/core/test/session-prompt.test.ts b/packages/core/test/session-prompt.test.ts
index c6bc9430b3..a0d6f26467 100644
--- a/packages/core/test/session-prompt.test.ts
+++ b/packages/core/test/session-prompt.test.ts
@@ -1,38 +1,39 @@
import { describe, expect } from "bun:test"
import { DateTime, Effect, Fiber, Layer, Stream } from "effect"
-import { eq } from "drizzle-orm"
+import { asc, eq } from "drizzle-orm"
import { Database } from "@opencode-ai/core/database/database"
import { AppNodeBuilder } from "@opencode-ai/core/effect/app-node-builder"
import { LayerNode } from "@opencode-ai/core/effect/layer-node"
import { EventV2 } from "@opencode-ai/core/event"
import { EventTable } from "@opencode-ai/core/event/sql"
import { SessionEvent } from "@opencode-ai/core/session/event"
import { Project } from "@opencode-ai/core/project"
import { ProjectTable } from "@opencode-ai/core/project/sql"
import { AbsolutePath } from "@opencode-ai/core/schema"
import { ...
<path>/home/byk/Code/opencode/packages/opencode/src/server/routes/instance/httpapi/server.ts</path>
<type>file</type>
<content>
200: yield* router.add("*", "/*", (request) =>
201: serveUIEffect(request, { fs, client, disableEmbeddedWebUi: flags.disableEmbeddedWebUi }),
202: )
203: }),
204: ).pipe(Layer.provide(authOnlyRouterLayer))
205:
206: type RouteRequirements =
207: | HttpRouter.HttpRouter
208: | HttpRouter.Request<"Error", unknown>
209: | HttpRouter.Request<"GlobalError", unknown>
210: | HttpRouter.Request<"Requires", unknown>
211: | HttpRouter.Request<"GlobalRequires", never>
212:
213: const app = LayerNode.group([
214: Npm.node,
215: FSUtil.node,
216: Database.node,
217: Auth.node,
218: Account.node,
219: Config.node,
220: Env.node,
221: Git.node,
222: Ripgrep.node,
223: Storage.node,
224: Snapshot.node,
225: Plugin.node,
226: ModelsDev.node,
227: Provider.node,
228: ProviderAuth.node,
229: Agent.node,
230: ...
Found 19 matches
/home/byk/Code/opencode/packages/sdk/js/src/v2/gen/types.gen.ts:
Line 24: | EventSessionNextPromptExecutionRequested
Line 874: requestExecution?: boolean
Line 983: type: "session.next.step.recovered"
Line 987: executionID: string
Line 1650: | SyncEventSessionNextPromptExecutionRequested
Line 2785: | SessionNextPromptExecutionRequested
Line 2915: | SessionNextPromptExecutionRequested
Line 3430: requestExecution?: boolean
Line 3435: export type SyncEventSessionNextPromptExecutionRequested = {
Line 3606: type: "session.next.step.recovered.1"
Line 3613: executionID: string
Line 4362: requestExecution?: boolean
Line 4366: export type SessionNextPromptExecutionRequested = {
Line 4565: type: "session.next.step.recovered"
Line 4575: executionID: string
Line 6464: requestExecution?: boolean
Line 6468: export type EventSessionNextPromptExecutionRequested = {
...
<path>/home/byk/Code/opencode/packages/sdk/js/src/v2/gen/types.gen.ts</path>
<type>file</type>
<content>
3570: id: string
3571: syncEvent: {
3572: type: "session.next.step.failed.2"
3573: id: string
3574: seq: number
3575: aggregateID: string
3576: data: {
3577: timestamp: number
3578: sessionID: string
3579: assistantMessageID: string
3580: error: SessionErrorUnknown
3581: }
3582: }
3583: }
3584:
3585: export type SyncEventSessionNextStepInterrupted = {
3586: type: "sync"
3587: id: string
3588: syncEvent: {
3589: type: "session.next.step.interrupted.1"
3590: id: string
3591: seq: number
3592: aggregateID: string
3593: data: {
3594: timestamp: number
3595: sessionID: string
3596: assistantMessageID: string
3597: error: SessionErrorUnknown
3598: }
3599: }
3600: }
3601:
3602: export type SyncEventSessionNextStepRecovered = {
3603: type: "sync"
3604: id: string
3605: ...
Found 1 matches
/home/byk/Code/opencode/packages/opencode/src/server/routes/instance/httpapi/handlers/sync.ts:
Line 51: yield* events.replayAll(payload, { ownerID, strictOwner: true })
<path>/home/byk/Code/opencode/packages/opencode/src/server/routes/instance/httpapi/handlers/sync.ts</path>
<type>file</type>
<content>
1: import { Workspace } from "@/control-plane/workspace"
2: import * as InstanceState from "@/effect/instance-state"
3: import { Session } from "@/session/session"
4: import { Database } from "@opencode-ai/core/database/database"
5: import { EventV2 } from "@opencode-ai/core/event"
6: import { EventV2Bridge } from "@/event-v2-bridge"
7: import { EventTable } from "@opencode-ai/core/event/sql"
8: import { asc } from "drizzle-orm"
9: import { and } from "drizzle-orm"
10: import { eq } from "drizzle-orm"
11: import { lte } from "drizzle-orm"
12: import { not } from "drizzle-orm"
13: import { or } from "drizzle-orm"
14: import { Effect, Scope } from "effect"
15: import { HttpApiBuilder, HttpApiError } from "effect/unstable/httpapi"
16: import { InstanceHttpApi } from "../api"
17: import { HistoryPayload, ReplayPayload, SessionPayload } from ...
Found 16 matches
/home/byk/Code/opencode/packages/sdk/openapi.json:
Line 17899: "requestExecution": {
Line 18289: "enum": ["session.next.step.recovered"]
Line 18301: "executionID": {
Line 18313: "required": ["timestamp", "sessionID", "executionID", "phase"],
Line 25709: "requestExecution": {
Line 26299: "enum": ["session.next.step.recovered.1"]
Line 26321: "executionID": {
Line 26333: "required": ["timestamp", "sessionID", "executionID", "phase"],
Line 28599: "requestExecution": {
Line 29190: "enum": ["session.next.step.recovered"]
Line 29221: "executionID": {
Line 29233: "required": ["timestamp", "sessionID", "executionID", "phase"],
Line 34811: "requestExecution": {
Line 35201: "enum": ...
<path>/home/byk/Code/opencode/packages/sdk/openapi.json</path>
<type>file</type>
<content>
18270: "$ref": "#/components/schemas/SessionErrorUnknown"
18271: }
18272: },
18273: "required": ["timestamp", "sessionID", "assistantMessageID", "error"],
18274: "additionalProperties": false
18275: }
18276: },
18277: "required": ["id", "type", "properties"],
18278: "additionalProperties": false
18279: },
18280: {
18281: "type": "object",
18282: "properties": {
18283: "id": {
18284: "type": "string",
18285: "pattern": "^evt_"
18286: },
18287: "type": {
18288: "type": "string",
18289: "enum": ["session.next.step.recovered"]
18290: ...
<path>/home/byk/Code/opencode/packages/schema/src/session-event.ts</path>
<type>file</type>
<content>
480: schema: { ...Base, messageID: SessionMessage.ID },
481: })
482: }
483:
484: export const DurableDefinitions = Event.inventory(
485: AgentSwitched,
486: ModelSwitched,
487: Moved,
488: Prompted,
489: PromptAdmitted,
490: PromptExecutionRequested,
491: ContextUpdated,
492: Synthetic,
493: Shell.Started,
494: Shell.Ended,
495: Step.Started,
496: Step.Ended,
497: Step.Failed,
498: Step.Interrupted,
499: Step.Recovered,
500: Text.Started,
501: Text.Ended,
502: Tool.Input.Started,
503: Tool.Input.Ended,
504: Tool.Called,
505: Tool.Progress,
506: Tool.Success,
507: Tool.Failed,
508: Reasoning.Started,
509: Reasoning.Ended,
510: Retried,
511: Compaction.Started,
512: Compaction.Ended,
513: RevertEvent.Staged,
514: RevertEvent.Cleared,
515: RevertEvent.Committed,
516: )
517:
518: export const Definitions = ...
diff --git a/packages/core/test/session-runner.test.ts b/packages/core/test/session-runner.test.ts
index cc58b43b29..2f4dd90d6e 100644
--- a/packages/core/test/session-runner.test.ts
+++ b/packages/core/test/session-runner.test.ts
@@ -34 +34,2 @@ import { SessionExecution } from "@opencode-ai/core/session/execution"
-import { SessionRunCoordinator } from "@opencode-ai/core/session/run-coordinator"
+import { SessionExecutionLocal } from "@opencode-ai/core/session/execution/local"
+import { SessionRecovery } from "@opencode-ai/core/session/recovery"
@@ -45,0 +47 @@ import {
+ SessionExecutionTable,
@@ -47,0 +50 @@ import {
+ SessionRecoveryTable,
@@ -59 +62 @@ import { Cause, DateTime, Deferred, Effect, Exit, Fiber, Layer, Schema, Stream }
-import { asc, eq } from "drizzle-orm"
+import { asc, eq, sql } from "drizzle-orm"
@@ -62,0 +66 @@ const requests: LLMRequest[] = []
+const executionID = "test-execution"
@@ -70,0 +75 @@ let toolExecutionsStarted: Deferred.Deferred<void> | ...
Found 31 matches
/home/byk/Code/opencode/packages/core/test/session-projector.test.ts:
Line 222: it.effect("records a recovery continuation without forging an assistant identity", () =>
Line 258: it.effect("recovers each abandoned execution once across repeated startup scans", () =>
Line 304: it.effect("never recovers a live execution lease", () =>
Line 342: it.effect("never recovers an execution superseded by a newer assistant", () =>
Line 434: it.effect("recovers assistant-less continuation at its current assistant boundary", () =>
Line 485: it.effect("redrives a durable recovery wake after admission", () =>
Line 536: it.effect("quarantines a malformed recovery row without blocking a valid wake", () =>
Line 590: it.effect("quarantines a full batch of poison recovery rows before redriving valid work", () =>
Line 655: it.effect("fairly redrives recovery and ordinary work beyond a full bounded batch", () =>
Line 791: it.effect("rejects ...
<path>/home/byk/Code/opencode/packages/core/test/session-projector.test.ts</path>
<type>file</type>
<content>
480: delivery: "queue",
481: })
482: }),
483: )
484:
485: it.effect("redrives a durable recovery wake after admission", () =>
486: Effect.gen(function* () {
487: const { db } = yield* Database.Service
488: const events = yield* EventV2.Service
489: yield* db
490: .insert(ProjectTable)
491: .values({ id: Project.ID.global, worktree: AbsolutePath.make("/project"), sandboxes: [] })
492: .run()
493: yield* db
494: .insert(SessionTable)
495: .values({
496: id: sessionID,
497: project_id: Project.ID.global,
498: slug: "test",
499: directory: "/project",
500: title: "test",
501: version: "test",
502: })
503: .run()
504: yield* events.publish(SessionEvent.Step.Recovered, {
505: sessionID,
506: ...
<path>/home/byk/Code/opencode/packages/core/src/event.ts</path>
<type>file</type>
<content>
440:
441: function replay(
442: event: SerializedEvent,
443: options?: { readonly publish?: boolean; readonly ownerID?: string; readonly strictOwner?: boolean },
444: ) {
445: return Effect.gen(function* () {
446: const definition = Durable.get(event.type)
447: if (!definition?.durable) {
448: yield* Effect.die(
449: new InvalidDurableEventError({ type: event.type, message: `Unknown durable event type ${event.type}` }),
450: )
451: } else {
452: const payload = {
453: id: event.id,
454: type: definition.type,
455: data: Schema.decodeUnknownSync(definition.data)(event.data),
456: } as Payload
457: const committed = yield* commitDurableEvent(definition, payload, {
458: seq: event.seq,
459: ...
a954d8f5b6923b0317200ee52048f0c649e8a8f6b166da03509473ca4b21ab11 /tmp/opencode/session-recovery-final-v12.patch 1f3de4dd2e48626680e3d52f48ab351ae7dca6d3bb4f996b6b3f1b7ec713daf6 /home/byk/Code/opencode/packages/opencode/dist/server/opencode-server M .lore.md M AGENTS.md M packages/core/schema.json M packages/core/src/database/migration.gen.ts M packages/core/src/database/migration/20260914170650_session-recovery.ts D packages/core/src/database/migration/20260914214636_session-execution.ts D packages/core/src/database/migration/20260914222526_session-execution-phase.ts M packages/core/src/database/schema.gen.ts M packages/core/src/session.ts M packages/core/src/session/compaction.ts M packages/core/src/session/context-epoch.ts M packages/core/src/session/execution/local.ts M packages/core/src/session/input.ts M packages/core/src/session/message-updater.ts M packages/core/src/session/projector.ts M packages/core/src/session/recovery.ts M ...
ab9408c81cc9916177641ae8e9f08624fc27b5b9.a954d8f5b6923b0317200ee52048f0c649e8a8f6b166da03509473ca4b21ab11.1f3de4dd2e48626680e3d52f48ab351ae7dca6d3bb4f996b6b3f1b7ec713daf6.repo-setup skill was unavailable; I followed the repository and nested AGENTS.md files directly.The primary closure is incomplete.
Claim acquisition correctly captures the latest assistant sequence inside the same immediate transaction that inserts the claim:
packages/core/src/session/execution/local.ts:36-65Step.Started also advances assistant_seq through the exact owner’s durable event transaction:
packages/core/src/session/runner/llm.ts:297-299packages/core/src/session/runner/publish-llm-event.ts:87-105packages/core/src/session/execution/claim.ts:27-54However, recovery checks the latest assistant before entering the durable Step.Recovered transaction:
packages/core/src/session/recovery.ts:142-155packages/core/src/session/recovery.ts:162-184.The projector only repeats the latest-assistant check when assistantMessageID is present:
packages/core/src/session/projector.ts:424-440Assistant-less ready, unknown, and continue recoveries therefore have this interleaving:
assistant_seq = N.N.Step.Started commits a newer assistant at N+1.Step.Recovered at N+2; the projector skips latest-assistant validation.