Dashboard › opencode › Session 0dhbNtbQaUYv
0dhbNtbQaUYvUS5VcStrict READ-ONLY correctness/adversarial review of frozen v23 in /tmp/opencode/session-recovery-v23-review. Never edit, run tests/builds/services, mutate VCS/index/refs, or use recall. Verify immutable inputs first: base ab9408c81cc9916177641ae8e9f08624fc27b5b9; patch /tmp/opencode/session-recovery-final-v23.patch SHA-256 14035d7631ba25b820fdc553087469935f447af034d549e2f14f8a141eda59dc; SEA /home/byk/Code/opencode/packages/opencode/dist/server/opencode-server SHA-256 f875987afa4336956b9f33e14eee6de0a4af90e2bc6de899cccb7cbe5a5df998; 34 paths. Inspect all changed files and relevant context. Focus on: acquisition-to-activeClaims registration/finalizer handoff under pending interrupt, acquired latch success/failure/defect semantics, coordinator stopping before durable cancelling and preservation of already/during-setup wakes/resumes, beforeInterrupt failure finalization, concurrent interrupt single-flight; malformed assistant decode quarantine under exact live claim and bounded batches; final cancellation Tool.Failed/Step.Interrupted event atomically deletes exact claim and publication failure rolls all back; completed Step.Failed preserves provider error; failed-Step restart never continues; continue phase still promotes. Recheck ownership, replay, fairness, corruption, snapshots, schema ancestry, generated contracts/layering. Accepted residuals: final check-call, process-local routing, bounded skew. Findings first with exact file:line and MUST-FIX/CONCERN. End exactly MERGE or DO-NOT-MERGE.
/tmp/opencode/session-recovery-v23-review/AGENTS.md /tmp/opencode/session-recovery-v23-review/packages/effect-sqlite-node/package.json /tmp/opencode/session-recovery-v23-review/packages/sdk-next/package.json /tmp/opencode/session-recovery-v23-review/CONTRIBUTING.md /tmp/opencode/session-recovery-v23-review/packages/schema/AGENTS.md /tmp/opencode/session-recovery-v23-review/packages/schema/package.json /tmp/opencode/session-recovery-v23-review/packages/protocol/package.json /tmp/opencode/session-recovery-v23-review/packages/session-ui/AGENTS.md /tmp/opencode/session-recovery-v23-review/github/package.json /tmp/opencode/session-recovery-v23-review/packages/session-ui/package.json /tmp/opencode/session-recovery-v23-review/packages/effect-drizzle-sqlite/AGENTS.md /tmp/opencode/session-recovery-v23-review/artifacts/glm52-rise-video/package.json /tmp/opencode/session-recovery-v23-review/packages/effect-drizzle-sqlite/package.json /tmp/opencode/session-recovery-v23-review/sdks/vscode/package....
<path>/tmp/opencode/session-recovery-v23-review/AGENTS.md</path> <type>file</type> <content> 1: - To regenerate the legacy JavaScript SDK, run `./packages/sdk/js/script/build.ts`. 2: - After changing the public Protocol or Server `HttpApi`, run `bun run generate` from `packages/client`. Do not edit `src/generated` or `src/generated-effect` directly. 3: - Keep runtime dependencies directed from Schema to Core and Protocol, then from Core and Protocol to Server. Client runtime code may depend on Schema and Protocol but never Core or Server; `sdk-next` composes Client, Core, and Server. 4: - The default branch in this repo is `dev`. 5: - Local `main` ref may not exist; use `dev` or `origin/dev` for diffs. 6: 7: ## Branch Names 8: 9: Use a short branch name of at most three words, separated by hyphens. Do not use slashes or type prefixes such as `feat/` or `fix/`. 10: 11: Examples: `session-recovery`, `fix-scroll-state`, `regenerate-sdk`. ...
<path>/tmp/opencode/session-recovery-v23-review/packages/core/package.json</path>
<type>file</type>
<content>
1: {
2: "$schema": "https://json.schemastore.org/package.json",
3: "version": "1.18.30",
4: "name": "@opencode-ai/core",
5: "type": "module",
6: "license": "MIT",
7: "private": true,
8: "scripts": {
9: "db": "bun drizzle-kit",
10: "migration": "bun run script/migration.ts",
11: "fix-node-pty": "bun run script/fix-node-pty.ts",
12: "test": "bun test --only-failures",
13: "typecheck": "tsgo --noEmit"
14: },
15: "bin": {
16: "opencode": "./bin/opencode"
17: },
18: "exports": {
19: "./effect/layer-node": "./src/effect/layer-node.ts",
20: "./effect/app-node": "./src/effect/app-node.ts",
21: "./session/runner": "./src/session/runner/index.ts",
22: "./system-context": "./src/system-context/index.ts",
23: "./*": "./src/*.ts"
24: },
25: "imports": {
26: "#sqlite": {
27: "bun": ...
<path>/tmp/opencode/session-recovery-v23-review/CONTRIBUTING.md</path> <type>file</type> <content> 1: # Contributing to OpenCode 2: 3: We want to make it easy for you to contribute to OpenCode. Here are the most common type of changes that get merged: 4: 5: - Bug fixes 6: - Additional LSPs / Formatters 7: - Improvements to LLM performance 8: - Support for new providers 9: - Fixes for environment-specific quirks 10: - Missing standard behavior 11: - Documentation improvements 12: 13: However, any UI or core product feature must go through a design review with the core team before implementation. 14: 15: If you are unsure if a PR would be accepted, feel free to ask a maintainer or look for issues with any of the following labels: 16: 17: - [`help wanted`](https://github.com/anomalyco/opencode/issues?q=is%3Aissue%20state%3Aopen%20label%3Ahelp-wanted) 18: - [`good first ...
14035d7631ba25b820fdc553087469935f447af034d549e2f14f8a141eda59dc /tmp/opencode/session-recovery-final-v23.patch f875987afa4336956b9f33e14eee6de0a4af90e2bc6de899cccb7cbe5a5df998 /home/byk/Code/opencode/packages/opencode/dist/server/opencode-server
ab9408c81cc9916177641ae8e9f08624fc27b5b9 2e9407768d1401a25b69febb36657638a779053a ab9408c81cc9916177641ae8e9f08624fc27b5b9 ab9408c81cc9916177641ae8e9f08624fc27b5b9 M packages/client/src/generated/types.ts M packages/core/schema.json M packages/core/src/database/migration.gen.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/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 packages/core/src/session/sql.ts M packages/core/test/database-migration.test.ts M packages/core/test/session-projector.test.ts M packages/core/test/session-prompt.test.ts M ...
M packages/client/src/generated/types.ts M packages/core/schema.json M packages/core/src/database/migration.gen.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/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 packages/core/src/session/sql.ts M packages/core/test/database-migration.test.ts M packages/core/test/session-projector.test.ts M packages/core/test/session-prompt.test.ts M packages/core/test/session-run-coordinator.test.ts M packages/core/test/session-runner-recorded.test.ts M packages/core/test/session-runner-tool-events.test.ts M packages/core/test/sessio...
<path>/tmp/opencode/session-recovery-v23-review/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: (
15: key: Key,
16: cleanup?: Effect.Effect<void>,
17: ...
<path>/tmp/opencode/session-recovery-v23-review/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, DateTime, Deferred, Duration, Effect, Exit, Layer, Option, Schedule, Schema } 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 { EventV2 } from "../../event"
13: import { SessionEvent } from "../event"
14: import { SessionExecutionClaim } from "./claim"
15: import {
16: SESSION_EXECUTION_LEASE_MS,
17: SessionExecutionTable,
18: ...
<path>/tmp/opencode/session-recovery-v23-review/packages/core/src/session/execution/claim.ts</path>
<type>file</type>
<content>
1: export * as SessionExecutionClaim from "./claim"
2:
3: import { and, eq, gt, notInArray } 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: ...
<path>/tmp/opencode/session-recovery-v23-review/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 { SessionMessage } from "./message"
14: import { continuation } from "./recovery-id"
15: import { SessionSchema } from "./schema"
16: import {
17: MAX_WAKE_ATTEMPTS,
18: SESSION_EXECUTION_LEASE_MS,
19: SessionExecutionTable,
20: ...
<path>/tmp/opencode/session-recovery-v23-review/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, SessionTable } from "./sql"
14:
15: type DatabaseService = Database.Interface["db"]
16:
17: export { Admitted, Delivery }
18:
19: const decodePrompt = Schema.decodeUnknownSync(Prompt)
20: const encodePrompt = ...
<path>/tmp/opencode/session-recovery-v23-review/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. ...
<path>/tmp/opencode/session-recovery-v23-review/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 ...
<path>/tmp/opencode/session-recovery-v23-review/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 ?? ...
No files found
/tmp/opencode/session-recovery-v23-review/packages/core/src/event.ts
Found 13 matches
/tmp/opencode/session-recovery-v23-review/packages/core/src/event.ts:
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 357: (wake) => PubSub.publish(wake, undefined),
Line 369: function publishEvent<D extends Definition>(definition: D, event: Payload<D>, commit?: PublishOptions["commit"]) {
Line 414: if (typed) yield* PubSub.publish(typed, event)
Line 415: yield* PubSub.publish(pubsub.all, event)
Line 419: function publish<D extends Definition>(definition: D, data: Data<D>, options?: PublishOptions) {
Line 427: return yield* publishEvent(
Line 443: options?: { readonly publish?: boolean; readonly ownerID?: string; readonly ...
<path>/tmp/opencode/session-recovery-v23-review/packages/core/src/event.ts</path>
<type>file</type>
<content>
340: id: event.id,
341: aggregate_id: aggregateID,
342: seq,
343: type: versionedType(definition.type, durable.version),
344: data: encoded,
345: },
346: ])
347: .run()
348: .pipe(Effect.orDie)
349: return { aggregateID, seq }
350: }),
351: { behavior: "immediate" },
352: )
353: .pipe(Effect.orDie)
354: if (committed) {
355: yield* Effect.forEach(
356: pubsub.durable.get(committed.aggregateID) ?? ...
<path>/tmp/opencode/session-recovery-v23-review/packages/core/src/event.ts</path>
<type>file</type>
<content>
260: )
261: }
262: if (input && input.seq <= latest) {
263: const stored = yield* db
264: .select()
265: .from(EventTable)
266: .where(and(eq(EventTable.aggregate_id, aggregateID), eq(EventTable.seq, input.seq)))
267: .get()
268: .pipe(Effect.orDie)
269: if (
270: stored?.id === event.id &&
271: stored.type === versionedType(definition.type, durable.version) &&
272: isDeepStrictEqual(stored.data, encoded)
273: ) {
274: if (input.ownerID && ...
<path>/tmp/opencode/session-recovery-v23-review/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: ...
<path>/tmp/opencode/session-recovery-v23-review/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>/tmp/opencode/session-recovery-v23-review/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 { ...
<path>/tmp/opencode/session-recovery-v23-review/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 ...
<path>/tmp/opencode/session-recovery-v23-review/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: ...
Found 21 matches
/tmp/opencode/session-recovery-v23-review/packages/core/src/database/schema.gen.ts:
Line 158: CREATE TABLE \`session_execution\` (
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', 'cancelled'))
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 \`fk_session_recovery_session_id_session_id_fk\` ...
<path>/tmp/opencode/session-recovery-v23-review/packages/core/src/database/schema.gen.ts</path> <type>file</type> <content> 120: \`time_created\` integer NOT NULL, 121: \`time_updated\` integer NOT NULL, 122: \`time_initialized\` integer, 123: \`sandboxes\` text NOT NULL, 124: \`commands\` text 125: ); 126: `) 127: yield* tx.run(` 128: CREATE TABLE \`message\` ( 129: \`id\` text PRIMARY KEY, 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: ...
<path>/tmp/opencode/session-recovery-v23-review/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 ...
Found 6 matches
/home/byk/.local/share/opencode/repos/github.com/Effect-TS/effect-smol/packages/effect/src/Option.ts:
Line 1345: export const andThen: {
/home/byk/.local/share/opencode/repos/github.com/Effect-TS/effect-smol/packages/effect/src/Schedule.ts:
Line 631: export const andThen: {
Line 689: export const andThenResult: {
/home/byk/.local/share/opencode/repos/github.com/Effect-TS/effect-smol/packages/effect/src/Effect.ts:
Line 2066: export const andThen: {
/home/byk/.local/share/opencode/repos/github.com/Effect-TS/effect-smol/packages/effect/src/Result.ts:
Line 1393: export const andThen: {
/home/byk/.local/share/opencode/repos/github.com/Effect-TS/effect-smol/packages/effect/src/internal/effect.ts:
Line 1363: export const andThen: {
<path>/home/byk/.local/share/opencode/repos/github.com/Effect-TS/effect-smol/packages/effect/src/Effect.ts</path> <type>file</type> <content> 2030: * // Function to apply a discount safely to a transaction amount 2031: * const applyDiscount = ( 2032: * total: number, 2033: * discountRate: number 2034: * ): Effect.Effect<number, DiscountRateError> => 2035: * discountRate === 0 2036: * ? Effect.fail(new DiscountRateError()) 2037: * : Effect.succeed(total - (total * discountRate) / 100) 2038: * 2039: * // Simulated asynchronous task to fetch a transaction amount from database 2040: * const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100)) 2041: * 2042: * // Using Effect.map and Effect.flatMap 2043: * const result1 = pipe( 2044: * fetchTransactionAmount, 2045: * Effect.map((amount) => amount * 2), 2046: * Effect.flatMap((amount) => applyDiscount(amount, 5)) 2047: * ) 2048: * 2049: * ...
Found 100 matches (more matches available)
/tmp/opencode/session-recovery-v23-review/packages/core/test/session-runner-message.test.ts:
Line 160: id: "pending",
Line 162: state: SessionMessage.ToolStatePending.make({ status: "pending", input: '{"path":"README.md"}' }),
Line 239: { type: "tool-call", id: "pending", name: "read", input: { path: "README.md" } },
/tmp/opencode/session-recovery-v23-review/packages/core/test/session-run-coordinator.test.ts:
Line 9: it.effect("joins concurrent resumes for one key", () =>
Line 47: const resumed = yield* coordinator.run("session").pipe(Effect.forkChild)
Line 50: yield* Fiber.join(resumed)
Line 159: const resumed = yield* coordinator.run("session").pipe(Effect.forkChild)
Line 166: yield* Fiber.join(resumed)
Line 194: const resumed = yield* coordinator.run("session").pipe(Effect.forkChild)
Line 202: yield* Fiber.join(resumed)
Line ...
<path>/tmp/opencode/session-recovery-v23-review/packages/core/test/session-run-coordinator.test.ts</path>
<type>file</type>
<content>
1: import { describe, expect } from "bun:test"
2: import { Cause, Deferred, Effect, Exit, Fiber, Layer } from "effect"
3: import { SessionRunCoordinator } from "@opencode-ai/core/session/run-coordinator"
4: import { testEffect } from "./lib/effect"
5:
6: const it = testEffect(Layer.empty)
7:
8: describe("SessionRunCoordinator", () => {
9: it.effect("joins concurrent resumes for one key", () =>
10: Effect.scoped(
11: Effect.gen(function* () {
12: const gate = yield* Deferred.make<void>()
13: let runs = 0
14: const coordinator = yield* SessionRunCoordinator.make({
15: drain: () => Effect.sync(() => runs++).pipe(Effect.andThen(Deferred.await(gate))),
16: })
17:
18: const first = yield* coordinator.run("session").pipe(Effect.forkChild)
19: yield* Effect.yieldNow
20: const ...
Found 3 matches
/home/byk/.local/share/opencode/repos/github.com/Effect-TS/effect-smol/packages/effect/src/Deferred.ts:
Line 321: internalEffect.sync(() => doneUnsafe(self, effect))
Line 839: * const success = Deferred.doneUnsafe(deferred, Effect.succeed(42))
Line 846: export const doneUnsafe = <A, E>(self: Deferred<A, E>, effect: Effect<A, E>): boolean => {
<path>/home/byk/.local/share/opencode/repos/github.com/Effect-TS/effect-smol/packages/effect/src/Deferred.ts</path>
<type>file</type>
<content>
820: * completion effect.
821: *
822: * **When to use**
823: *
824: * Use to complete a `Deferred` synchronously in low-level code that already has
825: * the completion effect.
826: *
827: * **Details**
828: *
829: * This mutates the `Deferred` directly and should be reserved for low-level
830: * code; prefer the effectful completion APIs when possible. Returns `true` if
831: * this call completed the `Deferred`, or `false` if it was already completed.
832: *
833: * **Example** (Completing a Deferred unsafely)
834: *
835: * ```ts
836: * import { Deferred, Effect } from "effect"
837: *
838: * const deferred = Deferred.makeUnsafe<number>()
839: * const success = Deferred.doneUnsafe(deferred, Effect.succeed(42))
840: * console.log(success) // true
841: * ```
842: *
843: * @category unsafe
844: * @since 4.0.0
845: ...
<path>/tmp/opencode/session-recovery-v23-review/packages/core/test/lib/effect.ts</path>
<type>file</type>
<content>
1: import { test, type TestOptions } from "bun:test"
2: import { Cause, Effect, Exit, Layer } from "effect"
3: import type * as Scope from "effect/Scope"
4: import * as TestClock from "effect/testing/TestClock"
5: import * as TestConsole from "effect/testing/TestConsole"
6:
7: type Body<A, E, R> = Effect.Effect<A, E, R> | (() => Effect.Effect<A, E, R>)
8:
9: const body = <A, E, R>(value: Body<A, E, R>) => Effect.suspend(() => (typeof value === "function" ? value() : value))
10:
11: const run = <A, E, R, E2>(value: Body<A, E, R | Scope.Scope>, layer: Layer.Layer<R, E2>) =>
12: Effect.gen(function* () {
13: const exit = yield* body(value).pipe(Effect.scoped, Effect.provide(layer), Effect.exit)
14: if (Exit.isFailure(exit)) {
15: for (const err of Cause.prettyErrors(exit.cause)) {
16: yield* Effect.logError(err)
17: }
18: }
19: ...
<path>/home/byk/.local/share/opencode/repos/github.com/Effect-TS/effect-smol/packages/effect/src/internal/effect.ts</path>
<type>file</type>
<content>
1345: }
1346: )
1347:
1348: /** @internal */
1349: export const asSome = <A, E, R>(
1350: self: Effect.Effect<A, E, R>
1351: ): Effect.Effect<Option.Option<A>, E, R> => map(self, Option.some)
1352:
1353: /** @internal */
1354: export const flip = <A, E, R>(
1355: self: Effect.Effect<A, E, R>
1356: ): Effect.Effect<E, A, R> =>
1357: matchEffect(self, {
1358: onFailure: succeed,
1359: onSuccess: fail
1360: })
1361:
1362: /** @internal */
1363: export const andThen: {
1364: <A, B, E2, R2>(
1365: f: (a: A) => Effect.Effect<B, E2, R2>
1366: ): <E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<B, E | E2, R | R2>
1367: <B, E2, R2>(
1368: f: Effect.Effect<B, E2, R2>
1369: ): <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<B, E | E2, R | R2>
1370: <A, E, R, B, E2, R2>(
1371: self: ...
<path>/tmp/opencode/session-recovery-v23-review/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, sql } 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 { SessionExecutionClaim } from "@opencode-ai/core/session/execution/claim"
11: import { SessionMessage } from "@opencode-ai/core/session/message"
12: import { SessionSchema } from "@opencode-ai/core/session/schema"
13: import { SessionExecutionTable, SessionTable } from "@opencode-ai/core/session/sql"
14: import { testEffect ...
<path>/tmp/opencode/session-recovery-v23-review/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>/tmp/opencode/session-recovery-v23-review/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: ...
<path>/tmp/opencode/session-recovery-v23-review/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>/tmp/opencode/session-recovery-v23-review/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 ...
Found 53 matches
/tmp/opencode/session-recovery-v23-review/packages/core/test/session-projector.test.ts:
Line 68: it.effect("atomically reconciles one abandoned execution into one continuation", () =>
Line 222: it.effect("never continues a Step that durably failed before owner loss", () =>
Line 325: it.effect("records a recovery continuation without forging an assistant identity", () =>
Line 361: it.effect("recovers each abandoned execution once across repeated startup scans", () =>
Line 407: it.effect("never recovers a live execution lease", () =>
Line 445: it.effect("never recovers an execution superseded by a newer assistant", () =>
Line 607: it.effect("recovers assistant-less continuation at its current assistant boundary", () =>
Line 658: it.effect("redrives a durable recovery wake after admission", () =>
Line 709: it.effect("quarantines a malformed recovery row without blocking a valid wake", () =>
Line 763: it.effect("quarantines ...
Found 100 matches (more matches available)
/tmp/opencode/session-recovery-v23-review/packages/core/test/session-runner.test.ts:
Line 619: it.effect("redrives only the synthetic recovery continuation", () =>
Line 688: it.effect("clears durable execution intent when ordinary input is promoted", () =>
Line 715: it.effect("redrives an ordinary prompt after its advisory wake is lost", () =>
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 902: it.effect("advertises and executes a globally attached application tool", () =>
Line 958: it.effect("starts a real runner turn after default prompt recording", () =>
Line 977: it.effect("streams one request with registry ...
Found 100 matches (more matches available)
/tmp/opencode/session-recovery-v23-review/packages/core/test/session-runner.test.ts:
Line 619: it.effect("redrives only the synthetic recovery continuation", () =>
Line 688: it.effect("clears durable execution intent when ordinary input is promoted", () =>
Line 715: it.effect("redrives an ordinary prompt after its advisory wake is lost", () =>
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 902: it.effect("advertises and executes a globally attached application tool", () =>
Line 958: it.effect("starts a real runner turn after default prompt recording", () =>
Line 977: it.effect("streams one request with registry ...
<path>/tmp/opencode/session-recovery-v23-review/packages/core/test/session-runner.test.ts</path>
<type>file</type>
<content>
3840: expect(result).toMatchObject({ _tag: "Failure" })
3841: }),
3842: 15_000,
3843: )
3844:
3845: it.effect("durably fails blocked local tools when a provider turn is interrupted", () =>
3846: Effect.gen(function* () {
3847: yield* setup
3848: const session = yield* SessionV2.Service
3849: yield* session.prompt({ sessionID, prompt: Prompt.make({ text: "Interrupt blocked tool" }), resume: false })
3850: executions.length = 0
3851: toolExecutionGate = yield* Deferred.make<void>()
3852: responseStream = Stream.concat(
3853: Stream.fromIterable([
3854: LLMEvent.stepStart({ index: 0 }),
3855: LLMEvent.toolCall({ id: "call-before-interrupt", name: "echo", input: { text: "blocked" } }),
3856: ]),
3857: Stream.never,
3858: )
3859:
3860: const run = ...
<path>/tmp/opencode/session-recovery-v23-review/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 ...
<path>/tmp/opencode/session-recovery-v23-review/packages/core/test/session-projector.test.ts</path>
<type>file</type>
<content>
2010: }),
2011: )
2012:
2013: it.effect("never promotes a quarantined recovery continuation as an ordinary steer", () =>
2014: Effect.gen(function* () {
2015: const { db } = yield* Database.Service
2016: const events = yield* EventV2.Service
2017: yield* db
2018: .insert(ProjectTable)
2019: .values({ id: Project.ID.global, worktree: AbsolutePath.make("/project"), sandboxes: [] })
2020: .run()
2021: yield* db
2022: .insert(SessionTable)
2023: .values({
2024: id: sessionID,
2025: project_id: Project.ID.global,
2026: slug: "test",
2027: directory: "/project",
2028: title: "test",
2029: version: "test",
2030: })
2031: .run()
2032: yield* events.publish(SessionEvent.Step.Recovered, {
2033: ...
<path>/tmp/opencode/session-recovery-v23-review/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 ...
Found 5 matches
/tmp/opencode/session-recovery-v23-review/packages/opencode/src/server/routes/instance/httpapi/server.ts:
Line 67: import { SessionExecution } from "@opencode-ai/core/session/execution"
Line 68: import * as SessionExecutionLocal from "@opencode-ai/core/session/execution/local"
Line 69: import { SessionRecovery } from "@opencode-ai/core/session/recovery"
Line 300: AppNodeBuilderV1.build(LayerNode.group([SessionV2.node, SessionRecovery.node]), [
Line 302: [SessionExecution.node, SessionExecutionLocal.node],
<path>/tmp/opencode/session-recovery-v23-review/packages/opencode/src/server/routes/instance/httpapi/server.ts</path>
<type>file</type>
<content>
45: import { Discovery } from "@/skill/discovery"
46: import { Snapshot } from "@/snapshot"
47: import { Storage } from "@/storage/storage"
48: import { ToolRegistry } from "@/tool/registry"
49: import { Truncate } from "@/tool/truncate"
50: import { Worktree } from "@/worktree"
51: import { RuntimeFlags } from "@/effect/runtime-flags"
52: import { MoveSession } from "@opencode-ai/core/control-plane/move-session"
53: import { Database } from "@opencode-ai/core/database/database"
54: import { AppNodeBuilderV1 } from "@/effect/app-node-builder-v1"
55: import { LayerNode } from "@opencode-ai/core/effect/layer-node"
56: import { httpClient } from "@opencode-ai/core/effect/app-node-platform"
57: import { EventV2 } from "@opencode-ai/core/event"
58: import { ModelsDev } from "@opencode-ai/core/models-dev"
59: import { Npm } from ...
<path>/tmp/opencode/session-recovery-v23-review/packages/opencode/src/server/routes/instance/httpapi/server.ts</path> <type>file</type> <content> 280: ptyConnectApiRoutes, 281: instanceRoutes, 282: serverRoutes, 283: docRoute, 284: uiRoute, 285: ).pipe( 286: Layer.provide([ 287: errorLayer, 288: compressionLayer, 289: corsVaryFix, 290: fenceLayer, 291: cors(corsOptions), 292: AppNodeBuilderV1.build(MoveSession.node, [[LocationServiceMap.node, locationServiceMapV2]]), 293: HttpServer.layerServices, 294: ]), 295: Layer.provide(Layer.succeed(CorsConfig)(corsOptions)), 296: Layer.provide(sessionLocationLayer), 297: Layer.provide(locationLayer), 298: Layer.provide(PtyEnvironment.layer), 299: Layer.provide( 300: AppNodeBuilderV1.build(LayerNode.group([SessionV2.node, SessionRecovery.node]), [ 301: [LocationServiceMap.node, locationServiceMapV2], 302: [SessionExecution.node, ...
Found 5 matches
/tmp/opencode/session-recovery-v23-review/packages/opencode/src/server/routes/instance/httpapi/server.ts:
Line 67: import { SessionExecution } from "@opencode-ai/core/session/execution"
Line 68: import * as SessionExecutionLocal from "@opencode-ai/core/session/execution/local"
Line 213: const app = LayerNode.group([
Line 300: AppNodeBuilderV1.build(LayerNode.group([SessionV2.node, SessionRecovery.node]), [
Line 302: [SessionExecution.node, SessionExecutionLocal.node],
<path>/tmp/opencode/session-recovery-v23-review/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: ...
Found 6 matches /tmp/opencode/session-recovery-v23-review/packages/client/src/generated/types.ts: Line 778: readonly requestExecution?: boolean Line 784: readonly type: "session.next.prompt.execution_requested" Line 908: readonly type: "session.next.step.recovered" Line 1272: readonly requestExecution?: boolean Line 1278: readonly type: "session.next.prompt.execution_requested" Line 1402: readonly type: "session.next.step.recovered"
<path>/tmp/opencode/session-recovery-v23-review/packages/client/src/generated/types.ts</path>
<type>file</type>
<content>
745: readonly agents?: ReadonlyArray<{
746: readonly name: string
747: readonly source?: { readonly start: number; readonly end: number; readonly text: string }
748: }>
749: }
750: readonly delivery: "steer" | "queue"
751: }
752: }
753: | {
754: readonly id: string
755: readonly metadata?: { readonly [x: string]: JsonValue }
756: readonly type: "session.next.prompt.admitted"
757: readonly durable?: { readonly aggregateID: string; readonly seq: number; readonly version: number }
758: readonly location?: { readonly directory: string; readonly workspaceID?: string }
759: readonly data: {
760: readonly timestamp: number
761: readonly sessionID: string
762: readonly messageID: string
763: ...
Found 19 matches
/tmp/opencode/session-recovery-v23-review/packages/sdk/js/src/v2/gen/types.gen.ts:
Line 33: | EventSessionNextStepRecovered
Line 874: requestExecution?: boolean
Line 879: type: "session.next.prompt.execution_requested"
Line 983: type: "session.next.step.recovered"
Line 1659: | SyncEventSessionNextStepRecovered
Line 2794: | SessionNextStepRecovered
Line 2924: | SessionNextStepRecovered
Line 3430: requestExecution?: boolean
Line 3439: type: "session.next.prompt.execution_requested.1"
Line 3602: export type SyncEventSessionNextStepRecovered = {
Line 3606: type: "session.next.step.recovered.1"
Line 4362: requestExecution?: boolean
Line 4371: type: "session.next.prompt.execution_requested"
Line 4560: export type SessionNextStepRecovered = {
Line 4565: type: "session.next.step.recovered"
Line 6464: requestExecution?: boolean
Line 6470: type: ...
<path>/tmp/opencode/session-recovery-v23-review/packages/sdk/js/src/v2/gen/types.gen.ts</path>
<type>file</type>
<content>
3410: prompt: Prompt
3411: delivery: "steer" | "queue"
3412: }
3413: }
3414: }
3415:
3416: export type SyncEventSessionNextPromptAdmitted = {
3417: type: "sync"
3418: id: string
3419: syncEvent: {
3420: type: "session.next.prompt.admitted.1"
3421: id: string
3422: seq: number
3423: aggregateID: string
3424: data: {
3425: timestamp: number
3426: sessionID: string
3427: messageID: string
3428: prompt: Prompt
3429: delivery: "steer" | "queue"
3430: requestExecution?: boolean
3431: }
3432: }
3433: }
3434:
3435: export type SyncEventSessionNextPromptExecutionRequested = {
3436: type: "sync"
3437: id: string
3438: syncEvent: {
3439: type: "session.next.prompt.execution_requested.1"
3440: id: string
3441: seq: number
3442: aggregateID: string
3443: data: ...
diff --git a/packages/core/src/session.ts b/packages/core/src/session.ts
index 2dabfb2d6f..1fbd6285d0 100644
--- a/packages/core/src/session.ts
+++ b/packages/core/src/session.ts
@@ -363,26 +363,27 @@ const layer = Layer.effect(
yield* result.get(input.sessionID)
const prompt = resolvePrompt(input.prompt)
const messageID = input.id ?? SessionMessage.ID.create()
const delivery = input.delivery ?? "steer"
const expected = { sessionID: input.sessionID, messageID, prompt, delivery }
- const admitted = yield* SessionInput.admit(db, events, {
+ const admission = yield* SessionInput.admit(db, events, {
id: messageID,
sessionID: input.sessionID,
prompt,
delivery,
+ requestExecution: input.resume !== false,
}).pipe(
Effect.catchDefect((defect) =>
defect instanceof ...
<path>/tmp/opencode/session-recovery-v23-review/packages/core/src/session/execution.ts</path>
<type>file</type>
<content>
1: export * as SessionExecution from "./execution"
2:
3: import { Context, Effect, Layer } from "effect"
4: import { LayerNode } from "../effect/layer-node"
5: import { Node } from "../effect/app-node"
6: import { SessionRunner } from "./runner/index"
7: import { SessionSchema } from "./schema"
8:
9: export interface Interface {
10: /** Snapshots active execution owned by this process. */
11: readonly active: Effect.Effect<ReadonlySet<SessionSchema.ID>>
12: /** Starts execution while idle or joins the active execution. */
13: readonly resume: (sessionID: SessionSchema.ID) => Effect.Effect<void, SessionRunner.RunError>
14: /** Registers newly recorded work. Repeated wakeups may coalesce. */
15: readonly wake: (sessionID: SessionSchema.ID) => Effect.Effect<void>
16: /** Interrupt active work owned by this process. Idle interruption is a no-op. ...
diff --git a/packages/core/src/session/execution/local.ts b/packages/core/src/session/execution/local.ts
index d874c40832..749531403e 100644
--- a/packages/core/src/session/execution/local.ts
+++ b/packages/core/src/session/execution/local.ts
@@ -1,46 +1,318 @@
-import { Cause, Effect, Layer } from "effect"
+import { and, asc, desc, eq, isNull } from "drizzle-orm"
+import { Cause, Clock, DateTime, Deferred, Duration, Effect, Exit, Layer, Option, Schedule, Schema } from "effect"
+import { Database } from "../../database/database"
import { LocationServiceMap } from "../../location-service-map"
import { makeGlobalNode } from "../../effect/app-node"
import { SessionRunCoordinator } from "../run-coordinator"
import { SessionRunner } from "../runner"
+import { SessionMessage } from "../message"
import { SessionSchema } from "../schema"
import { SessionStore } from "../store"
import { SessionExecution } from "../execution"
+import { EventV2 } from "../../event"
+import { SessionEvent ...
Found 1 matches /home/byk/.local/share/opencode/repos/github.com/Effect-TS/effect-smol/packages/effect/src/Exit.ts: Line 59: export type Exit<A, E = never> = Success<A, E> | Failure<A, E>
<path>/home/byk/.local/share/opencode/repos/github.com/Effect-TS/effect-smol/packages/effect/src/Exit.ts</path>
<type>file</type>
<content>
45: *
46: * const result = Exit.match(success, {
47: * onSuccess: (value) => `Got value: ${value}`,
48: * onFailure: (cause) => `Got error: ${cause}`
49: * })
50: * ```
51: *
52: * @see {@link Success} for the success case
53: * @see {@link Failure} for the failure case
54: * @see {@link match} for pattern matching
55: *
56: * @category models
57: * @since 2.0.0
58: */
59: export type Exit<A, E = never> = Success<A, E> | Failure<A, E>
60:
61: /**
62: * Namespace containing helper types shared by `Exit` values.
63: *
64: * **When to use**
65: *
66: * Use to reference helper types that describe the shared structure of `Exit`
67: * values.
68: *
69: * @since 2.0.0
70: */
71: export declare namespace Exit {
72: /**
73: * Base interface shared by both Success and Failure. ...
No files found
No files found
Found 2 matches /home/byk/.local/share/opencode/repos/github.com/Effect-TS/effect-smol/packages/effect/src/Fiber.ts: Line 272: export const join: <A, E>(self: Fiber<A, E>) => Effect<A, E> = effect.fiberJoin Line 298: export const joinAll: <A extends Iterable<Fiber<any, any>>>(
diff --git a/packages/core/schema.json b/packages/core/schema.json
index d0eeeebd5c..6b15057125 100644
--- a/packages/core/schema.json
+++ b/packages/core/schema.json
@@ -1,10 +1,12 @@
{
"version": "7",
"dialect": "sqlite",
- "id": "f14a9b18-8207-487e-a3d3-227e629ba9ad",
- "prevIds": ["169a0f0f-d58f-479f-b024-fa1c7b9a09db"],
+ "id": "3bc49670-06d1-4eba-9a45-8c8128bdcf6f",
+ "prevIds": [
+ "f14a9b18-8207-487e-a3d3-227e629ba9ad"
+ ],
"ddl": [
{
"name": "workspace",
"entityType": "tables"
},
@@ -58,18 +60,26 @@
},
{
"name": "session_context_epoch",
"entityType": "tables"
},
+ {
+ "name": "session_execution",
+ "entityType": "tables"
+ },
{
"name": "session_input",
"entityType": "tables"
},
{
"name": "session_message",
"entityType": "tables"
},
+ {
+ "name": "session_recovery",
+ "entityType": "tables"
+ },
{
"name": "session",
...
Found 12 matches
/tmp/opencode/session-recovery-v23-review/packages/sdk/openapi.json:
Line 17899: "requestExecution": {
Line 17919: "enum": ["session.next.prompt.execution_requested"]
Line 18289: "enum": ["session.next.step.recovered"]
Line 25709: "requestExecution": {
Line 25740: "enum": ["session.next.prompt.execution_requested.1"]
Line 26299: "enum": ["session.next.step.recovered.1"]
Line 28599: "requestExecution": {
Line 28622: "enum": ["session.next.prompt.execution_requested"]
Line 29190: "enum": ["session.next.step.recovered"]
Line 34811: "requestExecution": {
Line 34831: "enum": ["session.next.prompt.execution_requested"]
Line 35201: "enum": ["session.next.step.recovered"]
<path>/tmp/opencode/session-recovery-v23-review/packages/sdk/openapi.json</path>
<type>file</type>
<content>
26275: },
26276: "required": ["type", "id", "seq", "aggregateID", "data"],
26277: "additionalProperties": false
26278: }
26279: },
26280: "required": ["type", "id", "syncEvent"],
26281: "additionalProperties": false
26282: },
26283: "SyncEventSessionNextStepRecovered": {
26284: "type": "object",
26285: "properties": {
26286: "type": {
26287: "type": "string",
26288: "enum": ["sync"]
26289: },
26290: "id": {
26291: "type": "string",
26292: "pattern": "^evt_"
26293: },
26294: "syncEvent": {
26295: "type": "object",
26296: "properties": {
26297: "type": {
26298: "type": "string",
26299: "enum": ...
diff --git a/packages/core/src/session/input.ts b/packages/core/src/session/input.ts
index 14b613678d..61f6a9a465 100644
--- a/packages/core/src/session/input.ts
+++ b/packages/core/src/session/input.ts
@@ -1,24 +1,29 @@
export * as SessionInput from "./input"
-import { and, asc, eq, isNull, lte } from "drizzle-orm"
-import { DateTime, Effect, Schema } from "effect"
+import { and, asc, desc, eq, isNull, lte } from "drizzle-orm"
+import { DateTime, Effect, Option, Schema } from "effect"
import { Admitted, Delivery } from "@opencode-ai/schema/session-input"
import type { Database } from "../database/database"
-import type { EventV2 } from "../event"
+import { EventV2 } from "../event"
import { SessionEvent } from "./event"
import { SessionMessage } from "./message"
import { Prompt } from "./prompt"
+import { continuation, message } from "./recovery-id"
import { SessionSchema } from "./schema"
-import { SessionInputTable, SessionMessageTable } from "./sql"
+import { ...
diff --git a/packages/core/src/session/runner/llm.ts b/packages/core/src/session/runner/llm.ts
index 874086a06b..ed7cc57008 100644
--- a/packages/core/src/session/runner/llm.ts
+++ b/packages/core/src/session/runner/llm.ts
@@ -6,11 +6,12 @@ import {
Message,
SystemPart,
isContextOverflowFailure,
type ProviderErrorEvent,
} from "@opencode-ai/llm"
-import { Cause, DateTime, Effect, FiberSet, Layer, Option, Semaphore, Stream } from "effect"
+import { Cause, DateTime, Effect, Exit, Fiber, Layer, Option, Semaphore, Stream } from "effect"
+import { and, eq } from "drizzle-orm"
import { AgentV2 } from "../../agent"
import { Config } from "../../config"
import { Database } from "../../database/database"
import { EventV2 } from "../../event"
import { Location } from "../../location"
@@ -27,12 +28,15 @@ import { ToolOutputStore } from "../../tool-output-store"
import { SessionContextEpoch } from "../context-epoch"
import { SessionCompaction } from "../compaction"
import { ...
Found 34 matches /tmp/opencode/session-recovery-final-v23.patch: Line 1: diff --git a/packages/client/src/generated/types.ts b/packages/client/src/generated/types.ts Line 109: diff --git a/packages/core/schema.json b/packages/core/schema.json Line 1022: diff --git a/packages/core/src/database/migration.gen.ts b/packages/core/src/database/migration.gen.ts Line 1033: diff --git a/packages/core/src/database/migration/20260914170650_session-recovery.ts b/packages/core/src/database/migration/20260914170650_session-recovery.ts Line 1101: diff --git a/packages/core/src/database/schema.gen.ts b/packages/core/src/database/schema.gen.ts Line 1207: diff --git a/packages/core/src/session.ts b/packages/core/src/session.ts Line 1247: diff --git a/packages/core/src/session/compaction.ts b/packages/core/src/session/compaction.ts Line 1336: diff --git a/packages/core/src/session/context-epoch.ts b/packages/core/src/session/context-epoch.ts Line 1512: diff --git ...
Found 8 matches
/tmp/opencode/session-recovery-v23-review/packages/core/src/session/execution/claim.ts:
Line 47: values.phase === "cancelled"
Line 50: ? notInArray(SessionExecutionTable.phase, ["cancelled"])
Line 51: : notInArray(SessionExecutionTable.phase, ["cancelling", "cancelled"])
/tmp/opencode/session-recovery-v23-review/packages/core/src/session/sql.ts:
Line 230: phase: text().$type<"ready" | "safe" | "unknown" | "continue" | "cancelling" | "cancelled">().notNull(),
/tmp/opencode/session-recovery-v23-review/packages/core/src/session/recovery.ts:
Line 27: const Phase = Schema.Literals(["ready", "safe", "unknown", "continue", "cancelling", "cancelled"])
Line 122: if (phase.value === "cancelled") {
/tmp/opencode/session-recovery-v23-review/packages/core/src/session/execution/local.ts:
Line 132: if (current?.phase === "cancelling" || current?.phase === "cancelled") return
Line 156: if (current.phase === ...
Found 34 matches /tmp/opencode/session-recovery-final-v23.patch: Line 2: index 3b3188c874..5130fa9496 100644 Line 110: index d0eeeebd5c..6b15057125 100644 Line 1023: index e6ea4eaa14..77948f1529 100644 Line 1035: index 0000000000..20eb1a4373 Line 1102: index ed60fde6c5..94881e7038 100644 Line 1208: index 2dabfb2d6f..1fbd6285d0 100644 Line 1248: index f714633295..92a934c44f 100644 Line 1337: index 65b17a86a4..880d42bcf9 100644 Line 1513: index d874c40832..749531403e 100644 Line 1855: index 14b613678d..61f6a9a465 100644 Line 2450: index 46118a89fe..e2d7e6b38e 100644 Line 2544: index 792067017d..2742cabc24 100644 Line 2664: index 0000000000..c318d24982 Line 3248: index 2f89aff9e3..bb6c136257 100644 Line 3327: index 634075dd91..7b9ac3ae83 100644 Line 3349: index 874086a06b..ed7cc57008 100644 Line 3924: index 33652a618c..6943365105 100644 Line 4272: index 264a1d2cca..4f750e9786 100644 Line 4405: index 464ce2695a..9814b75a11 100644 ...
5130fa94963341f68ff81aeeb5c2f14e7338579e 6b15057125efd5fb0de2456a62b19bbef243bc18 77948f152910d908fa990652e38c8d756dca04e6 20eb1a43739b0bfaae61ad727f11b8a0f0c64c4e 94881e70387518c9caba17c8b9fcae204e5885b9 1fbd6285d00f1a5d75f4a60a726d085835bb7a06 92a934c44f1f805afbc6e8f01f76cb55362ddc91 880d42bcf9450b074028c920cbcaa4107178543c 749531403e0b180cff3035f452dd6cbf35c27a56 61f6a9a465a36f461493d3d3cc4f4477088e6e19 e2d7e6b38eebdfcdbe9742a2d6c2f16258c19090 2742cabc24865f914ea3634e25684c258147b797 c318d249827e6302e83e2dc6a036a49298ce3ea3 bb6c1362578f4ebe40ff98148bd5aba08f63e43e 7b9ac3ae83340794c509b353a6dccd442be3319a ed7cc57008ad27c4360bf483b171a560ec8d5dd8 694336510524d78fa6fc47636f0bfa9e86e85478 4f750e9786a0b5f554e917d1eecc16e24fb1af38 9814b75a11bc44be6dcf5fa1f50ade8d210832fe 117e67f3fadd172402437ca66ad6ee008ad85995 4918b87f21050cf876d96ae1d63a317c405280f2 a0d6f26467af572274bd16919d9623b2264be018 5fd15beee0715f45edfe60542ab7786052835e05 ec91d1b4a43360ae04691ab718cab92c1ba33a12 47b92f55e217c457...
<path>/tmp/opencode/session-recovery-final-v23.patch</path>
<type>file</type>
<content>
8630: diff --git a/packages/core/test/session-runner.test.ts b/packages/core/test/session-runner.test.ts
8631: index cc58b43b29..10bee0078d 100644
8632: --- a/packages/core/test/session-runner.test.ts
8633: +++ b/packages/core/test/session-runner.test.ts
8634: @@ -31,7 +31,8 @@ import { SessionMessage } from "@opencode-ai/core/session/message"
8635: import { Prompt } from "@opencode-ai/core/session/prompt"
8636: import { SessionProjector } from "@opencode-ai/core/session/projector"
8637: import { SessionExecution } from "@opencode-ai/core/session/execution"
8638: -import { SessionRunCoordinator } from "@opencode-ai/core/session/run-coordinator"
8639: +import { SessionExecutionLocal } from "@opencode-ai/core/session/execution/local"
8640: +import { SessionRecovery } from "@opencode-ai/core/session/recovery"
8641: import { SessionRunner } from "@opencode-ai/core/session/runner"
8642: import * as ...
<path>/tmp/opencode/session-recovery-final-v23.patch</path>
<type>file</type>
<content>
9180: + const session = yield* SessionV2.Service
9181: + const { db } = yield* Database.Service
9182: + response = fragmentFixture("text", "text-before-recovery-compaction", ["Earlier answer"]).completeEvents
9183: + yield* session.prompt({
9184: + sessionID,
9185: + prompt: Prompt.make({ text: "Earlier question ".repeat(180) }),
9186: + resume: false,
9187: + })
9188: + yield* session.resume(sessionID)
9189: + yield* session.prompt({
9190: + sessionID,
9191: + prompt: Prompt.make({ text: "Recent exact request ".repeat(180) }),
9192: + resume: false,
9193: + })
9194: + currentModel = compactModel
9195: + requests.length = 0
9196: + responses = [
9197: + fragmentFixture("text", "text-recovery-summary", ["## Objective\n- Preserve recovery"]).completeEvents,
9198: + ]
9199: + ...
<path>/tmp/opencode/session-recovery-final-v23.patch</path>
<type>file</type>
<content>
9730: + })
9731: + .onConflictDoNothing()
9732: + .returning({ id: SessionExecutionTable.id })
9733: + .get()
9734: + .pipe(Effect.orDie)
9735: + yield* Deferred.succeed(releaseFinalizer, undefined)
9736: + const result = yield* Fiber.join(run).pipe(Effect.timeout("5 seconds"))
9737: +
9738: + expect(retained).toMatchObject({ session_id: sessionID, phase: "safe" })
9739: + expect(replacement).toBeUndefined()
9740: + expect(result).toMatchObject({ _tag: "Failure" })
9741: + expect(yield* db.select().from(SessionExecutionTable).all()).toEqual([])
9742: }),
9743: + 15_000,
9744: )
9745:
9746: it.effect("returns permission corrections to the model and continues", () =>
9747: @@ -2942,6 +3785,63 @@ describe("SessionRunnerLLM", () => {
9748: }),
9749: )
9750:
9751: + it.live("never marks a failed Step safe while a ...
No files found
<path>/tmp/opencode/session-recovery-v23-review/packages/core/test/session-projector.test.ts</path>
<type>file</type>
<content>
1780: expect(yield* SessionInput.hasPending(db, sessionID, "queue")).toBe(false)
1781: expect(yield* SessionInput.promoteNextQueued(db, events, sessionID)).toBe(false)
1782: yield* SessionInput.admit(db, events, {
1783: id: ordinaryID,
1784: sessionID,
1785: prompt: Prompt.make({ text: "later" }),
1786: delivery: "queue",
1787: requestExecution: false,
1788: })
1789:
1790: expect(yield* SessionInput.hasPending(db, sessionID, "queue")).toBe(true)
1791: expect(yield* SessionInput.promoteNextQueued(db, events, sessionID)).toBe(true)
1792: expect(yield* db.select().from(SessionInputTable).where(eq(SessionInputTable.id, continuationID)).get()).toMatchObject(
1793: { promoted_seq: null },
1794: )
1795: expect(yield* ...
<path>/tmp/opencode/session-recovery-v23-review/packages/core/test/session-projector.test.ts</path>
<type>file</type>
<content>
1400: expect(yield* db.select().from(SessionExecutionTable).all()).toEqual([])
1401: expect(yield* db.select().from(SessionRecoveryTable).all()).toEqual([])
1402: expect(yield* db.select().from(SessionInputTable).get()).toMatchObject({
1403: id: inputID,
1404: promoted_seq: expect.any(Number),
1405: wake_pending: false,
1406: })
1407: expect(
1408: yield* db
1409: .select({ type: EventTable.type })
1410: .from(EventTable)
1411: .where(eq(EventTable.type, "session.next.step.recovered.1"))
1412: .all(),
1413: ).toEqual([])
1414: }),
1415: )
1416:
1417: it.effect("redrives one existing recovery after its replacement claim crashes before promotion", () =>
1418: Effect.gen(function* () {
1419: const { db } = yield* Database.Service
1420: ...
<path>/tmp/opencode/session-recovery-v23-review/packages/core/test/session-projector.test.ts</path>
<type>file</type>
<content>
430: owner_id: "live",
431: phase: "unknown",
432: time_created: Date.now(),
433: expires_at: Date.now() + 60_000,
434: })
435: .run()
436:
437: yield* SessionRecovery.recover().pipe(Effect.provideService(SessionExecution.Service, recoveryExecution))
438:
439: expect(yield* db.select().from(SessionExecutionTable).all()).toHaveLength(1)
440: expect(yield* db.select().from(SessionRecoveryTable).all()).toEqual([])
441: expect(yield* db.select().from(SessionInputTable).all()).toEqual([])
442: }),
443: )
444:
445: it.effect("never recovers an execution superseded by a newer assistant", () =>
446: Effect.gen(function* () {
447: const { db } = yield* Database.Service
448: const abandonedID = SessionMessage.ID.make("msg_recovery_abandoned")
449: yield* ...
<path>/tmp/opencode/session-recovery-v23-review/packages/schema/AGENTS.md</path> <type>file</type> <content> 1: # Schema Package Guide 2: 3: `@opencode-ai/schema` owns browser-safe wire and storage contracts shared by protocol, server, core, and generated SDKs. Keep runtime behavior, service layers, side effects, and host-local implementation details in the domain package that owns them. 4: 5: ## Package Boundary 6: 7: - Preserve the dependency direction: `@opencode-ai/schema <- @opencode-ai/protocol <- @opencode-ai/server`. 8: - Schema values should be serializable contract definitions, not service implementations or runtime registries. 9: - A domain may keep a minimal public wire contract here when SDK generation needs it, but do not move the broader runtime model into Schema just because an event is public. `plugin.added` is the current example: Schema may own the minimum browser-safe event payload, while plugin runtime behavior stays outside Schema. ...
<path>/tmp/opencode/session-recovery-v23-review/packages/opencode/AGENTS.md</path>
<type>file</type>
<content>
1: # opencode database guide
2:
3: ## Database
4:
5: - **Schema**: Drizzle schema lives in `packages/core/src/**/*.sql.ts`.
6: - **Migrations**: database migrations live in `packages/core` and are applied by core.
7:
8: ## Development server
9:
10: - Running `bun dev` from `packages/opencode` starts the live interactive TUI. Do not run it as a blocking foreground command when you need to inspect the result.
11: - Start it in `tmux` instead: `tmux new-session -d -s opencode-dev 'bun dev'`.
12: - Capture the current TUI output with: `tmux capture-pane -pt opencode-dev`.
13: - Stop the session explicitly when done: `tmux kill-session -t opencode-dev`.
14:
15: # Module shape
16:
17: Do not use `export namespace Foo { ... }` for module organization. It is not
18: standard ESM, it prevents tree-shaking, and it breaks Node's native TypeScript
19: runner. ...
<path>/tmp/opencode/session-recovery-v23-review/packages/opencode/src/server/routes/instance/httpapi/AGENTS.md</path>
<type>file</type>
<content>
1: # HttpApi Route Patterns
2:
3: Use `HttpApiBuilder.group(...)` for normal HTTP endpoints, including streaming HTTP responses such as server-sent events. Handlers should yield stable services once while building the handler layer, then close over those services in endpoint implementations.
4:
5: ```ts
6: export const sessionHandlers = HttpApiBuilder.group(InstanceHttpApi, "session", (handlers) =>
7: Effect.gen(function* () {
8: const session = yield* Session.Service
9:
10: return handlers.handle("list", () => session.list())
11: }),
12: )
13: ```
14:
15: For SSE endpoints, stay in `HttpApiBuilder.group(...)` and return `HttpServerResponse.stream(...)` from the handler. Annotate the endpoint success schema with `HttpApiSchema.asText({ contentType: "text/event-stream" })` so OpenAPI documents the stream content type. ...
<path>/tmp/opencode/session-recovery-v23-review/packages/core/src/database/schema.gen.ts</path>
<type>file</type>
<content>
1: import { Effect } from "effect"
2: import type { DatabaseMigration } from "./migration"
3:
4: export default {
5: up(tx) {
6: return Effect.gen(function* () {
7: yield* tx.run(`
8: CREATE TABLE \`workspace\` (
9: \`id\` text PRIMARY KEY,
10: \`type\` text NOT NULL,
11: \`name\` text DEFAULT '' NOT NULL,
12: \`branch\` text,
13: \`directory\` text,
14: \`extra\` text,
15: \`project_id\` text NOT NULL,
16: \`time_used\` integer NOT NULL,
17: CONSTRAINT \`fk_workspace_project_id_project_id_fk\` FOREIGN KEY (\`project_id\`) REFERENCES \`project\`(\`id\`) ON DELETE CASCADE
18: );
19: `)
20: yield* tx.run(`
21: CREATE TABLE \`data_migration\` (
22: \`name\` text PRIMARY KEY,
23: \`time_completed\` integer NOT ...
<path>/tmp/opencode/session-recovery-v23-review/packages/core/src/database/migration/20260622202450_simplify_session_input.ts</path>
<type>file</type>
<content>
1: import { Effect } from "effect"
2: import type { DatabaseMigration } from "../migration"
3:
4: export default {
5: id: "20260622202450_simplify_session_input",
6: up(tx) {
7: return Effect.gen(function* () {
8: yield* tx.run(`DELETE FROM \`session_context_epoch\`;`)
9: yield* tx.run(`DELETE FROM \`session_input\`;`)
10: yield* tx.run(`DELETE FROM \`session_message\`;`)
11: yield* tx.run(`DELETE FROM \`event\`;`)
12: yield* tx.run(`DELETE FROM \`event_sequence\`;`)
13: yield* tx.run(`UPDATE \`session\` SET \`workspace_id\` = NULL WHERE \`workspace_id\` IS NOT NULL;`)
14: yield* tx.run(`DELETE FROM \`workspace\`;`)
15: })
16: },
17: } satisfies DatabaseMigration.Migration
(End of file - total 17 lines)
</content>
<path>/tmp/opencode/session-recovery-v23-review/packages/core/src/session/recovery.ts</path> <type>file</type> <content> 260: and( 261: eq(SessionMessageTable.session_id, claim.session_id), 262: eq(SessionMessageTable.type, "assistant"), 263: ), 264: ) 265: .orderBy(desc(SessionMessageTable.seq)) 266: .limit(1) 267: .get() 268: .pipe(Effect.orDie) 269: if (latest !== undefined && latest.seq > claim.assistant_seq) 270: return yield* Effect.die(new SupersededExecution()) 271: } 272: if ( 273: phase.value === "ready" && 274: claim.assistant_message_id === null && 275: (yield* hasPendingExecutionIntent(db, claim.session_id, claim.id)) 276: ...
No files found
Found 2 matches
/tmp/opencode/session-recovery-v23-review/packages/core/test/session-execution-local.test.ts:
Line 116: it.effect("owns cleanup when interruption arrives after claim commit", () =>
Line 122: afterClaimed: Deferred.succeed(claimed, undefined).pipe(Effect.andThen(Deferred.await(releaseClaim))),
14035d7631ba25b820fdc553087469935f447af034d549e2f14f8a141eda59dc /tmp/opencode/session-recovery-final-v23.patch b944e38aea927633f92ec37241bd69b1e977eec8bd5d829b57dbfbae9867e579 /home/byk/Code/opencode/packages/opencode/dist/server/opencode-server ab9408c81cc9916177641ae8e9f08624fc27b5b9 ab9408c81cc9916177641ae8e9f08624fc27b5b9 M packages/client/src/generated/types.ts M packages/core/schema.json M packages/core/src/database/migration.gen.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/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 ...
MUST-FIX — Explicit resumes registered while the coordinator is stopping are lost. packages/core/src/session/run-coordinator.ts:81 waits on entry.done with Effect.andThen(run(key)). Interruption completes that deferred with the old owner’s failed exit at packages/core/src/session/run-coordinator.ts:128. The failure prevents andThen from calling run(key), so the promised successor never starts. Await the old exit without propagating it, then retry run(key).
MUST-FIX — A successful claim-clear race makes interruption fail with SessionExecutionClaim.Lost. A successful drain deletes its durable claim at packages/core/src/session/execution/local.ts:116-118, but leaves it registered in activeClaims until packages/core/src/session/execution/local.ts:141-148. An interrupt in that window finds the stale registration and attempts the cancelling transition at packages/core/src/session/execution/local.ts:263-268. That transition defects because the claim is already gone. The Lost reconciliation at packages/core/src/session/execution/local.ts:248-261 covers cleanup only, not this pre-interrupt transition, so a successful settlement can still surface an interruption failure.
MUST-FIX — The frozen SEA changed during review. /home/byk/Code/opencode/packages/opencode/dist/server/opencode-server initially matched the required SHA-256 f875987afa4336956b9f33e14eee6de0a4af90e2bc6de899cccb7cbe5a5df998; the final immutable-input check produced b944e38aea927633f92ec37241bd69b1e977eec8bd5d829b57dbfbae9867e579. The reviewed artifact set is therefore no longer frozen.
ab9408c81cc9916177641ae8e9f08624fc27b5b9.14035d7631ba25b820fdc553087469935f447af034d549e2f14f8a141eda59dc.Date: Sep 17, 2026 * 🔴 (10:03) User stated the session-recovery invariant: “never resume an older assistant projection”; a newer turn supersedes stale incomplete rows. * 🟡 (10:02) User supplied the `createLLMEventPublisher` implementation for review. It lazily creates an assistant message, tracks text and tool state by event/call ID, publishes text/tool lifecycle events, settles tool outputs, a…
Date: Sep 17, 2026 * 🔴 (10:02) User directed: “Replace local ownership with durable multi-node ownership when clustered.” * 🟡 (10:02) User supplied the session-input implementation for read-only review. Visible APIs and fields include `admit`, `isRecoveryInput`, `find`, `SessionInputTable.wake_pending`, `SessionRecoveryTable.continuation_message_id`, and `SessionMessage.ID`. * 🟡 (10:02) Sessio…
Date: Sep 17, 2026 * 🟡 (10:01) User supplied `packages/core/src/session/recovery.ts` for the ongoing read-only review; visible imports include `SessionProjector` from `./projector` and `SessionRecoveryTable`. * 🟡 (10:01) `packages/core/src/session/recovery.ts` defines `hasPendingExecutionIntent` via `Effect.fn("SessionRecovery.hasPendingExecutionIntent")`. * 🟡 (10:01) Recovery logic decodes pe…
Date: Sep 17, 2026 * 🔴 [requested-review] (10:00) User requested a strict READ-ONLY correctness/adversarial review of frozen v23 at `/tmp/opencode/session-recovery-v23-review`, with findings first, exact `file:line`, each finding labeled `MUST-FIX` or `CONCERN`, and the response ending exactly `MERGE` or `DO-NOT-MERGE`. * 🔴 [enforced-workflow] (10:00) User prohibited editing files, running test…