Skip to content

Commit 88ba90d

Browse files
Merge branch 'dev' into fix/22129-tui-skills-autocomplete
2 parents aea5e77 + 2cd89d6 commit 88ba90d

22 files changed

Lines changed: 930 additions & 481 deletions

File tree

packages/opencode/specs/effect/schema.md

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -159,15 +159,18 @@ Schema at source.
159159
These are the highest-priority next targets. Each is a small, self-contained
160160
schema module with a clear domain.
161161

162+
- [x] `src/account/schema.ts`
162163
- [x] `src/control-plane/schema.ts`
163164
- [x] `src/permission/schema.ts`
164165
- [x] `src/project/schema.ts`
165166
- [x] `src/provider/schema.ts`
166167
- [x] `src/pty/schema.ts`
167168
- [x] `src/question/schema.ts`
168169
- [x] `src/session/schema.ts`
170+
- [x] `src/storage/schema.ts`
169171
- [x] `src/sync/schema.ts`
170172
- [x] `src/tool/schema.ts`
173+
- [x] `src/util/schema.ts`
171174

172175
### Session domain
173176

@@ -248,15 +251,15 @@ Possible later tightening after the Schema-first migration is stable:
248251
- promote repeated opaque strings and timestamp numbers into branded/newtype
249252
leaf schemas where that adds domain value without changing the wire format
250253

251-
- [ ] `src/session/compaction.ts`
252-
- [ ] `src/session/message-v2.ts`
253-
- [ ] `src/session/message.ts`
254-
- [ ] `src/session/prompt.ts`
255-
- [ ] `src/session/revert.ts`
256-
- [ ] `src/session/session.ts`
257-
- [ ] `src/session/status.ts`
258-
- [ ] `src/session/summary.ts`
259-
- [ ] `src/session/todo.ts`
254+
- [x] `src/session/compaction.ts`
255+
- [x] `src/session/message-v2.ts`
256+
- [x] `src/session/message.ts`
257+
- [x] `src/session/prompt.ts`
258+
- [x] `src/session/revert.ts`
259+
- [x] `src/session/session.ts`
260+
- [x] `src/session/status.ts`
261+
- [x] `src/session/summary.ts`
262+
- [x] `src/session/todo.ts`
260263

261264
### Provider domain
262265

packages/opencode/src/acp/agent.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -372,7 +372,7 @@ export class Agent implements ACPAgent {
372372
}
373373

374374
if (part.tool === "todowrite") {
375-
const parsedTodos = z.array(Todo.Info).safeParse(JSON.parse(part.state.output))
375+
const parsedTodos = z.array(Todo.Info.zod).safeParse(JSON.parse(part.state.output))
376376
if (parsedTodos.success) {
377377
await this.connection
378378
.sessionUpdate({
@@ -901,7 +901,7 @@ export class Agent implements ACPAgent {
901901
}
902902

903903
if (part.tool === "todowrite") {
904-
const parsedTodos = z.array(Todo.Info).safeParse(JSON.parse(part.state.output))
904+
const parsedTodos = z.array(Todo.Info.zod).safeParse(JSON.parse(part.state.output))
905905
if (parsedTodos.success) {
906906
await this.connection
907907
.sessionUpdate({

packages/opencode/src/cli/cmd/import.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { ShareNext } from "../../share"
1111
import { EOL } from "os"
1212
import { Filesystem } from "../../util"
1313
import { AppRuntime } from "@/effect/app-runtime"
14+
import { Schema } from "effect"
1415

1516
/** Discriminated union returned by the ShareNext API (GET /api/shares/:id/data) */
1617
export type ShareData =
@@ -154,10 +155,10 @@ export const ImportCommand = cmd({
154155
return
155156
}
156157

157-
const info = Session.Info.parse({
158+
const info = Schema.decodeUnknownSync(Session.Info)({
158159
...exportData.info,
159160
projectID: Instance.project.id,
160-
})
161+
}) as Session.Info
161162
const row = Session.toRow(info)
162163
Database.use((db) =>
163164
db

packages/opencode/src/cli/cmd/tui/routes/session/index.tsx

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1250,7 +1250,17 @@ function UserMessage(props: {
12501250
}) {
12511251
const ctx = use()
12521252
const local = useLocal()
1253-
const text = createMemo(() => props.parts.flatMap((x) => (x.type === "text" && !x.synthetic ? [x] : []))[0])
1253+
const text = createMemo(() => {
1254+
const texts = props.parts
1255+
.map((x) => {
1256+
if (x.type === "text" && !x.synthetic) {
1257+
return x.text
1258+
}
1259+
return null
1260+
})
1261+
.filter(Boolean)
1262+
return texts.join("\n\n")
1263+
})
12541264
const files = createMemo(() => props.parts.flatMap((x) => (x.type === "file" ? [x] : [])))
12551265
const { theme } = useTheme()
12561266
const [hover, setHover] = createSignal(false)
@@ -1285,7 +1295,7 @@ function UserMessage(props: {
12851295
backgroundColor={hover() ? theme.backgroundElement : theme.backgroundPanel}
12861296
flexShrink={0}
12871297
>
1288-
<text fg={theme.text}>{text()?.text}</text>
1298+
<text fg={theme.text}>{text()}</text>
12891299
<Show when={files().length}>
12901300
<box flexDirection="row" paddingBottom={metadataVisible() ? 1 : 0} paddingTop={1} gap={1} flexWrap="wrap">
12911301
<For each={files()}>

packages/opencode/src/npm/index.ts

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
export * as Npm from "."
22

33
import path from "path"
4+
import { fileURLToPath } from "url"
45
import npa from "npm-package-arg"
56
import semver from "semver"
7+
import Config from "@npmcli/config"
8+
import { definitions, flatten, nerfDarts, shorthands } from "@npmcli/config/lib/definitions/index.js"
69
import { Effect, Schema, Context, Layer, Option, FileSystem } from "effect"
710
import { NodeFileSystem } from "@effect/platform-node"
811
import { AppFileSystem } from "@opencode-ai/shared/filesystem"
@@ -40,12 +43,39 @@ export interface Interface {
4043
export class Service extends Context.Service<Service, Interface>()("@opencode/Npm") {}
4144

4245
const illegal = process.platform === "win32" ? new Set(["<", ">", ":", '"', "|", "?", "*"]) : undefined
46+
const npmPath = fileURLToPath(new URL("../..", import.meta.url))
4347

4448
export function sanitize(pkg: string) {
4549
if (!illegal) return pkg
4650
return Array.from(pkg, (char) => (illegal.has(char) || char.charCodeAt(0) < 32 ? "_" : char)).join("")
4751
}
4852

53+
const loadOptions = (dir: string) =>
54+
Effect.tryPromise({
55+
try: async () => {
56+
const config = new Config({
57+
npmPath,
58+
cwd: dir,
59+
env: { ...process.env },
60+
argv: [process.execPath, process.execPath],
61+
execPath: process.execPath,
62+
platform: process.platform,
63+
definitions,
64+
flatten,
65+
nerfDarts,
66+
shorthands,
67+
warn: false,
68+
})
69+
await config.load()
70+
return config.flat
71+
},
72+
catch: (cause) =>
73+
new InstallFailedError({
74+
cause,
75+
dir,
76+
}),
77+
})
78+
4979
const resolveEntryPoint = (name: string, dir: string): EntryPoint => {
5080
let entrypoint: Option.Option<string>
5181
try {
@@ -81,7 +111,10 @@ export const layer = Layer.effect(
81111
Effect.gen(function* () {
82112
yield* flock.acquire(`npm-install:${input.dir}`)
83113
const { Arborist } = yield* Effect.promise(() => import("@npmcli/arborist"))
114+
const add = input.add ?? []
115+
const npmOptions = yield* loadOptions(input.dir)
84116
const arborist = new Arborist({
117+
...npmOptions,
85118
path: input.dir,
86119
binLinks: true,
87120
progress: false,
@@ -91,14 +124,15 @@ export const layer = Layer.effect(
91124
return yield* Effect.tryPromise({
92125
try: () =>
93126
arborist.reify({
94-
add: input?.add || [],
127+
...npmOptions,
128+
add,
95129
save: true,
96130
saveType: "prod",
97131
}),
98132
catch: (cause) =>
99133
new InstallFailedError({
100134
cause,
101-
add: input?.add,
135+
add,
102136
dir: input.dir,
103137
}),
104138
}) as Effect.Effect<ArboristTree, InstallFailedError>

packages/opencode/src/server/routes/instance/experimental.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -335,7 +335,7 @@ export const ExperimentalRoutes = lazy(() =>
335335
description: "List of sessions",
336336
content: {
337337
"application/json": {
338-
schema: resolver(Session.GlobalInfo.array()),
338+
schema: resolver(Session.GlobalInfo.zod.array()),
339339
},
340340
},
341341
},

0 commit comments

Comments
 (0)