Compare commits

...
8 Commits
41 changed files with 2652 additions and 2640 deletions

No files matched your search

+13 -12
View File
@@ -195,7 +195,7 @@
"solid-js": "catalog:",
},
"peerDependencies": {
"effect": "4.0.0-rc.118",
"effect": "catalog:",
"solid-js": ">=1.9.0",
},
"optionalPeers": [
@@ -558,7 +558,7 @@
"name": "@opencode/http-recorder",
"version": "2.0.26",
"dependencies": {
"@effect/platform-node-shared": "4.0.0-rc.118",
"@effect/platform-node-shared": "catalog:",
},
"devDependencies": {
"@effect/platform-node": "catalog:",
@@ -577,6 +577,7 @@
"name": "@opencode/httpapi-codegen",
"version": "2.0.26",
"dependencies": {
"@opencode/schema": "workspace:*",
"effect": "catalog:",
"prettier": "3.6.2",
},
@@ -1150,10 +1151,10 @@
"catalog": {
"@cloudflare/workers-types": "4.20251008.0",
"@corvu/drawer": "0.2.4",
"@effect/opentelemetry": "4.0.0-rc.118",
"@effect/platform-node": "4.0.0-rc.118",
"@effect/platform-node-shared": "4.0.0-rc.118",
"@effect/sql-sqlite-bun": "4.0.0-rc.118",
"@effect/opentelemetry": "4.0.1",
"@effect/platform-node": "4.0.1",
"@effect/platform-node-shared": "4.0.1",
"@effect/sql-sqlite-bun": "4.0.1",
"@hono/standard-validator": "0.2.0",
"@hono/zod-validator": "0.4.2",
"@kobalte/core": "0.13.13",
@@ -1193,7 +1194,7 @@
"dompurify": "3.4.14",
"drizzle-kit": "1.0.0-rc.5-ab785fc",
"drizzle-orm": "1.0.0-rc.5-169397b",
"effect": "4.0.0-rc.118",
"effect": "4.0.1",
"fast-check": "4.9.0",
"fuzzysort": "3.1.0",
"get-east-asian-width": "1.6.0",
@@ -1732,13 +1733,13 @@
"@drizzle-team/brocli": ["@drizzle-team/brocli@0.12.0", "", {}, "sha512-mlUE+rZ8CatQekLhnaiN91Iemdd+e2gFKooGlnRB3oPTL3VghLfX24dx7HrzMNeC1JrIB/0kpsfyty3f5HNfxQ=="],
"@effect/opentelemetry": ["@effect/opentelemetry@4.0.0-rc.118", "", { "peerDependencies": { "@opentelemetry/api": ">=1.9.0 <2.0.0", "@opentelemetry/api-logs": ">=0.203.0 <0.300.0", "@opentelemetry/resources": ">=2.0.0 <3.0.0", "@opentelemetry/sdk-logs": ">=0.203.0 <0.300.0", "@opentelemetry/sdk-metrics": ">=2.0.0 <3.0.0", "@opentelemetry/sdk-trace-base": ">=2.0.0 <3.0.0", "@opentelemetry/sdk-trace-node": ">=2.0.0 <3.0.0", "@opentelemetry/sdk-trace-web": ">=2.0.0 <3.0.0", "@opentelemetry/semantic-conventions": ">=1.33.0 <2.0.0", "effect": "^4.0.0-rc.118" }, "optionalPeers": ["@opentelemetry/api", "@opentelemetry/api-logs", "@opentelemetry/resources", "@opentelemetry/sdk-logs", "@opentelemetry/sdk-metrics", "@opentelemetry/sdk-trace-base", "@opentelemetry/sdk-trace-node", "@opentelemetry/sdk-trace-web"] }, "sha512-N5dvEeCj1W/9zgBvyyp/GucOKOEJdV7QNirWp+4g/axFKTB/cfV2gx/ZhMDUb69HzlyRmOelNvKEmB3RA0PdVw=="],
"@effect/opentelemetry": ["@effect/opentelemetry@4.0.1", "", { "peerDependencies": { "@opentelemetry/api": ">=1.9.0 <2.0.0", "@opentelemetry/api-logs": ">=0.203.0 <0.300.0", "@opentelemetry/resources": ">=2.0.0 <3.0.0", "@opentelemetry/sdk-logs": ">=0.203.0 <0.300.0", "@opentelemetry/sdk-metrics": ">=2.0.0 <3.0.0", "@opentelemetry/sdk-trace-base": ">=2.0.0 <3.0.0", "@opentelemetry/sdk-trace-node": ">=2.0.0 <3.0.0", "@opentelemetry/sdk-trace-web": ">=2.0.0 <3.0.0", "@opentelemetry/semantic-conventions": ">=1.33.0 <2.0.0", "effect": "^4.0.1" }, "optionalPeers": ["@opentelemetry/api", "@opentelemetry/api-logs", "@opentelemetry/resources", "@opentelemetry/sdk-logs", "@opentelemetry/sdk-metrics", "@opentelemetry/sdk-trace-base", "@opentelemetry/sdk-trace-node", "@opentelemetry/sdk-trace-web"] }, "sha512-MZ7M1a1dxMqTqeNwIGSECjO7RrReEgeEwHo8BnbOqP+8IfVpdiJi/iPCmkFVWlAxanMl4qhsq69e0Hkul9t+bA=="],
"@effect/platform-node": ["@effect/platform-node@4.0.0-rc.118", "", { "dependencies": { "@effect/platform-node-shared": "^4.0.0-rc.118", "undici": "^8.11.2" }, "peerDependencies": { "effect": "^4.0.0-rc.118", "redis": ">=5.0.0 <7.0.0" } }, "sha512-qdAxPZ+5bKxVnzkwziqcHZTHRHz2hyfFX6NhwEmm75CBpmaIzXIZR2LRqGd1/8eI3J3cOrXcAYzByhln7T1/EA=="],
"@effect/platform-node": ["@effect/platform-node@4.0.1", "", { "dependencies": { "@effect/platform-node-shared": "^4.0.1", "undici": "^8.11.2" }, "peerDependencies": { "effect": "^4.0.1", "redis": ">=5.0.0 <7.0.0" } }, "sha512-FT0Fu5LO0/XP9zBpj0HqrtJNLluK4StNKqf6TSulUsjp8FPBsDVXGJiDuyoN5J2yVMT7tgvhxSwaDcObWVRIaQ=="],
"@effect/platform-node-shared": ["@effect/platform-node-shared@4.0.0-rc.118", "", { "dependencies": { "@types/ws": "^8.18.1", "ws": "^8.22.0" }, "peerDependencies": { "effect": "^4.0.0-rc.118" } }, "sha512-pNbmIlxbAUxAthUNsp2xm1NLG9kxoYecsPkoYl9mNF2oxPcKDxAvkOar7tYnLSUpXJeATm4pxYVipdZjQfqO4Q=="],
"@effect/platform-node-shared": ["@effect/platform-node-shared@4.0.1", "", { "dependencies": { "@types/ws": "^8.18.1", "ws": "^8.22.0" }, "peerDependencies": { "effect": "^4.0.1" } }, "sha512-VanaejudEhKJ4mpmqnEzdncVUhN6sGSO9ZDND54mRxAlZxj+4dYAWjDTYAy9o4tJo9aALeP2U8cVcOFzEdSeLg=="],
"@effect/sql-sqlite-bun": ["@effect/sql-sqlite-bun@4.0.0-rc.118", "", { "peerDependencies": { "effect": "^4.0.0-rc.118" } }, "sha512-UF0oVOK7mQvEwpxySR9VTk5YoP5luRI//Z8NMOJKVG/SbZbsORGACd7Np+KZRiXXjgzSXEpfGb7Gs3G1cKfUCg=="],
"@effect/sql-sqlite-bun": ["@effect/sql-sqlite-bun@4.0.1", "", { "peerDependencies": { "effect": "^4.0.1" } }, "sha512-cBP2gD4KRuci02W1t/jzbrsk9spjiy45d7Z5i95nAnYaUXjU4JFgLa9Dxbumg5NUgzoK7qOdIeO0fULxEhK0LA=="],
"@electron-internal/extract-zip": ["@electron-internal/extract-zip@1.0.5", "", {}, "sha512-+bqFCP98pLI0Tt0XQo1TmlXtwjWchISndDOxCkEcIuUgXWpBnLyRI+2DU+mesvnMMX6L1XDqYNA0lXNDHd/yiA=="],
@@ -3910,7 +3911,7 @@
"editorconfig": ["editorconfig@1.0.7", "", { "dependencies": { "@one-ini/wasm": "0.1.1", "commander": "^10.0.0", "minimatch": "^9.0.1", "semver": "^7.5.3" }, "bin": { "editorconfig": "bin/editorconfig" } }, "sha512-e0GOtq/aTQhVdNyDU9e02+wz9oDDM+SIOQxWME2QRjzRX5yyLAuHDE+0aE8vHb9XRC8XD37eO2u57+F09JqFhw=="],
"effect": ["effect@4.0.0-rc.118", "", {}, "sha512-hxhpCd+swzrtu9lnyPpEFre2ODQzJ9qxgyL1oHIEY8NKnW4PxTbM1XzplMZXiAsLD62HO+KJc41Nqxr9T791ZQ=="],
"effect": ["effect@4.0.1", "", {}, "sha512-b1VlQG9g8fwxE5QnIZuPoOP/0MsqHJSRKxUijjoM80E5q95FXrX5yWtY5XI8G+GJsBQAVSDbLS458z9a++uVvw=="],
"ejs": ["ejs@3.1.10", "", { "dependencies": { "jake": "^10.8.5" }, "bin": { "ejs": "bin/cli.js" } }, "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA=="],
+5 -5
View File
@@ -43,10 +43,10 @@
"packages/stats/*"
],
"catalog": {
"@effect/opentelemetry": "4.0.0-rc.118",
"@effect/platform-node": "4.0.0-rc.118",
"@effect/platform-node-shared": "4.0.0-rc.118",
"@effect/sql-sqlite-bun": "4.0.0-rc.118",
"@effect/opentelemetry": "4.0.1",
"@effect/platform-node": "4.0.1",
"@effect/platform-node-shared": "4.0.1",
"@effect/sql-sqlite-bun": "4.0.1",
"@npmcli/arborist": "9.4.0",
"@types/bun": "1.4.0",
"@types/cross-spawn": "6.0.6",
@@ -80,7 +80,7 @@
"dompurify": "3.4.14",
"drizzle-kit": "1.0.0-rc.5-ab785fc",
"drizzle-orm": "1.0.0-rc.5-169397b",
"effect": "4.0.0-rc.118",
"effect": "4.0.1",
"fast-check": "4.9.0",
"ai": "6.0.168",
"cross-spawn": "7.0.6",
+1 -1
View File
@@ -37,7 +37,7 @@
"@opencode/protocol": "workspace:*"
},
"peerDependencies": {
"effect": "4.0.0-rc.118",
"effect": "catalog:",
"solid-js": ">=1.9.0"
},
"peerDependenciesMeta": {
+10
View File
@@ -10,7 +10,12 @@ import { EventLog } from "@opencode/schema/event-log"
import { FileDiff } from "@opencode/schema/file-diff"
import { FileSystem } from "@opencode/schema/filesystem"
import { Form } from "@opencode/schema/form"
import { SessionsCursor } from "@opencode/protocol/groups/session"
import { Instruction } from "@opencode/schema/instruction"
import { InstructionEntry } from "@opencode/schema/instruction-entry"
import { Money } from "@opencode/schema/money"
import { Snapshot } from "@opencode/schema/snapshot"
import { Workspace } from "@opencode/schema/workspace"
import { Integration } from "@opencode/schema/integration"
import { Location } from "@opencode/schema/location"
import { Mcp } from "@opencode/schema/mcp"
@@ -50,7 +55,12 @@ const effectTypeReferences = [
...namespaceTypes("FileDiff", "@opencode/schema/file-diff", FileDiff),
...namespaceTypes("FileSystem", "@opencode/schema/filesystem", FileSystem),
...namespaceTypes("Form", "@opencode/schema/form", Form),
...namespaceTypes("Instruction", "@opencode/schema/instruction", Instruction),
...namespaceTypes("InstructionEntry", "@opencode/schema/instruction-entry", InstructionEntry),
...namespaceTypes("Money", "@opencode/schema/money", Money),
...namespaceTypes("Snapshot", "@opencode/schema/snapshot", Snapshot),
...namespaceTypes("Workspace", "@opencode/schema/workspace", Workspace),
typeReference("SessionsCursor", "@opencode/protocol/groups/session", SessionsCursor),
...namespaceTypes("Integration", "@opencode/schema/integration", Integration),
typeReference("Location.PublicRef", "@opencode/schema/location", Location.PublicRef),
typeReference("Location.PublicInfo", "@opencode/schema/location", Location.PublicInfo),
+66 -208
View File
@@ -7,7 +7,8 @@ import type { Session } from "@opencode/schema/session"
import type { AbsolutePath } from "@opencode/schema/schema"
import type { Project } from "@opencode/schema/project"
import type { RelativePath } from "@opencode/schema/schema"
import type { Brand } from "effect"
import type { SessionsCursor } from "@opencode/protocol/groups/session"
import type { Money } from "@opencode/schema/money"
import type { Model } from "@opencode/schema/model"
import type { DateTime } from "effect"
import type { Permission } from "@opencode/schema/permission"
@@ -21,6 +22,9 @@ import type { InstructionEntry } from "@opencode/schema/instruction-entry"
import type { Schema } from "effect"
import type { Event } from "@opencode/schema/event"
import type { EventLog } from "@opencode/schema/event-log"
import type { Workspace } from "@opencode/schema/workspace"
import type { Instruction } from "@opencode/schema/instruction"
import type { Snapshot } from "@opencode/schema/snapshot"
import type { Shell } from "@opencode/schema/shell"
import type { Provider } from "@opencode/schema/provider"
import type { Form } from "@opencode/schema/form"
@@ -121,14 +125,11 @@ export type SessionListInput = {
readonly directory?: AbsolutePath | undefined
readonly project?: Project.ID | undefined
readonly subpath?: RelativePath | undefined
readonly cursor?: (string & Brand.Brand<"SessionsCursor">) | undefined
readonly cursor?: SessionsCursor | undefined
}
export type SessionListOutput = {
readonly data: ReadonlyArray<Session.Info>
readonly cursor: {
readonly previous?: (string & Brand.Brand<"SessionsCursor">) | undefined
readonly next?: (string & Brand.Brand<"SessionsCursor">) | undefined
}
readonly cursor: { readonly previous?: SessionsCursor | undefined; readonly next?: SessionsCursor | undefined }
}
export type SessionListOperation<E = never> = (input?: SessionListInput) => Effect.Effect<SessionListOutput, E>
@@ -151,7 +152,7 @@ export type SessionStatsOutput = {
readonly reasoning: number
readonly cache: { readonly read: number; readonly write: number }
}
readonly cost: number & Brand.Brand<"Money.USD">
readonly cost: Money.USD
readonly tools:
| { readonly mode: "none" }
| {
@@ -192,7 +193,7 @@ export type SessionStatsOutput = {
readonly reasoning: number
readonly cache: { readonly read: number; readonly write: number }
}
readonly cost: number & Brand.Brand<"Money.USD">
readonly cost: Money.USD
}>
}
export type SessionStatsOperation<E = never> = (input?: SessionStatsInput) => Effect.Effect<SessionStatsOutput, E>
@@ -433,18 +434,12 @@ export type SessionLogOutput =
readonly type: "session.created"
readonly durable: { readonly aggregateID: string; readonly seq: Event.Seq; readonly version: Event.Version }
readonly location?:
| {
readonly directory: AbsolutePath
readonly workspaceID?: (string & Brand.Brand<"Workspace.ID">) | undefined
}
| { readonly directory: AbsolutePath; readonly workspaceID?: Workspace.ID | undefined }
| undefined
readonly data: {
readonly sessionID: Session.ID
readonly projectID: Project.ID
readonly location: {
readonly directory: AbsolutePath
readonly workspaceID?: (string & Brand.Brand<"Workspace.ID">) | undefined
}
readonly location: { readonly directory: AbsolutePath; readonly workspaceID?: Workspace.ID | undefined }
readonly subpath?: RelativePath | undefined
readonly parentID?: Session.ID | undefined
readonly slug: string
@@ -463,10 +458,7 @@ export type SessionLogOutput =
readonly type: "session.agent.selected"
readonly durable: { readonly aggregateID: string; readonly seq: Event.Seq; readonly version: Event.Version }
readonly location?:
| {
readonly directory: AbsolutePath
readonly workspaceID?: (string & Brand.Brand<"Workspace.ID">) | undefined
}
| { readonly directory: AbsolutePath; readonly workspaceID?: Workspace.ID | undefined }
| undefined
readonly data: {
readonly sessionID: Session.ID
@@ -481,10 +473,7 @@ export type SessionLogOutput =
readonly type: "session.model.selected"
readonly durable: { readonly aggregateID: string; readonly seq: Event.Seq; readonly version: Event.Version }
readonly location?:
| {
readonly directory: AbsolutePath
readonly workspaceID?: (string & Brand.Brand<"Workspace.ID">) | undefined
}
| { readonly directory: AbsolutePath; readonly workspaceID?: Workspace.ID | undefined }
| undefined
readonly data: {
readonly sessionID: Session.ID
@@ -499,17 +488,11 @@ export type SessionLogOutput =
readonly type: "session.moved"
readonly durable: { readonly aggregateID: string; readonly seq: Event.Seq; readonly version: Event.Version }
readonly location?:
| {
readonly directory: AbsolutePath
readonly workspaceID?: (string & Brand.Brand<"Workspace.ID">) | undefined
}
| { readonly directory: AbsolutePath; readonly workspaceID?: Workspace.ID | undefined }
| undefined
readonly data: {
readonly sessionID: Session.ID
readonly location: {
readonly directory: AbsolutePath
readonly workspaceID?: (string & Brand.Brand<"Workspace.ID">) | undefined
}
readonly location: { readonly directory: AbsolutePath; readonly workspaceID?: Workspace.ID | undefined }
readonly projectID: Project.ID
readonly subpath?: RelativePath | undefined
}
@@ -521,10 +504,7 @@ export type SessionLogOutput =
readonly type: "session.renamed"
readonly durable: { readonly aggregateID: string; readonly seq: Event.Seq; readonly version: Event.Version }
readonly location?:
| {
readonly directory: AbsolutePath
readonly workspaceID?: (string & Brand.Brand<"Workspace.ID">) | undefined
}
| { readonly directory: AbsolutePath; readonly workspaceID?: Workspace.ID | undefined }
| undefined
readonly data: { readonly sessionID: Session.ID; readonly title: string }
}
@@ -535,10 +515,7 @@ export type SessionLogOutput =
readonly type: "session.metadata.updated"
readonly durable: { readonly aggregateID: string; readonly seq: Event.Seq; readonly version: Event.Version }
readonly location?:
| {
readonly directory: AbsolutePath
readonly workspaceID?: (string & Brand.Brand<"Workspace.ID">) | undefined
}
| { readonly directory: AbsolutePath; readonly workspaceID?: Workspace.ID | undefined }
| undefined
readonly data: { readonly sessionID: Session.ID; readonly metadata: Session.Metadata }
}
@@ -549,10 +526,7 @@ export type SessionLogOutput =
readonly type: "session.permissions"
readonly durable: { readonly aggregateID: string; readonly seq: Event.Seq; readonly version: Event.Version }
readonly location?:
| {
readonly directory: AbsolutePath
readonly workspaceID?: (string & Brand.Brand<"Workspace.ID">) | undefined
}
| { readonly directory: AbsolutePath; readonly workspaceID?: Workspace.ID | undefined }
| undefined
readonly data: { readonly sessionID: Session.ID; readonly permissions: Permission.Ruleset }
}
@@ -563,10 +537,7 @@ export type SessionLogOutput =
readonly type: "session.viewed"
readonly durable: { readonly aggregateID: string; readonly seq: Event.Seq; readonly version: Event.Version }
readonly location?:
| {
readonly directory: AbsolutePath
readonly workspaceID?: (string & Brand.Brand<"Workspace.ID">) | undefined
}
| { readonly directory: AbsolutePath; readonly workspaceID?: Workspace.ID | undefined }
| undefined
readonly data: { readonly sessionID: Session.ID; readonly idle: number }
}
@@ -577,10 +548,7 @@ export type SessionLogOutput =
readonly type: "session.deleted"
readonly durable: { readonly aggregateID: string; readonly seq: Event.Seq; readonly version: Event.Version }
readonly location?:
| {
readonly directory: AbsolutePath
readonly workspaceID?: (string & Brand.Brand<"Workspace.ID">) | undefined
}
| { readonly directory: AbsolutePath; readonly workspaceID?: Workspace.ID | undefined }
| undefined
readonly data: { readonly sessionID: Session.ID }
}
@@ -591,18 +559,13 @@ export type SessionLogOutput =
readonly type: "session.forked"
readonly durable: { readonly aggregateID: string; readonly seq: Event.Seq; readonly version: Event.Version }
readonly location?:
| {
readonly directory: AbsolutePath
readonly workspaceID?: (string & Brand.Brand<"Workspace.ID">) | undefined
}
| { readonly directory: AbsolutePath; readonly workspaceID?: Workspace.ID | undefined }
| undefined
readonly data: {
readonly sessionID: Session.ID
readonly parentID: Session.ID
readonly boundary: Session.ForkBoundary
readonly instructions?:
| { readonly [x: string & Brand.Brand<"Instruction.Key">]: string & Brand.Brand<"Instruction.Hash"> }
| undefined
readonly instructions?: { readonly [x: Instruction.Key]: Instruction.Hash } | undefined
readonly instructionEntries?: InstructionEntry.Snapshot | undefined
}
}
@@ -613,10 +576,7 @@ export type SessionLogOutput =
readonly type: "session.inbox.delivered"
readonly durable: { readonly aggregateID: string; readonly seq: Event.Seq; readonly version: Event.Version }
readonly location?:
| {
readonly directory: AbsolutePath
readonly workspaceID?: (string & Brand.Brand<"Workspace.ID">) | undefined
}
| { readonly directory: AbsolutePath; readonly workspaceID?: Workspace.ID | undefined }
| undefined
readonly data: { readonly sessionID: Session.ID; readonly inboxID: SessionMessage.ID }
}
@@ -627,10 +587,7 @@ export type SessionLogOutput =
readonly type: "session.inbox.enqueued"
readonly durable: { readonly aggregateID: string; readonly seq: Event.Seq; readonly version: Event.Version }
readonly location?:
| {
readonly directory: AbsolutePath
readonly workspaceID?: (string & Brand.Brand<"Workspace.ID">) | undefined
}
| { readonly directory: AbsolutePath; readonly workspaceID?: Workspace.ID | undefined }
| undefined
readonly data: {
readonly sessionID: Session.ID
@@ -645,10 +602,7 @@ export type SessionLogOutput =
readonly type: "session.inbox.cancelled"
readonly durable: { readonly aggregateID: string; readonly seq: Event.Seq; readonly version: Event.Version }
readonly location?:
| {
readonly directory: AbsolutePath
readonly workspaceID?: (string & Brand.Brand<"Workspace.ID">) | undefined
}
| { readonly directory: AbsolutePath; readonly workspaceID?: Workspace.ID | undefined }
| undefined
readonly data: { readonly sessionID: Session.ID; readonly inboxID: SessionMessage.ID }
}
@@ -659,10 +613,7 @@ export type SessionLogOutput =
readonly type: "session.inbox.delivery.changed"
readonly durable: { readonly aggregateID: string; readonly seq: Event.Seq; readonly version: Event.Version }
readonly location?:
| {
readonly directory: AbsolutePath
readonly workspaceID?: (string & Brand.Brand<"Workspace.ID">) | undefined
}
| { readonly directory: AbsolutePath; readonly workspaceID?: Workspace.ID | undefined }
| undefined
readonly data: {
readonly sessionID: Session.ID
@@ -677,10 +628,7 @@ export type SessionLogOutput =
readonly type: "session.execution.started"
readonly durable: { readonly aggregateID: string; readonly seq: Event.Seq; readonly version: Event.Version }
readonly location?:
| {
readonly directory: AbsolutePath
readonly workspaceID?: (string & Brand.Brand<"Workspace.ID">) | undefined
}
| { readonly directory: AbsolutePath; readonly workspaceID?: Workspace.ID | undefined }
| undefined
readonly data: { readonly sessionID: Session.ID }
}
@@ -691,10 +639,7 @@ export type SessionLogOutput =
readonly type: "session.execution.succeeded"
readonly durable: { readonly aggregateID: string; readonly seq: Event.Seq; readonly version: Event.Version }
readonly location?:
| {
readonly directory: AbsolutePath
readonly workspaceID?: (string & Brand.Brand<"Workspace.ID">) | undefined
}
| { readonly directory: AbsolutePath; readonly workspaceID?: Workspace.ID | undefined }
| undefined
readonly data: { readonly sessionID: Session.ID }
}
@@ -705,10 +650,7 @@ export type SessionLogOutput =
readonly type: "session.execution.failed"
readonly durable: { readonly aggregateID: string; readonly seq: Event.Seq; readonly version: Event.Version }
readonly location?:
| {
readonly directory: AbsolutePath
readonly workspaceID?: (string & Brand.Brand<"Workspace.ID">) | undefined
}
| { readonly directory: AbsolutePath; readonly workspaceID?: Workspace.ID | undefined }
| undefined
readonly data: {
readonly sessionID: Session.ID
@@ -727,10 +669,7 @@ export type SessionLogOutput =
readonly type: "session.execution.interrupted"
readonly durable: { readonly aggregateID: string; readonly seq: Event.Seq; readonly version: Event.Version }
readonly location?:
| {
readonly directory: AbsolutePath
readonly workspaceID?: (string & Brand.Brand<"Workspace.ID">) | undefined
}
| { readonly directory: AbsolutePath; readonly workspaceID?: Workspace.ID | undefined }
| undefined
readonly data: {
readonly sessionID: Session.ID
@@ -744,14 +683,11 @@ export type SessionLogOutput =
readonly type: "session.instructions.updated"
readonly durable: { readonly aggregateID: string; readonly seq: Event.Seq; readonly version: Event.Version }
readonly location?:
| {
readonly directory: AbsolutePath
readonly workspaceID?: (string & Brand.Brand<"Workspace.ID">) | undefined
}
| { readonly directory: AbsolutePath; readonly workspaceID?: Workspace.ID | undefined }
| undefined
readonly data: {
readonly sessionID: Session.ID
readonly delta: { readonly [x: string]: (string & Brand.Brand<"Instruction.Hash">) | "removed" }
readonly delta: { readonly [x: string]: Instruction.Hash | "removed" }
readonly text?: string | undefined
}
}
@@ -762,10 +698,7 @@ export type SessionLogOutput =
readonly type: "session.synthetic"
readonly durable: { readonly aggregateID: string; readonly seq: Event.Seq; readonly version: Event.Version }
readonly location?:
| {
readonly directory: AbsolutePath
readonly workspaceID?: (string & Brand.Brand<"Workspace.ID">) | undefined
}
| { readonly directory: AbsolutePath; readonly workspaceID?: Workspace.ID | undefined }
| undefined
readonly data: {
readonly sessionID: Session.ID
@@ -781,10 +714,7 @@ export type SessionLogOutput =
readonly type: "session.skill.activated"
readonly durable: { readonly aggregateID: string; readonly seq: Event.Seq; readonly version: Event.Version }
readonly location?:
| {
readonly directory: AbsolutePath
readonly workspaceID?: (string & Brand.Brand<"Workspace.ID">) | undefined
}
| { readonly directory: AbsolutePath; readonly workspaceID?: Workspace.ID | undefined }
| undefined
readonly data: {
readonly sessionID: Session.ID
@@ -800,10 +730,7 @@ export type SessionLogOutput =
readonly type: "session.shell.started"
readonly durable: { readonly aggregateID: string; readonly seq: Event.Seq; readonly version: Event.Version }
readonly location?:
| {
readonly directory: AbsolutePath
readonly workspaceID?: (string & Brand.Brand<"Workspace.ID">) | undefined
}
| { readonly directory: AbsolutePath; readonly workspaceID?: Workspace.ID | undefined }
| undefined
readonly data: { readonly sessionID: Session.ID; readonly shell: Shell.Info }
}
@@ -814,10 +741,7 @@ export type SessionLogOutput =
readonly type: "session.shell.ended"
readonly durable: { readonly aggregateID: string; readonly seq: Event.Seq; readonly version: Event.Version }
readonly location?:
| {
readonly directory: AbsolutePath
readonly workspaceID?: (string & Brand.Brand<"Workspace.ID">) | undefined
}
| { readonly directory: AbsolutePath; readonly workspaceID?: Workspace.ID | undefined }
| undefined
readonly data: {
readonly sessionID: Session.ID
@@ -837,17 +761,14 @@ export type SessionLogOutput =
readonly type: "session.step.started"
readonly durable: { readonly aggregateID: string; readonly seq: Event.Seq; readonly version: Event.Version }
readonly location?:
| {
readonly directory: AbsolutePath
readonly workspaceID?: (string & Brand.Brand<"Workspace.ID">) | undefined
}
| { readonly directory: AbsolutePath; readonly workspaceID?: Workspace.ID | undefined }
| undefined
readonly data: {
readonly sessionID: Session.ID
readonly assistantMessageID: SessionMessage.ID
readonly agent: Agent.ID
readonly model: Model.Ref
readonly snapshot?: (string & Brand.Brand<"Snapshot.ID">) | undefined
readonly snapshot?: Snapshot.ID | undefined
readonly started: number
}
}
@@ -858,10 +779,7 @@ export type SessionLogOutput =
readonly type: "session.step.streamed"
readonly durable: { readonly aggregateID: string; readonly seq: Event.Seq; readonly version: Event.Version }
readonly location?:
| {
readonly directory: AbsolutePath
readonly workspaceID?: (string & Brand.Brand<"Workspace.ID">) | undefined
}
| { readonly directory: AbsolutePath; readonly workspaceID?: Workspace.ID | undefined }
| undefined
readonly data: { readonly sessionID: Session.ID; readonly assistantMessageID: SessionMessage.ID }
}
@@ -872,10 +790,7 @@ export type SessionLogOutput =
readonly type: "session.step.ended"
readonly durable: { readonly aggregateID: string; readonly seq: Event.Seq; readonly version: Event.Version }
readonly location?:
| {
readonly directory: AbsolutePath
readonly workspaceID?: (string & Brand.Brand<"Workspace.ID">) | undefined
}
| { readonly directory: AbsolutePath; readonly workspaceID?: Workspace.ID | undefined }
| undefined
readonly data: {
readonly sessionID: Session.ID
@@ -883,14 +798,14 @@ export type SessionLogOutput =
readonly finish: "stop" | "length" | "tool-calls" | "content-filter" | "error" | "unknown"
readonly rawFinish?: string | undefined
readonly providerState?: SessionMessage.ProviderState | undefined
readonly cost: number & Brand.Brand<"Money.USD">
readonly cost: Money.USD
readonly tokens: {
readonly input: number
readonly output: number
readonly reasoning: number
readonly cache: { readonly read: number; readonly write: number }
}
readonly snapshot?: (string & Brand.Brand<"Snapshot.ID">) | undefined
readonly snapshot?: Snapshot.ID | undefined
readonly files?: ReadonlyArray<RelativePath> | undefined
}
}
@@ -901,10 +816,7 @@ export type SessionLogOutput =
readonly type: "session.step.failed"
readonly durable: { readonly aggregateID: string; readonly seq: Event.Seq; readonly version: Event.Version }
readonly location?:
| {
readonly directory: AbsolutePath
readonly workspaceID?: (string & Brand.Brand<"Workspace.ID">) | undefined
}
| { readonly directory: AbsolutePath; readonly workspaceID?: Workspace.ID | undefined }
| undefined
readonly data: {
readonly sessionID: Session.ID
@@ -918,7 +830,7 @@ export type SessionLogOutput =
readonly finish?: "content-filter" | undefined
readonly rawFinish?: string | undefined
readonly providerState?: SessionMessage.ProviderState | undefined
readonly cost?: (number & Brand.Brand<"Money.USD">) | undefined
readonly cost?: Money.USD | undefined
readonly tokens?:
| {
readonly input: number
@@ -927,7 +839,7 @@ export type SessionLogOutput =
readonly cache: { readonly read: number; readonly write: number }
}
| undefined
readonly snapshot?: (string & Brand.Brand<"Snapshot.ID">) | undefined
readonly snapshot?: Snapshot.ID | undefined
readonly files?: ReadonlyArray<RelativePath> | undefined
}
}
@@ -938,10 +850,7 @@ export type SessionLogOutput =
readonly type: "session.text.started"
readonly durable: { readonly aggregateID: string; readonly seq: Event.Seq; readonly version: Event.Version }
readonly location?:
| {
readonly directory: AbsolutePath
readonly workspaceID?: (string & Brand.Brand<"Workspace.ID">) | undefined
}
| { readonly directory: AbsolutePath; readonly workspaceID?: Workspace.ID | undefined }
| undefined
readonly data: {
readonly sessionID: Session.ID
@@ -956,10 +865,7 @@ export type SessionLogOutput =
readonly type: "session.text.ended"
readonly durable: { readonly aggregateID: string; readonly seq: Event.Seq; readonly version: Event.Version }
readonly location?:
| {
readonly directory: AbsolutePath
readonly workspaceID?: (string & Brand.Brand<"Workspace.ID">) | undefined
}
| { readonly directory: AbsolutePath; readonly workspaceID?: Workspace.ID | undefined }
| undefined
readonly data: {
readonly sessionID: Session.ID
@@ -976,10 +882,7 @@ export type SessionLogOutput =
readonly type: "session.reasoning.started"
readonly durable: { readonly aggregateID: string; readonly seq: Event.Seq; readonly version: Event.Version }
readonly location?:
| {
readonly directory: AbsolutePath
readonly workspaceID?: (string & Brand.Brand<"Workspace.ID">) | undefined
}
| { readonly directory: AbsolutePath; readonly workspaceID?: Workspace.ID | undefined }
| undefined
readonly data: {
readonly sessionID: Session.ID
@@ -995,10 +898,7 @@ export type SessionLogOutput =
readonly type: "session.reasoning.ended"
readonly durable: { readonly aggregateID: string; readonly seq: Event.Seq; readonly version: Event.Version }
readonly location?:
| {
readonly directory: AbsolutePath
readonly workspaceID?: (string & Brand.Brand<"Workspace.ID">) | undefined
}
| { readonly directory: AbsolutePath; readonly workspaceID?: Workspace.ID | undefined }
| undefined
readonly data: {
readonly sessionID: Session.ID
@@ -1015,10 +915,7 @@ export type SessionLogOutput =
readonly type: "session.tool.input.started"
readonly durable: { readonly aggregateID: string; readonly seq: Event.Seq; readonly version: Event.Version }
readonly location?:
| {
readonly directory: AbsolutePath
readonly workspaceID?: (string & Brand.Brand<"Workspace.ID">) | undefined
}
| { readonly directory: AbsolutePath; readonly workspaceID?: Workspace.ID | undefined }
| undefined
readonly data: {
readonly sessionID: Session.ID
@@ -1034,10 +931,7 @@ export type SessionLogOutput =
readonly type: "session.tool.input.ended"
readonly durable: { readonly aggregateID: string; readonly seq: Event.Seq; readonly version: Event.Version }
readonly location?:
| {
readonly directory: AbsolutePath
readonly workspaceID?: (string & Brand.Brand<"Workspace.ID">) | undefined
}
| { readonly directory: AbsolutePath; readonly workspaceID?: Workspace.ID | undefined }
| undefined
readonly data: {
readonly sessionID: Session.ID
@@ -1053,10 +947,7 @@ export type SessionLogOutput =
readonly type: "session.tool.called"
readonly durable: { readonly aggregateID: string; readonly seq: Event.Seq; readonly version: Event.Version }
readonly location?:
| {
readonly directory: AbsolutePath
readonly workspaceID?: (string & Brand.Brand<"Workspace.ID">) | undefined
}
| { readonly directory: AbsolutePath; readonly workspaceID?: Workspace.ID | undefined }
| undefined
readonly data: {
readonly sessionID: Session.ID
@@ -1074,10 +965,7 @@ export type SessionLogOutput =
readonly type: "session.tool.success"
readonly durable: { readonly aggregateID: string; readonly seq: Event.Seq; readonly version: Event.Version }
readonly location?:
| {
readonly directory: AbsolutePath
readonly workspaceID?: (string & Brand.Brand<"Workspace.ID">) | undefined
}
| { readonly directory: AbsolutePath; readonly workspaceID?: Workspace.ID | undefined }
| undefined
readonly data: {
readonly sessionID: Session.ID
@@ -1115,10 +1003,7 @@ export type SessionLogOutput =
readonly type: "session.tool.failed"
readonly durable: { readonly aggregateID: string; readonly seq: Event.Seq; readonly version: Event.Version }
readonly location?:
| {
readonly directory: AbsolutePath
readonly workspaceID?: (string & Brand.Brand<"Workspace.ID">) | undefined
}
| { readonly directory: AbsolutePath; readonly workspaceID?: Workspace.ID | undefined }
| undefined
readonly data: {
readonly sessionID: Session.ID
@@ -1164,10 +1049,7 @@ export type SessionLogOutput =
readonly type: "session.retry.scheduled"
readonly durable: { readonly aggregateID: string; readonly seq: Event.Seq; readonly version: Event.Version }
readonly location?:
| {
readonly directory: AbsolutePath
readonly workspaceID?: (string & Brand.Brand<"Workspace.ID">) | undefined
}
| { readonly directory: AbsolutePath; readonly workspaceID?: Workspace.ID | undefined }
| undefined
readonly data: {
readonly sessionID: Session.ID
@@ -1189,10 +1071,7 @@ export type SessionLogOutput =
readonly type: "session.compaction.started"
readonly durable: { readonly aggregateID: string; readonly seq: Event.Seq; readonly version: Event.Version }
readonly location?:
| {
readonly directory: AbsolutePath
readonly workspaceID?: (string & Brand.Brand<"Workspace.ID">) | undefined
}
| { readonly directory: AbsolutePath; readonly workspaceID?: Workspace.ID | undefined }
| undefined
readonly data: {
readonly sessionID: Session.ID
@@ -1208,10 +1087,7 @@ export type SessionLogOutput =
readonly type: "session.compaction.ended"
readonly durable: { readonly aggregateID: string; readonly seq: Event.Seq; readonly version: Event.Version }
readonly location?:
| {
readonly directory: AbsolutePath
readonly workspaceID?: (string & Brand.Brand<"Workspace.ID">) | undefined
}
| { readonly directory: AbsolutePath; readonly workspaceID?: Workspace.ID | undefined }
| undefined
readonly data: {
readonly sessionID: Session.ID
@@ -1234,7 +1110,7 @@ export type SessionLogOutput =
| undefined
readonly text: string
readonly recent: string
readonly cost?: (number & Brand.Brand<"Money.USD">) | undefined
readonly cost?: Money.USD | undefined
readonly tokens?:
| {
readonly input: number
@@ -1252,10 +1128,7 @@ export type SessionLogOutput =
readonly type: "session.compaction.failed"
readonly durable: { readonly aggregateID: string; readonly seq: Event.Seq; readonly version: Event.Version }
readonly location?:
| {
readonly directory: AbsolutePath
readonly workspaceID?: (string & Brand.Brand<"Workspace.ID">) | undefined
}
| { readonly directory: AbsolutePath; readonly workspaceID?: Workspace.ID | undefined }
| undefined
readonly data: {
readonly sessionID: Session.ID
@@ -1267,7 +1140,7 @@ export type SessionLogOutput =
readonly response?: { readonly body: string } | undefined
}
readonly inputID?: SessionMessage.ID | undefined
readonly cost?: (number & Brand.Brand<"Money.USD">) | undefined
readonly cost?: Money.USD | undefined
readonly tokens?:
| {
readonly input: number
@@ -1285,10 +1158,7 @@ export type SessionLogOutput =
readonly type: "session.revert.staged"
readonly durable: { readonly aggregateID: string; readonly seq: Event.Seq; readonly version: Event.Version }
readonly location?:
| {
readonly directory: AbsolutePath
readonly workspaceID?: (string & Brand.Brand<"Workspace.ID">) | undefined
}
| { readonly directory: AbsolutePath; readonly workspaceID?: Workspace.ID | undefined }
| undefined
readonly data: { readonly sessionID: Session.ID; readonly revert: Session.Revert }
}
@@ -1299,10 +1169,7 @@ export type SessionLogOutput =
readonly type: "session.revert.cleared"
readonly durable: { readonly aggregateID: string; readonly seq: Event.Seq; readonly version: Event.Version }
readonly location?:
| {
readonly directory: AbsolutePath
readonly workspaceID?: (string & Brand.Brand<"Workspace.ID">) | undefined
}
| { readonly directory: AbsolutePath; readonly workspaceID?: Workspace.ID | undefined }
| undefined
readonly data: { readonly sessionID: Session.ID }
}
@@ -1313,10 +1180,7 @@ export type SessionLogOutput =
readonly type: "session.revert.committed"
readonly durable: { readonly aggregateID: string; readonly seq: Event.Seq; readonly version: Event.Version }
readonly location?:
| {
readonly directory: AbsolutePath
readonly workspaceID?: (string & Brand.Brand<"Workspace.ID">) | undefined
}
| { readonly directory: AbsolutePath; readonly workspaceID?: Workspace.ID | undefined }
| undefined
readonly data: { readonly sessionID: Session.ID; readonly to: SessionMessage.ID }
}
@@ -1327,15 +1191,12 @@ export type SessionLogOutput =
readonly type: "session.usage.recorded"
readonly durable: { readonly aggregateID: string; readonly seq: Event.Seq; readonly version: Event.Version }
readonly location?:
| {
readonly directory: AbsolutePath
readonly workspaceID?: (string & Brand.Brand<"Workspace.ID">) | undefined
}
| { readonly directory: AbsolutePath; readonly workspaceID?: Workspace.ID | undefined }
| undefined
readonly data: {
readonly sessionID: Session.ID
readonly source: "title" | "compaction"
readonly cost: number & Brand.Brand<"Money.USD">
readonly cost: Money.USD
readonly tokens: {
readonly input: number
readonly output: number
@@ -1351,10 +1212,7 @@ export type SessionLogOutput =
readonly type: "session.message.content.updated"
readonly durable: { readonly aggregateID: string; readonly seq: Event.Seq; readonly version: Event.Version }
readonly location?:
| {
readonly directory: AbsolutePath
readonly workspaceID?: (string & Brand.Brand<"Workspace.ID">) | undefined
}
| { readonly directory: AbsolutePath; readonly workspaceID?: Workspace.ID | undefined }
| undefined
readonly data: {
readonly sessionID: Session.ID
+12 -2
View File
@@ -281,11 +281,21 @@ const mapClientError = <E>(error: E) =>
const preserveEffect =
<A>() =>
<E, R>(effect: Effect.Effect<A, E, R>) =>
<Actual extends A, E, R>(
effect: Effect.Effect<Actual, E, R> &
([A] extends [Actual]
? unknown
: { readonly __generatedOutputWiderThanContract: [expected: Actual, generated: A] }),
): Effect.Effect<A, E, R> =>
effect
const preserveStream =
<A>() =>
<E, R>(stream: Stream.Stream<A, E, R>) =>
<Actual extends A, E, R>(
stream: Stream.Stream<Actual, E, R> &
([A] extends [Actual]
? unknown
: { readonly __generatedOutputWiderThanContract: [expected: Actual, generated: A] }),
): Stream.Stream<A, E, R> =>
stream
const EndpointServerInfo = (raw: RawClient["server.server"]) => () =>
File diff suppressed because it is too large. Load diff
+8 -6
View File
@@ -1,6 +1,6 @@
export * as LocationLifecycle from "./location-lifecycle.js"
import { Context, Effect, Layer, Schema } from "effect"
import { Context, Deferred, Effect, Layer, Schema } from "effect"
import { makeLocationNode } from "@opencode/util/effect/app-node"
import { LocationEvent } from "@opencode/schema/location-event"
import { Bus } from "./bus.js"
@@ -39,9 +39,11 @@ const layer = Layer.effect(
})
yield* Effect.addFinalizer(() => unsubscribe)
let closed = false
const shutdown = yield* Effect.cached(
Effect.gen(function* () {
closed = true
const done = yield* Deferred.make<void>()
const shutdown = Effect.suspend(() => {
if (closed) return Deferred.await(done)
closed = true
return Effect.gen(function* () {
yield* permission.close
yield* forms.close
yield* rpc.close
@@ -52,8 +54,8 @@ const layer = Layer.effect(
location: Location.Ref.make({ directory: location.directory, workspaceID: location.workspaceID }),
},
)
}).pipe(Effect.uninterruptible),
)
}).pipe(Effect.ensuring(Deferred.succeed(done, undefined)))
}).pipe(Effect.uninterruptible)
return Service.of({
isClosed: () => closed,
shutdown,
+1 -1
View File
@@ -52,7 +52,7 @@
"typescript": "catalog:"
},
"dependencies": {
"@effect/platform-node-shared": "4.0.0-rc.118"
"@effect/platform-node-shared": "catalog:"
},
"peerDependencies": {
"effect": "catalog:"
+11 -19
View File
@@ -455,23 +455,20 @@ ${clientFields.join("\n")}
function effectTypeReferences(input: ReadonlyArray<EffectTypeReference>) {
const names = new Map<string, ResolvedEffectTypeReference>()
const asts = new Map<SchemaAST.AST, ResolvedEffectTypeReference>()
const brands = new Map<string, ResolvedEffectTypeReference>()
for (const reference of input) {
const document = SchemaRepresentation.toCodeDocument(
SchemaRepresentation.toRepresentations([codegenAst(Schema.toType(reference.schema).ast)]),
)
const name = document.codes[0]?.Type
const type =
name === undefined
? undefined
: (document.references.nonRecursives.find((item) => item.$ref === name)?.code.Type ?? name)
const nonRecursive =
name === undefined ? undefined : document.references.nonRecursives.find((item) => item.$ref === name)
const type = nonRecursive?.code.Type
const value = { name: reference.name, import: reference.import, ast: reference.schema.ast, type }
if (type?.includes("Brand.Brand<") && !brands.has(type)) brands.set(type, value)
if (SchemaAST.resolveIdentifier(reference.schema.ast) !== undefined || type?.includes("Brand.Brand<")) {
if (SchemaAST.resolveIdentifier(reference.schema.ast) !== undefined) {
asts.set(reference.schema.ast, value)
asts.set(Schema.toType(reference.schema).ast, value)
}
if (name === undefined || !/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(name)) continue
if (name === undefined || nonRecursive === undefined || !/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(name)) continue
const previous = names.get(name)
if (previous !== undefined) {
if (previous.ast !== reference.schema.ast) {
@@ -481,7 +478,7 @@ function effectTypeReferences(input: ReadonlyArray<EffectTypeReference>) {
}
names.set(name, value)
}
return { names, asts, brands }
return { names, asts }
}
function effectType(schema: Schema.Top, references: ReturnType<typeof effectTypeReferences>, imports: Set<string>) {
@@ -516,13 +513,7 @@ function effectType(schema: Schema.Top, references: ReturnType<typeof effectType
}
return type
}
let type = expand(document.codes[0].Type)
for (const [brand, reference] of references.brands) {
if (!type.includes(brand)) continue
imports.add(reference.import)
type = type.replaceAll(brand, reference.name)
}
if (type.includes("Brand.Brand<")) imports.add('import type { Brand } from "effect"')
const type = expand(document.codes[0].Type)
if (type.includes("DateTime.")) imports.add('import type { DateTime } from "effect"')
if (type.includes("Schema.")) imports.add('import type { Schema } from "effect"')
return type
@@ -588,7 +579,8 @@ function assertPromiseEndpoint(endpoint: Endpoint) {
const payloadEncoding =
payload === undefined
? undefined
: (resolveHttpApiEncoding(payload.ast)?._tag ?? (HttpMethod.hasBody(endpoint.endpoint.method) ? "Json" : "FormUrlEncoded"))
: (resolveHttpApiEncoding(payload.ast)?._tag ??
(HttpMethod.hasBody(endpoint.endpoint.method) ? "Json" : "FormUrlEncoded"))
if (payloadEncoding !== undefined && payloadEncoding !== "Json" && payloadEncoding !== "Uint8Array") {
throw new GenerationError({ reason: `Unsupported Promise payload encoding: ${name}` })
}
@@ -761,7 +753,7 @@ function renderImportedEffectFiles(
const preserve =
options.shapeModule === undefined
? ""
: `const preserveEffect = <A>() => <E, R>(effect: Effect.Effect<A, E, R>) => effect\n${usesStream ? "const preserveStream = <A>() => <E, R>(stream: Stream.Stream<A, E, R>) => stream\n" : ""}\n`
: `const preserveEffect = <A>() => <Actual extends A, E, R>(effect: Effect.Effect<Actual, E, R> & ([A] extends [Actual] ? unknown : { readonly __generatedOutputWiderThanContract: [expected: Actual, generated: A] })): Effect.Effect<A, E, R> => effect\n${usesStream ? "const preserveStream = <A>() => <Actual extends A, E, R>(stream: Stream.Stream<Actual, E, R> & ([A] extends [Actual] ? unknown : { readonly __generatedOutputWiderThanContract: [expected: Actual, generated: A] })): Stream.Stream<A, E, R> => stream\n" : ""}\n`
const client = `// Generated by @opencode/httpapi-codegen. Do not edit.\nimport { Effect${usesStream ? ", Stream" : ""}, Schema } from "effect"\nimport { Sse } from "effect/encoding"\nimport { HttpClientError } from "effect/http"\n${httpApiImport}${imports}\n${shapeImport}import { ClientError } from "./client-error.js"\n\n${projection?.source ?? ""}type RawClient = HttpApiClient.ForApi<typeof ${api}>\n\nconst mapClientError = <E>(error: E) => HttpClientError.isHttpClientError(error) || Schema.isSchemaError(error) || Sse.Retry.is(error) ? new ClientError({ cause: error }) : error\n\n${preserve}${adapters.join("\n\n")}\n\nconst adaptClient = (raw: RawClient) => ({ ${fields.join(", ")} })\n\nexport const make = (options?: { readonly baseUrl?: URL | string }) => HttpApiClient.make(${api}, options).pipe(Effect.map(adaptClient))\n`
return [
{
@@ -1253,7 +1245,7 @@ function normalizePromiseClientContent(content: string, groups: ReadonlyArray<Gr
'if (descriptor.body !== undefined && !headers.has("content-type"))\n headers.set("content-type", descriptor.binaryBody ? "application/octet-stream" : "application/json")',
),
"body: descriptor.body === undefined ? undefined : JSON.stringify(descriptor.body),",
"body:\n descriptor.body === undefined\n ? undefined\n : descriptor.binaryBody\n ? (descriptor.body as RequestInit[\"body\"])\n : JSON.stringify(descriptor.body),",
'body:\n descriptor.body === undefined\n ? undefined\n : descriptor.binaryBody\n ? (descriptor.body as RequestInit["body"])\n : JSON.stringify(descriptor.body),',
)
: binaryReady
return usesWildcard
+90 -13
View File
@@ -3,15 +3,8 @@ import { mkdtemp, rm } from "node:fs/promises"
import { tmpdir } from "node:os"
import { join } from "node:path"
import { fileURLToPath } from "node:url"
import { Effect, FileSystem, Schema, SchemaAST, SchemaGetter } from "effect"
import {
HttpApi,
HttpApiEndpoint,
HttpApiGroup,
HttpApiMiddleware,
HttpApiSchema,
OpenApi,
} from "effect/http-api"
import { type Brand, Effect, FileSystem, Schema, SchemaAST, SchemaGetter, Stream } from "effect"
import { HttpApi, HttpApiEndpoint, HttpApiGroup, HttpApiMiddleware, HttpApiSchema, OpenApi } from "effect/http-api"
import { format } from "prettier"
import {
compile as compileContract,
@@ -189,6 +182,61 @@ describe("HttpApiCodegen.generate", () => {
expect(source).toContain('readonly "different": ({ readonly [x: string]: number })')
})
test("preserves referenced branded Effect types across optional, record, and re-annotated shapes", () => {
const SessionID = Schema.String.check(Schema.isStartingWith("ses_")).pipe(
Schema.brand("Session.ID"),
Schema.annotate({ identifier: "Session.ID" }),
)
const AgentID = Schema.String.pipe(Schema.brand("Agent.ID"), Schema.annotate({ identifier: "Agent.ID" }))
const Cursor = Schema.String.pipe(
Schema.brand("SessionsCursor"),
Schema.annotate({ identifier: "SessionsCursor" }),
).annotate({ description: "Cursor" })
const Cost = Schema.Finite.pipe(Schema.brand("Money.USD"), Schema.annotate({ identifier: "Money.USD" }))
const output = emitEffectShape(
compileContract(
api(
HttpApiEndpoint.get("list", "/session/:sessionID", {
params: { sessionID: SessionID },
query: Schema.Struct({
agent: AgentID.pipe(Schema.optional),
cursor: Cursor.pipe(Schema.optional),
}),
success: Schema.Struct({
data: Schema.Struct({
active: Schema.Record(SessionID, Schema.Struct({ cost: Cost })),
agents: Schema.Array(AgentID),
}),
}),
}),
),
),
{
typeReferences: [
{ schema: SessionID, name: "Session.ID", import: 'import type { Session } from "@example/schema/session"' },
{ schema: AgentID, name: "Agent.ID", import: 'import type { Agent } from "@example/schema/agent"' },
{
schema: Cursor,
name: "SessionsCursor",
import: 'import type { SessionsCursor } from "@example/protocol/session"',
},
{ schema: Cost, name: "Money.USD", import: 'import type { Money } from "@example/schema/money"' },
],
},
)
const source = output.files[0]?.content
expect(source).toContain('import type { Session } from "@example/schema/session"')
expect(source).toContain('import type { Agent } from "@example/schema/agent"')
expect(source).toContain('import type { SessionsCursor } from "@example/protocol/session"')
expect(source).toContain('import type { Money } from "@example/schema/money"')
expect(source).toContain('readonly "sessionID": Session.ID')
expect(source).toContain('readonly "agent"?: Agent.ID | undefined')
expect(source).toContain('readonly "cursor"?: SessionsCursor | undefined')
expect(source).toContain('readonly [x: Session.ID]: { readonly "cost": Money.USD }')
expect(source).toContain('readonly "agents": ReadonlyArray<Agent.ID>')
})
test("allows composed Effect outputs to use an authoritative named type", () => {
const output = emitEffectShape(
compileContract(api(HttpApiEndpoint.get("events", "/event", { success: Schema.Unknown }))),
@@ -253,7 +301,7 @@ describe("HttpApiCodegen.generate", () => {
).toThrow("Generated Effect adapter collides with imported endpoint: EndpointSessionGet")
})
test("exposes an imported Effect client through its generated shape", () => {
test("exposes an imported Effect client through its generated shape and rejects widened outputs", () => {
const output = emitEffectImported(
compileContract(api(HttpApiEndpoint.get("get", "/session", { success: Schema.String }))),
{ module: "@example/api", api: "Api", shapeModule: "../api" },
@@ -262,6 +310,37 @@ describe("HttpApiCodegen.generate", () => {
expect(source).toContain('import type { SessionGetOutput } from "../api"')
expect(source).toContain("preserveEffect<SessionGetOutput>()")
expect(source).toContain("__generatedOutputWiderThanContract")
type BrandedID = string & Brand.Brand<"Session.ID">
const preserveEffect =
<A>() =>
<Actual extends A, E, R>(
effect: Effect.Effect<Actual, E, R> &
([A] extends [Actual]
? unknown
: { readonly __generatedOutputWiderThanContract: [expected: Actual, generated: A] }),
): Effect.Effect<A, E, R> =>
effect
const preserveStream =
<A>() =>
<Actual extends A, E, R>(
stream: Stream.Stream<Actual, E, R> &
([A] extends [Actual]
? unknown
: { readonly __generatedOutputWiderThanContract: [expected: Actual, generated: A] }),
): Stream.Stream<A, E, R> =>
stream
const brandedEffect = Effect.succeed("ses_1" as BrandedID)
const brandedStream = Stream.make("ses_1" as BrandedID)
preserveEffect<BrandedID>()(brandedEffect)
preserveStream<BrandedID>()(brandedStream)
// @ts-expect-error Generated output cannot widen a branded contract output to plain string.
preserveEffect<string>()(brandedEffect)
// @ts-expect-error Generated stream output cannot widen a branded contract output to plain string.
preserveStream<string>()(brandedStream)
})
test("projects imported endpoint constants into a generated API", () => {
@@ -1477,9 +1556,7 @@ describe("HttpApiCodegen.generate", () => {
class Attempt extends Schema.Class<Attempt>("Attempt")({
count: Schema.Int.check(Schema.isGreaterThanOrEqualTo(0)),
}) {}
const output = emitPromise(
compileContract(api(HttpApiEndpoint.get("get", "/session", { success: Attempt }))),
)
const output = emitPromise(compileContract(api(HttpApiEndpoint.get("get", "/session", { success: Attempt }))))
const types = output.files.find((file) => file.path === "types.ts")?.content
expect(types).toContain('export type Attempt = { readonly "count": number }')
+1 -1
View File
@@ -11,7 +11,7 @@ Authoring interfaces and runtime loader support for OpenCode V2 plugins:
When the OpenCode CLI loads server or TUI plugins, it resolves imports of `effect`, exported `effect/*` subpaths, and `@opencode/plugin` entrypoints (including imports from dependencies inside a plugin's `node_modules`) to the host's runtime module instances so fibers, loggers, and `Schema` parsers share one copy.
- Declare `effect` as a `peerDependency` (and `devDependency` for local type-checking and testing) rather than a bundled runtime dependency.
- Declare `"effect": "^4.0.0"` as a `peerDependency` (and `devDependency` for local type-checking and testing) rather than a bundled runtime dependency.
- Do not bundle `effect` into published plugin files; if you build with a bundler, keep `effect` and `effect/*` external. Two copies of `effect` do not share fiber, logger, or `Schema` internals.
- Plugins and their `node_modules` dependencies always receive OpenCode's host `effect` instance. Use `effect` APIs and module paths compatible with the OpenCode release you target; dependencies built on another `effect` major (such as Effect 3) are not supported.
- Only public `effect` subpaths are provided. A plugin that imports one of Effect's private `internal` modules fails to load with an error naming the path.
File diff suppressed because it is too large. Load diff
+5 -5
View File
@@ -99,6 +99,10 @@ const invalidCursor = "Invalid cursor" as const
export const SessionsCursor = Schema.String.pipe(
Schema.brand("SessionsCursor"),
Schema.annotate({
identifier: "SessionsCursor",
description: "Opaque pagination cursor returned as cursor.previous or cursor.next in the previous response.",
}),
statics((schema) => {
// Read the default constructor without caching it on the schema, so `make` can be replaced.
const make = SchemaParser.make(schema)
@@ -161,16 +165,12 @@ const BooleanFromString = Schema.Literals(["true", "false"]).pipe(
}),
)
const SessionsQueryCursor = SessionsCursor.annotate({
description: "Opaque pagination cursor returned as cursor.previous or cursor.next in the previous response.",
})
export const SessionsQuery = Schema.Struct({
...SessionsQueryFields,
directory: AbsolutePath.pipe(Schema.optional),
project: Project.ID.pipe(Schema.optional),
subpath: RelativePath.pipe(Schema.optional),
cursor: SessionsQueryCursor.pipe(Schema.optional),
cursor: SessionsCursor.pipe(Schema.optional),
}).annotate({ identifier: "SessionsQuery" })
export const makeSessionGroup = <I extends HttpApiMiddleware.AnyId, S, FormI extends HttpApiMiddleware.AnyId, FormS>(
+2 -2
View File
@@ -10,10 +10,10 @@ import { PositiveInt, statics } from "./schema.js"
const Updated = ephemeral({ type: "agent.updated", schema: {} })
export const ID = Schema.String.pipe(Schema.brand("Agent.ID"))
export const ID = Schema.String.pipe(Schema.brand("Agent.ID"), Schema.annotate({ identifier: "Agent.ID" }))
export type ID = typeof ID.Type
export const Name = Schema.String.pipe(Schema.brand("Agent.Name"))
export const Name = Schema.String.pipe(Schema.brand("Agent.Name"), Schema.annotate({ identifier: "Agent.Name" }))
export type Name = typeof Name.Type
export const Color = Schema.String.annotate({ identifier: "Agent.Color" })
+1
View File
@@ -10,6 +10,7 @@ import { Form } from "./form.js"
export const ID = Schema.String.pipe(
Schema.brand("Credential.ID"),
Schema.annotate({ identifier: "Credential.ID" }),
statics((schema) => ({ create: () => schema.make("cred_" + ascending()) })),
)
export type ID = typeof ID.Type
+9 -2
View File
@@ -8,6 +8,7 @@ import { statics } from "./schema.js"
export const ID = Schema.String.check(Schema.isStartingWith("evt_")).pipe(
Schema.brand("Event.ID"),
Schema.annotate({ identifier: "Event.ID" }),
statics((schema) => ({ create: () => schema.make("evt_" + ascending()) })),
)
export type ID = typeof ID.Type
@@ -17,11 +18,17 @@ export type ID = typeof ID.Type
* event envelope and synced markers;
* `after` cursors accept only values that came from those sources.
*/
export const Seq = Schema.Int.check(Schema.isGreaterThanOrEqualTo(0)).pipe(Schema.brand("Event.Seq"))
export const Seq = Schema.Int.check(Schema.isGreaterThanOrEqualTo(0)).pipe(
Schema.brand("Event.Seq"),
Schema.annotate({ identifier: "Event.Seq" }),
)
export type Seq = typeof Seq.Type
/** Durable schema version of one event type, from the event definition that committed it. */
export const Version = Schema.Int.check(Schema.isGreaterThanOrEqualTo(1)).pipe(Schema.brand("Event.Version"))
export const Version = Schema.Int.check(Schema.isGreaterThanOrEqualTo(1)).pipe(
Schema.brand("Event.Version"),
Schema.annotate({ identifier: "Event.Version" }),
)
export type Version = typeof Version.Type
const DurableEnvelope = Schema.Struct({ aggregateID: Schema.String, seq: Seq, version: Version })
+4 -1
View File
@@ -5,7 +5,10 @@ import { ephemeral, inventory } from "./event.js"
import { ascending } from "./identifier.js"
import { NonNegativeInt, optional, statics } from "./schema.js"
const IDSchema = Schema.String.check(Schema.isStartingWith("frm_")).pipe(Schema.brand("Form.ID"))
const IDSchema = Schema.String.check(Schema.isStartingWith("frm_")).pipe(
Schema.brand("Form.ID"),
Schema.annotate({ identifier: "Form.ID" }),
)
export const ID = IDSchema.pipe(
statics((schema: typeof IDSchema) => ({ create: (id?: string) => schema.make(id ?? "frm_" + ascending()) })),
+5 -1
View File
@@ -4,10 +4,14 @@ import { Schema } from "effect"
export const Key = Schema.String.check(Schema.isPattern(/^[a-z0-9][a-z0-9._-]*\/[a-z0-9][a-z0-9._/-]*$/u)).pipe(
Schema.brand("Instruction.Key"),
Schema.annotate({ identifier: "Instruction.Key" }),
)
export type Key = typeof Key.Type
export const Hash = Schema.String.check(Schema.isPattern(/^[a-f0-9]{64}$/u)).pipe(Schema.brand("Instruction.Hash"))
export const Hash = Schema.String.check(Schema.isPattern(/^[a-f0-9]{64}$/u)).pipe(
Schema.brand("Instruction.Hash"),
Schema.annotate({ identifier: "Instruction.Hash" }),
)
export type Hash = typeof Hash.Type
export const Values = Schema.Record(Key, Hash)
+8 -2
View File
@@ -1,7 +1,13 @@
import { Schema } from "effect"
export const IntegrationID = Schema.String.pipe(Schema.brand("Integration.ID"))
export const IntegrationID = Schema.String.pipe(
Schema.brand("Integration.ID"),
Schema.annotate({ identifier: "Integration.ID" }),
)
export type IntegrationID = typeof IntegrationID.Type
export const IntegrationMethodID = Schema.String.pipe(Schema.brand("Integration.MethodID"))
export const IntegrationMethodID = Schema.String.pipe(
Schema.brand("Integration.MethodID"),
Schema.annotate({ identifier: "Integration.MethodID" }),
)
export type IntegrationMethodID = typeof IntegrationMethodID.Type
+1
View File
@@ -82,6 +82,7 @@ export interface Info extends Schema.Schema.Type<typeof Info> {}
export const AttemptID = Schema.String.pipe(
Schema.brand("Integration.AttemptID"),
Schema.annotate({ identifier: "Integration.AttemptID" }),
statics((schema) => ({ create: () => schema.make("con_" + ascending()) })),
)
export type AttemptID = typeof AttemptID.Type
+6 -3
View File
@@ -6,13 +6,16 @@ import { Provider } from "./provider.js"
import { Money } from "./money.js"
import { ephemeral, inventory } from "./event.js"
export const ID = Schema.String.pipe(Schema.brand("Model.ID"))
export const ID = Schema.String.pipe(Schema.brand("Model.ID"), Schema.annotate({ identifier: "Model.ID" }))
export type ID = typeof ID.Type
const Updated = ephemeral({ type: "model.updated", schema: {} })
export const Event = { Updated, Definitions: inventory(Updated) }
export const VariantID = Schema.String.pipe(Schema.brand("Model.VariantID"))
export const VariantID = Schema.String.pipe(
Schema.brand("Model.VariantID"),
Schema.annotate({ identifier: "Model.VariantID" }),
)
export type VariantID = typeof VariantID.Type
export const Ref = Schema.Struct({
@@ -42,7 +45,7 @@ export const Ref = Schema.Struct({
)
export interface Ref extends Schema.Schema.Type<typeof Ref> {}
export const Family = Schema.String.pipe(Schema.brand("Model.Family"))
export const Family = Schema.String.pipe(Schema.brand("Model.Family"), Schema.annotate({ identifier: "Model.Family" }))
export type Family = typeof Family.Type
export type ReasoningField = "reasoning" | "reasoning_content" | "reasoning_text" | (string & {})
+1
View File
@@ -7,6 +7,7 @@ import { DateTimeUtcFromMillis, statics } from "./schema.js"
export const ID = Schema.String.pipe(
Schema.brand("PermissionSaved.ID"),
Schema.annotate({ identifier: "PermissionSaved.ID" }),
statics((schema) => ({ create: () => schema.make("psv_" + ascending()) })),
)
export type ID = typeof ID.Type
+1
View File
@@ -9,6 +9,7 @@ import { statics } from "./schema.js"
export const ID = Schema.String.check(Schema.isStartingWith("per")).pipe(
Schema.brand("Permission.ID"),
Schema.annotate({ identifier: "Permission.ID" }),
statics((schema) => ({ create: (id?: string) => schema.make(id ?? "per_" + ascending()) })),
)
export type ID = typeof ID.Type
+1 -1
View File
@@ -4,7 +4,7 @@ import { Schema } from "effect"
import { ephemeral, inventory } from "./event.js"
import { optional } from "./schema.js"
export const ID = Schema.String.pipe(Schema.brand("Plugin.ID"))
export const ID = Schema.String.pipe(Schema.brand("Plugin.ID"), Schema.annotate({ identifier: "Plugin.ID" }))
export type ID = typeof ID.Type
export const Source = Schema.Union([
+1
View File
@@ -3,6 +3,7 @@ import { statics } from "./schema.js"
export const ProjectID = Schema.String.pipe(
Schema.brand("Project.ID"),
Schema.annotate({ identifier: "Project.ID" }),
statics((schema) => ({ global: schema.make("global") })),
)
export type ProjectID = typeof ProjectID.Type
+1
View File
@@ -7,6 +7,7 @@ import { ephemeral, inventory } from "./event.js"
export const ID = Schema.String.pipe(
Schema.brand("Provider.ID"),
Schema.annotate({ identifier: "Provider.ID" }),
statics((schema) => ({
opencode: schema.make("opencode"),
anthropic: schema.make("anthropic"),
+4 -1
View File
@@ -6,7 +6,10 @@ import { ephemeral, inventory } from "./event.js"
import { ascending } from "./identifier.js"
import { NonNegativeInt, PositiveInt, statics } from "./schema.js"
const IDSchema = Schema.String.check(Schema.isStartingWith("pty")).pipe(Schema.brand("PtyID"))
const IDSchema = Schema.String.check(Schema.isStartingWith("pty")).pipe(
Schema.brand("PtyID"),
Schema.annotate({ identifier: "Pty.ID" }),
)
export const ID = IDSchema.pipe(
statics((schema: typeof IDSchema) => {
+8 -2
View File
@@ -3,10 +3,16 @@ import { DateTime, Option, Schema, SchemaGetter } from "effect"
export const PositiveInt = Schema.Int.check(Schema.isGreaterThan(0))
export const NonNegativeInt = Schema.Int.check(Schema.isGreaterThanOrEqualTo(0))
export const RelativePath = Schema.String.pipe(Schema.brand("RelativePath"))
export const RelativePath = Schema.String.pipe(
Schema.brand("RelativePath"),
Schema.annotate({ identifier: "RelativePath" }),
)
export type RelativePath = typeof RelativePath.Type
export const AbsolutePath = Schema.String.pipe(Schema.brand("AbsolutePath"))
export const AbsolutePath = Schema.String.pipe(
Schema.brand("AbsolutePath"),
Schema.annotate({ identifier: "AbsolutePath" }),
)
export type AbsolutePath = typeof AbsolutePath.Type
export const optional = <S extends Schema.Top>(schema: S) =>
+1
View File
@@ -4,6 +4,7 @@ import { statics } from "./schema.js"
export const SessionID = Schema.String.check(Schema.isStartingWith("ses")).pipe(
Schema.brand("SessionID"),
Schema.annotate({ identifier: "Session.ID" }),
statics((schema) => {
const create = () => schema.make("ses_" + descending())
return {
+1
View File
@@ -22,6 +22,7 @@ import { TokenUsage } from "./token-usage.js"
export const ID = Schema.String.check(Schema.isStartingWith("msg_")).pipe(
Schema.brand("Session.Message.ID"),
Schema.annotate({ identifier: "Session.Message.ID" }),
statics((schema) => ({
create: () => schema.make("msg_" + ascending()),
fromEvent: (eventID: Event.ID) => schema.make(eventID.replace(/^evt_/, "msg_")),
+4 -1
View File
@@ -6,7 +6,10 @@ import { ephemeral, inventory } from "./event.js"
import { ascending } from "./identifier.js"
import { NonNegativeInt, statics } from "./schema.js"
const IDSchema = Schema.String.check(Schema.isStartingWith("sh_")).pipe(Schema.brand("Shell.ID"))
const IDSchema = Schema.String.check(Schema.isStartingWith("sh_")).pipe(
Schema.brand("Shell.ID"),
Schema.annotate({ identifier: "Shell.ID" }),
)
export const ID = IDSchema.pipe(
statics((schema: typeof IDSchema) => {
+2 -2
View File
@@ -5,10 +5,10 @@ import { optional } from "./schema.js"
import { AbsolutePath } from "./schema.js"
import { ephemeral, inventory } from "./event.js"
export const ID = Schema.String.pipe(Schema.brand("Skill.ID"))
export const ID = Schema.String.pipe(Schema.brand("Skill.ID"), Schema.annotate({ identifier: "Skill.ID" }))
export type ID = typeof ID.Type
export const Name = Schema.String.pipe(Schema.brand("Skill.Name"))
export const Name = Schema.String.pipe(Schema.brand("Skill.Name"), Schema.annotate({ identifier: "Skill.Name" }))
export type Name = typeof Name.Type
export interface DirectorySource extends Schema.Schema.Type<typeof DirectorySource> {}
+1 -1
View File
@@ -2,5 +2,5 @@ export * as Snapshot from "./snapshot.js"
import { Schema } from "effect"
export const ID = Schema.String.pipe(Schema.brand("Snapshot.ID"))
export const ID = Schema.String.pipe(Schema.brand("Snapshot.ID"), Schema.annotate({ identifier: "Snapshot.ID" }))
export type ID = typeof ID.Type
+1 -1
View File
@@ -8,7 +8,7 @@ import type { SessionMessage } from "./session-message.js"
export type Metadata = Readonly<Record<string, any>>
export const CallID = Schema.String.pipe(Schema.brand("Tool.CallID"))
export const CallID = Schema.String.pipe(Schema.brand("Tool.CallID"), Schema.annotate({ identifier: "Tool.CallID" }))
export type CallID = typeof CallID.Type
export interface Context {
+1 -1
View File
@@ -4,7 +4,7 @@ import { Schema } from "effect"
import { ephemeral, inventory } from "./event.js"
import { optional } from "./schema.js"
export const ID = Schema.String.pipe(Schema.brand("WebSearch.ID"))
export const ID = Schema.String.pipe(Schema.brand("WebSearch.ID"), Schema.annotate({ identifier: "WebSearch.ID" }))
export type ID = typeof ID.Type
export interface Provider extends Schema.Schema.Type<typeof Provider> {}
+1
View File
@@ -4,6 +4,7 @@ import { statics } from "./schema.js"
export const WorkspaceID = Schema.String.check(Schema.isStartingWith("wrk")).pipe(
Schema.brand("Workspace.ID"),
Schema.annotate({ identifier: "Workspace.ID" }),
statics((schema) => {
const create = () => schema.make("wrk_" + ascending())
return {
+5 -1
View File
@@ -5,7 +5,11 @@ import { durable, ephemeral, inventory } from "./event.js"
import { AbsolutePath, optional } from "./schema.js"
import { Project } from "./project.js"
export const StrategyID = Schema.Trim.pipe(Schema.check(Schema.isNonEmpty()), Schema.brand("Worktree.StrategyID"))
export const StrategyID = Schema.Trim.pipe(
Schema.check(Schema.isNonEmpty()),
Schema.brand("Worktree.StrategyID"),
Schema.annotate({ identifier: "Worktree.StrategyID" }),
)
export type StrategyID = typeof StrategyID.Type
export const CreateInput = Schema.Struct({
+329 -356
View File
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
@@ -1517,7 +1517,7 @@ entrypoint and declare `effect` as a `peerDependency`.
"@opencode/plugin": "latest"
},
"peerDependencies": {
"effect": ">=4.0.0-rc.118"
"effect": "^4.0.0"
}
}
```