Dashboard › opencode › Session 1Grj0ALDVezJ
1Grj0ALDVezJhbS4BPerform a read-only independent security/pentest review of the exact frozen candidate. Base commit: ab9408c81cc9916177641ae8e9f08624fc27b5b9. Patch path: /tmp/opencode/session-recovery-final-v9.patch. Expected patch SHA-256: d525a720dae01d40d14301b9bd1fa7ca726dda77c142de332f74d9f3b5f5e15e. Expected SEA artifact: /home/byk/Code/opencode/packages/opencode/dist/server/opencode-server with SHA-256 edf38112295131282cb05d7f2d657417e38a40e3e19125d80c02056ee5b367f3. Do not mutate files, refs, index, services, or run builds/tests. Verify hashes and inspect all 33 changed files against immutable base. Threat-model malicious/corrupt durable rows/events, cross-Session identifiers, stale owners, multi-node races, replay, cancellation, external provider/tool side effects, queue/steer leakage, public retries, wake amplification/starvation, migration constraints, and fail-open error handling. Explicitly test by inspection these former blockers: Step.Recovered execution-ID collision across Sessions must abort atomically; projection failure after lease expiry must quarantine the exact execution/owner or prove ownership transferred; startAssistant must not mark in-memory active state before durable Step.Started succeeds; cancellation must never be recovered or start overlapping provider/tool work, including expired cancelling claims; live leases/expired acquisition/uncertain re-entry invariants; continuation reservation and shared validation; admission-at-recovery-boundary; hosted-tool reconciliation before continuation; provider stream failure after step-finish; bounded fairness and durable replay wake intent. Evidence already run on exact source: 1167 Core tests, recovery suite 230 tests, five typechecks, schema manifest, migration consistency, diff checks; isolated exact SEA health/schema/restart/idempotence smoke. Return findings ordered by severity with exact HEAD-after-patch file:line evidence. ...
d525a720dae01d40d14301b9bd1fa7ca726dda77c142de332f74d9f3b5f5e15e /tmp/opencode/session-recovery-final-v9.patch edf38112295131282cb05d7f2d657417e38a40e3e19125d80c02056ee5b367f3 /home/byk/Code/opencode/packages/opencode/dist/server/opencode-server
<path>/home/byk/Code/opencode</path> <type>directory</type> <entries> .dockerignore .editorconfig .git/ .gitattributes .github/ .gitignore .gitleaksignore .husky/ .lore.md .node-cache/ .opencode/ .oxlintrc.json .prettierignore .turbo/ .vscode/ .zed/ AGENTS.md artifacts/ bun.lock bunfig.toml CONTEXT.md CONTRIBUTING.md flake.lock flake.nix github/ infra/ install LICENSE nix/ node_modules/ package.json packages/ patches/ perf.data perf.data.old perf/ pnpm-lock.yaml pnpm-workspace.yaml README.ar.md README.bn.md README.br.md README.bs.md README.da.md README.de.md README.es.md README.fr.md README.gr.md README.it.md README.ja.md README.ko.md README.md README.no.md README.pl.md README.ru.md README.th.md README.tr.md README.uk.md README.vi.md README.zh.md README.zht.md screenshot-uk.png script/ sdks/ SECURITY.md specs/ sst-env.d.ts sst.config.ts STATS.md tmp/ tsconfig.json turbo.json (71 entries) </entries>
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 packages/core/src/session/sql.ts M packages/core/test/database-migration.test.ts M ...
(no output)
<path>/tmp/opencode/session-recovery-final-v9.patch</path>
<type>file</type>
<content>
1: diff --git a/packages/core/schema.json b/packages/core/schema.json
2: index d0eeeebd5c..86f650e83d 100644
3: --- a/packages/core/schema.json
4: +++ b/packages/core/schema.json
5: @@ -1,8 +1,10 @@
6: {
7: "version": "7",
8: "dialect": "sqlite",
9: - "id": "f14a9b18-8207-487e-a3d3-227e629ba9ad",
10: - "prevIds": ["169a0f0f-d58f-479f-b024-fa1c7b9a09db"],
11: + "id": "9e445a5f-9a7b-4d00-97f6-f80fee3c9383",
12: + "prevIds": [
13: + "682548a8-b895-4f9b-a6af-fdd4b14a5fc9"
14: + ],
15: "ddl": [
16: {
17: "name": "workspace",
18: @@ -60,6 +62,10 @@
19: "name": "session_context_epoch",
20: "entityType": "tables"
21: },
22: + {
23: + "name": "session_execution",
24: + "entityType": "tables"
25: + },
26: {
27: "name": "session_input",
28: "entityType": "tables"
29: @@ -68,6 +74,10 @@
30: "name": "session_message",
31: ...
paths=33 mismatches=0 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 packages/core/test/session-runne...
/home/byk/Code/opencode/packages/opencode/AGENTS.md /home/byk/Code/opencode/packages/codemode/AGENTS.md /home/byk/Code/opencode/packages/session-ui/AGENTS.md /home/byk/Code/opencode/packages/schema/AGENTS.md /home/byk/Code/opencode/packages/stats/AGENTS.md /home/byk/Code/opencode/packages/effect-drizzle-sqlite/AGENTS.md /home/byk/Code/opencode/packages/opencode/test/AGENTS.md /home/byk/Code/opencode/packages/opencode/test/server/AGENTS.md /home/byk/Code/opencode/packages/ui/AGENTS.md /home/byk/Code/opencode/packages/llm/AGENTS.md /home/byk/Code/opencode/packages/opencode/src/session/llm/AGENTS.md /home/byk/Code/opencode/packages/opencode/src/server/routes/instance/httpapi/AGENTS.md /home/byk/Code/opencode/packages/core/src/tool/AGENTS.md /home/byk/Code/opencode/packages/desktop/AGENTS.md /home/byk/Code/opencode/packages/app/AGENTS.md /home/byk/Code/opencode/packages/app/e2e/AGENTS.md /home/byk/Code/opencode/packages/app/e2e/performance/AGENTS.md
<path>/home/byk/Code/opencode/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>/home/byk/Code/opencode/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 issue`](https://github.com/anomalyco/opencode/issues?q=is%3Aissue%20state%3Aopen%20label%3A%22good%20first%20issue%22) 19: - ...
<path>/home/byk/Code/opencode/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>/home/byk/Code/opencode/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>/home/byk/Code/opencode/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>/home/byk/Code/opencode/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": "./src/database/sqlite.bun.ts",
28: ...
<path>/home/byk/Code/opencode/packages/schema/package.json</path>
<type>file</type>
<content>
1: {
2: "$schema": "https://json.schemastore.org/package.json",
3: "name": "@opencode-ai/schema",
4: "private": true,
5: "type": "module",
6: "license": "MIT",
7: "exports": {
8: ".": "./src/index.ts",
9: "./*": "./src/*.ts"
10: },
11: "scripts": {
12: "typecheck": "tsgo --noEmit"
13: },
14: "dependencies": {
15: "effect": "catalog:"
16: },
17: "devDependencies": {
18: "@tsconfig/bun": "catalog:",
19: "@types/bun": "catalog:",
20: "@typescript/native-preview": "catalog:"
21: }
22: }
(End of file - total 22 lines)
</content>
<system-reminder>
Instructions from: /home/byk/Code/opencode/packages/schema/AGENTS.md
# Schema Package Guide
`@opencode-ai/schema` owns browser-safe wire and storage contracts shared by protocol, server, core, and generated SDKs. ...
<path>/home/byk/Code/opencode/packages/server/package.json</path>
<type>file</type>
<content>
1: {
2: "$schema": "https://json.schemastore.org/package.json",
3: "name": "@opencode-ai/server",
4: "version": "1.18.30",
5: "private": true,
6: "type": "module",
7: "license": "MIT",
8: "exports": {
9: "./*": "./src/*.ts"
10: },
11: "scripts": {
12: "typecheck": "tsgo --noEmit"
13: },
14: "dependencies": {
15: "@opencode-ai/core": "workspace:*",
16: "@opencode-ai/protocol": "workspace:*",
17: "drizzle-orm": "catalog:",
18: "effect": "catalog:"
19: },
20: "devDependencies": {
21: "@tsconfig/bun": "catalog:",
22: "@types/bun": "catalog:",
23: "@typescript/native-preview": "catalog:"
24: }
25: }
(End of file - total 25 lines)
</content>
<path>/home/byk/Code/opencode/packages/opencode/package.json</path>
<type>file</type>
<content>
1: {
2: "$schema": "https://json.schemastore.org/package.json",
3: "version": "1.18.30",
4: "name": "opencode",
5: "type": "module",
6: "license": "MIT",
7: "private": true,
8: "scripts": {
9: "typecheck": "tsgo --noEmit",
10: "test": "bun test --timeout 30000 --only-failures",
11: "test:httpapi": "bun run script/httpapi-exercise.ts --mode coverage --fail-on-missing --fail-on-skip && bun run script/httpapi-exercise.ts --mode auth --fail-on-missing --fail-on-skip && bun run script/httpapi-exercise.ts --mode effect --fail-on-missing --fail-on-skip",
12: "bench:test": "bun run script/bench-test-suite.ts",
13: "profile:test": "bun run script/profile-test-files.ts",
14: "build": "bun run script/build.ts",
15: "build:server": "node script/build-server.mjs",
16: "dev": "bun run ./src/index.ts",
17: "dev:temporary": "bun run ./src/temporary.ts"
18: ...
Found 100 matches (more matches available)
/home/byk/Code/opencode/packages/core/src/session/recovery-id.ts:
Line 6: export const continuation = (executionID: string) => SessionMessage.ID.make(`msg_recovery_continue_${executionID}`)
/home/byk/Code/opencode/packages/core/src/session/recovery.ts:
Line 11: import { SessionExecutionClaim } from "./execution/claim"
Line 25: const Phase = Schema.Literals(["ready", "safe", "unknown", "continue", "cancelling"])
Line 39: eq(SessionRecoveryTable.continuation_message_id, SessionInputTable.id),
Line 46: and(isNull(SessionRecoveryTable.execution_id), eq(SessionInputTable.wake_pending, true)),
Line 48: eq(SessionRecoveryTable.wake_pending, true),
Line 69: const claims = yield* db
Line 72: .where(and(lte(SessionExecutionTable.expires_at, scanTime), isNull(SessionExecutionTable.recovery_error)))
Line 78: claims,
Line 79: (claim) =>
Line 84: .set({ owner_id: ownerID, ...
<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<Pick<typeof SessionExecutionTable.$inferInsert, "assistant_message_id" | "phase">>
18:
19: export class Lost extends Error {
20: constructor(readonly claim: Claim) {
21: super(`Session execution claim lost: ${claim.executionID}`)
22: }
23: }
24:
25: const where = (claim: Claim, now: number) =>
26: and(
27: ...
<path>/home/byk/Code/opencode/packages/core/src/session/execution/local.ts</path>
<type>file</type>
<content>
1: import { and, asc, 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 { SESSION_EXECUTION_LEASE_MS, SessionExecutionTable, SessionRecoveryTable } from "../sql"
14:
15: /** Current-process routing for implicit-local Locations. Future remote placement belongs here. ...
<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 { SessionSchema } from "./schema"
14: import {
15: MAX_WAKE_ATTEMPTS,
16: SESSION_EXECUTION_LEASE_MS,
17: SessionExecutionTable,
18: SessionInputTable,
19: SessionRecoveryTable,
20: SessionMessageTable,
21: SessionTable,
22: } from "./sql"
23:
24: export ...
<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: ...
No files found
/home/byk/Code/opencode/packages/core/src/event.ts
<path>/home/byk/Code/opencode/packages/core/src/event.ts</path>
<type>file</type>
<content>
1: export * as EventV2 from "./event"
2:
3: import { Cause, Context, Effect, Layer, Option, PubSub, Queue, Schema, Stream } from "effect"
4: import { Event } from "@opencode-ai/schema/event"
5: import type { Data, Definition, Payload } from "@opencode-ai/schema/event"
6: import { and, asc, eq, gt, inArray } from "drizzle-orm"
7: import { Database } from "./database/database"
8: import { EventSequenceTable, EventTable } from "./event/sql"
9: import { Location } from "./location"
10: import { makeGlobalNode } from "./effect/app-node"
11: import { isDeepStrictEqual } from "node:util"
12: import { Durable } from "@opencode-ai/schema/durable-event-manifest"
13:
14: export const ID = Event.ID
15: export type ID = import("@opencode-ai/schema/event").ID
16: export type { Data, Definition, Payload } from "@opencode-ai/schema/event"
17:
18: export type Subscriber<D extends Definition = Definition> = ...
<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 = ...
<path>/home/byk/Code/opencode/packages/core/src/session/input.ts</path>
<type>file</type>
<content>
561: export const promoteExact = Effect.fn("SessionInput.promoteExact")(function* (
562: db: DatabaseService,
563: events: EventV2.Interface,
564: sessionID: SessionSchema.ID,
565: messageID: SessionMessage.ID,
566: commit: (row: typeof SessionInputTable.$inferSelect) => Effect.Effect<void>,
567: ) {
568: const row = yield* db
569: .select()
570: .from(SessionInputTable)
571: .where(
572: and(
573: eq(SessionInputTable.id, messageID),
574: eq(SessionInputTable.session_id, sessionID),
575: isNull(SessionInputTable.promoted_seq),
576: eq(SessionInputTable.delivery, "queue"),
577: ),
578: )
579: .get()
580: .pipe(Effect.orDie)
581: if (!row) return yield* Effect.die(`Pending recovery input not found: ${messageID}`)
582: yield* publish(db, events, sessionID, [row], commit).pipe(
583: ...
<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/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 20 matches
/home/byk/Code/opencode/packages/core/src/database/schema.gen.ts:
Line 158: CREATE TABLE \`session_execution\` (
Line 167: CONSTRAINT \`session_execution_pk\` PRIMARY KEY(\`id\`),
Line 168: CONSTRAINT \`fk_session_execution_session_id_session_id_fk\` FOREIGN KEY (\`session_id\`) REFERENCES \`session\`(\`id\`) ON DELETE CASCADE,
Line 169: CONSTRAINT "session_execution_phase_check" CHECK("phase" IN ('ready', 'safe', 'unknown', 'continue', 'cancelling'))
Line 180: \`wake_pending\` integer DEFAULT false NOT NULL,
Line 198: CREATE TABLE \`session_recovery\` (
Line 204: \`wake_pending\` integer DEFAULT true NOT NULL,
Line 205: \`wake_attempts\` integer DEFAULT 0 NOT NULL,
Line 208: CONSTRAINT \`session_recovery_pk\` PRIMARY KEY(\`execution_id\`),
Line 209: CONSTRAINT \`fk_session_recovery_session_id_session_id_fk\` FOREIGN KEY (\`session_id\`) ...
<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/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/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) => 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/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 ...
<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/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/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 ...
<path>/home/byk/Code/opencode/packages/opencode/src/server/routes/instance/httpapi/server.ts</path>
<type>file</type>
<content>
241: EventV2Bridge.node,
242: SessionRunState.node,
243: SessionProcessor.node,
244: SessionCompaction.node,
245: SessionRevert.node,
246: SessionSummary.node,
247: SessionPrompt.node,
248: Instruction.node,
249: LLM.node,
250: LSP.node,
251: MCP.node,
252: McpAuth.node,
253: Command.node,
254: Truncate.node,
255: ToolRegistry.node,
256: Format.node,
257: Project.node,
258: Vcs.node,
259: Workspace.node,
260: Worktree.node,
261: Installation.node,
262: ShareNext.node,
263: SessionShare.node,
264: InstanceStore.node,
265: httpClient,
266: EventV2.node,
267: ProjectV2.node,
268: ProjectCopy.node,
269: PtyTicket.node,
270: ])
271:
272: export function createRoutes(
273: corsOptions?: CorsOptions,
274: ): Layer.Layer<never, EffectConfig.ConfigError, RouteRequirements> {
275: const locationServiceMapV2 ...
Found 63 matches
/home/byk/Code/opencode/packages/server/src/handlers/permission.ts:
Line 31: sessionID: ctx.params.sessionID,
Line 44: sessionID: error.sessionID,
Line 45: message: `Session not found: ${error.sessionID}`,
Line 56: return { data: yield* permission.forSession(ctx.params.sessionID) }
Line 63: if (!request || request.sessionID !== ctx.params.sessionID) return yield* missingRequest(ctx.params.requestID)
Line 72: if (!request || request.sessionID !== ctx.params.sessionID) return yield* missingRequest(ctx.params.requestID)
/home/byk/Code/opencode/packages/server/src/handlers/message.ts:
Line 43: sessionID: ctx.params.sessionID,
Line 52: sessionID: error.sessionID,
Line 53: message: `Session not found: ${error.sessionID}`,
Line 60: Effect.annotateLogs({ ref, sessionID: error.sessionID, ...
<path>/home/byk/Code/opencode/packages/server/src/middleware/session-location.ts</path>
<type>file</type>
<content>
1: import { Database } from "@opencode-ai/core/database/database"
2: import { LocationServiceMap } from "@opencode-ai/core/location-services"
3: import { Location } from "@opencode-ai/core/location"
4: import { AbsolutePath } from "@opencode-ai/core/schema"
5: import { SessionV2 } from "@opencode-ai/core/session"
6: import { SessionTable } from "@opencode-ai/core/session/sql"
7: import { WorkspaceV2 } from "@opencode-ai/core/workspace"
8: import { eq } from "drizzle-orm"
9: import { Effect, Layer, Schema } from "effect"
10: import { HttpRouter } from "effect/unstable/http"
11: import { HttpApiMiddleware } from "effect/unstable/httpapi"
12: import { InvalidRequestError, SessionNotFoundError } from "@opencode-ai/protocol/errors"
13: import type { LocationServices } from "../location"
14:
15: export class SessionLocationMiddleware extends HttpApiMiddleware.Service<
16: ...
<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/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/src/event.ts</path>
<type>file</type>
<content>
369: function publishEvent<D extends Definition>(definition: D, event: Payload<D>, commit?: PublishOptions["commit"]) {
370: return Effect.gen(function* () {
371: if (!definition?.durable && commit)
372: return yield* Effect.die(
373: new InvalidDurableEventError({
374: type: event.type,
375: message: "Local commit hooks require a durable event",
376: }),
377: )
378: if (definition?.durable) {
379: const committed = yield* commitDurableEvent(definition, event as Payload, undefined, commit)
380: if (committed) {
381: event = {
382: ...event,
383: durable: {
384: aggregateID: committed.aggregateID,
385: seq: committed.seq,
386: version: ...
<path>/home/byk/Code/opencode/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. ...
Found 20 matches
/home/byk/Code/opencode/packages/core/test/session-projector.test.ts:
Line 41: const it = testEffect(AppNodeBuilder.build(LayerNode.group([Database.node, EventV2.node, SessionProjector.node])))
Line 602: SessionInput.admit(db, events, {
Line 659: SessionInput.admit(db, events, {
Line 671: SessionInput.admit(db, events, {
Line 759: SessionInput.admit(db, events, {
Line 825: yield* SessionInput.admit(db, events, {
Line 949: yield* SessionInput.admit(db, events, {
Line 991: yield* SessionInput.admit(db, events, {
Line 1121: ? SessionInput.admit(db, events, {
Line 1311: const retried = yield* SessionInput.admit(db, events, {
Line 1347: yield* SessionInput.admit(db, events, {
Line 1528: yield* SessionInput.admit(db, events, {
Line 1769: SessionInput.admit(db, events, {
Line 1870: yield* SessionInput.admit(db, events, {
Line ...
Found 100 matches (more matches available)
/home/byk/Code/opencode/packages/core/test/session-runner-recorded.test.ts:
Line 132: it.effect("executes one recorded V2 prompt through the recorded HTTP transport", () =>
/home/byk/Code/opencode/packages/core/test/session-execution-local.test.ts:
Line 43: it.effect("clears the claim after a successful drain", () =>
Line 52: it.effect("preserves the claim when its scope closes", () =>
Line 68: it.effect("clears the claim after explicit interruption", () =>
Line 82: it.effect("never starts a second owner while the lease is live", () =>
Line 105: it.effect("never overwrites an expired lease", () =>
Line 132: it.effect("never re-enters its own uncertain live lease", () =>
Line 159: it.effect("renews heartbeat expiry from the current clock", () =>
Line 182: it.effect("never revives an expired claim on heartbeat", () =>
Line 200: it.effect("settles cancellation before starting a pending ...
Found 96 matches
/home/byk/Code/opencode/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 definitions from chronological V2 user ...
<path>/home/byk/Code/opencode/packages/core/test/session-projector.test.ts</path>
<type>file</type>
<content>
68: it.effect("atomically reconciles one abandoned execution into one continuation", () =>
69: Effect.gen(function* () {
70: const { db } = yield* Database.Service
71: const events = yield* EventV2.Service
72: const assistantID = SessionMessage.ID.make("msg_recovery_assistant")
73: const continuationID = continuation("execution")
74: yield* db
75: .insert(ProjectTable)
76: .values({ id: Project.ID.global, worktree: AbsolutePath.make("/project"), sandboxes: [] })
77: .run()
78: yield* db
79: .insert(SessionTable)
80: .values({
81: id: sessionID,
82: project_id: Project.ID.global,
83: slug: "test",
84: directory: "/project",
85: title: "test",
86: version: "test",
87: })
88: .run()
89: yield* db
90: ...
<path>/home/byk/Code/opencode/packages/core/test/session-projector.test.ts</path>
<type>file</type>
<content>
1086: it.effect("never recovers a pre-promotion claim when input commits at the recovery boundary", () =>
1087: Effect.gen(function* () {
1088: const { db } = yield* Database.Service
1089: const events = yield* EventV2.Service
1090: yield* db
1091: .insert(ProjectTable)
1092: .values({ id: Project.ID.global, worktree: AbsolutePath.make("/project"), sandboxes: [] })
1093: .run()
1094: yield* db
1095: .insert(SessionTable)
1096: .values({
1097: id: sessionID,
1098: project_id: Project.ID.global,
1099: slug: "test",
1100: directory: "/project",
1101: title: "test",
1102: version: "test",
1103: })
1104: .run()
1105: yield* db
1106: .insert(SessionExecutionTable)
1107: .values({
1108: id: ...
<path>/home/byk/Code/opencode/packages/core/test/session-projector.test.ts</path>
<type>file</type>
<content>
1545: it.effect("quarantines a malformed claim without blocking a valid claim", () =>
1546: Effect.gen(function* () {
1547: const { db } = yield* Database.Service
1548: const validSession = SessionV2.ID.make("ses_recovery_valid")
1549: yield* db
1550: .insert(ProjectTable)
1551: .values({ id: Project.ID.global, worktree: AbsolutePath.make("/project"), sandboxes: [] })
1552: .run()
1553: yield* db
1554: .insert(SessionTable)
1555: .values(
1556: [sessionID, validSession].map((id) => ({
1557: id,
1558: project_id: Project.ID.global,
1559: slug: id,
1560: directory: "/project",
1561: title: "test",
1562: version: "test",
1563: })),
1564: )
1565: .run()
1566: yield* db.run(sql`PRAGMA ...
<path>/home/byk/Code/opencode/packages/core/test/session-projector.test.ts</path>
<type>file</type>
<content>
1850: it.effect("rolls back promotion and Context Epoch mutation after ownership loss", () =>
1851: Effect.gen(function* () {
1852: const { db } = yield* Database.Service
1853: const events = yield* EventV2.Service
1854: const inputID = SessionMessage.ID.make("msg_fenced_input")
1855: yield* db
1856: .insert(ProjectTable)
1857: .values({ id: Project.ID.global, worktree: AbsolutePath.make("/project"), sandboxes: [] })
1858: .run()
1859: yield* db
1860: .insert(SessionTable)
1861: .values({
1862: id: sessionID,
1863: project_id: Project.ID.global,
1864: slug: "test",
1865: directory: "/project",
1866: title: "test",
1867: version: "test",
1868: })
1869: .run()
1870: yield* SessionInput.admit(db, events, {
1871: 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 ...
<path>/home/byk/Code/opencode/packages/core/test/session-runner.test.ts</path>
<type>file</type>
<content>
619: it.effect("redrives only the synthetic recovery continuation", () =>
620: Effect.gen(function* () {
621: yield* setup
622: const session = yield* SessionV2.Service
623: const events = yield* EventV2.Service
624: const executionService = yield* SessionExecution.Service
625: const unrelatedID = SessionMessage.ID.make("msg_recovery_unrelated")
626: yield* session.prompt({
627: id: unrelatedID,
628: sessionID,
629: prompt: Prompt.make({ text: "unrelated admit-only" }),
630: delivery: "queue",
631: resume: false,
632: })
633: yield* events.publish(SessionEvent.Step.Recovered, {
634: sessionID,
635: timestamp: DateTime.makeUnsafe(1),
636: executionID: "lost-recovery-wake",
637: phase: "ready",
638: })
639: requests.length = 0
640: response ...
<path>/home/byk/Code/opencode/packages/core/test/session-runner.test.ts</path>
<type>file</type>
<content>
1917: it.effect("continues with reloaded history after durably settling one local tool call", () =>
1918: Effect.gen(function* () {
1919: yield* setup
1920: const session = yield* SessionV2.Service
1921: yield* session.prompt({ sessionID, prompt: Prompt.make({ text: "Echo this" }), resume: false })
1922:
1923: requests.length = 0
1924: authorizations.length = 0
1925: executions.length = 0
1926: streamGate = undefined
1927: streamStarted = undefined
1928: responses = [
1929: [
1930: LLMEvent.stepStart({ index: 0 }),
1931: LLMEvent.toolCall({ id: "call-echo", name: "echo", input: { text: "hello" } }),
1932: LLMEvent.stepFinish({ index: 0, reason: "tool-calls" }),
1933: LLMEvent.finish({ reason: "tool-calls" }),
1934: ],
1935: [
1936: ...
Found 29 matches
/home/byk/Code/opencode/packages/core/test/session-prompt.test.ts:
Line 140: it.effect("exposes the execution registry", () =>
Line 147: it.effect("delegates execution continuation through SessionExecution", () =>
Line 159: it.effect("delegates process-local interruption through SessionExecution", () =>
Line 171: it.effect("delegates interruption without requiring a recorded Session", () =>
Line 181: it.effect("durably admits one user message before transcript promotion", () =>
Line 203: it.effect("resolves attachment MIME before admission", () =>
Line 224: it.effect("streams durable Session events after an aggregate sequence", () =>
Line 254: it.effect("resumes through a recorded message without appending another prompt", () =>
Line 275: it.effect("records distinct messages when the ID is omitted", () =>
Line 290: it.effect("returns the original recorded message when the ID is retried", () =>
Line 310: ...
Found 20 matches
/home/byk/Code/opencode/packages/core/test/database-migration.test.ts:
Line 43: test("defaults missing workspace names while preserving legacy workspace data", async () => {
Line 75: test("imports unnamed legacy Drizzle journal entries by their actual migration timestamps", async () => {
Line 92: test("rejects unknown legacy Drizzle journal timestamps instead of guessing completed migrations", async () => {
Line 105: test("serializes concurrent embedded initialization for one database path", async () => {
Line 118: test("declared schema has no ungenerated migrations", async () => {
Line 127: test("applies tracked migrations to an empty database", async () => {
Line 166: test("adds final recovery ownership tables to a populated predecessor", async () => {
Line 230: test("rejects a non-empty database without a session table", async () => {
Line 242: test("backfills existing Context Epoch rows to the build agent", async () => ...
<path>/home/byk/Code/opencode/packages/core/test/database-migration.test.ts</path>
<type>file</type>
<content>
112: layers.map((layer) => Effect.scoped(Layer.build(layer))),
113: { concurrency: "unbounded" },
114: ),
115: )
116: })
117: if (process.platform === "linux") {
118: test("declared schema has no ungenerated migrations", async () => {
119: const result = await $`bun ${fileURLToPath(new URL("../script/migration.ts", import.meta.url))} --check`
120: .quiet()
121: .nothrow()
122: expect(result.exitCode, result.stderr.toString()).toBe(0)
123: expect(result.stdout.toString()).toContain("No schema changes, nothing to migrate")
124: }, 30_000)
125: }
126:
127: test("applies tracked migrations to an empty database", async () => {
128: await run(
129: Effect.gen(function* () {
130: const db = yield* makeDb
131: yield* DatabaseMigration.apply(db)
132:
133: expect(yield* ...
<path>/home/byk/Code/opencode/packages/core/src/database/schema.gen.ts</path> <type>file</type> <content> 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: CREATE TABLE \`session_context_epoch\` ( 150: \`session_id\` text PRIMARY KEY, 151: \`baseline\` text NOT NULL, 152: \`snapshot\` text NOT NULL, 153: \`baseline_seq\` integer NOT NULL, 154: CONSTRAINT \`fk_session_context_epoch_session_id_session_id_fk\` FOREIGN KEY (\`session_id\`) REFERENCES \`session\`(\`id\`) ON DELETE CASCADE 155: ); 156: `) 157: yield* tx.run(` 158: ...
<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>
No files found
Found 5 matches
/home/byk/Code/opencode/packages/core/test/session-runner-tool-events.test.ts:
Line 92: test("local tool success serializes media base64 once and reconstructs from structured content", async () => {
Line 115: test("provider-executed success retains its compatibility result", async () => {
Line 123: test("binary failure emits no success event", async () => {
Line 139: test("old success event data containing result still decodes", () => {
Line 168: test("step finish records settlement without publishing step ended", async () => {
<path>/home/byk/Code/opencode/packages/core/test/session-runner-tool-events.test.ts</path>
<type>file</type>
<content>
150: mime: "image/png",
151: },
152: ],
153: result: {
154: type: "content",
155: value: [
156: {
157: type: "file",
158: uri: `data:image/png;base64,${base64}`,
159: mime: "image/png",
160: },
161: ],
162: },
163: provider: { executed: false },
164: })
165: expect(decoded.result).toMatchObject({ type: "content" })
166: })
167:
168: test("step finish records settlement without publishing step ended", async () => {
169: const { published, publisher } = capture()
170: await Effect.runPromise(publisher.publish(LLMEvent.stepStart({ index: 0 })))
171: await Effect.runPromise(publisher.publish(LLMEvent.stepFinish({ index: 0, reason: "stop" })))
172:
173: expect(published.some((event) => event.type === "session.next.step.ended.2")).toBe(false)
174: ...
<path>/home/byk/Code/opencode/packages/core/test/session-runner-recorded.test.ts</path>
<type>file</type>
<content>
110: Snapshot.node,
111: SessionRunnerLLM.node,
112: SessionV2.node,
113: ]),
114: [
115: [LayerNodePlatform.llmClient, client],
116: [PermissionV2.node, permission],
117: [ToolOutputStore.node, ToolOutputStore.nodeWithoutConfig],
118: [SessionRunnerModel.node, models],
119: [SystemContextRegistry.node, systemContext],
120: [Location.node, Location.boundNode({ directory: AbsolutePath.make("/project") })],
121: [SkillGuidance.node, skillGuidance],
122: [ReferenceGuidance.node, referenceGuidance],
123: [Config.node, config],
124: [Snapshot.node, Snapshot.noopLayer],
125: [SessionExecution.node, execution],
126: ],
127: ),
128: )
129: const sessionID = SessionV2.ID.make("ses_runner_recorded")
130:
131: describe("SessionRunnerLLM recorded", () => {
132: it.effect("executes ...
<path>/home/byk/Code/opencode/packages/schema/test/event-manifest.test.ts</path>
<type>file</type>
<content>
1: import { describe, expect, test } from "bun:test"
2: import { FileSystem, Integration, Permission, Project, Reference, Session, Workspace } from "../src"
3: import { EventManifest } from "../src/event-manifest"
4: import { IdeEvent } from "../src/ide-event"
5: import { SessionEvent } from "../src/session-event"
6: import { SessionTodo } from "../src/session-todo"
7: import { SessionV1 } from "../src/session-v1"
8: import { WorkspaceEvent } from "../src/workspace-event"
9:
10: describe("public event manifest", () => {
11: test("owns the complete public event surface", () => {
12: expect(EventManifest.ServerDefinitions.length).toBe(61)
13: expect(EventManifest.Definitions.length).toBe(91)
14: expect(SessionV1.Event.Definitions).toEqual([
15: SessionV1.Event.Created,
16: SessionV1.Event.Updated,
17: SessionV1.Event.Deleted,
18: ...
Found 54 matches
/home/byk/Code/opencode/packages/sdk/js/src/v2/gen/types.gen.ts:
Line 24: | EventSessionNextPromptExecutionRequested
Line 874: requestExecution?: boolean
Line 879: type: "session.next.prompt.execution_requested"
Line 983: type: "session.next.step.recovered"
Line 987: executionID: string
Line 989: phase: "ready" | "unknown" | "continue"
Line 1650: | SyncEventSessionNextPromptExecutionRequested
Line 2785: | SessionNextPromptExecutionRequested
Line 2915: | SessionNextPromptExecutionRequested
Line 3430: requestExecution?: boolean
Line 3435: export type SyncEventSessionNextPromptExecutionRequested = {
Line 3439: type: "session.next.prompt.execution_requested.1"
Line 3606: type: "session.next.step.recovered.1"
Line 3613: executionID: string
Line 3615: phase: "ready" | "unknown" | "continue"
Line 4362: requestExecution?: boolean
Line 4366: ...
<path>/home/byk/Code/opencode/packages/sdk/js/src/v2/gen/types.gen.ts</path>
<type>file</type>
<content>
850: location: LocationRef
851: subdirectory?: string
852: }
853: }
854: | {
855: id: string
856: type: "session.next.prompted"
857: properties: {
858: timestamp: number
859: sessionID: string
860: messageID: string
861: prompt: Prompt
862: delivery: "steer" | "queue"
863: }
864: }
865: | {
866: id: string
867: type: "session.next.prompt.admitted"
868: properties: {
869: timestamp: number
870: sessionID: string
871: messageID: string
872: prompt: Prompt
873: delivery: "steer" | "queue"
874: requestExecution?: boolean
875: }
876: }
877: | {
878: id: string
879: type: "session.next.prompt.execution_requested"
880: properties: {
881: ...
Found 12 matches /home/byk/Code/opencode/packages/core/schema.json: Line 1229: "name": "wake_attempts", Line 1549: "name": "wake_attempts", Line 1859: "name": "fk_session_recovery_session_id_session_id_fk", Line 1874: "name": "fk_session_recovery_assistant_message_id_session_message_id_fk", Line 1889: "name": "fk_session_recovery_continuation_message_id_session_input_id_fk", Line 2256: "name": "session_execution_session_idx", Line 2459: "value": "wake_attempts", Line 2536: "name": "session_execution_phase_check", Line 2541: "value": "\"wake_attempts\" >= 0 AND \"wake_attempts\" <= 9007199254740991", Line 2542: "name": "session_recovery_wake_attempts_check", Line 2547: "value": "\"wake_attempts\" >= 0 AND \"wake_attempts\" <= 9007199254740991", Line 2548: "name": "session_wake_attempts_check",
Found 51 matches
/home/byk/Code/opencode/packages/core/test/session-runner.test.ts:
Line 416: yield* events.replayAll(
/home/byk/Code/opencode/packages/core/test/session-projector.test.ts:
Line 160: yield* events.replayAll(
Line 199: yield* events.replayAll(
/home/byk/Code/opencode/packages/core/test/session-prompt.test.ts:
Line 115: yield* events.replayAll(
Line 415: yield* events.replay({
/home/byk/Code/opencode/packages/core/test/session-create.test.ts:
Line 258: expect(yield* events.replayAll(serialized.slice(0, 2))).toBe(created.id)
Line 268: expect(yield* events.replayAll(serialized.slice(2))).toBe(created.id)
/home/byk/Code/opencode/packages/core/test/event.test.ts:
Line 551: yield* events.replay({
Line 570: yield* events.replay({
Line 606: .replay({
Line 639: yield* events.replay({
Line 647: .replay({
Line 671: yield* events.replay({
Line 687: ...
Found 1 matches /home/byk/Code/opencode/packages/core/test/session-projector.test.ts: Line 1715: .where(eq(SessionExecutionTable.recovery_error, "Recovery projection failed"))
Found 14 matches
/home/byk/Code/opencode/packages/server/src/api.ts:
Line 3: import { SessionLocationMiddleware } from "./middleware/session-location"
Line 7: sessionLocationMiddleware: SessionLocationMiddleware,
/home/byk/Code/opencode/packages/server/src/middleware/session-location.ts:
Line 15: export class SessionLocationMiddleware extends HttpApiMiddleware.Service<
Line 16: SessionLocationMiddleware,
Line 25: SessionLocationMiddleware,
Line 30: return SessionLocationMiddleware.of((effect) =>
/home/byk/Code/opencode/packages/server/src/middleware/authorization.ts:
Line 3: import { Authorization } from "@opencode-ai/protocol/middleware/authorization"
Line 4: export { Authorization } from "@opencode-ai/protocol/middleware/authorization"
Line 39: Authorization,
Line 42: if (!ServerAuth.required(config)) return Authorization.of((effect) => effect)
Line 43: return Authorization.of((effect) ...
<path>/home/byk/Code/opencode/packages/server/src/api.ts</path>
<type>file</type>
<content>
1: import { makeDefaultApi } from "@opencode-ai/protocol/api"
2: import { LocationMiddleware } from "./location"
3: import { SessionLocationMiddleware } from "./middleware/session-location"
4:
5: export const Api = makeDefaultApi({
6: locationMiddleware: LocationMiddleware,
7: sessionLocationMiddleware: SessionLocationMiddleware,
8: })
(End of file - total 8 lines)
</content>
<path>/home/byk/Code/opencode/packages/server/src/middleware/authorization.ts</path>
<type>file</type>
<content>
1: import { ServerAuth } from "../auth"
2: import { UnauthorizedError } from "@opencode-ai/protocol/errors"
3: import { Authorization } from "@opencode-ai/protocol/middleware/authorization"
4: export { Authorization } from "@opencode-ai/protocol/middleware/authorization"
5: import { hasPtyConnectTicketURL } from "@opencode-ai/protocol/groups/pty"
6: import { Effect, Encoding, Layer, Redacted } from "effect"
7: import { HttpEffect, HttpServerRequest, HttpServerResponse } from "effect/unstable/http"
8:
9: const AUTH_TOKEN_QUERY = "auth_token"
10: const WWW_AUTHENTICATE = 'Basic realm="Secure Area"'
11:
12: function emptyCredential() {
13: return { username: "", password: Redacted.make("") }
14: }
15:
16: function decodeCredential(input: string) {
17: return Effect.fromResult(Encoding.decodeBase64String(input)).pipe(
18: Effect.match({
19: onFailure: ...
<path>/home/byk/Code/opencode/packages/sdk/openapi.json</path>
<type>file</type>
<content>
18260: },
18261: "sessionID": {
18262: "type": "string",
18263: "pattern": "^ses"
18264: },
18265: "assistantMessageID": {
18266: "type": "string",
18267: "pattern": "^msg_"
18268: },
18269: "error": {
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: ...
<path>/home/byk/Code/opencode/packages/core/test/session-prompt.test.ts</path>
<type>file</type>
<content>
275: it.effect("records distinct messages when the ID is omitted", () =>
276: Effect.gen(function* () {
277: yield* setup
278: const session = yield* SessionV2.Service
279: const input = { sessionID, prompt: Prompt.make({ text: "Fix the failing tests" }), resume: false }
280:
281: const first = yield* session.prompt(input)
282: const second = yield* session.prompt(input)
283:
284: expect(second.id).not.toBe(first.id)
285: expect(yield* session.messages({ sessionID })).toEqual([])
286: expect(yield* admittedCount).toBe(2)
287: }),
288: )
289:
290: it.effect("returns the original recorded message when the ID is retried", () =>
291: Effect.gen(function* () {
292: yield* setup
293: const session = yield* SessionV2.Service
294: const input = {
295: sessionID,
296: id: messageID,
297: ...
d525a720dae01d40d14301b9bd1fa7ca726dda77c142de332f74d9f3b5f5e15e /tmp/opencode/session-recovery-final-v9.patch edf38112295131282cb05d7f2d657417e38a40e3e19125d80c02056ee5b367f3 /home/byk/Code/opencode/packages/opencode/dist/server/opencode-server ab9408c81cc9916177641ae8e9f08624fc27b5b9 verified_paths=33 mismatches=0
ab9408c81cc9916177641ae8e9f08624fc27b5b9d525a720dae01d40d14301b9bd1fa7ca726dda77c142de332f74d9f3b5f5e15eedf38112295131282cb05d7f2d657417e38a40e3e19125d80c02056ee5b367f3repo-setup skill was unavailable; I read the applicable AGENTS.md, CONTRIBUTING.md, and package manifests directly.A corrupt or malicious session_recovery row can share the expired claim’s Session and execution ID while differing in phase, assistant ID, or continuation ID.
The projector correctly detects the mismatch and aborts at packages/core/src/session/projector.ts:403-423. Because durable projection runs in the event transaction, the attempted event, synthetic message, continuation input, and claim deletion roll back atomically.
The recovery error path then searches only by Session and execution ID:
packages/core/src/session/recovery.ts:186-194If any such row exists, it returns without validating the stored identity:
packages/core/src/session/recovery.ts:197-199That skips both required outcomes:
(sessionID, executionID, ownerID) claim;The claim remains in session_execution. Ordinary acquisition uses insert-on-conflict and returns without running:
packages/core/src/session/execution/local.ts:31-45After the renewed lease expires, the background scanner retries:
packages/core/src/session/recovery.ts:63-76