Skip to content

Commit 966f5ac

Browse files
committed
refactor: tighten numeric schemas and simplify public.ts OpenAPI transform
- Replace Schema.Finite with NonNegativeInt/PositiveInt where values are always integers (timestamps, token counts, positions, PIDs, etc.) - Simplify public.ts: remove finite-number normalization, TUI event hoisting, and sync replay inlining (all now handled at schema level) - Add generic self-referencing $ref fixer for Effect OpenAPI generation bug where annotated union arms sharing AST nodes produce circular component schemas - Keep: optional null stripping, workspace re-nulling, SSE response override, instance query param injection, query param type overrides
1 parent 0b395cd commit 966f5ac

33 files changed

Lines changed: 424 additions & 244 deletions

packages/opencode/src/auth/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import path from "path"
22
import { Effect, Layer, Record, Result, Schema, Context } from "effect"
33
import { zod } from "@/util/effect-zod"
4+
import { NonNegativeInt } from "@/util/schema"
45
import { Global } from "@opencode-ai/core/global"
56
import { AppFileSystem } from "@opencode-ai/core/filesystem"
67

@@ -14,7 +15,7 @@ export class Oauth extends Schema.Class<Oauth>("OAuth")({
1415
type: Schema.Literal("oauth"),
1516
refresh: Schema.String,
1617
access: Schema.String,
17-
expires: Schema.Finite,
18+
expires: NonNegativeInt,
1819
accountId: Schema.optional(Schema.String),
1920
enterpriseUrl: Schema.optional(Schema.String),
2021
}) {}

packages/opencode/src/cli/cmd/tui/event.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { BusEvent } from "@/bus/bus-event"
22
import { SessionID } from "@/session/schema"
3+
import { PositiveInt } from "@/util/schema"
34
import { Effect, Schema } from "effect"
45

56
const DEFAULT_TOAST_DURATION = 5000
@@ -38,7 +39,7 @@ export const TuiEvent = {
3839
title: Schema.optional(Schema.String),
3940
message: Schema.String,
4041
variant: Schema.Literals(["info", "success", "warning", "error"]),
41-
duration: Schema.Finite.pipe(Schema.withDecodingDefault(Effect.succeed(DEFAULT_TOAST_DURATION))).annotate({
42+
duration: PositiveInt.pipe(Schema.withDecodingDefault(Effect.succeed(DEFAULT_TOAST_DURATION))).annotate({
4243
description: "Duration in milliseconds",
4344
}),
4445
}),

packages/opencode/src/config/console-state.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
import { Schema } from "effect"
22
import { zod } from "@/util/effect-zod"
3+
import { NonNegativeInt } from "@/util/schema"
34

45
export class ConsoleState extends Schema.Class<ConsoleState>("ConsoleState")({
56
consoleManagedProviders: Schema.mutable(Schema.Array(Schema.String)),
67
activeOrgName: Schema.optional(Schema.String),
7-
switchableOrgCount: Schema.Number,
8+
switchableOrgCount: NonNegativeInt,
89
}) {
910
static readonly zod = zod(this)
1011
}

packages/opencode/src/config/mcp.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { Schema } from "effect"
22
import { zod } from "@/util/effect-zod"
3-
import { withStatics } from "@/util/schema"
3+
import { PositiveInt, withStatics } from "@/util/schema"
44

55
export const Local = Schema.Struct({
66
type: Schema.Literal("local").annotate({ description: "Type of MCP server connection" }),
@@ -13,7 +13,7 @@ export const Local = Schema.Struct({
1313
enabled: Schema.optional(Schema.Boolean).annotate({
1414
description: "Enable or disable the MCP server on startup",
1515
}),
16-
timeout: Schema.optional(Schema.Finite).annotate({
16+
timeout: Schema.optional(PositiveInt).annotate({
1717
description: "Timeout in ms for MCP server requests. Defaults to 5000 (5 seconds) if not specified.",
1818
}),
1919
})
@@ -49,7 +49,7 @@ export const Remote = Schema.Struct({
4949
oauth: Schema.optional(Schema.Union([OAuth, Schema.Literal(false)])).annotate({
5050
description: "OAuth authentication configuration for the MCP server. Set to false to disable OAuth auto-detection.",
5151
}),
52-
timeout: Schema.optional(Schema.Finite).annotate({
52+
timeout: Schema.optional(PositiveInt).annotate({
5353
description: "Timeout in ms for MCP server requests. Defaults to 5000 (5 seconds) if not specified.",
5454
}),
5555
})

packages/opencode/src/config/provider.ts

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -21,25 +21,25 @@ export const Model = Schema.Struct({
2121
),
2222
cost: Schema.optional(
2323
Schema.Struct({
24-
input: Schema.Number,
25-
output: Schema.Number,
26-
cache_read: Schema.optional(Schema.Number),
27-
cache_write: Schema.optional(Schema.Number),
24+
input: Schema.Finite,
25+
output: Schema.Finite,
26+
cache_read: Schema.optional(Schema.Finite),
27+
cache_write: Schema.optional(Schema.Finite),
2828
context_over_200k: Schema.optional(
2929
Schema.Struct({
30-
input: Schema.Number,
31-
output: Schema.Number,
32-
cache_read: Schema.optional(Schema.Number),
33-
cache_write: Schema.optional(Schema.Number),
30+
input: Schema.Finite,
31+
output: Schema.Finite,
32+
cache_read: Schema.optional(Schema.Finite),
33+
cache_write: Schema.optional(Schema.Finite),
3434
}),
3535
),
3636
}),
3737
),
3838
limit: Schema.optional(
3939
Schema.Struct({
40-
context: Schema.Number,
41-
input: Schema.optional(Schema.Number),
42-
output: Schema.Number,
40+
context: Schema.Finite,
41+
input: Schema.optional(Schema.Finite),
42+
output: Schema.Finite,
4343
}),
4444
),
4545
modalities: Schema.optional(

packages/opencode/src/file/index.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,12 @@ import * as Log from "@opencode-ai/core/util/log"
1515
import { Protected } from "./protected"
1616
import { Ripgrep } from "./ripgrep"
1717
import { zod } from "@/util/effect-zod"
18-
import { type DeepMutable, withStatics } from "@/util/schema"
18+
import { NonNegativeInt, type DeepMutable, withStatics } from "@/util/schema"
1919

2020
export const Info = Schema.Struct({
2121
path: Schema.String,
22-
added: Schema.Int,
23-
removed: Schema.Int,
22+
added: NonNegativeInt,
23+
removed: NonNegativeInt,
2424
status: Schema.Literals(["added", "deleted", "modified"]),
2525
})
2626
.annotate({ identifier: "File" })
@@ -39,10 +39,10 @@ export const Node = Schema.Struct({
3939
export type Node = DeepMutable<Schema.Schema.Type<typeof Node>>
4040

4141
const Hunk = Schema.Struct({
42-
oldStart: Schema.Number,
43-
oldLines: Schema.Number,
44-
newStart: Schema.Number,
45-
newLines: Schema.Number,
42+
oldStart: NonNegativeInt,
43+
oldLines: NonNegativeInt,
44+
newStart: NonNegativeInt,
45+
newLines: NonNegativeInt,
4646
lines: Schema.Array(Schema.String),
4747
})
4848

packages/opencode/src/file/ripgrep.ts

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import * as Log from "@opencode-ai/core/util/log"
1212
import { sanitizedProcessEnv } from "@opencode-ai/core/util/opencode-process"
1313
import { which } from "@/util/which"
1414
import { zod } from "@/util/effect-zod"
15-
import { withStatics } from "@/util/schema"
15+
import { NonNegativeInt, withStatics } from "@/util/schema"
1616

1717
const log = Log.create({ service: "ripgrep" })
1818
const VERSION = "15.1.0"
@@ -27,19 +27,19 @@ const PLATFORM = {
2727
} as const
2828

2929
const TimeStats = Schema.Struct({
30-
secs: Schema.Number,
31-
nanos: Schema.Number,
30+
secs: NonNegativeInt,
31+
nanos: NonNegativeInt,
3232
human: Schema.String,
3333
})
3434

3535
const Stats = Schema.Struct({
3636
elapsed: TimeStats,
37-
searches: Schema.Number,
38-
searches_with_match: Schema.Number,
39-
bytes_searched: Schema.Number,
40-
bytes_printed: Schema.Number,
41-
matched_lines: Schema.Number,
42-
matches: Schema.Number,
37+
searches: NonNegativeInt,
38+
searches_with_match: NonNegativeInt,
39+
bytes_searched: NonNegativeInt,
40+
bytes_printed: NonNegativeInt,
41+
matched_lines: NonNegativeInt,
42+
matches: NonNegativeInt,
4343
})
4444

4545
const PathText = Schema.Struct({
@@ -58,15 +58,15 @@ export const SearchMatch = Schema.Struct({
5858
lines: Schema.Struct({
5959
text: Schema.String,
6060
}),
61-
line_number: Schema.Number,
62-
absolute_offset: Schema.Number,
61+
line_number: NonNegativeInt,
62+
absolute_offset: NonNegativeInt,
6363
submatches: Schema.Array(
6464
Schema.Struct({
6565
match: Schema.Struct({
6666
text: Schema.String,
6767
}),
68-
start: Schema.Number,
69-
end: Schema.Number,
68+
start: NonNegativeInt,
69+
end: NonNegativeInt,
7070
}),
7171
),
7272
}).pipe(withStatics((s) => ({ zod: zod(s) })))
@@ -80,7 +80,7 @@ const End = Schema.Struct({
8080
type: Schema.Literal("end"),
8181
data: Schema.Struct({
8282
path: PathText,
83-
binary_offset: Schema.NullOr(Schema.Number),
83+
binary_offset: Schema.NullOr(NonNegativeInt),
8484
stats: Stats,
8585
}),
8686
})

packages/opencode/src/lsp/lsp.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import { spawn as lspspawn } from "./launch"
1313
import { Effect, Layer, Context, Schema } from "effect"
1414
import { InstanceState } from "@/effect/instance-state"
1515
import { AppFileSystem } from "@opencode-ai/core/filesystem"
16-
import { withStatics } from "@/util/schema"
16+
import { NonNegativeInt, withStatics } from "@/util/schema"
1717
import { zod, ZodOverride } from "@/util/effect-zod"
1818

1919
const log = Log.create({ service: "lsp" })
@@ -23,8 +23,8 @@ export const Event = {
2323
}
2424

2525
const Position = Schema.Struct({
26-
line: Schema.Finite,
27-
character: Schema.Finite,
26+
line: NonNegativeInt,
27+
character: NonNegativeInt,
2828
})
2929

3030
export const Range = Schema.Struct({
@@ -37,7 +37,7 @@ export type Range = typeof Range.Type
3737

3838
export const Symbol = Schema.Struct({
3939
name: Schema.String,
40-
kind: Schema.Number,
40+
kind: NonNegativeInt,
4141
location: Schema.Struct({
4242
uri: Schema.String,
4343
range: Range,
@@ -50,7 +50,7 @@ export type Symbol = typeof Symbol.Type
5050
export const DocumentSymbol = Schema.Struct({
5151
name: Schema.String,
5252
detail: Schema.optional(Schema.String),
53-
kind: Schema.Number,
53+
kind: NonNegativeInt,
5454
range: Range,
5555
selectionRange: Range,
5656
})

packages/opencode/src/project/project.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import { NodePath } from "@effect/platform-node"
1616
import { AppFileSystem } from "@opencode-ai/core/filesystem"
1717
import { CrossSpawnSpawner } from "@opencode-ai/core/cross-spawn-spawner"
1818
import { zod } from "@/util/effect-zod"
19-
import { withStatics } from "@/util/schema"
19+
import { NonNegativeInt, withStatics } from "@/util/schema"
2020

2121
const log = Log.create({ service: "project" })
2222

@@ -35,9 +35,9 @@ const ProjectCommands = Schema.Struct({
3535
})
3636

3737
const ProjectTime = Schema.Struct({
38-
created: Schema.Finite,
39-
updated: Schema.Finite,
40-
initialized: Schema.optional(Schema.Finite),
38+
created: NonNegativeInt,
39+
updated: NonNegativeInt,
40+
initialized: Schema.optional(NonNegativeInt),
4141
})
4242

4343
export const Info = Schema.Struct({

packages/opencode/src/project/vcs.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import { FileWatcher } from "@/file/watcher"
99
import { Git } from "@/git"
1010
import * as Log from "@opencode-ai/core/util/log"
1111
import { zod } from "@/util/effect-zod"
12-
import { withStatics } from "@/util/schema"
12+
import { NonNegativeInt, withStatics } from "@/util/schema"
1313

1414
const log = Log.create({ service: "vcs" })
1515

@@ -125,8 +125,8 @@ export type Info = Schema.Schema.Type<typeof Info>
125125
export const FileDiff = Schema.Struct({
126126
file: Schema.String,
127127
patch: Schema.String,
128-
additions: Schema.Finite,
129-
deletions: Schema.Finite,
128+
additions: NonNegativeInt,
129+
deletions: NonNegativeInt,
130130
status: Schema.optional(Schema.Literals(["added", "deleted", "modified"])),
131131
})
132132
.annotate({ identifier: "VcsFileDiff" })

0 commit comments

Comments
 (0)