mirror of
https://github.com/aljazceru/opencode.git
synced 2025-12-18 16:34:18 +01:00
Refactor to support multiple instances inside single opencode process (#2360)
This release has a bunch of minor breaking changes if you are using opencode plugins or sdk 1. storage events have been removed (we might bring this back but had some issues) 2. concept of `app` is gone - there is a new concept called `project` and endpoints to list projects and get the current project 3. plugin receives `directory` which is cwd and `worktree` which is where the root of the project is if it's a git repo 4. the session.chat function has been renamed to session.prompt in sdk. it no longer requires model to be passed in (model is now an object) 5. every endpoint takes an optional `directory` parameter to operate as though opencode is running in that directory
This commit is contained in:
@@ -10,3 +10,7 @@
|
|||||||
- AVOID `let` statements
|
- AVOID `let` statements
|
||||||
- PREFER single word variable names where possible
|
- PREFER single word variable names where possible
|
||||||
- Use as many bun apis as possible like Bun.file()
|
- Use as many bun apis as possible like Bun.file()
|
||||||
|
|
||||||
|
## Debugging
|
||||||
|
|
||||||
|
- To test opencode in the `packages/opencode` directory you can run `bun dev`
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import { App } from "../app/app"
|
|
||||||
import { Config } from "../config/config"
|
import { Config } from "../config/config"
|
||||||
import z from "zod"
|
import z from "zod"
|
||||||
import { Provider } from "../provider/provider"
|
import { Provider } from "../provider/provider"
|
||||||
import { generateObject, type ModelMessage } from "ai"
|
import { generateObject, type ModelMessage } from "ai"
|
||||||
import PROMPT_GENERATE from "./generate.txt"
|
import PROMPT_GENERATE from "./generate.txt"
|
||||||
import { SystemPrompt } from "../session/system"
|
import { SystemPrompt } from "../session/system"
|
||||||
|
import { Instance } from "../project/instance"
|
||||||
import { mergeDeep } from "remeda"
|
import { mergeDeep } from "remeda"
|
||||||
|
|
||||||
export namespace Agent {
|
export namespace Agent {
|
||||||
@@ -36,7 +36,7 @@ export namespace Agent {
|
|||||||
})
|
})
|
||||||
export type Info = z.infer<typeof Info>
|
export type Info = z.infer<typeof Info>
|
||||||
|
|
||||||
const state = App.state("agent", async () => {
|
const state = Instance.state(async () => {
|
||||||
const cfg = await Config.get()
|
const cfg = await Config.get()
|
||||||
const defaultTools = cfg.tools ?? {}
|
const defaultTools = cfg.tools ?? {}
|
||||||
const defaultPermission: Info["permission"] = {
|
const defaultPermission: Info["permission"] = {
|
||||||
|
|||||||
@@ -1,147 +0,0 @@
|
|||||||
import "zod-openapi/extend"
|
|
||||||
import { Log } from "../util/log"
|
|
||||||
import { Context } from "../util/context"
|
|
||||||
import { Filesystem } from "../util/filesystem"
|
|
||||||
import { Global } from "../global"
|
|
||||||
import path from "path"
|
|
||||||
import os from "os"
|
|
||||||
import { z } from "zod"
|
|
||||||
|
|
||||||
export namespace App {
|
|
||||||
const log = Log.create({ service: "app" })
|
|
||||||
|
|
||||||
export const Info = z
|
|
||||||
.object({
|
|
||||||
hostname: z.string(),
|
|
||||||
git: z.boolean(),
|
|
||||||
path: z.object({
|
|
||||||
home: z.string(),
|
|
||||||
config: z.string(),
|
|
||||||
data: z.string(),
|
|
||||||
root: z.string(),
|
|
||||||
cwd: z.string(),
|
|
||||||
state: z.string(),
|
|
||||||
}),
|
|
||||||
time: z.object({
|
|
||||||
initialized: z.number().optional(),
|
|
||||||
}),
|
|
||||||
})
|
|
||||||
.openapi({
|
|
||||||
ref: "App",
|
|
||||||
})
|
|
||||||
export type Info = z.infer<typeof Info>
|
|
||||||
|
|
||||||
const ctx = Context.create<{
|
|
||||||
info: Info
|
|
||||||
services: Map<any, { state: any; shutdown?: (input: any) => Promise<void> }>
|
|
||||||
}>("app")
|
|
||||||
|
|
||||||
export const use = ctx.use
|
|
||||||
|
|
||||||
const APP_JSON = "app.json"
|
|
||||||
|
|
||||||
export type Input = {
|
|
||||||
cwd: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export const provideExisting = ctx.provide
|
|
||||||
export async function provide<T>(input: Input, cb: (app: App.Info) => Promise<T>) {
|
|
||||||
log.info("creating", {
|
|
||||||
cwd: input.cwd,
|
|
||||||
})
|
|
||||||
const git = await Filesystem.findUp(".git", input.cwd).then(([x]) => (x ? path.dirname(x) : undefined))
|
|
||||||
log.info("git", { git })
|
|
||||||
|
|
||||||
const data = path.join(Global.Path.data, "project", git ? directory(git) : "global")
|
|
||||||
const stateFile = Bun.file(path.join(data, APP_JSON))
|
|
||||||
const state = (await stateFile.json().catch(() => ({}))) as {
|
|
||||||
initialized: number
|
|
||||||
}
|
|
||||||
await stateFile.write(JSON.stringify(state))
|
|
||||||
|
|
||||||
const services = new Map<
|
|
||||||
any,
|
|
||||||
{
|
|
||||||
state: any
|
|
||||||
shutdown?: (input: any) => Promise<void>
|
|
||||||
}
|
|
||||||
>()
|
|
||||||
|
|
||||||
const root = git ?? input.cwd
|
|
||||||
|
|
||||||
const info: Info = {
|
|
||||||
hostname: os.hostname(),
|
|
||||||
time: {
|
|
||||||
initialized: state.initialized,
|
|
||||||
},
|
|
||||||
git: git !== undefined,
|
|
||||||
path: {
|
|
||||||
home: os.homedir(),
|
|
||||||
config: Global.Path.config,
|
|
||||||
state: Global.Path.state,
|
|
||||||
data,
|
|
||||||
root,
|
|
||||||
cwd: input.cwd,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
const app = {
|
|
||||||
services,
|
|
||||||
info,
|
|
||||||
}
|
|
||||||
|
|
||||||
return ctx.provide(app, async () => {
|
|
||||||
try {
|
|
||||||
const result = await cb(app.info)
|
|
||||||
return result
|
|
||||||
} finally {
|
|
||||||
for (const [key, entry] of app.services.entries()) {
|
|
||||||
if (!entry.shutdown) continue
|
|
||||||
log.info("shutdown", { name: key })
|
|
||||||
await entry.shutdown?.(await entry.state)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
export function state<State>(
|
|
||||||
key: any,
|
|
||||||
init: (app: Info) => State,
|
|
||||||
shutdown?: (state: Awaited<State>) => Promise<void>,
|
|
||||||
) {
|
|
||||||
return () => {
|
|
||||||
const app = ctx.use()
|
|
||||||
const services = app.services
|
|
||||||
if (!services.has(key)) {
|
|
||||||
log.info("registering service", { name: key })
|
|
||||||
services.set(key, {
|
|
||||||
state: init(app.info),
|
|
||||||
shutdown,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return services.get(key)?.state as State
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function info() {
|
|
||||||
return ctx.use().info
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function initialize() {
|
|
||||||
const { info } = ctx.use()
|
|
||||||
info.time.initialized = Date.now()
|
|
||||||
await Bun.write(
|
|
||||||
path.join(info.path.data, APP_JSON),
|
|
||||||
JSON.stringify({
|
|
||||||
initialized: Date.now(),
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
function directory(input: string): string {
|
|
||||||
return input
|
|
||||||
.split(path.sep)
|
|
||||||
.filter(Boolean)
|
|
||||||
.join("-")
|
|
||||||
.replace(/[^A-Za-z0-9_]/g, "-")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,12 +1,12 @@
|
|||||||
import { z, type ZodType } from "zod"
|
import { z, type ZodType } from "zod"
|
||||||
import { App } from "../app/app"
|
|
||||||
import { Log } from "../util/log"
|
import { Log } from "../util/log"
|
||||||
|
import { Instance } from "../project/instance"
|
||||||
|
|
||||||
export namespace Bus {
|
export namespace Bus {
|
||||||
const log = Log.create({ service: "bus" })
|
const log = Log.create({ service: "bus" })
|
||||||
type Subscription = (event: any) => void
|
type Subscription = (event: any) => void
|
||||||
|
|
||||||
const state = App.state("bus", () => {
|
const state = Instance.state(() => {
|
||||||
const subscriptions = new Map<any, Subscription[]>()
|
const subscriptions = new Map<any, Subscription[]>()
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -1,20 +1,19 @@
|
|||||||
import { App } from "../app/app"
|
|
||||||
import { ConfigHooks } from "../config/hooks"
|
|
||||||
import { Format } from "../format"
|
import { Format } from "../format"
|
||||||
import { LSP } from "../lsp"
|
import { LSP } from "../lsp"
|
||||||
import { Plugin } from "../plugin"
|
import { Plugin } from "../plugin"
|
||||||
|
import { Instance } from "../project/instance"
|
||||||
import { Share } from "../share/share"
|
import { Share } from "../share/share"
|
||||||
import { Snapshot } from "../snapshot"
|
import { Snapshot } from "../snapshot"
|
||||||
|
|
||||||
export async function bootstrap<T>(input: App.Input, cb: (app: App.Info) => Promise<T>) {
|
export async function bootstrap<T>(directory: string, cb: () => Promise<T>) {
|
||||||
return App.provide(input, async (app) => {
|
return Instance.provide(directory, async () => {
|
||||||
await Plugin.init()
|
await Plugin.init()
|
||||||
Share.init()
|
Share.init()
|
||||||
Format.init()
|
Format.init()
|
||||||
ConfigHooks.init()
|
|
||||||
LSP.init()
|
LSP.init()
|
||||||
Snapshot.init()
|
Snapshot.init()
|
||||||
|
const result = await cb()
|
||||||
return cb(app)
|
await Instance.dispose()
|
||||||
|
return result
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,25 +5,26 @@ import { Global } from "../../global"
|
|||||||
import { Agent } from "../../agent/agent"
|
import { Agent } from "../../agent/agent"
|
||||||
import path from "path"
|
import path from "path"
|
||||||
import matter from "gray-matter"
|
import matter from "gray-matter"
|
||||||
import { App } from "../../app/app"
|
import { Instance } from "../../project/instance"
|
||||||
|
|
||||||
const AgentCreateCommand = cmd({
|
const AgentCreateCommand = cmd({
|
||||||
command: "create",
|
command: "create",
|
||||||
describe: "create a new agent",
|
describe: "create a new agent",
|
||||||
async handler() {
|
async handler() {
|
||||||
await App.provide({ cwd: process.cwd() }, async (app) => {
|
await Instance.provide(process.cwd(), async () => {
|
||||||
UI.empty()
|
UI.empty()
|
||||||
prompts.intro("Create agent")
|
prompts.intro("Create agent")
|
||||||
|
const project = Instance.project
|
||||||
|
|
||||||
let scope: "global" | "project" = "global"
|
let scope: "global" | "project" = "global"
|
||||||
if (app.git) {
|
if (project.vcs === "git") {
|
||||||
const scopeResult = await prompts.select({
|
const scopeResult = await prompts.select({
|
||||||
message: "Location",
|
message: "Location",
|
||||||
options: [
|
options: [
|
||||||
{
|
{
|
||||||
label: "Current project",
|
label: "Current project",
|
||||||
value: "project" as const,
|
value: "project" as const,
|
||||||
hint: app.path.root,
|
hint: Instance.worktree,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "Global",
|
label: "Global",
|
||||||
@@ -116,7 +117,7 @@ const AgentCreateCommand = cmd({
|
|||||||
|
|
||||||
const content = matter.stringify(generated.systemPrompt, frontmatter)
|
const content = matter.stringify(generated.systemPrompt, frontmatter)
|
||||||
const filePath = path.join(
|
const filePath = path.join(
|
||||||
scope === "global" ? Global.Path.config : path.join(app.path.root, ".opencode"),
|
scope === "global" ? Global.Path.config : path.join(Instance.worktree, ".opencode"),
|
||||||
`agent`,
|
`agent`,
|
||||||
`${generated.identifier}.md`,
|
`${generated.identifier}.md`,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import path from "path"
|
|||||||
import os from "os"
|
import os from "os"
|
||||||
import { Global } from "../../global"
|
import { Global } from "../../global"
|
||||||
import { Plugin } from "../../plugin"
|
import { Plugin } from "../../plugin"
|
||||||
import { App } from "../../app/app"
|
import { Instance } from "../../project/instance"
|
||||||
|
|
||||||
export const AuthCommand = cmd({
|
export const AuthCommand = cmd({
|
||||||
command: "auth",
|
command: "auth",
|
||||||
@@ -74,7 +74,7 @@ export const AuthLoginCommand = cmd({
|
|||||||
type: "string",
|
type: "string",
|
||||||
}),
|
}),
|
||||||
async handler(args) {
|
async handler(args) {
|
||||||
await App.provide({ cwd: process.cwd() }, async () => {
|
await Instance.provide(process.cwd(), async () => {
|
||||||
UI.empty()
|
UI.empty()
|
||||||
prompts.intro("Add credential")
|
prompts.intro("Add credential")
|
||||||
if (args.url) {
|
if (args.url) {
|
||||||
|
|||||||
@@ -1,20 +0,0 @@
|
|||||||
import { App } from "../../../app/app"
|
|
||||||
import { bootstrap } from "../../bootstrap"
|
|
||||||
import { cmd } from "../cmd"
|
|
||||||
|
|
||||||
const AppInfoCommand = cmd({
|
|
||||||
command: "info",
|
|
||||||
builder: (yargs) => yargs,
|
|
||||||
async handler() {
|
|
||||||
await bootstrap({ cwd: process.cwd() }, async () => {
|
|
||||||
const app = App.info()
|
|
||||||
console.log(JSON.stringify(app, null, 2))
|
|
||||||
})
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
export const AppCommand = cmd({
|
|
||||||
command: "app",
|
|
||||||
builder: (yargs) => yargs.command(AppInfoCommand).demandCommand(),
|
|
||||||
async handler() {},
|
|
||||||
})
|
|
||||||
@@ -11,7 +11,7 @@ const FileReadCommand = cmd({
|
|||||||
description: "File path to read",
|
description: "File path to read",
|
||||||
}),
|
}),
|
||||||
async handler(args) {
|
async handler(args) {
|
||||||
await bootstrap({ cwd: process.cwd() }, async () => {
|
await bootstrap(process.cwd(), async () => {
|
||||||
const content = await File.read(args.path)
|
const content = await File.read(args.path)
|
||||||
console.log(content)
|
console.log(content)
|
||||||
})
|
})
|
||||||
@@ -22,7 +22,7 @@ const FileStatusCommand = cmd({
|
|||||||
command: "status",
|
command: "status",
|
||||||
builder: (yargs) => yargs,
|
builder: (yargs) => yargs,
|
||||||
async handler() {
|
async handler() {
|
||||||
await bootstrap({ cwd: process.cwd() }, async () => {
|
await bootstrap(process.cwd(), async () => {
|
||||||
const status = await File.status()
|
const status = await File.status()
|
||||||
console.log(JSON.stringify(status, null, 2))
|
console.log(JSON.stringify(status, null, 2))
|
||||||
})
|
})
|
||||||
@@ -38,7 +38,7 @@ const FileListCommand = cmd({
|
|||||||
description: "File path to list",
|
description: "File path to list",
|
||||||
}),
|
}),
|
||||||
async handler(args) {
|
async handler(args) {
|
||||||
await bootstrap({ cwd: process.cwd() }, async () => {
|
await bootstrap(process.cwd(), async () => {
|
||||||
const files = await File.list(args.path)
|
const files = await File.list(args.path)
|
||||||
console.log(JSON.stringify(files, null, 2))
|
console.log(JSON.stringify(files, null, 2))
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import { Global } from "../../../global"
|
import { Global } from "../../../global"
|
||||||
import { bootstrap } from "../../bootstrap"
|
import { bootstrap } from "../../bootstrap"
|
||||||
import { cmd } from "../cmd"
|
import { cmd } from "../cmd"
|
||||||
import { AppCommand } from "./app"
|
|
||||||
import { FileCommand } from "./file"
|
import { FileCommand } from "./file"
|
||||||
import { LSPCommand } from "./lsp"
|
import { LSPCommand } from "./lsp"
|
||||||
import { RipgrepCommand } from "./ripgrep"
|
import { RipgrepCommand } from "./ripgrep"
|
||||||
@@ -12,7 +11,6 @@ export const DebugCommand = cmd({
|
|||||||
command: "debug",
|
command: "debug",
|
||||||
builder: (yargs) =>
|
builder: (yargs) =>
|
||||||
yargs
|
yargs
|
||||||
.command(AppCommand)
|
|
||||||
.command(LSPCommand)
|
.command(LSPCommand)
|
||||||
.command(RipgrepCommand)
|
.command(RipgrepCommand)
|
||||||
.command(FileCommand)
|
.command(FileCommand)
|
||||||
@@ -22,7 +20,7 @@ export const DebugCommand = cmd({
|
|||||||
.command({
|
.command({
|
||||||
command: "wait",
|
command: "wait",
|
||||||
async handler() {
|
async handler() {
|
||||||
await bootstrap({ cwd: process.cwd() }, async () => {
|
await bootstrap(process.cwd(), async () => {
|
||||||
await new Promise((resolve) => setTimeout(resolve, 1_000 * 60 * 60 * 24))
|
await new Promise((resolve) => setTimeout(resolve, 1_000 * 60 * 60 * 24))
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ const DiagnosticsCommand = cmd({
|
|||||||
command: "diagnostics <file>",
|
command: "diagnostics <file>",
|
||||||
builder: (yargs) => yargs.positional("file", { type: "string", demandOption: true }),
|
builder: (yargs) => yargs.positional("file", { type: "string", demandOption: true }),
|
||||||
async handler(args) {
|
async handler(args) {
|
||||||
await bootstrap({ cwd: process.cwd() }, async () => {
|
await bootstrap(process.cwd(), async () => {
|
||||||
await LSP.touchFile(args.file, true)
|
await LSP.touchFile(args.file, true)
|
||||||
console.log(JSON.stringify(await LSP.diagnostics(), null, 2))
|
console.log(JSON.stringify(await LSP.diagnostics(), null, 2))
|
||||||
})
|
})
|
||||||
@@ -25,7 +25,7 @@ export const SymbolsCommand = cmd({
|
|||||||
command: "symbols <query>",
|
command: "symbols <query>",
|
||||||
builder: (yargs) => yargs.positional("query", { type: "string", demandOption: true }),
|
builder: (yargs) => yargs.positional("query", { type: "string", demandOption: true }),
|
||||||
async handler(args) {
|
async handler(args) {
|
||||||
await bootstrap({ cwd: process.cwd() }, async () => {
|
await bootstrap(process.cwd(), async () => {
|
||||||
using _ = Log.Default.time("symbols")
|
using _ = Log.Default.time("symbols")
|
||||||
const results = await LSP.workspaceSymbol(args.query)
|
const results = await LSP.workspaceSymbol(args.query)
|
||||||
console.log(JSON.stringify(results, null, 2))
|
console.log(JSON.stringify(results, null, 2))
|
||||||
@@ -37,7 +37,7 @@ export const DocumentSymbolsCommand = cmd({
|
|||||||
command: "document-symbols <uri>",
|
command: "document-symbols <uri>",
|
||||||
builder: (yargs) => yargs.positional("uri", { type: "string", demandOption: true }),
|
builder: (yargs) => yargs.positional("uri", { type: "string", demandOption: true }),
|
||||||
async handler(args) {
|
async handler(args) {
|
||||||
await bootstrap({ cwd: process.cwd() }, async () => {
|
await bootstrap(process.cwd(), async () => {
|
||||||
using _ = Log.Default.time("document-symbols")
|
using _ = Log.Default.time("document-symbols")
|
||||||
const results = await LSP.documentSymbol(args.uri)
|
const results = await LSP.documentSymbol(args.uri)
|
||||||
console.log(JSON.stringify(results, null, 2))
|
console.log(JSON.stringify(results, null, 2))
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { App } from "../../../app/app"
|
|
||||||
import { Ripgrep } from "../../../file/ripgrep"
|
import { Ripgrep } from "../../../file/ripgrep"
|
||||||
|
import { Instance } from "../../../project/instance"
|
||||||
import { bootstrap } from "../../bootstrap"
|
import { bootstrap } from "../../bootstrap"
|
||||||
import { cmd } from "../cmd"
|
import { cmd } from "../cmd"
|
||||||
|
|
||||||
@@ -16,9 +16,8 @@ const TreeCommand = cmd({
|
|||||||
type: "number",
|
type: "number",
|
||||||
}),
|
}),
|
||||||
async handler(args) {
|
async handler(args) {
|
||||||
await bootstrap({ cwd: process.cwd() }, async () => {
|
await bootstrap(process.cwd(), async () => {
|
||||||
const app = App.info()
|
console.log(await Ripgrep.tree({ cwd: Instance.directory, limit: args.limit }))
|
||||||
console.log(await Ripgrep.tree({ cwd: app.path.cwd, limit: args.limit }))
|
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
@@ -40,10 +39,9 @@ const FilesCommand = cmd({
|
|||||||
description: "Limit number of results",
|
description: "Limit number of results",
|
||||||
}),
|
}),
|
||||||
async handler(args) {
|
async handler(args) {
|
||||||
await bootstrap({ cwd: process.cwd() }, async () => {
|
await bootstrap(process.cwd(), async () => {
|
||||||
const app = App.info()
|
|
||||||
const files = await Ripgrep.files({
|
const files = await Ripgrep.files({
|
||||||
cwd: app.path.cwd,
|
cwd: Instance.directory,
|
||||||
query: args.query,
|
query: args.query,
|
||||||
glob: args.glob ? [args.glob] : undefined,
|
glob: args.glob ? [args.glob] : undefined,
|
||||||
limit: args.limit,
|
limit: args.limit,
|
||||||
|
|||||||
@@ -1,7 +1,14 @@
|
|||||||
|
import { Project } from "../../../project/project"
|
||||||
|
import { Log } from "../../../util/log"
|
||||||
import { cmd } from "../cmd"
|
import { cmd } from "../cmd"
|
||||||
|
|
||||||
export const ScrapCommand = cmd({
|
export const ScrapCommand = cmd({
|
||||||
command: "scrap",
|
command: "scrap",
|
||||||
builder: (yargs) => yargs,
|
builder: (yargs) => yargs,
|
||||||
async handler() {},
|
async handler() {
|
||||||
|
const timer = Log.Default.time("scrap")
|
||||||
|
const list = await Project.list()
|
||||||
|
console.log(list)
|
||||||
|
timer.stop()
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ export const SnapshotCommand = cmd({
|
|||||||
const TrackCommand = cmd({
|
const TrackCommand = cmd({
|
||||||
command: "track",
|
command: "track",
|
||||||
async handler() {
|
async handler() {
|
||||||
await bootstrap({ cwd: process.cwd() }, async () => {
|
await bootstrap(process.cwd(), async () => {
|
||||||
console.log(await Snapshot.track())
|
console.log(await Snapshot.track())
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
@@ -26,7 +26,7 @@ const PatchCommand = cmd({
|
|||||||
demandOption: true,
|
demandOption: true,
|
||||||
}),
|
}),
|
||||||
async handler(args) {
|
async handler(args) {
|
||||||
await bootstrap({ cwd: process.cwd() }, async () => {
|
await bootstrap(process.cwd(), async () => {
|
||||||
console.log(await Snapshot.patch(args.hash))
|
console.log(await Snapshot.patch(args.hash))
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
@@ -41,7 +41,7 @@ const DiffCommand = cmd({
|
|||||||
demandOption: true,
|
demandOption: true,
|
||||||
}),
|
}),
|
||||||
async handler(args) {
|
async handler(args) {
|
||||||
await bootstrap({ cwd: process.cwd() }, async () => {
|
await bootstrap(process.cwd(), async () => {
|
||||||
console.log(await Snapshot.diff(args.hash))
|
console.log(await Snapshot.diff(args.hash))
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|||||||
76
packages/opencode/src/cli/cmd/export.ts
Normal file
76
packages/opencode/src/cli/cmd/export.ts
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
import type { Argv } from "yargs"
|
||||||
|
import { Session } from "../../session"
|
||||||
|
import { cmd } from "./cmd"
|
||||||
|
import { bootstrap } from "../bootstrap"
|
||||||
|
import { UI } from "../ui"
|
||||||
|
import * as prompts from "@clack/prompts"
|
||||||
|
|
||||||
|
export const ExportCommand = cmd({
|
||||||
|
command: "export [sessionID]",
|
||||||
|
describe: "export session data as JSON",
|
||||||
|
builder: (yargs: Argv) => {
|
||||||
|
return yargs.positional("sessionID", {
|
||||||
|
describe: "session id to export",
|
||||||
|
type: "string",
|
||||||
|
})
|
||||||
|
},
|
||||||
|
handler: async (args) => {
|
||||||
|
await bootstrap(process.cwd(), async () => {
|
||||||
|
let sessionID = args.sessionID
|
||||||
|
|
||||||
|
if (!sessionID) {
|
||||||
|
UI.empty()
|
||||||
|
prompts.intro("Export session")
|
||||||
|
|
||||||
|
const sessions = []
|
||||||
|
for await (const session of Session.list()) {
|
||||||
|
sessions.push(session)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sessions.length === 0) {
|
||||||
|
prompts.log.error("No sessions found")
|
||||||
|
prompts.outro("Done")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
sessions.sort((a, b) => b.time.updated - a.time.updated)
|
||||||
|
|
||||||
|
const selectedSession = await prompts.autocomplete({
|
||||||
|
message: "Select session to export",
|
||||||
|
maxItems: 10,
|
||||||
|
options: sessions.map((session) => ({
|
||||||
|
label: session.title,
|
||||||
|
value: session.id,
|
||||||
|
hint: `${new Date(session.time.updated).toLocaleString()} • ${session.id.slice(-8)}`,
|
||||||
|
})),
|
||||||
|
})
|
||||||
|
|
||||||
|
if (prompts.isCancel(selectedSession)) {
|
||||||
|
throw new UI.CancelledError()
|
||||||
|
}
|
||||||
|
|
||||||
|
sessionID = selectedSession as string
|
||||||
|
|
||||||
|
prompts.outro("Exporting session...")
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const sessionInfo = await Session.get(sessionID!)
|
||||||
|
const messages = await Session.messages(sessionID!)
|
||||||
|
|
||||||
|
const exportData = {
|
||||||
|
info: sessionInfo,
|
||||||
|
messages: messages.map((msg) => ({
|
||||||
|
info: msg.info,
|
||||||
|
parts: msg.parts,
|
||||||
|
})),
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(JSON.stringify(exportData, null, 2))
|
||||||
|
} catch (error) {
|
||||||
|
UI.error(`Session not found: ${sessionID!}`)
|
||||||
|
process.exit(1)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
})
|
||||||
@@ -6,7 +6,7 @@ import { map, pipe, sortBy, values } from "remeda"
|
|||||||
import { UI } from "../ui"
|
import { UI } from "../ui"
|
||||||
import { cmd } from "./cmd"
|
import { cmd } from "./cmd"
|
||||||
import { ModelsDev } from "../../provider/models"
|
import { ModelsDev } from "../../provider/models"
|
||||||
import { App } from "../../app/app"
|
import { Instance } from "../../project/instance"
|
||||||
|
|
||||||
const WORKFLOW_FILE = ".github/workflows/opencode.yml"
|
const WORKFLOW_FILE = ".github/workflows/opencode.yml"
|
||||||
|
|
||||||
@@ -21,7 +21,7 @@ export const GithubInstallCommand = cmd({
|
|||||||
command: "install",
|
command: "install",
|
||||||
describe: "install the GitHub agent",
|
describe: "install the GitHub agent",
|
||||||
async handler() {
|
async handler() {
|
||||||
await App.provide({ cwd: process.cwd() }, async () => {
|
await Instance.provide(process.cwd(), async () => {
|
||||||
UI.empty()
|
UI.empty()
|
||||||
prompts.intro("Install GitHub agent")
|
prompts.intro("Install GitHub agent")
|
||||||
const app = await getAppInfo()
|
const app = await getAppInfo()
|
||||||
@@ -63,8 +63,8 @@ export const GithubInstallCommand = cmd({
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function getAppInfo() {
|
async function getAppInfo() {
|
||||||
const app = App.info()
|
const project = Instance.project
|
||||||
if (!app.git) {
|
if (project.vcs !== "git") {
|
||||||
prompts.log.error(`Could not find git repository. Please run this command from a git repository.`)
|
prompts.log.error(`Could not find git repository. Please run this command from a git repository.`)
|
||||||
throw new UI.CancelledError()
|
throw new UI.CancelledError()
|
||||||
}
|
}
|
||||||
@@ -88,7 +88,7 @@ export const GithubInstallCommand = cmd({
|
|||||||
throw new UI.CancelledError()
|
throw new UI.CancelledError()
|
||||||
}
|
}
|
||||||
const [, owner, repo] = parsed
|
const [, owner, repo] = parsed
|
||||||
return { owner, repo, root: app.path.root }
|
return { owner, repo, root: Instance.worktree }
|
||||||
}
|
}
|
||||||
|
|
||||||
async function promptProvider() {
|
async function promptProvider() {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { App } from "../../app/app"
|
import { Instance } from "../../project/instance"
|
||||||
import { Provider } from "../../provider/provider"
|
import { Provider } from "../../provider/provider"
|
||||||
import { cmd } from "./cmd"
|
import { cmd } from "./cmd"
|
||||||
|
|
||||||
@@ -6,7 +6,7 @@ export const ModelsCommand = cmd({
|
|||||||
command: "models",
|
command: "models",
|
||||||
describe: "list all available models",
|
describe: "list all available models",
|
||||||
handler: async () => {
|
handler: async () => {
|
||||||
await App.provide({ cwd: process.cwd() }, async () => {
|
await Instance.provide(process.cwd(), async () => {
|
||||||
const providers = await Provider.list()
|
const providers = await Provider.list()
|
||||||
|
|
||||||
for (const [providerID, provider] of Object.entries(providers)) {
|
for (const [providerID, provider] of Object.entries(providers)) {
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ export const RunCommand = cmd({
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
await bootstrap({ cwd: process.cwd() }, async () => {
|
await bootstrap(process.cwd(), async () => {
|
||||||
if (args.command) {
|
if (args.command) {
|
||||||
const exists = await Command.get(args.command)
|
const exists = await Command.get(args.command)
|
||||||
if (!exists) {
|
if (!exists) {
|
||||||
@@ -82,7 +82,6 @@ export const RunCommand = cmd({
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const session = await (async () => {
|
const session = await (async () => {
|
||||||
if (args.continue) {
|
if (args.continue) {
|
||||||
const it = Session.list()
|
const it = Session.list()
|
||||||
@@ -198,11 +197,13 @@ export const RunCommand = cmd({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const messageID = Identifier.ascending("message")
|
const messageID = Identifier.ascending("message")
|
||||||
const result = await Session.chat({
|
const result = await Session.prompt({
|
||||||
sessionID: session.id,
|
sessionID: session.id,
|
||||||
messageID,
|
messageID,
|
||||||
providerID,
|
model: {
|
||||||
modelID,
|
providerID,
|
||||||
|
modelID,
|
||||||
|
},
|
||||||
agent: agent.name,
|
agent: agent.name,
|
||||||
parts: [
|
parts: [
|
||||||
{
|
{
|
||||||
@@ -215,7 +216,7 @@ export const RunCommand = cmd({
|
|||||||
|
|
||||||
const isPiped = !process.stdout.isTTY
|
const isPiped = !process.stdout.isTTY
|
||||||
if (isPiped) {
|
if (isPiped) {
|
||||||
const match = result.parts.findLast((x) => x.type === "text")
|
const match = result.parts.findLast((x: any) => x.type === "text") as any
|
||||||
if (match) process.stdout.write(UI.markdown(match.text))
|
if (match) process.stdout.write(UI.markdown(match.text))
|
||||||
if (errorMsg) process.stdout.write(errorMsg)
|
if (errorMsg) process.stdout.write(errorMsg)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
import { Provider } from "../../provider/provider"
|
|
||||||
import { Server } from "../../server/server"
|
import { Server } from "../../server/server"
|
||||||
import { bootstrap } from "../bootstrap"
|
|
||||||
import { cmd } from "./cmd"
|
import { cmd } from "./cmd"
|
||||||
|
|
||||||
export const ServeCommand = cmd({
|
export const ServeCommand = cmd({
|
||||||
@@ -21,26 +19,14 @@ export const ServeCommand = cmd({
|
|||||||
}),
|
}),
|
||||||
describe: "starts a headless opencode server",
|
describe: "starts a headless opencode server",
|
||||||
handler: async (args) => {
|
handler: async (args) => {
|
||||||
const cwd = process.cwd()
|
const hostname = args.hostname
|
||||||
await bootstrap({ cwd }, async () => {
|
const port = args.port
|
||||||
const providers = await Provider.list()
|
const server = Server.listen({
|
||||||
if (Object.keys(providers).length === 0) {
|
port,
|
||||||
return "needs_provider"
|
hostname,
|
||||||
}
|
|
||||||
|
|
||||||
const hostname = args.hostname
|
|
||||||
const port = args.port
|
|
||||||
|
|
||||||
const server = Server.listen({
|
|
||||||
port,
|
|
||||||
hostname,
|
|
||||||
})
|
|
||||||
|
|
||||||
console.log(`opencode server listening on http://${server.hostname}:${server.port}`)
|
|
||||||
|
|
||||||
await new Promise(() => {})
|
|
||||||
|
|
||||||
server.stop()
|
|
||||||
})
|
})
|
||||||
|
console.log(`opencode server listening on http://${server.hostname}:${server.port}`)
|
||||||
|
await new Promise(() => {})
|
||||||
|
server.stop()
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import { Ide } from "../../ide"
|
|||||||
|
|
||||||
import { Flag } from "../../flag/flag"
|
import { Flag } from "../../flag/flag"
|
||||||
import { Session } from "../../session"
|
import { Session } from "../../session"
|
||||||
|
import { Instance } from "../../project/instance"
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
const OPENCODE_TUI_PATH: string
|
const OPENCODE_TUI_PATH: string
|
||||||
@@ -79,7 +80,7 @@ export const TuiCommand = cmd({
|
|||||||
UI.error("Failed to change directory to " + cwd)
|
UI.error("Failed to change directory to " + cwd)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const result = await bootstrap({ cwd }, async (app) => {
|
const result = await bootstrap(cwd, async () => {
|
||||||
const sessionID = await (async () => {
|
const sessionID = await (async () => {
|
||||||
if (args.continue) {
|
if (args.continue) {
|
||||||
const it = Session.list()
|
const it = Session.list()
|
||||||
@@ -146,7 +147,7 @@ export const TuiCommand = cmd({
|
|||||||
...process.env,
|
...process.env,
|
||||||
CGO_ENABLED: "0",
|
CGO_ENABLED: "0",
|
||||||
OPENCODE_SERVER: server.url.toString(),
|
OPENCODE_SERVER: server.url.toString(),
|
||||||
OPENCODE_APP_INFO: JSON.stringify(app),
|
OPENCODE_PROJECT: JSON.stringify(Instance.project),
|
||||||
},
|
},
|
||||||
onExit: () => {
|
onExit: () => {
|
||||||
server.stop()
|
server.stop()
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import z from "zod"
|
import z from "zod"
|
||||||
import { App } from "../app/app"
|
|
||||||
import { Config } from "../config/config"
|
import { Config } from "../config/config"
|
||||||
|
import { Instance } from "../project/instance"
|
||||||
|
|
||||||
export namespace Command {
|
export namespace Command {
|
||||||
export const Info = z
|
export const Info = z
|
||||||
@@ -16,7 +16,7 @@ export namespace Command {
|
|||||||
})
|
})
|
||||||
export type Info = z.infer<typeof Info>
|
export type Info = z.infer<typeof Info>
|
||||||
|
|
||||||
const state = App.state("command", async () => {
|
const state = Instance.state(async () => {
|
||||||
const cfg = await Config.get()
|
const cfg = await Config.get()
|
||||||
|
|
||||||
const result: Record<string, Info> = {}
|
const result: Record<string, Info> = {}
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ import { Log } from "../util/log"
|
|||||||
import path from "path"
|
import path from "path"
|
||||||
import os from "os"
|
import os from "os"
|
||||||
import { z } from "zod"
|
import { z } from "zod"
|
||||||
import { App } from "../app/app"
|
|
||||||
import { Filesystem } from "../util/filesystem"
|
import { Filesystem } from "../util/filesystem"
|
||||||
import { ModelsDev } from "../provider/models"
|
import { ModelsDev } from "../provider/models"
|
||||||
import { mergeDeep, pipe } from "remeda"
|
import { mergeDeep, pipe } from "remeda"
|
||||||
@@ -14,15 +13,16 @@ import matter from "gray-matter"
|
|||||||
import { Flag } from "../flag/flag"
|
import { Flag } from "../flag/flag"
|
||||||
import { Auth } from "../auth"
|
import { Auth } from "../auth"
|
||||||
import { type ParseError as JsoncParseError, parse as parseJsonc, printParseErrorCode } from "jsonc-parser"
|
import { type ParseError as JsoncParseError, parse as parseJsonc, printParseErrorCode } from "jsonc-parser"
|
||||||
|
import { Instance } from "../project/instance"
|
||||||
|
|
||||||
export namespace Config {
|
export namespace Config {
|
||||||
const log = Log.create({ service: "config" })
|
const log = Log.create({ service: "config" })
|
||||||
|
|
||||||
export const state = App.state("config", async (app) => {
|
export const state = Instance.state(async () => {
|
||||||
const auth = await Auth.all()
|
const auth = await Auth.all()
|
||||||
let result = await global()
|
let result = await global()
|
||||||
for (const file of ["opencode.jsonc", "opencode.json"]) {
|
for (const file of ["opencode.jsonc", "opencode.json"]) {
|
||||||
const found = await Filesystem.findUp(file, app.path.cwd, app.path.root)
|
const found = await Filesystem.findUp(file, Instance.directory, Instance.worktree)
|
||||||
for (const resolved of found.toReversed()) {
|
for (const resolved of found.toReversed()) {
|
||||||
result = mergeDeep(result, await loadFile(resolved))
|
result = mergeDeep(result, await loadFile(resolved))
|
||||||
}
|
}
|
||||||
@@ -45,7 +45,7 @@ export namespace Config {
|
|||||||
result.agent = result.agent || {}
|
result.agent = result.agent || {}
|
||||||
const markdownAgents = [
|
const markdownAgents = [
|
||||||
...(await Filesystem.globUp("agent/**/*.md", Global.Path.config, Global.Path.config)),
|
...(await Filesystem.globUp("agent/**/*.md", Global.Path.config, Global.Path.config)),
|
||||||
...(await Filesystem.globUp(".opencode/agent/**/*.md", app.path.cwd, app.path.root)),
|
...(await Filesystem.globUp(".opencode/agent/*.md", Instance.directory, Instance.worktree)),
|
||||||
]
|
]
|
||||||
for (const item of markdownAgents) {
|
for (const item of markdownAgents) {
|
||||||
const content = await Bun.file(item).text()
|
const content = await Bun.file(item).text()
|
||||||
@@ -86,7 +86,7 @@ export namespace Config {
|
|||||||
result.mode = result.mode || {}
|
result.mode = result.mode || {}
|
||||||
const markdownModes = [
|
const markdownModes = [
|
||||||
...(await Filesystem.globUp("mode/*.md", Global.Path.config, Global.Path.config)),
|
...(await Filesystem.globUp("mode/*.md", Global.Path.config, Global.Path.config)),
|
||||||
...(await Filesystem.globUp(".opencode/mode/*.md", app.path.cwd, app.path.root)),
|
...(await Filesystem.globUp(".opencode/mode/*.md", Instance.directory, Instance.worktree)),
|
||||||
]
|
]
|
||||||
for (const item of markdownModes) {
|
for (const item of markdownModes) {
|
||||||
const content = await Bun.file(item).text()
|
const content = await Bun.file(item).text()
|
||||||
@@ -100,19 +100,21 @@ export namespace Config {
|
|||||||
}
|
}
|
||||||
const parsed = Agent.safeParse(config)
|
const parsed = Agent.safeParse(config)
|
||||||
if (parsed.success) {
|
if (parsed.success) {
|
||||||
result.mode = mergeDeep(result.mode, {
|
result.agent = mergeDeep(result.mode, {
|
||||||
[config.name]: parsed.data,
|
[config.name]: {
|
||||||
|
...parsed.data,
|
||||||
|
mode: "primary" as const,
|
||||||
|
},
|
||||||
})
|
})
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
throw new InvalidError({ path: item }, { cause: parsed.error })
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load command markdown files
|
// Load command markdown files
|
||||||
result.command = result.command || {}
|
result.command = result.command || {}
|
||||||
const markdownCommands = [
|
const markdownCommands = [
|
||||||
...(await Filesystem.globUp("command/*.md", Global.Path.config, Global.Path.config)),
|
...(await Filesystem.globUp("command/*.md", Global.Path.config, Global.Path.config)),
|
||||||
...(await Filesystem.globUp(".opencode/command/*.md", app.path.cwd, app.path.root)),
|
...(await Filesystem.globUp(".opencode/command/*.md", Instance.directory, Instance.worktree)),
|
||||||
]
|
]
|
||||||
for (const item of markdownCommands) {
|
for (const item of markdownCommands) {
|
||||||
const content = await Bun.file(item).text()
|
const content = await Bun.file(item).text()
|
||||||
@@ -147,7 +149,7 @@ export namespace Config {
|
|||||||
result.plugin.push(
|
result.plugin.push(
|
||||||
...[
|
...[
|
||||||
...(await Filesystem.globUp("plugin/*.{ts,js}", Global.Path.config, Global.Path.config)),
|
...(await Filesystem.globUp("plugin/*.{ts,js}", Global.Path.config, Global.Path.config)),
|
||||||
...(await Filesystem.globUp(".opencode/plugin/*.{ts,js}", app.path.cwd, app.path.root)),
|
...(await Filesystem.globUp(".opencode/plugin/*.{ts,js}", Instance.directory, Instance.worktree)),
|
||||||
].map((x) => "file://" + x),
|
].map((x) => "file://" + x),
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -155,6 +157,16 @@ export namespace Config {
|
|||||||
result.permission = mergeDeep(result.permission ?? {}, JSON.parse(Flag.OPENCODE_PERMISSION))
|
result.permission = mergeDeep(result.permission ?? {}, JSON.parse(Flag.OPENCODE_PERMISSION))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!result.username) result.username = os.userInfo().username
|
||||||
|
|
||||||
|
// Handle migration from autoshare to share field
|
||||||
|
if (result.autoshare === true && !result.share) {
|
||||||
|
result.share = "auto"
|
||||||
|
}
|
||||||
|
if (result.keybinds?.messages_revert && !result.keybinds.messages_undo) {
|
||||||
|
result.keybinds.messages_undo = result.keybinds.messages_revert
|
||||||
|
}
|
||||||
|
|
||||||
// Handle migration from autoshare to share field
|
// Handle migration from autoshare to share field
|
||||||
if (result.autoshare === true && !result.share) {
|
if (result.autoshare === true && !result.share) {
|
||||||
result.share = "auto"
|
result.share = "auto"
|
||||||
@@ -175,13 +187,6 @@ export namespace Config {
|
|||||||
result.keybinds.agent_cycle_reverse = result.keybinds.switch_agent_reverse
|
result.keybinds.agent_cycle_reverse = result.keybinds.switch_agent_reverse
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!result.username) {
|
|
||||||
const os = await import("os")
|
|
||||||
result.username = os.userInfo().username
|
|
||||||
}
|
|
||||||
|
|
||||||
log.info("loaded", result)
|
|
||||||
|
|
||||||
return result
|
return result
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -1,56 +0,0 @@
|
|||||||
import { App } from "../app/app"
|
|
||||||
import { Bus } from "../bus"
|
|
||||||
import { File } from "../file"
|
|
||||||
import { Session } from "../session"
|
|
||||||
import { Log } from "../util/log"
|
|
||||||
import { Config } from "./config"
|
|
||||||
import path from "path"
|
|
||||||
|
|
||||||
export namespace ConfigHooks {
|
|
||||||
const log = Log.create({ service: "config.hooks" })
|
|
||||||
|
|
||||||
export function init() {
|
|
||||||
log.info("init")
|
|
||||||
const app = App.info()
|
|
||||||
|
|
||||||
Bus.subscribe(File.Event.Edited, async (payload) => {
|
|
||||||
const cfg = await Config.get()
|
|
||||||
const ext = path.extname(payload.properties.file)
|
|
||||||
for (const item of cfg.experimental?.hook?.file_edited?.[ext] ?? []) {
|
|
||||||
log.info("file_edited", {
|
|
||||||
file: payload.properties.file,
|
|
||||||
command: item.command,
|
|
||||||
})
|
|
||||||
Bun.spawn({
|
|
||||||
cmd: item.command.map((x) => x.replace("$FILE", payload.properties.file)),
|
|
||||||
env: item.environment,
|
|
||||||
cwd: app.path.cwd,
|
|
||||||
stdout: "ignore",
|
|
||||||
stderr: "ignore",
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
Bus.subscribe(Session.Event.Idle, async (payload) => {
|
|
||||||
const cfg = await Config.get()
|
|
||||||
if (cfg.experimental?.hook?.session_completed) {
|
|
||||||
const session = await Session.get(payload.properties.sessionID)
|
|
||||||
// Only fire hook for top-level sessions (not subagent sessions)
|
|
||||||
if (session.parentID) return
|
|
||||||
|
|
||||||
for (const item of cfg.experimental.hook.session_completed) {
|
|
||||||
log.info("session_completed", {
|
|
||||||
command: item.command,
|
|
||||||
})
|
|
||||||
Bun.spawn({
|
|
||||||
cmd: item.command,
|
|
||||||
cwd: App.info().path.cwd,
|
|
||||||
env: item.environment,
|
|
||||||
stdout: "ignore",
|
|
||||||
stderr: "ignore",
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -3,10 +3,10 @@ import { Bus } from "../bus"
|
|||||||
import { $ } from "bun"
|
import { $ } from "bun"
|
||||||
import { createPatch } from "diff"
|
import { createPatch } from "diff"
|
||||||
import path from "path"
|
import path from "path"
|
||||||
import { App } from "../app/app"
|
|
||||||
import fs from "fs"
|
import fs from "fs"
|
||||||
import ignore from "ignore"
|
import ignore from "ignore"
|
||||||
import { Log } from "../util/log"
|
import { Log } from "../util/log"
|
||||||
|
import { Instance } from "../project/instance"
|
||||||
|
|
||||||
export namespace File {
|
export namespace File {
|
||||||
const log = Log.create({ service: "file" })
|
const log = Log.create({ service: "file" })
|
||||||
@@ -46,10 +46,10 @@ export namespace File {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function status() {
|
export async function status() {
|
||||||
const app = App.info()
|
const project = Instance.project
|
||||||
if (!app.git) return []
|
if (project.vcs !== "git") return []
|
||||||
|
|
||||||
const diffOutput = await $`git diff --numstat HEAD`.cwd(app.path.cwd).quiet().nothrow().text()
|
const diffOutput = await $`git diff --numstat HEAD`.cwd(Instance.directory).quiet().nothrow().text()
|
||||||
|
|
||||||
const changedFiles: Info[] = []
|
const changedFiles: Info[] = []
|
||||||
|
|
||||||
@@ -66,13 +66,17 @@ export namespace File {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const untrackedOutput = await $`git ls-files --others --exclude-standard`.cwd(app.path.cwd).quiet().nothrow().text()
|
const untrackedOutput = await $`git ls-files --others --exclude-standard`
|
||||||
|
.cwd(Instance.directory)
|
||||||
|
.quiet()
|
||||||
|
.nothrow()
|
||||||
|
.text()
|
||||||
|
|
||||||
if (untrackedOutput.trim()) {
|
if (untrackedOutput.trim()) {
|
||||||
const untrackedFiles = untrackedOutput.trim().split("\n")
|
const untrackedFiles = untrackedOutput.trim().split("\n")
|
||||||
for (const filepath of untrackedFiles) {
|
for (const filepath of untrackedFiles) {
|
||||||
try {
|
try {
|
||||||
const content = await Bun.file(path.join(app.path.root, filepath)).text()
|
const content = await Bun.file(path.join(Instance.worktree, filepath)).text()
|
||||||
const lines = content.split("\n").length
|
const lines = content.split("\n").length
|
||||||
changedFiles.push({
|
changedFiles.push({
|
||||||
path: filepath,
|
path: filepath,
|
||||||
@@ -87,7 +91,11 @@ export namespace File {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get deleted files
|
// Get deleted files
|
||||||
const deletedOutput = await $`git diff --name-only --diff-filter=D HEAD`.cwd(app.path.cwd).quiet().nothrow().text()
|
const deletedOutput = await $`git diff --name-only --diff-filter=D HEAD`
|
||||||
|
.cwd(Instance.directory)
|
||||||
|
.quiet()
|
||||||
|
.nothrow()
|
||||||
|
.text()
|
||||||
|
|
||||||
if (deletedOutput.trim()) {
|
if (deletedOutput.trim()) {
|
||||||
const deletedFiles = deletedOutput.trim().split("\n")
|
const deletedFiles = deletedOutput.trim().split("\n")
|
||||||
@@ -103,23 +111,23 @@ export namespace File {
|
|||||||
|
|
||||||
return changedFiles.map((x) => ({
|
return changedFiles.map((x) => ({
|
||||||
...x,
|
...x,
|
||||||
path: path.relative(app.path.cwd, path.join(app.path.root, x.path)),
|
path: path.relative(Instance.directory, path.join(Instance.worktree, x.path)),
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function read(file: string) {
|
export async function read(file: string) {
|
||||||
using _ = log.time("read", { file })
|
using _ = log.time("read", { file })
|
||||||
const app = App.info()
|
const project = Instance.project
|
||||||
const full = path.join(app.path.cwd, file)
|
const full = path.join(Instance.directory, file)
|
||||||
const content = await Bun.file(full)
|
const content = await Bun.file(full)
|
||||||
.text()
|
.text()
|
||||||
.catch(() => "")
|
.catch(() => "")
|
||||||
.then((x) => x.trim())
|
.then((x) => x.trim())
|
||||||
if (app.git) {
|
if (project.vcs === "git") {
|
||||||
const rel = path.relative(app.path.root, full)
|
const rel = path.relative(Instance.worktree, full)
|
||||||
const diff = await $`git diff ${rel}`.cwd(app.path.root).quiet().nothrow().text()
|
const diff = await $`git diff ${rel}`.cwd(Instance.worktree).quiet().nothrow().text()
|
||||||
if (diff.trim()) {
|
if (diff.trim()) {
|
||||||
const original = await $`git show HEAD:${rel}`.cwd(app.path.root).quiet().nothrow().text()
|
const original = await $`git show HEAD:${rel}`.cwd(Instance.worktree).quiet().nothrow().text()
|
||||||
const patch = createPatch(file, original, content, "old", "new", {
|
const patch = createPatch(file, original, content, "old", "new", {
|
||||||
context: Infinity,
|
context: Infinity,
|
||||||
})
|
})
|
||||||
@@ -131,22 +139,22 @@ export namespace File {
|
|||||||
|
|
||||||
export async function list(dir?: string) {
|
export async function list(dir?: string) {
|
||||||
const exclude = [".git", ".DS_Store"]
|
const exclude = [".git", ".DS_Store"]
|
||||||
const app = App.info()
|
const project = Instance.project
|
||||||
let ignored = (_: string) => false
|
let ignored = (_: string) => false
|
||||||
if (app.git) {
|
if (project.vcs === "git") {
|
||||||
const gitignore = Bun.file(path.join(app.path.root, ".gitignore"))
|
const gitignore = Bun.file(path.join(Instance.worktree, ".gitignore"))
|
||||||
if (await gitignore.exists()) {
|
if (await gitignore.exists()) {
|
||||||
const ig = ignore().add(await gitignore.text())
|
const ig = ignore().add(await gitignore.text())
|
||||||
ignored = ig.ignores.bind(ig)
|
ignored = ig.ignores.bind(ig)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const resolved = dir ? path.join(app.path.cwd, dir) : app.path.cwd
|
const resolved = dir ? path.join(Instance.directory, dir) : Instance.directory
|
||||||
const nodes: Node[] = []
|
const nodes: Node[] = []
|
||||||
for (const entry of await fs.promises.readdir(resolved, { withFileTypes: true })) {
|
for (const entry of await fs.promises.readdir(resolved, { withFileTypes: true })) {
|
||||||
if (exclude.includes(entry.name)) continue
|
if (exclude.includes(entry.name)) continue
|
||||||
const fullPath = path.join(resolved, entry.name)
|
const fullPath = path.join(resolved, entry.name)
|
||||||
const relativePath = path.relative(app.path.cwd, fullPath)
|
const relativePath = path.relative(Instance.directory, fullPath)
|
||||||
const relativeToRoot = path.relative(app.path.root, fullPath)
|
const relativeToRoot = path.relative(Instance.worktree, fullPath)
|
||||||
const type = entry.isDirectory() ? "directory" : "file"
|
const type = entry.isDirectory() ? "directory" : "file"
|
||||||
nodes.push({
|
nodes.push({
|
||||||
name: entry.name,
|
name: entry.name,
|
||||||
|
|||||||
@@ -1,18 +1,20 @@
|
|||||||
import { App } from "../app/app"
|
import { Instance } from "../project/instance"
|
||||||
import { Log } from "../util/log"
|
import { Log } from "../util/log"
|
||||||
|
|
||||||
export namespace FileTime {
|
export namespace FileTime {
|
||||||
const log = Log.create({ service: "file.time" })
|
const log = Log.create({ service: "file.time" })
|
||||||
export const state = App.state("tool.filetimes", () => {
|
export const state = Instance.state(
|
||||||
const read: {
|
() => {
|
||||||
[sessionID: string]: {
|
const read: {
|
||||||
[path: string]: Date | undefined
|
[sessionID: string]: {
|
||||||
|
[path: string]: Date | undefined
|
||||||
|
}
|
||||||
|
} = {}
|
||||||
|
return {
|
||||||
|
read,
|
||||||
}
|
}
|
||||||
} = {}
|
},
|
||||||
return {
|
)
|
||||||
read,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
export function read(sessionID: string, file: string) {
|
export function read(sessionID: string, file: string) {
|
||||||
log.info("read", { sessionID, file })
|
log.info("read", { sessionID, file })
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import { z } from "zod"
|
import { z } from "zod"
|
||||||
import { Bus } from "../bus"
|
import { Bus } from "../bus"
|
||||||
import fs from "fs"
|
import fs from "fs"
|
||||||
import { App } from "../app/app"
|
|
||||||
import { Log } from "../util/log"
|
import { Log } from "../util/log"
|
||||||
import { Flag } from "../flag/flag"
|
import { Flag } from "../flag/flag"
|
||||||
|
import { Instance } from "../project/instance"
|
||||||
|
|
||||||
export namespace FileWatcher {
|
export namespace FileWatcher {
|
||||||
const log = Log.create({ service: "file.watcher" })
|
const log = Log.create({ service: "file.watcher" })
|
||||||
@@ -17,22 +17,16 @@ export namespace FileWatcher {
|
|||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
const state = App.state(
|
const state = Instance.state(
|
||||||
"file.watcher",
|
|
||||||
() => {
|
() => {
|
||||||
const app = App.use()
|
if (Instance.project.vcs !== "git") return {}
|
||||||
if (!app.info.git) return {}
|
|
||||||
try {
|
try {
|
||||||
const watcher = fs.watch(app.info.path.cwd, { recursive: true }, (event, file) => {
|
const watcher = fs.watch(Instance.directory, { recursive: true }, (event, file) => {
|
||||||
log.info("change", { file, event })
|
log.info("change", { file, event })
|
||||||
if (!file) return
|
if (!file) return
|
||||||
// for some reason async local storage is lost here
|
Bus.publish(Event.Updated, {
|
||||||
// https://github.com/oven-sh/bun/issues/20754
|
file,
|
||||||
App.provideExisting(app, async () => {
|
event,
|
||||||
Bus.publish(Event.Updated, {
|
|
||||||
file,
|
|
||||||
event,
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
return { watcher }
|
return { watcher }
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { App } from "../app/app"
|
|
||||||
import { BunProc } from "../bun"
|
import { BunProc } from "../bun"
|
||||||
|
import { Instance } from "../project/instance"
|
||||||
import { Filesystem } from "../util/filesystem"
|
import { Filesystem } from "../util/filesystem"
|
||||||
|
|
||||||
export interface Info {
|
export interface Info {
|
||||||
@@ -63,8 +63,7 @@ export const prettier: Info = {
|
|||||||
".gql",
|
".gql",
|
||||||
],
|
],
|
||||||
async enabled() {
|
async enabled() {
|
||||||
const app = App.info()
|
const items = await Filesystem.findUp("package.json", Instance.directory, Instance.worktree)
|
||||||
const items = await Filesystem.findUp("package.json", app.path.cwd, app.path.root)
|
|
||||||
for (const item of items) {
|
for (const item of items) {
|
||||||
const json = await Bun.file(item).json()
|
const json = await Bun.file(item).json()
|
||||||
if (json.dependencies?.prettier) return true
|
if (json.dependencies?.prettier) return true
|
||||||
@@ -109,10 +108,9 @@ export const biome: Info = {
|
|||||||
".gql",
|
".gql",
|
||||||
],
|
],
|
||||||
async enabled() {
|
async enabled() {
|
||||||
const app = App.info()
|
|
||||||
const configs = ["biome.json", "biome.jsonc"]
|
const configs = ["biome.json", "biome.jsonc"]
|
||||||
for (const config of configs) {
|
for (const config of configs) {
|
||||||
const found = await Filesystem.findUp(config, app.path.cwd, app.path.root)
|
const found = await Filesystem.findUp(config, Instance.directory, Instance.worktree)
|
||||||
if (found.length > 0) {
|
if (found.length > 0) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@@ -135,8 +133,7 @@ export const clang: Info = {
|
|||||||
command: ["clang-format", "-i", "$FILE"],
|
command: ["clang-format", "-i", "$FILE"],
|
||||||
extensions: [".c", ".cc", ".cpp", ".cxx", ".c++", ".h", ".hh", ".hpp", ".hxx", ".h++", ".ino", ".C", ".H"],
|
extensions: [".c", ".cc", ".cpp", ".cxx", ".c++", ".h", ".hh", ".hpp", ".hxx", ".h++", ".ino", ".C", ".H"],
|
||||||
async enabled() {
|
async enabled() {
|
||||||
const app = App.info()
|
const items = await Filesystem.findUp(".clang-format", Instance.directory, Instance.worktree)
|
||||||
const items = await Filesystem.findUp(".clang-format", app.path.cwd, app.path.root)
|
|
||||||
return items.length > 0
|
return items.length > 0
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -156,10 +153,9 @@ export const ruff: Info = {
|
|||||||
extensions: [".py", ".pyi"],
|
extensions: [".py", ".pyi"],
|
||||||
async enabled() {
|
async enabled() {
|
||||||
if (!Bun.which("ruff")) return false
|
if (!Bun.which("ruff")) return false
|
||||||
const app = App.info()
|
|
||||||
const configs = ["pyproject.toml", "ruff.toml", ".ruff.toml"]
|
const configs = ["pyproject.toml", "ruff.toml", ".ruff.toml"]
|
||||||
for (const config of configs) {
|
for (const config of configs) {
|
||||||
const found = await Filesystem.findUp(config, app.path.cwd, app.path.root)
|
const found = await Filesystem.findUp(config, Instance.directory, Instance.worktree)
|
||||||
if (found.length > 0) {
|
if (found.length > 0) {
|
||||||
if (config === "pyproject.toml") {
|
if (config === "pyproject.toml") {
|
||||||
const content = await Bun.file(found[0]).text()
|
const content = await Bun.file(found[0]).text()
|
||||||
@@ -171,7 +167,7 @@ export const ruff: Info = {
|
|||||||
}
|
}
|
||||||
const deps = ["requirements.txt", "pyproject.toml", "Pipfile"]
|
const deps = ["requirements.txt", "pyproject.toml", "Pipfile"]
|
||||||
for (const dep of deps) {
|
for (const dep of deps) {
|
||||||
const found = await Filesystem.findUp(dep, app.path.cwd, app.path.root)
|
const found = await Filesystem.findUp(dep, Instance.directory, Instance.worktree)
|
||||||
if (found.length > 0) {
|
if (found.length > 0) {
|
||||||
const content = await Bun.file(found[0]).text()
|
const content = await Bun.file(found[0]).text()
|
||||||
if (content.includes("ruff")) return true
|
if (content.includes("ruff")) return true
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import { App } from "../app/app"
|
|
||||||
import { Bus } from "../bus"
|
import { Bus } from "../bus"
|
||||||
import { File } from "../file"
|
import { File } from "../file"
|
||||||
import { Log } from "../util/log"
|
import { Log } from "../util/log"
|
||||||
@@ -7,11 +6,12 @@ import path from "path"
|
|||||||
import * as Formatter from "./formatter"
|
import * as Formatter from "./formatter"
|
||||||
import { Config } from "../config/config"
|
import { Config } from "../config/config"
|
||||||
import { mergeDeep } from "remeda"
|
import { mergeDeep } from "remeda"
|
||||||
|
import { Instance } from "../project/instance"
|
||||||
|
|
||||||
export namespace Format {
|
export namespace Format {
|
||||||
const log = Log.create({ service: "format" })
|
const log = Log.create({ service: "format" })
|
||||||
|
|
||||||
const state = App.state("format", async () => {
|
const state = Instance.state(async () => {
|
||||||
const enabled: Record<string, boolean> = {}
|
const enabled: Record<string, boolean> = {}
|
||||||
const cfg = await Config.get()
|
const cfg = await Config.get()
|
||||||
|
|
||||||
@@ -71,7 +71,7 @@ export namespace Format {
|
|||||||
try {
|
try {
|
||||||
const proc = Bun.spawn({
|
const proc = Bun.spawn({
|
||||||
cmd: item.command.map((x) => x.replace("$FILE", file)),
|
cmd: item.command.map((x) => x.replace("$FILE", file)),
|
||||||
cwd: App.info().path.cwd,
|
cwd: Instance.directory,
|
||||||
env: { ...process.env, ...item.environment },
|
env: { ...process.env, ...item.environment },
|
||||||
stdout: "ignore",
|
stdout: "ignore",
|
||||||
stderr: "ignore",
|
stderr: "ignore",
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import { DebugCommand } from "./cli/cmd/debug"
|
|||||||
import { StatsCommand } from "./cli/cmd/stats"
|
import { StatsCommand } from "./cli/cmd/stats"
|
||||||
import { McpCommand } from "./cli/cmd/mcp"
|
import { McpCommand } from "./cli/cmd/mcp"
|
||||||
import { GithubCommand } from "./cli/cmd/github"
|
import { GithubCommand } from "./cli/cmd/github"
|
||||||
|
import { ExportCommand } from "./cli/cmd/export"
|
||||||
|
|
||||||
const cancel = new AbortController()
|
const cancel = new AbortController()
|
||||||
|
|
||||||
@@ -80,6 +81,7 @@ const cli = yargs(hideBin(process.argv))
|
|||||||
.command(ServeCommand)
|
.command(ServeCommand)
|
||||||
.command(ModelsCommand)
|
.command(ModelsCommand)
|
||||||
.command(StatsCommand)
|
.command(StatsCommand)
|
||||||
|
.command(ExportCommand)
|
||||||
.command(GithubCommand)
|
.command(GithubCommand)
|
||||||
.fail((msg) => {
|
.fail((msg) => {
|
||||||
if (msg.startsWith("Unknown argument") || msg.startsWith("Not enough non-option arguments")) {
|
if (msg.startsWith("Unknown argument") || msg.startsWith("Not enough non-option arguments")) {
|
||||||
@@ -105,6 +107,7 @@ try {
|
|||||||
name: e.name,
|
name: e.name,
|
||||||
message: e.message,
|
message: e.message,
|
||||||
cause: e.cause?.toString(),
|
cause: e.cause?.toString(),
|
||||||
|
stack: e.stack,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import path from "path"
|
import path from "path"
|
||||||
import { createMessageConnection, StreamMessageReader, StreamMessageWriter } from "vscode-jsonrpc/node"
|
import { createMessageConnection, StreamMessageReader, StreamMessageWriter } from "vscode-jsonrpc/node"
|
||||||
import type { Diagnostic as VSCodeDiagnostic } from "vscode-languageserver-types"
|
import type { Diagnostic as VSCodeDiagnostic } from "vscode-languageserver-types"
|
||||||
import { App } from "../app/app"
|
|
||||||
import { Log } from "../util/log"
|
import { Log } from "../util/log"
|
||||||
import { LANGUAGE_EXTENSIONS } from "./language"
|
import { LANGUAGE_EXTENSIONS } from "./language"
|
||||||
import { Bus } from "../bus"
|
import { Bus } from "../bus"
|
||||||
@@ -9,6 +8,7 @@ import z from "zod"
|
|||||||
import type { LSPServer } from "./server"
|
import type { LSPServer } from "./server"
|
||||||
import { NamedError } from "../util/error"
|
import { NamedError } from "../util/error"
|
||||||
import { withTimeout } from "../util/timeout"
|
import { withTimeout } from "../util/timeout"
|
||||||
|
import { Instance } from "../project/instance"
|
||||||
|
|
||||||
export namespace LSPClient {
|
export namespace LSPClient {
|
||||||
const log = Log.create({ service: "lsp.client" })
|
const log = Log.create({ service: "lsp.client" })
|
||||||
@@ -35,7 +35,6 @@ export namespace LSPClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function create(input: { serverID: string; server: LSPServer.Handle; root: string }) {
|
export async function create(input: { serverID: string; server: LSPServer.Handle; root: string }) {
|
||||||
const app = App.info()
|
|
||||||
const l = log.clone().tag("serverID", input.serverID)
|
const l = log.clone().tag("serverID", input.serverID)
|
||||||
l.info("starting client")
|
l.info("starting client")
|
||||||
|
|
||||||
@@ -130,7 +129,7 @@ export namespace LSPClient {
|
|||||||
},
|
},
|
||||||
notify: {
|
notify: {
|
||||||
async open(input: { path: string }) {
|
async open(input: { path: string }) {
|
||||||
input.path = path.isAbsolute(input.path) ? input.path : path.resolve(app.path.cwd, input.path)
|
input.path = path.isAbsolute(input.path) ? input.path : path.resolve(Instance.directory, input.path)
|
||||||
const file = Bun.file(input.path)
|
const file = Bun.file(input.path)
|
||||||
const text = await file.text()
|
const text = await file.text()
|
||||||
const extension = path.extname(input.path)
|
const extension = path.extname(input.path)
|
||||||
@@ -169,7 +168,7 @@ export namespace LSPClient {
|
|||||||
return diagnostics
|
return diagnostics
|
||||||
},
|
},
|
||||||
async waitForDiagnostics(input: { path: string }) {
|
async waitForDiagnostics(input: { path: string }) {
|
||||||
input.path = path.isAbsolute(input.path) ? input.path : path.resolve(app.path.cwd, input.path)
|
input.path = path.isAbsolute(input.path) ? input.path : path.resolve(Instance.directory, input.path)
|
||||||
log.info("waiting for diagnostics", input)
|
log.info("waiting for diagnostics", input)
|
||||||
let unsub: () => void
|
let unsub: () => void
|
||||||
return await withTimeout(
|
return await withTimeout(
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import { App } from "../app/app"
|
|
||||||
import { Log } from "../util/log"
|
import { Log } from "../util/log"
|
||||||
import { LSPClient } from "./client"
|
import { LSPClient } from "./client"
|
||||||
import path from "path"
|
import path from "path"
|
||||||
@@ -6,6 +5,7 @@ import { LSPServer } from "./server"
|
|||||||
import { z } from "zod"
|
import { z } from "zod"
|
||||||
import { Config } from "../config/config"
|
import { Config } from "../config/config"
|
||||||
import { spawn } from "child_process"
|
import { spawn } from "child_process"
|
||||||
|
import { Instance } from "../project/instance"
|
||||||
|
|
||||||
export namespace LSP {
|
export namespace LSP {
|
||||||
const log = Log.create({ service: "lsp" })
|
const log = Log.create({ service: "lsp" })
|
||||||
@@ -53,8 +53,7 @@ export namespace LSP {
|
|||||||
})
|
})
|
||||||
export type DocumentSymbol = z.infer<typeof DocumentSymbol>
|
export type DocumentSymbol = z.infer<typeof DocumentSymbol>
|
||||||
|
|
||||||
const state = App.state(
|
const state = Instance.state(
|
||||||
"lsp",
|
|
||||||
async () => {
|
async () => {
|
||||||
const clients: LSPClient.Info[] = []
|
const clients: LSPClient.Info[] = []
|
||||||
const servers: Record<string, LSPServer.Info> = {}
|
const servers: Record<string, LSPServer.Info> = {}
|
||||||
@@ -71,9 +70,9 @@ export namespace LSP {
|
|||||||
}
|
}
|
||||||
servers[name] = {
|
servers[name] = {
|
||||||
...existing,
|
...existing,
|
||||||
root: existing?.root ?? (async (_file, app) => app.path.root),
|
root: existing?.root ?? (async () => Instance.directory),
|
||||||
extensions: item.extensions ?? existing.extensions,
|
extensions: item.extensions ?? existing.extensions,
|
||||||
spawn: async (_app, root) => {
|
spawn: async (root) => {
|
||||||
return {
|
return {
|
||||||
process: spawn(item.command[0], item.command.slice(1), {
|
process: spawn(item.command[0], item.command.slice(1), {
|
||||||
cwd: root,
|
cwd: root,
|
||||||
@@ -117,7 +116,7 @@ export namespace LSP {
|
|||||||
const result: LSPClient.Info[] = []
|
const result: LSPClient.Info[] = []
|
||||||
for (const server of Object.values(s.servers)) {
|
for (const server of Object.values(s.servers)) {
|
||||||
if (server.extensions.length && !server.extensions.includes(extension)) continue
|
if (server.extensions.length && !server.extensions.includes(extension)) continue
|
||||||
const root = await server.root(file, App.info())
|
const root = await server.root(file)
|
||||||
if (!root) continue
|
if (!root) continue
|
||||||
if (s.broken.has(root + server.id)) continue
|
if (s.broken.has(root + server.id)) continue
|
||||||
|
|
||||||
@@ -126,7 +125,7 @@ export namespace LSP {
|
|||||||
result.push(match)
|
result.push(match)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
const handle = await server.spawn(App.info(), root).catch((err) => {
|
const handle = await server.spawn(root).catch((err) => {
|
||||||
s.broken.add(root + server.id)
|
s.broken.add(root + server.id)
|
||||||
log.error(`Failed to spawn LSP server ${server.id}`, { error: err })
|
log.error(`Failed to spawn LSP server ${server.id}`, { error: err })
|
||||||
return undefined
|
return undefined
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import { spawn, type ChildProcessWithoutNullStreams } from "child_process"
|
import { spawn, type ChildProcessWithoutNullStreams } from "child_process"
|
||||||
import type { App } from "../app/app"
|
|
||||||
import path from "path"
|
import path from "path"
|
||||||
import { Global } from "../global"
|
import { Global } from "../global"
|
||||||
import { Log } from "../util/log"
|
import { Log } from "../util/log"
|
||||||
@@ -7,6 +6,7 @@ import { BunProc } from "../bun"
|
|||||||
import { $ } from "bun"
|
import { $ } from "bun"
|
||||||
import fs from "fs/promises"
|
import fs from "fs/promises"
|
||||||
import { Filesystem } from "../util/filesystem"
|
import { Filesystem } from "../util/filesystem"
|
||||||
|
import { Instance } from "../project/instance"
|
||||||
import { Flag } from "../flag/flag"
|
import { Flag } from "../flag/flag"
|
||||||
|
|
||||||
export namespace LSPServer {
|
export namespace LSPServer {
|
||||||
@@ -17,18 +17,18 @@ export namespace LSPServer {
|
|||||||
initialization?: Record<string, any>
|
initialization?: Record<string, any>
|
||||||
}
|
}
|
||||||
|
|
||||||
type RootFunction = (file: string, app: App.Info) => Promise<string | undefined>
|
type RootFunction = (file: string) => Promise<string | undefined>
|
||||||
|
|
||||||
const NearestRoot = (patterns: string[]): RootFunction => {
|
const NearestRoot = (patterns: string[]): RootFunction => {
|
||||||
return async (file, app) => {
|
return async (file) => {
|
||||||
const files = Filesystem.up({
|
const files = Filesystem.up({
|
||||||
targets: patterns,
|
targets: patterns,
|
||||||
start: path.dirname(file),
|
start: path.dirname(file),
|
||||||
stop: app.path.root,
|
stop: Instance.worktree,
|
||||||
})
|
})
|
||||||
const first = await files.next()
|
const first = await files.next()
|
||||||
await files.return()
|
await files.return()
|
||||||
if (!first.value) return app.path.root
|
if (!first.value) return Instance.worktree
|
||||||
return path.dirname(first.value)
|
return path.dirname(first.value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -38,15 +38,15 @@ export namespace LSPServer {
|
|||||||
extensions: string[]
|
extensions: string[]
|
||||||
global?: boolean
|
global?: boolean
|
||||||
root: RootFunction
|
root: RootFunction
|
||||||
spawn(app: App.Info, root: string): Promise<Handle | undefined>
|
spawn(root: string): Promise<Handle | undefined>
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Typescript: Info = {
|
export const Typescript: Info = {
|
||||||
id: "typescript",
|
id: "typescript",
|
||||||
root: NearestRoot(["tsconfig.json", "package.json", "jsconfig.json"]),
|
root: NearestRoot(["tsconfig.json", "package.json", "jsconfig.json"]),
|
||||||
extensions: [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs", ".mts", ".cts"],
|
extensions: [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs", ".mts", ".cts"],
|
||||||
async spawn(app, root) {
|
async spawn(root) {
|
||||||
const tsserver = await Bun.resolve("typescript/lib/tsserver.js", app.path.cwd).catch(() => {})
|
const tsserver = await Bun.resolve("typescript/lib/tsserver.js", Instance.directory).catch(() => {})
|
||||||
if (!tsserver) return
|
if (!tsserver) return
|
||||||
const proc = spawn(BunProc.which(), ["x", "typescript-language-server", "--stdio"], {
|
const proc = spawn(BunProc.which(), ["x", "typescript-language-server", "--stdio"], {
|
||||||
cwd: root,
|
cwd: root,
|
||||||
@@ -83,7 +83,7 @@ export namespace LSPServer {
|
|||||||
"nuxt.config.js",
|
"nuxt.config.js",
|
||||||
"vue.config.js",
|
"vue.config.js",
|
||||||
]),
|
]),
|
||||||
async spawn(_, root) {
|
async spawn(root) {
|
||||||
let binary = Bun.which("vue-language-server")
|
let binary = Bun.which("vue-language-server")
|
||||||
const args: string[] = []
|
const args: string[] = []
|
||||||
if (!binary) {
|
if (!binary) {
|
||||||
@@ -145,8 +145,8 @@ export namespace LSPServer {
|
|||||||
"package.json",
|
"package.json",
|
||||||
]),
|
]),
|
||||||
extensions: [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs", ".mts", ".cts", ".vue"],
|
extensions: [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs", ".mts", ".cts", ".vue"],
|
||||||
async spawn(app, root) {
|
async spawn(root) {
|
||||||
const eslint = await Bun.resolve("eslint", app.path.cwd).catch(() => {})
|
const eslint = await Bun.resolve("eslint", Instance.directory).catch(() => {})
|
||||||
if (!eslint) return
|
if (!eslint) return
|
||||||
log.info("spawning eslint server")
|
log.info("spawning eslint server")
|
||||||
const serverPath = path.join(Global.Path.bin, "vscode-eslint", "server", "out", "eslintServer.js")
|
const serverPath = path.join(Global.Path.bin, "vscode-eslint", "server", "out", "eslintServer.js")
|
||||||
@@ -194,13 +194,13 @@ export namespace LSPServer {
|
|||||||
|
|
||||||
export const Gopls: Info = {
|
export const Gopls: Info = {
|
||||||
id: "gopls",
|
id: "gopls",
|
||||||
root: async (file, app) => {
|
root: async (file) => {
|
||||||
const work = await NearestRoot(["go.work"])(file, app)
|
const work = await NearestRoot(["go.work"])(file)
|
||||||
if (work) return work
|
if (work) return work
|
||||||
return NearestRoot(["go.mod", "go.sum"])(file, app)
|
return NearestRoot(["go.mod", "go.sum"])(file)
|
||||||
},
|
},
|
||||||
extensions: [".go"],
|
extensions: [".go"],
|
||||||
async spawn(_, root) {
|
async spawn(root) {
|
||||||
let bin = Bun.which("gopls", {
|
let bin = Bun.which("gopls", {
|
||||||
PATH: process.env["PATH"] + ":" + Global.Path.bin,
|
PATH: process.env["PATH"] + ":" + Global.Path.bin,
|
||||||
})
|
})
|
||||||
@@ -238,7 +238,7 @@ export namespace LSPServer {
|
|||||||
id: "ruby-lsp",
|
id: "ruby-lsp",
|
||||||
root: NearestRoot(["Gemfile"]),
|
root: NearestRoot(["Gemfile"]),
|
||||||
extensions: [".rb", ".rake", ".gemspec", ".ru"],
|
extensions: [".rb", ".rake", ".gemspec", ".ru"],
|
||||||
async spawn(_, root) {
|
async spawn(root) {
|
||||||
let bin = Bun.which("ruby-lsp", {
|
let bin = Bun.which("ruby-lsp", {
|
||||||
PATH: process.env["PATH"] + ":" + Global.Path.bin,
|
PATH: process.env["PATH"] + ":" + Global.Path.bin,
|
||||||
})
|
})
|
||||||
@@ -279,7 +279,7 @@ export namespace LSPServer {
|
|||||||
id: "pyright",
|
id: "pyright",
|
||||||
extensions: [".py", ".pyi"],
|
extensions: [".py", ".pyi"],
|
||||||
root: NearestRoot(["pyproject.toml", "setup.py", "setup.cfg", "requirements.txt", "Pipfile", "pyrightconfig.json"]),
|
root: NearestRoot(["pyproject.toml", "setup.py", "setup.cfg", "requirements.txt", "Pipfile", "pyrightconfig.json"]),
|
||||||
async spawn(_, root) {
|
async spawn(root) {
|
||||||
let binary = Bun.which("pyright-langserver")
|
let binary = Bun.which("pyright-langserver")
|
||||||
const args = []
|
const args = []
|
||||||
if (!binary) {
|
if (!binary) {
|
||||||
@@ -333,7 +333,7 @@ export namespace LSPServer {
|
|||||||
id: "elixir-ls",
|
id: "elixir-ls",
|
||||||
extensions: [".ex", ".exs"],
|
extensions: [".ex", ".exs"],
|
||||||
root: NearestRoot(["mix.exs", "mix.lock"]),
|
root: NearestRoot(["mix.exs", "mix.lock"]),
|
||||||
async spawn(_, root) {
|
async spawn(root) {
|
||||||
let binary = Bun.which("elixir-ls")
|
let binary = Bun.which("elixir-ls")
|
||||||
if (!binary) {
|
if (!binary) {
|
||||||
const elixirLsPath = path.join(Global.Path.bin, "elixir-ls")
|
const elixirLsPath = path.join(Global.Path.bin, "elixir-ls")
|
||||||
@@ -389,7 +389,7 @@ export namespace LSPServer {
|
|||||||
id: "zls",
|
id: "zls",
|
||||||
extensions: [".zig", ".zon"],
|
extensions: [".zig", ".zon"],
|
||||||
root: NearestRoot(["build.zig"]),
|
root: NearestRoot(["build.zig"]),
|
||||||
async spawn(_, root) {
|
async spawn(root) {
|
||||||
let bin = Bun.which("zls", {
|
let bin = Bun.which("zls", {
|
||||||
PATH: process.env["PATH"] + ":" + Global.Path.bin,
|
PATH: process.env["PATH"] + ":" + Global.Path.bin,
|
||||||
})
|
})
|
||||||
@@ -495,7 +495,7 @@ export namespace LSPServer {
|
|||||||
id: "csharp",
|
id: "csharp",
|
||||||
root: NearestRoot([".sln", ".csproj", "global.json"]),
|
root: NearestRoot([".sln", ".csproj", "global.json"]),
|
||||||
extensions: [".cs"],
|
extensions: [".cs"],
|
||||||
async spawn(_, root) {
|
async spawn(root) {
|
||||||
let bin = Bun.which("csharp-ls", {
|
let bin = Bun.which("csharp-ls", {
|
||||||
PATH: process.env["PATH"] + ":" + Global.Path.bin,
|
PATH: process.env["PATH"] + ":" + Global.Path.bin,
|
||||||
})
|
})
|
||||||
@@ -533,8 +533,8 @@ export namespace LSPServer {
|
|||||||
|
|
||||||
export const RustAnalyzer: Info = {
|
export const RustAnalyzer: Info = {
|
||||||
id: "rust",
|
id: "rust",
|
||||||
root: async (file, app) => {
|
root: async (root) => {
|
||||||
const crateRoot = await NearestRoot(["Cargo.toml", "Cargo.lock"])(file, app)
|
const crateRoot = await NearestRoot(["Cargo.toml", "Cargo.lock"])(root)
|
||||||
if (crateRoot === undefined) {
|
if (crateRoot === undefined) {
|
||||||
return undefined
|
return undefined
|
||||||
}
|
}
|
||||||
@@ -557,13 +557,13 @@ export namespace LSPServer {
|
|||||||
currentDir = parentDir
|
currentDir = parentDir
|
||||||
|
|
||||||
// Stop if we've gone above the app root
|
// Stop if we've gone above the app root
|
||||||
if (!currentDir.startsWith(app.path.root)) break
|
if (!currentDir.startsWith(Instance.worktree)) break
|
||||||
}
|
}
|
||||||
|
|
||||||
return crateRoot
|
return crateRoot
|
||||||
},
|
},
|
||||||
extensions: [".rs"],
|
extensions: [".rs"],
|
||||||
async spawn(_, root) {
|
async spawn(root) {
|
||||||
const bin = Bun.which("rust-analyzer")
|
const bin = Bun.which("rust-analyzer")
|
||||||
if (!bin) {
|
if (!bin) {
|
||||||
log.info("rust-analyzer not found in path, please install it")
|
log.info("rust-analyzer not found in path, please install it")
|
||||||
@@ -581,7 +581,7 @@ export namespace LSPServer {
|
|||||||
id: "clangd",
|
id: "clangd",
|
||||||
root: NearestRoot(["compile_commands.json", "compile_flags.txt", ".clangd", "CMakeLists.txt", "Makefile"]),
|
root: NearestRoot(["compile_commands.json", "compile_flags.txt", ".clangd", "CMakeLists.txt", "Makefile"]),
|
||||||
extensions: [".c", ".cpp", ".cc", ".cxx", ".c++", ".h", ".hpp", ".hh", ".hxx", ".h++"],
|
extensions: [".c", ".cpp", ".cc", ".cxx", ".c++", ".h", ".hpp", ".hh", ".hxx", ".h++"],
|
||||||
async spawn(_, root) {
|
async spawn(root) {
|
||||||
let bin = Bun.which("clangd", {
|
let bin = Bun.which("clangd", {
|
||||||
PATH: process.env["PATH"] + ":" + Global.Path.bin,
|
PATH: process.env["PATH"] + ":" + Global.Path.bin,
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -2,13 +2,13 @@ import { experimental_createMCPClient, type Tool } from "ai"
|
|||||||
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js"
|
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js"
|
||||||
import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js"
|
import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js"
|
||||||
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js"
|
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js"
|
||||||
import { App } from "../app/app"
|
|
||||||
import { Config } from "../config/config"
|
import { Config } from "../config/config"
|
||||||
import { Log } from "../util/log"
|
import { Log } from "../util/log"
|
||||||
import { NamedError } from "../util/error"
|
import { NamedError } from "../util/error"
|
||||||
import { z } from "zod"
|
import { z } from "zod"
|
||||||
import { Session } from "../session"
|
import { Session } from "../session"
|
||||||
import { Bus } from "../bus"
|
import { Bus } from "../bus"
|
||||||
|
import { Instance } from "../project/instance"
|
||||||
|
|
||||||
export namespace MCP {
|
export namespace MCP {
|
||||||
const log = Log.create({ service: "mcp" })
|
const log = Log.create({ service: "mcp" })
|
||||||
@@ -20,8 +20,7 @@ export namespace MCP {
|
|||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
|
||||||
const state = App.state(
|
const state = Instance.state(
|
||||||
"mcp",
|
|
||||||
async () => {
|
async () => {
|
||||||
const cfg = await Config.get()
|
const cfg = await Config.get()
|
||||||
const clients: {
|
const clients: {
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import { App } from "../app/app"
|
|
||||||
import { z } from "zod"
|
import { z } from "zod"
|
||||||
import { Bus } from "../bus"
|
import { Bus } from "../bus"
|
||||||
import { Log } from "../util/log"
|
import { Log } from "../util/log"
|
||||||
import { Identifier } from "../id/id"
|
import { Identifier } from "../id/id"
|
||||||
import { Plugin } from "../plugin"
|
import { Plugin } from "../plugin"
|
||||||
|
import { Instance } from "../project/instance"
|
||||||
|
|
||||||
export namespace Permission {
|
export namespace Permission {
|
||||||
const log = Log.create({ service: "permission" })
|
const log = Log.create({ service: "permission" })
|
||||||
@@ -35,8 +35,7 @@ export namespace Permission {
|
|||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
const state = App.state(
|
const state = Instance.state(
|
||||||
"permission",
|
|
||||||
() => {
|
() => {
|
||||||
const pending: {
|
const pending: {
|
||||||
[sessionID: string]: {
|
[sessionID: string]: {
|
||||||
|
|||||||
@@ -1,26 +1,28 @@
|
|||||||
import type { Hooks, Plugin as PluginInstance } from "@opencode-ai/plugin"
|
import type { Hooks, Plugin as PluginInstance } from "@opencode-ai/plugin"
|
||||||
import { App } from "../app/app"
|
|
||||||
import { Config } from "../config/config"
|
import { Config } from "../config/config"
|
||||||
import { Bus } from "../bus"
|
import { Bus } from "../bus"
|
||||||
import { Log } from "../util/log"
|
import { Log } from "../util/log"
|
||||||
import { createOpencodeClient } from "@opencode-ai/sdk"
|
import { createOpencodeClient } from "@opencode-ai/sdk"
|
||||||
import { Server } from "../server/server"
|
import { Server } from "../server/server"
|
||||||
import { BunProc } from "../bun"
|
import { BunProc } from "../bun"
|
||||||
|
import { Instance } from "../project/instance"
|
||||||
import { Flag } from "../flag/flag"
|
import { Flag } from "../flag/flag"
|
||||||
|
|
||||||
export namespace Plugin {
|
export namespace Plugin {
|
||||||
const log = Log.create({ service: "plugin" })
|
const log = Log.create({ service: "plugin" })
|
||||||
|
|
||||||
const state = App.state("plugin", async (app) => {
|
const state = Instance.state(async () => {
|
||||||
const client = createOpencodeClient({
|
const client = createOpencodeClient({
|
||||||
baseUrl: "http://localhost:4096",
|
baseUrl: "http://localhost:4096",
|
||||||
fetch: async (...args) => Server.app().fetch(...args),
|
fetch: async (...args) => Server.App.fetch(...args),
|
||||||
})
|
})
|
||||||
const config = await Config.get()
|
const config = await Config.get()
|
||||||
const hooks = []
|
const hooks = []
|
||||||
const input = {
|
const input = {
|
||||||
client,
|
client,
|
||||||
app,
|
project: Instance.project,
|
||||||
|
worktree: Instance.worktree,
|
||||||
|
directory: Instance.directory,
|
||||||
$: Bun.$,
|
$: Bun.$,
|
||||||
}
|
}
|
||||||
const plugins = [...(config.plugin ?? [])]
|
const plugins = [...(config.plugin ?? [])]
|
||||||
|
|||||||
27
packages/opencode/src/project/instance.ts
Normal file
27
packages/opencode/src/project/instance.ts
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
import { Context } from "../util/context"
|
||||||
|
import { Project } from "./project"
|
||||||
|
import { State } from "./state"
|
||||||
|
|
||||||
|
const context = Context.create<{ directory: string; worktree: string; project: Project.Info }>("path")
|
||||||
|
|
||||||
|
export const Instance = {
|
||||||
|
async provide<R>(directory: string, cb: () => R): Promise<R> {
|
||||||
|
const project = await Project.fromDirectory(directory)
|
||||||
|
return context.provide({ directory, worktree: project.worktree, project }, cb)
|
||||||
|
},
|
||||||
|
get directory() {
|
||||||
|
return context.use().directory
|
||||||
|
},
|
||||||
|
get worktree() {
|
||||||
|
return context.use().worktree
|
||||||
|
},
|
||||||
|
get project() {
|
||||||
|
return context.use().project
|
||||||
|
},
|
||||||
|
state<S>(init: () => S, dispose?: (state: Awaited<S>) => Promise<void>): () => S {
|
||||||
|
return State.create(() => Instance.directory, init, dispose)
|
||||||
|
},
|
||||||
|
async dispose() {
|
||||||
|
await State.dispose(Instance.directory)
|
||||||
|
},
|
||||||
|
}
|
||||||
93
packages/opencode/src/project/project.ts
Normal file
93
packages/opencode/src/project/project.ts
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
import z from "zod"
|
||||||
|
import { Filesystem } from "../util/filesystem"
|
||||||
|
import path from "path"
|
||||||
|
import { $ } from "bun"
|
||||||
|
import { Storage } from "../storage/storage"
|
||||||
|
import { Log } from "../util/log"
|
||||||
|
|
||||||
|
export namespace Project {
|
||||||
|
const log = Log.create({ service: "project" })
|
||||||
|
export const Info = z
|
||||||
|
.object({
|
||||||
|
id: z.string(),
|
||||||
|
worktree: z.string(),
|
||||||
|
vcs: z.literal("git").optional(),
|
||||||
|
time: z.object({
|
||||||
|
created: z.number(),
|
||||||
|
initialized: z.number().optional(),
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
.openapi({
|
||||||
|
ref: "Project",
|
||||||
|
})
|
||||||
|
export type Info = z.infer<typeof Info>
|
||||||
|
|
||||||
|
const cache = new Map<string, Info>()
|
||||||
|
export async function fromDirectory(directory: string) {
|
||||||
|
log.info("fromDirectory", { directory })
|
||||||
|
const fn = async () => {
|
||||||
|
const matches = Filesystem.up({ targets: [".git"], start: directory })
|
||||||
|
const git = await matches.next().then((x) => x.value)
|
||||||
|
await matches.return()
|
||||||
|
if (!git) {
|
||||||
|
const project: Info = {
|
||||||
|
id: "global",
|
||||||
|
worktree: "/",
|
||||||
|
time: {
|
||||||
|
created: Date.now(),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
await Storage.write<Info>(["project", "global"], project)
|
||||||
|
return project
|
||||||
|
}
|
||||||
|
let worktree = path.dirname(git)
|
||||||
|
const [id] = await $`git rev-list --max-parents=0 --all`
|
||||||
|
.quiet()
|
||||||
|
.nothrow()
|
||||||
|
.cwd(worktree)
|
||||||
|
.text()
|
||||||
|
.then((x) =>
|
||||||
|
x
|
||||||
|
.split("\n")
|
||||||
|
.filter(Boolean)
|
||||||
|
.map((x) => x.trim())
|
||||||
|
.toSorted(),
|
||||||
|
)
|
||||||
|
worktree = path.dirname(
|
||||||
|
await $`git rev-parse --path-format=absolute --git-common-dir`
|
||||||
|
.quiet()
|
||||||
|
.nothrow()
|
||||||
|
.cwd(worktree)
|
||||||
|
.text()
|
||||||
|
.then((x) => x.trim()),
|
||||||
|
)
|
||||||
|
const project: Info = {
|
||||||
|
id,
|
||||||
|
worktree,
|
||||||
|
vcs: "git",
|
||||||
|
time: {
|
||||||
|
created: Date.now(),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
await Storage.write<Info>(["project", id], project)
|
||||||
|
return project
|
||||||
|
}
|
||||||
|
if (cache.has(directory)) {
|
||||||
|
return cache.get(directory)!
|
||||||
|
}
|
||||||
|
const result = await fn()
|
||||||
|
cache.set(directory, result)
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function setInitialized(projectID: string) {
|
||||||
|
await Storage.update<Info>(["project", projectID], (draft) => {
|
||||||
|
draft.time.initialized = Date.now()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function list() {
|
||||||
|
const keys = await Storage.list(["project"])
|
||||||
|
return await Promise.all(keys.map((x) => Storage.read<Info>(x)))
|
||||||
|
}
|
||||||
|
}
|
||||||
34
packages/opencode/src/project/state.ts
Normal file
34
packages/opencode/src/project/state.ts
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
export namespace State {
|
||||||
|
interface Entry {
|
||||||
|
state: any
|
||||||
|
dispose?: (state: any) => Promise<void>
|
||||||
|
}
|
||||||
|
|
||||||
|
const entries = new Map<string, Map<any, Entry>>()
|
||||||
|
|
||||||
|
export function create<S>(root: () => string, init: () => S, dispose?: (state: Awaited<S>) => Promise<void>) {
|
||||||
|
return () => {
|
||||||
|
const key = root()
|
||||||
|
let collection = entries.get(key)
|
||||||
|
if (!collection) {
|
||||||
|
collection = new Map<string, Entry>()
|
||||||
|
entries.set(key, collection)
|
||||||
|
}
|
||||||
|
const exists = collection.get(init)
|
||||||
|
if (exists) return exists.state as S
|
||||||
|
const state = init()
|
||||||
|
collection.set(init, {
|
||||||
|
state,
|
||||||
|
dispose,
|
||||||
|
})
|
||||||
|
return state
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function dispose(key: string) {
|
||||||
|
for (const [_, entry] of entries.get(key)?.entries() ?? []) {
|
||||||
|
if (!entry.dispose) continue
|
||||||
|
await entry.dispose(await entry.state)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
import z from "zod"
|
import z from "zod"
|
||||||
import { App } from "../app/app"
|
|
||||||
import { Config } from "../config/config"
|
import { Config } from "../config/config"
|
||||||
import { mergeDeep, sortBy } from "remeda"
|
import { mergeDeep, sortBy } from "remeda"
|
||||||
import { NoSuchModelError, type LanguageModel, type Provider as SDK } from "ai"
|
import { NoSuchModelError, type LanguageModel, type Provider as SDK } from "ai"
|
||||||
@@ -9,6 +8,7 @@ import { Plugin } from "../plugin"
|
|||||||
import { ModelsDev } from "./models"
|
import { ModelsDev } from "./models"
|
||||||
import { NamedError } from "../util/error"
|
import { NamedError } from "../util/error"
|
||||||
import { Auth } from "../auth"
|
import { Auth } from "../auth"
|
||||||
|
import { Instance } from "../project/instance"
|
||||||
|
|
||||||
export namespace Provider {
|
export namespace Provider {
|
||||||
const log = Log.create({ service: "provider" })
|
const log = Log.create({ service: "provider" })
|
||||||
@@ -141,7 +141,7 @@ export namespace Provider {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
const state = App.state("provider", async () => {
|
const state = Instance.state(async () => {
|
||||||
const config = await Config.get()
|
const config = await Config.get()
|
||||||
const database = await ModelsDev.get()
|
const database = await ModelsDev.get()
|
||||||
|
|
||||||
@@ -153,7 +153,10 @@ export namespace Provider {
|
|||||||
options: Record<string, any>
|
options: Record<string, any>
|
||||||
}
|
}
|
||||||
} = {}
|
} = {}
|
||||||
const models = new Map<string, { info: ModelsDev.Model; language: LanguageModel }>()
|
const models = new Map<
|
||||||
|
string,
|
||||||
|
{ providerID: string; modelID: string; info: ModelsDev.Model; language: LanguageModel }
|
||||||
|
>()
|
||||||
const sdk = new Map<string, SDK>()
|
const sdk = new Map<string, SDK>()
|
||||||
|
|
||||||
log.info("init")
|
log.info("init")
|
||||||
@@ -362,10 +365,14 @@ export namespace Provider {
|
|||||||
const language = provider.getModel ? await provider.getModel(sdk, modelID) : sdk.languageModel(modelID)
|
const language = provider.getModel ? await provider.getModel(sdk, modelID) : sdk.languageModel(modelID)
|
||||||
log.info("found", { providerID, modelID })
|
log.info("found", { providerID, modelID })
|
||||||
s.models.set(key, {
|
s.models.set(key, {
|
||||||
|
providerID,
|
||||||
|
modelID,
|
||||||
info,
|
info,
|
||||||
language,
|
language,
|
||||||
})
|
})
|
||||||
return {
|
return {
|
||||||
|
modelID,
|
||||||
|
providerID,
|
||||||
info,
|
info,
|
||||||
language,
|
language,
|
||||||
}
|
}
|
||||||
|
|||||||
48
packages/opencode/src/server/project.ts
Normal file
48
packages/opencode/src/server/project.ts
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
import { Hono } from "hono"
|
||||||
|
import { describeRoute } from "hono-openapi"
|
||||||
|
import { resolver } from "hono-openapi/zod"
|
||||||
|
import { Instance } from "../project/instance"
|
||||||
|
import { Project } from "../project/project"
|
||||||
|
|
||||||
|
export const ProjectRoute = new Hono()
|
||||||
|
.get(
|
||||||
|
"/",
|
||||||
|
describeRoute({
|
||||||
|
description: "List all projects",
|
||||||
|
operationId: "project.list",
|
||||||
|
responses: {
|
||||||
|
200: {
|
||||||
|
description: "List of projects",
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
schema: resolver(Project.Info.array()),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
async (c) => {
|
||||||
|
const projects = await Project.list()
|
||||||
|
return c.json(projects)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.get(
|
||||||
|
"/current",
|
||||||
|
describeRoute({
|
||||||
|
description: "Get the current project",
|
||||||
|
operationId: "project.current",
|
||||||
|
responses: {
|
||||||
|
200: {
|
||||||
|
description: "Current project",
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
schema: resolver(Project.Info),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
async (c) => {
|
||||||
|
return c.json(Instance.project)
|
||||||
|
},
|
||||||
|
)
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -20,7 +20,6 @@ import PROMPT_INITIALIZE from "../session/prompt/initialize.txt"
|
|||||||
import PROMPT_PLAN from "../session/prompt/plan.txt"
|
import PROMPT_PLAN from "../session/prompt/plan.txt"
|
||||||
import BUILD_SWITCH from "../session/prompt/build-switch.txt"
|
import BUILD_SWITCH from "../session/prompt/build-switch.txt"
|
||||||
|
|
||||||
import { App } from "../app/app"
|
|
||||||
import { Bus } from "../bus"
|
import { Bus } from "../bus"
|
||||||
import { Config } from "../config/config"
|
import { Config } from "../config/config"
|
||||||
import { Flag } from "../flag/flag"
|
import { Flag } from "../flag/flag"
|
||||||
@@ -43,6 +42,8 @@ import { ReadTool } from "../tool/read"
|
|||||||
import { mergeDeep, pipe, splitWhen } from "remeda"
|
import { mergeDeep, pipe, splitWhen } from "remeda"
|
||||||
import { ToolRegistry } from "../tool/registry"
|
import { ToolRegistry } from "../tool/registry"
|
||||||
import { Plugin } from "../plugin"
|
import { Plugin } from "../plugin"
|
||||||
|
import { Project } from "../project/project"
|
||||||
|
import { Instance } from "../project/instance"
|
||||||
import { Agent } from "../agent/agent"
|
import { Agent } from "../agent/agent"
|
||||||
import { Permission } from "../permission"
|
import { Permission } from "../permission"
|
||||||
import { Wildcard } from "../util/wildcard"
|
import { Wildcard } from "../util/wildcard"
|
||||||
@@ -70,6 +71,8 @@ export namespace Session {
|
|||||||
export const Info = z
|
export const Info = z
|
||||||
.object({
|
.object({
|
||||||
id: Identifier.schema("session"),
|
id: Identifier.schema("session"),
|
||||||
|
projectID: z.string(),
|
||||||
|
directory: z.string(),
|
||||||
parentID: Identifier.schema("session").optional(),
|
parentID: Identifier.schema("session").optional(),
|
||||||
share: z
|
share: z
|
||||||
.object({
|
.object({
|
||||||
@@ -134,11 +137,8 @@ export namespace Session {
|
|||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
const state = App.state(
|
const state = Instance.state(
|
||||||
"session",
|
|
||||||
() => {
|
() => {
|
||||||
const sessions = new Map<string, Info>()
|
|
||||||
const messages = new Map<string, MessageV2.Info[]>()
|
|
||||||
const pending = new Map<string, AbortController>()
|
const pending = new Map<string, AbortController>()
|
||||||
const autoCompacting = new Map<string, boolean>()
|
const autoCompacting = new Map<string, boolean>()
|
||||||
const queued = new Map<
|
const queued = new Map<
|
||||||
@@ -153,8 +153,6 @@ export namespace Session {
|
|||||||
>()
|
>()
|
||||||
|
|
||||||
return {
|
return {
|
||||||
sessions,
|
|
||||||
messages,
|
|
||||||
pending,
|
pending,
|
||||||
autoCompacting,
|
autoCompacting,
|
||||||
queued,
|
queued,
|
||||||
@@ -168,19 +166,28 @@ export namespace Session {
|
|||||||
)
|
)
|
||||||
|
|
||||||
export async function create(parentID?: string, title?: string) {
|
export async function create(parentID?: string, title?: string) {
|
||||||
const result: Info = {
|
return createNext({
|
||||||
id: Identifier.descending("session"),
|
|
||||||
version: Installation.VERSION,
|
|
||||||
parentID,
|
parentID,
|
||||||
title: title ?? createDefaultTitle(!!parentID),
|
directory: Instance.directory,
|
||||||
|
title,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function createNext(input: { id?: string; title?: string; parentID?: string; directory: string }) {
|
||||||
|
const result: Info = {
|
||||||
|
id: Identifier.descending("session", input.id),
|
||||||
|
version: Installation.VERSION,
|
||||||
|
projectID: Instance.project.id,
|
||||||
|
directory: input.directory,
|
||||||
|
parentID: input.parentID,
|
||||||
|
title: input.title ?? createDefaultTitle(!!input.parentID),
|
||||||
time: {
|
time: {
|
||||||
created: Date.now(),
|
created: Date.now(),
|
||||||
updated: Date.now(),
|
updated: Date.now(),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
log.info("created", result)
|
log.info("created", result)
|
||||||
state().sessions.set(result.id, result)
|
await Storage.write(["session", Instance.project.id, result.id], result)
|
||||||
await Storage.writeJSON("session/info/" + result.id, result)
|
|
||||||
const cfg = await Config.get()
|
const cfg = await Config.get()
|
||||||
if (!result.parentID && (Flag.OPENCODE_AUTO_SHARE || cfg.share === "auto"))
|
if (!result.parentID && (Flag.OPENCODE_AUTO_SHARE || cfg.share === "auto"))
|
||||||
share(result.id)
|
share(result.id)
|
||||||
@@ -199,17 +206,12 @@ export namespace Session {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function get(id: string) {
|
export async function get(id: string) {
|
||||||
const result = state().sessions.get(id)
|
const read = await Storage.read<Info>(["session", Instance.project.id, id])
|
||||||
if (result) {
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
const read = await Storage.readJSON<Info>("session/info/" + id)
|
|
||||||
state().sessions.set(id, read)
|
|
||||||
return read as Info
|
return read as Info
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getShare(id: string) {
|
export async function getShare(id: string) {
|
||||||
return Storage.readJSON<ShareInfo>("session/share/" + id)
|
return Storage.read<ShareInfo>(["share", id])
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function share(id: string) {
|
export async function share(id: string) {
|
||||||
@@ -226,7 +228,7 @@ export namespace Session {
|
|||||||
url: share.url,
|
url: share.url,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
await Storage.writeJSON<ShareInfo>("session/share/" + id, share)
|
await Storage.write(["share", id], share)
|
||||||
await Share.sync("session/info/" + id, session)
|
await Share.sync("session/info/" + id, session)
|
||||||
for (const msg of await messages(id)) {
|
for (const msg of await messages(id)) {
|
||||||
await Share.sync("session/message/" + id + "/" + msg.info.id, msg.info)
|
await Share.sync("session/message/" + id + "/" + msg.info.id, msg.info)
|
||||||
@@ -240,7 +242,7 @@ export namespace Session {
|
|||||||
export async function unshare(id: string) {
|
export async function unshare(id: string) {
|
||||||
const share = await getShare(id)
|
const share = await getShare(id)
|
||||||
if (!share) return
|
if (!share) return
|
||||||
await Storage.remove("session/share/" + id)
|
await Storage.remove(["share", id])
|
||||||
await update(id, (draft) => {
|
await update(id, (draft) => {
|
||||||
draft.share = undefined
|
draft.share = undefined
|
||||||
})
|
})
|
||||||
@@ -248,17 +250,15 @@ export namespace Session {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function update(id: string, editor: (session: Info) => void) {
|
export async function update(id: string, editor: (session: Info) => void) {
|
||||||
const { sessions } = state()
|
const project = Instance.project
|
||||||
const session = await get(id)
|
const result = await Storage.update<Info>(["session", project.id, id], (draft) => {
|
||||||
if (!session) return
|
editor(draft)
|
||||||
editor(session)
|
draft.time.updated = Date.now()
|
||||||
session.time.updated = Date.now()
|
|
||||||
sessions.set(id, session)
|
|
||||||
await Storage.writeJSON("session/info/" + id, session)
|
|
||||||
Bus.publish(Event.Updated, {
|
|
||||||
info: session,
|
|
||||||
})
|
})
|
||||||
return session
|
Bus.publish(Event.Updated, {
|
||||||
|
info: result,
|
||||||
|
})
|
||||||
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function messages(sessionID: string) {
|
export async function messages(sessionID: string) {
|
||||||
@@ -266,11 +266,11 @@ export namespace Session {
|
|||||||
info: MessageV2.Info
|
info: MessageV2.Info
|
||||||
parts: MessageV2.Part[]
|
parts: MessageV2.Part[]
|
||||||
}[]
|
}[]
|
||||||
for (const p of await Storage.list("session/message/" + sessionID)) {
|
for (const p of await Storage.list(["message", sessionID])) {
|
||||||
const read = await Storage.readJSON<MessageV2.Info>(p)
|
const read = await Storage.read<MessageV2.Info>(p)
|
||||||
result.push({
|
result.push({
|
||||||
info: read,
|
info: read,
|
||||||
parts: await getParts(sessionID, read.id),
|
parts: await getParts(read.id),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
result.sort((a, b) => (a.info.id > b.info.id ? 1 : -1))
|
result.sort((a, b) => (a.info.id > b.info.id ? 1 : -1))
|
||||||
@@ -279,15 +279,15 @@ export namespace Session {
|
|||||||
|
|
||||||
export async function getMessage(sessionID: string, messageID: string) {
|
export async function getMessage(sessionID: string, messageID: string) {
|
||||||
return {
|
return {
|
||||||
info: await Storage.readJSON<MessageV2.Info>("session/message/" + sessionID + "/" + messageID),
|
info: await Storage.read<MessageV2.Info>(["message", sessionID, messageID]),
|
||||||
parts: await getParts(sessionID, messageID),
|
parts: await getParts(messageID),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getParts(sessionID: string, messageID: string) {
|
export async function getParts(messageID: string) {
|
||||||
const result = [] as MessageV2.Part[]
|
const result = [] as MessageV2.Part[]
|
||||||
for (const item of await Storage.list("session/part/" + sessionID + "/" + messageID)) {
|
for (const item of await Storage.list(["part", messageID])) {
|
||||||
const read = await Storage.readJSON<MessageV2.Part>(item)
|
const read = await Storage.read<MessageV2.Part>(item)
|
||||||
result.push(read)
|
result.push(read)
|
||||||
}
|
}
|
||||||
result.sort((a, b) => (a.id > b.id ? 1 : -1))
|
result.sort((a, b) => (a.id > b.id ? 1 : -1))
|
||||||
@@ -295,17 +295,17 @@ export namespace Session {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function* list() {
|
export async function* list() {
|
||||||
for (const item of await Storage.list("session/info")) {
|
const project = Instance.project
|
||||||
const sessionID = path.basename(item, ".json")
|
for (const item of await Storage.list(["session", project.id])) {
|
||||||
yield get(sessionID)
|
yield Storage.read<Info>(item)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function children(parentID: string) {
|
export async function children(parentID: string) {
|
||||||
|
const project = Instance.project
|
||||||
const result = [] as Session.Info[]
|
const result = [] as Session.Info[]
|
||||||
for (const item of await Storage.list("session/info")) {
|
for (const item of await Storage.list(["session", project.id])) {
|
||||||
const sessionID = path.basename(item, ".json")
|
const session = await Storage.read<Info>(item)
|
||||||
const session = await get(sessionID)
|
|
||||||
if (session.parentID !== parentID) continue
|
if (session.parentID !== parentID) continue
|
||||||
result.push(session)
|
result.push(session)
|
||||||
}
|
}
|
||||||
@@ -324,6 +324,7 @@ export namespace Session {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function remove(sessionID: string, emitEvent = true) {
|
export async function remove(sessionID: string, emitEvent = true) {
|
||||||
|
const project = Instance.project
|
||||||
try {
|
try {
|
||||||
abort(sessionID)
|
abort(sessionID)
|
||||||
const session = await get(sessionID)
|
const session = await get(sessionID)
|
||||||
@@ -331,10 +332,13 @@ export namespace Session {
|
|||||||
await remove(child.id, false)
|
await remove(child.id, false)
|
||||||
}
|
}
|
||||||
await unshare(sessionID).catch(() => {})
|
await unshare(sessionID).catch(() => {})
|
||||||
await Storage.remove(`session/info/${sessionID}`).catch(() => {})
|
for (const msg of await Storage.list(["message", sessionID])) {
|
||||||
await Storage.removeDir(`session/message/${sessionID}/`).catch(() => {})
|
for (const part of await Storage.list(["part", msg.at(-1)!])) {
|
||||||
state().sessions.delete(sessionID)
|
await Storage.remove(part)
|
||||||
state().messages.delete(sessionID)
|
}
|
||||||
|
await Storage.remove(msg)
|
||||||
|
}
|
||||||
|
await Storage.remove(["session", project.id, sessionID])
|
||||||
if (emitEvent) {
|
if (emitEvent) {
|
||||||
Bus.publish(Event.Deleted, {
|
Bus.publish(Event.Deleted, {
|
||||||
info: session,
|
info: session,
|
||||||
@@ -346,25 +350,29 @@ export namespace Session {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function updateMessage(msg: MessageV2.Info) {
|
async function updateMessage(msg: MessageV2.Info) {
|
||||||
await Storage.writeJSON("session/message/" + msg.sessionID + "/" + msg.id, msg)
|
await Storage.write(["message", msg.sessionID, msg.id], msg)
|
||||||
Bus.publish(MessageV2.Event.Updated, {
|
Bus.publish(MessageV2.Event.Updated, {
|
||||||
info: msg,
|
info: msg,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async function updatePart(part: MessageV2.Part) {
|
async function updatePart(part: MessageV2.Part) {
|
||||||
await Storage.writeJSON(["session", "part", part.sessionID, part.messageID, part.id].join("/"), part)
|
await Storage.write(["part", part.messageID, part.id], part)
|
||||||
Bus.publish(MessageV2.Event.PartUpdated, {
|
Bus.publish(MessageV2.Event.PartUpdated, {
|
||||||
part,
|
part,
|
||||||
})
|
})
|
||||||
return part
|
return part
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ChatInput = z.object({
|
export const PromptInput = z.object({
|
||||||
sessionID: Identifier.schema("session"),
|
sessionID: Identifier.schema("session"),
|
||||||
messageID: Identifier.schema("message").optional(),
|
messageID: Identifier.schema("message").optional(),
|
||||||
providerID: z.string(),
|
model: z
|
||||||
modelID: z.string(),
|
.object({
|
||||||
|
providerID: z.string(),
|
||||||
|
modelID: z.string(),
|
||||||
|
})
|
||||||
|
.optional(),
|
||||||
agent: z.string().optional(),
|
agent: z.string().optional(),
|
||||||
system: z.string().optional(),
|
system: z.string().optional(),
|
||||||
tools: z.record(z.boolean()).optional(),
|
tools: z.record(z.boolean()).optional(),
|
||||||
@@ -403,10 +411,10 @@ export namespace Session {
|
|||||||
]),
|
]),
|
||||||
),
|
),
|
||||||
})
|
})
|
||||||
export type ChatInput = z.infer<typeof ChatInput>
|
export type ChatInput = z.infer<typeof PromptInput>
|
||||||
|
|
||||||
export async function chat(
|
export async function prompt(
|
||||||
input: z.infer<typeof ChatInput>,
|
input: z.infer<typeof PromptInput>,
|
||||||
): Promise<{ info: MessageV2.Assistant; parts: MessageV2.Part[] }> {
|
): Promise<{ info: MessageV2.Assistant; parts: MessageV2.Part[] }> {
|
||||||
const l = log.clone().tag("session", input.sessionID)
|
const l = log.clone().tag("session", input.sessionID)
|
||||||
l.info("chatting")
|
l.info("chatting")
|
||||||
@@ -421,7 +429,7 @@ export namespace Session {
|
|||||||
const [preserve, remove] = splitWhen(msgs, (x) => x.info.id === messageID)
|
const [preserve, remove] = splitWhen(msgs, (x) => x.info.id === messageID)
|
||||||
msgs = preserve
|
msgs = preserve
|
||||||
for (const msg of remove) {
|
for (const msg of remove) {
|
||||||
await Storage.remove(`session/message/${input.sessionID}/${msg.info.id}`)
|
await Storage.remove(["message", input.sessionID, msg.info.id])
|
||||||
await Bus.publish(MessageV2.Event.Removed, { sessionID: input.sessionID, messageID: msg.info.id })
|
await Bus.publish(MessageV2.Event.Removed, { sessionID: input.sessionID, messageID: msg.info.id })
|
||||||
}
|
}
|
||||||
const last = preserve.at(-1)
|
const last = preserve.at(-1)
|
||||||
@@ -430,7 +438,7 @@ export namespace Session {
|
|||||||
const [preserveParts, removeParts] = splitWhen(last.parts, (x) => x.id === partID)
|
const [preserveParts, removeParts] = splitWhen(last.parts, (x) => x.id === partID)
|
||||||
last.parts = preserveParts
|
last.parts = preserveParts
|
||||||
for (const part of removeParts) {
|
for (const part of removeParts) {
|
||||||
await Storage.remove(`session/part/${input.sessionID}/${last.info.id}/${part.id}`)
|
await Storage.remove(["part", last.info.id, part.id])
|
||||||
await Bus.publish(MessageV2.Event.PartRemoved, {
|
await Bus.publish(MessageV2.Event.PartRemoved, {
|
||||||
sessionID: input.sessionID,
|
sessionID: input.sessionID,
|
||||||
messageID: last.info.id,
|
messageID: last.info.id,
|
||||||
@@ -451,7 +459,6 @@ export namespace Session {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
const app = App.info()
|
|
||||||
const userParts = await Promise.all(
|
const userParts = await Promise.all(
|
||||||
input.parts.map(async (part): Promise<MessageV2.Part[]> => {
|
input.parts.map(async (part): Promise<MessageV2.Part[]> => {
|
||||||
if (part.type === "file") {
|
if (part.type === "file") {
|
||||||
@@ -649,7 +656,16 @@ export namespace Session {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const model = await Provider.getModel(input.providerID, input.modelID)
|
const agent = await Agent.get(inputAgent)
|
||||||
|
const model = await (async () => {
|
||||||
|
if (input.model) {
|
||||||
|
return input.model
|
||||||
|
}
|
||||||
|
if (agent.model) {
|
||||||
|
return agent.model
|
||||||
|
}
|
||||||
|
return Provider.defaultModel()
|
||||||
|
})().then((x) => Provider.getModel(x.providerID, x.modelID))
|
||||||
let msgs = await messages(input.sessionID)
|
let msgs = await messages(input.sessionID)
|
||||||
|
|
||||||
const previous = msgs.filter((x) => x.info.role === "assistant").at(-1)?.info as MessageV2.Assistant
|
const previous = msgs.filter((x) => x.info.role === "assistant").at(-1)?.info as MessageV2.Assistant
|
||||||
@@ -664,10 +680,10 @@ export namespace Session {
|
|||||||
|
|
||||||
await summarize({
|
await summarize({
|
||||||
sessionID: input.sessionID,
|
sessionID: input.sessionID,
|
||||||
providerID: input.providerID,
|
providerID: model.providerID,
|
||||||
modelID: input.modelID,
|
modelID: model.info.id,
|
||||||
})
|
})
|
||||||
return chat(input)
|
return prompt(input)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
using abort = lock(input.sessionID)
|
using abort = lock(input.sessionID)
|
||||||
@@ -676,17 +692,17 @@ export namespace Session {
|
|||||||
if (lastSummary) msgs = msgs.filter((msg) => msg.info.id >= lastSummary.info.id)
|
if (lastSummary) msgs = msgs.filter((msg) => msg.info.id >= lastSummary.info.id)
|
||||||
|
|
||||||
if (msgs.filter((m) => m.info.role === "user").length === 1 && !session.parentID && isDefaultTitle(session.title)) {
|
if (msgs.filter((m) => m.info.role === "user").length === 1 && !session.parentID && isDefaultTitle(session.title)) {
|
||||||
const small = (await Provider.getSmallModel(input.providerID)) ?? model
|
const small = (await Provider.getSmallModel(model.providerID)) ?? model
|
||||||
generateText({
|
generateText({
|
||||||
maxOutputTokens: small.info.reasoning ? 1024 : 20,
|
maxOutputTokens: small.info.reasoning ? 1024 : 20,
|
||||||
providerOptions: {
|
providerOptions: {
|
||||||
[input.providerID]: {
|
[model.providerID]: {
|
||||||
...small.info.options,
|
...small.info.options,
|
||||||
...ProviderTransform.options(input.providerID, small.info.id, input.sessionID),
|
...ProviderTransform.options(small.providerID, small.modelID, input.sessionID),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
messages: [
|
messages: [
|
||||||
...SystemPrompt.title(input.providerID).map(
|
...SystemPrompt.title(model.providerID).map(
|
||||||
(x): ModelMessage => ({
|
(x): ModelMessage => ({
|
||||||
role: "system",
|
role: "system",
|
||||||
content: x,
|
content: x,
|
||||||
@@ -721,7 +737,6 @@ export namespace Session {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const agent = await Agent.get(inputAgent)
|
|
||||||
if (agent.name === "plan") {
|
if (agent.name === "plan") {
|
||||||
msgs.at(-1)?.parts.push({
|
msgs.at(-1)?.parts.push({
|
||||||
id: Identifier.ascending("part"),
|
id: Identifier.ascending("part"),
|
||||||
@@ -744,12 +759,12 @@ export namespace Session {
|
|||||||
synthetic: true,
|
synthetic: true,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
let system = SystemPrompt.header(input.providerID)
|
let system = SystemPrompt.header(model.providerID)
|
||||||
system.push(
|
system.push(
|
||||||
...(() => {
|
...(() => {
|
||||||
if (input.system) return [input.system]
|
if (input.system) return [input.system]
|
||||||
if (agent.prompt) return [agent.prompt]
|
if (agent.prompt) return [agent.prompt]
|
||||||
return SystemPrompt.provider(input.modelID)
|
return SystemPrompt.provider(model.modelID)
|
||||||
})(),
|
})(),
|
||||||
)
|
)
|
||||||
system.push(...(await SystemPrompt.environment()))
|
system.push(...(await SystemPrompt.environment()))
|
||||||
@@ -764,8 +779,8 @@ export namespace Session {
|
|||||||
system,
|
system,
|
||||||
mode: inputAgent,
|
mode: inputAgent,
|
||||||
path: {
|
path: {
|
||||||
cwd: app.path.cwd,
|
cwd: Instance.directory,
|
||||||
root: app.path.root,
|
root: Instance.worktree,
|
||||||
},
|
},
|
||||||
cost: 0,
|
cost: 0,
|
||||||
tokens: {
|
tokens: {
|
||||||
@@ -774,8 +789,8 @@ export namespace Session {
|
|||||||
reasoning: 0,
|
reasoning: 0,
|
||||||
cache: { read: 0, write: 0 },
|
cache: { read: 0, write: 0 },
|
||||||
},
|
},
|
||||||
modelID: input.modelID,
|
modelID: model.modelID,
|
||||||
providerID: input.providerID,
|
providerID: model.providerID,
|
||||||
time: {
|
time: {
|
||||||
created: Date.now(),
|
created: Date.now(),
|
||||||
},
|
},
|
||||||
@@ -784,7 +799,7 @@ export namespace Session {
|
|||||||
await updateMessage(assistantMsg)
|
await updateMessage(assistantMsg)
|
||||||
await using _ = defer(async () => {
|
await using _ = defer(async () => {
|
||||||
if (assistantMsg.time.completed) return
|
if (assistantMsg.time.completed) return
|
||||||
await Storage.remove(`session/message/${input.sessionID}/${assistantMsg.id}`)
|
await Storage.remove(["session", "message", input.sessionID, assistantMsg.id])
|
||||||
await Bus.publish(MessageV2.Event.Removed, { sessionID: input.sessionID, messageID: assistantMsg.id })
|
await Bus.publish(MessageV2.Event.Removed, { sessionID: input.sessionID, messageID: assistantMsg.id })
|
||||||
})
|
})
|
||||||
const tools: Record<string, AITool> = {}
|
const tools: Record<string, AITool> = {}
|
||||||
@@ -793,10 +808,10 @@ export namespace Session {
|
|||||||
|
|
||||||
const enabledTools = pipe(
|
const enabledTools = pipe(
|
||||||
agent.tools,
|
agent.tools,
|
||||||
mergeDeep(await ToolRegistry.enabled(input.providerID, input.modelID, agent)),
|
mergeDeep(await ToolRegistry.enabled(model.providerID, model.modelID, agent)),
|
||||||
mergeDeep(input.tools ?? {}),
|
mergeDeep(input.tools ?? {}),
|
||||||
)
|
)
|
||||||
for (const item of await ToolRegistry.tools(input.providerID, input.modelID)) {
|
for (const item of await ToolRegistry.tools(model.providerID, model.modelID)) {
|
||||||
if (Wildcard.all(item.id, enabledTools) === false) continue
|
if (Wildcard.all(item.id, enabledTools) === false) continue
|
||||||
tools[item.id] = tool({
|
tools[item.id] = tool({
|
||||||
id: item.id as any,
|
id: item.id as any,
|
||||||
@@ -906,16 +921,16 @@ export namespace Session {
|
|||||||
"chat.params",
|
"chat.params",
|
||||||
{
|
{
|
||||||
model: model.info,
|
model: model.info,
|
||||||
provider: await Provider.getProvider(input.providerID),
|
provider: await Provider.getProvider(model.providerID),
|
||||||
message: userMsg,
|
message: userMsg,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
temperature: model.info.temperature
|
temperature: model.info.temperature
|
||||||
? (agent.temperature ?? ProviderTransform.temperature(input.providerID, input.modelID))
|
? (agent.temperature ?? ProviderTransform.temperature(model.providerID, model.modelID))
|
||||||
: undefined,
|
: undefined,
|
||||||
topP: agent.topP ?? ProviderTransform.topP(input.providerID, input.modelID),
|
topP: agent.topP ?? ProviderTransform.topP(model.providerID, model.modelID),
|
||||||
options: {
|
options: {
|
||||||
...ProviderTransform.options(input.providerID, input.modelID, input.sessionID),
|
...ProviderTransform.options(model.providerID, model.modelID, input.sessionID),
|
||||||
...model.info.options,
|
...model.info.options,
|
||||||
...agent.options,
|
...agent.options,
|
||||||
},
|
},
|
||||||
@@ -949,8 +964,8 @@ export namespace Session {
|
|||||||
role: "assistant",
|
role: "assistant",
|
||||||
system,
|
system,
|
||||||
path: {
|
path: {
|
||||||
cwd: app.path.cwd,
|
cwd: Instance.directory,
|
||||||
root: app.path.root,
|
root: Instance.worktree,
|
||||||
},
|
},
|
||||||
cost: 0,
|
cost: 0,
|
||||||
tokens: {
|
tokens: {
|
||||||
@@ -959,8 +974,8 @@ export namespace Session {
|
|||||||
reasoning: 0,
|
reasoning: 0,
|
||||||
cache: { read: 0, write: 0 },
|
cache: { read: 0, write: 0 },
|
||||||
},
|
},
|
||||||
modelID: input.modelID,
|
modelID: model.modelID,
|
||||||
providerID: input.providerID,
|
providerID: model.providerID,
|
||||||
mode: inputAgent,
|
mode: inputAgent,
|
||||||
time: {
|
time: {
|
||||||
created: Date.now(),
|
created: Date.now(),
|
||||||
@@ -984,7 +999,7 @@ export namespace Session {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
headers:
|
headers:
|
||||||
input.providerID === "opencode"
|
model.providerID === "opencode"
|
||||||
? {
|
? {
|
||||||
"x-opencode-session": input.sessionID,
|
"x-opencode-session": input.sessionID,
|
||||||
"x-opencode-request": userMsg.id,
|
"x-opencode-request": userMsg.id,
|
||||||
@@ -1007,7 +1022,7 @@ export namespace Session {
|
|||||||
return false
|
return false
|
||||||
},
|
},
|
||||||
providerOptions: {
|
providerOptions: {
|
||||||
[input.providerID]: params.options,
|
[model.providerID]: params.options,
|
||||||
},
|
},
|
||||||
temperature: params.temperature,
|
temperature: params.temperature,
|
||||||
topP: params.topP,
|
topP: params.topP,
|
||||||
@@ -1028,7 +1043,7 @@ export namespace Session {
|
|||||||
async transformParams(args) {
|
async transformParams(args) {
|
||||||
if (args.type === "stream") {
|
if (args.type === "stream") {
|
||||||
// @ts-expect-error
|
// @ts-expect-error
|
||||||
args.params.prompt = ProviderTransform.message(args.params.prompt, input.providerID, input.modelID)
|
args.params.prompt = ProviderTransform.message(args.params.prompt, model.providerID, model.modelID)
|
||||||
}
|
}
|
||||||
return args.params
|
return args.params
|
||||||
},
|
},
|
||||||
@@ -1041,7 +1056,7 @@ export namespace Session {
|
|||||||
const unprocessed = queued.find((x) => !x.processed)
|
const unprocessed = queued.find((x) => !x.processed)
|
||||||
if (unprocessed) {
|
if (unprocessed) {
|
||||||
unprocessed.processed = true
|
unprocessed.processed = true
|
||||||
return chat(unprocessed.input)
|
return prompt(unprocessed.input)
|
||||||
}
|
}
|
||||||
for (const item of queued) {
|
for (const item of queued) {
|
||||||
item.callback(result)
|
item.callback(result)
|
||||||
@@ -1084,8 +1099,8 @@ export namespace Session {
|
|||||||
mode: input.agent,
|
mode: input.agent,
|
||||||
cost: 0,
|
cost: 0,
|
||||||
path: {
|
path: {
|
||||||
cwd: App.info().path.cwd,
|
cwd: Instance.directory,
|
||||||
root: App.info().path.root,
|
root: Instance.worktree,
|
||||||
},
|
},
|
||||||
time: {
|
time: {
|
||||||
created: Date.now(),
|
created: Date.now(),
|
||||||
@@ -1119,7 +1134,6 @@ export namespace Session {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
await updatePart(part)
|
await updatePart(part)
|
||||||
const app = App.info()
|
|
||||||
const shell = process.env["SHELL"] ?? "bash"
|
const shell = process.env["SHELL"] ?? "bash"
|
||||||
const shellName = path.basename(shell)
|
const shellName = path.basename(shell)
|
||||||
|
|
||||||
@@ -1139,7 +1153,7 @@ export namespace Session {
|
|||||||
const args = isFishOrNu ? ["-c", script] : ["-c", "-l", script]
|
const args = isFishOrNu ? ["-c", script] : ["-c", "-l", script]
|
||||||
|
|
||||||
const proc = spawn(shell, args, {
|
const proc = spawn(shell, args, {
|
||||||
cwd: app.path.cwd,
|
cwd: Instance.directory,
|
||||||
signal: abort.signal,
|
signal: abort.signal,
|
||||||
detached: true,
|
detached: true,
|
||||||
stdio: ["ignore", "pipe", "pipe"],
|
stdio: ["ignore", "pipe", "pipe"],
|
||||||
@@ -1218,16 +1232,9 @@ export namespace Session {
|
|||||||
const fileRegex = /@([^\s]+)/g
|
const fileRegex = /@([^\s]+)/g
|
||||||
|
|
||||||
export async function command(input: CommandInput) {
|
export async function command(input: CommandInput) {
|
||||||
|
log.info("command", input)
|
||||||
const command = await Command.get(input.command)
|
const command = await Command.get(input.command)
|
||||||
const agent = command.agent ?? input.agent ?? "build"
|
const agent = command.agent ?? input.agent ?? "build"
|
||||||
const fmtModel = (model: { providerID: string; modelID: string }) => `${model.providerID}/${model.modelID}`
|
|
||||||
|
|
||||||
const model =
|
|
||||||
command.model ??
|
|
||||||
(command.agent && (await Agent.get(command.agent).then((x) => (x.model ? fmtModel(x.model) : undefined)))) ??
|
|
||||||
input.model ??
|
|
||||||
(input.agent && (await Agent.get(input.agent).then((x) => (x.model ? fmtModel(x.model) : undefined)))) ??
|
|
||||||
fmtModel(await Provider.defaultModel())
|
|
||||||
|
|
||||||
let template = command.template.replace("$ARGUMENTS", input.arguments)
|
let template = command.template.replace("$ARGUMENTS", input.arguments)
|
||||||
|
|
||||||
@@ -1257,13 +1264,11 @@ export namespace Session {
|
|||||||
},
|
},
|
||||||
] as ChatInput["parts"]
|
] as ChatInput["parts"]
|
||||||
|
|
||||||
const app = App.info()
|
|
||||||
|
|
||||||
for (const match of fileMatches) {
|
for (const match of fileMatches) {
|
||||||
const filename = match[1]
|
const filename = match[1]
|
||||||
const filepath = filename.startsWith("~/")
|
const filepath = filename.startsWith("~/")
|
||||||
? path.join(os.homedir(), filename.slice(2))
|
? path.join(os.homedir(), filename.slice(2))
|
||||||
: path.join(app.path.cwd, filename)
|
: path.join(Instance.worktree, filename)
|
||||||
|
|
||||||
parts.push({
|
parts.push({
|
||||||
type: "file",
|
type: "file",
|
||||||
@@ -1273,10 +1278,18 @@ export namespace Session {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return chat({
|
return prompt({
|
||||||
sessionID: input.sessionID,
|
sessionID: input.sessionID,
|
||||||
messageID: input.messageID,
|
messageID: input.messageID,
|
||||||
...Provider.parseModel(model!),
|
model: (() => {
|
||||||
|
if (input.model) {
|
||||||
|
return Provider.parseModel(input.model)
|
||||||
|
}
|
||||||
|
if (command.model) {
|
||||||
|
return Provider.parseModel(command.model)
|
||||||
|
}
|
||||||
|
return undefined
|
||||||
|
})(),
|
||||||
agent,
|
agent,
|
||||||
parts,
|
parts,
|
||||||
})
|
})
|
||||||
@@ -1550,7 +1563,7 @@ export namespace Session {
|
|||||||
error: assistantMsg.error,
|
error: assistantMsg.error,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
const p = await getParts(assistantMsg.sessionID, assistantMsg.id)
|
const p = await getParts(assistantMsg.id)
|
||||||
for (const part of p) {
|
for (const part of p) {
|
||||||
if (part.type === "tool" && part.state.status !== "completed" && part.state.status !== "error") {
|
if (part.type === "tool" && part.state.status !== "completed" && part.state.status !== "error") {
|
||||||
updatePart({
|
updatePart({
|
||||||
@@ -1642,9 +1655,8 @@ export namespace Session {
|
|||||||
const lastSummary = msgs.findLast((msg) => msg.info.role === "assistant" && msg.info.summary === true)
|
const lastSummary = msgs.findLast((msg) => msg.info.role === "assistant" && msg.info.summary === true)
|
||||||
const filtered = msgs.filter((msg) => !lastSummary || msg.info.id >= lastSummary.info.id)
|
const filtered = msgs.filter((msg) => !lastSummary || msg.info.id >= lastSummary.info.id)
|
||||||
const model = await Provider.getModel(input.providerID, input.modelID)
|
const model = await Provider.getModel(input.providerID, input.modelID)
|
||||||
const app = App.info()
|
|
||||||
const system = [
|
const system = [
|
||||||
...SystemPrompt.summarize(input.providerID),
|
...SystemPrompt.summarize(model.providerID),
|
||||||
...(await SystemPrompt.environment()),
|
...(await SystemPrompt.environment()),
|
||||||
...(await SystemPrompt.custom()),
|
...(await SystemPrompt.custom()),
|
||||||
]
|
]
|
||||||
@@ -1656,13 +1668,13 @@ export namespace Session {
|
|||||||
system,
|
system,
|
||||||
mode: "build",
|
mode: "build",
|
||||||
path: {
|
path: {
|
||||||
cwd: app.path.cwd,
|
cwd: Instance.directory,
|
||||||
root: app.path.root,
|
root: Instance.worktree,
|
||||||
},
|
},
|
||||||
summary: true,
|
summary: true,
|
||||||
cost: 0,
|
cost: 0,
|
||||||
modelID: input.modelID,
|
modelID: input.modelID,
|
||||||
providerID: input.providerID,
|
providerID: model.providerID,
|
||||||
tokens: {
|
tokens: {
|
||||||
input: 0,
|
input: 0,
|
||||||
output: 0,
|
output: 0,
|
||||||
@@ -1771,20 +1783,21 @@ export namespace Session {
|
|||||||
providerID: string
|
providerID: string
|
||||||
messageID: string
|
messageID: string
|
||||||
}) {
|
}) {
|
||||||
const app = App.info()
|
await Session.prompt({
|
||||||
await Session.chat({
|
|
||||||
sessionID: input.sessionID,
|
sessionID: input.sessionID,
|
||||||
messageID: input.messageID,
|
messageID: input.messageID,
|
||||||
providerID: input.providerID,
|
model: {
|
||||||
modelID: input.modelID,
|
providerID: input.providerID,
|
||||||
|
modelID: input.modelID,
|
||||||
|
},
|
||||||
parts: [
|
parts: [
|
||||||
{
|
{
|
||||||
id: Identifier.ascending("part"),
|
id: Identifier.ascending("part"),
|
||||||
type: "text",
|
type: "text",
|
||||||
text: PROMPT_INITIALIZE.replace("${path}", app.path.root),
|
text: PROMPT_INITIALIZE.replace("${path}", Instance.worktree),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
await App.initialize()
|
await Project.setInitialized(Instance.project.id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
import { App } from "../app/app"
|
|
||||||
import { Ripgrep } from "../file/ripgrep"
|
import { Ripgrep } from "../file/ripgrep"
|
||||||
import { Global } from "../global"
|
import { Global } from "../global"
|
||||||
import { Filesystem } from "../util/filesystem"
|
import { Filesystem } from "../util/filesystem"
|
||||||
import { Config } from "../config/config"
|
import { Config } from "../config/config"
|
||||||
|
|
||||||
|
import { Instance } from "../project/instance"
|
||||||
import path from "path"
|
import path from "path"
|
||||||
import os from "os"
|
import os from "os"
|
||||||
|
|
||||||
@@ -30,21 +31,21 @@ export namespace SystemPrompt {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function environment() {
|
export async function environment() {
|
||||||
const app = App.info()
|
const project = Instance.project
|
||||||
return [
|
return [
|
||||||
[
|
[
|
||||||
`Here is some useful information about the environment you are running in:`,
|
`Here is some useful information about the environment you are running in:`,
|
||||||
`<env>`,
|
`<env>`,
|
||||||
` Working directory: ${app.path.cwd}`,
|
` Working directory: ${Instance.directory}`,
|
||||||
` Is directory a git repo: ${app.git ? "yes" : "no"}`,
|
` Is directory a git repo: ${project.vcs === "git" ? "yes" : "no"}`,
|
||||||
` Platform: ${process.platform}`,
|
` Platform: ${process.platform}`,
|
||||||
` Today's date: ${new Date().toDateString()}`,
|
` Today's date: ${new Date().toDateString()}`,
|
||||||
`</env>`,
|
`</env>`,
|
||||||
`<project>`,
|
`<project>`,
|
||||||
` ${
|
` ${
|
||||||
app.git
|
project.vcs === "git"
|
||||||
? await Ripgrep.tree({
|
? await Ripgrep.tree({
|
||||||
cwd: app.path.cwd,
|
cwd: Instance.directory,
|
||||||
limit: 200,
|
limit: 200,
|
||||||
})
|
})
|
||||||
: ""
|
: ""
|
||||||
@@ -65,12 +66,11 @@ export namespace SystemPrompt {
|
|||||||
]
|
]
|
||||||
|
|
||||||
export async function custom() {
|
export async function custom() {
|
||||||
const { cwd, root } = App.info().path
|
|
||||||
const config = await Config.get()
|
const config = await Config.get()
|
||||||
const paths = new Set<string>()
|
const paths = new Set<string>()
|
||||||
|
|
||||||
for (const localRuleFile of LOCAL_RULE_FILES) {
|
for (const localRuleFile of LOCAL_RULE_FILES) {
|
||||||
const matches = await Filesystem.findUp(localRuleFile, cwd, root)
|
const matches = await Filesystem.findUp(localRuleFile, Instance.directory, Instance.worktree)
|
||||||
if (matches.length > 0) {
|
if (matches.length > 0) {
|
||||||
matches.forEach((path) => paths.add(path))
|
matches.forEach((path) => paths.add(path))
|
||||||
break
|
break
|
||||||
@@ -99,7 +99,7 @@ export namespace SystemPrompt {
|
|||||||
}),
|
}),
|
||||||
).catch(() => [])
|
).catch(() => [])
|
||||||
} else {
|
} else {
|
||||||
matches = await Filesystem.globUp(instruction, cwd, root).catch(() => [])
|
matches = await Filesystem.globUp(instruction, Instance.directory, Instance.worktree).catch(() => [])
|
||||||
}
|
}
|
||||||
matches.forEach((path) => paths.add(path))
|
matches.forEach((path) => paths.add(path))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { Bus } from "../bus"
|
import { Bus } from "../bus"
|
||||||
import { Installation } from "../installation"
|
import { Installation } from "../installation"
|
||||||
import { Session } from "../session"
|
import { Session } from "../session"
|
||||||
import { Storage } from "../storage/storage"
|
import { MessageV2 } from "../session/message-v2"
|
||||||
import { Log } from "../util/log"
|
import { Log } from "../util/log"
|
||||||
|
|
||||||
export namespace Share {
|
export namespace Share {
|
||||||
@@ -46,8 +46,22 @@ export namespace Share {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function init() {
|
export function init() {
|
||||||
Bus.subscribe(Storage.Event.Write, async (payload) => {
|
Bus.subscribe(Session.Event.Updated, async (evt) => {
|
||||||
await sync(payload.properties.key, payload.properties.content)
|
await sync("session/info/" + evt.properties.info.id, evt.properties.info)
|
||||||
|
})
|
||||||
|
Bus.subscribe(MessageV2.Event.Updated, async (evt) => {
|
||||||
|
await sync("session/message/" + evt.properties.info.sessionID + "/" + evt.properties.info.id, evt.properties.info)
|
||||||
|
})
|
||||||
|
Bus.subscribe(MessageV2.Event.PartUpdated, async (evt) => {
|
||||||
|
await sync(
|
||||||
|
"session/part/" +
|
||||||
|
evt.properties.part.sessionID +
|
||||||
|
"/" +
|
||||||
|
evt.properties.part.messageID +
|
||||||
|
"/" +
|
||||||
|
evt.properties.part.id,
|
||||||
|
evt.properties.part,
|
||||||
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import { App } from "../app/app"
|
|
||||||
import { $ } from "bun"
|
import { $ } from "bun"
|
||||||
import path from "path"
|
import path from "path"
|
||||||
import fs from "fs/promises"
|
import fs from "fs/promises"
|
||||||
@@ -6,6 +5,7 @@ import { Log } from "../util/log"
|
|||||||
import { Global } from "../global"
|
import { Global } from "../global"
|
||||||
import { z } from "zod"
|
import { z } from "zod"
|
||||||
import { Config } from "../config/config"
|
import { Config } from "../config/config"
|
||||||
|
import { Instance } from "../project/instance"
|
||||||
|
|
||||||
export namespace Snapshot {
|
export namespace Snapshot {
|
||||||
const log = Log.create({ service: "snapshot" })
|
const log = Log.create({ service: "snapshot" })
|
||||||
@@ -25,8 +25,7 @@ export namespace Snapshot {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function track() {
|
export async function track() {
|
||||||
const app = App.info()
|
if (Instance.project.vcs !== "git") return
|
||||||
if (!app.git) return
|
|
||||||
const cfg = await Config.get()
|
const cfg = await Config.get()
|
||||||
if (cfg.snapshot === false) return
|
if (cfg.snapshot === false) return
|
||||||
const git = gitdir()
|
const git = gitdir()
|
||||||
@@ -35,15 +34,15 @@ export namespace Snapshot {
|
|||||||
.env({
|
.env({
|
||||||
...process.env,
|
...process.env,
|
||||||
GIT_DIR: git,
|
GIT_DIR: git,
|
||||||
GIT_WORK_TREE: app.path.root,
|
GIT_WORK_TREE: Instance.worktree,
|
||||||
})
|
})
|
||||||
.quiet()
|
.quiet()
|
||||||
.nothrow()
|
.nothrow()
|
||||||
log.info("initialized")
|
log.info("initialized")
|
||||||
}
|
}
|
||||||
await $`git --git-dir ${git} add .`.quiet().cwd(app.path.cwd).nothrow()
|
await $`git --git-dir ${git} add .`.quiet().cwd(Instance.directory).nothrow()
|
||||||
const hash = await $`git --git-dir ${git} write-tree`.quiet().cwd(app.path.cwd).nothrow().text()
|
const hash = await $`git --git-dir ${git} write-tree`.quiet().cwd(Instance.directory).nothrow().text()
|
||||||
log.info("tracking", { hash, cwd: app.path.cwd, git })
|
log.info("tracking", { hash, cwd: Instance.directory, git })
|
||||||
return hash.trim()
|
return hash.trim()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -54,10 +53,9 @@ export namespace Snapshot {
|
|||||||
export type Patch = z.infer<typeof Patch>
|
export type Patch = z.infer<typeof Patch>
|
||||||
|
|
||||||
export async function patch(hash: string): Promise<Patch> {
|
export async function patch(hash: string): Promise<Patch> {
|
||||||
const app = App.info()
|
|
||||||
const git = gitdir()
|
const git = gitdir()
|
||||||
await $`git --git-dir ${git} add .`.quiet().cwd(app.path.cwd).nothrow()
|
await $`git --git-dir ${git} add .`.quiet().cwd(Instance.directory).nothrow()
|
||||||
const files = await $`git --git-dir ${git} diff --name-only ${hash} -- .`.cwd(app.path.cwd).text()
|
const files = await $`git --git-dir ${git} diff --name-only ${hash} -- .`.cwd(Instance.directory).text()
|
||||||
return {
|
return {
|
||||||
hash,
|
hash,
|
||||||
files: files
|
files: files
|
||||||
@@ -65,17 +63,16 @@ export namespace Snapshot {
|
|||||||
.split("\n")
|
.split("\n")
|
||||||
.map((x) => x.trim())
|
.map((x) => x.trim())
|
||||||
.filter(Boolean)
|
.filter(Boolean)
|
||||||
.map((x) => path.join(app.path.root, x)),
|
.map((x) => path.join(Instance.worktree, x)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function restore(snapshot: string) {
|
export async function restore(snapshot: string) {
|
||||||
log.info("restore", { commit: snapshot })
|
log.info("restore", { commit: snapshot })
|
||||||
const app = App.info()
|
|
||||||
const git = gitdir()
|
const git = gitdir()
|
||||||
await $`git --git-dir=${git} read-tree ${snapshot} && git --git-dir=${git} checkout-index -a -f`
|
await $`git --git-dir=${git} read-tree ${snapshot} && git --git-dir=${git} checkout-index -a -f`
|
||||||
.quiet()
|
.quiet()
|
||||||
.cwd(app.path.root)
|
.cwd(Instance.worktree)
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function revert(patches: Patch[]) {
|
export async function revert(patches: Patch[]) {
|
||||||
@@ -87,7 +84,7 @@ export namespace Snapshot {
|
|||||||
log.info("reverting", { file, hash: item.hash })
|
log.info("reverting", { file, hash: item.hash })
|
||||||
const result = await $`git --git-dir=${git} checkout ${item.hash} -- ${file}`
|
const result = await $`git --git-dir=${git} checkout ${item.hash} -- ${file}`
|
||||||
.quiet()
|
.quiet()
|
||||||
.cwd(App.info().path.root)
|
.cwd(Instance.worktree)
|
||||||
.nothrow()
|
.nothrow()
|
||||||
if (result.exitCode !== 0) {
|
if (result.exitCode !== 0) {
|
||||||
log.info("file not found in history, deleting", { file })
|
log.info("file not found in history, deleting", { file })
|
||||||
@@ -99,14 +96,13 @@ export namespace Snapshot {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function diff(hash: string) {
|
export async function diff(hash: string) {
|
||||||
const app = App.info()
|
|
||||||
const git = gitdir()
|
const git = gitdir()
|
||||||
const result = await $`git --git-dir=${git} diff ${hash} -- .`.quiet().cwd(app.path.root).text()
|
const result = await $`git --git-dir=${git} diff ${hash} -- .`.quiet().cwd(Instance.worktree).text()
|
||||||
return result.trim()
|
return result.trim()
|
||||||
}
|
}
|
||||||
|
|
||||||
function gitdir() {
|
function gitdir() {
|
||||||
const app = App.info()
|
const project = Instance.project
|
||||||
return path.join(app.path.data, "snapshots")
|
return path.join(Global.Path.data, "snapshot", project.id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,99 +1,113 @@
|
|||||||
import { Log } from "../util/log"
|
import { Log } from "../util/log"
|
||||||
import { App } from "../app/app"
|
|
||||||
import { Bus } from "../bus"
|
|
||||||
import path from "path"
|
import path from "path"
|
||||||
import z from "zod"
|
|
||||||
import fs from "fs/promises"
|
import fs from "fs/promises"
|
||||||
import { MessageV2 } from "../session/message-v2"
|
import { Global } from "../global"
|
||||||
import { Identifier } from "../id/id"
|
import { lazy } from "../util/lazy"
|
||||||
|
import { Lock } from "../util/lock"
|
||||||
|
import { $ } from "bun"
|
||||||
|
|
||||||
export namespace Storage {
|
export namespace Storage {
|
||||||
const log = Log.create({ service: "storage" })
|
const log = Log.create({ service: "storage" })
|
||||||
|
|
||||||
export const Event = {
|
|
||||||
Write: Bus.event("storage.write", z.object({ key: z.string(), content: z.any() })),
|
|
||||||
}
|
|
||||||
|
|
||||||
type Migration = (dir: string) => Promise<void>
|
type Migration = (dir: string) => Promise<void>
|
||||||
|
|
||||||
const MIGRATIONS: Migration[] = [
|
const MIGRATIONS: Migration[] = [
|
||||||
async (dir: string) => {
|
async (dir) => {
|
||||||
try {
|
const project = path.resolve(dir, "../project")
|
||||||
const files = new Bun.Glob("session/message/*/*.json").scanSync({
|
for await (const projectDir of new Bun.Glob("*").scan({ cwd: project, onlyFiles: false })) {
|
||||||
cwd: dir,
|
log.info(`migrating project ${projectDir}`)
|
||||||
absolute: true,
|
let projectID = projectDir
|
||||||
})
|
const fullProjectDir = path.join(project, projectDir)
|
||||||
for (const file of files) {
|
let worktree = "/"
|
||||||
const content = await Bun.file(file).json()
|
|
||||||
if (!content.metadata) continue
|
if (projectID !== "global") {
|
||||||
log.info("migrating to v2 message", { file })
|
for await (const msgFile of new Bun.Glob("storage/session/message/*/*.json").scan({
|
||||||
try {
|
cwd: path.join(project, projectDir),
|
||||||
const result = MessageV2.fromV1(content)
|
absolute: true,
|
||||||
await Bun.write(
|
})) {
|
||||||
file,
|
const json = await Bun.file(msgFile).json()
|
||||||
JSON.stringify(
|
worktree = json.path?.root
|
||||||
{
|
if (worktree) break
|
||||||
...result.info,
|
}
|
||||||
parts: result.parts,
|
if (!worktree) continue
|
||||||
},
|
if (!(await fs.exists(worktree))) continue
|
||||||
null,
|
const [id] = await $`git rev-list --max-parents=0 --all`
|
||||||
2,
|
.quiet()
|
||||||
),
|
.nothrow()
|
||||||
|
.cwd(worktree)
|
||||||
|
.text()
|
||||||
|
.then((x) =>
|
||||||
|
x
|
||||||
|
.split("\n")
|
||||||
|
.filter(Boolean)
|
||||||
|
.map((x) => x.trim())
|
||||||
|
.toSorted(),
|
||||||
)
|
)
|
||||||
} catch (e) {
|
if (!id) continue
|
||||||
await fs.rename(file, file.replace("storage", "broken"))
|
projectID = id
|
||||||
|
|
||||||
|
await Bun.write(
|
||||||
|
path.join(dir, "project", projectID + ".json"),
|
||||||
|
JSON.stringify({
|
||||||
|
id,
|
||||||
|
vcs: "git",
|
||||||
|
worktree,
|
||||||
|
time: {
|
||||||
|
created: Date.now(),
|
||||||
|
initialized: Date.now(),
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
|
||||||
|
log.info(`migrating sessions for project ${projectID}`)
|
||||||
|
for await (const sessionFile of new Bun.Glob("storage/session/info/*.json").scan({
|
||||||
|
cwd: fullProjectDir,
|
||||||
|
absolute: true,
|
||||||
|
})) {
|
||||||
|
const dest = path.join(dir, "session", projectID, path.basename(sessionFile))
|
||||||
|
log.info("copying", {
|
||||||
|
sessionFile,
|
||||||
|
dest,
|
||||||
|
})
|
||||||
|
const session = await Bun.file(sessionFile).json()
|
||||||
|
await Bun.write(dest, JSON.stringify(session))
|
||||||
|
log.info(`migrating messages for session ${session.id}`)
|
||||||
|
for await (const msgFile of new Bun.Glob(`storage/session/message/${session.id}/*.json`).scan({
|
||||||
|
cwd: fullProjectDir,
|
||||||
|
absolute: true,
|
||||||
|
})) {
|
||||||
|
const dest = path.join(dir, "message", session.id, path.basename(msgFile))
|
||||||
|
log.info("copying", {
|
||||||
|
msgFile,
|
||||||
|
dest,
|
||||||
|
})
|
||||||
|
const message = await Bun.file(msgFile).json()
|
||||||
|
await Bun.write(dest, JSON.stringify(message))
|
||||||
|
|
||||||
|
log.info(`migrating parts for message ${message.id}`)
|
||||||
|
for await (const partFile of new Bun.Glob(`storage/session/part/${session.id}/${message.id}/*.json`).scan(
|
||||||
|
{
|
||||||
|
cwd: fullProjectDir,
|
||||||
|
absolute: true,
|
||||||
|
},
|
||||||
|
)) {
|
||||||
|
const dest = path.join(dir, "part", message.id, path.basename(partFile))
|
||||||
|
const part = await Bun.file(partFile).json()
|
||||||
|
log.info("copying", {
|
||||||
|
partFile,
|
||||||
|
dest,
|
||||||
|
})
|
||||||
|
await Bun.write(dest, JSON.stringify(part))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch {}
|
|
||||||
},
|
|
||||||
async (dir: string) => {
|
|
||||||
const files = new Bun.Glob("session/message/*/*.json").scanSync({
|
|
||||||
cwd: dir,
|
|
||||||
absolute: true,
|
|
||||||
})
|
|
||||||
for (const file of files) {
|
|
||||||
try {
|
|
||||||
const { parts, ...info } = await Bun.file(file).json()
|
|
||||||
if (!parts) continue
|
|
||||||
for (const part of parts) {
|
|
||||||
const id = Identifier.ascending("part")
|
|
||||||
await Bun.write(
|
|
||||||
[dir, "session", "part", info.sessionID, info.id, id + ".json"].join("/"),
|
|
||||||
JSON.stringify({
|
|
||||||
...part,
|
|
||||||
id,
|
|
||||||
sessionID: info.sessionID,
|
|
||||||
messageID: info.id,
|
|
||||||
...(part.type === "tool" ? { callID: part.id } : {}),
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
await Bun.write(file, JSON.stringify(info, null, 2))
|
|
||||||
} catch (e) {}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
async (dir: string) => {
|
|
||||||
const files = new Bun.Glob("session/message/*/*.json").scanSync({
|
|
||||||
cwd: dir,
|
|
||||||
absolute: true,
|
|
||||||
})
|
|
||||||
for (const file of files) {
|
|
||||||
try {
|
|
||||||
const content = await Bun.file(file).json()
|
|
||||||
if (content.role === "assistant" && !content.mode) {
|
|
||||||
log.info("adding mode field to message", { file })
|
|
||||||
content.mode = "build"
|
|
||||||
await Bun.write(file, JSON.stringify(content, null, 2))
|
|
||||||
}
|
|
||||||
} catch (e) {}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
const state = App.state("storage", async () => {
|
const state = lazy(async () => {
|
||||||
const app = App.info()
|
const dir = path.join(Global.Path.data, "storage")
|
||||||
const dir = path.normalize(path.join(app.path.data, "storage"))
|
|
||||||
await fs.mkdir(dir, { recursive: true })
|
|
||||||
const migration = await Bun.file(path.join(dir, "migration"))
|
const migration = await Bun.file(path.join(dir, "migration"))
|
||||||
.json()
|
.json()
|
||||||
.then((x) => parseInt(x))
|
.then((x) => parseInt(x))
|
||||||
@@ -109,43 +123,46 @@ export namespace Storage {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
export async function remove(key: string) {
|
export async function remove(key: string[]) {
|
||||||
const dir = await state().then((x) => x.dir)
|
const dir = await state().then((x) => x.dir)
|
||||||
const target = path.join(dir, key + ".json")
|
const target = path.join(dir, ...key) + ".json"
|
||||||
await fs.unlink(target).catch(() => {})
|
await fs.unlink(target).catch(() => {})
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function removeDir(key: string) {
|
export async function read<T>(key: string[]) {
|
||||||
const dir = await state().then((x) => x.dir)
|
const dir = await state().then((x) => x.dir)
|
||||||
const target = path.join(dir, key)
|
const target = path.join(dir, ...key) + ".json"
|
||||||
await fs.rm(target, { recursive: true, force: true }).catch(() => {})
|
using _ = await Lock.read(target)
|
||||||
|
return Bun.file(target).json() as Promise<T>
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function readJSON<T>(key: string) {
|
export async function update<T>(key: string[], fn: (draft: T) => void) {
|
||||||
const dir = await state().then((x) => x.dir)
|
const dir = await state().then((x) => x.dir)
|
||||||
return Bun.file(path.join(dir, key + ".json")).json() as Promise<T>
|
const target = path.join(dir, ...key) + ".json"
|
||||||
|
using _ = await Lock.write("storage")
|
||||||
|
const content = await Bun.file(target).json()
|
||||||
|
fn(content)
|
||||||
|
await Bun.write(target, JSON.stringify(content, null, 2))
|
||||||
|
return content as T
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function writeJSON<T>(key: string, content: T) {
|
export async function write<T>(key: string[], content: T) {
|
||||||
const dir = await state().then((x) => x.dir)
|
const dir = await state().then((x) => x.dir)
|
||||||
const target = path.join(dir, key + ".json")
|
const target = path.join(dir, ...key) + ".json"
|
||||||
const tmp = target + Date.now() + ".tmp"
|
using _ = await Lock.write("storage")
|
||||||
await Bun.write(tmp, JSON.stringify(content, null, 2))
|
await Bun.write(target, JSON.stringify(content, null, 2))
|
||||||
await fs.rename(tmp, target).catch(() => {})
|
|
||||||
await fs.unlink(tmp).catch(() => {})
|
|
||||||
Bus.publish(Event.Write, { key, content })
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const glob = new Bun.Glob("**/*")
|
const glob = new Bun.Glob("**/*")
|
||||||
export async function list(prefix: string) {
|
export async function list(prefix: string[]) {
|
||||||
const dir = await state().then((x) => x.dir)
|
const dir = await state().then((x) => x.dir)
|
||||||
try {
|
try {
|
||||||
const result = await Array.fromAsync(
|
const result = await Array.fromAsync(
|
||||||
glob.scan({
|
glob.scan({
|
||||||
cwd: path.join(dir, prefix),
|
cwd: path.join(dir, ...prefix),
|
||||||
onlyFiles: true,
|
onlyFiles: true,
|
||||||
}),
|
}),
|
||||||
).then((items) => items.map((item) => path.join(prefix, item.slice(0, -5))))
|
).then((results) => results.map((x) => [...prefix, ...x.slice(0, -5).split(path.sep)]))
|
||||||
result.sort()
|
result.sort()
|
||||||
return result
|
return result
|
||||||
} catch {
|
} catch {
|
||||||
|
|||||||
@@ -3,13 +3,13 @@ import { exec } from "child_process"
|
|||||||
|
|
||||||
import { Tool } from "./tool"
|
import { Tool } from "./tool"
|
||||||
import DESCRIPTION from "./bash.txt"
|
import DESCRIPTION from "./bash.txt"
|
||||||
import { App } from "../app/app"
|
|
||||||
import { Permission } from "../permission"
|
import { Permission } from "../permission"
|
||||||
import { Filesystem } from "../util/filesystem"
|
import { Filesystem } from "../util/filesystem"
|
||||||
import { lazy } from "../util/lazy"
|
import { lazy } from "../util/lazy"
|
||||||
import { Log } from "../util/log"
|
import { Log } from "../util/log"
|
||||||
import { Wildcard } from "../util/wildcard"
|
import { Wildcard } from "../util/wildcard"
|
||||||
import { $ } from "bun"
|
import { $ } from "bun"
|
||||||
|
import { Instance } from "../project/instance"
|
||||||
import { Agent } from "../agent/agent"
|
import { Agent } from "../agent/agent"
|
||||||
|
|
||||||
const MAX_OUTPUT_LENGTH = 30_000
|
const MAX_OUTPUT_LENGTH = 30_000
|
||||||
@@ -56,7 +56,6 @@ export const BashTool = Tool.define("bash", {
|
|||||||
}),
|
}),
|
||||||
async execute(params, ctx) {
|
async execute(params, ctx) {
|
||||||
const timeout = Math.min(params.timeout ?? DEFAULT_TIMEOUT, MAX_TIMEOUT)
|
const timeout = Math.min(params.timeout ?? DEFAULT_TIMEOUT, MAX_TIMEOUT)
|
||||||
const app = App.info()
|
|
||||||
const tree = await parser().then((p) => p.parse(params.command))
|
const tree = await parser().then((p) => p.parse(params.command))
|
||||||
const permissions = await Agent.get(ctx.agent).then((x) => x.permission.bash)
|
const permissions = await Agent.get(ctx.agent).then((x) => x.permission.bash)
|
||||||
|
|
||||||
@@ -88,9 +87,9 @@ export const BashTool = Tool.define("bash", {
|
|||||||
.text()
|
.text()
|
||||||
.then((x) => x.trim())
|
.then((x) => x.trim())
|
||||||
log.info("resolved path", { arg, resolved })
|
log.info("resolved path", { arg, resolved })
|
||||||
if (resolved && !Filesystem.contains(app.path.cwd, resolved)) {
|
if (resolved && !Filesystem.contains(Instance.directory, resolved)) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`This command references paths outside of ${app.path.cwd} so it is not allowed to be executed.`,
|
`This command references paths outside of ${Instance.directory} so it is not allowed to be executed.`,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -123,7 +122,7 @@ export const BashTool = Tool.define("bash", {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const process = exec(params.command, {
|
const process = exec(params.command, {
|
||||||
cwd: app.path.cwd,
|
cwd: Instance.directory,
|
||||||
signal: ctx.abort,
|
signal: ctx.abort,
|
||||||
timeout,
|
timeout,
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -10,11 +10,11 @@ import { LSP } from "../lsp"
|
|||||||
import { createTwoFilesPatch } from "diff"
|
import { createTwoFilesPatch } from "diff"
|
||||||
import { Permission } from "../permission"
|
import { Permission } from "../permission"
|
||||||
import DESCRIPTION from "./edit.txt"
|
import DESCRIPTION from "./edit.txt"
|
||||||
import { App } from "../app/app"
|
|
||||||
import { File } from "../file"
|
import { File } from "../file"
|
||||||
import { Bus } from "../bus"
|
import { Bus } from "../bus"
|
||||||
import { FileTime } from "../file/time"
|
import { FileTime } from "../file/time"
|
||||||
import { Filesystem } from "../util/filesystem"
|
import { Filesystem } from "../util/filesystem"
|
||||||
|
import { Instance } from "../project/instance"
|
||||||
import { Agent } from "../agent/agent"
|
import { Agent } from "../agent/agent"
|
||||||
|
|
||||||
export const EditTool = Tool.define("edit", {
|
export const EditTool = Tool.define("edit", {
|
||||||
@@ -34,9 +34,8 @@ export const EditTool = Tool.define("edit", {
|
|||||||
throw new Error("oldString and newString must be different")
|
throw new Error("oldString and newString must be different")
|
||||||
}
|
}
|
||||||
|
|
||||||
const app = App.info()
|
const filePath = path.isAbsolute(params.filePath) ? params.filePath : path.join(Instance.directory, params.filePath)
|
||||||
const filePath = path.isAbsolute(params.filePath) ? params.filePath : path.join(app.path.cwd, params.filePath)
|
if (!Filesystem.contains(Instance.directory, filePath)) {
|
||||||
if (!Filesystem.contains(app.path.cwd, filePath)) {
|
|
||||||
throw new Error(`File ${filePath} is not in the current working directory`)
|
throw new Error(`File ${filePath} is not in the current working directory`)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -123,7 +122,7 @@ export const EditTool = Tool.define("edit", {
|
|||||||
diagnostics,
|
diagnostics,
|
||||||
diff,
|
diff,
|
||||||
},
|
},
|
||||||
title: `${path.relative(app.path.root, filePath)}`,
|
title: `${path.relative(Instance.worktree, filePath)}`,
|
||||||
output,
|
output,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import { z } from "zod"
|
import { z } from "zod"
|
||||||
import path from "path"
|
import path from "path"
|
||||||
import { Tool } from "./tool"
|
import { Tool } from "./tool"
|
||||||
import { App } from "../app/app"
|
|
||||||
import DESCRIPTION from "./glob.txt"
|
import DESCRIPTION from "./glob.txt"
|
||||||
import { Ripgrep } from "../file/ripgrep"
|
import { Ripgrep } from "../file/ripgrep"
|
||||||
|
import { Instance } from "../project/instance"
|
||||||
|
|
||||||
export const GlobTool = Tool.define("glob", {
|
export const GlobTool = Tool.define("glob", {
|
||||||
description: DESCRIPTION,
|
description: DESCRIPTION,
|
||||||
@@ -17,9 +17,8 @@ export const GlobTool = Tool.define("glob", {
|
|||||||
),
|
),
|
||||||
}),
|
}),
|
||||||
async execute(params) {
|
async execute(params) {
|
||||||
const app = App.info()
|
let search = params.path ?? Instance.directory
|
||||||
let search = params.path ?? app.path.cwd
|
search = path.isAbsolute(search) ? search : path.resolve(Instance.directory, search)
|
||||||
search = path.isAbsolute(search) ? search : path.resolve(app.path.cwd, search)
|
|
||||||
|
|
||||||
const limit = 100
|
const limit = 100
|
||||||
const files = []
|
const files = []
|
||||||
@@ -55,7 +54,7 @@ export const GlobTool = Tool.define("glob", {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
title: path.relative(app.path.root, search),
|
title: path.relative(Instance.worktree, search),
|
||||||
metadata: {
|
metadata: {
|
||||||
count: files.length,
|
count: files.length,
|
||||||
truncated,
|
truncated,
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import { z } from "zod"
|
import { z } from "zod"
|
||||||
import { Tool } from "./tool"
|
import { Tool } from "./tool"
|
||||||
import { App } from "../app/app"
|
|
||||||
import { Ripgrep } from "../file/ripgrep"
|
import { Ripgrep } from "../file/ripgrep"
|
||||||
|
|
||||||
import DESCRIPTION from "./grep.txt"
|
import DESCRIPTION from "./grep.txt"
|
||||||
|
import { Instance } from "../project/instance"
|
||||||
|
|
||||||
export const GrepTool = Tool.define("grep", {
|
export const GrepTool = Tool.define("grep", {
|
||||||
description: DESCRIPTION,
|
description: DESCRIPTION,
|
||||||
@@ -17,8 +17,7 @@ export const GrepTool = Tool.define("grep", {
|
|||||||
throw new Error("pattern is required")
|
throw new Error("pattern is required")
|
||||||
}
|
}
|
||||||
|
|
||||||
const app = App.info()
|
const searchPath = params.path || Instance.directory
|
||||||
const searchPath = params.path || app.path.cwd
|
|
||||||
|
|
||||||
const rgPath = await Ripgrep.filepath()
|
const rgPath = await Ripgrep.filepath()
|
||||||
const args = ["-n", params.pattern]
|
const args = ["-n", params.pattern]
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { z } from "zod"
|
import { z } from "zod"
|
||||||
import { Tool } from "./tool"
|
import { Tool } from "./tool"
|
||||||
import { App } from "../app/app"
|
|
||||||
import * as path from "path"
|
import * as path from "path"
|
||||||
import DESCRIPTION from "./ls.txt"
|
import DESCRIPTION from "./ls.txt"
|
||||||
|
import { Instance } from "../project/instance"
|
||||||
|
|
||||||
export const IGNORE_PATTERNS = [
|
export const IGNORE_PATTERNS = [
|
||||||
"node_modules/",
|
"node_modules/",
|
||||||
@@ -40,8 +40,7 @@ export const ListTool = Tool.define("list", {
|
|||||||
ignore: z.array(z.string()).describe("List of glob patterns to ignore").optional(),
|
ignore: z.array(z.string()).describe("List of glob patterns to ignore").optional(),
|
||||||
}),
|
}),
|
||||||
async execute(params) {
|
async execute(params) {
|
||||||
const app = App.info()
|
const searchPath = path.resolve(Instance.directory, params.path || ".")
|
||||||
const searchPath = path.resolve(app.path.cwd, params.path || ".")
|
|
||||||
|
|
||||||
const glob = new Bun.Glob("**/*")
|
const glob = new Bun.Glob("**/*")
|
||||||
const files = []
|
const files = []
|
||||||
@@ -102,7 +101,7 @@ export const ListTool = Tool.define("list", {
|
|||||||
const output = `${searchPath}/\n` + renderDir(".", 0)
|
const output = `${searchPath}/\n` + renderDir(".", 0)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
title: path.relative(app.path.root, searchPath),
|
title: path.relative(Instance.worktree, searchPath),
|
||||||
metadata: {
|
metadata: {
|
||||||
count: files.length,
|
count: files.length,
|
||||||
truncated: files.length >= LIMIT,
|
truncated: files.length >= LIMIT,
|
||||||
|
|||||||
@@ -2,8 +2,8 @@ import { z } from "zod"
|
|||||||
import { Tool } from "./tool"
|
import { Tool } from "./tool"
|
||||||
import path from "path"
|
import path from "path"
|
||||||
import { LSP } from "../lsp"
|
import { LSP } from "../lsp"
|
||||||
import { App } from "../app/app"
|
|
||||||
import DESCRIPTION from "./lsp-diagnostics.txt"
|
import DESCRIPTION from "./lsp-diagnostics.txt"
|
||||||
|
import { Instance } from "../project/instance"
|
||||||
|
|
||||||
export const LspDiagnosticTool = Tool.define("lsp_diagnostics", {
|
export const LspDiagnosticTool = Tool.define("lsp_diagnostics", {
|
||||||
description: DESCRIPTION,
|
description: DESCRIPTION,
|
||||||
@@ -11,13 +11,12 @@ export const LspDiagnosticTool = Tool.define("lsp_diagnostics", {
|
|||||||
path: z.string().describe("The path to the file to get diagnostics."),
|
path: z.string().describe("The path to the file to get diagnostics."),
|
||||||
}),
|
}),
|
||||||
execute: async (args) => {
|
execute: async (args) => {
|
||||||
const app = App.info()
|
const normalized = path.isAbsolute(args.path) ? args.path : path.join(Instance.directory, args.path)
|
||||||
const normalized = path.isAbsolute(args.path) ? args.path : path.join(app.path.cwd, args.path)
|
|
||||||
await LSP.touchFile(normalized, true)
|
await LSP.touchFile(normalized, true)
|
||||||
const diagnostics = await LSP.diagnostics()
|
const diagnostics = await LSP.diagnostics()
|
||||||
const file = diagnostics[normalized]
|
const file = diagnostics[normalized]
|
||||||
return {
|
return {
|
||||||
title: path.relative(app.path.root, normalized),
|
title: path.relative(Instance.worktree, normalized),
|
||||||
metadata: {
|
metadata: {
|
||||||
diagnostics,
|
diagnostics,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -2,8 +2,8 @@ import { z } from "zod"
|
|||||||
import { Tool } from "./tool"
|
import { Tool } from "./tool"
|
||||||
import path from "path"
|
import path from "path"
|
||||||
import { LSP } from "../lsp"
|
import { LSP } from "../lsp"
|
||||||
import { App } from "../app/app"
|
|
||||||
import DESCRIPTION from "./lsp-hover.txt"
|
import DESCRIPTION from "./lsp-hover.txt"
|
||||||
|
import { Instance } from "../project/instance"
|
||||||
|
|
||||||
export const LspHoverTool = Tool.define("lsp_hover", {
|
export const LspHoverTool = Tool.define("lsp_hover", {
|
||||||
description: DESCRIPTION,
|
description: DESCRIPTION,
|
||||||
@@ -13,8 +13,7 @@ export const LspHoverTool = Tool.define("lsp_hover", {
|
|||||||
character: z.number().describe("The character number to get diagnostics."),
|
character: z.number().describe("The character number to get diagnostics."),
|
||||||
}),
|
}),
|
||||||
execute: async (args) => {
|
execute: async (args) => {
|
||||||
const app = App.info()
|
const file = path.isAbsolute(args.file) ? args.file : path.join(Instance.directory, args.file)
|
||||||
const file = path.isAbsolute(args.file) ? args.file : path.join(app.path.cwd, args.file)
|
|
||||||
await LSP.touchFile(file, true)
|
await LSP.touchFile(file, true)
|
||||||
const result = await LSP.hover({
|
const result = await LSP.hover({
|
||||||
...args,
|
...args,
|
||||||
@@ -22,7 +21,7 @@ export const LspHoverTool = Tool.define("lsp_hover", {
|
|||||||
})
|
})
|
||||||
|
|
||||||
return {
|
return {
|
||||||
title: path.relative(app.path.root, file) + ":" + args.line + ":" + args.character,
|
title: path.relative(Instance.worktree, file) + ":" + args.line + ":" + args.character,
|
||||||
metadata: {
|
metadata: {
|
||||||
result,
|
result,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { Tool } from "./tool"
|
|||||||
import { EditTool } from "./edit"
|
import { EditTool } from "./edit"
|
||||||
import DESCRIPTION from "./multiedit.txt"
|
import DESCRIPTION from "./multiedit.txt"
|
||||||
import path from "path"
|
import path from "path"
|
||||||
import { App } from "../app/app"
|
import { Instance } from "../project/instance"
|
||||||
|
|
||||||
export const MultiEditTool = Tool.define("multiedit", {
|
export const MultiEditTool = Tool.define("multiedit", {
|
||||||
description: DESCRIPTION,
|
description: DESCRIPTION,
|
||||||
@@ -35,9 +35,8 @@ export const MultiEditTool = Tool.define("multiedit", {
|
|||||||
)
|
)
|
||||||
results.push(result)
|
results.push(result)
|
||||||
}
|
}
|
||||||
const app = App.info()
|
|
||||||
return {
|
return {
|
||||||
title: path.relative(app.path.root, params.filePath),
|
title: path.relative(Instance.worktree, params.filePath),
|
||||||
metadata: {
|
metadata: {
|
||||||
results: results.map((r) => r.metadata),
|
results: results.map((r) => r.metadata),
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ import { Tool } from "./tool"
|
|||||||
import { LSP } from "../lsp"
|
import { LSP } from "../lsp"
|
||||||
import { FileTime } from "../file/time"
|
import { FileTime } from "../file/time"
|
||||||
import DESCRIPTION from "./read.txt"
|
import DESCRIPTION from "./read.txt"
|
||||||
import { App } from "../app/app"
|
|
||||||
import { Filesystem } from "../util/filesystem"
|
import { Filesystem } from "../util/filesystem"
|
||||||
|
import { Instance } from "../project/instance"
|
||||||
|
|
||||||
const DEFAULT_READ_LIMIT = 2000
|
const DEFAULT_READ_LIMIT = 2000
|
||||||
const MAX_LINE_LENGTH = 2000
|
const MAX_LINE_LENGTH = 2000
|
||||||
@@ -23,8 +23,7 @@ export const ReadTool = Tool.define("read", {
|
|||||||
if (!path.isAbsolute(filepath)) {
|
if (!path.isAbsolute(filepath)) {
|
||||||
filepath = path.join(process.cwd(), filepath)
|
filepath = path.join(process.cwd(), filepath)
|
||||||
}
|
}
|
||||||
const app = App.info()
|
if (!ctx.extra?.["bypassCwdCheck"] && !Filesystem.contains(Instance.directory, filepath)) {
|
||||||
if (!ctx.extra?.["bypassCwdCheck"] && !Filesystem.contains(app.path.cwd, filepath)) {
|
|
||||||
throw new Error(`File ${filepath} is not in the current working directory`)
|
throw new Error(`File ${filepath} is not in the current working directory`)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -77,7 +76,7 @@ export const ReadTool = Tool.define("read", {
|
|||||||
FileTime.read(ctx.sessionID, filepath)
|
FileTime.read(ctx.sessionID, filepath)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
title: path.relative(App.info().path.root, filepath),
|
title: path.relative(Instance.worktree, filepath),
|
||||||
output,
|
output,
|
||||||
metadata: {
|
metadata: {
|
||||||
preview,
|
preview,
|
||||||
|
|||||||
@@ -51,11 +51,13 @@ export const TaskTool = Tool.define("task", async () => {
|
|||||||
ctx.abort.addEventListener("abort", () => {
|
ctx.abort.addEventListener("abort", () => {
|
||||||
Session.abort(session.id)
|
Session.abort(session.id)
|
||||||
})
|
})
|
||||||
const result = await Session.chat({
|
const result = await Session.prompt({
|
||||||
messageID,
|
messageID,
|
||||||
sessionID: session.id,
|
sessionID: session.id,
|
||||||
modelID: model.modelID,
|
model: {
|
||||||
providerID: model.providerID,
|
modelID: model.modelID,
|
||||||
|
providerID: model.providerID,
|
||||||
|
},
|
||||||
agent: agent.name,
|
agent: agent.name,
|
||||||
tools: {
|
tools: {
|
||||||
todowrite: false,
|
todowrite: false,
|
||||||
@@ -75,9 +77,9 @@ export const TaskTool = Tool.define("task", async () => {
|
|||||||
return {
|
return {
|
||||||
title: params.description,
|
title: params.description,
|
||||||
metadata: {
|
metadata: {
|
||||||
summary: result.parts.filter((x) => x.type === "tool"),
|
summary: result.parts.filter((x: any) => x.type === "tool"),
|
||||||
},
|
},
|
||||||
output: result.parts.findLast((x) => x.type === "text")?.text ?? "",
|
output: (result.parts.findLast((x: any) => x.type === "text") as any)?.text ?? "",
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { z } from "zod"
|
import { z } from "zod"
|
||||||
import { Tool } from "./tool"
|
import { Tool } from "./tool"
|
||||||
import DESCRIPTION_WRITE from "./todowrite.txt"
|
import DESCRIPTION_WRITE from "./todowrite.txt"
|
||||||
import { App } from "../app/app"
|
import { Instance } from "../project/instance"
|
||||||
|
|
||||||
const TodoInfo = z.object({
|
const TodoInfo = z.object({
|
||||||
content: z.string().describe("Brief description of the task"),
|
content: z.string().describe("Brief description of the task"),
|
||||||
@@ -11,12 +11,14 @@ const TodoInfo = z.object({
|
|||||||
})
|
})
|
||||||
type TodoInfo = z.infer<typeof TodoInfo>
|
type TodoInfo = z.infer<typeof TodoInfo>
|
||||||
|
|
||||||
const state = App.state("todo-tool", () => {
|
const state = Instance.state(
|
||||||
const todos: {
|
() => {
|
||||||
[sessionId: string]: TodoInfo[]
|
const todos: {
|
||||||
} = {}
|
[sessionId: string]: TodoInfo[]
|
||||||
return todos
|
} = {}
|
||||||
})
|
return todos
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
export const TodoWriteTool = Tool.define("todowrite", {
|
export const TodoWriteTool = Tool.define("todowrite", {
|
||||||
description: DESCRIPTION_WRITE,
|
description: DESCRIPTION_WRITE,
|
||||||
|
|||||||
@@ -4,11 +4,11 @@ import { Tool } from "./tool"
|
|||||||
import { LSP } from "../lsp"
|
import { LSP } from "../lsp"
|
||||||
import { Permission } from "../permission"
|
import { Permission } from "../permission"
|
||||||
import DESCRIPTION from "./write.txt"
|
import DESCRIPTION from "./write.txt"
|
||||||
import { App } from "../app/app"
|
|
||||||
import { Bus } from "../bus"
|
import { Bus } from "../bus"
|
||||||
import { File } from "../file"
|
import { File } from "../file"
|
||||||
import { FileTime } from "../file/time"
|
import { FileTime } from "../file/time"
|
||||||
import { Filesystem } from "../util/filesystem"
|
import { Filesystem } from "../util/filesystem"
|
||||||
|
import { Instance } from "../project/instance"
|
||||||
import { Agent } from "../agent/agent"
|
import { Agent } from "../agent/agent"
|
||||||
|
|
||||||
export const WriteTool = Tool.define("write", {
|
export const WriteTool = Tool.define("write", {
|
||||||
@@ -18,9 +18,8 @@ export const WriteTool = Tool.define("write", {
|
|||||||
content: z.string().describe("The content to write to the file"),
|
content: z.string().describe("The content to write to the file"),
|
||||||
}),
|
}),
|
||||||
async execute(params, ctx) {
|
async execute(params, ctx) {
|
||||||
const app = App.info()
|
const filepath = path.isAbsolute(params.filePath) ? params.filePath : path.join(Instance.directory, params.filePath)
|
||||||
const filepath = path.isAbsolute(params.filePath) ? params.filePath : path.join(app.path.cwd, params.filePath)
|
if (!Filesystem.contains(Instance.directory, filepath)) {
|
||||||
if (!Filesystem.contains(app.path.cwd, filepath)) {
|
|
||||||
throw new Error(`File ${filepath} is not in the current working directory`)
|
throw new Error(`File ${filepath} is not in the current working directory`)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -62,7 +61,7 @@ export const WriteTool = Tool.define("write", {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
title: path.relative(app.path.root, filepath),
|
title: path.relative(Instance.worktree, filepath),
|
||||||
metadata: {
|
metadata: {
|
||||||
diagnostics,
|
diagnostics,
|
||||||
filepath,
|
filepath,
|
||||||
|
|||||||
98
packages/opencode/src/util/lock.ts
Normal file
98
packages/opencode/src/util/lock.ts
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
export namespace Lock {
|
||||||
|
const locks = new Map<
|
||||||
|
string,
|
||||||
|
{
|
||||||
|
readers: number
|
||||||
|
writer: boolean
|
||||||
|
waitingReaders: (() => void)[]
|
||||||
|
waitingWriters: (() => void)[]
|
||||||
|
}
|
||||||
|
>()
|
||||||
|
|
||||||
|
function get(key: string) {
|
||||||
|
if (!locks.has(key)) {
|
||||||
|
locks.set(key, {
|
||||||
|
readers: 0,
|
||||||
|
writer: false,
|
||||||
|
waitingReaders: [],
|
||||||
|
waitingWriters: [],
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return locks.get(key)!
|
||||||
|
}
|
||||||
|
|
||||||
|
function process(key: string) {
|
||||||
|
const lock = locks.get(key)
|
||||||
|
if (!lock || lock.writer || lock.readers > 0) return
|
||||||
|
|
||||||
|
// Prioritize writers to prevent starvation
|
||||||
|
if (lock.waitingWriters.length > 0) {
|
||||||
|
const nextWriter = lock.waitingWriters.shift()!
|
||||||
|
nextWriter()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wake up all waiting readers
|
||||||
|
while (lock.waitingReaders.length > 0) {
|
||||||
|
const nextReader = lock.waitingReaders.shift()!
|
||||||
|
nextReader()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clean up empty locks
|
||||||
|
if (lock.readers === 0 && !lock.writer && lock.waitingReaders.length === 0 && lock.waitingWriters.length === 0) {
|
||||||
|
locks.delete(key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function read(key: string): Promise<Disposable> {
|
||||||
|
const lock = get(key)
|
||||||
|
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
if (!lock.writer && lock.waitingWriters.length === 0) {
|
||||||
|
lock.readers++
|
||||||
|
resolve({
|
||||||
|
[Symbol.dispose]: () => {
|
||||||
|
lock.readers--
|
||||||
|
process(key)
|
||||||
|
},
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
lock.waitingReaders.push(() => {
|
||||||
|
lock.readers++
|
||||||
|
resolve({
|
||||||
|
[Symbol.dispose]: () => {
|
||||||
|
lock.readers--
|
||||||
|
process(key)
|
||||||
|
},
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function write(key: string): Promise<Disposable> {
|
||||||
|
const lock = get(key)
|
||||||
|
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
if (!lock.writer && lock.readers === 0) {
|
||||||
|
lock.writer = true
|
||||||
|
resolve({
|
||||||
|
[Symbol.dispose]: () => {
|
||||||
|
lock.writer = false
|
||||||
|
process(key)
|
||||||
|
},
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
lock.waitingWriters.push(() => {
|
||||||
|
lock.writer = true
|
||||||
|
resolve({
|
||||||
|
[Symbol.dispose]: () => {
|
||||||
|
lock.writer = false
|
||||||
|
process(key)
|
||||||
|
},
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
import { describe, expect, test } from "bun:test"
|
import { describe, expect, test } from "bun:test"
|
||||||
import { App } from "../../src/app/app"
|
|
||||||
import path from "path"
|
import path from "path"
|
||||||
import { BashTool } from "../../src/tool/bash"
|
import { BashTool } from "../../src/tool/bash"
|
||||||
import { Log } from "../../src/util/log"
|
import { Log } from "../../src/util/log"
|
||||||
|
import { Instance } from "../../src/project/instance"
|
||||||
|
|
||||||
const ctx = {
|
const ctx = {
|
||||||
sessionID: "test",
|
sessionID: "test",
|
||||||
@@ -19,7 +19,7 @@ Log.init({ print: false })
|
|||||||
|
|
||||||
describe("tool.bash", () => {
|
describe("tool.bash", () => {
|
||||||
test("basic", async () => {
|
test("basic", async () => {
|
||||||
await App.provide({ cwd: projectRoot }, async () => {
|
await Instance.provide(projectRoot, async () => {
|
||||||
const result = await bash.execute(
|
const result = await bash.execute(
|
||||||
{
|
{
|
||||||
command: "echo 'test'",
|
command: "echo 'test'",
|
||||||
@@ -33,7 +33,7 @@ describe("tool.bash", () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
test("cd ../ should fail outside of project root", async () => {
|
test("cd ../ should fail outside of project root", async () => {
|
||||||
await App.provide({ cwd: projectRoot }, async () => {
|
await Instance.provide(projectRoot, async () => {
|
||||||
expect(
|
expect(
|
||||||
bash.execute(
|
bash.execute(
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { describe, expect, test } from "bun:test"
|
import { describe, expect, test } from "bun:test"
|
||||||
import { App } from "../../src/app/app"
|
|
||||||
import { GlobTool } from "../../src/tool/glob"
|
import { GlobTool } from "../../src/tool/glob"
|
||||||
import { ListTool } from "../../src/tool/ls"
|
import { ListTool } from "../../src/tool/ls"
|
||||||
import path from "path"
|
import path from "path"
|
||||||
|
import { Instance } from "../../src/project/instance"
|
||||||
|
|
||||||
const ctx = {
|
const ctx = {
|
||||||
sessionID: "test",
|
sessionID: "test",
|
||||||
@@ -20,7 +20,7 @@ const fixturePath = path.join(__dirname, "../fixtures/example")
|
|||||||
|
|
||||||
describe("tool.glob", () => {
|
describe("tool.glob", () => {
|
||||||
test("truncate", async () => {
|
test("truncate", async () => {
|
||||||
await App.provide({ cwd: projectRoot }, async () => {
|
await Instance.provide(projectRoot, async () => {
|
||||||
let result = await glob.execute(
|
let result = await glob.execute(
|
||||||
{
|
{
|
||||||
pattern: "**/*",
|
pattern: "**/*",
|
||||||
@@ -32,7 +32,7 @@ describe("tool.glob", () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
test("basic", async () => {
|
test("basic", async () => {
|
||||||
await App.provide({ cwd: projectRoot }, async () => {
|
await Instance.provide(projectRoot, async () => {
|
||||||
let result = await glob.execute(
|
let result = await glob.execute(
|
||||||
{
|
{
|
||||||
pattern: "*.json",
|
pattern: "*.json",
|
||||||
@@ -50,7 +50,7 @@ describe("tool.glob", () => {
|
|||||||
|
|
||||||
describe("tool.ls", () => {
|
describe("tool.ls", () => {
|
||||||
test("basic", async () => {
|
test("basic", async () => {
|
||||||
const result = await App.provide({ cwd: projectRoot }, async () => {
|
const result = await Instance.provide(projectRoot, async () => {
|
||||||
return await list.execute({ path: fixturePath, ignore: [".git"] }, ctx)
|
return await list.execute({ path: fixturePath, ignore: [".git"] }, ctx)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { Plugin } from "./index"
|
import { Plugin } from "./index"
|
||||||
|
|
||||||
export const ExamplePlugin: Plugin = async ({ app, client, $ }) => {
|
export const ExamplePlugin: Plugin = async ({ client, $ }) => {
|
||||||
return {
|
return {
|
||||||
permission: {},
|
permission: {},
|
||||||
async "chat.params"(input, output) {
|
async "chat.params"(input, output) {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import type {
|
import type {
|
||||||
Event,
|
Event,
|
||||||
createOpencodeClient,
|
createOpencodeClient,
|
||||||
App,
|
Project,
|
||||||
Model,
|
Model,
|
||||||
Provider,
|
Provider,
|
||||||
Permission,
|
Permission,
|
||||||
@@ -14,7 +14,9 @@ import type { BunShell } from "./shell"
|
|||||||
|
|
||||||
export type PluginInput = {
|
export type PluginInput = {
|
||||||
client: ReturnType<typeof createOpencodeClient>
|
client: ReturnType<typeof createOpencodeClient>
|
||||||
app: App
|
project: Project
|
||||||
|
directory: string
|
||||||
|
worktree: string
|
||||||
$: BunShell
|
$: BunShell
|
||||||
}
|
}
|
||||||
export type Plugin = (input: PluginInput) => Promise<Hooks>
|
export type Plugin = (input: PluginInput) => Promise<Hooks>
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
{
|
{
|
||||||
".": "0.1.0-alpha.8"
|
".": "0.8.0"
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
configured_endpoints: 41
|
configured_endpoints: 43
|
||||||
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/opencode%2Fopencode-6d8e9dfd438cac63fc7d689ea29adfff81ff8880c2d8e1e10fc36f375a721594.yml
|
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/opencode%2Fopencode-97b61518d8666ea7cb310af04248e00bcf8dc9753ba3c7e84471df72b3232004.yml
|
||||||
openapi_spec_hash: 7ac6028dd5957c67a98d91e790863c80
|
openapi_spec_hash: a3500531973ad999c350b87c21aa3ab8
|
||||||
config_hash: fb625e876313a9f8f31532348fa91f59
|
config_hash: 026ef000d34bf2f930e7b41e77d2d3ff
|
||||||
|
|||||||
@@ -1,73 +1,122 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
## 0.1.0-alpha.8 (2025-07-02)
|
## 0.8.0 (2025-09-01)
|
||||||
|
|
||||||
Full Changelog: [v0.1.0-alpha.7...v0.1.0-alpha.8](https://github.com/sst/opencode-sdk-go/compare/v0.1.0-alpha.7...v0.1.0-alpha.8)
|
Full Changelog: [v0.7.0...v0.8.0](https://github.com/sst/opencode-sdk-go/compare/v0.7.0...v0.8.0)
|
||||||
|
|
||||||
### Features
|
### Features
|
||||||
|
|
||||||
* **api:** update via SDK Studio ([651e937](https://github.com/sst/opencode-sdk-go/commit/651e937c334e1caba3b968e6cac865c219879519))
|
* **api:** api update ([ae87a71](https://github.com/sst/opencode-sdk-go/commit/ae87a71949994590ace8285a39f0991ef34b664d))
|
||||||
|
|
||||||
## 0.1.0-alpha.7 (2025-06-30)
|
## 0.7.0 (2025-09-01)
|
||||||
|
|
||||||
Full Changelog: [v0.1.0-alpha.6...v0.1.0-alpha.7](https://github.com/sst/opencode-sdk-go/compare/v0.1.0-alpha.6...v0.1.0-alpha.7)
|
Full Changelog: [v0.6.0...v0.7.0](https://github.com/sst/opencode-sdk-go/compare/v0.6.0...v0.7.0)
|
||||||
|
|
||||||
### Features
|
### Features
|
||||||
|
|
||||||
|
* **api:** api update ([64bb1b1](https://github.com/sst/opencode-sdk-go/commit/64bb1b1ee0cbe153abc6fb7bd9703b47911724d4))
|
||||||
|
|
||||||
|
## 0.6.0 (2025-09-01)
|
||||||
|
|
||||||
|
Full Changelog: [v0.5.0...v0.6.0](https://github.com/sst/opencode-sdk-go/compare/v0.5.0...v0.6.0)
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **api:** api update ([928e384](https://github.com/sst/opencode-sdk-go/commit/928e3843355f96899f046f002b84372281dad0c8))
|
||||||
|
|
||||||
|
## 0.5.0 (2025-08-31)
|
||||||
|
|
||||||
|
Full Changelog: [v0.4.0...v0.5.0](https://github.com/sst/opencode-sdk-go/compare/v0.4.0...v0.5.0)
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **api:** api update ([44b281d](https://github.com/sst/opencode-sdk-go/commit/44b281d0bb39c5022a984ac9d0fca1529ccc0604))
|
||||||
|
|
||||||
|
## 0.4.0 (2025-08-31)
|
||||||
|
|
||||||
|
Full Changelog: [v0.3.0...v0.4.0](https://github.com/sst/opencode-sdk-go/compare/v0.3.0...v0.4.0)
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **api:** api update ([fa9d6ec](https://github.com/sst/opencode-sdk-go/commit/fa9d6ec6472e62f4f6605d0a71a7aa8bf8a24559))
|
||||||
|
|
||||||
|
## 0.3.0 (2025-08-31)
|
||||||
|
|
||||||
|
Full Changelog: [v0.2.0...v0.3.0](https://github.com/sst/opencode-sdk-go/compare/v0.2.0...v0.3.0)
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **api:** api update ([aae1c06](https://github.com/sst/opencode-sdk-go/commit/aae1c06bb5a93a1cd9c589846a84b3f16246f5da))
|
||||||
|
|
||||||
|
## 0.2.0 (2025-08-31)
|
||||||
|
|
||||||
|
Full Changelog: [v0.1.0...v0.2.0](https://github.com/sst/opencode-sdk-go/compare/v0.1.0...v0.2.0)
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **api:** api update ([1472790](https://github.com/sst/opencode-sdk-go/commit/1472790542515f47bd46e2a9e28d8afea024cf9c))
|
||||||
|
|
||||||
|
## 0.1.0 (2025-08-31)
|
||||||
|
|
||||||
|
Full Changelog: [v0.0.1...v0.1.0](https://github.com/sst/opencode-sdk-go/compare/v0.0.1...v0.1.0)
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **api:** api update ([3f03ddd](https://github.com/sst/opencode-sdk-go/commit/3f03dddd5ec0de98f99ce48679077dcae9ceffd6))
|
||||||
|
* **api:** api update ([e9f79c4](https://github.com/sst/opencode-sdk-go/commit/e9f79c4792b21ef64ab0431ffd76f5a71e04d182))
|
||||||
|
* **api:** api update ([139a686](https://github.com/sst/opencode-sdk-go/commit/139a6862d2f0ab0c8ea791663d736868be3e96e6))
|
||||||
|
* **api:** api update ([2ed0800](https://github.com/sst/opencode-sdk-go/commit/2ed0800b2c5b99877e9f7fde669a6c005fad6b77))
|
||||||
|
* **api:** api update ([88a87a4](https://github.com/sst/opencode-sdk-go/commit/88a87a458f56ce0c18b502c73da933f614f56e8b))
|
||||||
|
* **api:** api update ([0e5d65b](https://github.com/sst/opencode-sdk-go/commit/0e5d65b571e7b30dc6347e6730098878ebba3a42))
|
||||||
|
* **api:** api update ([ba381f1](https://github.com/sst/opencode-sdk-go/commit/ba381f1e07aad24e9824df7d53befae2a644f69f))
|
||||||
|
* **api:** api update ([3f429f5](https://github.com/sst/opencode-sdk-go/commit/3f429f5b4be5607433ef5fdc0d5bf67fe590d039))
|
||||||
|
* **api:** api update ([9f34787](https://github.com/sst/opencode-sdk-go/commit/9f347876b35b7f898060c1a5f71c322e95978e3e))
|
||||||
|
* **api:** api update ([379c8e0](https://github.com/sst/opencode-sdk-go/commit/379c8e00197e13aebaf2f2d61277b125f1f90011))
|
||||||
|
* **api:** api update ([550511c](https://github.com/sst/opencode-sdk-go/commit/550511c4c5b5055ac8ff22b7b11731331bd9d088))
|
||||||
|
* **api:** api update ([547f0c2](https://github.com/sst/opencode-sdk-go/commit/547f0c262f2df1ce83eaa7267d68be64bb29b841))
|
||||||
|
* **api:** api update ([b7b0720](https://github.com/sst/opencode-sdk-go/commit/b7b07204bff314da24b1819c128835a43ef64065))
|
||||||
|
* **api:** api update ([7250ffc](https://github.com/sst/opencode-sdk-go/commit/7250ffcba262b916c958ddecc2a42927982db39f))
|
||||||
|
* **api:** api update ([17fbab7](https://github.com/sst/opencode-sdk-go/commit/17fbab73111a3eae488737c69b12370bc69c65f7))
|
||||||
|
* **api:** api update ([1270b5c](https://github.com/sst/opencode-sdk-go/commit/1270b5cd81e6ac769dcd92ade6d877891bf51bd5))
|
||||||
|
* **api:** api update ([a238d4a](https://github.com/sst/opencode-sdk-go/commit/a238d4abd6ed7d15f3547d27a4b6ecf4aec8431e))
|
||||||
|
* **api:** api update ([7475655](https://github.com/sst/opencode-sdk-go/commit/7475655aca577fe4f807c2f02f92171f6a358e9c))
|
||||||
|
* **api:** api update ([429d258](https://github.com/sst/opencode-sdk-go/commit/429d258bb56e9cdeb1528be3944bf5537ac26a96))
|
||||||
|
* **api:** api update ([f250915](https://github.com/sst/opencode-sdk-go/commit/f2509157eaf1b453e741ee9482127cad2e3ace25))
|
||||||
|
* **api:** api update ([5efc987](https://github.com/sst/opencode-sdk-go/commit/5efc987353801d1e772c20edf162b1c75da32743))
|
||||||
|
* **api:** api update ([98a8350](https://github.com/sst/opencode-sdk-go/commit/98a83504f7cfc361e83314c3e79a4e9ff53f0560))
|
||||||
|
* **api:** api update ([6da8bf8](https://github.com/sst/opencode-sdk-go/commit/6da8bf8bfe91d45991fb580753d77c5534fc0b1b))
|
||||||
|
* **api:** api update ([f8c7148](https://github.com/sst/opencode-sdk-go/commit/f8c7148ae56143823186e2675a78e82676154956))
|
||||||
|
* **api:** manual updates ([7cf038f](https://github.com/sst/opencode-sdk-go/commit/7cf038ffae5da1b77e1cef11b5fa166a53b467f2))
|
||||||
|
* **api:** update via SDK Studio ([068a0eb](https://github.com/sst/opencode-sdk-go/commit/068a0eb025010da0c8d86fa1bb496a39dbedcef9))
|
||||||
|
* **api:** update via SDK Studio ([ca651ed](https://github.com/sst/opencode-sdk-go/commit/ca651edaf71d1f3678f929287474f5bc4f1aad10))
|
||||||
* **api:** update via SDK Studio ([13550a5](https://github.com/sst/opencode-sdk-go/commit/13550a5c65d77325e945ed99fe0799cd1107b775))
|
* **api:** update via SDK Studio ([13550a5](https://github.com/sst/opencode-sdk-go/commit/13550a5c65d77325e945ed99fe0799cd1107b775))
|
||||||
* **api:** update via SDK Studio ([7b73730](https://github.com/sst/opencode-sdk-go/commit/7b73730c7fa62ba966dda3541c3e97b49be8d2bf))
|
* **api:** update via SDK Studio ([7b73730](https://github.com/sst/opencode-sdk-go/commit/7b73730c7fa62ba966dda3541c3e97b49be8d2bf))
|
||||||
|
* **api:** update via SDK Studio ([9e39a59](https://github.com/sst/opencode-sdk-go/commit/9e39a59b3d5d1bd5e64633732521fb28362cc70e))
|
||||||
|
* **api:** update via SDK Studio ([9609d1b](https://github.com/sst/opencode-sdk-go/commit/9609d1b1db7806d00cb846c9914cb4935cdedf52))
|
||||||
|
* **api:** update via SDK Studio ([51315fa](https://github.com/sst/opencode-sdk-go/commit/51315fa2eae424743ea79701e67d44447c44144d))
|
||||||
|
* **api:** update via SDK Studio ([af07955](https://github.com/sst/opencode-sdk-go/commit/af0795543240aefaf04fc7663a348825541c79ed))
|
||||||
|
* **api:** update via SDK Studio ([5e3468a](https://github.com/sst/opencode-sdk-go/commit/5e3468a0aaa5ed3b13e019c3a24e0ba9147d1675))
|
||||||
|
* **api:** update via SDK Studio ([0a73e04](https://github.com/sst/opencode-sdk-go/commit/0a73e04c23c90b2061611edaa8fd6282dc0ce397))
|
||||||
|
* **api:** update via SDK Studio ([9b7883a](https://github.com/sst/opencode-sdk-go/commit/9b7883a144eeac526d9d04538e0876a9d18bb844))
|
||||||
|
* **client:** expand max streaming buffer size ([76303e5](https://github.com/sst/opencode-sdk-go/commit/76303e51067e78e732af26ced9d83b8bad7655c3))
|
||||||
|
* **client:** support optional json html escaping ([449748f](https://github.com/sst/opencode-sdk-go/commit/449748f35a1d8cb6f91dc36d25bf9489f4f371bd))
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **client:** process custom base url ahead of time ([9b360d6](https://github.com/sst/opencode-sdk-go/commit/9b360d642cf6f302104308af5622e17099899e5f))
|
||||||
|
* **client:** resolve lint errors in streaming tests ([4d36cb0](https://github.com/sst/opencode-sdk-go/commit/4d36cb09fc9d436734d5dab1c499acaa88568ff7))
|
||||||
|
* close body before retrying ([4da3f7f](https://github.com/sst/opencode-sdk-go/commit/4da3f7f372bad222a189ba3eabcfde3373166ae5))
|
||||||
|
* don't try to deserialize as json when ResponseBodyInto is []byte ([595291f](https://github.com/sst/opencode-sdk-go/commit/595291f6dba6af472f160b9f8e3d145002f43a4a))
|
||||||
|
|
||||||
|
|
||||||
### Chores
|
### Chores
|
||||||
|
|
||||||
* **ci:** only run for pushes and fork pull requests ([bea59b8](https://github.com/sst/opencode-sdk-go/commit/bea59b886800ef555f89c47a9256d6392ed2e53d))
|
* **ci:** only run for pushes and fork pull requests ([bea59b8](https://github.com/sst/opencode-sdk-go/commit/bea59b886800ef555f89c47a9256d6392ed2e53d))
|
||||||
|
* **internal:** codegen related update ([6a22ce6](https://github.com/sst/opencode-sdk-go/commit/6a22ce6df155f5003e80b8a75686a9e513a5568a))
|
||||||
## 0.1.0-alpha.6 (2025-06-28)
|
* **internal:** fix lint script for tests ([391c482](https://github.com/sst/opencode-sdk-go/commit/391c482148ed0a77c4ad52807abeb2d540b56797))
|
||||||
|
* **internal:** update comment in script ([b7f1c3e](https://github.com/sst/opencode-sdk-go/commit/b7f1c3e16935c71e243004b8f321d661cd8e9474))
|
||||||
Full Changelog: [v0.1.0-alpha.5...v0.1.0-alpha.6](https://github.com/sst/opencode-sdk-go/compare/v0.1.0-alpha.5...v0.1.0-alpha.6)
|
* lint tests ([616796b](https://github.com/sst/opencode-sdk-go/commit/616796b761704bde6be5c6c2428f28c79c7f05ff))
|
||||||
|
* lint tests in subpackages ([50c82ff](https://github.com/sst/opencode-sdk-go/commit/50c82ff0757c973834b68adc22566b70f767b611))
|
||||||
### Bug Fixes
|
* sync repo ([2f34d5d](https://github.com/sst/opencode-sdk-go/commit/2f34d5d53e56e9cdc3df99be7ee7efc83dd977a3))
|
||||||
|
* update @stainless-api/prism-cli to v5.15.0 ([2f24852](https://github.com/sst/opencode-sdk-go/commit/2f2485216d4f4891d1fbfbc23ff8410c2f35152a))
|
||||||
* don't try to deserialize as json when ResponseBodyInto is []byte ([5988d04](https://github.com/sst/opencode-sdk-go/commit/5988d04839cb78b6613057280b91b72a60fef33d))
|
|
||||||
|
|
||||||
## 0.1.0-alpha.5 (2025-06-27)
|
|
||||||
|
|
||||||
Full Changelog: [v0.1.0-alpha.4...v0.1.0-alpha.5](https://github.com/sst/opencode-sdk-go/compare/v0.1.0-alpha.4...v0.1.0-alpha.5)
|
|
||||||
|
|
||||||
### Features
|
|
||||||
|
|
||||||
* **api:** update via SDK Studio ([9e39a59](https://github.com/sst/opencode-sdk-go/commit/9e39a59b3d5d1bd5e64633732521fb28362cc70e))
|
|
||||||
|
|
||||||
## 0.1.0-alpha.4 (2025-06-27)
|
|
||||||
|
|
||||||
Full Changelog: [v0.1.0-alpha.3...v0.1.0-alpha.4](https://github.com/sst/opencode-sdk-go/compare/v0.1.0-alpha.3...v0.1.0-alpha.4)
|
|
||||||
|
|
||||||
### Features
|
|
||||||
|
|
||||||
* **api:** update via SDK Studio ([9609d1b](https://github.com/sst/opencode-sdk-go/commit/9609d1b1db7806d00cb846c9914cb4935cdedf52))
|
|
||||||
|
|
||||||
## 0.1.0-alpha.3 (2025-06-27)
|
|
||||||
|
|
||||||
Full Changelog: [v0.1.0-alpha.2...v0.1.0-alpha.3](https://github.com/sst/opencode-sdk-go/compare/v0.1.0-alpha.2...v0.1.0-alpha.3)
|
|
||||||
|
|
||||||
### Features
|
|
||||||
|
|
||||||
* **api:** update via SDK Studio ([57f3230](https://github.com/sst/opencode-sdk-go/commit/57f32309023cc1f0f20c20d02a3907e390a71f61))
|
|
||||||
|
|
||||||
## 0.1.0-alpha.2 (2025-06-27)
|
|
||||||
|
|
||||||
Full Changelog: [v0.1.0-alpha.1...v0.1.0-alpha.2](https://github.com/sst/opencode-sdk-go/compare/v0.1.0-alpha.1...v0.1.0-alpha.2)
|
|
||||||
|
|
||||||
### Features
|
|
||||||
|
|
||||||
* **api:** update via SDK Studio ([a766f1c](https://github.com/sst/opencode-sdk-go/commit/a766f1c54f02bbc1380151b0e22d97cc2c5892e6))
|
|
||||||
|
|
||||||
## 0.1.0-alpha.1 (2025-06-27)
|
|
||||||
|
|
||||||
Full Changelog: [v0.0.1-alpha.0...v0.1.0-alpha.1](https://github.com/sst/opencode-sdk-go/compare/v0.0.1-alpha.0...v0.1.0-alpha.1)
|
|
||||||
|
|
||||||
### Features
|
|
||||||
|
|
||||||
* **api:** update via SDK Studio ([27b7376](https://github.com/sst/opencode-sdk-go/commit/27b7376310466ee17a63f2104f546b53a2b8361a))
|
|
||||||
* **api:** update via SDK Studio ([0a73e04](https://github.com/sst/opencode-sdk-go/commit/0a73e04c23c90b2061611edaa8fd6282dc0ce397))
|
|
||||||
* **api:** update via SDK Studio ([9b7883a](https://github.com/sst/opencode-sdk-go/commit/9b7883a144eeac526d9d04538e0876a9d18bb844))
|
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ Or to pin the version:
|
|||||||
<!-- x-release-please-start-version -->
|
<!-- x-release-please-start-version -->
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
go get -u 'github.com/sst/opencode-sdk-go@v0.1.0-alpha.8'
|
go get -u 'github.com/sst/opencode-sdk-go@v0.8.0'
|
||||||
```
|
```
|
||||||
|
|
||||||
<!-- x-release-please-end -->
|
<!-- x-release-please-end -->
|
||||||
@@ -49,7 +49,7 @@ import (
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
client := opencode.NewClient()
|
client := opencode.NewClient()
|
||||||
sessions, err := client.Session.List(context.TODO())
|
sessions, err := client.Session.List(context.TODO(), opencode.SessionListParams{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err.Error())
|
panic(err.Error())
|
||||||
}
|
}
|
||||||
@@ -171,7 +171,7 @@ When the API returns a non-success status code, we return an error with type
|
|||||||
To handle errors, we recommend that you use the `errors.As` pattern:
|
To handle errors, we recommend that you use the `errors.As` pattern:
|
||||||
|
|
||||||
```go
|
```go
|
||||||
_, err := client.Session.List(context.TODO())
|
_, err := client.Session.List(context.TODO(), opencode.SessionListParams{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
var apierr *opencode.Error
|
var apierr *opencode.Error
|
||||||
if errors.As(err, &apierr) {
|
if errors.As(err, &apierr) {
|
||||||
@@ -198,6 +198,7 @@ ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
|
|||||||
defer cancel()
|
defer cancel()
|
||||||
client.Session.List(
|
client.Session.List(
|
||||||
ctx,
|
ctx,
|
||||||
|
opencode.SessionListParams{},
|
||||||
// This sets the per-retry timeout
|
// This sets the per-retry timeout
|
||||||
option.WithRequestTimeout(20*time.Second),
|
option.WithRequestTimeout(20*time.Second),
|
||||||
)
|
)
|
||||||
@@ -231,7 +232,11 @@ client := opencode.NewClient(
|
|||||||
)
|
)
|
||||||
|
|
||||||
// Override per-request:
|
// Override per-request:
|
||||||
client.Session.List(context.TODO(), option.WithMaxRetries(5))
|
client.Session.List(
|
||||||
|
context.TODO(),
|
||||||
|
opencode.SessionListParams{},
|
||||||
|
option.WithMaxRetries(5),
|
||||||
|
)
|
||||||
```
|
```
|
||||||
|
|
||||||
### Accessing raw response data (e.g. response headers)
|
### Accessing raw response data (e.g. response headers)
|
||||||
@@ -242,7 +247,11 @@ you need to examine response headers, status codes, or other details.
|
|||||||
```go
|
```go
|
||||||
// Create a variable to store the HTTP response
|
// Create a variable to store the HTTP response
|
||||||
var response *http.Response
|
var response *http.Response
|
||||||
sessions, err := client.Session.List(context.TODO(), option.WithResponseInto(&response))
|
sessions, err := client.Session.List(
|
||||||
|
context.TODO(),
|
||||||
|
opencode.SessionListParams{},
|
||||||
|
option.WithResponseInto(&response),
|
||||||
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// handle error
|
// handle error
|
||||||
}
|
}
|
||||||
|
|||||||
204
packages/sdk/go/agent.go
Normal file
204
packages/sdk/go/agent.go
Normal file
@@ -0,0 +1,204 @@
|
|||||||
|
// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
|
||||||
|
|
||||||
|
package opencode
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
|
||||||
|
"github.com/sst/opencode-sdk-go/internal/apijson"
|
||||||
|
"github.com/sst/opencode-sdk-go/internal/apiquery"
|
||||||
|
"github.com/sst/opencode-sdk-go/internal/param"
|
||||||
|
"github.com/sst/opencode-sdk-go/internal/requestconfig"
|
||||||
|
"github.com/sst/opencode-sdk-go/option"
|
||||||
|
)
|
||||||
|
|
||||||
|
// AgentService contains methods and other services that help with interacting with
|
||||||
|
// the opencode API.
|
||||||
|
//
|
||||||
|
// Note, unlike clients, this service does not read variables from the environment
|
||||||
|
// automatically. You should not instantiate this service directly, and instead use
|
||||||
|
// the [NewAgentService] method instead.
|
||||||
|
type AgentService struct {
|
||||||
|
Options []option.RequestOption
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewAgentService generates a new service that applies the given options to each
|
||||||
|
// request. These options are applied after the parent client's options (if there
|
||||||
|
// is one), and before any request-specific options.
|
||||||
|
func NewAgentService(opts ...option.RequestOption) (r *AgentService) {
|
||||||
|
r = &AgentService{}
|
||||||
|
r.Options = opts
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// List all agents
|
||||||
|
func (r *AgentService) List(ctx context.Context, query AgentListParams, opts ...option.RequestOption) (res *[]Agent, err error) {
|
||||||
|
opts = append(r.Options[:], opts...)
|
||||||
|
path := "agent"
|
||||||
|
err = requestconfig.ExecuteNewRequest(ctx, http.MethodGet, path, query, &res, opts...)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
type Agent struct {
|
||||||
|
BuiltIn bool `json:"builtIn,required"`
|
||||||
|
Mode AgentMode `json:"mode,required"`
|
||||||
|
Name string `json:"name,required"`
|
||||||
|
Options map[string]interface{} `json:"options,required"`
|
||||||
|
Permission AgentPermission `json:"permission,required"`
|
||||||
|
Tools map[string]bool `json:"tools,required"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
Model AgentModel `json:"model"`
|
||||||
|
Prompt string `json:"prompt"`
|
||||||
|
Temperature float64 `json:"temperature"`
|
||||||
|
TopP float64 `json:"topP"`
|
||||||
|
JSON agentJSON `json:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// agentJSON contains the JSON metadata for the struct [Agent]
|
||||||
|
type agentJSON struct {
|
||||||
|
BuiltIn apijson.Field
|
||||||
|
Mode apijson.Field
|
||||||
|
Name apijson.Field
|
||||||
|
Options apijson.Field
|
||||||
|
Permission apijson.Field
|
||||||
|
Tools apijson.Field
|
||||||
|
Description apijson.Field
|
||||||
|
Model apijson.Field
|
||||||
|
Prompt apijson.Field
|
||||||
|
Temperature apijson.Field
|
||||||
|
TopP apijson.Field
|
||||||
|
raw string
|
||||||
|
ExtraFields map[string]apijson.Field
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Agent) UnmarshalJSON(data []byte) (err error) {
|
||||||
|
return apijson.UnmarshalRoot(data, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r agentJSON) RawJSON() string {
|
||||||
|
return r.raw
|
||||||
|
}
|
||||||
|
|
||||||
|
type AgentMode string
|
||||||
|
|
||||||
|
const (
|
||||||
|
AgentModeSubagent AgentMode = "subagent"
|
||||||
|
AgentModePrimary AgentMode = "primary"
|
||||||
|
AgentModeAll AgentMode = "all"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (r AgentMode) IsKnown() bool {
|
||||||
|
switch r {
|
||||||
|
case AgentModeSubagent, AgentModePrimary, AgentModeAll:
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
type AgentPermission struct {
|
||||||
|
Bash map[string]AgentPermissionBash `json:"bash,required"`
|
||||||
|
Edit AgentPermissionEdit `json:"edit,required"`
|
||||||
|
Webfetch AgentPermissionWebfetch `json:"webfetch"`
|
||||||
|
JSON agentPermissionJSON `json:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// agentPermissionJSON contains the JSON metadata for the struct [AgentPermission]
|
||||||
|
type agentPermissionJSON struct {
|
||||||
|
Bash apijson.Field
|
||||||
|
Edit apijson.Field
|
||||||
|
Webfetch apijson.Field
|
||||||
|
raw string
|
||||||
|
ExtraFields map[string]apijson.Field
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *AgentPermission) UnmarshalJSON(data []byte) (err error) {
|
||||||
|
return apijson.UnmarshalRoot(data, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r agentPermissionJSON) RawJSON() string {
|
||||||
|
return r.raw
|
||||||
|
}
|
||||||
|
|
||||||
|
type AgentPermissionBash string
|
||||||
|
|
||||||
|
const (
|
||||||
|
AgentPermissionBashAsk AgentPermissionBash = "ask"
|
||||||
|
AgentPermissionBashAllow AgentPermissionBash = "allow"
|
||||||
|
AgentPermissionBashDeny AgentPermissionBash = "deny"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (r AgentPermissionBash) IsKnown() bool {
|
||||||
|
switch r {
|
||||||
|
case AgentPermissionBashAsk, AgentPermissionBashAllow, AgentPermissionBashDeny:
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
type AgentPermissionEdit string
|
||||||
|
|
||||||
|
const (
|
||||||
|
AgentPermissionEditAsk AgentPermissionEdit = "ask"
|
||||||
|
AgentPermissionEditAllow AgentPermissionEdit = "allow"
|
||||||
|
AgentPermissionEditDeny AgentPermissionEdit = "deny"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (r AgentPermissionEdit) IsKnown() bool {
|
||||||
|
switch r {
|
||||||
|
case AgentPermissionEditAsk, AgentPermissionEditAllow, AgentPermissionEditDeny:
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
type AgentPermissionWebfetch string
|
||||||
|
|
||||||
|
const (
|
||||||
|
AgentPermissionWebfetchAsk AgentPermissionWebfetch = "ask"
|
||||||
|
AgentPermissionWebfetchAllow AgentPermissionWebfetch = "allow"
|
||||||
|
AgentPermissionWebfetchDeny AgentPermissionWebfetch = "deny"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (r AgentPermissionWebfetch) IsKnown() bool {
|
||||||
|
switch r {
|
||||||
|
case AgentPermissionWebfetchAsk, AgentPermissionWebfetchAllow, AgentPermissionWebfetchDeny:
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
type AgentModel struct {
|
||||||
|
ModelID string `json:"modelID,required"`
|
||||||
|
ProviderID string `json:"providerID,required"`
|
||||||
|
JSON agentModelJSON `json:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// agentModelJSON contains the JSON metadata for the struct [AgentModel]
|
||||||
|
type agentModelJSON struct {
|
||||||
|
ModelID apijson.Field
|
||||||
|
ProviderID apijson.Field
|
||||||
|
raw string
|
||||||
|
ExtraFields map[string]apijson.Field
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *AgentModel) UnmarshalJSON(data []byte) (err error) {
|
||||||
|
return apijson.UnmarshalRoot(data, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r agentModelJSON) RawJSON() string {
|
||||||
|
return r.raw
|
||||||
|
}
|
||||||
|
|
||||||
|
type AgentListParams struct {
|
||||||
|
Directory param.Field[string] `query:"directory"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// URLQuery serializes [AgentListParams]'s query parameters as `url.Values`.
|
||||||
|
func (r AgentListParams) URLQuery() (v url.Values) {
|
||||||
|
return apiquery.MarshalWithSettings(r, apiquery.QuerySettings{
|
||||||
|
ArrayFormat: apiquery.ArrayQueryFormatComma,
|
||||||
|
NestedFormat: apiquery.NestedQueryFormatBrackets,
|
||||||
|
})
|
||||||
|
}
|
||||||
38
packages/sdk/go/agent_test.go
Normal file
38
packages/sdk/go/agent_test.go
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
|
||||||
|
|
||||||
|
package opencode_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/sst/opencode-sdk-go"
|
||||||
|
"github.com/sst/opencode-sdk-go/internal/testutil"
|
||||||
|
"github.com/sst/opencode-sdk-go/option"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestAgentListWithOptionalParams(t *testing.T) {
|
||||||
|
t.Skip("Prism tests are disabled")
|
||||||
|
baseURL := "http://localhost:4010"
|
||||||
|
if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
|
||||||
|
baseURL = envURL
|
||||||
|
}
|
||||||
|
if !testutil.CheckTestServer(t, baseURL) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
client := opencode.NewClient(
|
||||||
|
option.WithBaseURL(baseURL),
|
||||||
|
)
|
||||||
|
_, err := client.Agent.List(context.TODO(), opencode.AgentListParams{
|
||||||
|
Directory: opencode.F("directory"),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
var apierr *opencode.Error
|
||||||
|
if errors.As(err, &apierr) {
|
||||||
|
t.Log(string(apierr.DumpRequest(true)))
|
||||||
|
}
|
||||||
|
t.Fatalf("err should be nil: %s", err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -12,25 +12,40 @@ Response Types:
|
|||||||
|
|
||||||
Methods:
|
Methods:
|
||||||
|
|
||||||
- <code title="get /event">client.Event.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#EventService.List">List</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>) (<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#EventListResponse">EventListResponse</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
- <code title="get /event">client.Event.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#EventService.List">List</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, query <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#EventListParams">EventListParams</a>) (<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#EventListResponse">EventListResponse</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
||||||
|
|
||||||
|
# Path
|
||||||
|
|
||||||
|
Response Types:
|
||||||
|
|
||||||
|
- <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#Path">Path</a>
|
||||||
|
|
||||||
|
Methods:
|
||||||
|
|
||||||
|
- <code title="get /path">client.Path.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#PathService.Get">Get</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, query <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#PathGetParams">PathGetParams</a>) (<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#Path">Path</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
||||||
|
|
||||||
# App
|
# App
|
||||||
|
|
||||||
Response Types:
|
Response Types:
|
||||||
|
|
||||||
- <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#Agent">Agent</a>
|
|
||||||
- <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#App">App</a>
|
|
||||||
- <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#Model">Model</a>
|
- <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#Model">Model</a>
|
||||||
- <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#Provider">Provider</a>
|
- <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#Provider">Provider</a>
|
||||||
- <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#AppProvidersResponse">AppProvidersResponse</a>
|
- <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#AppProvidersResponse">AppProvidersResponse</a>
|
||||||
|
|
||||||
Methods:
|
Methods:
|
||||||
|
|
||||||
- <code title="get /agent">client.App.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#AppService.Agents">Agents</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>) ([]<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#Agent">Agent</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
- <code title="post /log">client.App.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#AppService.Log">Log</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, params <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#AppLogParams">AppLogParams</a>) (<a href="https://pkg.go.dev/builtin#bool">bool</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
||||||
- <code title="get /app">client.App.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#AppService.Get">Get</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>) (<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#App">App</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
- <code title="get /config/providers">client.App.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#AppService.Providers">Providers</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, query <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#AppProvidersParams">AppProvidersParams</a>) (<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#AppProvidersResponse">AppProvidersResponse</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
||||||
- <code title="post /app/init">client.App.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#AppService.Init">Init</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>) (<a href="https://pkg.go.dev/builtin#bool">bool</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
|
||||||
- <code title="post /log">client.App.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#AppService.Log">Log</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, body <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#AppLogParams">AppLogParams</a>) (<a href="https://pkg.go.dev/builtin#bool">bool</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
# Agent
|
||||||
- <code title="get /config/providers">client.App.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#AppService.Providers">Providers</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>) (<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#AppProvidersResponse">AppProvidersResponse</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
|
||||||
|
Response Types:
|
||||||
|
|
||||||
|
- <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#Agent">Agent</a>
|
||||||
|
|
||||||
|
Methods:
|
||||||
|
|
||||||
|
- <code title="get /agent">client.Agent.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#AgentService.List">List</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, query <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#AgentListParams">AgentListParams</a>) ([]<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#Agent">Agent</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
||||||
|
|
||||||
# Find
|
# Find
|
||||||
|
|
||||||
@@ -50,12 +65,14 @@ Methods:
|
|||||||
Response Types:
|
Response Types:
|
||||||
|
|
||||||
- <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#File">File</a>
|
- <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#File">File</a>
|
||||||
|
- <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#FileNode">FileNode</a>
|
||||||
- <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#FileReadResponse">FileReadResponse</a>
|
- <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#FileReadResponse">FileReadResponse</a>
|
||||||
|
|
||||||
Methods:
|
Methods:
|
||||||
|
|
||||||
- <code title="get /file">client.File.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#FileService.Read">Read</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, query <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#FileReadParams">FileReadParams</a>) (<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#FileReadResponse">FileReadResponse</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
- <code title="get /file">client.File.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#FileService.List">List</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, query <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#FileListParams">FileListParams</a>) ([]<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#FileNode">FileNode</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
||||||
- <code title="get /file/status">client.File.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#FileService.Status">Status</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>) ([]<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#File">File</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
- <code title="get /file/content">client.File.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#FileService.Read">Read</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, query <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#FileReadParams">FileReadParams</a>) (<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#FileReadResponse">FileReadResponse</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
||||||
|
- <code title="get /file/status">client.File.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#FileService.Status">Status</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, query <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#FileStatusParams">FileStatusParams</a>) ([]<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#File">File</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
||||||
|
|
||||||
# Config
|
# Config
|
||||||
|
|
||||||
@@ -68,7 +85,7 @@ Response Types:
|
|||||||
|
|
||||||
Methods:
|
Methods:
|
||||||
|
|
||||||
- <code title="get /config">client.Config.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#ConfigService.Get">Get</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>) (<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#Config">Config</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
- <code title="get /config">client.Config.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#ConfigService.Get">Get</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, query <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#ConfigGetParams">ConfigGetParams</a>) (<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#Config">Config</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
||||||
|
|
||||||
# Command
|
# Command
|
||||||
|
|
||||||
@@ -78,7 +95,18 @@ Response Types:
|
|||||||
|
|
||||||
Methods:
|
Methods:
|
||||||
|
|
||||||
- <code title="get /command">client.Command.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#CommandService.List">List</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>) ([]<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#Command">Command</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
- <code title="get /command">client.Command.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#CommandService.List">List</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, query <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#CommandListParams">CommandListParams</a>) ([]<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#Command">Command</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
||||||
|
|
||||||
|
# Project
|
||||||
|
|
||||||
|
Response Types:
|
||||||
|
|
||||||
|
- <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#Project">Project</a>
|
||||||
|
|
||||||
|
Methods:
|
||||||
|
|
||||||
|
- <code title="get /project">client.Project.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#ProjectService.List">List</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, query <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#ProjectListParams">ProjectListParams</a>) ([]<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#Project">Project</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
||||||
|
- <code title="get /project/current">client.Project.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#ProjectService.Current">Current</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, query <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#ProjectCurrentParams">ProjectCurrentParams</a>) (<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#Project">Project</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
||||||
|
|
||||||
# Session
|
# Session
|
||||||
|
|
||||||
@@ -115,31 +143,31 @@ Response Types:
|
|||||||
- <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#ToolStatePending">ToolStatePending</a>
|
- <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#ToolStatePending">ToolStatePending</a>
|
||||||
- <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#ToolStateRunning">ToolStateRunning</a>
|
- <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#ToolStateRunning">ToolStateRunning</a>
|
||||||
- <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#UserMessage">UserMessage</a>
|
- <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#UserMessage">UserMessage</a>
|
||||||
- <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionChatResponse">SessionChatResponse</a>
|
|
||||||
- <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionCommandResponse">SessionCommandResponse</a>
|
- <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionCommandResponse">SessionCommandResponse</a>
|
||||||
- <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionMessageResponse">SessionMessageResponse</a>
|
- <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionMessageResponse">SessionMessageResponse</a>
|
||||||
- <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionMessagesResponse">SessionMessagesResponse</a>
|
- <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionMessagesResponse">SessionMessagesResponse</a>
|
||||||
|
- <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionPromptResponse">SessionPromptResponse</a>
|
||||||
|
|
||||||
Methods:
|
Methods:
|
||||||
|
|
||||||
- <code title="post /session">client.Session.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionService.New">New</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, body <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionNewParams">SessionNewParams</a>) (<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#Session">Session</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
- <code title="post /session">client.Session.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionService.New">New</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, params <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionNewParams">SessionNewParams</a>) (<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#Session">Session</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
||||||
- <code title="patch /session/{id}">client.Session.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionService.Update">Update</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, id <a href="https://pkg.go.dev/builtin#string">string</a>, body <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionUpdateParams">SessionUpdateParams</a>) (<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#Session">Session</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
- <code title="patch /session/{id}">client.Session.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionService.Update">Update</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, id <a href="https://pkg.go.dev/builtin#string">string</a>, params <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionUpdateParams">SessionUpdateParams</a>) (<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#Session">Session</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
||||||
- <code title="get /session">client.Session.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionService.List">List</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>) ([]<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#Session">Session</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
- <code title="get /session">client.Session.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionService.List">List</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, query <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionListParams">SessionListParams</a>) ([]<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#Session">Session</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
||||||
- <code title="delete /session/{id}">client.Session.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionService.Delete">Delete</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, id <a href="https://pkg.go.dev/builtin#string">string</a>) (<a href="https://pkg.go.dev/builtin#bool">bool</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
- <code title="delete /session/{id}">client.Session.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionService.Delete">Delete</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, id <a href="https://pkg.go.dev/builtin#string">string</a>, body <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionDeleteParams">SessionDeleteParams</a>) (<a href="https://pkg.go.dev/builtin#bool">bool</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
||||||
- <code title="post /session/{id}/abort">client.Session.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionService.Abort">Abort</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, id <a href="https://pkg.go.dev/builtin#string">string</a>) (<a href="https://pkg.go.dev/builtin#bool">bool</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
- <code title="post /session/{id}/abort">client.Session.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionService.Abort">Abort</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, id <a href="https://pkg.go.dev/builtin#string">string</a>, body <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionAbortParams">SessionAbortParams</a>) (<a href="https://pkg.go.dev/builtin#bool">bool</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
||||||
- <code title="post /session/{id}/message">client.Session.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionService.Chat">Chat</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, id <a href="https://pkg.go.dev/builtin#string">string</a>, body <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionChatParams">SessionChatParams</a>) (<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionChatResponse">SessionChatResponse</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
- <code title="get /session/{id}/children">client.Session.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionService.Children">Children</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, id <a href="https://pkg.go.dev/builtin#string">string</a>, query <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionChildrenParams">SessionChildrenParams</a>) ([]<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#Session">Session</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
||||||
- <code title="get /session/{id}/children">client.Session.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionService.Children">Children</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, id <a href="https://pkg.go.dev/builtin#string">string</a>) ([]<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#Session">Session</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
- <code title="post /session/{id}/command">client.Session.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionService.Command">Command</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, id <a href="https://pkg.go.dev/builtin#string">string</a>, params <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionCommandParams">SessionCommandParams</a>) (<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionCommandResponse">SessionCommandResponse</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
||||||
- <code title="post /session/{id}/command">client.Session.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionService.Command">Command</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, id <a href="https://pkg.go.dev/builtin#string">string</a>, body <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionCommandParams">SessionCommandParams</a>) (<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionCommandResponse">SessionCommandResponse</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
- <code title="get /session/{id}">client.Session.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionService.Get">Get</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, id <a href="https://pkg.go.dev/builtin#string">string</a>, query <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionGetParams">SessionGetParams</a>) (<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#Session">Session</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
||||||
- <code title="get /session/{id}">client.Session.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionService.Get">Get</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, id <a href="https://pkg.go.dev/builtin#string">string</a>) (<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#Session">Session</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
- <code title="post /session/{id}/init">client.Session.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionService.Init">Init</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, id <a href="https://pkg.go.dev/builtin#string">string</a>, params <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionInitParams">SessionInitParams</a>) (<a href="https://pkg.go.dev/builtin#bool">bool</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
||||||
- <code title="post /session/{id}/init">client.Session.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionService.Init">Init</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, id <a href="https://pkg.go.dev/builtin#string">string</a>, body <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionInitParams">SessionInitParams</a>) (<a href="https://pkg.go.dev/builtin#bool">bool</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
- <code title="get /session/{id}/message/{messageID}">client.Session.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionService.Message">Message</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, id <a href="https://pkg.go.dev/builtin#string">string</a>, messageID <a href="https://pkg.go.dev/builtin#string">string</a>, query <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionMessageParams">SessionMessageParams</a>) (<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionMessageResponse">SessionMessageResponse</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
||||||
- <code title="get /session/{id}/message/{messageID}">client.Session.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionService.Message">Message</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, id <a href="https://pkg.go.dev/builtin#string">string</a>, messageID <a href="https://pkg.go.dev/builtin#string">string</a>) (<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionMessageResponse">SessionMessageResponse</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
- <code title="get /session/{id}/message">client.Session.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionService.Messages">Messages</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, id <a href="https://pkg.go.dev/builtin#string">string</a>, query <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionMessagesParams">SessionMessagesParams</a>) ([]<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionMessagesResponse">SessionMessagesResponse</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
||||||
- <code title="get /session/{id}/message">client.Session.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionService.Messages">Messages</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, id <a href="https://pkg.go.dev/builtin#string">string</a>) ([]<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionMessagesResponse">SessionMessagesResponse</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
- <code title="post /session/{id}/message">client.Session.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionService.Prompt">Prompt</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, id <a href="https://pkg.go.dev/builtin#string">string</a>, params <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionPromptParams">SessionPromptParams</a>) (<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionPromptResponse">SessionPromptResponse</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
||||||
- <code title="post /session/{id}/revert">client.Session.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionService.Revert">Revert</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, id <a href="https://pkg.go.dev/builtin#string">string</a>, body <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionRevertParams">SessionRevertParams</a>) (<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#Session">Session</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
- <code title="post /session/{id}/revert">client.Session.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionService.Revert">Revert</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, id <a href="https://pkg.go.dev/builtin#string">string</a>, params <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionRevertParams">SessionRevertParams</a>) (<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#Session">Session</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
||||||
- <code title="post /session/{id}/share">client.Session.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionService.Share">Share</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, id <a href="https://pkg.go.dev/builtin#string">string</a>) (<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#Session">Session</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
- <code title="post /session/{id}/share">client.Session.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionService.Share">Share</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, id <a href="https://pkg.go.dev/builtin#string">string</a>, body <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionShareParams">SessionShareParams</a>) (<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#Session">Session</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
||||||
- <code title="post /session/{id}/shell">client.Session.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionService.Shell">Shell</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, id <a href="https://pkg.go.dev/builtin#string">string</a>, body <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionShellParams">SessionShellParams</a>) (<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#AssistantMessage">AssistantMessage</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
- <code title="post /session/{id}/shell">client.Session.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionService.Shell">Shell</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, id <a href="https://pkg.go.dev/builtin#string">string</a>, params <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionShellParams">SessionShellParams</a>) (<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#AssistantMessage">AssistantMessage</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
||||||
- <code title="post /session/{id}/summarize">client.Session.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionService.Summarize">Summarize</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, id <a href="https://pkg.go.dev/builtin#string">string</a>, body <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionSummarizeParams">SessionSummarizeParams</a>) (<a href="https://pkg.go.dev/builtin#bool">bool</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
- <code title="post /session/{id}/summarize">client.Session.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionService.Summarize">Summarize</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, id <a href="https://pkg.go.dev/builtin#string">string</a>, params <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionSummarizeParams">SessionSummarizeParams</a>) (<a href="https://pkg.go.dev/builtin#bool">bool</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
||||||
- <code title="post /session/{id}/unrevert">client.Session.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionService.Unrevert">Unrevert</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, id <a href="https://pkg.go.dev/builtin#string">string</a>) (<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#Session">Session</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
- <code title="post /session/{id}/unrevert">client.Session.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionService.Unrevert">Unrevert</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, id <a href="https://pkg.go.dev/builtin#string">string</a>, body <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionUnrevertParams">SessionUnrevertParams</a>) (<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#Session">Session</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
||||||
- <code title="delete /session/{id}/share">client.Session.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionService.Unshare">Unshare</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, id <a href="https://pkg.go.dev/builtin#string">string</a>) (<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#Session">Session</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
- <code title="delete /session/{id}/share">client.Session.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionService.Unshare">Unshare</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, id <a href="https://pkg.go.dev/builtin#string">string</a>, body <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionUnshareParams">SessionUnshareParams</a>) (<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#Session">Session</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
||||||
|
|
||||||
## Permissions
|
## Permissions
|
||||||
|
|
||||||
@@ -149,18 +177,18 @@ Response Types:
|
|||||||
|
|
||||||
Methods:
|
Methods:
|
||||||
|
|
||||||
- <code title="post /session/{id}/permissions/{permissionID}">client.Session.Permissions.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionPermissionService.Respond">Respond</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, id <a href="https://pkg.go.dev/builtin#string">string</a>, permissionID <a href="https://pkg.go.dev/builtin#string">string</a>, body <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionPermissionRespondParams">SessionPermissionRespondParams</a>) (<a href="https://pkg.go.dev/builtin#bool">bool</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
- <code title="post /session/{id}/permissions/{permissionID}">client.Session.Permissions.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionPermissionService.Respond">Respond</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, id <a href="https://pkg.go.dev/builtin#string">string</a>, permissionID <a href="https://pkg.go.dev/builtin#string">string</a>, params <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionPermissionRespondParams">SessionPermissionRespondParams</a>) (<a href="https://pkg.go.dev/builtin#bool">bool</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
||||||
|
|
||||||
# Tui
|
# Tui
|
||||||
|
|
||||||
Methods:
|
Methods:
|
||||||
|
|
||||||
- <code title="post /tui/append-prompt">client.Tui.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#TuiService.AppendPrompt">AppendPrompt</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, body <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#TuiAppendPromptParams">TuiAppendPromptParams</a>) (<a href="https://pkg.go.dev/builtin#bool">bool</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
- <code title="post /tui/append-prompt">client.Tui.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#TuiService.AppendPrompt">AppendPrompt</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, params <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#TuiAppendPromptParams">TuiAppendPromptParams</a>) (<a href="https://pkg.go.dev/builtin#bool">bool</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
||||||
- <code title="post /tui/clear-prompt">client.Tui.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#TuiService.ClearPrompt">ClearPrompt</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>) (<a href="https://pkg.go.dev/builtin#bool">bool</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
- <code title="post /tui/clear-prompt">client.Tui.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#TuiService.ClearPrompt">ClearPrompt</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, body <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#TuiClearPromptParams">TuiClearPromptParams</a>) (<a href="https://pkg.go.dev/builtin#bool">bool</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
||||||
- <code title="post /tui/execute-command">client.Tui.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#TuiService.ExecuteCommand">ExecuteCommand</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, body <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#TuiExecuteCommandParams">TuiExecuteCommandParams</a>) (<a href="https://pkg.go.dev/builtin#bool">bool</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
- <code title="post /tui/execute-command">client.Tui.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#TuiService.ExecuteCommand">ExecuteCommand</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, params <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#TuiExecuteCommandParams">TuiExecuteCommandParams</a>) (<a href="https://pkg.go.dev/builtin#bool">bool</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
||||||
- <code title="post /tui/open-help">client.Tui.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#TuiService.OpenHelp">OpenHelp</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>) (<a href="https://pkg.go.dev/builtin#bool">bool</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
- <code title="post /tui/open-help">client.Tui.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#TuiService.OpenHelp">OpenHelp</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, body <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#TuiOpenHelpParams">TuiOpenHelpParams</a>) (<a href="https://pkg.go.dev/builtin#bool">bool</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
||||||
- <code title="post /tui/open-models">client.Tui.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#TuiService.OpenModels">OpenModels</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>) (<a href="https://pkg.go.dev/builtin#bool">bool</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
- <code title="post /tui/open-models">client.Tui.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#TuiService.OpenModels">OpenModels</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, body <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#TuiOpenModelsParams">TuiOpenModelsParams</a>) (<a href="https://pkg.go.dev/builtin#bool">bool</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
||||||
- <code title="post /tui/open-sessions">client.Tui.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#TuiService.OpenSessions">OpenSessions</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>) (<a href="https://pkg.go.dev/builtin#bool">bool</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
- <code title="post /tui/open-sessions">client.Tui.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#TuiService.OpenSessions">OpenSessions</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, body <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#TuiOpenSessionsParams">TuiOpenSessionsParams</a>) (<a href="https://pkg.go.dev/builtin#bool">bool</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
||||||
- <code title="post /tui/open-themes">client.Tui.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#TuiService.OpenThemes">OpenThemes</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>) (<a href="https://pkg.go.dev/builtin#bool">bool</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
- <code title="post /tui/open-themes">client.Tui.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#TuiService.OpenThemes">OpenThemes</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, body <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#TuiOpenThemesParams">TuiOpenThemesParams</a>) (<a href="https://pkg.go.dev/builtin#bool">bool</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
||||||
- <code title="post /tui/show-toast">client.Tui.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#TuiService.ShowToast">ShowToast</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, body <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#TuiShowToastParams">TuiShowToastParams</a>) (<a href="https://pkg.go.dev/builtin#bool">bool</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
- <code title="post /tui/show-toast">client.Tui.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#TuiService.ShowToast">ShowToast</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, params <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#TuiShowToastParams">TuiShowToastParams</a>) (<a href="https://pkg.go.dev/builtin#bool">bool</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
||||||
- <code title="post /tui/submit-prompt">client.Tui.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#TuiService.SubmitPrompt">SubmitPrompt</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>) (<a href="https://pkg.go.dev/builtin#bool">bool</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
- <code title="post /tui/submit-prompt">client.Tui.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#TuiService.SubmitPrompt">SubmitPrompt</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, body <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#TuiSubmitPromptParams">TuiSubmitPromptParams</a>) (<a href="https://pkg.go.dev/builtin#bool">bool</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
||||||
|
|||||||
@@ -5,8 +5,10 @@ package opencode
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
|
||||||
"github.com/sst/opencode-sdk-go/internal/apijson"
|
"github.com/sst/opencode-sdk-go/internal/apijson"
|
||||||
|
"github.com/sst/opencode-sdk-go/internal/apiquery"
|
||||||
"github.com/sst/opencode-sdk-go/internal/param"
|
"github.com/sst/opencode-sdk-go/internal/param"
|
||||||
"github.com/sst/opencode-sdk-go/internal/requestconfig"
|
"github.com/sst/opencode-sdk-go/internal/requestconfig"
|
||||||
"github.com/sst/opencode-sdk-go/option"
|
"github.com/sst/opencode-sdk-go/option"
|
||||||
@@ -31,270 +33,22 @@ func NewAppService(opts ...option.RequestOption) (r *AppService) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// List all agents
|
|
||||||
func (r *AppService) Agents(ctx context.Context, opts ...option.RequestOption) (res *[]Agent, err error) {
|
|
||||||
opts = append(r.Options[:], opts...)
|
|
||||||
path := "agent"
|
|
||||||
err = requestconfig.ExecuteNewRequest(ctx, http.MethodGet, path, nil, &res, opts...)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get app info
|
|
||||||
func (r *AppService) Get(ctx context.Context, opts ...option.RequestOption) (res *App, err error) {
|
|
||||||
opts = append(r.Options[:], opts...)
|
|
||||||
path := "app"
|
|
||||||
err = requestconfig.ExecuteNewRequest(ctx, http.MethodGet, path, nil, &res, opts...)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialize the app
|
|
||||||
func (r *AppService) Init(ctx context.Context, opts ...option.RequestOption) (res *bool, err error) {
|
|
||||||
opts = append(r.Options[:], opts...)
|
|
||||||
path := "app/init"
|
|
||||||
err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, nil, &res, opts...)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write a log entry to the server logs
|
// Write a log entry to the server logs
|
||||||
func (r *AppService) Log(ctx context.Context, body AppLogParams, opts ...option.RequestOption) (res *bool, err error) {
|
func (r *AppService) Log(ctx context.Context, params AppLogParams, opts ...option.RequestOption) (res *bool, err error) {
|
||||||
opts = append(r.Options[:], opts...)
|
opts = append(r.Options[:], opts...)
|
||||||
path := "log"
|
path := "log"
|
||||||
err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, body, &res, opts...)
|
err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, params, &res, opts...)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// List all providers
|
// List all providers
|
||||||
func (r *AppService) Providers(ctx context.Context, opts ...option.RequestOption) (res *AppProvidersResponse, err error) {
|
func (r *AppService) Providers(ctx context.Context, query AppProvidersParams, opts ...option.RequestOption) (res *AppProvidersResponse, err error) {
|
||||||
opts = append(r.Options[:], opts...)
|
opts = append(r.Options[:], opts...)
|
||||||
path := "config/providers"
|
path := "config/providers"
|
||||||
err = requestconfig.ExecuteNewRequest(ctx, http.MethodGet, path, nil, &res, opts...)
|
err = requestconfig.ExecuteNewRequest(ctx, http.MethodGet, path, query, &res, opts...)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
type Agent struct {
|
|
||||||
BuiltIn bool `json:"builtIn,required"`
|
|
||||||
Mode AgentMode `json:"mode,required"`
|
|
||||||
Name string `json:"name,required"`
|
|
||||||
Options map[string]interface{} `json:"options,required"`
|
|
||||||
Permission AgentPermission `json:"permission,required"`
|
|
||||||
Tools map[string]bool `json:"tools,required"`
|
|
||||||
Description string `json:"description"`
|
|
||||||
Model AgentModel `json:"model"`
|
|
||||||
Prompt string `json:"prompt"`
|
|
||||||
Temperature float64 `json:"temperature"`
|
|
||||||
TopP float64 `json:"topP"`
|
|
||||||
JSON agentJSON `json:"-"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// agentJSON contains the JSON metadata for the struct [Agent]
|
|
||||||
type agentJSON struct {
|
|
||||||
BuiltIn apijson.Field
|
|
||||||
Mode apijson.Field
|
|
||||||
Name apijson.Field
|
|
||||||
Options apijson.Field
|
|
||||||
Permission apijson.Field
|
|
||||||
Tools apijson.Field
|
|
||||||
Description apijson.Field
|
|
||||||
Model apijson.Field
|
|
||||||
Prompt apijson.Field
|
|
||||||
Temperature apijson.Field
|
|
||||||
TopP apijson.Field
|
|
||||||
raw string
|
|
||||||
ExtraFields map[string]apijson.Field
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *Agent) UnmarshalJSON(data []byte) (err error) {
|
|
||||||
return apijson.UnmarshalRoot(data, r)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r agentJSON) RawJSON() string {
|
|
||||||
return r.raw
|
|
||||||
}
|
|
||||||
|
|
||||||
type AgentMode string
|
|
||||||
|
|
||||||
const (
|
|
||||||
AgentModeSubagent AgentMode = "subagent"
|
|
||||||
AgentModePrimary AgentMode = "primary"
|
|
||||||
AgentModeAll AgentMode = "all"
|
|
||||||
)
|
|
||||||
|
|
||||||
func (r AgentMode) IsKnown() bool {
|
|
||||||
switch r {
|
|
||||||
case AgentModeSubagent, AgentModePrimary, AgentModeAll:
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
type AgentPermission struct {
|
|
||||||
Bash map[string]AgentPermissionBash `json:"bash,required"`
|
|
||||||
Edit AgentPermissionEdit `json:"edit,required"`
|
|
||||||
Webfetch AgentPermissionWebfetch `json:"webfetch"`
|
|
||||||
JSON agentPermissionJSON `json:"-"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// agentPermissionJSON contains the JSON metadata for the struct [AgentPermission]
|
|
||||||
type agentPermissionJSON struct {
|
|
||||||
Bash apijson.Field
|
|
||||||
Edit apijson.Field
|
|
||||||
Webfetch apijson.Field
|
|
||||||
raw string
|
|
||||||
ExtraFields map[string]apijson.Field
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *AgentPermission) UnmarshalJSON(data []byte) (err error) {
|
|
||||||
return apijson.UnmarshalRoot(data, r)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r agentPermissionJSON) RawJSON() string {
|
|
||||||
return r.raw
|
|
||||||
}
|
|
||||||
|
|
||||||
type AgentPermissionBash string
|
|
||||||
|
|
||||||
const (
|
|
||||||
AgentPermissionBashAsk AgentPermissionBash = "ask"
|
|
||||||
AgentPermissionBashAllow AgentPermissionBash = "allow"
|
|
||||||
AgentPermissionBashDeny AgentPermissionBash = "deny"
|
|
||||||
)
|
|
||||||
|
|
||||||
func (r AgentPermissionBash) IsKnown() bool {
|
|
||||||
switch r {
|
|
||||||
case AgentPermissionBashAsk, AgentPermissionBashAllow, AgentPermissionBashDeny:
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
type AgentPermissionEdit string
|
|
||||||
|
|
||||||
const (
|
|
||||||
AgentPermissionEditAsk AgentPermissionEdit = "ask"
|
|
||||||
AgentPermissionEditAllow AgentPermissionEdit = "allow"
|
|
||||||
AgentPermissionEditDeny AgentPermissionEdit = "deny"
|
|
||||||
)
|
|
||||||
|
|
||||||
func (r AgentPermissionEdit) IsKnown() bool {
|
|
||||||
switch r {
|
|
||||||
case AgentPermissionEditAsk, AgentPermissionEditAllow, AgentPermissionEditDeny:
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
type AgentPermissionWebfetch string
|
|
||||||
|
|
||||||
const (
|
|
||||||
AgentPermissionWebfetchAsk AgentPermissionWebfetch = "ask"
|
|
||||||
AgentPermissionWebfetchAllow AgentPermissionWebfetch = "allow"
|
|
||||||
AgentPermissionWebfetchDeny AgentPermissionWebfetch = "deny"
|
|
||||||
)
|
|
||||||
|
|
||||||
func (r AgentPermissionWebfetch) IsKnown() bool {
|
|
||||||
switch r {
|
|
||||||
case AgentPermissionWebfetchAsk, AgentPermissionWebfetchAllow, AgentPermissionWebfetchDeny:
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
type AgentModel struct {
|
|
||||||
ModelID string `json:"modelID,required"`
|
|
||||||
ProviderID string `json:"providerID,required"`
|
|
||||||
JSON agentModelJSON `json:"-"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// agentModelJSON contains the JSON metadata for the struct [AgentModel]
|
|
||||||
type agentModelJSON struct {
|
|
||||||
ModelID apijson.Field
|
|
||||||
ProviderID apijson.Field
|
|
||||||
raw string
|
|
||||||
ExtraFields map[string]apijson.Field
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *AgentModel) UnmarshalJSON(data []byte) (err error) {
|
|
||||||
return apijson.UnmarshalRoot(data, r)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r agentModelJSON) RawJSON() string {
|
|
||||||
return r.raw
|
|
||||||
}
|
|
||||||
|
|
||||||
type App struct {
|
|
||||||
Git bool `json:"git,required"`
|
|
||||||
Hostname string `json:"hostname,required"`
|
|
||||||
Path AppPath `json:"path,required"`
|
|
||||||
Time AppTime `json:"time,required"`
|
|
||||||
JSON appJSON `json:"-"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// appJSON contains the JSON metadata for the struct [App]
|
|
||||||
type appJSON struct {
|
|
||||||
Git apijson.Field
|
|
||||||
Hostname apijson.Field
|
|
||||||
Path apijson.Field
|
|
||||||
Time apijson.Field
|
|
||||||
raw string
|
|
||||||
ExtraFields map[string]apijson.Field
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *App) UnmarshalJSON(data []byte) (err error) {
|
|
||||||
return apijson.UnmarshalRoot(data, r)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r appJSON) RawJSON() string {
|
|
||||||
return r.raw
|
|
||||||
}
|
|
||||||
|
|
||||||
type AppPath struct {
|
|
||||||
Config string `json:"config,required"`
|
|
||||||
Cwd string `json:"cwd,required"`
|
|
||||||
Data string `json:"data,required"`
|
|
||||||
Root string `json:"root,required"`
|
|
||||||
State string `json:"state,required"`
|
|
||||||
JSON appPathJSON `json:"-"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// appPathJSON contains the JSON metadata for the struct [AppPath]
|
|
||||||
type appPathJSON struct {
|
|
||||||
Config apijson.Field
|
|
||||||
Cwd apijson.Field
|
|
||||||
Data apijson.Field
|
|
||||||
Root apijson.Field
|
|
||||||
State apijson.Field
|
|
||||||
raw string
|
|
||||||
ExtraFields map[string]apijson.Field
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *AppPath) UnmarshalJSON(data []byte) (err error) {
|
|
||||||
return apijson.UnmarshalRoot(data, r)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r appPathJSON) RawJSON() string {
|
|
||||||
return r.raw
|
|
||||||
}
|
|
||||||
|
|
||||||
type AppTime struct {
|
|
||||||
Initialized float64 `json:"initialized"`
|
|
||||||
JSON appTimeJSON `json:"-"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// appTimeJSON contains the JSON metadata for the struct [AppTime]
|
|
||||||
type appTimeJSON struct {
|
|
||||||
Initialized apijson.Field
|
|
||||||
raw string
|
|
||||||
ExtraFields map[string]apijson.Field
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *AppTime) UnmarshalJSON(data []byte) (err error) {
|
|
||||||
return apijson.UnmarshalRoot(data, r)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r appTimeJSON) RawJSON() string {
|
|
||||||
return r.raw
|
|
||||||
}
|
|
||||||
|
|
||||||
type Model struct {
|
type Model struct {
|
||||||
ID string `json:"id,required"`
|
ID string `json:"id,required"`
|
||||||
Attachment bool `json:"attachment,required"`
|
Attachment bool `json:"attachment,required"`
|
||||||
@@ -440,7 +194,8 @@ type AppLogParams struct {
|
|||||||
// Log message
|
// Log message
|
||||||
Message param.Field[string] `json:"message,required"`
|
Message param.Field[string] `json:"message,required"`
|
||||||
// Service name for the log entry
|
// Service name for the log entry
|
||||||
Service param.Field[string] `json:"service,required"`
|
Service param.Field[string] `json:"service,required"`
|
||||||
|
Directory param.Field[string] `query:"directory"`
|
||||||
// Additional metadata for the log entry
|
// Additional metadata for the log entry
|
||||||
Extra param.Field[map[string]interface{}] `json:"extra"`
|
Extra param.Field[map[string]interface{}] `json:"extra"`
|
||||||
}
|
}
|
||||||
@@ -449,6 +204,14 @@ func (r AppLogParams) MarshalJSON() (data []byte, err error) {
|
|||||||
return apijson.MarshalRoot(r)
|
return apijson.MarshalRoot(r)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// URLQuery serializes [AppLogParams]'s query parameters as `url.Values`.
|
||||||
|
func (r AppLogParams) URLQuery() (v url.Values) {
|
||||||
|
return apiquery.MarshalWithSettings(r, apiquery.QuerySettings{
|
||||||
|
ArrayFormat: apiquery.ArrayQueryFormatComma,
|
||||||
|
NestedFormat: apiquery.NestedQueryFormatBrackets,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// Log level
|
// Log level
|
||||||
type AppLogParamsLevel string
|
type AppLogParamsLevel string
|
||||||
|
|
||||||
@@ -466,3 +229,15 @@ func (r AppLogParamsLevel) IsKnown() bool {
|
|||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type AppProvidersParams struct {
|
||||||
|
Directory param.Field[string] `query:"directory"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// URLQuery serializes [AppProvidersParams]'s query parameters as `url.Values`.
|
||||||
|
func (r AppProvidersParams) URLQuery() (v url.Values) {
|
||||||
|
return apiquery.MarshalWithSettings(r, apiquery.QuerySettings{
|
||||||
|
ArrayFormat: apiquery.ArrayQueryFormatComma,
|
||||||
|
NestedFormat: apiquery.NestedQueryFormatBrackets,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
@@ -13,74 +13,8 @@ import (
|
|||||||
"github.com/sst/opencode-sdk-go/option"
|
"github.com/sst/opencode-sdk-go/option"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestAppAgents(t *testing.T) {
|
|
||||||
t.Skip("skipped: tests are disabled for the time being")
|
|
||||||
baseURL := "http://localhost:4010"
|
|
||||||
if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
|
|
||||||
baseURL = envURL
|
|
||||||
}
|
|
||||||
if !testutil.CheckTestServer(t, baseURL) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
client := opencode.NewClient(
|
|
||||||
option.WithBaseURL(baseURL),
|
|
||||||
)
|
|
||||||
_, err := client.App.Agents(context.TODO())
|
|
||||||
if err != nil {
|
|
||||||
var apierr *opencode.Error
|
|
||||||
if errors.As(err, &apierr) {
|
|
||||||
t.Log(string(apierr.DumpRequest(true)))
|
|
||||||
}
|
|
||||||
t.Fatalf("err should be nil: %s", err.Error())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestAppGet(t *testing.T) {
|
|
||||||
t.Skip("skipped: tests are disabled for the time being")
|
|
||||||
baseURL := "http://localhost:4010"
|
|
||||||
if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
|
|
||||||
baseURL = envURL
|
|
||||||
}
|
|
||||||
if !testutil.CheckTestServer(t, baseURL) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
client := opencode.NewClient(
|
|
||||||
option.WithBaseURL(baseURL),
|
|
||||||
)
|
|
||||||
_, err := client.App.Get(context.TODO())
|
|
||||||
if err != nil {
|
|
||||||
var apierr *opencode.Error
|
|
||||||
if errors.As(err, &apierr) {
|
|
||||||
t.Log(string(apierr.DumpRequest(true)))
|
|
||||||
}
|
|
||||||
t.Fatalf("err should be nil: %s", err.Error())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestAppInit(t *testing.T) {
|
|
||||||
t.Skip("skipped: tests are disabled for the time being")
|
|
||||||
baseURL := "http://localhost:4010"
|
|
||||||
if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
|
|
||||||
baseURL = envURL
|
|
||||||
}
|
|
||||||
if !testutil.CheckTestServer(t, baseURL) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
client := opencode.NewClient(
|
|
||||||
option.WithBaseURL(baseURL),
|
|
||||||
)
|
|
||||||
_, err := client.App.Init(context.TODO())
|
|
||||||
if err != nil {
|
|
||||||
var apierr *opencode.Error
|
|
||||||
if errors.As(err, &apierr) {
|
|
||||||
t.Log(string(apierr.DumpRequest(true)))
|
|
||||||
}
|
|
||||||
t.Fatalf("err should be nil: %s", err.Error())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestAppLogWithOptionalParams(t *testing.T) {
|
func TestAppLogWithOptionalParams(t *testing.T) {
|
||||||
t.Skip("skipped: tests are disabled for the time being")
|
t.Skip("Prism tests are disabled")
|
||||||
baseURL := "http://localhost:4010"
|
baseURL := "http://localhost:4010"
|
||||||
if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
|
if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
|
||||||
baseURL = envURL
|
baseURL = envURL
|
||||||
@@ -92,9 +26,10 @@ func TestAppLogWithOptionalParams(t *testing.T) {
|
|||||||
option.WithBaseURL(baseURL),
|
option.WithBaseURL(baseURL),
|
||||||
)
|
)
|
||||||
_, err := client.App.Log(context.TODO(), opencode.AppLogParams{
|
_, err := client.App.Log(context.TODO(), opencode.AppLogParams{
|
||||||
Level: opencode.F(opencode.AppLogParamsLevelDebug),
|
Level: opencode.F(opencode.AppLogParamsLevelDebug),
|
||||||
Message: opencode.F("message"),
|
Message: opencode.F("message"),
|
||||||
Service: opencode.F("service"),
|
Service: opencode.F("service"),
|
||||||
|
Directory: opencode.F("directory"),
|
||||||
Extra: opencode.F(map[string]interface{}{
|
Extra: opencode.F(map[string]interface{}{
|
||||||
"foo": "bar",
|
"foo": "bar",
|
||||||
}),
|
}),
|
||||||
@@ -108,8 +43,8 @@ func TestAppLogWithOptionalParams(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAppProviders(t *testing.T) {
|
func TestAppProvidersWithOptionalParams(t *testing.T) {
|
||||||
t.Skip("skipped: tests are disabled for the time being")
|
t.Skip("Prism tests are disabled")
|
||||||
baseURL := "http://localhost:4010"
|
baseURL := "http://localhost:4010"
|
||||||
if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
|
if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
|
||||||
baseURL = envURL
|
baseURL = envURL
|
||||||
@@ -120,7 +55,9 @@ func TestAppProviders(t *testing.T) {
|
|||||||
client := opencode.NewClient(
|
client := opencode.NewClient(
|
||||||
option.WithBaseURL(baseURL),
|
option.WithBaseURL(baseURL),
|
||||||
)
|
)
|
||||||
_, err := client.App.Providers(context.TODO())
|
_, err := client.App.Providers(context.TODO(), opencode.AppProvidersParams{
|
||||||
|
Directory: opencode.F("directory"),
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
var apierr *opencode.Error
|
var apierr *opencode.Error
|
||||||
if errors.As(err, &apierr) {
|
if errors.As(err, &apierr) {
|
||||||
|
|||||||
@@ -17,11 +17,14 @@ import (
|
|||||||
type Client struct {
|
type Client struct {
|
||||||
Options []option.RequestOption
|
Options []option.RequestOption
|
||||||
Event *EventService
|
Event *EventService
|
||||||
|
Path *PathService
|
||||||
App *AppService
|
App *AppService
|
||||||
|
Agent *AgentService
|
||||||
Find *FindService
|
Find *FindService
|
||||||
File *FileService
|
File *FileService
|
||||||
Config *ConfigService
|
Config *ConfigService
|
||||||
Command *CommandService
|
Command *CommandService
|
||||||
|
Project *ProjectService
|
||||||
Session *SessionService
|
Session *SessionService
|
||||||
Tui *TuiService
|
Tui *TuiService
|
||||||
}
|
}
|
||||||
@@ -46,11 +49,14 @@ func NewClient(opts ...option.RequestOption) (r *Client) {
|
|||||||
r = &Client{Options: opts}
|
r = &Client{Options: opts}
|
||||||
|
|
||||||
r.Event = NewEventService(opts...)
|
r.Event = NewEventService(opts...)
|
||||||
|
r.Path = NewPathService(opts...)
|
||||||
r.App = NewAppService(opts...)
|
r.App = NewAppService(opts...)
|
||||||
|
r.Agent = NewAgentService(opts...)
|
||||||
r.Find = NewFindService(opts...)
|
r.Find = NewFindService(opts...)
|
||||||
r.File = NewFileService(opts...)
|
r.File = NewFileService(opts...)
|
||||||
r.Config = NewConfigService(opts...)
|
r.Config = NewConfigService(opts...)
|
||||||
r.Command = NewCommandService(opts...)
|
r.Command = NewCommandService(opts...)
|
||||||
|
r.Project = NewProjectService(opts...)
|
||||||
r.Session = NewSessionService(opts...)
|
r.Session = NewSessionService(opts...)
|
||||||
r.Tui = NewTuiService(opts...)
|
r.Tui = NewTuiService(opts...)
|
||||||
|
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ func TestUserAgentHeader(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
client.Session.List(context.Background())
|
client.Session.List(context.Background(), opencode.SessionListParams{})
|
||||||
if userAgent != fmt.Sprintf("Opencode/Go %s", internal.PackageVersion) {
|
if userAgent != fmt.Sprintf("Opencode/Go %s", internal.PackageVersion) {
|
||||||
t.Errorf("Expected User-Agent to be correct, but got: %#v", userAgent)
|
t.Errorf("Expected User-Agent to be correct, but got: %#v", userAgent)
|
||||||
}
|
}
|
||||||
@@ -61,7 +61,7 @@ func TestRetryAfter(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
_, err := client.Session.List(context.Background())
|
_, err := client.Session.List(context.Background(), opencode.SessionListParams{})
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Error("Expected there to be a cancel error")
|
t.Error("Expected there to be a cancel error")
|
||||||
}
|
}
|
||||||
@@ -95,7 +95,7 @@ func TestDeleteRetryCountHeader(t *testing.T) {
|
|||||||
}),
|
}),
|
||||||
option.WithHeaderDel("X-Stainless-Retry-Count"),
|
option.WithHeaderDel("X-Stainless-Retry-Count"),
|
||||||
)
|
)
|
||||||
_, err := client.Session.List(context.Background())
|
_, err := client.Session.List(context.Background(), opencode.SessionListParams{})
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Error("Expected there to be a cancel error")
|
t.Error("Expected there to be a cancel error")
|
||||||
}
|
}
|
||||||
@@ -124,7 +124,7 @@ func TestOverwriteRetryCountHeader(t *testing.T) {
|
|||||||
}),
|
}),
|
||||||
option.WithHeader("X-Stainless-Retry-Count", "42"),
|
option.WithHeader("X-Stainless-Retry-Count", "42"),
|
||||||
)
|
)
|
||||||
_, err := client.Session.List(context.Background())
|
_, err := client.Session.List(context.Background(), opencode.SessionListParams{})
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Error("Expected there to be a cancel error")
|
t.Error("Expected there to be a cancel error")
|
||||||
}
|
}
|
||||||
@@ -152,7 +152,7 @@ func TestRetryAfterMs(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
_, err := client.Session.List(context.Background())
|
_, err := client.Session.List(context.Background(), opencode.SessionListParams{})
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Error("Expected there to be a cancel error")
|
t.Error("Expected there to be a cancel error")
|
||||||
}
|
}
|
||||||
@@ -174,7 +174,7 @@ func TestContextCancel(t *testing.T) {
|
|||||||
)
|
)
|
||||||
cancelCtx, cancel := context.WithCancel(context.Background())
|
cancelCtx, cancel := context.WithCancel(context.Background())
|
||||||
cancel()
|
cancel()
|
||||||
_, err := client.Session.List(cancelCtx)
|
_, err := client.Session.List(cancelCtx, opencode.SessionListParams{})
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Error("Expected there to be a cancel error")
|
t.Error("Expected there to be a cancel error")
|
||||||
}
|
}
|
||||||
@@ -193,7 +193,7 @@ func TestContextCancelDelay(t *testing.T) {
|
|||||||
)
|
)
|
||||||
cancelCtx, cancel := context.WithTimeout(context.Background(), 2*time.Millisecond)
|
cancelCtx, cancel := context.WithTimeout(context.Background(), 2*time.Millisecond)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
_, err := client.Session.List(cancelCtx)
|
_, err := client.Session.List(cancelCtx, opencode.SessionListParams{})
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Error("expected there to be a cancel error")
|
t.Error("expected there to be a cancel error")
|
||||||
}
|
}
|
||||||
@@ -218,7 +218,7 @@ func TestContextDeadline(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
_, err := client.Session.List(deadlineCtx)
|
_, err := client.Session.List(deadlineCtx, opencode.SessionListParams{})
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Error("expected there to be a deadline error")
|
t.Error("expected there to be a deadline error")
|
||||||
}
|
}
|
||||||
@@ -262,7 +262,7 @@ func TestContextDeadlineStreaming(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
stream := client.Event.ListStreaming(deadlineCtx)
|
stream := client.Event.ListStreaming(deadlineCtx, opencode.EventListParams{})
|
||||||
for stream.Next() {
|
for stream.Next() {
|
||||||
_ = stream.Current()
|
_ = stream.Current()
|
||||||
}
|
}
|
||||||
@@ -306,7 +306,11 @@ func TestContextDeadlineStreamingWithRequestTimeout(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
stream := client.Event.ListStreaming(context.Background(), option.WithRequestTimeout((100 * time.Millisecond)))
|
stream := client.Event.ListStreaming(
|
||||||
|
context.Background(),
|
||||||
|
opencode.EventListParams{},
|
||||||
|
option.WithRequestTimeout((100 * time.Millisecond)),
|
||||||
|
)
|
||||||
for stream.Next() {
|
for stream.Next() {
|
||||||
_ = stream.Current()
|
_ = stream.Current()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,8 +5,11 @@ package opencode
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
|
||||||
"github.com/sst/opencode-sdk-go/internal/apijson"
|
"github.com/sst/opencode-sdk-go/internal/apijson"
|
||||||
|
"github.com/sst/opencode-sdk-go/internal/apiquery"
|
||||||
|
"github.com/sst/opencode-sdk-go/internal/param"
|
||||||
"github.com/sst/opencode-sdk-go/internal/requestconfig"
|
"github.com/sst/opencode-sdk-go/internal/requestconfig"
|
||||||
"github.com/sst/opencode-sdk-go/option"
|
"github.com/sst/opencode-sdk-go/option"
|
||||||
)
|
)
|
||||||
@@ -31,10 +34,10 @@ func NewCommandService(opts ...option.RequestOption) (r *CommandService) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// List all commands
|
// List all commands
|
||||||
func (r *CommandService) List(ctx context.Context, opts ...option.RequestOption) (res *[]Command, err error) {
|
func (r *CommandService) List(ctx context.Context, query CommandListParams, opts ...option.RequestOption) (res *[]Command, err error) {
|
||||||
opts = append(r.Options[:], opts...)
|
opts = append(r.Options[:], opts...)
|
||||||
path := "command"
|
path := "command"
|
||||||
err = requestconfig.ExecuteNewRequest(ctx, http.MethodGet, path, nil, &res, opts...)
|
err = requestconfig.ExecuteNewRequest(ctx, http.MethodGet, path, query, &res, opts...)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,3 +68,15 @@ func (r *Command) UnmarshalJSON(data []byte) (err error) {
|
|||||||
func (r commandJSON) RawJSON() string {
|
func (r commandJSON) RawJSON() string {
|
||||||
return r.raw
|
return r.raw
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type CommandListParams struct {
|
||||||
|
Directory param.Field[string] `query:"directory"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// URLQuery serializes [CommandListParams]'s query parameters as `url.Values`.
|
||||||
|
func (r CommandListParams) URLQuery() (v url.Values) {
|
||||||
|
return apiquery.MarshalWithSettings(r, apiquery.QuerySettings{
|
||||||
|
ArrayFormat: apiquery.ArrayQueryFormatComma,
|
||||||
|
NestedFormat: apiquery.NestedQueryFormatBrackets,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
@@ -13,8 +13,8 @@ import (
|
|||||||
"github.com/sst/opencode-sdk-go/option"
|
"github.com/sst/opencode-sdk-go/option"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestCommandList(t *testing.T) {
|
func TestCommandListWithOptionalParams(t *testing.T) {
|
||||||
t.Skip("skipped: tests are disabled for the time being")
|
t.Skip("Prism tests are disabled")
|
||||||
baseURL := "http://localhost:4010"
|
baseURL := "http://localhost:4010"
|
||||||
if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
|
if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
|
||||||
baseURL = envURL
|
baseURL = envURL
|
||||||
@@ -25,7 +25,9 @@ func TestCommandList(t *testing.T) {
|
|||||||
client := opencode.NewClient(
|
client := opencode.NewClient(
|
||||||
option.WithBaseURL(baseURL),
|
option.WithBaseURL(baseURL),
|
||||||
)
|
)
|
||||||
_, err := client.Command.List(context.TODO())
|
_, err := client.Command.List(context.TODO(), opencode.CommandListParams{
|
||||||
|
Directory: opencode.F("directory"),
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
var apierr *opencode.Error
|
var apierr *opencode.Error
|
||||||
if errors.As(err, &apierr) {
|
if errors.As(err, &apierr) {
|
||||||
|
|||||||
@@ -5,11 +5,15 @@ package opencode
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/url"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
|
||||||
"github.com/sst/opencode-sdk-go/internal/apijson"
|
"github.com/sst/opencode-sdk-go/internal/apijson"
|
||||||
|
"github.com/sst/opencode-sdk-go/internal/apiquery"
|
||||||
|
"github.com/sst/opencode-sdk-go/internal/param"
|
||||||
"github.com/sst/opencode-sdk-go/internal/requestconfig"
|
"github.com/sst/opencode-sdk-go/internal/requestconfig"
|
||||||
"github.com/sst/opencode-sdk-go/option"
|
"github.com/sst/opencode-sdk-go/option"
|
||||||
|
"github.com/sst/opencode-sdk-go/shared"
|
||||||
"github.com/tidwall/gjson"
|
"github.com/tidwall/gjson"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -33,10 +37,10 @@ func NewConfigService(opts ...option.RequestOption) (r *ConfigService) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get config info
|
// Get config info
|
||||||
func (r *ConfigService) Get(ctx context.Context, opts ...option.RequestOption) (res *Config, err error) {
|
func (r *ConfigService) Get(ctx context.Context, query ConfigGetParams, opts ...option.RequestOption) (res *Config, err error) {
|
||||||
opts = append(r.Options[:], opts...)
|
opts = append(r.Options[:], opts...)
|
||||||
path := "config"
|
path := "config"
|
||||||
err = requestconfig.ExecuteNewRequest(ctx, http.MethodGet, path, nil, &res, opts...)
|
err = requestconfig.ExecuteNewRequest(ctx, http.MethodGet, path, query, &res, opts...)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,8 +53,9 @@ type Config struct {
|
|||||||
// automatically
|
// automatically
|
||||||
Autoshare bool `json:"autoshare"`
|
Autoshare bool `json:"autoshare"`
|
||||||
// Automatically update to the latest version
|
// Automatically update to the latest version
|
||||||
Autoupdate bool `json:"autoupdate"`
|
Autoupdate bool `json:"autoupdate"`
|
||||||
Command map[string]ConfigCommand `json:"command"`
|
// Command configuration, see https://opencode.ai/docs/commands
|
||||||
|
Command map[string]ConfigCommand `json:"command"`
|
||||||
// Disable providers that are loaded automatically
|
// Disable providers that are loaded automatically
|
||||||
DisabledProviders []string `json:"disabled_providers"`
|
DisabledProviders []string `json:"disabled_providers"`
|
||||||
Experimental ConfigExperimental `json:"experimental"`
|
Experimental ConfigExperimental `json:"experimental"`
|
||||||
@@ -1646,10 +1651,13 @@ func (r configProviderModelsLimitJSON) RawJSON() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ConfigProviderOptions struct {
|
type ConfigProviderOptions struct {
|
||||||
APIKey string `json:"apiKey"`
|
APIKey string `json:"apiKey"`
|
||||||
BaseURL string `json:"baseURL"`
|
BaseURL string `json:"baseURL"`
|
||||||
ExtraFields map[string]interface{} `json:"-,extras"`
|
// Timeout in milliseconds for requests to this provider. Default is 300000 (5
|
||||||
JSON configProviderOptionsJSON `json:"-"`
|
// minutes). Set to false to disable timeout.
|
||||||
|
Timeout ConfigProviderOptionsTimeoutUnion `json:"timeout"`
|
||||||
|
ExtraFields map[string]interface{} `json:"-,extras"`
|
||||||
|
JSON configProviderOptionsJSON `json:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// configProviderOptionsJSON contains the JSON metadata for the struct
|
// configProviderOptionsJSON contains the JSON metadata for the struct
|
||||||
@@ -1657,6 +1665,7 @@ type ConfigProviderOptions struct {
|
|||||||
type configProviderOptionsJSON struct {
|
type configProviderOptionsJSON struct {
|
||||||
APIKey apijson.Field
|
APIKey apijson.Field
|
||||||
BaseURL apijson.Field
|
BaseURL apijson.Field
|
||||||
|
Timeout apijson.Field
|
||||||
raw string
|
raw string
|
||||||
ExtraFields map[string]apijson.Field
|
ExtraFields map[string]apijson.Field
|
||||||
}
|
}
|
||||||
@@ -1669,6 +1678,33 @@ func (r configProviderOptionsJSON) RawJSON() string {
|
|||||||
return r.raw
|
return r.raw
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Timeout in milliseconds for requests to this provider. Default is 300000 (5
|
||||||
|
// minutes). Set to false to disable timeout.
|
||||||
|
//
|
||||||
|
// Union satisfied by [shared.UnionInt] or [shared.UnionBool].
|
||||||
|
type ConfigProviderOptionsTimeoutUnion interface {
|
||||||
|
ImplementsConfigProviderOptionsTimeoutUnion()
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
apijson.RegisterUnion(
|
||||||
|
reflect.TypeOf((*ConfigProviderOptionsTimeoutUnion)(nil)).Elem(),
|
||||||
|
"",
|
||||||
|
apijson.UnionVariant{
|
||||||
|
TypeFilter: gjson.Number,
|
||||||
|
Type: reflect.TypeOf(shared.UnionInt(0)),
|
||||||
|
},
|
||||||
|
apijson.UnionVariant{
|
||||||
|
TypeFilter: gjson.True,
|
||||||
|
Type: reflect.TypeOf(shared.UnionBool(false)),
|
||||||
|
},
|
||||||
|
apijson.UnionVariant{
|
||||||
|
TypeFilter: gjson.False,
|
||||||
|
Type: reflect.TypeOf(shared.UnionBool(false)),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
// Control sharing behavior:'manual' allows manual sharing via commands, 'auto'
|
// Control sharing behavior:'manual' allows manual sharing via commands, 'auto'
|
||||||
// enables automatic sharing, 'disabled' disables all sharing
|
// enables automatic sharing, 'disabled' disables all sharing
|
||||||
type ConfigShare string
|
type ConfigShare string
|
||||||
@@ -1967,3 +2003,15 @@ func (r McpRemoteConfigType) IsKnown() bool {
|
|||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ConfigGetParams struct {
|
||||||
|
Directory param.Field[string] `query:"directory"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// URLQuery serializes [ConfigGetParams]'s query parameters as `url.Values`.
|
||||||
|
func (r ConfigGetParams) URLQuery() (v url.Values) {
|
||||||
|
return apiquery.MarshalWithSettings(r, apiquery.QuerySettings{
|
||||||
|
ArrayFormat: apiquery.ArrayQueryFormatComma,
|
||||||
|
NestedFormat: apiquery.NestedQueryFormatBrackets,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
@@ -13,8 +13,8 @@ import (
|
|||||||
"github.com/sst/opencode-sdk-go/option"
|
"github.com/sst/opencode-sdk-go/option"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestConfigGet(t *testing.T) {
|
func TestConfigGetWithOptionalParams(t *testing.T) {
|
||||||
t.Skip("skipped: tests are disabled for the time being")
|
t.Skip("Prism tests are disabled")
|
||||||
baseURL := "http://localhost:4010"
|
baseURL := "http://localhost:4010"
|
||||||
if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
|
if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
|
||||||
baseURL = envURL
|
baseURL = envURL
|
||||||
@@ -25,7 +25,9 @@ func TestConfigGet(t *testing.T) {
|
|||||||
client := opencode.NewClient(
|
client := opencode.NewClient(
|
||||||
option.WithBaseURL(baseURL),
|
option.WithBaseURL(baseURL),
|
||||||
)
|
)
|
||||||
_, err := client.Config.Get(context.TODO())
|
_, err := client.Config.Get(context.TODO(), opencode.ConfigGetParams{
|
||||||
|
Directory: opencode.F("directory"),
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
var apierr *opencode.Error
|
var apierr *opencode.Error
|
||||||
if errors.As(err, &apierr) {
|
if errors.As(err, &apierr) {
|
||||||
|
|||||||
@@ -5,9 +5,12 @@ package opencode
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/url"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
|
||||||
"github.com/sst/opencode-sdk-go/internal/apijson"
|
"github.com/sst/opencode-sdk-go/internal/apijson"
|
||||||
|
"github.com/sst/opencode-sdk-go/internal/apiquery"
|
||||||
|
"github.com/sst/opencode-sdk-go/internal/param"
|
||||||
"github.com/sst/opencode-sdk-go/internal/requestconfig"
|
"github.com/sst/opencode-sdk-go/internal/requestconfig"
|
||||||
"github.com/sst/opencode-sdk-go/option"
|
"github.com/sst/opencode-sdk-go/option"
|
||||||
"github.com/sst/opencode-sdk-go/packages/ssestream"
|
"github.com/sst/opencode-sdk-go/packages/ssestream"
|
||||||
@@ -35,7 +38,7 @@ func NewEventService(opts ...option.RequestOption) (r *EventService) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get events
|
// Get events
|
||||||
func (r *EventService) ListStreaming(ctx context.Context, opts ...option.RequestOption) (stream *ssestream.Stream[EventListResponse]) {
|
func (r *EventService) ListStreaming(ctx context.Context, query EventListParams, opts ...option.RequestOption) (stream *ssestream.Stream[EventListResponse]) {
|
||||||
var (
|
var (
|
||||||
raw *http.Response
|
raw *http.Response
|
||||||
err error
|
err error
|
||||||
@@ -43,7 +46,7 @@ func (r *EventService) ListStreaming(ctx context.Context, opts ...option.Request
|
|||||||
opts = append(r.Options[:], opts...)
|
opts = append(r.Options[:], opts...)
|
||||||
opts = append([]option.RequestOption{option.WithHeader("Accept", "text/event-stream")}, opts...)
|
opts = append([]option.RequestOption{option.WithHeader("Accept", "text/event-stream")}, opts...)
|
||||||
path := "event"
|
path := "event"
|
||||||
err = requestconfig.ExecuteNewRequest(ctx, http.MethodGet, path, nil, &raw, opts...)
|
err = requestconfig.ExecuteNewRequest(ctx, http.MethodGet, path, query, &raw, opts...)
|
||||||
return ssestream.NewStream[EventListResponse](ssestream.NewDecoder(raw), err)
|
return ssestream.NewStream[EventListResponse](ssestream.NewDecoder(raw), err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -54,16 +57,13 @@ type EventListResponse struct {
|
|||||||
// [EventListResponseEventMessageUpdatedProperties],
|
// [EventListResponseEventMessageUpdatedProperties],
|
||||||
// [EventListResponseEventMessageRemovedProperties],
|
// [EventListResponseEventMessageRemovedProperties],
|
||||||
// [EventListResponseEventMessagePartUpdatedProperties],
|
// [EventListResponseEventMessagePartUpdatedProperties],
|
||||||
// [EventListResponseEventMessagePartRemovedProperties],
|
// [EventListResponseEventMessagePartRemovedProperties], [Permission],
|
||||||
// [EventListResponseEventStorageWriteProperties], [Permission],
|
|
||||||
// [EventListResponseEventPermissionRepliedProperties],
|
// [EventListResponseEventPermissionRepliedProperties],
|
||||||
// [EventListResponseEventFileEditedProperties],
|
// [EventListResponseEventFileEditedProperties],
|
||||||
// [EventListResponseEventSessionUpdatedProperties],
|
// [EventListResponseEventSessionUpdatedProperties],
|
||||||
// [EventListResponseEventSessionDeletedProperties],
|
// [EventListResponseEventSessionDeletedProperties],
|
||||||
// [EventListResponseEventSessionIdleProperties],
|
// [EventListResponseEventSessionIdleProperties],
|
||||||
// [EventListResponseEventSessionErrorProperties], [interface{}],
|
// [EventListResponseEventSessionErrorProperties], [interface{}].
|
||||||
// [EventListResponseEventFileWatcherUpdatedProperties],
|
|
||||||
// [EventListResponseEventIdeInstalledProperties].
|
|
||||||
Properties interface{} `json:"properties,required"`
|
Properties interface{} `json:"properties,required"`
|
||||||
Type EventListResponseType `json:"type,required"`
|
Type EventListResponseType `json:"type,required"`
|
||||||
JSON eventListResponseJSON `json:"-"`
|
JSON eventListResponseJSON `json:"-"`
|
||||||
@@ -101,13 +101,11 @@ func (r *EventListResponse) UnmarshalJSON(data []byte) (err error) {
|
|||||||
// [EventListResponseEventMessageUpdated], [EventListResponseEventMessageRemoved],
|
// [EventListResponseEventMessageUpdated], [EventListResponseEventMessageRemoved],
|
||||||
// [EventListResponseEventMessagePartUpdated],
|
// [EventListResponseEventMessagePartUpdated],
|
||||||
// [EventListResponseEventMessagePartRemoved],
|
// [EventListResponseEventMessagePartRemoved],
|
||||||
// [EventListResponseEventStorageWrite], [EventListResponseEventPermissionUpdated],
|
// [EventListResponseEventPermissionUpdated],
|
||||||
// [EventListResponseEventPermissionReplied], [EventListResponseEventFileEdited],
|
// [EventListResponseEventPermissionReplied], [EventListResponseEventFileEdited],
|
||||||
// [EventListResponseEventSessionUpdated], [EventListResponseEventSessionDeleted],
|
// [EventListResponseEventSessionUpdated], [EventListResponseEventSessionDeleted],
|
||||||
// [EventListResponseEventSessionIdle], [EventListResponseEventSessionError],
|
// [EventListResponseEventSessionIdle], [EventListResponseEventSessionError],
|
||||||
// [EventListResponseEventServerConnected],
|
// [EventListResponseEventServerConnected].
|
||||||
// [EventListResponseEventFileWatcherUpdated],
|
|
||||||
// [EventListResponseEventIdeInstalled].
|
|
||||||
func (r EventListResponse) AsUnion() EventListResponseUnion {
|
func (r EventListResponse) AsUnion() EventListResponseUnion {
|
||||||
return r.union
|
return r.union
|
||||||
}
|
}
|
||||||
@@ -117,13 +115,11 @@ func (r EventListResponse) AsUnion() EventListResponseUnion {
|
|||||||
// [EventListResponseEventMessageUpdated], [EventListResponseEventMessageRemoved],
|
// [EventListResponseEventMessageUpdated], [EventListResponseEventMessageRemoved],
|
||||||
// [EventListResponseEventMessagePartUpdated],
|
// [EventListResponseEventMessagePartUpdated],
|
||||||
// [EventListResponseEventMessagePartRemoved],
|
// [EventListResponseEventMessagePartRemoved],
|
||||||
// [EventListResponseEventStorageWrite], [EventListResponseEventPermissionUpdated],
|
// [EventListResponseEventPermissionUpdated],
|
||||||
// [EventListResponseEventPermissionReplied], [EventListResponseEventFileEdited],
|
// [EventListResponseEventPermissionReplied], [EventListResponseEventFileEdited],
|
||||||
// [EventListResponseEventSessionUpdated], [EventListResponseEventSessionDeleted],
|
// [EventListResponseEventSessionUpdated], [EventListResponseEventSessionDeleted],
|
||||||
// [EventListResponseEventSessionIdle], [EventListResponseEventSessionError],
|
// [EventListResponseEventSessionIdle], [EventListResponseEventSessionError] or
|
||||||
// [EventListResponseEventServerConnected],
|
// [EventListResponseEventServerConnected].
|
||||||
// [EventListResponseEventFileWatcherUpdated] or
|
|
||||||
// [EventListResponseEventIdeInstalled].
|
|
||||||
type EventListResponseUnion interface {
|
type EventListResponseUnion interface {
|
||||||
implementsEventListResponse()
|
implementsEventListResponse()
|
||||||
}
|
}
|
||||||
@@ -162,11 +158,6 @@ func init() {
|
|||||||
Type: reflect.TypeOf(EventListResponseEventMessagePartRemoved{}),
|
Type: reflect.TypeOf(EventListResponseEventMessagePartRemoved{}),
|
||||||
DiscriminatorValue: "message.part.removed",
|
DiscriminatorValue: "message.part.removed",
|
||||||
},
|
},
|
||||||
apijson.UnionVariant{
|
|
||||||
TypeFilter: gjson.JSON,
|
|
||||||
Type: reflect.TypeOf(EventListResponseEventStorageWrite{}),
|
|
||||||
DiscriminatorValue: "storage.write",
|
|
||||||
},
|
|
||||||
apijson.UnionVariant{
|
apijson.UnionVariant{
|
||||||
TypeFilter: gjson.JSON,
|
TypeFilter: gjson.JSON,
|
||||||
Type: reflect.TypeOf(EventListResponseEventPermissionUpdated{}),
|
Type: reflect.TypeOf(EventListResponseEventPermissionUpdated{}),
|
||||||
@@ -207,16 +198,6 @@ func init() {
|
|||||||
Type: reflect.TypeOf(EventListResponseEventServerConnected{}),
|
Type: reflect.TypeOf(EventListResponseEventServerConnected{}),
|
||||||
DiscriminatorValue: "server.connected",
|
DiscriminatorValue: "server.connected",
|
||||||
},
|
},
|
||||||
apijson.UnionVariant{
|
|
||||||
TypeFilter: gjson.JSON,
|
|
||||||
Type: reflect.TypeOf(EventListResponseEventFileWatcherUpdated{}),
|
|
||||||
DiscriminatorValue: "file.watcher.updated",
|
|
||||||
},
|
|
||||||
apijson.UnionVariant{
|
|
||||||
TypeFilter: gjson.JSON,
|
|
||||||
Type: reflect.TypeOf(EventListResponseEventIdeInstalled{}),
|
|
||||||
DiscriminatorValue: "ide.installed",
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -588,68 +569,6 @@ func (r EventListResponseEventMessagePartRemovedType) IsKnown() bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
type EventListResponseEventStorageWrite struct {
|
|
||||||
Properties EventListResponseEventStorageWriteProperties `json:"properties,required"`
|
|
||||||
Type EventListResponseEventStorageWriteType `json:"type,required"`
|
|
||||||
JSON eventListResponseEventStorageWriteJSON `json:"-"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// eventListResponseEventStorageWriteJSON contains the JSON metadata for the struct
|
|
||||||
// [EventListResponseEventStorageWrite]
|
|
||||||
type eventListResponseEventStorageWriteJSON struct {
|
|
||||||
Properties apijson.Field
|
|
||||||
Type apijson.Field
|
|
||||||
raw string
|
|
||||||
ExtraFields map[string]apijson.Field
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *EventListResponseEventStorageWrite) UnmarshalJSON(data []byte) (err error) {
|
|
||||||
return apijson.UnmarshalRoot(data, r)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r eventListResponseEventStorageWriteJSON) RawJSON() string {
|
|
||||||
return r.raw
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r EventListResponseEventStorageWrite) implementsEventListResponse() {}
|
|
||||||
|
|
||||||
type EventListResponseEventStorageWriteProperties struct {
|
|
||||||
Key string `json:"key,required"`
|
|
||||||
Content interface{} `json:"content"`
|
|
||||||
JSON eventListResponseEventStorageWritePropertiesJSON `json:"-"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// eventListResponseEventStorageWritePropertiesJSON contains the JSON metadata for
|
|
||||||
// the struct [EventListResponseEventStorageWriteProperties]
|
|
||||||
type eventListResponseEventStorageWritePropertiesJSON struct {
|
|
||||||
Key apijson.Field
|
|
||||||
Content apijson.Field
|
|
||||||
raw string
|
|
||||||
ExtraFields map[string]apijson.Field
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *EventListResponseEventStorageWriteProperties) UnmarshalJSON(data []byte) (err error) {
|
|
||||||
return apijson.UnmarshalRoot(data, r)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r eventListResponseEventStorageWritePropertiesJSON) RawJSON() string {
|
|
||||||
return r.raw
|
|
||||||
}
|
|
||||||
|
|
||||||
type EventListResponseEventStorageWriteType string
|
|
||||||
|
|
||||||
const (
|
|
||||||
EventListResponseEventStorageWriteTypeStorageWrite EventListResponseEventStorageWriteType = "storage.write"
|
|
||||||
)
|
|
||||||
|
|
||||||
func (r EventListResponseEventStorageWriteType) IsKnown() bool {
|
|
||||||
switch r {
|
|
||||||
case EventListResponseEventStorageWriteTypeStorageWrite:
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
type EventListResponseEventPermissionUpdated struct {
|
type EventListResponseEventPermissionUpdated struct {
|
||||||
Properties Permission `json:"properties,required"`
|
Properties Permission `json:"properties,required"`
|
||||||
Type EventListResponseEventPermissionUpdatedType `json:"type,required"`
|
Type EventListResponseEventPermissionUpdatedType `json:"type,required"`
|
||||||
@@ -1228,143 +1147,6 @@ func (r EventListResponseEventServerConnectedType) IsKnown() bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
type EventListResponseEventFileWatcherUpdated struct {
|
|
||||||
Properties EventListResponseEventFileWatcherUpdatedProperties `json:"properties,required"`
|
|
||||||
Type EventListResponseEventFileWatcherUpdatedType `json:"type,required"`
|
|
||||||
JSON eventListResponseEventFileWatcherUpdatedJSON `json:"-"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// eventListResponseEventFileWatcherUpdatedJSON contains the JSON metadata for the
|
|
||||||
// struct [EventListResponseEventFileWatcherUpdated]
|
|
||||||
type eventListResponseEventFileWatcherUpdatedJSON struct {
|
|
||||||
Properties apijson.Field
|
|
||||||
Type apijson.Field
|
|
||||||
raw string
|
|
||||||
ExtraFields map[string]apijson.Field
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *EventListResponseEventFileWatcherUpdated) UnmarshalJSON(data []byte) (err error) {
|
|
||||||
return apijson.UnmarshalRoot(data, r)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r eventListResponseEventFileWatcherUpdatedJSON) RawJSON() string {
|
|
||||||
return r.raw
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r EventListResponseEventFileWatcherUpdated) implementsEventListResponse() {}
|
|
||||||
|
|
||||||
type EventListResponseEventFileWatcherUpdatedProperties struct {
|
|
||||||
Event EventListResponseEventFileWatcherUpdatedPropertiesEvent `json:"event,required"`
|
|
||||||
File string `json:"file,required"`
|
|
||||||
JSON eventListResponseEventFileWatcherUpdatedPropertiesJSON `json:"-"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// eventListResponseEventFileWatcherUpdatedPropertiesJSON contains the JSON
|
|
||||||
// metadata for the struct [EventListResponseEventFileWatcherUpdatedProperties]
|
|
||||||
type eventListResponseEventFileWatcherUpdatedPropertiesJSON struct {
|
|
||||||
Event apijson.Field
|
|
||||||
File apijson.Field
|
|
||||||
raw string
|
|
||||||
ExtraFields map[string]apijson.Field
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *EventListResponseEventFileWatcherUpdatedProperties) UnmarshalJSON(data []byte) (err error) {
|
|
||||||
return apijson.UnmarshalRoot(data, r)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r eventListResponseEventFileWatcherUpdatedPropertiesJSON) RawJSON() string {
|
|
||||||
return r.raw
|
|
||||||
}
|
|
||||||
|
|
||||||
type EventListResponseEventFileWatcherUpdatedPropertiesEvent string
|
|
||||||
|
|
||||||
const (
|
|
||||||
EventListResponseEventFileWatcherUpdatedPropertiesEventRename EventListResponseEventFileWatcherUpdatedPropertiesEvent = "rename"
|
|
||||||
EventListResponseEventFileWatcherUpdatedPropertiesEventChange EventListResponseEventFileWatcherUpdatedPropertiesEvent = "change"
|
|
||||||
)
|
|
||||||
|
|
||||||
func (r EventListResponseEventFileWatcherUpdatedPropertiesEvent) IsKnown() bool {
|
|
||||||
switch r {
|
|
||||||
case EventListResponseEventFileWatcherUpdatedPropertiesEventRename, EventListResponseEventFileWatcherUpdatedPropertiesEventChange:
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
type EventListResponseEventFileWatcherUpdatedType string
|
|
||||||
|
|
||||||
const (
|
|
||||||
EventListResponseEventFileWatcherUpdatedTypeFileWatcherUpdated EventListResponseEventFileWatcherUpdatedType = "file.watcher.updated"
|
|
||||||
)
|
|
||||||
|
|
||||||
func (r EventListResponseEventFileWatcherUpdatedType) IsKnown() bool {
|
|
||||||
switch r {
|
|
||||||
case EventListResponseEventFileWatcherUpdatedTypeFileWatcherUpdated:
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
type EventListResponseEventIdeInstalled struct {
|
|
||||||
Properties EventListResponseEventIdeInstalledProperties `json:"properties,required"`
|
|
||||||
Type EventListResponseEventIdeInstalledType `json:"type,required"`
|
|
||||||
JSON eventListResponseEventIdeInstalledJSON `json:"-"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// eventListResponseEventIdeInstalledJSON contains the JSON metadata for the struct
|
|
||||||
// [EventListResponseEventIdeInstalled]
|
|
||||||
type eventListResponseEventIdeInstalledJSON struct {
|
|
||||||
Properties apijson.Field
|
|
||||||
Type apijson.Field
|
|
||||||
raw string
|
|
||||||
ExtraFields map[string]apijson.Field
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *EventListResponseEventIdeInstalled) UnmarshalJSON(data []byte) (err error) {
|
|
||||||
return apijson.UnmarshalRoot(data, r)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r eventListResponseEventIdeInstalledJSON) RawJSON() string {
|
|
||||||
return r.raw
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r EventListResponseEventIdeInstalled) implementsEventListResponse() {}
|
|
||||||
|
|
||||||
type EventListResponseEventIdeInstalledProperties struct {
|
|
||||||
Ide string `json:"ide,required"`
|
|
||||||
JSON eventListResponseEventIdeInstalledPropertiesJSON `json:"-"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// eventListResponseEventIdeInstalledPropertiesJSON contains the JSON metadata for
|
|
||||||
// the struct [EventListResponseEventIdeInstalledProperties]
|
|
||||||
type eventListResponseEventIdeInstalledPropertiesJSON struct {
|
|
||||||
Ide apijson.Field
|
|
||||||
raw string
|
|
||||||
ExtraFields map[string]apijson.Field
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *EventListResponseEventIdeInstalledProperties) UnmarshalJSON(data []byte) (err error) {
|
|
||||||
return apijson.UnmarshalRoot(data, r)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r eventListResponseEventIdeInstalledPropertiesJSON) RawJSON() string {
|
|
||||||
return r.raw
|
|
||||||
}
|
|
||||||
|
|
||||||
type EventListResponseEventIdeInstalledType string
|
|
||||||
|
|
||||||
const (
|
|
||||||
EventListResponseEventIdeInstalledTypeIdeInstalled EventListResponseEventIdeInstalledType = "ide.installed"
|
|
||||||
)
|
|
||||||
|
|
||||||
func (r EventListResponseEventIdeInstalledType) IsKnown() bool {
|
|
||||||
switch r {
|
|
||||||
case EventListResponseEventIdeInstalledTypeIdeInstalled:
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
type EventListResponseType string
|
type EventListResponseType string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -1374,7 +1156,6 @@ const (
|
|||||||
EventListResponseTypeMessageRemoved EventListResponseType = "message.removed"
|
EventListResponseTypeMessageRemoved EventListResponseType = "message.removed"
|
||||||
EventListResponseTypeMessagePartUpdated EventListResponseType = "message.part.updated"
|
EventListResponseTypeMessagePartUpdated EventListResponseType = "message.part.updated"
|
||||||
EventListResponseTypeMessagePartRemoved EventListResponseType = "message.part.removed"
|
EventListResponseTypeMessagePartRemoved EventListResponseType = "message.part.removed"
|
||||||
EventListResponseTypeStorageWrite EventListResponseType = "storage.write"
|
|
||||||
EventListResponseTypePermissionUpdated EventListResponseType = "permission.updated"
|
EventListResponseTypePermissionUpdated EventListResponseType = "permission.updated"
|
||||||
EventListResponseTypePermissionReplied EventListResponseType = "permission.replied"
|
EventListResponseTypePermissionReplied EventListResponseType = "permission.replied"
|
||||||
EventListResponseTypeFileEdited EventListResponseType = "file.edited"
|
EventListResponseTypeFileEdited EventListResponseType = "file.edited"
|
||||||
@@ -1383,14 +1164,24 @@ const (
|
|||||||
EventListResponseTypeSessionIdle EventListResponseType = "session.idle"
|
EventListResponseTypeSessionIdle EventListResponseType = "session.idle"
|
||||||
EventListResponseTypeSessionError EventListResponseType = "session.error"
|
EventListResponseTypeSessionError EventListResponseType = "session.error"
|
||||||
EventListResponseTypeServerConnected EventListResponseType = "server.connected"
|
EventListResponseTypeServerConnected EventListResponseType = "server.connected"
|
||||||
EventListResponseTypeFileWatcherUpdated EventListResponseType = "file.watcher.updated"
|
|
||||||
EventListResponseTypeIdeInstalled EventListResponseType = "ide.installed"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func (r EventListResponseType) IsKnown() bool {
|
func (r EventListResponseType) IsKnown() bool {
|
||||||
switch r {
|
switch r {
|
||||||
case EventListResponseTypeInstallationUpdated, EventListResponseTypeLspClientDiagnostics, EventListResponseTypeMessageUpdated, EventListResponseTypeMessageRemoved, EventListResponseTypeMessagePartUpdated, EventListResponseTypeMessagePartRemoved, EventListResponseTypeStorageWrite, EventListResponseTypePermissionUpdated, EventListResponseTypePermissionReplied, EventListResponseTypeFileEdited, EventListResponseTypeSessionUpdated, EventListResponseTypeSessionDeleted, EventListResponseTypeSessionIdle, EventListResponseTypeSessionError, EventListResponseTypeServerConnected, EventListResponseTypeFileWatcherUpdated, EventListResponseTypeIdeInstalled:
|
case EventListResponseTypeInstallationUpdated, EventListResponseTypeLspClientDiagnostics, EventListResponseTypeMessageUpdated, EventListResponseTypeMessageRemoved, EventListResponseTypeMessagePartUpdated, EventListResponseTypeMessagePartRemoved, EventListResponseTypePermissionUpdated, EventListResponseTypePermissionReplied, EventListResponseTypeFileEdited, EventListResponseTypeSessionUpdated, EventListResponseTypeSessionDeleted, EventListResponseTypeSessionIdle, EventListResponseTypeSessionError, EventListResponseTypeServerConnected:
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type EventListParams struct {
|
||||||
|
Directory param.Field[string] `query:"directory"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// URLQuery serializes [EventListParams]'s query parameters as `url.Values`.
|
||||||
|
func (r EventListParams) URLQuery() (v url.Values) {
|
||||||
|
return apiquery.MarshalWithSettings(r, apiquery.QuerySettings{
|
||||||
|
ArrayFormat: apiquery.ArrayQueryFormatComma,
|
||||||
|
NestedFormat: apiquery.NestedQueryFormatBrackets,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
@@ -33,19 +33,27 @@ func NewFileService(opts ...option.RequestOption) (r *FileService) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read a file
|
// List files and directories
|
||||||
func (r *FileService) Read(ctx context.Context, query FileReadParams, opts ...option.RequestOption) (res *FileReadResponse, err error) {
|
func (r *FileService) List(ctx context.Context, query FileListParams, opts ...option.RequestOption) (res *[]FileNode, err error) {
|
||||||
opts = append(r.Options[:], opts...)
|
opts = append(r.Options[:], opts...)
|
||||||
path := "file"
|
path := "file"
|
||||||
err = requestconfig.ExecuteNewRequest(ctx, http.MethodGet, path, query, &res, opts...)
|
err = requestconfig.ExecuteNewRequest(ctx, http.MethodGet, path, query, &res, opts...)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Read a file
|
||||||
|
func (r *FileService) Read(ctx context.Context, query FileReadParams, opts ...option.RequestOption) (res *FileReadResponse, err error) {
|
||||||
|
opts = append(r.Options[:], opts...)
|
||||||
|
path := "file/content"
|
||||||
|
err = requestconfig.ExecuteNewRequest(ctx, http.MethodGet, path, query, &res, opts...)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// Get file status
|
// Get file status
|
||||||
func (r *FileService) Status(ctx context.Context, opts ...option.RequestOption) (res *[]File, err error) {
|
func (r *FileService) Status(ctx context.Context, query FileStatusParams, opts ...option.RequestOption) (res *[]File, err error) {
|
||||||
opts = append(r.Options[:], opts...)
|
opts = append(r.Options[:], opts...)
|
||||||
path := "file/status"
|
path := "file/status"
|
||||||
err = requestconfig.ExecuteNewRequest(ctx, http.MethodGet, path, nil, &res, opts...)
|
err = requestconfig.ExecuteNewRequest(ctx, http.MethodGet, path, query, &res, opts...)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -91,6 +99,47 @@ func (r FileStatus) IsKnown() bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type FileNode struct {
|
||||||
|
Ignored bool `json:"ignored,required"`
|
||||||
|
Name string `json:"name,required"`
|
||||||
|
Path string `json:"path,required"`
|
||||||
|
Type FileNodeType `json:"type,required"`
|
||||||
|
JSON fileNodeJSON `json:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// fileNodeJSON contains the JSON metadata for the struct [FileNode]
|
||||||
|
type fileNodeJSON struct {
|
||||||
|
Ignored apijson.Field
|
||||||
|
Name apijson.Field
|
||||||
|
Path apijson.Field
|
||||||
|
Type apijson.Field
|
||||||
|
raw string
|
||||||
|
ExtraFields map[string]apijson.Field
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *FileNode) UnmarshalJSON(data []byte) (err error) {
|
||||||
|
return apijson.UnmarshalRoot(data, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r fileNodeJSON) RawJSON() string {
|
||||||
|
return r.raw
|
||||||
|
}
|
||||||
|
|
||||||
|
type FileNodeType string
|
||||||
|
|
||||||
|
const (
|
||||||
|
FileNodeTypeFile FileNodeType = "file"
|
||||||
|
FileNodeTypeDirectory FileNodeType = "directory"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (r FileNodeType) IsKnown() bool {
|
||||||
|
switch r {
|
||||||
|
case FileNodeTypeFile, FileNodeTypeDirectory:
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
type FileReadResponse struct {
|
type FileReadResponse struct {
|
||||||
Content string `json:"content,required"`
|
Content string `json:"content,required"`
|
||||||
Type FileReadResponseType `json:"type,required"`
|
Type FileReadResponseType `json:"type,required"`
|
||||||
@@ -129,8 +178,22 @@ func (r FileReadResponseType) IsKnown() bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type FileListParams struct {
|
||||||
|
Path param.Field[string] `query:"path,required"`
|
||||||
|
Directory param.Field[string] `query:"directory"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// URLQuery serializes [FileListParams]'s query parameters as `url.Values`.
|
||||||
|
func (r FileListParams) URLQuery() (v url.Values) {
|
||||||
|
return apiquery.MarshalWithSettings(r, apiquery.QuerySettings{
|
||||||
|
ArrayFormat: apiquery.ArrayQueryFormatComma,
|
||||||
|
NestedFormat: apiquery.NestedQueryFormatBrackets,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
type FileReadParams struct {
|
type FileReadParams struct {
|
||||||
Path param.Field[string] `query:"path,required"`
|
Path param.Field[string] `query:"path,required"`
|
||||||
|
Directory param.Field[string] `query:"directory"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// URLQuery serializes [FileReadParams]'s query parameters as `url.Values`.
|
// URLQuery serializes [FileReadParams]'s query parameters as `url.Values`.
|
||||||
@@ -140,3 +203,15 @@ func (r FileReadParams) URLQuery() (v url.Values) {
|
|||||||
NestedFormat: apiquery.NestedQueryFormatBrackets,
|
NestedFormat: apiquery.NestedQueryFormatBrackets,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type FileStatusParams struct {
|
||||||
|
Directory param.Field[string] `query:"directory"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// URLQuery serializes [FileStatusParams]'s query parameters as `url.Values`.
|
||||||
|
func (r FileStatusParams) URLQuery() (v url.Values) {
|
||||||
|
return apiquery.MarshalWithSettings(r, apiquery.QuerySettings{
|
||||||
|
ArrayFormat: apiquery.ArrayQueryFormatComma,
|
||||||
|
NestedFormat: apiquery.NestedQueryFormatBrackets,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
@@ -13,8 +13,33 @@ import (
|
|||||||
"github.com/sst/opencode-sdk-go/option"
|
"github.com/sst/opencode-sdk-go/option"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestFileRead(t *testing.T) {
|
func TestFileListWithOptionalParams(t *testing.T) {
|
||||||
t.Skip("skipped: tests are disabled for the time being")
|
t.Skip("Prism tests are disabled")
|
||||||
|
baseURL := "http://localhost:4010"
|
||||||
|
if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
|
||||||
|
baseURL = envURL
|
||||||
|
}
|
||||||
|
if !testutil.CheckTestServer(t, baseURL) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
client := opencode.NewClient(
|
||||||
|
option.WithBaseURL(baseURL),
|
||||||
|
)
|
||||||
|
_, err := client.File.List(context.TODO(), opencode.FileListParams{
|
||||||
|
Path: opencode.F("path"),
|
||||||
|
Directory: opencode.F("directory"),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
var apierr *opencode.Error
|
||||||
|
if errors.As(err, &apierr) {
|
||||||
|
t.Log(string(apierr.DumpRequest(true)))
|
||||||
|
}
|
||||||
|
t.Fatalf("err should be nil: %s", err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFileReadWithOptionalParams(t *testing.T) {
|
||||||
|
t.Skip("Prism tests are disabled")
|
||||||
baseURL := "http://localhost:4010"
|
baseURL := "http://localhost:4010"
|
||||||
if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
|
if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
|
||||||
baseURL = envURL
|
baseURL = envURL
|
||||||
@@ -26,7 +51,8 @@ func TestFileRead(t *testing.T) {
|
|||||||
option.WithBaseURL(baseURL),
|
option.WithBaseURL(baseURL),
|
||||||
)
|
)
|
||||||
_, err := client.File.Read(context.TODO(), opencode.FileReadParams{
|
_, err := client.File.Read(context.TODO(), opencode.FileReadParams{
|
||||||
Path: opencode.F("path"),
|
Path: opencode.F("path"),
|
||||||
|
Directory: opencode.F("directory"),
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
var apierr *opencode.Error
|
var apierr *opencode.Error
|
||||||
@@ -37,8 +63,8 @@ func TestFileRead(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestFileStatus(t *testing.T) {
|
func TestFileStatusWithOptionalParams(t *testing.T) {
|
||||||
t.Skip("skipped: tests are disabled for the time being")
|
t.Skip("Prism tests are disabled")
|
||||||
baseURL := "http://localhost:4010"
|
baseURL := "http://localhost:4010"
|
||||||
if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
|
if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
|
||||||
baseURL = envURL
|
baseURL = envURL
|
||||||
@@ -49,7 +75,9 @@ func TestFileStatus(t *testing.T) {
|
|||||||
client := opencode.NewClient(
|
client := opencode.NewClient(
|
||||||
option.WithBaseURL(baseURL),
|
option.WithBaseURL(baseURL),
|
||||||
)
|
)
|
||||||
_, err := client.File.Status(context.TODO())
|
_, err := client.File.Status(context.TODO(), opencode.FileStatusParams{
|
||||||
|
Directory: opencode.F("directory"),
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
var apierr *opencode.Error
|
var apierr *opencode.Error
|
||||||
if errors.As(err, &apierr) {
|
if errors.As(err, &apierr) {
|
||||||
|
|||||||
@@ -290,7 +290,8 @@ func (r findTextResponseSubmatchesMatchJSON) RawJSON() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type FindFilesParams struct {
|
type FindFilesParams struct {
|
||||||
Query param.Field[string] `query:"query,required"`
|
Query param.Field[string] `query:"query,required"`
|
||||||
|
Directory param.Field[string] `query:"directory"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// URLQuery serializes [FindFilesParams]'s query parameters as `url.Values`.
|
// URLQuery serializes [FindFilesParams]'s query parameters as `url.Values`.
|
||||||
@@ -302,7 +303,8 @@ func (r FindFilesParams) URLQuery() (v url.Values) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type FindSymbolsParams struct {
|
type FindSymbolsParams struct {
|
||||||
Query param.Field[string] `query:"query,required"`
|
Query param.Field[string] `query:"query,required"`
|
||||||
|
Directory param.Field[string] `query:"directory"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// URLQuery serializes [FindSymbolsParams]'s query parameters as `url.Values`.
|
// URLQuery serializes [FindSymbolsParams]'s query parameters as `url.Values`.
|
||||||
@@ -314,7 +316,8 @@ func (r FindSymbolsParams) URLQuery() (v url.Values) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type FindTextParams struct {
|
type FindTextParams struct {
|
||||||
Pattern param.Field[string] `query:"pattern,required"`
|
Pattern param.Field[string] `query:"pattern,required"`
|
||||||
|
Directory param.Field[string] `query:"directory"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// URLQuery serializes [FindTextParams]'s query parameters as `url.Values`.
|
// URLQuery serializes [FindTextParams]'s query parameters as `url.Values`.
|
||||||
|
|||||||
@@ -13,8 +13,8 @@ import (
|
|||||||
"github.com/sst/opencode-sdk-go/option"
|
"github.com/sst/opencode-sdk-go/option"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestFindFiles(t *testing.T) {
|
func TestFindFilesWithOptionalParams(t *testing.T) {
|
||||||
t.Skip("skipped: tests are disabled for the time being")
|
t.Skip("Prism tests are disabled")
|
||||||
baseURL := "http://localhost:4010"
|
baseURL := "http://localhost:4010"
|
||||||
if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
|
if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
|
||||||
baseURL = envURL
|
baseURL = envURL
|
||||||
@@ -26,7 +26,8 @@ func TestFindFiles(t *testing.T) {
|
|||||||
option.WithBaseURL(baseURL),
|
option.WithBaseURL(baseURL),
|
||||||
)
|
)
|
||||||
_, err := client.Find.Files(context.TODO(), opencode.FindFilesParams{
|
_, err := client.Find.Files(context.TODO(), opencode.FindFilesParams{
|
||||||
Query: opencode.F("query"),
|
Query: opencode.F("query"),
|
||||||
|
Directory: opencode.F("directory"),
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
var apierr *opencode.Error
|
var apierr *opencode.Error
|
||||||
@@ -37,8 +38,8 @@ func TestFindFiles(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestFindSymbols(t *testing.T) {
|
func TestFindSymbolsWithOptionalParams(t *testing.T) {
|
||||||
t.Skip("skipped: tests are disabled for the time being")
|
t.Skip("Prism tests are disabled")
|
||||||
baseURL := "http://localhost:4010"
|
baseURL := "http://localhost:4010"
|
||||||
if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
|
if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
|
||||||
baseURL = envURL
|
baseURL = envURL
|
||||||
@@ -50,7 +51,8 @@ func TestFindSymbols(t *testing.T) {
|
|||||||
option.WithBaseURL(baseURL),
|
option.WithBaseURL(baseURL),
|
||||||
)
|
)
|
||||||
_, err := client.Find.Symbols(context.TODO(), opencode.FindSymbolsParams{
|
_, err := client.Find.Symbols(context.TODO(), opencode.FindSymbolsParams{
|
||||||
Query: opencode.F("query"),
|
Query: opencode.F("query"),
|
||||||
|
Directory: opencode.F("directory"),
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
var apierr *opencode.Error
|
var apierr *opencode.Error
|
||||||
@@ -61,8 +63,8 @@ func TestFindSymbols(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestFindText(t *testing.T) {
|
func TestFindTextWithOptionalParams(t *testing.T) {
|
||||||
t.Skip("skipped: tests are disabled for the time being")
|
t.Skip("Prism tests are disabled")
|
||||||
baseURL := "http://localhost:4010"
|
baseURL := "http://localhost:4010"
|
||||||
if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
|
if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
|
||||||
baseURL = envURL
|
baseURL = envURL
|
||||||
@@ -74,7 +76,8 @@ func TestFindText(t *testing.T) {
|
|||||||
option.WithBaseURL(baseURL),
|
option.WithBaseURL(baseURL),
|
||||||
)
|
)
|
||||||
_, err := client.Find.Text(context.TODO(), opencode.FindTextParams{
|
_, err := client.Find.Text(context.TODO(), opencode.FindTextParams{
|
||||||
Pattern: opencode.F("pattern"),
|
Pattern: opencode.F("pattern"),
|
||||||
|
Directory: opencode.F("directory"),
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
var apierr *opencode.Error
|
var apierr *opencode.Error
|
||||||
|
|||||||
@@ -464,6 +464,11 @@ func (cfg *RequestConfig) Execute() (err error) {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Close the response body before retrying to prevent connection leaks
|
||||||
|
if res != nil && res.Body != nil {
|
||||||
|
res.Body.Close()
|
||||||
|
}
|
||||||
|
|
||||||
time.Sleep(retryDelay(res, retryCount))
|
time.Sleep(retryDelay(res, retryCount))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,4 +2,4 @@
|
|||||||
|
|
||||||
package internal
|
package internal
|
||||||
|
|
||||||
const PackageVersion = "0.1.0-alpha.8" // x-release-please-version
|
const PackageVersion = "0.8.0" // x-release-please-version
|
||||||
|
|||||||
80
packages/sdk/go/path.go
Normal file
80
packages/sdk/go/path.go
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
|
||||||
|
|
||||||
|
package opencode
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
|
||||||
|
"github.com/sst/opencode-sdk-go/internal/apijson"
|
||||||
|
"github.com/sst/opencode-sdk-go/internal/apiquery"
|
||||||
|
"github.com/sst/opencode-sdk-go/internal/param"
|
||||||
|
"github.com/sst/opencode-sdk-go/internal/requestconfig"
|
||||||
|
"github.com/sst/opencode-sdk-go/option"
|
||||||
|
)
|
||||||
|
|
||||||
|
// PathService contains methods and other services that help with interacting with
|
||||||
|
// the opencode API.
|
||||||
|
//
|
||||||
|
// Note, unlike clients, this service does not read variables from the environment
|
||||||
|
// automatically. You should not instantiate this service directly, and instead use
|
||||||
|
// the [NewPathService] method instead.
|
||||||
|
type PathService struct {
|
||||||
|
Options []option.RequestOption
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewPathService generates a new service that applies the given options to each
|
||||||
|
// request. These options are applied after the parent client's options (if there
|
||||||
|
// is one), and before any request-specific options.
|
||||||
|
func NewPathService(opts ...option.RequestOption) (r *PathService) {
|
||||||
|
r = &PathService{}
|
||||||
|
r.Options = opts
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the current path
|
||||||
|
func (r *PathService) Get(ctx context.Context, query PathGetParams, opts ...option.RequestOption) (res *Path, err error) {
|
||||||
|
opts = append(r.Options[:], opts...)
|
||||||
|
path := "path"
|
||||||
|
err = requestconfig.ExecuteNewRequest(ctx, http.MethodGet, path, query, &res, opts...)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
type Path struct {
|
||||||
|
Config string `json:"config,required"`
|
||||||
|
Directory string `json:"directory,required"`
|
||||||
|
State string `json:"state,required"`
|
||||||
|
Worktree string `json:"worktree,required"`
|
||||||
|
JSON pathJSON `json:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// pathJSON contains the JSON metadata for the struct [Path]
|
||||||
|
type pathJSON struct {
|
||||||
|
Config apijson.Field
|
||||||
|
Directory apijson.Field
|
||||||
|
State apijson.Field
|
||||||
|
Worktree apijson.Field
|
||||||
|
raw string
|
||||||
|
ExtraFields map[string]apijson.Field
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Path) UnmarshalJSON(data []byte) (err error) {
|
||||||
|
return apijson.UnmarshalRoot(data, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r pathJSON) RawJSON() string {
|
||||||
|
return r.raw
|
||||||
|
}
|
||||||
|
|
||||||
|
type PathGetParams struct {
|
||||||
|
Directory param.Field[string] `query:"directory"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// URLQuery serializes [PathGetParams]'s query parameters as `url.Values`.
|
||||||
|
func (r PathGetParams) URLQuery() (v url.Values) {
|
||||||
|
return apiquery.MarshalWithSettings(r, apiquery.QuerySettings{
|
||||||
|
ArrayFormat: apiquery.ArrayQueryFormatComma,
|
||||||
|
NestedFormat: apiquery.NestedQueryFormatBrackets,
|
||||||
|
})
|
||||||
|
}
|
||||||
38
packages/sdk/go/path_test.go
Normal file
38
packages/sdk/go/path_test.go
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
|
||||||
|
|
||||||
|
package opencode_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/sst/opencode-sdk-go"
|
||||||
|
"github.com/sst/opencode-sdk-go/internal/testutil"
|
||||||
|
"github.com/sst/opencode-sdk-go/option"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestPathGetWithOptionalParams(t *testing.T) {
|
||||||
|
t.Skip("Prism tests are disabled")
|
||||||
|
baseURL := "http://localhost:4010"
|
||||||
|
if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
|
||||||
|
baseURL = envURL
|
||||||
|
}
|
||||||
|
if !testutil.CheckTestServer(t, baseURL) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
client := opencode.NewClient(
|
||||||
|
option.WithBaseURL(baseURL),
|
||||||
|
)
|
||||||
|
_, err := client.Path.Get(context.TODO(), opencode.PathGetParams{
|
||||||
|
Directory: opencode.F("directory"),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
var apierr *opencode.Error
|
||||||
|
if errors.As(err, &apierr) {
|
||||||
|
t.Log(string(apierr.DumpRequest(true)))
|
||||||
|
}
|
||||||
|
t.Fatalf("err should be nil: %s", err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
136
packages/sdk/go/project.go
Normal file
136
packages/sdk/go/project.go
Normal file
@@ -0,0 +1,136 @@
|
|||||||
|
// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
|
||||||
|
|
||||||
|
package opencode
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
|
||||||
|
"github.com/sst/opencode-sdk-go/internal/apijson"
|
||||||
|
"github.com/sst/opencode-sdk-go/internal/apiquery"
|
||||||
|
"github.com/sst/opencode-sdk-go/internal/param"
|
||||||
|
"github.com/sst/opencode-sdk-go/internal/requestconfig"
|
||||||
|
"github.com/sst/opencode-sdk-go/option"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ProjectService contains methods and other services that help with interacting
|
||||||
|
// with the opencode API.
|
||||||
|
//
|
||||||
|
// Note, unlike clients, this service does not read variables from the environment
|
||||||
|
// automatically. You should not instantiate this service directly, and instead use
|
||||||
|
// the [NewProjectService] method instead.
|
||||||
|
type ProjectService struct {
|
||||||
|
Options []option.RequestOption
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewProjectService generates a new service that applies the given options to each
|
||||||
|
// request. These options are applied after the parent client's options (if there
|
||||||
|
// is one), and before any request-specific options.
|
||||||
|
func NewProjectService(opts ...option.RequestOption) (r *ProjectService) {
|
||||||
|
r = &ProjectService{}
|
||||||
|
r.Options = opts
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// List all projects
|
||||||
|
func (r *ProjectService) List(ctx context.Context, query ProjectListParams, opts ...option.RequestOption) (res *[]Project, err error) {
|
||||||
|
opts = append(r.Options[:], opts...)
|
||||||
|
path := "project"
|
||||||
|
err = requestconfig.ExecuteNewRequest(ctx, http.MethodGet, path, query, &res, opts...)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the current project
|
||||||
|
func (r *ProjectService) Current(ctx context.Context, query ProjectCurrentParams, opts ...option.RequestOption) (res *Project, err error) {
|
||||||
|
opts = append(r.Options[:], opts...)
|
||||||
|
path := "project/current"
|
||||||
|
err = requestconfig.ExecuteNewRequest(ctx, http.MethodGet, path, query, &res, opts...)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
type Project struct {
|
||||||
|
ID string `json:"id,required"`
|
||||||
|
Time ProjectTime `json:"time,required"`
|
||||||
|
Worktree string `json:"worktree,required"`
|
||||||
|
Vcs ProjectVcs `json:"vcs"`
|
||||||
|
JSON projectJSON `json:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// projectJSON contains the JSON metadata for the struct [Project]
|
||||||
|
type projectJSON struct {
|
||||||
|
ID apijson.Field
|
||||||
|
Time apijson.Field
|
||||||
|
Worktree apijson.Field
|
||||||
|
Vcs apijson.Field
|
||||||
|
raw string
|
||||||
|
ExtraFields map[string]apijson.Field
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Project) UnmarshalJSON(data []byte) (err error) {
|
||||||
|
return apijson.UnmarshalRoot(data, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r projectJSON) RawJSON() string {
|
||||||
|
return r.raw
|
||||||
|
}
|
||||||
|
|
||||||
|
type ProjectTime struct {
|
||||||
|
Created float64 `json:"created,required"`
|
||||||
|
Initialized float64 `json:"initialized"`
|
||||||
|
JSON projectTimeJSON `json:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// projectTimeJSON contains the JSON metadata for the struct [ProjectTime]
|
||||||
|
type projectTimeJSON struct {
|
||||||
|
Created apijson.Field
|
||||||
|
Initialized apijson.Field
|
||||||
|
raw string
|
||||||
|
ExtraFields map[string]apijson.Field
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *ProjectTime) UnmarshalJSON(data []byte) (err error) {
|
||||||
|
return apijson.UnmarshalRoot(data, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r projectTimeJSON) RawJSON() string {
|
||||||
|
return r.raw
|
||||||
|
}
|
||||||
|
|
||||||
|
type ProjectVcs string
|
||||||
|
|
||||||
|
const (
|
||||||
|
ProjectVcsGit ProjectVcs = "git"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (r ProjectVcs) IsKnown() bool {
|
||||||
|
switch r {
|
||||||
|
case ProjectVcsGit:
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
type ProjectListParams struct {
|
||||||
|
Directory param.Field[string] `query:"directory"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// URLQuery serializes [ProjectListParams]'s query parameters as `url.Values`.
|
||||||
|
func (r ProjectListParams) URLQuery() (v url.Values) {
|
||||||
|
return apiquery.MarshalWithSettings(r, apiquery.QuerySettings{
|
||||||
|
ArrayFormat: apiquery.ArrayQueryFormatComma,
|
||||||
|
NestedFormat: apiquery.NestedQueryFormatBrackets,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
type ProjectCurrentParams struct {
|
||||||
|
Directory param.Field[string] `query:"directory"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// URLQuery serializes [ProjectCurrentParams]'s query parameters as `url.Values`.
|
||||||
|
func (r ProjectCurrentParams) URLQuery() (v url.Values) {
|
||||||
|
return apiquery.MarshalWithSettings(r, apiquery.QuerySettings{
|
||||||
|
ArrayFormat: apiquery.ArrayQueryFormatComma,
|
||||||
|
NestedFormat: apiquery.NestedQueryFormatBrackets,
|
||||||
|
})
|
||||||
|
}
|
||||||
62
packages/sdk/go/project_test.go
Normal file
62
packages/sdk/go/project_test.go
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
|
||||||
|
|
||||||
|
package opencode_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/sst/opencode-sdk-go"
|
||||||
|
"github.com/sst/opencode-sdk-go/internal/testutil"
|
||||||
|
"github.com/sst/opencode-sdk-go/option"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestProjectListWithOptionalParams(t *testing.T) {
|
||||||
|
t.Skip("Prism tests are disabled")
|
||||||
|
baseURL := "http://localhost:4010"
|
||||||
|
if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
|
||||||
|
baseURL = envURL
|
||||||
|
}
|
||||||
|
if !testutil.CheckTestServer(t, baseURL) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
client := opencode.NewClient(
|
||||||
|
option.WithBaseURL(baseURL),
|
||||||
|
)
|
||||||
|
_, err := client.Project.List(context.TODO(), opencode.ProjectListParams{
|
||||||
|
Directory: opencode.F("directory"),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
var apierr *opencode.Error
|
||||||
|
if errors.As(err, &apierr) {
|
||||||
|
t.Log(string(apierr.DumpRequest(true)))
|
||||||
|
}
|
||||||
|
t.Fatalf("err should be nil: %s", err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestProjectCurrentWithOptionalParams(t *testing.T) {
|
||||||
|
t.Skip("Prism tests are disabled")
|
||||||
|
baseURL := "http://localhost:4010"
|
||||||
|
if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
|
||||||
|
baseURL = envURL
|
||||||
|
}
|
||||||
|
if !testutil.CheckTestServer(t, baseURL) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
client := opencode.NewClient(
|
||||||
|
option.WithBaseURL(baseURL),
|
||||||
|
)
|
||||||
|
_, err := client.Project.Current(context.TODO(), opencode.ProjectCurrentParams{
|
||||||
|
Directory: opencode.F("directory"),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
var apierr *opencode.Error
|
||||||
|
if errors.As(err, &apierr) {
|
||||||
|
t.Log(string(apierr.DumpRequest(true)))
|
||||||
|
}
|
||||||
|
t.Fatalf("err should be nil: %s", err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,9 +7,11 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/url"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
|
||||||
"github.com/sst/opencode-sdk-go/internal/apijson"
|
"github.com/sst/opencode-sdk-go/internal/apijson"
|
||||||
|
"github.com/sst/opencode-sdk-go/internal/apiquery"
|
||||||
"github.com/sst/opencode-sdk-go/internal/param"
|
"github.com/sst/opencode-sdk-go/internal/param"
|
||||||
"github.com/sst/opencode-sdk-go/internal/requestconfig"
|
"github.com/sst/opencode-sdk-go/internal/requestconfig"
|
||||||
"github.com/sst/opencode-sdk-go/option"
|
"github.com/sst/opencode-sdk-go/option"
|
||||||
@@ -39,119 +41,107 @@ func NewSessionService(opts ...option.RequestOption) (r *SessionService) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create a new session
|
// Create a new session
|
||||||
func (r *SessionService) New(ctx context.Context, body SessionNewParams, opts ...option.RequestOption) (res *Session, err error) {
|
func (r *SessionService) New(ctx context.Context, params SessionNewParams, opts ...option.RequestOption) (res *Session, err error) {
|
||||||
opts = append(r.Options[:], opts...)
|
opts = append(r.Options[:], opts...)
|
||||||
path := "session"
|
path := "session"
|
||||||
err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, body, &res, opts...)
|
err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, params, &res, opts...)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update session properties
|
// Update session properties
|
||||||
func (r *SessionService) Update(ctx context.Context, id string, body SessionUpdateParams, opts ...option.RequestOption) (res *Session, err error) {
|
func (r *SessionService) Update(ctx context.Context, id string, params SessionUpdateParams, opts ...option.RequestOption) (res *Session, err error) {
|
||||||
opts = append(r.Options[:], opts...)
|
opts = append(r.Options[:], opts...)
|
||||||
if id == "" {
|
if id == "" {
|
||||||
err = errors.New("missing required id parameter")
|
err = errors.New("missing required id parameter")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
path := fmt.Sprintf("session/%s", id)
|
path := fmt.Sprintf("session/%s", id)
|
||||||
err = requestconfig.ExecuteNewRequest(ctx, http.MethodPatch, path, body, &res, opts...)
|
err = requestconfig.ExecuteNewRequest(ctx, http.MethodPatch, path, params, &res, opts...)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// List all sessions
|
// List all sessions
|
||||||
func (r *SessionService) List(ctx context.Context, opts ...option.RequestOption) (res *[]Session, err error) {
|
func (r *SessionService) List(ctx context.Context, query SessionListParams, opts ...option.RequestOption) (res *[]Session, err error) {
|
||||||
opts = append(r.Options[:], opts...)
|
opts = append(r.Options[:], opts...)
|
||||||
path := "session"
|
path := "session"
|
||||||
err = requestconfig.ExecuteNewRequest(ctx, http.MethodGet, path, nil, &res, opts...)
|
err = requestconfig.ExecuteNewRequest(ctx, http.MethodGet, path, query, &res, opts...)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete a session and all its data
|
// Delete a session and all its data
|
||||||
func (r *SessionService) Delete(ctx context.Context, id string, opts ...option.RequestOption) (res *bool, err error) {
|
func (r *SessionService) Delete(ctx context.Context, id string, body SessionDeleteParams, opts ...option.RequestOption) (res *bool, err error) {
|
||||||
opts = append(r.Options[:], opts...)
|
opts = append(r.Options[:], opts...)
|
||||||
if id == "" {
|
if id == "" {
|
||||||
err = errors.New("missing required id parameter")
|
err = errors.New("missing required id parameter")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
path := fmt.Sprintf("session/%s", id)
|
path := fmt.Sprintf("session/%s", id)
|
||||||
err = requestconfig.ExecuteNewRequest(ctx, http.MethodDelete, path, nil, &res, opts...)
|
err = requestconfig.ExecuteNewRequest(ctx, http.MethodDelete, path, body, &res, opts...)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Abort a session
|
// Abort a session
|
||||||
func (r *SessionService) Abort(ctx context.Context, id string, opts ...option.RequestOption) (res *bool, err error) {
|
func (r *SessionService) Abort(ctx context.Context, id string, body SessionAbortParams, opts ...option.RequestOption) (res *bool, err error) {
|
||||||
opts = append(r.Options[:], opts...)
|
opts = append(r.Options[:], opts...)
|
||||||
if id == "" {
|
if id == "" {
|
||||||
err = errors.New("missing required id parameter")
|
err = errors.New("missing required id parameter")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
path := fmt.Sprintf("session/%s/abort", id)
|
path := fmt.Sprintf("session/%s/abort", id)
|
||||||
err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, nil, &res, opts...)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create and send a new message to a session
|
|
||||||
func (r *SessionService) Chat(ctx context.Context, id string, body SessionChatParams, opts ...option.RequestOption) (res *SessionChatResponse, err error) {
|
|
||||||
opts = append(r.Options[:], opts...)
|
|
||||||
if id == "" {
|
|
||||||
err = errors.New("missing required id parameter")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
path := fmt.Sprintf("session/%s/message", id)
|
|
||||||
err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, body, &res, opts...)
|
err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, body, &res, opts...)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get a session's children
|
// Get a session's children
|
||||||
func (r *SessionService) Children(ctx context.Context, id string, opts ...option.RequestOption) (res *[]Session, err error) {
|
func (r *SessionService) Children(ctx context.Context, id string, query SessionChildrenParams, opts ...option.RequestOption) (res *[]Session, err error) {
|
||||||
opts = append(r.Options[:], opts...)
|
opts = append(r.Options[:], opts...)
|
||||||
if id == "" {
|
if id == "" {
|
||||||
err = errors.New("missing required id parameter")
|
err = errors.New("missing required id parameter")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
path := fmt.Sprintf("session/%s/children", id)
|
path := fmt.Sprintf("session/%s/children", id)
|
||||||
err = requestconfig.ExecuteNewRequest(ctx, http.MethodGet, path, nil, &res, opts...)
|
err = requestconfig.ExecuteNewRequest(ctx, http.MethodGet, path, query, &res, opts...)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send a new command to a session
|
// Send a new command to a session
|
||||||
func (r *SessionService) Command(ctx context.Context, id string, body SessionCommandParams, opts ...option.RequestOption) (res *SessionCommandResponse, err error) {
|
func (r *SessionService) Command(ctx context.Context, id string, params SessionCommandParams, opts ...option.RequestOption) (res *SessionCommandResponse, err error) {
|
||||||
opts = append(r.Options[:], opts...)
|
opts = append(r.Options[:], opts...)
|
||||||
if id == "" {
|
if id == "" {
|
||||||
err = errors.New("missing required id parameter")
|
err = errors.New("missing required id parameter")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
path := fmt.Sprintf("session/%s/command", id)
|
path := fmt.Sprintf("session/%s/command", id)
|
||||||
err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, body, &res, opts...)
|
err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, params, &res, opts...)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get session
|
// Get session
|
||||||
func (r *SessionService) Get(ctx context.Context, id string, opts ...option.RequestOption) (res *Session, err error) {
|
func (r *SessionService) Get(ctx context.Context, id string, query SessionGetParams, opts ...option.RequestOption) (res *Session, err error) {
|
||||||
opts = append(r.Options[:], opts...)
|
opts = append(r.Options[:], opts...)
|
||||||
if id == "" {
|
if id == "" {
|
||||||
err = errors.New("missing required id parameter")
|
err = errors.New("missing required id parameter")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
path := fmt.Sprintf("session/%s", id)
|
path := fmt.Sprintf("session/%s", id)
|
||||||
err = requestconfig.ExecuteNewRequest(ctx, http.MethodGet, path, nil, &res, opts...)
|
err = requestconfig.ExecuteNewRequest(ctx, http.MethodGet, path, query, &res, opts...)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Analyze the app and create an AGENTS.md file
|
// Analyze the app and create an AGENTS.md file
|
||||||
func (r *SessionService) Init(ctx context.Context, id string, body SessionInitParams, opts ...option.RequestOption) (res *bool, err error) {
|
func (r *SessionService) Init(ctx context.Context, id string, params SessionInitParams, opts ...option.RequestOption) (res *bool, err error) {
|
||||||
opts = append(r.Options[:], opts...)
|
opts = append(r.Options[:], opts...)
|
||||||
if id == "" {
|
if id == "" {
|
||||||
err = errors.New("missing required id parameter")
|
err = errors.New("missing required id parameter")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
path := fmt.Sprintf("session/%s/init", id)
|
path := fmt.Sprintf("session/%s/init", id)
|
||||||
err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, body, &res, opts...)
|
err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, params, &res, opts...)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get a message from a session
|
// Get a message from a session
|
||||||
func (r *SessionService) Message(ctx context.Context, id string, messageID string, opts ...option.RequestOption) (res *SessionMessageResponse, err error) {
|
func (r *SessionService) Message(ctx context.Context, id string, messageID string, query SessionMessageParams, opts ...option.RequestOption) (res *SessionMessageResponse, err error) {
|
||||||
opts = append(r.Options[:], opts...)
|
opts = append(r.Options[:], opts...)
|
||||||
if id == "" {
|
if id == "" {
|
||||||
err = errors.New("missing required id parameter")
|
err = errors.New("missing required id parameter")
|
||||||
@@ -162,91 +152,103 @@ func (r *SessionService) Message(ctx context.Context, id string, messageID strin
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
path := fmt.Sprintf("session/%s/message/%s", id, messageID)
|
path := fmt.Sprintf("session/%s/message/%s", id, messageID)
|
||||||
err = requestconfig.ExecuteNewRequest(ctx, http.MethodGet, path, nil, &res, opts...)
|
err = requestconfig.ExecuteNewRequest(ctx, http.MethodGet, path, query, &res, opts...)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// List messages for a session
|
// List messages for a session
|
||||||
func (r *SessionService) Messages(ctx context.Context, id string, opts ...option.RequestOption) (res *[]SessionMessagesResponse, err error) {
|
func (r *SessionService) Messages(ctx context.Context, id string, query SessionMessagesParams, opts ...option.RequestOption) (res *[]SessionMessagesResponse, err error) {
|
||||||
opts = append(r.Options[:], opts...)
|
opts = append(r.Options[:], opts...)
|
||||||
if id == "" {
|
if id == "" {
|
||||||
err = errors.New("missing required id parameter")
|
err = errors.New("missing required id parameter")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
path := fmt.Sprintf("session/%s/message", id)
|
path := fmt.Sprintf("session/%s/message", id)
|
||||||
err = requestconfig.ExecuteNewRequest(ctx, http.MethodGet, path, nil, &res, opts...)
|
err = requestconfig.ExecuteNewRequest(ctx, http.MethodGet, path, query, &res, opts...)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create and send a new message to a session
|
||||||
|
func (r *SessionService) Prompt(ctx context.Context, id string, params SessionPromptParams, opts ...option.RequestOption) (res *SessionPromptResponse, err error) {
|
||||||
|
opts = append(r.Options[:], opts...)
|
||||||
|
if id == "" {
|
||||||
|
err = errors.New("missing required id parameter")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
path := fmt.Sprintf("session/%s/message", id)
|
||||||
|
err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, params, &res, opts...)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Revert a message
|
// Revert a message
|
||||||
func (r *SessionService) Revert(ctx context.Context, id string, body SessionRevertParams, opts ...option.RequestOption) (res *Session, err error) {
|
func (r *SessionService) Revert(ctx context.Context, id string, params SessionRevertParams, opts ...option.RequestOption) (res *Session, err error) {
|
||||||
opts = append(r.Options[:], opts...)
|
opts = append(r.Options[:], opts...)
|
||||||
if id == "" {
|
if id == "" {
|
||||||
err = errors.New("missing required id parameter")
|
err = errors.New("missing required id parameter")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
path := fmt.Sprintf("session/%s/revert", id)
|
path := fmt.Sprintf("session/%s/revert", id)
|
||||||
err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, body, &res, opts...)
|
err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, params, &res, opts...)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Share a session
|
// Share a session
|
||||||
func (r *SessionService) Share(ctx context.Context, id string, opts ...option.RequestOption) (res *Session, err error) {
|
func (r *SessionService) Share(ctx context.Context, id string, body SessionShareParams, opts ...option.RequestOption) (res *Session, err error) {
|
||||||
opts = append(r.Options[:], opts...)
|
opts = append(r.Options[:], opts...)
|
||||||
if id == "" {
|
if id == "" {
|
||||||
err = errors.New("missing required id parameter")
|
err = errors.New("missing required id parameter")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
path := fmt.Sprintf("session/%s/share", id)
|
path := fmt.Sprintf("session/%s/share", id)
|
||||||
err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, nil, &res, opts...)
|
err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, body, &res, opts...)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run a shell command
|
// Run a shell command
|
||||||
func (r *SessionService) Shell(ctx context.Context, id string, body SessionShellParams, opts ...option.RequestOption) (res *AssistantMessage, err error) {
|
func (r *SessionService) Shell(ctx context.Context, id string, params SessionShellParams, opts ...option.RequestOption) (res *AssistantMessage, err error) {
|
||||||
opts = append(r.Options[:], opts...)
|
opts = append(r.Options[:], opts...)
|
||||||
if id == "" {
|
if id == "" {
|
||||||
err = errors.New("missing required id parameter")
|
err = errors.New("missing required id parameter")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
path := fmt.Sprintf("session/%s/shell", id)
|
path := fmt.Sprintf("session/%s/shell", id)
|
||||||
err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, body, &res, opts...)
|
err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, params, &res, opts...)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Summarize the session
|
// Summarize the session
|
||||||
func (r *SessionService) Summarize(ctx context.Context, id string, body SessionSummarizeParams, opts ...option.RequestOption) (res *bool, err error) {
|
func (r *SessionService) Summarize(ctx context.Context, id string, params SessionSummarizeParams, opts ...option.RequestOption) (res *bool, err error) {
|
||||||
opts = append(r.Options[:], opts...)
|
opts = append(r.Options[:], opts...)
|
||||||
if id == "" {
|
if id == "" {
|
||||||
err = errors.New("missing required id parameter")
|
err = errors.New("missing required id parameter")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
path := fmt.Sprintf("session/%s/summarize", id)
|
path := fmt.Sprintf("session/%s/summarize", id)
|
||||||
err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, body, &res, opts...)
|
err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, params, &res, opts...)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Restore all reverted messages
|
// Restore all reverted messages
|
||||||
func (r *SessionService) Unrevert(ctx context.Context, id string, opts ...option.RequestOption) (res *Session, err error) {
|
func (r *SessionService) Unrevert(ctx context.Context, id string, body SessionUnrevertParams, opts ...option.RequestOption) (res *Session, err error) {
|
||||||
opts = append(r.Options[:], opts...)
|
opts = append(r.Options[:], opts...)
|
||||||
if id == "" {
|
if id == "" {
|
||||||
err = errors.New("missing required id parameter")
|
err = errors.New("missing required id parameter")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
path := fmt.Sprintf("session/%s/unrevert", id)
|
path := fmt.Sprintf("session/%s/unrevert", id)
|
||||||
err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, nil, &res, opts...)
|
err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, body, &res, opts...)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unshare the session
|
// Unshare the session
|
||||||
func (r *SessionService) Unshare(ctx context.Context, id string, opts ...option.RequestOption) (res *Session, err error) {
|
func (r *SessionService) Unshare(ctx context.Context, id string, body SessionUnshareParams, opts ...option.RequestOption) (res *Session, err error) {
|
||||||
opts = append(r.Options[:], opts...)
|
opts = append(r.Options[:], opts...)
|
||||||
if id == "" {
|
if id == "" {
|
||||||
err = errors.New("missing required id parameter")
|
err = errors.New("missing required id parameter")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
path := fmt.Sprintf("session/%s/share", id)
|
path := fmt.Sprintf("session/%s/share", id)
|
||||||
err = requestconfig.ExecuteNewRequest(ctx, http.MethodDelete, path, nil, &res, opts...)
|
err = requestconfig.ExecuteNewRequest(ctx, http.MethodDelete, path, body, &res, opts...)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -331,7 +333,7 @@ func (r AgentPartInputParam) MarshalJSON() (data []byte, err error) {
|
|||||||
return apijson.MarshalRoot(r)
|
return apijson.MarshalRoot(r)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r AgentPartInputParam) implementsSessionChatParamsPartUnion() {}
|
func (r AgentPartInputParam) implementsSessionPromptParamsPartUnion() {}
|
||||||
|
|
||||||
type AgentPartInputType string
|
type AgentPartInputType string
|
||||||
|
|
||||||
@@ -707,7 +709,7 @@ func (r FilePartInputParam) MarshalJSON() (data []byte, err error) {
|
|||||||
return apijson.MarshalRoot(r)
|
return apijson.MarshalRoot(r)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r FilePartInputParam) implementsSessionChatParamsPartUnion() {}
|
func (r FilePartInputParam) implementsSessionPromptParamsPartUnion() {}
|
||||||
|
|
||||||
type FilePartInputType string
|
type FilePartInputType string
|
||||||
|
|
||||||
@@ -1294,19 +1296,23 @@ func (r ReasoningPartType) IsKnown() bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Session struct {
|
type Session struct {
|
||||||
ID string `json:"id,required"`
|
ID string `json:"id,required"`
|
||||||
Time SessionTime `json:"time,required"`
|
Directory string `json:"directory,required"`
|
||||||
Title string `json:"title,required"`
|
ProjectID string `json:"projectID,required"`
|
||||||
Version string `json:"version,required"`
|
Time SessionTime `json:"time,required"`
|
||||||
ParentID string `json:"parentID"`
|
Title string `json:"title,required"`
|
||||||
Revert SessionRevert `json:"revert"`
|
Version string `json:"version,required"`
|
||||||
Share SessionShare `json:"share"`
|
ParentID string `json:"parentID"`
|
||||||
JSON sessionJSON `json:"-"`
|
Revert SessionRevert `json:"revert"`
|
||||||
|
Share SessionShare `json:"share"`
|
||||||
|
JSON sessionJSON `json:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// sessionJSON contains the JSON metadata for the struct [Session]
|
// sessionJSON contains the JSON metadata for the struct [Session]
|
||||||
type sessionJSON struct {
|
type sessionJSON struct {
|
||||||
ID apijson.Field
|
ID apijson.Field
|
||||||
|
Directory apijson.Field
|
||||||
|
ProjectID apijson.Field
|
||||||
Time apijson.Field
|
Time apijson.Field
|
||||||
Title apijson.Field
|
Title apijson.Field
|
||||||
Version apijson.Field
|
Version apijson.Field
|
||||||
@@ -1814,7 +1820,7 @@ func (r TextPartInputParam) MarshalJSON() (data []byte, err error) {
|
|||||||
return apijson.MarshalRoot(r)
|
return apijson.MarshalRoot(r)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r TextPartInputParam) implementsSessionChatParamsPartUnion() {}
|
func (r TextPartInputParam) implementsSessionPromptParamsPartUnion() {}
|
||||||
|
|
||||||
type TextPartInputType string
|
type TextPartInputType string
|
||||||
|
|
||||||
@@ -2290,29 +2296,6 @@ func (r userMessageTimeJSON) RawJSON() string {
|
|||||||
return r.raw
|
return r.raw
|
||||||
}
|
}
|
||||||
|
|
||||||
type SessionChatResponse struct {
|
|
||||||
Info AssistantMessage `json:"info,required"`
|
|
||||||
Parts []Part `json:"parts,required"`
|
|
||||||
JSON sessionChatResponseJSON `json:"-"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// sessionChatResponseJSON contains the JSON metadata for the struct
|
|
||||||
// [SessionChatResponse]
|
|
||||||
type sessionChatResponseJSON struct {
|
|
||||||
Info apijson.Field
|
|
||||||
Parts apijson.Field
|
|
||||||
raw string
|
|
||||||
ExtraFields map[string]apijson.Field
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *SessionChatResponse) UnmarshalJSON(data []byte) (err error) {
|
|
||||||
return apijson.UnmarshalRoot(data, r)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r sessionChatResponseJSON) RawJSON() string {
|
|
||||||
return r.raw
|
|
||||||
}
|
|
||||||
|
|
||||||
type SessionCommandResponse struct {
|
type SessionCommandResponse struct {
|
||||||
Info AssistantMessage `json:"info,required"`
|
Info AssistantMessage `json:"info,required"`
|
||||||
Parts []Part `json:"parts,required"`
|
Parts []Part `json:"parts,required"`
|
||||||
@@ -2382,81 +2365,116 @@ func (r sessionMessagesResponseJSON) RawJSON() string {
|
|||||||
return r.raw
|
return r.raw
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type SessionPromptResponse struct {
|
||||||
|
Info AssistantMessage `json:"info,required"`
|
||||||
|
Parts []Part `json:"parts,required"`
|
||||||
|
JSON sessionPromptResponseJSON `json:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// sessionPromptResponseJSON contains the JSON metadata for the struct
|
||||||
|
// [SessionPromptResponse]
|
||||||
|
type sessionPromptResponseJSON struct {
|
||||||
|
Info apijson.Field
|
||||||
|
Parts apijson.Field
|
||||||
|
raw string
|
||||||
|
ExtraFields map[string]apijson.Field
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *SessionPromptResponse) UnmarshalJSON(data []byte) (err error) {
|
||||||
|
return apijson.UnmarshalRoot(data, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r sessionPromptResponseJSON) RawJSON() string {
|
||||||
|
return r.raw
|
||||||
|
}
|
||||||
|
|
||||||
type SessionNewParams struct {
|
type SessionNewParams struct {
|
||||||
ParentID param.Field[string] `json:"parentID"`
|
Directory param.Field[string] `query:"directory"`
|
||||||
Title param.Field[string] `json:"title"`
|
ParentID param.Field[string] `json:"parentID"`
|
||||||
|
Title param.Field[string] `json:"title"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r SessionNewParams) MarshalJSON() (data []byte, err error) {
|
func (r SessionNewParams) MarshalJSON() (data []byte, err error) {
|
||||||
return apijson.MarshalRoot(r)
|
return apijson.MarshalRoot(r)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// URLQuery serializes [SessionNewParams]'s query parameters as `url.Values`.
|
||||||
|
func (r SessionNewParams) URLQuery() (v url.Values) {
|
||||||
|
return apiquery.MarshalWithSettings(r, apiquery.QuerySettings{
|
||||||
|
ArrayFormat: apiquery.ArrayQueryFormatComma,
|
||||||
|
NestedFormat: apiquery.NestedQueryFormatBrackets,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
type SessionUpdateParams struct {
|
type SessionUpdateParams struct {
|
||||||
Title param.Field[string] `json:"title"`
|
Directory param.Field[string] `query:"directory"`
|
||||||
|
Title param.Field[string] `json:"title"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r SessionUpdateParams) MarshalJSON() (data []byte, err error) {
|
func (r SessionUpdateParams) MarshalJSON() (data []byte, err error) {
|
||||||
return apijson.MarshalRoot(r)
|
return apijson.MarshalRoot(r)
|
||||||
}
|
}
|
||||||
|
|
||||||
type SessionChatParams struct {
|
// URLQuery serializes [SessionUpdateParams]'s query parameters as `url.Values`.
|
||||||
ModelID param.Field[string] `json:"modelID,required"`
|
func (r SessionUpdateParams) URLQuery() (v url.Values) {
|
||||||
Parts param.Field[[]SessionChatParamsPartUnion] `json:"parts,required"`
|
return apiquery.MarshalWithSettings(r, apiquery.QuerySettings{
|
||||||
ProviderID param.Field[string] `json:"providerID,required"`
|
ArrayFormat: apiquery.ArrayQueryFormatComma,
|
||||||
Agent param.Field[string] `json:"agent"`
|
NestedFormat: apiquery.NestedQueryFormatBrackets,
|
||||||
MessageID param.Field[string] `json:"messageID"`
|
})
|
||||||
System param.Field[string] `json:"system"`
|
|
||||||
Tools param.Field[map[string]bool] `json:"tools"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r SessionChatParams) MarshalJSON() (data []byte, err error) {
|
type SessionListParams struct {
|
||||||
return apijson.MarshalRoot(r)
|
Directory param.Field[string] `query:"directory"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type SessionChatParamsPart struct {
|
// URLQuery serializes [SessionListParams]'s query parameters as `url.Values`.
|
||||||
Type param.Field[SessionChatParamsPartsType] `json:"type,required"`
|
func (r SessionListParams) URLQuery() (v url.Values) {
|
||||||
ID param.Field[string] `json:"id"`
|
return apiquery.MarshalWithSettings(r, apiquery.QuerySettings{
|
||||||
Filename param.Field[string] `json:"filename"`
|
ArrayFormat: apiquery.ArrayQueryFormatComma,
|
||||||
Mime param.Field[string] `json:"mime"`
|
NestedFormat: apiquery.NestedQueryFormatBrackets,
|
||||||
Name param.Field[string] `json:"name"`
|
})
|
||||||
Source param.Field[interface{}] `json:"source"`
|
|
||||||
Synthetic param.Field[bool] `json:"synthetic"`
|
|
||||||
Text param.Field[string] `json:"text"`
|
|
||||||
Time param.Field[interface{}] `json:"time"`
|
|
||||||
URL param.Field[string] `json:"url"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r SessionChatParamsPart) MarshalJSON() (data []byte, err error) {
|
type SessionDeleteParams struct {
|
||||||
return apijson.MarshalRoot(r)
|
Directory param.Field[string] `query:"directory"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r SessionChatParamsPart) implementsSessionChatParamsPartUnion() {}
|
// URLQuery serializes [SessionDeleteParams]'s query parameters as `url.Values`.
|
||||||
|
func (r SessionDeleteParams) URLQuery() (v url.Values) {
|
||||||
// Satisfied by [TextPartInputParam], [FilePartInputParam], [AgentPartInputParam],
|
return apiquery.MarshalWithSettings(r, apiquery.QuerySettings{
|
||||||
// [SessionChatParamsPart].
|
ArrayFormat: apiquery.ArrayQueryFormatComma,
|
||||||
type SessionChatParamsPartUnion interface {
|
NestedFormat: apiquery.NestedQueryFormatBrackets,
|
||||||
implementsSessionChatParamsPartUnion()
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
type SessionChatParamsPartsType string
|
type SessionAbortParams struct {
|
||||||
|
Directory param.Field[string] `query:"directory"`
|
||||||
|
}
|
||||||
|
|
||||||
const (
|
// URLQuery serializes [SessionAbortParams]'s query parameters as `url.Values`.
|
||||||
SessionChatParamsPartsTypeText SessionChatParamsPartsType = "text"
|
func (r SessionAbortParams) URLQuery() (v url.Values) {
|
||||||
SessionChatParamsPartsTypeFile SessionChatParamsPartsType = "file"
|
return apiquery.MarshalWithSettings(r, apiquery.QuerySettings{
|
||||||
SessionChatParamsPartsTypeAgent SessionChatParamsPartsType = "agent"
|
ArrayFormat: apiquery.ArrayQueryFormatComma,
|
||||||
)
|
NestedFormat: apiquery.NestedQueryFormatBrackets,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func (r SessionChatParamsPartsType) IsKnown() bool {
|
type SessionChildrenParams struct {
|
||||||
switch r {
|
Directory param.Field[string] `query:"directory"`
|
||||||
case SessionChatParamsPartsTypeText, SessionChatParamsPartsTypeFile, SessionChatParamsPartsTypeAgent:
|
}
|
||||||
return true
|
|
||||||
}
|
// URLQuery serializes [SessionChildrenParams]'s query parameters as `url.Values`.
|
||||||
return false
|
func (r SessionChildrenParams) URLQuery() (v url.Values) {
|
||||||
|
return apiquery.MarshalWithSettings(r, apiquery.QuerySettings{
|
||||||
|
ArrayFormat: apiquery.ArrayQueryFormatComma,
|
||||||
|
NestedFormat: apiquery.NestedQueryFormatBrackets,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
type SessionCommandParams struct {
|
type SessionCommandParams struct {
|
||||||
Arguments param.Field[string] `json:"arguments,required"`
|
Arguments param.Field[string] `json:"arguments,required"`
|
||||||
Command param.Field[string] `json:"command,required"`
|
Command param.Field[string] `json:"command,required"`
|
||||||
|
Directory param.Field[string] `query:"directory"`
|
||||||
Agent param.Field[string] `json:"agent"`
|
Agent param.Field[string] `json:"agent"`
|
||||||
MessageID param.Field[string] `json:"messageID"`
|
MessageID param.Field[string] `json:"messageID"`
|
||||||
Model param.Field[string] `json:"model"`
|
Model param.Field[string] `json:"model"`
|
||||||
@@ -2466,18 +2484,144 @@ func (r SessionCommandParams) MarshalJSON() (data []byte, err error) {
|
|||||||
return apijson.MarshalRoot(r)
|
return apijson.MarshalRoot(r)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// URLQuery serializes [SessionCommandParams]'s query parameters as `url.Values`.
|
||||||
|
func (r SessionCommandParams) URLQuery() (v url.Values) {
|
||||||
|
return apiquery.MarshalWithSettings(r, apiquery.QuerySettings{
|
||||||
|
ArrayFormat: apiquery.ArrayQueryFormatComma,
|
||||||
|
NestedFormat: apiquery.NestedQueryFormatBrackets,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
type SessionGetParams struct {
|
||||||
|
Directory param.Field[string] `query:"directory"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// URLQuery serializes [SessionGetParams]'s query parameters as `url.Values`.
|
||||||
|
func (r SessionGetParams) URLQuery() (v url.Values) {
|
||||||
|
return apiquery.MarshalWithSettings(r, apiquery.QuerySettings{
|
||||||
|
ArrayFormat: apiquery.ArrayQueryFormatComma,
|
||||||
|
NestedFormat: apiquery.NestedQueryFormatBrackets,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
type SessionInitParams struct {
|
type SessionInitParams struct {
|
||||||
MessageID param.Field[string] `json:"messageID,required"`
|
MessageID param.Field[string] `json:"messageID,required"`
|
||||||
ModelID param.Field[string] `json:"modelID,required"`
|
ModelID param.Field[string] `json:"modelID,required"`
|
||||||
ProviderID param.Field[string] `json:"providerID,required"`
|
ProviderID param.Field[string] `json:"providerID,required"`
|
||||||
|
Directory param.Field[string] `query:"directory"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r SessionInitParams) MarshalJSON() (data []byte, err error) {
|
func (r SessionInitParams) MarshalJSON() (data []byte, err error) {
|
||||||
return apijson.MarshalRoot(r)
|
return apijson.MarshalRoot(r)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// URLQuery serializes [SessionInitParams]'s query parameters as `url.Values`.
|
||||||
|
func (r SessionInitParams) URLQuery() (v url.Values) {
|
||||||
|
return apiquery.MarshalWithSettings(r, apiquery.QuerySettings{
|
||||||
|
ArrayFormat: apiquery.ArrayQueryFormatComma,
|
||||||
|
NestedFormat: apiquery.NestedQueryFormatBrackets,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
type SessionMessageParams struct {
|
||||||
|
Directory param.Field[string] `query:"directory"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// URLQuery serializes [SessionMessageParams]'s query parameters as `url.Values`.
|
||||||
|
func (r SessionMessageParams) URLQuery() (v url.Values) {
|
||||||
|
return apiquery.MarshalWithSettings(r, apiquery.QuerySettings{
|
||||||
|
ArrayFormat: apiquery.ArrayQueryFormatComma,
|
||||||
|
NestedFormat: apiquery.NestedQueryFormatBrackets,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
type SessionMessagesParams struct {
|
||||||
|
Directory param.Field[string] `query:"directory"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// URLQuery serializes [SessionMessagesParams]'s query parameters as `url.Values`.
|
||||||
|
func (r SessionMessagesParams) URLQuery() (v url.Values) {
|
||||||
|
return apiquery.MarshalWithSettings(r, apiquery.QuerySettings{
|
||||||
|
ArrayFormat: apiquery.ArrayQueryFormatComma,
|
||||||
|
NestedFormat: apiquery.NestedQueryFormatBrackets,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
type SessionPromptParams struct {
|
||||||
|
Parts param.Field[[]SessionPromptParamsPartUnion] `json:"parts,required"`
|
||||||
|
Directory param.Field[string] `query:"directory"`
|
||||||
|
Agent param.Field[string] `json:"agent"`
|
||||||
|
MessageID param.Field[string] `json:"messageID"`
|
||||||
|
Model param.Field[SessionPromptParamsModel] `json:"model"`
|
||||||
|
System param.Field[string] `json:"system"`
|
||||||
|
Tools param.Field[map[string]bool] `json:"tools"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r SessionPromptParams) MarshalJSON() (data []byte, err error) {
|
||||||
|
return apijson.MarshalRoot(r)
|
||||||
|
}
|
||||||
|
|
||||||
|
// URLQuery serializes [SessionPromptParams]'s query parameters as `url.Values`.
|
||||||
|
func (r SessionPromptParams) URLQuery() (v url.Values) {
|
||||||
|
return apiquery.MarshalWithSettings(r, apiquery.QuerySettings{
|
||||||
|
ArrayFormat: apiquery.ArrayQueryFormatComma,
|
||||||
|
NestedFormat: apiquery.NestedQueryFormatBrackets,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
type SessionPromptParamsPart struct {
|
||||||
|
Type param.Field[SessionPromptParamsPartsType] `json:"type,required"`
|
||||||
|
ID param.Field[string] `json:"id"`
|
||||||
|
Filename param.Field[string] `json:"filename"`
|
||||||
|
Mime param.Field[string] `json:"mime"`
|
||||||
|
Name param.Field[string] `json:"name"`
|
||||||
|
Source param.Field[interface{}] `json:"source"`
|
||||||
|
Synthetic param.Field[bool] `json:"synthetic"`
|
||||||
|
Text param.Field[string] `json:"text"`
|
||||||
|
Time param.Field[interface{}] `json:"time"`
|
||||||
|
URL param.Field[string] `json:"url"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r SessionPromptParamsPart) MarshalJSON() (data []byte, err error) {
|
||||||
|
return apijson.MarshalRoot(r)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r SessionPromptParamsPart) implementsSessionPromptParamsPartUnion() {}
|
||||||
|
|
||||||
|
// Satisfied by [TextPartInputParam], [FilePartInputParam], [AgentPartInputParam],
|
||||||
|
// [SessionPromptParamsPart].
|
||||||
|
type SessionPromptParamsPartUnion interface {
|
||||||
|
implementsSessionPromptParamsPartUnion()
|
||||||
|
}
|
||||||
|
|
||||||
|
type SessionPromptParamsPartsType string
|
||||||
|
|
||||||
|
const (
|
||||||
|
SessionPromptParamsPartsTypeText SessionPromptParamsPartsType = "text"
|
||||||
|
SessionPromptParamsPartsTypeFile SessionPromptParamsPartsType = "file"
|
||||||
|
SessionPromptParamsPartsTypeAgent SessionPromptParamsPartsType = "agent"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (r SessionPromptParamsPartsType) IsKnown() bool {
|
||||||
|
switch r {
|
||||||
|
case SessionPromptParamsPartsTypeText, SessionPromptParamsPartsTypeFile, SessionPromptParamsPartsTypeAgent:
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
type SessionPromptParamsModel struct {
|
||||||
|
ModelID param.Field[string] `json:"modelID,required"`
|
||||||
|
ProviderID param.Field[string] `json:"providerID,required"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r SessionPromptParamsModel) MarshalJSON() (data []byte, err error) {
|
||||||
|
return apijson.MarshalRoot(r)
|
||||||
|
}
|
||||||
|
|
||||||
type SessionRevertParams struct {
|
type SessionRevertParams struct {
|
||||||
MessageID param.Field[string] `json:"messageID,required"`
|
MessageID param.Field[string] `json:"messageID,required"`
|
||||||
|
Directory param.Field[string] `query:"directory"`
|
||||||
PartID param.Field[string] `json:"partID"`
|
PartID param.Field[string] `json:"partID"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2485,20 +2629,82 @@ func (r SessionRevertParams) MarshalJSON() (data []byte, err error) {
|
|||||||
return apijson.MarshalRoot(r)
|
return apijson.MarshalRoot(r)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// URLQuery serializes [SessionRevertParams]'s query parameters as `url.Values`.
|
||||||
|
func (r SessionRevertParams) URLQuery() (v url.Values) {
|
||||||
|
return apiquery.MarshalWithSettings(r, apiquery.QuerySettings{
|
||||||
|
ArrayFormat: apiquery.ArrayQueryFormatComma,
|
||||||
|
NestedFormat: apiquery.NestedQueryFormatBrackets,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
type SessionShareParams struct {
|
||||||
|
Directory param.Field[string] `query:"directory"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// URLQuery serializes [SessionShareParams]'s query parameters as `url.Values`.
|
||||||
|
func (r SessionShareParams) URLQuery() (v url.Values) {
|
||||||
|
return apiquery.MarshalWithSettings(r, apiquery.QuerySettings{
|
||||||
|
ArrayFormat: apiquery.ArrayQueryFormatComma,
|
||||||
|
NestedFormat: apiquery.NestedQueryFormatBrackets,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
type SessionShellParams struct {
|
type SessionShellParams struct {
|
||||||
Agent param.Field[string] `json:"agent,required"`
|
Agent param.Field[string] `json:"agent,required"`
|
||||||
Command param.Field[string] `json:"command,required"`
|
Command param.Field[string] `json:"command,required"`
|
||||||
|
Directory param.Field[string] `query:"directory"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r SessionShellParams) MarshalJSON() (data []byte, err error) {
|
func (r SessionShellParams) MarshalJSON() (data []byte, err error) {
|
||||||
return apijson.MarshalRoot(r)
|
return apijson.MarshalRoot(r)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// URLQuery serializes [SessionShellParams]'s query parameters as `url.Values`.
|
||||||
|
func (r SessionShellParams) URLQuery() (v url.Values) {
|
||||||
|
return apiquery.MarshalWithSettings(r, apiquery.QuerySettings{
|
||||||
|
ArrayFormat: apiquery.ArrayQueryFormatComma,
|
||||||
|
NestedFormat: apiquery.NestedQueryFormatBrackets,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
type SessionSummarizeParams struct {
|
type SessionSummarizeParams struct {
|
||||||
ModelID param.Field[string] `json:"modelID,required"`
|
ModelID param.Field[string] `json:"modelID,required"`
|
||||||
ProviderID param.Field[string] `json:"providerID,required"`
|
ProviderID param.Field[string] `json:"providerID,required"`
|
||||||
|
Directory param.Field[string] `query:"directory"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r SessionSummarizeParams) MarshalJSON() (data []byte, err error) {
|
func (r SessionSummarizeParams) MarshalJSON() (data []byte, err error) {
|
||||||
return apijson.MarshalRoot(r)
|
return apijson.MarshalRoot(r)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// URLQuery serializes [SessionSummarizeParams]'s query parameters as `url.Values`.
|
||||||
|
func (r SessionSummarizeParams) URLQuery() (v url.Values) {
|
||||||
|
return apiquery.MarshalWithSettings(r, apiquery.QuerySettings{
|
||||||
|
ArrayFormat: apiquery.ArrayQueryFormatComma,
|
||||||
|
NestedFormat: apiquery.NestedQueryFormatBrackets,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
type SessionUnrevertParams struct {
|
||||||
|
Directory param.Field[string] `query:"directory"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// URLQuery serializes [SessionUnrevertParams]'s query parameters as `url.Values`.
|
||||||
|
func (r SessionUnrevertParams) URLQuery() (v url.Values) {
|
||||||
|
return apiquery.MarshalWithSettings(r, apiquery.QuerySettings{
|
||||||
|
ArrayFormat: apiquery.ArrayQueryFormatComma,
|
||||||
|
NestedFormat: apiquery.NestedQueryFormatBrackets,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
type SessionUnshareParams struct {
|
||||||
|
Directory param.Field[string] `query:"directory"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// URLQuery serializes [SessionUnshareParams]'s query parameters as `url.Values`.
|
||||||
|
func (r SessionUnshareParams) URLQuery() (v url.Values) {
|
||||||
|
return apiquery.MarshalWithSettings(r, apiquery.QuerySettings{
|
||||||
|
ArrayFormat: apiquery.ArrayQueryFormatComma,
|
||||||
|
NestedFormat: apiquery.NestedQueryFormatBrackets,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestSessionNewWithOptionalParams(t *testing.T) {
|
func TestSessionNewWithOptionalParams(t *testing.T) {
|
||||||
t.Skip("skipped: tests are disabled for the time being")
|
t.Skip("Prism tests are disabled")
|
||||||
baseURL := "http://localhost:4010"
|
baseURL := "http://localhost:4010"
|
||||||
if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
|
if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
|
||||||
baseURL = envURL
|
baseURL = envURL
|
||||||
@@ -26,8 +26,9 @@ func TestSessionNewWithOptionalParams(t *testing.T) {
|
|||||||
option.WithBaseURL(baseURL),
|
option.WithBaseURL(baseURL),
|
||||||
)
|
)
|
||||||
_, err := client.Session.New(context.TODO(), opencode.SessionNewParams{
|
_, err := client.Session.New(context.TODO(), opencode.SessionNewParams{
|
||||||
ParentID: opencode.F("parentID"),
|
Directory: opencode.F("directory"),
|
||||||
Title: opencode.F("title"),
|
ParentID: opencode.F("parentID"),
|
||||||
|
Title: opencode.F("title"),
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
var apierr *opencode.Error
|
var apierr *opencode.Error
|
||||||
@@ -39,7 +40,7 @@ func TestSessionNewWithOptionalParams(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestSessionUpdateWithOptionalParams(t *testing.T) {
|
func TestSessionUpdateWithOptionalParams(t *testing.T) {
|
||||||
t.Skip("skipped: tests are disabled for the time being")
|
t.Skip("Prism tests are disabled")
|
||||||
baseURL := "http://localhost:4010"
|
baseURL := "http://localhost:4010"
|
||||||
if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
|
if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
|
||||||
baseURL = envURL
|
baseURL = envURL
|
||||||
@@ -54,7 +55,8 @@ func TestSessionUpdateWithOptionalParams(t *testing.T) {
|
|||||||
context.TODO(),
|
context.TODO(),
|
||||||
"id",
|
"id",
|
||||||
opencode.SessionUpdateParams{
|
opencode.SessionUpdateParams{
|
||||||
Title: opencode.F("title"),
|
Directory: opencode.F("directory"),
|
||||||
|
Title: opencode.F("title"),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -66,8 +68,8 @@ func TestSessionUpdateWithOptionalParams(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSessionList(t *testing.T) {
|
func TestSessionListWithOptionalParams(t *testing.T) {
|
||||||
t.Skip("skipped: tests are disabled for the time being")
|
t.Skip("Prism tests are disabled")
|
||||||
baseURL := "http://localhost:4010"
|
baseURL := "http://localhost:4010"
|
||||||
if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
|
if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
|
||||||
baseURL = envURL
|
baseURL = envURL
|
||||||
@@ -78,7 +80,9 @@ func TestSessionList(t *testing.T) {
|
|||||||
client := opencode.NewClient(
|
client := opencode.NewClient(
|
||||||
option.WithBaseURL(baseURL),
|
option.WithBaseURL(baseURL),
|
||||||
)
|
)
|
||||||
_, err := client.Session.List(context.TODO())
|
_, err := client.Session.List(context.TODO(), opencode.SessionListParams{
|
||||||
|
Directory: opencode.F("directory"),
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
var apierr *opencode.Error
|
var apierr *opencode.Error
|
||||||
if errors.As(err, &apierr) {
|
if errors.As(err, &apierr) {
|
||||||
@@ -88,8 +92,8 @@ func TestSessionList(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSessionDelete(t *testing.T) {
|
func TestSessionDeleteWithOptionalParams(t *testing.T) {
|
||||||
t.Skip("skipped: tests are disabled for the time being")
|
t.Skip("Prism tests are disabled")
|
||||||
baseURL := "http://localhost:4010"
|
baseURL := "http://localhost:4010"
|
||||||
if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
|
if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
|
||||||
baseURL = envURL
|
baseURL = envURL
|
||||||
@@ -100,72 +104,11 @@ func TestSessionDelete(t *testing.T) {
|
|||||||
client := opencode.NewClient(
|
client := opencode.NewClient(
|
||||||
option.WithBaseURL(baseURL),
|
option.WithBaseURL(baseURL),
|
||||||
)
|
)
|
||||||
_, err := client.Session.Delete(context.TODO(), "id")
|
_, err := client.Session.Delete(
|
||||||
if err != nil {
|
|
||||||
var apierr *opencode.Error
|
|
||||||
if errors.As(err, &apierr) {
|
|
||||||
t.Log(string(apierr.DumpRequest(true)))
|
|
||||||
}
|
|
||||||
t.Fatalf("err should be nil: %s", err.Error())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSessionAbort(t *testing.T) {
|
|
||||||
t.Skip("skipped: tests are disabled for the time being")
|
|
||||||
baseURL := "http://localhost:4010"
|
|
||||||
if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
|
|
||||||
baseURL = envURL
|
|
||||||
}
|
|
||||||
if !testutil.CheckTestServer(t, baseURL) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
client := opencode.NewClient(
|
|
||||||
option.WithBaseURL(baseURL),
|
|
||||||
)
|
|
||||||
_, err := client.Session.Abort(context.TODO(), "id")
|
|
||||||
if err != nil {
|
|
||||||
var apierr *opencode.Error
|
|
||||||
if errors.As(err, &apierr) {
|
|
||||||
t.Log(string(apierr.DumpRequest(true)))
|
|
||||||
}
|
|
||||||
t.Fatalf("err should be nil: %s", err.Error())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSessionChatWithOptionalParams(t *testing.T) {
|
|
||||||
t.Skip("skipped: tests are disabled for the time being")
|
|
||||||
baseURL := "http://localhost:4010"
|
|
||||||
if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
|
|
||||||
baseURL = envURL
|
|
||||||
}
|
|
||||||
if !testutil.CheckTestServer(t, baseURL) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
client := opencode.NewClient(
|
|
||||||
option.WithBaseURL(baseURL),
|
|
||||||
)
|
|
||||||
_, err := client.Session.Chat(
|
|
||||||
context.TODO(),
|
context.TODO(),
|
||||||
"id",
|
"id",
|
||||||
opencode.SessionChatParams{
|
opencode.SessionDeleteParams{
|
||||||
ModelID: opencode.F("modelID"),
|
Directory: opencode.F("directory"),
|
||||||
Parts: opencode.F([]opencode.SessionChatParamsPartUnion{opencode.TextPartInputParam{
|
|
||||||
Text: opencode.F("text"),
|
|
||||||
Type: opencode.F(opencode.TextPartInputTypeText),
|
|
||||||
ID: opencode.F("id"),
|
|
||||||
Synthetic: opencode.F(true),
|
|
||||||
Time: opencode.F(opencode.TextPartInputTimeParam{
|
|
||||||
Start: opencode.F(0.000000),
|
|
||||||
End: opencode.F(0.000000),
|
|
||||||
}),
|
|
||||||
}}),
|
|
||||||
ProviderID: opencode.F("providerID"),
|
|
||||||
Agent: opencode.F("agent"),
|
|
||||||
MessageID: opencode.F("msg"),
|
|
||||||
System: opencode.F("system"),
|
|
||||||
Tools: opencode.F(map[string]bool{
|
|
||||||
"foo": true,
|
|
||||||
}),
|
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -177,8 +120,8 @@ func TestSessionChatWithOptionalParams(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSessionChildren(t *testing.T) {
|
func TestSessionAbortWithOptionalParams(t *testing.T) {
|
||||||
t.Skip("skipped: tests are disabled for the time being")
|
t.Skip("Prism tests are disabled")
|
||||||
baseURL := "http://localhost:4010"
|
baseURL := "http://localhost:4010"
|
||||||
if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
|
if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
|
||||||
baseURL = envURL
|
baseURL = envURL
|
||||||
@@ -189,7 +132,41 @@ func TestSessionChildren(t *testing.T) {
|
|||||||
client := opencode.NewClient(
|
client := opencode.NewClient(
|
||||||
option.WithBaseURL(baseURL),
|
option.WithBaseURL(baseURL),
|
||||||
)
|
)
|
||||||
_, err := client.Session.Children(context.TODO(), "id")
|
_, err := client.Session.Abort(
|
||||||
|
context.TODO(),
|
||||||
|
"id",
|
||||||
|
opencode.SessionAbortParams{
|
||||||
|
Directory: opencode.F("directory"),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
var apierr *opencode.Error
|
||||||
|
if errors.As(err, &apierr) {
|
||||||
|
t.Log(string(apierr.DumpRequest(true)))
|
||||||
|
}
|
||||||
|
t.Fatalf("err should be nil: %s", err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSessionChildrenWithOptionalParams(t *testing.T) {
|
||||||
|
t.Skip("Prism tests are disabled")
|
||||||
|
baseURL := "http://localhost:4010"
|
||||||
|
if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
|
||||||
|
baseURL = envURL
|
||||||
|
}
|
||||||
|
if !testutil.CheckTestServer(t, baseURL) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
client := opencode.NewClient(
|
||||||
|
option.WithBaseURL(baseURL),
|
||||||
|
)
|
||||||
|
_, err := client.Session.Children(
|
||||||
|
context.TODO(),
|
||||||
|
"id",
|
||||||
|
opencode.SessionChildrenParams{
|
||||||
|
Directory: opencode.F("directory"),
|
||||||
|
},
|
||||||
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
var apierr *opencode.Error
|
var apierr *opencode.Error
|
||||||
if errors.As(err, &apierr) {
|
if errors.As(err, &apierr) {
|
||||||
@@ -200,7 +177,7 @@ func TestSessionChildren(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestSessionCommandWithOptionalParams(t *testing.T) {
|
func TestSessionCommandWithOptionalParams(t *testing.T) {
|
||||||
t.Skip("skipped: tests are disabled for the time being")
|
t.Skip("Prism tests are disabled")
|
||||||
baseURL := "http://localhost:4010"
|
baseURL := "http://localhost:4010"
|
||||||
if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
|
if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
|
||||||
baseURL = envURL
|
baseURL = envURL
|
||||||
@@ -217,6 +194,7 @@ func TestSessionCommandWithOptionalParams(t *testing.T) {
|
|||||||
opencode.SessionCommandParams{
|
opencode.SessionCommandParams{
|
||||||
Arguments: opencode.F("arguments"),
|
Arguments: opencode.F("arguments"),
|
||||||
Command: opencode.F("command"),
|
Command: opencode.F("command"),
|
||||||
|
Directory: opencode.F("directory"),
|
||||||
Agent: opencode.F("agent"),
|
Agent: opencode.F("agent"),
|
||||||
MessageID: opencode.F("msg"),
|
MessageID: opencode.F("msg"),
|
||||||
Model: opencode.F("model"),
|
Model: opencode.F("model"),
|
||||||
@@ -231,8 +209,8 @@ func TestSessionCommandWithOptionalParams(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSessionGet(t *testing.T) {
|
func TestSessionGetWithOptionalParams(t *testing.T) {
|
||||||
t.Skip("skipped: tests are disabled for the time being")
|
t.Skip("Prism tests are disabled")
|
||||||
baseURL := "http://localhost:4010"
|
baseURL := "http://localhost:4010"
|
||||||
if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
|
if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
|
||||||
baseURL = envURL
|
baseURL = envURL
|
||||||
@@ -243,7 +221,13 @@ func TestSessionGet(t *testing.T) {
|
|||||||
client := opencode.NewClient(
|
client := opencode.NewClient(
|
||||||
option.WithBaseURL(baseURL),
|
option.WithBaseURL(baseURL),
|
||||||
)
|
)
|
||||||
_, err := client.Session.Get(context.TODO(), "id")
|
_, err := client.Session.Get(
|
||||||
|
context.TODO(),
|
||||||
|
"id",
|
||||||
|
opencode.SessionGetParams{
|
||||||
|
Directory: opencode.F("directory"),
|
||||||
|
},
|
||||||
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
var apierr *opencode.Error
|
var apierr *opencode.Error
|
||||||
if errors.As(err, &apierr) {
|
if errors.As(err, &apierr) {
|
||||||
@@ -253,8 +237,8 @@ func TestSessionGet(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSessionInit(t *testing.T) {
|
func TestSessionInitWithOptionalParams(t *testing.T) {
|
||||||
t.Skip("skipped: tests are disabled for the time being")
|
t.Skip("Prism tests are disabled")
|
||||||
baseURL := "http://localhost:4010"
|
baseURL := "http://localhost:4010"
|
||||||
if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
|
if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
|
||||||
baseURL = envURL
|
baseURL = envURL
|
||||||
@@ -272,6 +256,7 @@ func TestSessionInit(t *testing.T) {
|
|||||||
MessageID: opencode.F("messageID"),
|
MessageID: opencode.F("messageID"),
|
||||||
ModelID: opencode.F("modelID"),
|
ModelID: opencode.F("modelID"),
|
||||||
ProviderID: opencode.F("providerID"),
|
ProviderID: opencode.F("providerID"),
|
||||||
|
Directory: opencode.F("directory"),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -283,8 +268,8 @@ func TestSessionInit(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSessionMessage(t *testing.T) {
|
func TestSessionMessageWithOptionalParams(t *testing.T) {
|
||||||
t.Skip("skipped: tests are disabled for the time being")
|
t.Skip("Prism tests are disabled")
|
||||||
baseURL := "http://localhost:4010"
|
baseURL := "http://localhost:4010"
|
||||||
if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
|
if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
|
||||||
baseURL = envURL
|
baseURL = envURL
|
||||||
@@ -299,6 +284,9 @@ func TestSessionMessage(t *testing.T) {
|
|||||||
context.TODO(),
|
context.TODO(),
|
||||||
"id",
|
"id",
|
||||||
"messageID",
|
"messageID",
|
||||||
|
opencode.SessionMessageParams{
|
||||||
|
Directory: opencode.F("directory"),
|
||||||
|
},
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
var apierr *opencode.Error
|
var apierr *opencode.Error
|
||||||
@@ -309,8 +297,8 @@ func TestSessionMessage(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSessionMessages(t *testing.T) {
|
func TestSessionMessagesWithOptionalParams(t *testing.T) {
|
||||||
t.Skip("skipped: tests are disabled for the time being")
|
t.Skip("Prism tests are disabled")
|
||||||
baseURL := "http://localhost:4010"
|
baseURL := "http://localhost:4010"
|
||||||
if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
|
if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
|
||||||
baseURL = envURL
|
baseURL = envURL
|
||||||
@@ -321,7 +309,61 @@ func TestSessionMessages(t *testing.T) {
|
|||||||
client := opencode.NewClient(
|
client := opencode.NewClient(
|
||||||
option.WithBaseURL(baseURL),
|
option.WithBaseURL(baseURL),
|
||||||
)
|
)
|
||||||
_, err := client.Session.Messages(context.TODO(), "id")
|
_, err := client.Session.Messages(
|
||||||
|
context.TODO(),
|
||||||
|
"id",
|
||||||
|
opencode.SessionMessagesParams{
|
||||||
|
Directory: opencode.F("directory"),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
var apierr *opencode.Error
|
||||||
|
if errors.As(err, &apierr) {
|
||||||
|
t.Log(string(apierr.DumpRequest(true)))
|
||||||
|
}
|
||||||
|
t.Fatalf("err should be nil: %s", err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSessionPromptWithOptionalParams(t *testing.T) {
|
||||||
|
t.Skip("Prism tests are disabled")
|
||||||
|
baseURL := "http://localhost:4010"
|
||||||
|
if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
|
||||||
|
baseURL = envURL
|
||||||
|
}
|
||||||
|
if !testutil.CheckTestServer(t, baseURL) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
client := opencode.NewClient(
|
||||||
|
option.WithBaseURL(baseURL),
|
||||||
|
)
|
||||||
|
_, err := client.Session.Prompt(
|
||||||
|
context.TODO(),
|
||||||
|
"id",
|
||||||
|
opencode.SessionPromptParams{
|
||||||
|
Parts: opencode.F([]opencode.SessionPromptParamsPartUnion{opencode.TextPartInputParam{
|
||||||
|
Text: opencode.F("text"),
|
||||||
|
Type: opencode.F(opencode.TextPartInputTypeText),
|
||||||
|
ID: opencode.F("id"),
|
||||||
|
Synthetic: opencode.F(true),
|
||||||
|
Time: opencode.F(opencode.TextPartInputTimeParam{
|
||||||
|
Start: opencode.F(0.000000),
|
||||||
|
End: opencode.F(0.000000),
|
||||||
|
}),
|
||||||
|
}}),
|
||||||
|
Directory: opencode.F("directory"),
|
||||||
|
Agent: opencode.F("agent"),
|
||||||
|
MessageID: opencode.F("msg"),
|
||||||
|
Model: opencode.F(opencode.SessionPromptParamsModel{
|
||||||
|
ModelID: opencode.F("modelID"),
|
||||||
|
ProviderID: opencode.F("providerID"),
|
||||||
|
}),
|
||||||
|
System: opencode.F("system"),
|
||||||
|
Tools: opencode.F(map[string]bool{
|
||||||
|
"foo": true,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
var apierr *opencode.Error
|
var apierr *opencode.Error
|
||||||
if errors.As(err, &apierr) {
|
if errors.As(err, &apierr) {
|
||||||
@@ -332,7 +374,7 @@ func TestSessionMessages(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestSessionRevertWithOptionalParams(t *testing.T) {
|
func TestSessionRevertWithOptionalParams(t *testing.T) {
|
||||||
t.Skip("skipped: tests are disabled for the time being")
|
t.Skip("Prism tests are disabled")
|
||||||
baseURL := "http://localhost:4010"
|
baseURL := "http://localhost:4010"
|
||||||
if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
|
if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
|
||||||
baseURL = envURL
|
baseURL = envURL
|
||||||
@@ -348,6 +390,7 @@ func TestSessionRevertWithOptionalParams(t *testing.T) {
|
|||||||
"id",
|
"id",
|
||||||
opencode.SessionRevertParams{
|
opencode.SessionRevertParams{
|
||||||
MessageID: opencode.F("msg"),
|
MessageID: opencode.F("msg"),
|
||||||
|
Directory: opencode.F("directory"),
|
||||||
PartID: opencode.F("prt"),
|
PartID: opencode.F("prt"),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
@@ -360,8 +403,8 @@ func TestSessionRevertWithOptionalParams(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSessionShare(t *testing.T) {
|
func TestSessionShareWithOptionalParams(t *testing.T) {
|
||||||
t.Skip("skipped: tests are disabled for the time being")
|
t.Skip("Prism tests are disabled")
|
||||||
baseURL := "http://localhost:4010"
|
baseURL := "http://localhost:4010"
|
||||||
if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
|
if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
|
||||||
baseURL = envURL
|
baseURL = envURL
|
||||||
@@ -372,7 +415,13 @@ func TestSessionShare(t *testing.T) {
|
|||||||
client := opencode.NewClient(
|
client := opencode.NewClient(
|
||||||
option.WithBaseURL(baseURL),
|
option.WithBaseURL(baseURL),
|
||||||
)
|
)
|
||||||
_, err := client.Session.Share(context.TODO(), "id")
|
_, err := client.Session.Share(
|
||||||
|
context.TODO(),
|
||||||
|
"id",
|
||||||
|
opencode.SessionShareParams{
|
||||||
|
Directory: opencode.F("directory"),
|
||||||
|
},
|
||||||
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
var apierr *opencode.Error
|
var apierr *opencode.Error
|
||||||
if errors.As(err, &apierr) {
|
if errors.As(err, &apierr) {
|
||||||
@@ -382,8 +431,8 @@ func TestSessionShare(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSessionShell(t *testing.T) {
|
func TestSessionShellWithOptionalParams(t *testing.T) {
|
||||||
t.Skip("skipped: tests are disabled for the time being")
|
t.Skip("Prism tests are disabled")
|
||||||
baseURL := "http://localhost:4010"
|
baseURL := "http://localhost:4010"
|
||||||
if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
|
if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
|
||||||
baseURL = envURL
|
baseURL = envURL
|
||||||
@@ -398,8 +447,9 @@ func TestSessionShell(t *testing.T) {
|
|||||||
context.TODO(),
|
context.TODO(),
|
||||||
"id",
|
"id",
|
||||||
opencode.SessionShellParams{
|
opencode.SessionShellParams{
|
||||||
Agent: opencode.F("agent"),
|
Agent: opencode.F("agent"),
|
||||||
Command: opencode.F("command"),
|
Command: opencode.F("command"),
|
||||||
|
Directory: opencode.F("directory"),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -411,8 +461,8 @@ func TestSessionShell(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSessionSummarize(t *testing.T) {
|
func TestSessionSummarizeWithOptionalParams(t *testing.T) {
|
||||||
t.Skip("skipped: tests are disabled for the time being")
|
t.Skip("Prism tests are disabled")
|
||||||
baseURL := "http://localhost:4010"
|
baseURL := "http://localhost:4010"
|
||||||
if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
|
if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
|
||||||
baseURL = envURL
|
baseURL = envURL
|
||||||
@@ -429,6 +479,7 @@ func TestSessionSummarize(t *testing.T) {
|
|||||||
opencode.SessionSummarizeParams{
|
opencode.SessionSummarizeParams{
|
||||||
ModelID: opencode.F("modelID"),
|
ModelID: opencode.F("modelID"),
|
||||||
ProviderID: opencode.F("providerID"),
|
ProviderID: opencode.F("providerID"),
|
||||||
|
Directory: opencode.F("directory"),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -440,8 +491,8 @@ func TestSessionSummarize(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSessionUnrevert(t *testing.T) {
|
func TestSessionUnrevertWithOptionalParams(t *testing.T) {
|
||||||
t.Skip("skipped: tests are disabled for the time being")
|
t.Skip("Prism tests are disabled")
|
||||||
baseURL := "http://localhost:4010"
|
baseURL := "http://localhost:4010"
|
||||||
if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
|
if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
|
||||||
baseURL = envURL
|
baseURL = envURL
|
||||||
@@ -452,7 +503,13 @@ func TestSessionUnrevert(t *testing.T) {
|
|||||||
client := opencode.NewClient(
|
client := opencode.NewClient(
|
||||||
option.WithBaseURL(baseURL),
|
option.WithBaseURL(baseURL),
|
||||||
)
|
)
|
||||||
_, err := client.Session.Unrevert(context.TODO(), "id")
|
_, err := client.Session.Unrevert(
|
||||||
|
context.TODO(),
|
||||||
|
"id",
|
||||||
|
opencode.SessionUnrevertParams{
|
||||||
|
Directory: opencode.F("directory"),
|
||||||
|
},
|
||||||
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
var apierr *opencode.Error
|
var apierr *opencode.Error
|
||||||
if errors.As(err, &apierr) {
|
if errors.As(err, &apierr) {
|
||||||
@@ -462,8 +519,8 @@ func TestSessionUnrevert(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSessionUnshare(t *testing.T) {
|
func TestSessionUnshareWithOptionalParams(t *testing.T) {
|
||||||
t.Skip("skipped: tests are disabled for the time being")
|
t.Skip("Prism tests are disabled")
|
||||||
baseURL := "http://localhost:4010"
|
baseURL := "http://localhost:4010"
|
||||||
if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
|
if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
|
||||||
baseURL = envURL
|
baseURL = envURL
|
||||||
@@ -474,7 +531,13 @@ func TestSessionUnshare(t *testing.T) {
|
|||||||
client := opencode.NewClient(
|
client := opencode.NewClient(
|
||||||
option.WithBaseURL(baseURL),
|
option.WithBaseURL(baseURL),
|
||||||
)
|
)
|
||||||
_, err := client.Session.Unshare(context.TODO(), "id")
|
_, err := client.Session.Unshare(
|
||||||
|
context.TODO(),
|
||||||
|
"id",
|
||||||
|
opencode.SessionUnshareParams{
|
||||||
|
Directory: opencode.F("directory"),
|
||||||
|
},
|
||||||
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
var apierr *opencode.Error
|
var apierr *opencode.Error
|
||||||
if errors.As(err, &apierr) {
|
if errors.As(err, &apierr) {
|
||||||
|
|||||||
@@ -7,8 +7,10 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
|
||||||
"github.com/sst/opencode-sdk-go/internal/apijson"
|
"github.com/sst/opencode-sdk-go/internal/apijson"
|
||||||
|
"github.com/sst/opencode-sdk-go/internal/apiquery"
|
||||||
"github.com/sst/opencode-sdk-go/internal/param"
|
"github.com/sst/opencode-sdk-go/internal/param"
|
||||||
"github.com/sst/opencode-sdk-go/internal/requestconfig"
|
"github.com/sst/opencode-sdk-go/internal/requestconfig"
|
||||||
"github.com/sst/opencode-sdk-go/option"
|
"github.com/sst/opencode-sdk-go/option"
|
||||||
@@ -34,7 +36,7 @@ func NewSessionPermissionService(opts ...option.RequestOption) (r *SessionPermis
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Respond to a permission request
|
// Respond to a permission request
|
||||||
func (r *SessionPermissionService) Respond(ctx context.Context, id string, permissionID string, body SessionPermissionRespondParams, opts ...option.RequestOption) (res *bool, err error) {
|
func (r *SessionPermissionService) Respond(ctx context.Context, id string, permissionID string, params SessionPermissionRespondParams, opts ...option.RequestOption) (res *bool, err error) {
|
||||||
opts = append(r.Options[:], opts...)
|
opts = append(r.Options[:], opts...)
|
||||||
if id == "" {
|
if id == "" {
|
||||||
err = errors.New("missing required id parameter")
|
err = errors.New("missing required id parameter")
|
||||||
@@ -45,7 +47,7 @@ func (r *SessionPermissionService) Respond(ctx context.Context, id string, permi
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
path := fmt.Sprintf("session/%s/permissions/%s", id, permissionID)
|
path := fmt.Sprintf("session/%s/permissions/%s", id, permissionID)
|
||||||
err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, body, &res, opts...)
|
err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, params, &res, opts...)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,13 +108,23 @@ func (r permissionTimeJSON) RawJSON() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type SessionPermissionRespondParams struct {
|
type SessionPermissionRespondParams struct {
|
||||||
Response param.Field[SessionPermissionRespondParamsResponse] `json:"response,required"`
|
Response param.Field[SessionPermissionRespondParamsResponse] `json:"response,required"`
|
||||||
|
Directory param.Field[string] `query:"directory"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r SessionPermissionRespondParams) MarshalJSON() (data []byte, err error) {
|
func (r SessionPermissionRespondParams) MarshalJSON() (data []byte, err error) {
|
||||||
return apijson.MarshalRoot(r)
|
return apijson.MarshalRoot(r)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// URLQuery serializes [SessionPermissionRespondParams]'s query parameters as
|
||||||
|
// `url.Values`.
|
||||||
|
func (r SessionPermissionRespondParams) URLQuery() (v url.Values) {
|
||||||
|
return apiquery.MarshalWithSettings(r, apiquery.QuerySettings{
|
||||||
|
ArrayFormat: apiquery.ArrayQueryFormatComma,
|
||||||
|
NestedFormat: apiquery.NestedQueryFormatBrackets,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
type SessionPermissionRespondParamsResponse string
|
type SessionPermissionRespondParamsResponse string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|||||||
@@ -13,8 +13,8 @@ import (
|
|||||||
"github.com/sst/opencode-sdk-go/option"
|
"github.com/sst/opencode-sdk-go/option"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestSessionPermissionRespond(t *testing.T) {
|
func TestSessionPermissionRespondWithOptionalParams(t *testing.T) {
|
||||||
t.Skip("skipped: tests are disabled for the time being")
|
t.Skip("Prism tests are disabled")
|
||||||
baseURL := "http://localhost:4010"
|
baseURL := "http://localhost:4010"
|
||||||
if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
|
if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
|
||||||
baseURL = envURL
|
baseURL = envURL
|
||||||
@@ -30,7 +30,8 @@ func TestSessionPermissionRespond(t *testing.T) {
|
|||||||
"id",
|
"id",
|
||||||
"permissionID",
|
"permissionID",
|
||||||
opencode.SessionPermissionRespondParams{
|
opencode.SessionPermissionRespondParams{
|
||||||
Response: opencode.F(opencode.SessionPermissionRespondParamsResponseOnce),
|
Response: opencode.F(opencode.SessionPermissionRespondParamsResponseOnce),
|
||||||
|
Directory: opencode.F("directory"),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
11
packages/sdk/go/shared/union.go
Normal file
11
packages/sdk/go/shared/union.go
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
|
||||||
|
|
||||||
|
package shared
|
||||||
|
|
||||||
|
type UnionBool bool
|
||||||
|
|
||||||
|
func (UnionBool) ImplementsConfigProviderOptionsTimeoutUnion() {}
|
||||||
|
|
||||||
|
type UnionInt int64
|
||||||
|
|
||||||
|
func (UnionInt) ImplementsConfigProviderOptionsTimeoutUnion() {}
|
||||||
@@ -5,8 +5,10 @@ package opencode
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
|
||||||
"github.com/sst/opencode-sdk-go/internal/apijson"
|
"github.com/sst/opencode-sdk-go/internal/apijson"
|
||||||
|
"github.com/sst/opencode-sdk-go/internal/apiquery"
|
||||||
"github.com/sst/opencode-sdk-go/internal/param"
|
"github.com/sst/opencode-sdk-go/internal/param"
|
||||||
"github.com/sst/opencode-sdk-go/internal/requestconfig"
|
"github.com/sst/opencode-sdk-go/internal/requestconfig"
|
||||||
"github.com/sst/opencode-sdk-go/option"
|
"github.com/sst/opencode-sdk-go/option"
|
||||||
@@ -32,103 +34,191 @@ func NewTuiService(opts ...option.RequestOption) (r *TuiService) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Append prompt to the TUI
|
// Append prompt to the TUI
|
||||||
func (r *TuiService) AppendPrompt(ctx context.Context, body TuiAppendPromptParams, opts ...option.RequestOption) (res *bool, err error) {
|
func (r *TuiService) AppendPrompt(ctx context.Context, params TuiAppendPromptParams, opts ...option.RequestOption) (res *bool, err error) {
|
||||||
opts = append(r.Options[:], opts...)
|
opts = append(r.Options[:], opts...)
|
||||||
path := "tui/append-prompt"
|
path := "tui/append-prompt"
|
||||||
err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, body, &res, opts...)
|
err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, params, &res, opts...)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clear the prompt
|
// Clear the prompt
|
||||||
func (r *TuiService) ClearPrompt(ctx context.Context, opts ...option.RequestOption) (res *bool, err error) {
|
func (r *TuiService) ClearPrompt(ctx context.Context, body TuiClearPromptParams, opts ...option.RequestOption) (res *bool, err error) {
|
||||||
opts = append(r.Options[:], opts...)
|
opts = append(r.Options[:], opts...)
|
||||||
path := "tui/clear-prompt"
|
path := "tui/clear-prompt"
|
||||||
err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, nil, &res, opts...)
|
err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, body, &res, opts...)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Execute a TUI command (e.g. agent_cycle)
|
// Execute a TUI command (e.g. agent_cycle)
|
||||||
func (r *TuiService) ExecuteCommand(ctx context.Context, body TuiExecuteCommandParams, opts ...option.RequestOption) (res *bool, err error) {
|
func (r *TuiService) ExecuteCommand(ctx context.Context, params TuiExecuteCommandParams, opts ...option.RequestOption) (res *bool, err error) {
|
||||||
opts = append(r.Options[:], opts...)
|
opts = append(r.Options[:], opts...)
|
||||||
path := "tui/execute-command"
|
path := "tui/execute-command"
|
||||||
err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, body, &res, opts...)
|
err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, params, &res, opts...)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Open the help dialog
|
// Open the help dialog
|
||||||
func (r *TuiService) OpenHelp(ctx context.Context, opts ...option.RequestOption) (res *bool, err error) {
|
func (r *TuiService) OpenHelp(ctx context.Context, body TuiOpenHelpParams, opts ...option.RequestOption) (res *bool, err error) {
|
||||||
opts = append(r.Options[:], opts...)
|
opts = append(r.Options[:], opts...)
|
||||||
path := "tui/open-help"
|
path := "tui/open-help"
|
||||||
err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, nil, &res, opts...)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Open the model dialog
|
|
||||||
func (r *TuiService) OpenModels(ctx context.Context, opts ...option.RequestOption) (res *bool, err error) {
|
|
||||||
opts = append(r.Options[:], opts...)
|
|
||||||
path := "tui/open-models"
|
|
||||||
err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, nil, &res, opts...)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Open the session dialog
|
|
||||||
func (r *TuiService) OpenSessions(ctx context.Context, opts ...option.RequestOption) (res *bool, err error) {
|
|
||||||
opts = append(r.Options[:], opts...)
|
|
||||||
path := "tui/open-sessions"
|
|
||||||
err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, nil, &res, opts...)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Open the theme dialog
|
|
||||||
func (r *TuiService) OpenThemes(ctx context.Context, opts ...option.RequestOption) (res *bool, err error) {
|
|
||||||
opts = append(r.Options[:], opts...)
|
|
||||||
path := "tui/open-themes"
|
|
||||||
err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, nil, &res, opts...)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Show a toast notification in the TUI
|
|
||||||
func (r *TuiService) ShowToast(ctx context.Context, body TuiShowToastParams, opts ...option.RequestOption) (res *bool, err error) {
|
|
||||||
opts = append(r.Options[:], opts...)
|
|
||||||
path := "tui/show-toast"
|
|
||||||
err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, body, &res, opts...)
|
err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, body, &res, opts...)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Open the model dialog
|
||||||
|
func (r *TuiService) OpenModels(ctx context.Context, body TuiOpenModelsParams, opts ...option.RequestOption) (res *bool, err error) {
|
||||||
|
opts = append(r.Options[:], opts...)
|
||||||
|
path := "tui/open-models"
|
||||||
|
err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, body, &res, opts...)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open the session dialog
|
||||||
|
func (r *TuiService) OpenSessions(ctx context.Context, body TuiOpenSessionsParams, opts ...option.RequestOption) (res *bool, err error) {
|
||||||
|
opts = append(r.Options[:], opts...)
|
||||||
|
path := "tui/open-sessions"
|
||||||
|
err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, body, &res, opts...)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open the theme dialog
|
||||||
|
func (r *TuiService) OpenThemes(ctx context.Context, body TuiOpenThemesParams, opts ...option.RequestOption) (res *bool, err error) {
|
||||||
|
opts = append(r.Options[:], opts...)
|
||||||
|
path := "tui/open-themes"
|
||||||
|
err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, body, &res, opts...)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show a toast notification in the TUI
|
||||||
|
func (r *TuiService) ShowToast(ctx context.Context, params TuiShowToastParams, opts ...option.RequestOption) (res *bool, err error) {
|
||||||
|
opts = append(r.Options[:], opts...)
|
||||||
|
path := "tui/show-toast"
|
||||||
|
err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, params, &res, opts...)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// Submit the prompt
|
// Submit the prompt
|
||||||
func (r *TuiService) SubmitPrompt(ctx context.Context, opts ...option.RequestOption) (res *bool, err error) {
|
func (r *TuiService) SubmitPrompt(ctx context.Context, body TuiSubmitPromptParams, opts ...option.RequestOption) (res *bool, err error) {
|
||||||
opts = append(r.Options[:], opts...)
|
opts = append(r.Options[:], opts...)
|
||||||
path := "tui/submit-prompt"
|
path := "tui/submit-prompt"
|
||||||
err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, nil, &res, opts...)
|
err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, body, &res, opts...)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
type TuiAppendPromptParams struct {
|
type TuiAppendPromptParams struct {
|
||||||
Text param.Field[string] `json:"text,required"`
|
Text param.Field[string] `json:"text,required"`
|
||||||
|
Directory param.Field[string] `query:"directory"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r TuiAppendPromptParams) MarshalJSON() (data []byte, err error) {
|
func (r TuiAppendPromptParams) MarshalJSON() (data []byte, err error) {
|
||||||
return apijson.MarshalRoot(r)
|
return apijson.MarshalRoot(r)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// URLQuery serializes [TuiAppendPromptParams]'s query parameters as `url.Values`.
|
||||||
|
func (r TuiAppendPromptParams) URLQuery() (v url.Values) {
|
||||||
|
return apiquery.MarshalWithSettings(r, apiquery.QuerySettings{
|
||||||
|
ArrayFormat: apiquery.ArrayQueryFormatComma,
|
||||||
|
NestedFormat: apiquery.NestedQueryFormatBrackets,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
type TuiClearPromptParams struct {
|
||||||
|
Directory param.Field[string] `query:"directory"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// URLQuery serializes [TuiClearPromptParams]'s query parameters as `url.Values`.
|
||||||
|
func (r TuiClearPromptParams) URLQuery() (v url.Values) {
|
||||||
|
return apiquery.MarshalWithSettings(r, apiquery.QuerySettings{
|
||||||
|
ArrayFormat: apiquery.ArrayQueryFormatComma,
|
||||||
|
NestedFormat: apiquery.NestedQueryFormatBrackets,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
type TuiExecuteCommandParams struct {
|
type TuiExecuteCommandParams struct {
|
||||||
Command param.Field[string] `json:"command,required"`
|
Command param.Field[string] `json:"command,required"`
|
||||||
|
Directory param.Field[string] `query:"directory"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r TuiExecuteCommandParams) MarshalJSON() (data []byte, err error) {
|
func (r TuiExecuteCommandParams) MarshalJSON() (data []byte, err error) {
|
||||||
return apijson.MarshalRoot(r)
|
return apijson.MarshalRoot(r)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// URLQuery serializes [TuiExecuteCommandParams]'s query parameters as
|
||||||
|
// `url.Values`.
|
||||||
|
func (r TuiExecuteCommandParams) URLQuery() (v url.Values) {
|
||||||
|
return apiquery.MarshalWithSettings(r, apiquery.QuerySettings{
|
||||||
|
ArrayFormat: apiquery.ArrayQueryFormatComma,
|
||||||
|
NestedFormat: apiquery.NestedQueryFormatBrackets,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
type TuiOpenHelpParams struct {
|
||||||
|
Directory param.Field[string] `query:"directory"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// URLQuery serializes [TuiOpenHelpParams]'s query parameters as `url.Values`.
|
||||||
|
func (r TuiOpenHelpParams) URLQuery() (v url.Values) {
|
||||||
|
return apiquery.MarshalWithSettings(r, apiquery.QuerySettings{
|
||||||
|
ArrayFormat: apiquery.ArrayQueryFormatComma,
|
||||||
|
NestedFormat: apiquery.NestedQueryFormatBrackets,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
type TuiOpenModelsParams struct {
|
||||||
|
Directory param.Field[string] `query:"directory"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// URLQuery serializes [TuiOpenModelsParams]'s query parameters as `url.Values`.
|
||||||
|
func (r TuiOpenModelsParams) URLQuery() (v url.Values) {
|
||||||
|
return apiquery.MarshalWithSettings(r, apiquery.QuerySettings{
|
||||||
|
ArrayFormat: apiquery.ArrayQueryFormatComma,
|
||||||
|
NestedFormat: apiquery.NestedQueryFormatBrackets,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
type TuiOpenSessionsParams struct {
|
||||||
|
Directory param.Field[string] `query:"directory"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// URLQuery serializes [TuiOpenSessionsParams]'s query parameters as `url.Values`.
|
||||||
|
func (r TuiOpenSessionsParams) URLQuery() (v url.Values) {
|
||||||
|
return apiquery.MarshalWithSettings(r, apiquery.QuerySettings{
|
||||||
|
ArrayFormat: apiquery.ArrayQueryFormatComma,
|
||||||
|
NestedFormat: apiquery.NestedQueryFormatBrackets,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
type TuiOpenThemesParams struct {
|
||||||
|
Directory param.Field[string] `query:"directory"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// URLQuery serializes [TuiOpenThemesParams]'s query parameters as `url.Values`.
|
||||||
|
func (r TuiOpenThemesParams) URLQuery() (v url.Values) {
|
||||||
|
return apiquery.MarshalWithSettings(r, apiquery.QuerySettings{
|
||||||
|
ArrayFormat: apiquery.ArrayQueryFormatComma,
|
||||||
|
NestedFormat: apiquery.NestedQueryFormatBrackets,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
type TuiShowToastParams struct {
|
type TuiShowToastParams struct {
|
||||||
Message param.Field[string] `json:"message,required"`
|
Message param.Field[string] `json:"message,required"`
|
||||||
Variant param.Field[TuiShowToastParamsVariant] `json:"variant,required"`
|
Variant param.Field[TuiShowToastParamsVariant] `json:"variant,required"`
|
||||||
Title param.Field[string] `json:"title"`
|
Directory param.Field[string] `query:"directory"`
|
||||||
|
Title param.Field[string] `json:"title"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r TuiShowToastParams) MarshalJSON() (data []byte, err error) {
|
func (r TuiShowToastParams) MarshalJSON() (data []byte, err error) {
|
||||||
return apijson.MarshalRoot(r)
|
return apijson.MarshalRoot(r)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// URLQuery serializes [TuiShowToastParams]'s query parameters as `url.Values`.
|
||||||
|
func (r TuiShowToastParams) URLQuery() (v url.Values) {
|
||||||
|
return apiquery.MarshalWithSettings(r, apiquery.QuerySettings{
|
||||||
|
ArrayFormat: apiquery.ArrayQueryFormatComma,
|
||||||
|
NestedFormat: apiquery.NestedQueryFormatBrackets,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
type TuiShowToastParamsVariant string
|
type TuiShowToastParamsVariant string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -145,3 +235,15 @@ func (r TuiShowToastParamsVariant) IsKnown() bool {
|
|||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type TuiSubmitPromptParams struct {
|
||||||
|
Directory param.Field[string] `query:"directory"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// URLQuery serializes [TuiSubmitPromptParams]'s query parameters as `url.Values`.
|
||||||
|
func (r TuiSubmitPromptParams) URLQuery() (v url.Values) {
|
||||||
|
return apiquery.MarshalWithSettings(r, apiquery.QuerySettings{
|
||||||
|
ArrayFormat: apiquery.ArrayQueryFormatComma,
|
||||||
|
NestedFormat: apiquery.NestedQueryFormatBrackets,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
@@ -13,8 +13,8 @@ import (
|
|||||||
"github.com/sst/opencode-sdk-go/option"
|
"github.com/sst/opencode-sdk-go/option"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestTuiAppendPrompt(t *testing.T) {
|
func TestTuiAppendPromptWithOptionalParams(t *testing.T) {
|
||||||
t.Skip("skipped: tests are disabled for the time being")
|
t.Skip("Prism tests are disabled")
|
||||||
baseURL := "http://localhost:4010"
|
baseURL := "http://localhost:4010"
|
||||||
if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
|
if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
|
||||||
baseURL = envURL
|
baseURL = envURL
|
||||||
@@ -26,7 +26,8 @@ func TestTuiAppendPrompt(t *testing.T) {
|
|||||||
option.WithBaseURL(baseURL),
|
option.WithBaseURL(baseURL),
|
||||||
)
|
)
|
||||||
_, err := client.Tui.AppendPrompt(context.TODO(), opencode.TuiAppendPromptParams{
|
_, err := client.Tui.AppendPrompt(context.TODO(), opencode.TuiAppendPromptParams{
|
||||||
Text: opencode.F("text"),
|
Text: opencode.F("text"),
|
||||||
|
Directory: opencode.F("directory"),
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
var apierr *opencode.Error
|
var apierr *opencode.Error
|
||||||
@@ -37,8 +38,8 @@ func TestTuiAppendPrompt(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestTuiClearPrompt(t *testing.T) {
|
func TestTuiClearPromptWithOptionalParams(t *testing.T) {
|
||||||
t.Skip("skipped: tests are disabled for the time being")
|
t.Skip("Prism tests are disabled")
|
||||||
baseURL := "http://localhost:4010"
|
baseURL := "http://localhost:4010"
|
||||||
if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
|
if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
|
||||||
baseURL = envURL
|
baseURL = envURL
|
||||||
@@ -49,7 +50,9 @@ func TestTuiClearPrompt(t *testing.T) {
|
|||||||
client := opencode.NewClient(
|
client := opencode.NewClient(
|
||||||
option.WithBaseURL(baseURL),
|
option.WithBaseURL(baseURL),
|
||||||
)
|
)
|
||||||
_, err := client.Tui.ClearPrompt(context.TODO())
|
_, err := client.Tui.ClearPrompt(context.TODO(), opencode.TuiClearPromptParams{
|
||||||
|
Directory: opencode.F("directory"),
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
var apierr *opencode.Error
|
var apierr *opencode.Error
|
||||||
if errors.As(err, &apierr) {
|
if errors.As(err, &apierr) {
|
||||||
@@ -59,8 +62,8 @@ func TestTuiClearPrompt(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestTuiExecuteCommand(t *testing.T) {
|
func TestTuiExecuteCommandWithOptionalParams(t *testing.T) {
|
||||||
t.Skip("skipped: tests are disabled for the time being")
|
t.Skip("Prism tests are disabled")
|
||||||
baseURL := "http://localhost:4010"
|
baseURL := "http://localhost:4010"
|
||||||
if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
|
if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
|
||||||
baseURL = envURL
|
baseURL = envURL
|
||||||
@@ -72,7 +75,8 @@ func TestTuiExecuteCommand(t *testing.T) {
|
|||||||
option.WithBaseURL(baseURL),
|
option.WithBaseURL(baseURL),
|
||||||
)
|
)
|
||||||
_, err := client.Tui.ExecuteCommand(context.TODO(), opencode.TuiExecuteCommandParams{
|
_, err := client.Tui.ExecuteCommand(context.TODO(), opencode.TuiExecuteCommandParams{
|
||||||
Command: opencode.F("command"),
|
Command: opencode.F("command"),
|
||||||
|
Directory: opencode.F("directory"),
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
var apierr *opencode.Error
|
var apierr *opencode.Error
|
||||||
@@ -83,8 +87,8 @@ func TestTuiExecuteCommand(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestTuiOpenHelp(t *testing.T) {
|
func TestTuiOpenHelpWithOptionalParams(t *testing.T) {
|
||||||
t.Skip("skipped: tests are disabled for the time being")
|
t.Skip("Prism tests are disabled")
|
||||||
baseURL := "http://localhost:4010"
|
baseURL := "http://localhost:4010"
|
||||||
if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
|
if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
|
||||||
baseURL = envURL
|
baseURL = envURL
|
||||||
@@ -95,7 +99,9 @@ func TestTuiOpenHelp(t *testing.T) {
|
|||||||
client := opencode.NewClient(
|
client := opencode.NewClient(
|
||||||
option.WithBaseURL(baseURL),
|
option.WithBaseURL(baseURL),
|
||||||
)
|
)
|
||||||
_, err := client.Tui.OpenHelp(context.TODO())
|
_, err := client.Tui.OpenHelp(context.TODO(), opencode.TuiOpenHelpParams{
|
||||||
|
Directory: opencode.F("directory"),
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
var apierr *opencode.Error
|
var apierr *opencode.Error
|
||||||
if errors.As(err, &apierr) {
|
if errors.As(err, &apierr) {
|
||||||
@@ -105,8 +111,8 @@ func TestTuiOpenHelp(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestTuiOpenModels(t *testing.T) {
|
func TestTuiOpenModelsWithOptionalParams(t *testing.T) {
|
||||||
t.Skip("skipped: tests are disabled for the time being")
|
t.Skip("Prism tests are disabled")
|
||||||
baseURL := "http://localhost:4010"
|
baseURL := "http://localhost:4010"
|
||||||
if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
|
if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
|
||||||
baseURL = envURL
|
baseURL = envURL
|
||||||
@@ -117,7 +123,9 @@ func TestTuiOpenModels(t *testing.T) {
|
|||||||
client := opencode.NewClient(
|
client := opencode.NewClient(
|
||||||
option.WithBaseURL(baseURL),
|
option.WithBaseURL(baseURL),
|
||||||
)
|
)
|
||||||
_, err := client.Tui.OpenModels(context.TODO())
|
_, err := client.Tui.OpenModels(context.TODO(), opencode.TuiOpenModelsParams{
|
||||||
|
Directory: opencode.F("directory"),
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
var apierr *opencode.Error
|
var apierr *opencode.Error
|
||||||
if errors.As(err, &apierr) {
|
if errors.As(err, &apierr) {
|
||||||
@@ -127,8 +135,8 @@ func TestTuiOpenModels(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestTuiOpenSessions(t *testing.T) {
|
func TestTuiOpenSessionsWithOptionalParams(t *testing.T) {
|
||||||
t.Skip("skipped: tests are disabled for the time being")
|
t.Skip("Prism tests are disabled")
|
||||||
baseURL := "http://localhost:4010"
|
baseURL := "http://localhost:4010"
|
||||||
if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
|
if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
|
||||||
baseURL = envURL
|
baseURL = envURL
|
||||||
@@ -139,7 +147,9 @@ func TestTuiOpenSessions(t *testing.T) {
|
|||||||
client := opencode.NewClient(
|
client := opencode.NewClient(
|
||||||
option.WithBaseURL(baseURL),
|
option.WithBaseURL(baseURL),
|
||||||
)
|
)
|
||||||
_, err := client.Tui.OpenSessions(context.TODO())
|
_, err := client.Tui.OpenSessions(context.TODO(), opencode.TuiOpenSessionsParams{
|
||||||
|
Directory: opencode.F("directory"),
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
var apierr *opencode.Error
|
var apierr *opencode.Error
|
||||||
if errors.As(err, &apierr) {
|
if errors.As(err, &apierr) {
|
||||||
@@ -149,8 +159,8 @@ func TestTuiOpenSessions(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestTuiOpenThemes(t *testing.T) {
|
func TestTuiOpenThemesWithOptionalParams(t *testing.T) {
|
||||||
t.Skip("skipped: tests are disabled for the time being")
|
t.Skip("Prism tests are disabled")
|
||||||
baseURL := "http://localhost:4010"
|
baseURL := "http://localhost:4010"
|
||||||
if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
|
if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
|
||||||
baseURL = envURL
|
baseURL = envURL
|
||||||
@@ -161,7 +171,9 @@ func TestTuiOpenThemes(t *testing.T) {
|
|||||||
client := opencode.NewClient(
|
client := opencode.NewClient(
|
||||||
option.WithBaseURL(baseURL),
|
option.WithBaseURL(baseURL),
|
||||||
)
|
)
|
||||||
_, err := client.Tui.OpenThemes(context.TODO())
|
_, err := client.Tui.OpenThemes(context.TODO(), opencode.TuiOpenThemesParams{
|
||||||
|
Directory: opencode.F("directory"),
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
var apierr *opencode.Error
|
var apierr *opencode.Error
|
||||||
if errors.As(err, &apierr) {
|
if errors.As(err, &apierr) {
|
||||||
@@ -172,7 +184,7 @@ func TestTuiOpenThemes(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestTuiShowToastWithOptionalParams(t *testing.T) {
|
func TestTuiShowToastWithOptionalParams(t *testing.T) {
|
||||||
t.Skip("skipped: tests are disabled for the time being")
|
t.Skip("Prism tests are disabled")
|
||||||
baseURL := "http://localhost:4010"
|
baseURL := "http://localhost:4010"
|
||||||
if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
|
if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
|
||||||
baseURL = envURL
|
baseURL = envURL
|
||||||
@@ -184,9 +196,10 @@ func TestTuiShowToastWithOptionalParams(t *testing.T) {
|
|||||||
option.WithBaseURL(baseURL),
|
option.WithBaseURL(baseURL),
|
||||||
)
|
)
|
||||||
_, err := client.Tui.ShowToast(context.TODO(), opencode.TuiShowToastParams{
|
_, err := client.Tui.ShowToast(context.TODO(), opencode.TuiShowToastParams{
|
||||||
Message: opencode.F("message"),
|
Message: opencode.F("message"),
|
||||||
Variant: opencode.F(opencode.TuiShowToastParamsVariantInfo),
|
Variant: opencode.F(opencode.TuiShowToastParamsVariantInfo),
|
||||||
Title: opencode.F("title"),
|
Directory: opencode.F("directory"),
|
||||||
|
Title: opencode.F("title"),
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
var apierr *opencode.Error
|
var apierr *opencode.Error
|
||||||
@@ -197,8 +210,8 @@ func TestTuiShowToastWithOptionalParams(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestTuiSubmitPrompt(t *testing.T) {
|
func TestTuiSubmitPromptWithOptionalParams(t *testing.T) {
|
||||||
t.Skip("skipped: tests are disabled for the time being")
|
t.Skip("Prism tests are disabled")
|
||||||
baseURL := "http://localhost:4010"
|
baseURL := "http://localhost:4010"
|
||||||
if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
|
if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
|
||||||
baseURL = envURL
|
baseURL = envURL
|
||||||
@@ -209,7 +222,9 @@ func TestTuiSubmitPrompt(t *testing.T) {
|
|||||||
client := opencode.NewClient(
|
client := opencode.NewClient(
|
||||||
option.WithBaseURL(baseURL),
|
option.WithBaseURL(baseURL),
|
||||||
)
|
)
|
||||||
_, err := client.Tui.SubmitPrompt(context.TODO())
|
_, err := client.Tui.SubmitPrompt(context.TODO(), opencode.TuiSubmitPromptParams{
|
||||||
|
Directory: opencode.F("directory"),
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
var apierr *opencode.Error
|
var apierr *opencode.Error
|
||||||
if errors.As(err, &apierr) {
|
if errors.As(err, &apierr) {
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ func TestUsage(t *testing.T) {
|
|||||||
client := opencode.NewClient(
|
client := opencode.NewClient(
|
||||||
option.WithBaseURL(baseURL),
|
option.WithBaseURL(baseURL),
|
||||||
)
|
)
|
||||||
sessions, err := client.Session.List(context.TODO())
|
sessions, err := client.Session.List(context.TODO(), opencode.SessionListParams{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -2,14 +2,16 @@
|
|||||||
|
|
||||||
import type { Options as ClientOptions, TDataShape, Client } from "./client/index.js"
|
import type { Options as ClientOptions, TDataShape, Client } from "./client/index.js"
|
||||||
import type {
|
import type {
|
||||||
|
ProjectListData,
|
||||||
|
ProjectListResponses,
|
||||||
|
ProjectCurrentData,
|
||||||
|
ProjectCurrentResponses,
|
||||||
EventSubscribeData,
|
EventSubscribeData,
|
||||||
EventSubscribeResponses,
|
EventSubscribeResponses,
|
||||||
AppGetData,
|
|
||||||
AppGetResponses,
|
|
||||||
AppInitData,
|
|
||||||
AppInitResponses,
|
|
||||||
ConfigGetData,
|
ConfigGetData,
|
||||||
ConfigGetResponses,
|
ConfigGetResponses,
|
||||||
|
PathGetData,
|
||||||
|
PathGetResponses,
|
||||||
SessionListData,
|
SessionListData,
|
||||||
SessionListResponses,
|
SessionListResponses,
|
||||||
SessionCreateData,
|
SessionCreateData,
|
||||||
@@ -35,8 +37,8 @@ import type {
|
|||||||
SessionSummarizeResponses,
|
SessionSummarizeResponses,
|
||||||
SessionMessagesData,
|
SessionMessagesData,
|
||||||
SessionMessagesResponses,
|
SessionMessagesResponses,
|
||||||
SessionChatData,
|
SessionPromptData,
|
||||||
SessionChatResponses,
|
SessionPromptResponses,
|
||||||
SessionMessageData,
|
SessionMessageData,
|
||||||
SessionMessageResponses,
|
SessionMessageResponses,
|
||||||
SessionCommandData,
|
SessionCommandData,
|
||||||
@@ -120,6 +122,28 @@ class _HeyApiClient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class Project extends _HeyApiClient {
|
||||||
|
/**
|
||||||
|
* List all projects
|
||||||
|
*/
|
||||||
|
public list<ThrowOnError extends boolean = false>(options?: Options<ProjectListData, ThrowOnError>) {
|
||||||
|
return (options?.client ?? this._client).get<ProjectListResponses, unknown, ThrowOnError>({
|
||||||
|
url: "/project",
|
||||||
|
...options,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the current project
|
||||||
|
*/
|
||||||
|
public current<ThrowOnError extends boolean = false>(options?: Options<ProjectCurrentData, ThrowOnError>) {
|
||||||
|
return (options?.client ?? this._client).get<ProjectCurrentResponses, unknown, ThrowOnError>({
|
||||||
|
url: "/project/current",
|
||||||
|
...options,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class Event extends _HeyApiClient {
|
class Event extends _HeyApiClient {
|
||||||
/**
|
/**
|
||||||
* Get events
|
* Get events
|
||||||
@@ -132,52 +156,6 @@ class Event extends _HeyApiClient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class App extends _HeyApiClient {
|
|
||||||
/**
|
|
||||||
* Get app info
|
|
||||||
*/
|
|
||||||
public get<ThrowOnError extends boolean = false>(options?: Options<AppGetData, ThrowOnError>) {
|
|
||||||
return (options?.client ?? this._client).get<AppGetResponses, unknown, ThrowOnError>({
|
|
||||||
url: "/app",
|
|
||||||
...options,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize the app
|
|
||||||
*/
|
|
||||||
public init<ThrowOnError extends boolean = false>(options?: Options<AppInitData, ThrowOnError>) {
|
|
||||||
return (options?.client ?? this._client).post<AppInitResponses, unknown, ThrowOnError>({
|
|
||||||
url: "/app/init",
|
|
||||||
...options,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Write a log entry to the server logs
|
|
||||||
*/
|
|
||||||
public log<ThrowOnError extends boolean = false>(options?: Options<AppLogData, ThrowOnError>) {
|
|
||||||
return (options?.client ?? this._client).post<AppLogResponses, unknown, ThrowOnError>({
|
|
||||||
url: "/log",
|
|
||||||
...options,
|
|
||||||
headers: {
|
|
||||||
"Content-Type": "application/json",
|
|
||||||
...options?.headers,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* List all agents
|
|
||||||
*/
|
|
||||||
public agents<ThrowOnError extends boolean = false>(options?: Options<AppAgentsData, ThrowOnError>) {
|
|
||||||
return (options?.client ?? this._client).get<AppAgentsResponses, unknown, ThrowOnError>({
|
|
||||||
url: "/agent",
|
|
||||||
...options,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class Config extends _HeyApiClient {
|
class Config extends _HeyApiClient {
|
||||||
/**
|
/**
|
||||||
* Get config info
|
* Get config info
|
||||||
@@ -200,6 +178,18 @@ class Config extends _HeyApiClient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class Path extends _HeyApiClient {
|
||||||
|
/**
|
||||||
|
* Get the current path
|
||||||
|
*/
|
||||||
|
public get<ThrowOnError extends boolean = false>(options?: Options<PathGetData, ThrowOnError>) {
|
||||||
|
return (options?.client ?? this._client).get<PathGetResponses, unknown, ThrowOnError>({
|
||||||
|
url: "/path",
|
||||||
|
...options,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class Session extends _HeyApiClient {
|
class Session extends _HeyApiClient {
|
||||||
/**
|
/**
|
||||||
* List all sessions
|
* List all sessions
|
||||||
@@ -340,8 +330,8 @@ class Session extends _HeyApiClient {
|
|||||||
/**
|
/**
|
||||||
* Create and send a new message to a session
|
* Create and send a new message to a session
|
||||||
*/
|
*/
|
||||||
public chat<ThrowOnError extends boolean = false>(options: Options<SessionChatData, ThrowOnError>) {
|
public prompt<ThrowOnError extends boolean = false>(options: Options<SessionPromptData, ThrowOnError>) {
|
||||||
return (options.client ?? this._client).post<SessionChatResponses, unknown, ThrowOnError>({
|
return (options.client ?? this._client).post<SessionPromptResponses, unknown, ThrowOnError>({
|
||||||
url: "/session/{id}/message",
|
url: "/session/{id}/message",
|
||||||
...options,
|
...options,
|
||||||
headers: {
|
headers: {
|
||||||
@@ -490,6 +480,32 @@ class File extends _HeyApiClient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class App extends _HeyApiClient {
|
||||||
|
/**
|
||||||
|
* Write a log entry to the server logs
|
||||||
|
*/
|
||||||
|
public log<ThrowOnError extends boolean = false>(options?: Options<AppLogData, ThrowOnError>) {
|
||||||
|
return (options?.client ?? this._client).post<AppLogResponses, unknown, ThrowOnError>({
|
||||||
|
url: "/log",
|
||||||
|
...options,
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
...options?.headers,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List all agents
|
||||||
|
*/
|
||||||
|
public agents<ThrowOnError extends boolean = false>(options?: Options<AppAgentsData, ThrowOnError>) {
|
||||||
|
return (options?.client ?? this._client).get<AppAgentsResponses, unknown, ThrowOnError>({
|
||||||
|
url: "/agent",
|
||||||
|
...options,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class Tui extends _HeyApiClient {
|
class Tui extends _HeyApiClient {
|
||||||
/**
|
/**
|
||||||
* Append prompt to the TUI
|
* Append prompt to the TUI
|
||||||
@@ -630,13 +646,15 @@ export class OpencodeClient extends _HeyApiClient {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
project = new Project({ client: this._client })
|
||||||
event = new Event({ client: this._client })
|
event = new Event({ client: this._client })
|
||||||
app = new App({ client: this._client })
|
|
||||||
config = new Config({ client: this._client })
|
config = new Config({ client: this._client })
|
||||||
|
path = new Path({ client: this._client })
|
||||||
session = new Session({ client: this._client })
|
session = new Session({ client: this._client })
|
||||||
command = new Command({ client: this._client })
|
command = new Command({ client: this._client })
|
||||||
find = new Find({ client: this._client })
|
find = new Find({ client: this._client })
|
||||||
file = new File({ client: this._client })
|
file = new File({ client: this._client })
|
||||||
|
app = new App({ client: this._client })
|
||||||
tui = new Tui({ client: this._client })
|
tui = new Tui({ client: this._client })
|
||||||
auth = new Auth({ client: this._client })
|
auth = new Auth({ client: this._client })
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,15 @@
|
|||||||
// This file is auto-generated by @hey-api/openapi-ts
|
// This file is auto-generated by @hey-api/openapi-ts
|
||||||
|
|
||||||
|
export type Project = {
|
||||||
|
id: string
|
||||||
|
worktree: string
|
||||||
|
vcs?: "git"
|
||||||
|
time: {
|
||||||
|
created: number
|
||||||
|
initialized?: number
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export type Event =
|
export type Event =
|
||||||
| ({
|
| ({
|
||||||
type: "installation.updated"
|
type: "installation.updated"
|
||||||
@@ -19,9 +29,6 @@ export type Event =
|
|||||||
| ({
|
| ({
|
||||||
type: "message.part.removed"
|
type: "message.part.removed"
|
||||||
} & EventMessagePartRemoved)
|
} & EventMessagePartRemoved)
|
||||||
| ({
|
|
||||||
type: "storage.write"
|
|
||||||
} & EventStorageWrite)
|
|
||||||
| ({
|
| ({
|
||||||
type: "permission.updated"
|
type: "permission.updated"
|
||||||
} & EventPermissionUpdated)
|
} & EventPermissionUpdated)
|
||||||
@@ -46,12 +53,6 @@ export type Event =
|
|||||||
| ({
|
| ({
|
||||||
type: "server.connected"
|
type: "server.connected"
|
||||||
} & EventServerConnected)
|
} & EventServerConnected)
|
||||||
| ({
|
|
||||||
type: "file.watcher.updated"
|
|
||||||
} & EventFileWatcherUpdated)
|
|
||||||
| ({
|
|
||||||
type: "ide.installed"
|
|
||||||
} & EventIdeInstalled)
|
|
||||||
|
|
||||||
export type EventInstallationUpdated = {
|
export type EventInstallationUpdated = {
|
||||||
type: "installation.updated"
|
type: "installation.updated"
|
||||||
@@ -420,14 +421,6 @@ export type EventMessagePartRemoved = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export type EventStorageWrite = {
|
|
||||||
type: "storage.write"
|
|
||||||
properties: {
|
|
||||||
key: string
|
|
||||||
content?: unknown
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export type EventPermissionUpdated = {
|
export type EventPermissionUpdated = {
|
||||||
type: "permission.updated"
|
type: "permission.updated"
|
||||||
properties: Permission
|
properties: Permission
|
||||||
@@ -474,6 +467,8 @@ export type EventSessionUpdated = {
|
|||||||
|
|
||||||
export type Session = {
|
export type Session = {
|
||||||
id: string
|
id: string
|
||||||
|
projectID: string
|
||||||
|
directory: string
|
||||||
parentID?: string
|
parentID?: string
|
||||||
share?: {
|
share?: {
|
||||||
url: string
|
url: string
|
||||||
@@ -533,37 +528,6 @@ export type EventServerConnected = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export type EventFileWatcherUpdated = {
|
|
||||||
type: "file.watcher.updated"
|
|
||||||
properties: {
|
|
||||||
file: string
|
|
||||||
event: "rename" | "change"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export type EventIdeInstalled = {
|
|
||||||
type: "ide.installed"
|
|
||||||
properties: {
|
|
||||||
ide: string
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export type App = {
|
|
||||||
hostname: string
|
|
||||||
git: boolean
|
|
||||||
path: {
|
|
||||||
home: string
|
|
||||||
config: string
|
|
||||||
data: string
|
|
||||||
root: string
|
|
||||||
cwd: string
|
|
||||||
state: string
|
|
||||||
}
|
|
||||||
time: {
|
|
||||||
initialized?: number
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export type Config = {
|
export type Config = {
|
||||||
/**
|
/**
|
||||||
* JSON schema reference for configuration validation
|
* JSON schema reference for configuration validation
|
||||||
@@ -681,7 +645,11 @@ export type Config = {
|
|||||||
options?: {
|
options?: {
|
||||||
apiKey?: string
|
apiKey?: string
|
||||||
baseURL?: string
|
baseURL?: string
|
||||||
[key: string]: unknown | string | undefined
|
/**
|
||||||
|
* Timeout in milliseconds for requests to this provider. Default is 300000 (5 minutes). Set to false to disable timeout.
|
||||||
|
*/
|
||||||
|
timeout?: number | false
|
||||||
|
[key: string]: unknown | string | (number | false) | undefined
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1085,6 +1053,13 @@ export type McpRemoteConfig = {
|
|||||||
|
|
||||||
export type LayoutConfig = "auto" | "stretch"
|
export type LayoutConfig = "auto" | "stretch"
|
||||||
|
|
||||||
|
export type Path = {
|
||||||
|
state: string
|
||||||
|
config: string
|
||||||
|
worktree: string
|
||||||
|
directory: string
|
||||||
|
}
|
||||||
|
|
||||||
export type _Error = {
|
export type _Error = {
|
||||||
data: {
|
data: {
|
||||||
[key: string]: unknown
|
[key: string]: unknown
|
||||||
@@ -1209,10 +1184,48 @@ export type WellKnownAuth = {
|
|||||||
token: string
|
token: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type ProjectListData = {
|
||||||
|
body?: never
|
||||||
|
path?: never
|
||||||
|
query?: {
|
||||||
|
directory?: string
|
||||||
|
}
|
||||||
|
url: "/project"
|
||||||
|
}
|
||||||
|
|
||||||
|
export type ProjectListResponses = {
|
||||||
|
/**
|
||||||
|
* List of projects
|
||||||
|
*/
|
||||||
|
200: Array<Project>
|
||||||
|
}
|
||||||
|
|
||||||
|
export type ProjectListResponse = ProjectListResponses[keyof ProjectListResponses]
|
||||||
|
|
||||||
|
export type ProjectCurrentData = {
|
||||||
|
body?: never
|
||||||
|
path?: never
|
||||||
|
query?: {
|
||||||
|
directory?: string
|
||||||
|
}
|
||||||
|
url: "/project/current"
|
||||||
|
}
|
||||||
|
|
||||||
|
export type ProjectCurrentResponses = {
|
||||||
|
/**
|
||||||
|
* Current project
|
||||||
|
*/
|
||||||
|
200: Project
|
||||||
|
}
|
||||||
|
|
||||||
|
export type ProjectCurrentResponse = ProjectCurrentResponses[keyof ProjectCurrentResponses]
|
||||||
|
|
||||||
export type EventSubscribeData = {
|
export type EventSubscribeData = {
|
||||||
body?: never
|
body?: never
|
||||||
path?: never
|
path?: never
|
||||||
query?: never
|
query?: {
|
||||||
|
directory?: string
|
||||||
|
}
|
||||||
url: "/event"
|
url: "/event"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1225,42 +1238,12 @@ export type EventSubscribeResponses = {
|
|||||||
|
|
||||||
export type EventSubscribeResponse = EventSubscribeResponses[keyof EventSubscribeResponses]
|
export type EventSubscribeResponse = EventSubscribeResponses[keyof EventSubscribeResponses]
|
||||||
|
|
||||||
export type AppGetData = {
|
|
||||||
body?: never
|
|
||||||
path?: never
|
|
||||||
query?: never
|
|
||||||
url: "/app"
|
|
||||||
}
|
|
||||||
|
|
||||||
export type AppGetResponses = {
|
|
||||||
/**
|
|
||||||
* 200
|
|
||||||
*/
|
|
||||||
200: App
|
|
||||||
}
|
|
||||||
|
|
||||||
export type AppGetResponse = AppGetResponses[keyof AppGetResponses]
|
|
||||||
|
|
||||||
export type AppInitData = {
|
|
||||||
body?: never
|
|
||||||
path?: never
|
|
||||||
query?: never
|
|
||||||
url: "/app/init"
|
|
||||||
}
|
|
||||||
|
|
||||||
export type AppInitResponses = {
|
|
||||||
/**
|
|
||||||
* Initialize the app
|
|
||||||
*/
|
|
||||||
200: boolean
|
|
||||||
}
|
|
||||||
|
|
||||||
export type AppInitResponse = AppInitResponses[keyof AppInitResponses]
|
|
||||||
|
|
||||||
export type ConfigGetData = {
|
export type ConfigGetData = {
|
||||||
body?: never
|
body?: never
|
||||||
path?: never
|
path?: never
|
||||||
query?: never
|
query?: {
|
||||||
|
directory?: string
|
||||||
|
}
|
||||||
url: "/config"
|
url: "/config"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1273,10 +1256,30 @@ export type ConfigGetResponses = {
|
|||||||
|
|
||||||
export type ConfigGetResponse = ConfigGetResponses[keyof ConfigGetResponses]
|
export type ConfigGetResponse = ConfigGetResponses[keyof ConfigGetResponses]
|
||||||
|
|
||||||
|
export type PathGetData = {
|
||||||
|
body?: never
|
||||||
|
path?: never
|
||||||
|
query?: {
|
||||||
|
directory?: string
|
||||||
|
}
|
||||||
|
url: "/path"
|
||||||
|
}
|
||||||
|
|
||||||
|
export type PathGetResponses = {
|
||||||
|
/**
|
||||||
|
* Path
|
||||||
|
*/
|
||||||
|
200: Path
|
||||||
|
}
|
||||||
|
|
||||||
|
export type PathGetResponse = PathGetResponses[keyof PathGetResponses]
|
||||||
|
|
||||||
export type SessionListData = {
|
export type SessionListData = {
|
||||||
body?: never
|
body?: never
|
||||||
path?: never
|
path?: never
|
||||||
query?: never
|
query?: {
|
||||||
|
directory?: string
|
||||||
|
}
|
||||||
url: "/session"
|
url: "/session"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1295,7 +1298,9 @@ export type SessionCreateData = {
|
|||||||
title?: string
|
title?: string
|
||||||
}
|
}
|
||||||
path?: never
|
path?: never
|
||||||
query?: never
|
query?: {
|
||||||
|
directory?: string
|
||||||
|
}
|
||||||
url: "/session"
|
url: "/session"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1322,7 +1327,9 @@ export type SessionDeleteData = {
|
|||||||
path: {
|
path: {
|
||||||
id: string
|
id: string
|
||||||
}
|
}
|
||||||
query?: never
|
query?: {
|
||||||
|
directory?: string
|
||||||
|
}
|
||||||
url: "/session/{id}"
|
url: "/session/{id}"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1340,7 +1347,9 @@ export type SessionGetData = {
|
|||||||
path: {
|
path: {
|
||||||
id: string
|
id: string
|
||||||
}
|
}
|
||||||
query?: never
|
query?: {
|
||||||
|
directory?: string
|
||||||
|
}
|
||||||
url: "/session/{id}"
|
url: "/session/{id}"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1360,7 +1369,9 @@ export type SessionUpdateData = {
|
|||||||
path: {
|
path: {
|
||||||
id: string
|
id: string
|
||||||
}
|
}
|
||||||
query?: never
|
query?: {
|
||||||
|
directory?: string
|
||||||
|
}
|
||||||
url: "/session/{id}"
|
url: "/session/{id}"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1378,7 +1389,9 @@ export type SessionChildrenData = {
|
|||||||
path: {
|
path: {
|
||||||
id: string
|
id: string
|
||||||
}
|
}
|
||||||
query?: never
|
query?: {
|
||||||
|
directory?: string
|
||||||
|
}
|
||||||
url: "/session/{id}/children"
|
url: "/session/{id}/children"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1403,7 +1416,9 @@ export type SessionInitData = {
|
|||||||
*/
|
*/
|
||||||
id: string
|
id: string
|
||||||
}
|
}
|
||||||
query?: never
|
query?: {
|
||||||
|
directory?: string
|
||||||
|
}
|
||||||
url: "/session/{id}/init"
|
url: "/session/{id}/init"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1421,7 +1436,9 @@ export type SessionAbortData = {
|
|||||||
path: {
|
path: {
|
||||||
id: string
|
id: string
|
||||||
}
|
}
|
||||||
query?: never
|
query?: {
|
||||||
|
directory?: string
|
||||||
|
}
|
||||||
url: "/session/{id}/abort"
|
url: "/session/{id}/abort"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1439,7 +1456,9 @@ export type SessionUnshareData = {
|
|||||||
path: {
|
path: {
|
||||||
id: string
|
id: string
|
||||||
}
|
}
|
||||||
query?: never
|
query?: {
|
||||||
|
directory?: string
|
||||||
|
}
|
||||||
url: "/session/{id}/share"
|
url: "/session/{id}/share"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1457,7 +1476,9 @@ export type SessionShareData = {
|
|||||||
path: {
|
path: {
|
||||||
id: string
|
id: string
|
||||||
}
|
}
|
||||||
query?: never
|
query?: {
|
||||||
|
directory?: string
|
||||||
|
}
|
||||||
url: "/session/{id}/share"
|
url: "/session/{id}/share"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1481,7 +1502,9 @@ export type SessionSummarizeData = {
|
|||||||
*/
|
*/
|
||||||
id: string
|
id: string
|
||||||
}
|
}
|
||||||
query?: never
|
query?: {
|
||||||
|
directory?: string
|
||||||
|
}
|
||||||
url: "/session/{id}/summarize"
|
url: "/session/{id}/summarize"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1502,7 +1525,9 @@ export type SessionMessagesData = {
|
|||||||
*/
|
*/
|
||||||
id: string
|
id: string
|
||||||
}
|
}
|
||||||
query?: never
|
query?: {
|
||||||
|
directory?: string
|
||||||
|
}
|
||||||
url: "/session/{id}/message"
|
url: "/session/{id}/message"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1518,11 +1543,13 @@ export type SessionMessagesResponses = {
|
|||||||
|
|
||||||
export type SessionMessagesResponse = SessionMessagesResponses[keyof SessionMessagesResponses]
|
export type SessionMessagesResponse = SessionMessagesResponses[keyof SessionMessagesResponses]
|
||||||
|
|
||||||
export type SessionChatData = {
|
export type SessionPromptData = {
|
||||||
body?: {
|
body?: {
|
||||||
messageID?: string
|
messageID?: string
|
||||||
providerID: string
|
model?: {
|
||||||
modelID: string
|
providerID: string
|
||||||
|
modelID: string
|
||||||
|
}
|
||||||
agent?: string
|
agent?: string
|
||||||
system?: string
|
system?: string
|
||||||
tools?: {
|
tools?: {
|
||||||
@@ -1546,11 +1573,13 @@ export type SessionChatData = {
|
|||||||
*/
|
*/
|
||||||
id: string
|
id: string
|
||||||
}
|
}
|
||||||
query?: never
|
query?: {
|
||||||
|
directory?: string
|
||||||
|
}
|
||||||
url: "/session/{id}/message"
|
url: "/session/{id}/message"
|
||||||
}
|
}
|
||||||
|
|
||||||
export type SessionChatResponses = {
|
export type SessionPromptResponses = {
|
||||||
/**
|
/**
|
||||||
* Created message
|
* Created message
|
||||||
*/
|
*/
|
||||||
@@ -1560,7 +1589,7 @@ export type SessionChatResponses = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export type SessionChatResponse = SessionChatResponses[keyof SessionChatResponses]
|
export type SessionPromptResponse = SessionPromptResponses[keyof SessionPromptResponses]
|
||||||
|
|
||||||
export type SessionMessageData = {
|
export type SessionMessageData = {
|
||||||
body?: never
|
body?: never
|
||||||
@@ -1574,7 +1603,9 @@ export type SessionMessageData = {
|
|||||||
*/
|
*/
|
||||||
messageID: string
|
messageID: string
|
||||||
}
|
}
|
||||||
query?: never
|
query?: {
|
||||||
|
directory?: string
|
||||||
|
}
|
||||||
url: "/session/{id}/message/{messageID}"
|
url: "/session/{id}/message/{messageID}"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1604,7 +1635,9 @@ export type SessionCommandData = {
|
|||||||
*/
|
*/
|
||||||
id: string
|
id: string
|
||||||
}
|
}
|
||||||
query?: never
|
query?: {
|
||||||
|
directory?: string
|
||||||
|
}
|
||||||
url: "/session/{id}/command"
|
url: "/session/{id}/command"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1631,7 +1664,9 @@ export type SessionShellData = {
|
|||||||
*/
|
*/
|
||||||
id: string
|
id: string
|
||||||
}
|
}
|
||||||
query?: never
|
query?: {
|
||||||
|
directory?: string
|
||||||
|
}
|
||||||
url: "/session/{id}/shell"
|
url: "/session/{id}/shell"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1652,7 +1687,9 @@ export type SessionRevertData = {
|
|||||||
path: {
|
path: {
|
||||||
id: string
|
id: string
|
||||||
}
|
}
|
||||||
query?: never
|
query?: {
|
||||||
|
directory?: string
|
||||||
|
}
|
||||||
url: "/session/{id}/revert"
|
url: "/session/{id}/revert"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1670,7 +1707,9 @@ export type SessionUnrevertData = {
|
|||||||
path: {
|
path: {
|
||||||
id: string
|
id: string
|
||||||
}
|
}
|
||||||
query?: never
|
query?: {
|
||||||
|
directory?: string
|
||||||
|
}
|
||||||
url: "/session/{id}/unrevert"
|
url: "/session/{id}/unrevert"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1691,7 +1730,9 @@ export type PostSessionByIdPermissionsByPermissionIdData = {
|
|||||||
id: string
|
id: string
|
||||||
permissionID: string
|
permissionID: string
|
||||||
}
|
}
|
||||||
query?: never
|
query?: {
|
||||||
|
directory?: string
|
||||||
|
}
|
||||||
url: "/session/{id}/permissions/{permissionID}"
|
url: "/session/{id}/permissions/{permissionID}"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1708,7 +1749,9 @@ export type PostSessionByIdPermissionsByPermissionIdResponse =
|
|||||||
export type CommandListData = {
|
export type CommandListData = {
|
||||||
body?: never
|
body?: never
|
||||||
path?: never
|
path?: never
|
||||||
query?: never
|
query?: {
|
||||||
|
directory?: string
|
||||||
|
}
|
||||||
url: "/command"
|
url: "/command"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1724,7 +1767,9 @@ export type CommandListResponse = CommandListResponses[keyof CommandListResponse
|
|||||||
export type ConfigProvidersData = {
|
export type ConfigProvidersData = {
|
||||||
body?: never
|
body?: never
|
||||||
path?: never
|
path?: never
|
||||||
query?: never
|
query?: {
|
||||||
|
directory?: string
|
||||||
|
}
|
||||||
url: "/config/providers"
|
url: "/config/providers"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1746,6 +1791,7 @@ export type FindTextData = {
|
|||||||
body?: never
|
body?: never
|
||||||
path?: never
|
path?: never
|
||||||
query: {
|
query: {
|
||||||
|
directory?: string
|
||||||
pattern: string
|
pattern: string
|
||||||
}
|
}
|
||||||
url: "/find"
|
url: "/find"
|
||||||
@@ -1780,6 +1826,7 @@ export type FindFilesData = {
|
|||||||
body?: never
|
body?: never
|
||||||
path?: never
|
path?: never
|
||||||
query: {
|
query: {
|
||||||
|
directory?: string
|
||||||
query: string
|
query: string
|
||||||
}
|
}
|
||||||
url: "/find/file"
|
url: "/find/file"
|
||||||
@@ -1798,6 +1845,7 @@ export type FindSymbolsData = {
|
|||||||
body?: never
|
body?: never
|
||||||
path?: never
|
path?: never
|
||||||
query: {
|
query: {
|
||||||
|
directory?: string
|
||||||
query: string
|
query: string
|
||||||
}
|
}
|
||||||
url: "/find/symbol"
|
url: "/find/symbol"
|
||||||
@@ -1816,6 +1864,7 @@ export type FileListData = {
|
|||||||
body?: never
|
body?: never
|
||||||
path?: never
|
path?: never
|
||||||
query: {
|
query: {
|
||||||
|
directory?: string
|
||||||
path: string
|
path: string
|
||||||
}
|
}
|
||||||
url: "/file"
|
url: "/file"
|
||||||
@@ -1834,6 +1883,7 @@ export type FileReadData = {
|
|||||||
body?: never
|
body?: never
|
||||||
path?: never
|
path?: never
|
||||||
query: {
|
query: {
|
||||||
|
directory?: string
|
||||||
path: string
|
path: string
|
||||||
}
|
}
|
||||||
url: "/file/content"
|
url: "/file/content"
|
||||||
@@ -1854,7 +1904,9 @@ export type FileReadResponse = FileReadResponses[keyof FileReadResponses]
|
|||||||
export type FileStatusData = {
|
export type FileStatusData = {
|
||||||
body?: never
|
body?: never
|
||||||
path?: never
|
path?: never
|
||||||
query?: never
|
query?: {
|
||||||
|
directory?: string
|
||||||
|
}
|
||||||
url: "/file/status"
|
url: "/file/status"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1889,7 +1941,9 @@ export type AppLogData = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
path?: never
|
path?: never
|
||||||
query?: never
|
query?: {
|
||||||
|
directory?: string
|
||||||
|
}
|
||||||
url: "/log"
|
url: "/log"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1905,7 +1959,9 @@ export type AppLogResponse = AppLogResponses[keyof AppLogResponses]
|
|||||||
export type AppAgentsData = {
|
export type AppAgentsData = {
|
||||||
body?: never
|
body?: never
|
||||||
path?: never
|
path?: never
|
||||||
query?: never
|
query?: {
|
||||||
|
directory?: string
|
||||||
|
}
|
||||||
url: "/agent"
|
url: "/agent"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1923,7 +1979,9 @@ export type TuiAppendPromptData = {
|
|||||||
text: string
|
text: string
|
||||||
}
|
}
|
||||||
path?: never
|
path?: never
|
||||||
query?: never
|
query?: {
|
||||||
|
directory?: string
|
||||||
|
}
|
||||||
url: "/tui/append-prompt"
|
url: "/tui/append-prompt"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1939,7 +1997,9 @@ export type TuiAppendPromptResponse = TuiAppendPromptResponses[keyof TuiAppendPr
|
|||||||
export type TuiOpenHelpData = {
|
export type TuiOpenHelpData = {
|
||||||
body?: never
|
body?: never
|
||||||
path?: never
|
path?: never
|
||||||
query?: never
|
query?: {
|
||||||
|
directory?: string
|
||||||
|
}
|
||||||
url: "/tui/open-help"
|
url: "/tui/open-help"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1955,7 +2015,9 @@ export type TuiOpenHelpResponse = TuiOpenHelpResponses[keyof TuiOpenHelpResponse
|
|||||||
export type TuiOpenSessionsData = {
|
export type TuiOpenSessionsData = {
|
||||||
body?: never
|
body?: never
|
||||||
path?: never
|
path?: never
|
||||||
query?: never
|
query?: {
|
||||||
|
directory?: string
|
||||||
|
}
|
||||||
url: "/tui/open-sessions"
|
url: "/tui/open-sessions"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1971,7 +2033,9 @@ export type TuiOpenSessionsResponse = TuiOpenSessionsResponses[keyof TuiOpenSess
|
|||||||
export type TuiOpenThemesData = {
|
export type TuiOpenThemesData = {
|
||||||
body?: never
|
body?: never
|
||||||
path?: never
|
path?: never
|
||||||
query?: never
|
query?: {
|
||||||
|
directory?: string
|
||||||
|
}
|
||||||
url: "/tui/open-themes"
|
url: "/tui/open-themes"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1987,7 +2051,9 @@ export type TuiOpenThemesResponse = TuiOpenThemesResponses[keyof TuiOpenThemesRe
|
|||||||
export type TuiOpenModelsData = {
|
export type TuiOpenModelsData = {
|
||||||
body?: never
|
body?: never
|
||||||
path?: never
|
path?: never
|
||||||
query?: never
|
query?: {
|
||||||
|
directory?: string
|
||||||
|
}
|
||||||
url: "/tui/open-models"
|
url: "/tui/open-models"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2003,7 +2069,9 @@ export type TuiOpenModelsResponse = TuiOpenModelsResponses[keyof TuiOpenModelsRe
|
|||||||
export type TuiSubmitPromptData = {
|
export type TuiSubmitPromptData = {
|
||||||
body?: never
|
body?: never
|
||||||
path?: never
|
path?: never
|
||||||
query?: never
|
query?: {
|
||||||
|
directory?: string
|
||||||
|
}
|
||||||
url: "/tui/submit-prompt"
|
url: "/tui/submit-prompt"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2019,7 +2087,9 @@ export type TuiSubmitPromptResponse = TuiSubmitPromptResponses[keyof TuiSubmitPr
|
|||||||
export type TuiClearPromptData = {
|
export type TuiClearPromptData = {
|
||||||
body?: never
|
body?: never
|
||||||
path?: never
|
path?: never
|
||||||
query?: never
|
query?: {
|
||||||
|
directory?: string
|
||||||
|
}
|
||||||
url: "/tui/clear-prompt"
|
url: "/tui/clear-prompt"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2037,7 +2107,9 @@ export type TuiExecuteCommandData = {
|
|||||||
command: string
|
command: string
|
||||||
}
|
}
|
||||||
path?: never
|
path?: never
|
||||||
query?: never
|
query?: {
|
||||||
|
directory?: string
|
||||||
|
}
|
||||||
url: "/tui/execute-command"
|
url: "/tui/execute-command"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2057,7 +2129,9 @@ export type TuiShowToastData = {
|
|||||||
variant: "info" | "success" | "warning" | "error"
|
variant: "info" | "success" | "warning" | "error"
|
||||||
}
|
}
|
||||||
path?: never
|
path?: never
|
||||||
query?: never
|
query?: {
|
||||||
|
directory?: string
|
||||||
|
}
|
||||||
url: "/tui/show-toast"
|
url: "/tui/show-toast"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2075,7 +2149,9 @@ export type AuthSetData = {
|
|||||||
path: {
|
path: {
|
||||||
id: string
|
id: string
|
||||||
}
|
}
|
||||||
query?: never
|
query?: {
|
||||||
|
directory?: string
|
||||||
|
}
|
||||||
url: "/auth/{id}"
|
url: "/auth/{id}"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ console.log(process.cwd())
|
|||||||
|
|
||||||
await $`rm -rf go`
|
await $`rm -rf go`
|
||||||
await $`bun run --conditions=development ../../opencode/src/index.ts generate > openapi.json`
|
await $`bun run --conditions=development ../../opencode/src/index.ts generate > openapi.json`
|
||||||
await $`stl builds create --branch dev --pull --allow-empty --+target go`
|
await $`stl builds create --branch main --pull --allow-empty --+target go`
|
||||||
|
|
||||||
await $`rm -rf ../go`
|
await $`rm -rf ../go`
|
||||||
await $`mv opencode-go/ ../go`
|
await $`mv opencode-go/ ../go`
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user