Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c2f487906a | ||
|
|
ae78ec7a0c | ||
|
|
e8c03f13dd | ||
|
|
f85d30c484 | ||
|
|
1bac46612c | ||
|
|
9ab3462821 | ||
|
|
3b36822696 | ||
|
|
5b731479d5 | ||
|
|
a50bef6913 | ||
|
|
ed397c5057 | ||
|
|
c9187a9f3a | ||
|
|
2c67b26b5d | ||
|
|
170b94a99e | ||
|
|
cd58f10e3c | ||
|
|
ea85fdf3cd | ||
|
|
edda26ab33 | ||
|
|
ea4e1913c0 | ||
|
|
5eebc8ab51 | ||
|
|
21c52fd5cb | ||
|
|
5e8634afaf | ||
|
|
d4bac5cdbd | ||
|
|
263b266476 | ||
|
|
06830327e7 | ||
|
|
4b204fee58 | ||
|
|
99d3a0bb24 | ||
|
|
0930f6ac55 | ||
|
|
24515162fa |
@@ -0,0 +1,24 @@
|
||||
name: Typecheck
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches: [dev]
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
typecheck:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Bun
|
||||
uses: oven-sh/setup-bun@v1
|
||||
with:
|
||||
bun-version: 1.2.19
|
||||
|
||||
- name: Install dependencies
|
||||
run: bun install
|
||||
|
||||
- name: Run typecheck
|
||||
run: bun typecheck
|
||||
+1
-1
@@ -5,4 +5,4 @@ node_modules
|
||||
.idea
|
||||
.vscode
|
||||
openapi.json
|
||||
scratch
|
||||
playground
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
import { Plugin } from "./index"
|
||||
|
||||
export const ExamplePlugin: Plugin = async ({ app, client, $ }) => {
|
||||
return {
|
||||
permission: {},
|
||||
async "chat.params"(input, output) {
|
||||
output.topP = 1
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -37,3 +37,4 @@
|
||||
| 2025-08-01 | 123,539 (+5,200) | 146,680 (+3,336) | 270,219 (+8,536) |
|
||||
| 2025-08-02 | 127,864 (+4,325) | 149,236 (+2,556) | 277,100 (+6,881) |
|
||||
| 2025-08-03 | 131,397 (+3,533) | 150,451 (+1,215) | 281,848 (+4,748) |
|
||||
| 2025-08-04 | 136,266 (+4,869) | 153,260 (+2,809) | 289,526 (+7,678) |
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
},
|
||||
"packages/function": {
|
||||
"name": "@opencode/function",
|
||||
"version": "0.3.113",
|
||||
"version": "0.3.126",
|
||||
"dependencies": {
|
||||
"@octokit/auth-app": "8.0.1",
|
||||
"@octokit/rest": "22.0.0",
|
||||
@@ -25,7 +25,7 @@
|
||||
},
|
||||
"packages/opencode": {
|
||||
"name": "opencode",
|
||||
"version": "0.3.113",
|
||||
"version": "0.3.126",
|
||||
"bin": {
|
||||
"opencode": "./bin/opencode",
|
||||
},
|
||||
@@ -78,7 +78,7 @@
|
||||
},
|
||||
"packages/plugin": {
|
||||
"name": "@opencode-ai/plugin",
|
||||
"version": "0.3.113",
|
||||
"version": "0.3.126",
|
||||
"devDependencies": {
|
||||
"@hey-api/openapi-ts": "0.80.1",
|
||||
"@opencode-ai/sdk": "workspace:*",
|
||||
@@ -88,7 +88,7 @@
|
||||
},
|
||||
"packages/sdk/js": {
|
||||
"name": "@opencode-ai/sdk",
|
||||
"version": "0.3.113",
|
||||
"version": "0.3.126",
|
||||
"devDependencies": {
|
||||
"@hey-api/openapi-ts": "0.80.1",
|
||||
"@tsconfig/node22": "catalog:",
|
||||
@@ -97,7 +97,7 @@
|
||||
},
|
||||
"packages/web": {
|
||||
"name": "@opencode/web",
|
||||
"version": "0.3.113",
|
||||
"version": "0.3.126",
|
||||
"dependencies": {
|
||||
"@astrojs/cloudflare": "^12.5.4",
|
||||
"@astrojs/markdown-remark": "6.3.1",
|
||||
@@ -132,6 +132,9 @@
|
||||
"sharp",
|
||||
"esbuild",
|
||||
],
|
||||
"patchedDependencies": {
|
||||
"marked-shiki@1.2.0": "patches/marked-shiki@1.2.0.patch",
|
||||
},
|
||||
"catalog": {
|
||||
"@tsconfig/node22": "22.0.2",
|
||||
"@types/node": "22.13.9",
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
{
|
||||
"$schema": "https://opencode.ai/config.json",
|
||||
"plugin": ["./packages/plugin/src/example.ts"],
|
||||
"mcp": {
|
||||
"context7": {
|
||||
"type": "remote",
|
||||
|
||||
+4
-2
@@ -5,7 +5,7 @@
|
||||
"type": "module",
|
||||
"packageManager": "bun@1.2.14",
|
||||
"scripts": {
|
||||
"dev": "bun run packages/opencode/src/index.ts",
|
||||
"dev": "bun run --conditions=development packages/opencode/src/index.ts",
|
||||
"typecheck": "bun run --filter='*' typecheck",
|
||||
"stainless": "./scripts/stainless",
|
||||
"postinstall": "./script/hooks"
|
||||
@@ -43,5 +43,7 @@
|
||||
"protobufjs",
|
||||
"sharp"
|
||||
],
|
||||
"patchedDependencies": {}
|
||||
"patchedDependencies": {
|
||||
"marked-shiki@1.2.0": "patches/marked-shiki@1.2.0.patch"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@opencode/function",
|
||||
"version": "0.3.113",
|
||||
"version": "0.3.126",
|
||||
"$schema": "https://json.schemastore.org/package.json",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/package.json",
|
||||
"version": "0.3.113",
|
||||
"version": "0.3.126",
|
||||
"name": "opencode",
|
||||
"type": "module",
|
||||
"private": true,
|
||||
|
||||
@@ -93,6 +93,14 @@ export namespace Config {
|
||||
throw new InvalidError({ path: item }, { cause: parsed.error })
|
||||
}
|
||||
|
||||
result.plugin = result.plugin || []
|
||||
result.plugin.push(
|
||||
...[
|
||||
...(await Filesystem.globUp("plugin/*.ts", Global.Path.config, Global.Path.config)),
|
||||
...(await Filesystem.globUp(".opencode/plugin/*.ts", app.path.cwd, app.path.root)),
|
||||
].map((x) => "file://" + x),
|
||||
)
|
||||
|
||||
// Handle migration from autoshare to share field
|
||||
if (result.autoshare === true && !result.share) {
|
||||
result.share = "auto"
|
||||
@@ -449,9 +457,9 @@ export namespace Config {
|
||||
if (data.plugin) {
|
||||
for (let i = 0; i < data.plugin?.length; i++) {
|
||||
const plugin = data.plugin[i]
|
||||
if (typeof plugin === "string") {
|
||||
data.plugin[i] = path.resolve(path.dirname(filepath), plugin)
|
||||
}
|
||||
try {
|
||||
data.plugin[i] = import.meta.resolve(plugin, filepath)
|
||||
} catch (err) {}
|
||||
}
|
||||
}
|
||||
return data
|
||||
|
||||
@@ -83,6 +83,7 @@ const cli = yargs(hideBin(process.argv))
|
||||
if (msg.startsWith("Unknown argument") || msg.startsWith("Not enough non-option arguments")) {
|
||||
cli.showHelp("log")
|
||||
}
|
||||
process.exit(1)
|
||||
})
|
||||
.strict()
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ import { Bus } from "../bus"
|
||||
import { Log } from "../util/log"
|
||||
import { createOpencodeClient } from "@opencode-ai/sdk"
|
||||
import { Server } from "../server/server"
|
||||
import { pathOr } from "remeda"
|
||||
import { BunProc } from "../bun"
|
||||
|
||||
export namespace Plugin {
|
||||
const log = Log.create({ service: "plugin" })
|
||||
@@ -17,8 +17,12 @@ export namespace Plugin {
|
||||
})
|
||||
const config = await Config.get()
|
||||
const hooks = []
|
||||
for (const plugin of config.plugin ?? []) {
|
||||
for (let plugin of config.plugin ?? []) {
|
||||
log.info("loading plugin", { path: plugin })
|
||||
if (!plugin.startsWith("file://")) {
|
||||
const [pkg, version] = plugin.split("@")
|
||||
plugin = await BunProc.install(pkg, version ?? "latest")
|
||||
}
|
||||
const mod = await import(plugin)
|
||||
for (const [_name, fn] of Object.entries<PluginInstance>(mod)) {
|
||||
const init = await fn({
|
||||
@@ -35,38 +39,18 @@ export namespace Plugin {
|
||||
}
|
||||
})
|
||||
|
||||
type Path<T, Prefix extends string = ""> = T extends object
|
||||
? {
|
||||
[K in keyof T]: K extends string
|
||||
? T[K] extends Function | undefined
|
||||
? `${Prefix}${K}`
|
||||
: Path<T[K], `${Prefix}${K}.`>
|
||||
: never
|
||||
}[keyof T]
|
||||
: never
|
||||
|
||||
export type FunctionFromKey<T, P extends Path<T>> = P extends `${infer K}.${infer R}`
|
||||
? K extends keyof T
|
||||
? R extends Path<T[K]>
|
||||
? FunctionFromKey<T[K], R>
|
||||
: never
|
||||
: never
|
||||
: P extends keyof T
|
||||
? T[P]
|
||||
: never
|
||||
|
||||
export async function trigger<
|
||||
Name extends Path<Required<Hooks>>,
|
||||
Input = Parameters<FunctionFromKey<Required<Hooks>, Name>>[0],
|
||||
Output = Parameters<FunctionFromKey<Required<Hooks>, Name>>[1],
|
||||
>(fn: Name, input: Input, output: Output): Promise<Output> {
|
||||
if (!fn) return output
|
||||
const path = fn.split(".")
|
||||
Name extends keyof Required<Hooks>,
|
||||
Input = Parameters<Required<Hooks>[Name]>[0],
|
||||
Output = Parameters<Required<Hooks>[Name]>[1],
|
||||
>(name: Name, input: Input, output: Output): Promise<Output> {
|
||||
if (!name) return output
|
||||
for (const hook of await state().then((x) => x.hooks)) {
|
||||
// @ts-expect-error
|
||||
const fn = pathOr(hook, path, undefined)
|
||||
const fn = hook[name]
|
||||
if (!fn) continue
|
||||
// @ts-expect-error
|
||||
// @ts-expect-error if you feel adventurous, please fix the typing, make sure to bump the try-counter if you
|
||||
// give up.
|
||||
// try-counter: 2
|
||||
await fn(input, output)
|
||||
}
|
||||
return output
|
||||
|
||||
@@ -77,4 +77,4 @@ export namespace ModelsDev {
|
||||
}
|
||||
}
|
||||
|
||||
setInterval(() => ModelsDev.refresh(), 60 * 1000).unref()
|
||||
setInterval(() => ModelsDev.refresh(), 60 * 1000 * 60).unref()
|
||||
|
||||
@@ -735,10 +735,9 @@ export namespace Session {
|
||||
args,
|
||||
},
|
||||
)
|
||||
await processor.track(options.toolCallId)
|
||||
const result = await item.execute(args, {
|
||||
sessionID: input.sessionID,
|
||||
abort: abort.signal,
|
||||
abort: options.abortSignal!,
|
||||
messageID: assistantMsg.id,
|
||||
callID: options.toolCallId,
|
||||
metadata: async (val) => {
|
||||
@@ -780,11 +779,10 @@ export namespace Session {
|
||||
}
|
||||
|
||||
for (const [key, item] of Object.entries(await MCP.tools())) {
|
||||
if (mode.tools[key] === false) continue
|
||||
if (enabledTools[key] === false) continue
|
||||
const execute = item.execute
|
||||
if (!execute) continue
|
||||
item.execute = async (args, opts) => {
|
||||
await processor.track(opts.toolCallId)
|
||||
const result = await execute(args, opts)
|
||||
const output = result.content
|
||||
.filter((x: any) => x.type === "text")
|
||||
@@ -920,15 +918,11 @@ export namespace Session {
|
||||
}
|
||||
|
||||
function createProcessor(assistantMsg: MessageV2.Assistant, model: ModelsDev.Model) {
|
||||
const toolCalls: Record<string, MessageV2.ToolPart> = {}
|
||||
const snapshots: Record<string, string> = {}
|
||||
const toolcalls: Record<string, MessageV2.ToolPart> = {}
|
||||
let snapshot: string | undefined
|
||||
return {
|
||||
async track(toolCallID: string) {
|
||||
const hash = await Snapshot.track()
|
||||
if (hash) snapshots[toolCallID] = hash
|
||||
},
|
||||
partFromToolCall(toolCallID: string) {
|
||||
return toolCalls[toolCallID]
|
||||
return toolcalls[toolCallID]
|
||||
},
|
||||
async process(stream: StreamTextResult<Record<string, AITool>, never>) {
|
||||
try {
|
||||
@@ -944,7 +938,7 @@ export namespace Session {
|
||||
|
||||
case "tool-input-start":
|
||||
const part = await updatePart({
|
||||
id: toolCalls[value.id]?.id ?? Identifier.ascending("part"),
|
||||
id: toolcalls[value.id]?.id ?? Identifier.ascending("part"),
|
||||
messageID: assistantMsg.id,
|
||||
sessionID: assistantMsg.sessionID,
|
||||
type: "tool",
|
||||
@@ -954,7 +948,7 @@ export namespace Session {
|
||||
status: "pending",
|
||||
},
|
||||
})
|
||||
toolCalls[value.id] = part as MessageV2.ToolPart
|
||||
toolcalls[value.id] = part as MessageV2.ToolPart
|
||||
break
|
||||
|
||||
case "tool-input-delta":
|
||||
@@ -964,7 +958,7 @@ export namespace Session {
|
||||
break
|
||||
|
||||
case "tool-call": {
|
||||
const match = toolCalls[value.toolCallId]
|
||||
const match = toolcalls[value.toolCallId]
|
||||
if (match) {
|
||||
const part = await updatePart({
|
||||
...match,
|
||||
@@ -976,12 +970,12 @@ export namespace Session {
|
||||
},
|
||||
},
|
||||
})
|
||||
toolCalls[value.toolCallId] = part as MessageV2.ToolPart
|
||||
toolcalls[value.toolCallId] = part as MessageV2.ToolPart
|
||||
}
|
||||
break
|
||||
}
|
||||
case "tool-result": {
|
||||
const match = toolCalls[value.toolCallId]
|
||||
const match = toolcalls[value.toolCallId]
|
||||
if (match && match.state.status === "running") {
|
||||
await updatePart({
|
||||
...match,
|
||||
@@ -997,27 +991,13 @@ export namespace Session {
|
||||
},
|
||||
},
|
||||
})
|
||||
delete toolCalls[value.toolCallId]
|
||||
const snapshot = snapshots[value.toolCallId]
|
||||
if (snapshot) {
|
||||
const patch = await Snapshot.patch(snapshot)
|
||||
if (patch.files.length) {
|
||||
await updatePart({
|
||||
id: Identifier.ascending("part"),
|
||||
messageID: assistantMsg.id,
|
||||
sessionID: assistantMsg.sessionID,
|
||||
type: "patch",
|
||||
hash: patch.hash,
|
||||
files: patch.files,
|
||||
})
|
||||
}
|
||||
}
|
||||
delete toolcalls[value.toolCallId]
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
case "tool-error": {
|
||||
const match = toolCalls[value.toolCallId]
|
||||
const match = toolcalls[value.toolCallId]
|
||||
if (match && match.state.status === "running") {
|
||||
await updatePart({
|
||||
...match,
|
||||
@@ -1031,19 +1011,7 @@ export namespace Session {
|
||||
},
|
||||
},
|
||||
})
|
||||
delete toolCalls[value.toolCallId]
|
||||
const snapshot = snapshots[value.toolCallId]
|
||||
if (snapshot) {
|
||||
const patch = await Snapshot.patch(snapshot)
|
||||
await updatePart({
|
||||
id: Identifier.ascending("part"),
|
||||
messageID: assistantMsg.id,
|
||||
sessionID: assistantMsg.sessionID,
|
||||
type: "patch",
|
||||
hash: patch.hash,
|
||||
files: patch.files,
|
||||
})
|
||||
}
|
||||
delete toolcalls[value.toolCallId]
|
||||
}
|
||||
break
|
||||
}
|
||||
@@ -1058,6 +1026,7 @@ export namespace Session {
|
||||
sessionID: assistantMsg.sessionID,
|
||||
type: "step-start",
|
||||
})
|
||||
snapshot = await Snapshot.track()
|
||||
break
|
||||
|
||||
case "finish-step":
|
||||
@@ -1073,6 +1042,20 @@ export namespace Session {
|
||||
cost: usage.cost,
|
||||
})
|
||||
await updateMessage(assistantMsg)
|
||||
if (snapshot) {
|
||||
const patch = await Snapshot.patch(snapshot)
|
||||
if (patch.files.length) {
|
||||
await updatePart({
|
||||
id: Identifier.ascending("part"),
|
||||
messageID: assistantMsg.id,
|
||||
sessionID: assistantMsg.sessionID,
|
||||
type: "patch",
|
||||
hash: patch.hash,
|
||||
files: patch.files,
|
||||
})
|
||||
}
|
||||
snapshot = undefined
|
||||
}
|
||||
break
|
||||
|
||||
case "text-start":
|
||||
|
||||
@@ -60,33 +60,28 @@ export namespace SystemPrompt {
|
||||
export async function custom() {
|
||||
const { cwd, root } = App.info().path
|
||||
const config = await Config.get()
|
||||
const found = []
|
||||
const paths = new Set<string>()
|
||||
|
||||
for (const item of CUSTOM_FILES) {
|
||||
const matches = await Filesystem.findUp(item, cwd, root)
|
||||
found.push(...matches.map((x) => Bun.file(x).text()))
|
||||
matches.forEach((path) => paths.add(path))
|
||||
}
|
||||
found.push(
|
||||
Bun.file(path.join(Global.Path.config, "AGENTS.md"))
|
||||
.text()
|
||||
.catch(() => ""),
|
||||
)
|
||||
found.push(
|
||||
Bun.file(path.join(os.homedir(), ".claude", "CLAUDE.md"))
|
||||
.text()
|
||||
.catch(() => ""),
|
||||
)
|
||||
|
||||
paths.add(path.join(Global.Path.config, "AGENTS.md"))
|
||||
paths.add(path.join(os.homedir(), ".claude", "CLAUDE.md"))
|
||||
|
||||
if (config.instructions) {
|
||||
for (const instruction of config.instructions) {
|
||||
try {
|
||||
const matches = await Filesystem.globUp(instruction, cwd, root)
|
||||
found.push(...matches.map((x) => Bun.file(x).text()))
|
||||
} catch {
|
||||
continue // Skip invalid glob patterns
|
||||
}
|
||||
const matches = await Filesystem.globUp(instruction, cwd, root).catch(() => [])
|
||||
matches.forEach((path) => paths.add(path))
|
||||
}
|
||||
}
|
||||
|
||||
const found = Array.from(paths).map((p) =>
|
||||
Bun.file(p)
|
||||
.text()
|
||||
.catch(() => ""),
|
||||
)
|
||||
return Promise.all(found).then((result) => result.filter(Boolean))
|
||||
}
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ export namespace Snapshot {
|
||||
log.info("initialized")
|
||||
}
|
||||
await $`git --git-dir ${git} add .`.quiet().cwd(app.path.cwd).nothrow()
|
||||
const hash = await $`git --git-dir ${git} write-tree`.quiet().cwd(app.path.cwd).text()
|
||||
const hash = await $`git --git-dir ${git} write-tree`.quiet().cwd(app.path.cwd).nothrow().text()
|
||||
return hash.trim()
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import { z } from "zod"
|
||||
import { exec } from "child_process"
|
||||
import { text } from "stream/consumers"
|
||||
import { Tool } from "./tool"
|
||||
import DESCRIPTION from "./bash.txt"
|
||||
import { App } from "../app/app"
|
||||
@@ -116,19 +118,24 @@ export const BashTool = Tool.define("bash", {
|
||||
})
|
||||
}
|
||||
|
||||
const process = Bun.spawn({
|
||||
cmd: ["bash", "-c", params.command],
|
||||
const process = exec(params.command, {
|
||||
cwd: app.path.cwd,
|
||||
maxBuffer: MAX_OUTPUT_LENGTH,
|
||||
signal: ctx.abort,
|
||||
timeout: timeout,
|
||||
stdin: "pipe",
|
||||
stdout: "pipe",
|
||||
stderr: "pipe",
|
||||
maxBuffer: MAX_OUTPUT_LENGTH,
|
||||
timeout,
|
||||
})
|
||||
await process.exited
|
||||
const stdout = await new Response(process.stdout).text()
|
||||
const stderr = await new Response(process.stderr).text()
|
||||
|
||||
const stdoutPromise = text(process.stdout!)
|
||||
const stderrPromise = text(process.stderr!)
|
||||
|
||||
await new Promise<void>((resolve) => {
|
||||
process.on("close", () => {
|
||||
resolve()
|
||||
})
|
||||
})
|
||||
|
||||
const stdout = await stdoutPromise
|
||||
const stderr = await stderrPromise
|
||||
|
||||
return {
|
||||
title: params.command,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/package.json",
|
||||
"name": "@opencode-ai/plugin",
|
||||
"version": "0.3.113",
|
||||
"version": "0.3.126",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"typecheck": "tsc --noEmit"
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
import { Plugin } from "./index"
|
||||
|
||||
export const ExamplePlugin: Plugin = async ({ app, client }) => {
|
||||
export const ExamplePlugin: Plugin = async ({ app, client, $ }) => {
|
||||
return {
|
||||
permission: {},
|
||||
async "chat.params"(input, output) {
|
||||
output.topP = 1
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,47 +10,28 @@ export type Plugin = (input: PluginInput) => Promise<Hooks>
|
||||
|
||||
export interface Hooks {
|
||||
event?: (input: { event: Event }) => Promise<void>
|
||||
chat?: {
|
||||
/**
|
||||
* Called when a new message is received
|
||||
*/
|
||||
message?: (input: {}, output: { message: UserMessage; parts: Part[] }) => Promise<void>
|
||||
/**
|
||||
* Modify parameters sent to LLM
|
||||
*/
|
||||
params?: (
|
||||
input: { model: Model; provider: Provider; message: UserMessage },
|
||||
output: { temperature: number; topP: number },
|
||||
) => Promise<void>
|
||||
}
|
||||
permission?: {
|
||||
/**
|
||||
* Called when a permission is asked
|
||||
*/
|
||||
ask?: (input: Permission, output: { status: "ask" | "deny" | "allow" }) => Promise<void>
|
||||
}
|
||||
tool?: {
|
||||
execute?: {
|
||||
/**
|
||||
* Called before a tool is executed
|
||||
*/
|
||||
before?: (
|
||||
input: { tool: string; sessionID: string; callID: string },
|
||||
output: {
|
||||
args: any
|
||||
},
|
||||
) => Promise<void>
|
||||
/**
|
||||
* Called after a tool is executed
|
||||
*/
|
||||
after?: (
|
||||
input: { tool: string; sessionID: string; callID: string },
|
||||
output: {
|
||||
title: string
|
||||
output: string
|
||||
metadata: any
|
||||
},
|
||||
) => Promise<void>
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Called when a new message is received
|
||||
*/
|
||||
"chat.message"?: (input: {}, output: { message: UserMessage; parts: Part[] }) => Promise<void>
|
||||
/**
|
||||
* Modify parameters sent to LLM
|
||||
*/
|
||||
"chat.params"?: (
|
||||
input: { model: Model; provider: Provider; message: UserMessage },
|
||||
output: { temperature: number; topP: number },
|
||||
) => Promise<void>
|
||||
"permission.ask"?: (input: Permission, output: { status: "ask" | "deny" | "allow" }) => Promise<void>
|
||||
"tool.execute.before"?: (
|
||||
input: { tool: string; sessionID: string; callID: string },
|
||||
output: { args: any },
|
||||
) => Promise<void>
|
||||
"tool.execute.after"?: (
|
||||
input: { tool: string; sessionID: string; callID: string },
|
||||
output: {
|
||||
title: string
|
||||
output: string
|
||||
metadata: any
|
||||
},
|
||||
) => Promise<void>
|
||||
}
|
||||
|
||||
-88
@@ -1,88 +0,0 @@
|
||||
name: CI
|
||||
on:
|
||||
push:
|
||||
branches-ignore:
|
||||
- 'generated'
|
||||
- 'codegen/**'
|
||||
- 'integrated/**'
|
||||
- 'stl-preview-head/**'
|
||||
- 'stl-preview-base/**'
|
||||
pull_request:
|
||||
branches-ignore:
|
||||
- 'stl-preview-head/**'
|
||||
- 'stl-preview-base/**'
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
timeout-minutes: 10
|
||||
name: lint
|
||||
runs-on: ${{ github.repository == 'stainless-sdks/opencode-typescript' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }}
|
||||
if: github.event_name == 'push' || github.event.pull_request.head.repo.fork
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Node
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '20'
|
||||
|
||||
- name: Bootstrap
|
||||
run: ./scripts/bootstrap
|
||||
|
||||
- name: Check types
|
||||
run: ./scripts/lint
|
||||
|
||||
build:
|
||||
timeout-minutes: 5
|
||||
name: build
|
||||
runs-on: ${{ github.repository == 'stainless-sdks/opencode-typescript' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }}
|
||||
if: github.event_name == 'push' || github.event.pull_request.head.repo.fork
|
||||
permissions:
|
||||
contents: read
|
||||
id-token: write
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Node
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '20'
|
||||
|
||||
- name: Bootstrap
|
||||
run: ./scripts/bootstrap
|
||||
|
||||
- name: Check build
|
||||
run: ./scripts/build
|
||||
|
||||
- name: Get GitHub OIDC Token
|
||||
if: github.repository == 'stainless-sdks/opencode-typescript'
|
||||
id: github-oidc
|
||||
uses: actions/github-script@v6
|
||||
with:
|
||||
script: core.setOutput('github_token', await core.getIDToken());
|
||||
|
||||
- name: Upload tarball
|
||||
if: github.repository == 'stainless-sdks/opencode-typescript'
|
||||
env:
|
||||
URL: https://pkg.stainless.com/s
|
||||
AUTH: ${{ steps.github-oidc.outputs.github_token }}
|
||||
SHA: ${{ github.sha }}
|
||||
run: ./scripts/utils/upload-artifact.sh
|
||||
test:
|
||||
timeout-minutes: 10
|
||||
name: test
|
||||
runs-on: ${{ github.repository == 'stainless-sdks/opencode-typescript' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }}
|
||||
if: github.event_name == 'push' || github.event.pull_request.head.repo.fork
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Node
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '20'
|
||||
|
||||
- name: Bootstrap
|
||||
run: ./scripts/bootstrap
|
||||
|
||||
- name: Run tests
|
||||
run: ./scripts/test
|
||||
-32
@@ -1,32 +0,0 @@
|
||||
# This workflow is triggered when a GitHub release is created.
|
||||
# It can also be run manually to re-publish to NPM in case it failed for some reason.
|
||||
# You can run this workflow by navigating to https://www.github.com/sst/opencode-sdk-js/actions/workflows/publish-npm.yml
|
||||
name: Publish NPM
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
release:
|
||||
types: [published]
|
||||
|
||||
jobs:
|
||||
publish:
|
||||
name: publish
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Node
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: '20'
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
yarn install
|
||||
|
||||
- name: Publish to NPM
|
||||
run: |
|
||||
bash ./bin/publish-npm
|
||||
env:
|
||||
NPM_TOKEN: ${{ secrets.OPENCODE_NPM_TOKEN || secrets.NPM_TOKEN }}
|
||||
@@ -1,21 +0,0 @@
|
||||
name: Release Doctor
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
release_doctor:
|
||||
name: release doctor
|
||||
runs-on: ubuntu-latest
|
||||
if: github.repository == 'sst/opencode-sdk-js' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch' || startsWith(github.head_ref, 'release-please') || github.head_ref == 'next')
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Check release environment
|
||||
run: |
|
||||
bash ./bin/check-release-environment
|
||||
env:
|
||||
NPM_TOKEN: ${{ secrets.OPENCODE_NPM_TOKEN || secrets.NPM_TOKEN }}
|
||||
@@ -1,4 +1,4 @@
|
||||
configured_endpoints: 34
|
||||
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/opencode%2Fopencode-2ebd9d5478864042a2e01b4995f42acbc39069fa7fcccd1c2e567366ee6c243d.yml
|
||||
openapi_spec_hash: 2a34451b288ea30af1cb61332c417c2a
|
||||
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/opencode%2Fopencode-52fd0b61e84fdc1cdd31ec12e1600510e9dd2f9d4fb20c2315b4975cb763ee98.yml
|
||||
openapi_spec_hash: e851b8d5a2412f5fc9be82ab88ebdfde
|
||||
config_hash: 11a6f0803eb407367c3f677d3e524c37
|
||||
|
||||
@@ -151,6 +151,7 @@ type Mode struct {
|
||||
Model ModeModel `json:"model"`
|
||||
Prompt string `json:"prompt"`
|
||||
Temperature float64 `json:"temperature"`
|
||||
TopP float64 `json:"topP"`
|
||||
JSON modeJSON `json:"-"`
|
||||
}
|
||||
|
||||
@@ -161,6 +162,7 @@ type modeJSON struct {
|
||||
Model apijson.Field
|
||||
Prompt apijson.Field
|
||||
Temperature apijson.Field
|
||||
TopP apijson.Field
|
||||
raw string
|
||||
ExtraFields map[string]apijson.Field
|
||||
}
|
||||
|
||||
+170
-3
@@ -51,14 +51,16 @@ type Config struct {
|
||||
// Automatically update to the latest version
|
||||
Autoupdate bool `json:"autoupdate"`
|
||||
// Disable providers that are loaded automatically
|
||||
DisabledProviders []string `json:"disabled_providers"`
|
||||
Experimental ConfigExperimental `json:"experimental"`
|
||||
DisabledProviders []string `json:"disabled_providers"`
|
||||
Experimental ConfigExperimental `json:"experimental"`
|
||||
Formatter map[string]ConfigFormatter `json:"formatter"`
|
||||
// Additional instruction files or patterns to include
|
||||
Instructions []string `json:"instructions"`
|
||||
// Custom keybind configurations
|
||||
Keybinds KeybindsConfig `json:"keybinds"`
|
||||
// @deprecated Always uses stretch layout.
|
||||
Layout ConfigLayout `json:"layout"`
|
||||
Layout ConfigLayout `json:"layout"`
|
||||
Lsp map[string]ConfigLsp `json:"lsp"`
|
||||
// MCP (Model Context Protocol) server configurations
|
||||
Mcp map[string]ConfigMcp `json:"mcp"`
|
||||
// Modes configuration, see https://opencode.ai/docs/modes
|
||||
@@ -66,6 +68,7 @@ type Config struct {
|
||||
// Model to use in the format of provider/model, eg anthropic/claude-2
|
||||
Model string `json:"model"`
|
||||
Permission ConfigPermission `json:"permission"`
|
||||
Plugin []string `json:"plugin"`
|
||||
// Custom provider configurations and model overrides
|
||||
Provider map[string]ConfigProvider `json:"provider"`
|
||||
// Control sharing behavior:'manual' allows manual sharing via commands, 'auto'
|
||||
@@ -89,13 +92,16 @@ type configJSON struct {
|
||||
Autoupdate apijson.Field
|
||||
DisabledProviders apijson.Field
|
||||
Experimental apijson.Field
|
||||
Formatter apijson.Field
|
||||
Instructions apijson.Field
|
||||
Keybinds apijson.Field
|
||||
Layout apijson.Field
|
||||
Lsp apijson.Field
|
||||
Mcp apijson.Field
|
||||
Mode apijson.Field
|
||||
Model apijson.Field
|
||||
Permission apijson.Field
|
||||
Plugin apijson.Field
|
||||
Provider apijson.Field
|
||||
Share apijson.Field
|
||||
SmallModel apijson.Field
|
||||
@@ -247,6 +253,32 @@ func (r configExperimentalHookSessionCompletedJSON) RawJSON() string {
|
||||
return r.raw
|
||||
}
|
||||
|
||||
type ConfigFormatter struct {
|
||||
Command []string `json:"command"`
|
||||
Disabled bool `json:"disabled"`
|
||||
Environment map[string]string `json:"environment"`
|
||||
Extensions []string `json:"extensions"`
|
||||
JSON configFormatterJSON `json:"-"`
|
||||
}
|
||||
|
||||
// configFormatterJSON contains the JSON metadata for the struct [ConfigFormatter]
|
||||
type configFormatterJSON struct {
|
||||
Command apijson.Field
|
||||
Disabled apijson.Field
|
||||
Environment apijson.Field
|
||||
Extensions apijson.Field
|
||||
raw string
|
||||
ExtraFields map[string]apijson.Field
|
||||
}
|
||||
|
||||
func (r *ConfigFormatter) UnmarshalJSON(data []byte) (err error) {
|
||||
return apijson.UnmarshalRoot(data, r)
|
||||
}
|
||||
|
||||
func (r configFormatterJSON) RawJSON() string {
|
||||
return r.raw
|
||||
}
|
||||
|
||||
// @deprecated Always uses stretch layout.
|
||||
type ConfigLayout string
|
||||
|
||||
@@ -263,6 +295,139 @@ func (r ConfigLayout) IsKnown() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
type ConfigLsp struct {
|
||||
// This field can have the runtime type of [[]string].
|
||||
Command interface{} `json:"command"`
|
||||
Disabled bool `json:"disabled"`
|
||||
// This field can have the runtime type of [map[string]string].
|
||||
Env interface{} `json:"env"`
|
||||
// This field can have the runtime type of [[]string].
|
||||
Extensions interface{} `json:"extensions"`
|
||||
// This field can have the runtime type of [map[string]interface{}].
|
||||
Initialization interface{} `json:"initialization"`
|
||||
JSON configLspJSON `json:"-"`
|
||||
union ConfigLspUnion
|
||||
}
|
||||
|
||||
// configLspJSON contains the JSON metadata for the struct [ConfigLsp]
|
||||
type configLspJSON struct {
|
||||
Command apijson.Field
|
||||
Disabled apijson.Field
|
||||
Env apijson.Field
|
||||
Extensions apijson.Field
|
||||
Initialization apijson.Field
|
||||
raw string
|
||||
ExtraFields map[string]apijson.Field
|
||||
}
|
||||
|
||||
func (r configLspJSON) RawJSON() string {
|
||||
return r.raw
|
||||
}
|
||||
|
||||
func (r *ConfigLsp) UnmarshalJSON(data []byte) (err error) {
|
||||
*r = ConfigLsp{}
|
||||
err = apijson.UnmarshalRoot(data, &r.union)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return apijson.Port(r.union, &r)
|
||||
}
|
||||
|
||||
// AsUnion returns a [ConfigLspUnion] interface which you can cast to the specific
|
||||
// types for more type safety.
|
||||
//
|
||||
// Possible runtime types of the union are [ConfigLspDisabled], [ConfigLspObject].
|
||||
func (r ConfigLsp) AsUnion() ConfigLspUnion {
|
||||
return r.union
|
||||
}
|
||||
|
||||
// Union satisfied by [ConfigLspDisabled] or [ConfigLspObject].
|
||||
type ConfigLspUnion interface {
|
||||
implementsConfigLsp()
|
||||
}
|
||||
|
||||
func init() {
|
||||
apijson.RegisterUnion(
|
||||
reflect.TypeOf((*ConfigLspUnion)(nil)).Elem(),
|
||||
"",
|
||||
apijson.UnionVariant{
|
||||
TypeFilter: gjson.JSON,
|
||||
Type: reflect.TypeOf(ConfigLspDisabled{}),
|
||||
},
|
||||
apijson.UnionVariant{
|
||||
TypeFilter: gjson.JSON,
|
||||
Type: reflect.TypeOf(ConfigLspObject{}),
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
type ConfigLspDisabled struct {
|
||||
Disabled ConfigLspDisabledDisabled `json:"disabled,required"`
|
||||
JSON configLspDisabledJSON `json:"-"`
|
||||
}
|
||||
|
||||
// configLspDisabledJSON contains the JSON metadata for the struct
|
||||
// [ConfigLspDisabled]
|
||||
type configLspDisabledJSON struct {
|
||||
Disabled apijson.Field
|
||||
raw string
|
||||
ExtraFields map[string]apijson.Field
|
||||
}
|
||||
|
||||
func (r *ConfigLspDisabled) UnmarshalJSON(data []byte) (err error) {
|
||||
return apijson.UnmarshalRoot(data, r)
|
||||
}
|
||||
|
||||
func (r configLspDisabledJSON) RawJSON() string {
|
||||
return r.raw
|
||||
}
|
||||
|
||||
func (r ConfigLspDisabled) implementsConfigLsp() {}
|
||||
|
||||
type ConfigLspDisabledDisabled bool
|
||||
|
||||
const (
|
||||
ConfigLspDisabledDisabledTrue ConfigLspDisabledDisabled = true
|
||||
)
|
||||
|
||||
func (r ConfigLspDisabledDisabled) IsKnown() bool {
|
||||
switch r {
|
||||
case ConfigLspDisabledDisabledTrue:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type ConfigLspObject struct {
|
||||
Command []string `json:"command,required"`
|
||||
Disabled bool `json:"disabled"`
|
||||
Env map[string]string `json:"env"`
|
||||
Extensions []string `json:"extensions"`
|
||||
Initialization map[string]interface{} `json:"initialization"`
|
||||
JSON configLspObjectJSON `json:"-"`
|
||||
}
|
||||
|
||||
// configLspObjectJSON contains the JSON metadata for the struct [ConfigLspObject]
|
||||
type configLspObjectJSON struct {
|
||||
Command apijson.Field
|
||||
Disabled apijson.Field
|
||||
Env apijson.Field
|
||||
Extensions apijson.Field
|
||||
Initialization apijson.Field
|
||||
raw string
|
||||
ExtraFields map[string]apijson.Field
|
||||
}
|
||||
|
||||
func (r *ConfigLspObject) UnmarshalJSON(data []byte) (err error) {
|
||||
return apijson.UnmarshalRoot(data, r)
|
||||
}
|
||||
|
||||
func (r configLspObjectJSON) RawJSON() string {
|
||||
return r.raw
|
||||
}
|
||||
|
||||
func (r ConfigLspObject) implementsConfigLsp() {}
|
||||
|
||||
type ConfigMcp struct {
|
||||
// Type of MCP server connection
|
||||
Type ConfigMcpType `json:"type,required"`
|
||||
@@ -864,6 +1029,7 @@ type ModeConfig struct {
|
||||
Prompt string `json:"prompt"`
|
||||
Temperature float64 `json:"temperature"`
|
||||
Tools map[string]bool `json:"tools"`
|
||||
TopP float64 `json:"top_p"`
|
||||
JSON modeConfigJSON `json:"-"`
|
||||
}
|
||||
|
||||
@@ -874,6 +1040,7 @@ type modeConfigJSON struct {
|
||||
Prompt apijson.Field
|
||||
Temperature apijson.Field
|
||||
Tools apijson.Field
|
||||
TopP apijson.Field
|
||||
raw string
|
||||
ExtraFields map[string]apijson.Field
|
||||
}
|
||||
|
||||
+123
-121
@@ -54,13 +54,13 @@ type EventListResponse struct {
|
||||
// [EventListResponseEventMessageRemovedProperties],
|
||||
// [EventListResponseEventMessagePartUpdatedProperties],
|
||||
// [EventListResponseEventMessagePartRemovedProperties],
|
||||
// [EventListResponseEventStorageWriteProperties], [Permission],
|
||||
// [EventListResponseEventStorageWriteProperties],
|
||||
// [EventListResponseEventFileEditedProperties], [interface{}], [Permission],
|
||||
// [EventListResponseEventPermissionRepliedProperties],
|
||||
// [EventListResponseEventFileEditedProperties],
|
||||
// [EventListResponseEventSessionUpdatedProperties],
|
||||
// [EventListResponseEventSessionDeletedProperties],
|
||||
// [EventListResponseEventSessionIdleProperties],
|
||||
// [EventListResponseEventSessionErrorProperties], [interface{}],
|
||||
// [EventListResponseEventSessionErrorProperties],
|
||||
// [EventListResponseEventFileWatcherUpdatedProperties],
|
||||
// [EventListResponseEventIdeInstalledProperties].
|
||||
Properties interface{} `json:"properties,required"`
|
||||
@@ -100,11 +100,12 @@ func (r *EventListResponse) UnmarshalJSON(data []byte) (err error) {
|
||||
// [EventListResponseEventMessageUpdated], [EventListResponseEventMessageRemoved],
|
||||
// [EventListResponseEventMessagePartUpdated],
|
||||
// [EventListResponseEventMessagePartRemoved],
|
||||
// [EventListResponseEventStorageWrite], [EventListResponseEventPermissionUpdated],
|
||||
// [EventListResponseEventPermissionReplied], [EventListResponseEventFileEdited],
|
||||
// [EventListResponseEventStorageWrite], [EventListResponseEventFileEdited],
|
||||
// [EventListResponseEventServerConnected],
|
||||
// [EventListResponseEventPermissionUpdated],
|
||||
// [EventListResponseEventPermissionReplied],
|
||||
// [EventListResponseEventSessionUpdated], [EventListResponseEventSessionDeleted],
|
||||
// [EventListResponseEventSessionIdle], [EventListResponseEventSessionError],
|
||||
// [EventListResponseEventServerConnected],
|
||||
// [EventListResponseEventFileWatcherUpdated],
|
||||
// [EventListResponseEventIdeInstalled].
|
||||
func (r EventListResponse) AsUnion() EventListResponseUnion {
|
||||
@@ -116,11 +117,12 @@ func (r EventListResponse) AsUnion() EventListResponseUnion {
|
||||
// [EventListResponseEventMessageUpdated], [EventListResponseEventMessageRemoved],
|
||||
// [EventListResponseEventMessagePartUpdated],
|
||||
// [EventListResponseEventMessagePartRemoved],
|
||||
// [EventListResponseEventStorageWrite], [EventListResponseEventPermissionUpdated],
|
||||
// [EventListResponseEventPermissionReplied], [EventListResponseEventFileEdited],
|
||||
// [EventListResponseEventStorageWrite], [EventListResponseEventFileEdited],
|
||||
// [EventListResponseEventServerConnected],
|
||||
// [EventListResponseEventPermissionUpdated],
|
||||
// [EventListResponseEventPermissionReplied],
|
||||
// [EventListResponseEventSessionUpdated], [EventListResponseEventSessionDeleted],
|
||||
// [EventListResponseEventSessionIdle], [EventListResponseEventSessionError],
|
||||
// [EventListResponseEventServerConnected],
|
||||
// [EventListResponseEventFileWatcherUpdated] or
|
||||
// [EventListResponseEventIdeInstalled].
|
||||
type EventListResponseUnion interface {
|
||||
@@ -166,6 +168,16 @@ func init() {
|
||||
Type: reflect.TypeOf(EventListResponseEventStorageWrite{}),
|
||||
DiscriminatorValue: "storage.write",
|
||||
},
|
||||
apijson.UnionVariant{
|
||||
TypeFilter: gjson.JSON,
|
||||
Type: reflect.TypeOf(EventListResponseEventFileEdited{}),
|
||||
DiscriminatorValue: "file.edited",
|
||||
},
|
||||
apijson.UnionVariant{
|
||||
TypeFilter: gjson.JSON,
|
||||
Type: reflect.TypeOf(EventListResponseEventServerConnected{}),
|
||||
DiscriminatorValue: "server.connected",
|
||||
},
|
||||
apijson.UnionVariant{
|
||||
TypeFilter: gjson.JSON,
|
||||
Type: reflect.TypeOf(EventListResponseEventPermissionUpdated{}),
|
||||
@@ -176,11 +188,6 @@ func init() {
|
||||
Type: reflect.TypeOf(EventListResponseEventPermissionReplied{}),
|
||||
DiscriminatorValue: "permission.replied",
|
||||
},
|
||||
apijson.UnionVariant{
|
||||
TypeFilter: gjson.JSON,
|
||||
Type: reflect.TypeOf(EventListResponseEventFileEdited{}),
|
||||
DiscriminatorValue: "file.edited",
|
||||
},
|
||||
apijson.UnionVariant{
|
||||
TypeFilter: gjson.JSON,
|
||||
Type: reflect.TypeOf(EventListResponseEventSessionUpdated{}),
|
||||
@@ -201,11 +208,6 @@ func init() {
|
||||
Type: reflect.TypeOf(EventListResponseEventSessionError{}),
|
||||
DiscriminatorValue: "session.error",
|
||||
},
|
||||
apijson.UnionVariant{
|
||||
TypeFilter: gjson.JSON,
|
||||
Type: reflect.TypeOf(EventListResponseEventServerConnected{}),
|
||||
DiscriminatorValue: "server.connected",
|
||||
},
|
||||
apijson.UnionVariant{
|
||||
TypeFilter: gjson.JSON,
|
||||
Type: reflect.TypeOf(EventListResponseEventFileWatcherUpdated{}),
|
||||
@@ -649,6 +651,105 @@ func (r EventListResponseEventStorageWriteType) IsKnown() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
type EventListResponseEventFileEdited struct {
|
||||
Properties EventListResponseEventFileEditedProperties `json:"properties,required"`
|
||||
Type EventListResponseEventFileEditedType `json:"type,required"`
|
||||
JSON eventListResponseEventFileEditedJSON `json:"-"`
|
||||
}
|
||||
|
||||
// eventListResponseEventFileEditedJSON contains the JSON metadata for the struct
|
||||
// [EventListResponseEventFileEdited]
|
||||
type eventListResponseEventFileEditedJSON struct {
|
||||
Properties apijson.Field
|
||||
Type apijson.Field
|
||||
raw string
|
||||
ExtraFields map[string]apijson.Field
|
||||
}
|
||||
|
||||
func (r *EventListResponseEventFileEdited) UnmarshalJSON(data []byte) (err error) {
|
||||
return apijson.UnmarshalRoot(data, r)
|
||||
}
|
||||
|
||||
func (r eventListResponseEventFileEditedJSON) RawJSON() string {
|
||||
return r.raw
|
||||
}
|
||||
|
||||
func (r EventListResponseEventFileEdited) implementsEventListResponse() {}
|
||||
|
||||
type EventListResponseEventFileEditedProperties struct {
|
||||
File string `json:"file,required"`
|
||||
JSON eventListResponseEventFileEditedPropertiesJSON `json:"-"`
|
||||
}
|
||||
|
||||
// eventListResponseEventFileEditedPropertiesJSON contains the JSON metadata for
|
||||
// the struct [EventListResponseEventFileEditedProperties]
|
||||
type eventListResponseEventFileEditedPropertiesJSON struct {
|
||||
File apijson.Field
|
||||
raw string
|
||||
ExtraFields map[string]apijson.Field
|
||||
}
|
||||
|
||||
func (r *EventListResponseEventFileEditedProperties) UnmarshalJSON(data []byte) (err error) {
|
||||
return apijson.UnmarshalRoot(data, r)
|
||||
}
|
||||
|
||||
func (r eventListResponseEventFileEditedPropertiesJSON) RawJSON() string {
|
||||
return r.raw
|
||||
}
|
||||
|
||||
type EventListResponseEventFileEditedType string
|
||||
|
||||
const (
|
||||
EventListResponseEventFileEditedTypeFileEdited EventListResponseEventFileEditedType = "file.edited"
|
||||
)
|
||||
|
||||
func (r EventListResponseEventFileEditedType) IsKnown() bool {
|
||||
switch r {
|
||||
case EventListResponseEventFileEditedTypeFileEdited:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type EventListResponseEventServerConnected struct {
|
||||
Properties interface{} `json:"properties,required"`
|
||||
Type EventListResponseEventServerConnectedType `json:"type,required"`
|
||||
JSON eventListResponseEventServerConnectedJSON `json:"-"`
|
||||
}
|
||||
|
||||
// eventListResponseEventServerConnectedJSON contains the JSON metadata for the
|
||||
// struct [EventListResponseEventServerConnected]
|
||||
type eventListResponseEventServerConnectedJSON struct {
|
||||
Properties apijson.Field
|
||||
Type apijson.Field
|
||||
raw string
|
||||
ExtraFields map[string]apijson.Field
|
||||
}
|
||||
|
||||
func (r *EventListResponseEventServerConnected) UnmarshalJSON(data []byte) (err error) {
|
||||
return apijson.UnmarshalRoot(data, r)
|
||||
}
|
||||
|
||||
func (r eventListResponseEventServerConnectedJSON) RawJSON() string {
|
||||
return r.raw
|
||||
}
|
||||
|
||||
func (r EventListResponseEventServerConnected) implementsEventListResponse() {}
|
||||
|
||||
type EventListResponseEventServerConnectedType string
|
||||
|
||||
const (
|
||||
EventListResponseEventServerConnectedTypeServerConnected EventListResponseEventServerConnectedType = "server.connected"
|
||||
)
|
||||
|
||||
func (r EventListResponseEventServerConnectedType) IsKnown() bool {
|
||||
switch r {
|
||||
case EventListResponseEventServerConnectedTypeServerConnected:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type EventListResponseEventPermissionUpdated struct {
|
||||
Properties Permission `json:"properties,required"`
|
||||
Type EventListResponseEventPermissionUpdatedType `json:"type,required"`
|
||||
@@ -752,66 +853,6 @@ func (r EventListResponseEventPermissionRepliedType) IsKnown() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
type EventListResponseEventFileEdited struct {
|
||||
Properties EventListResponseEventFileEditedProperties `json:"properties,required"`
|
||||
Type EventListResponseEventFileEditedType `json:"type,required"`
|
||||
JSON eventListResponseEventFileEditedJSON `json:"-"`
|
||||
}
|
||||
|
||||
// eventListResponseEventFileEditedJSON contains the JSON metadata for the struct
|
||||
// [EventListResponseEventFileEdited]
|
||||
type eventListResponseEventFileEditedJSON struct {
|
||||
Properties apijson.Field
|
||||
Type apijson.Field
|
||||
raw string
|
||||
ExtraFields map[string]apijson.Field
|
||||
}
|
||||
|
||||
func (r *EventListResponseEventFileEdited) UnmarshalJSON(data []byte) (err error) {
|
||||
return apijson.UnmarshalRoot(data, r)
|
||||
}
|
||||
|
||||
func (r eventListResponseEventFileEditedJSON) RawJSON() string {
|
||||
return r.raw
|
||||
}
|
||||
|
||||
func (r EventListResponseEventFileEdited) implementsEventListResponse() {}
|
||||
|
||||
type EventListResponseEventFileEditedProperties struct {
|
||||
File string `json:"file,required"`
|
||||
JSON eventListResponseEventFileEditedPropertiesJSON `json:"-"`
|
||||
}
|
||||
|
||||
// eventListResponseEventFileEditedPropertiesJSON contains the JSON metadata for
|
||||
// the struct [EventListResponseEventFileEditedProperties]
|
||||
type eventListResponseEventFileEditedPropertiesJSON struct {
|
||||
File apijson.Field
|
||||
raw string
|
||||
ExtraFields map[string]apijson.Field
|
||||
}
|
||||
|
||||
func (r *EventListResponseEventFileEditedProperties) UnmarshalJSON(data []byte) (err error) {
|
||||
return apijson.UnmarshalRoot(data, r)
|
||||
}
|
||||
|
||||
func (r eventListResponseEventFileEditedPropertiesJSON) RawJSON() string {
|
||||
return r.raw
|
||||
}
|
||||
|
||||
type EventListResponseEventFileEditedType string
|
||||
|
||||
const (
|
||||
EventListResponseEventFileEditedTypeFileEdited EventListResponseEventFileEditedType = "file.edited"
|
||||
)
|
||||
|
||||
func (r EventListResponseEventFileEditedType) IsKnown() bool {
|
||||
switch r {
|
||||
case EventListResponseEventFileEditedTypeFileEdited:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type EventListResponseEventSessionUpdated struct {
|
||||
Properties EventListResponseEventSessionUpdatedProperties `json:"properties,required"`
|
||||
Type EventListResponseEventSessionUpdatedType `json:"type,required"`
|
||||
@@ -1188,45 +1229,6 @@ func (r EventListResponseEventSessionErrorType) IsKnown() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
type EventListResponseEventServerConnected struct {
|
||||
Properties interface{} `json:"properties,required"`
|
||||
Type EventListResponseEventServerConnectedType `json:"type,required"`
|
||||
JSON eventListResponseEventServerConnectedJSON `json:"-"`
|
||||
}
|
||||
|
||||
// eventListResponseEventServerConnectedJSON contains the JSON metadata for the
|
||||
// struct [EventListResponseEventServerConnected]
|
||||
type eventListResponseEventServerConnectedJSON struct {
|
||||
Properties apijson.Field
|
||||
Type apijson.Field
|
||||
raw string
|
||||
ExtraFields map[string]apijson.Field
|
||||
}
|
||||
|
||||
func (r *EventListResponseEventServerConnected) UnmarshalJSON(data []byte) (err error) {
|
||||
return apijson.UnmarshalRoot(data, r)
|
||||
}
|
||||
|
||||
func (r eventListResponseEventServerConnectedJSON) RawJSON() string {
|
||||
return r.raw
|
||||
}
|
||||
|
||||
func (r EventListResponseEventServerConnected) implementsEventListResponse() {}
|
||||
|
||||
type EventListResponseEventServerConnectedType string
|
||||
|
||||
const (
|
||||
EventListResponseEventServerConnectedTypeServerConnected EventListResponseEventServerConnectedType = "server.connected"
|
||||
)
|
||||
|
||||
func (r EventListResponseEventServerConnectedType) IsKnown() bool {
|
||||
switch r {
|
||||
case EventListResponseEventServerConnectedTypeServerConnected:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type EventListResponseEventFileWatcherUpdated struct {
|
||||
Properties EventListResponseEventFileWatcherUpdatedProperties `json:"properties,required"`
|
||||
Type EventListResponseEventFileWatcherUpdatedType `json:"type,required"`
|
||||
@@ -1374,21 +1376,21 @@ const (
|
||||
EventListResponseTypeMessagePartUpdated EventListResponseType = "message.part.updated"
|
||||
EventListResponseTypeMessagePartRemoved EventListResponseType = "message.part.removed"
|
||||
EventListResponseTypeStorageWrite EventListResponseType = "storage.write"
|
||||
EventListResponseTypeFileEdited EventListResponseType = "file.edited"
|
||||
EventListResponseTypeServerConnected EventListResponseType = "server.connected"
|
||||
EventListResponseTypePermissionUpdated EventListResponseType = "permission.updated"
|
||||
EventListResponseTypePermissionReplied EventListResponseType = "permission.replied"
|
||||
EventListResponseTypeFileEdited EventListResponseType = "file.edited"
|
||||
EventListResponseTypeSessionUpdated EventListResponseType = "session.updated"
|
||||
EventListResponseTypeSessionDeleted EventListResponseType = "session.deleted"
|
||||
EventListResponseTypeSessionIdle EventListResponseType = "session.idle"
|
||||
EventListResponseTypeSessionError EventListResponseType = "session.error"
|
||||
EventListResponseTypeServerConnected EventListResponseType = "server.connected"
|
||||
EventListResponseTypeFileWatcherUpdated EventListResponseType = "file.watcher.updated"
|
||||
EventListResponseTypeIdeInstalled EventListResponseType = "ide.installed"
|
||||
)
|
||||
|
||||
func (r EventListResponseType) IsKnown() bool {
|
||||
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, EventListResponseTypeStorageWrite, EventListResponseTypeFileEdited, EventListResponseTypeServerConnected, EventListResponseTypePermissionUpdated, EventListResponseTypePermissionReplied, EventListResponseTypeSessionUpdated, EventListResponseTypeSessionDeleted, EventListResponseTypeSessionIdle, EventListResponseTypeSessionError, EventListResponseTypeFileWatcherUpdated, EventListResponseTypeIdeInstalled:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/package.json",
|
||||
"name": "@opencode-ai/sdk",
|
||||
"version": "0.3.113",
|
||||
"version": "0.3.126",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"typecheck": "tsc --noEmit"
|
||||
|
||||
@@ -6,12 +6,9 @@ process.chdir(dir)
|
||||
import { $ } from "bun"
|
||||
import path from "path"
|
||||
|
||||
console.log("=== Generating JS SDK ===")
|
||||
console.log()
|
||||
|
||||
import { createClient } from "@hey-api/openapi-ts"
|
||||
|
||||
await $`bun dev generate > openapi.json`.cwd(path.resolve(dir, "../../opencode"))
|
||||
await $`bun dev generate > ${dir}/openapi.json`.cwd(path.resolve(dir, "../../opencode"))
|
||||
|
||||
await createClient({
|
||||
input: "./openapi.json",
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
|
||||
|
||||
export {
|
||||
Permissions,
|
||||
type Permission,
|
||||
type PermissionRespondResponse,
|
||||
type PermissionRespondParams,
|
||||
} from './permissions';
|
||||
export {
|
||||
SessionResource,
|
||||
type AssistantMessage,
|
||||
type FilePart,
|
||||
type FilePartInput,
|
||||
type FilePartSource,
|
||||
type FilePartSourceText,
|
||||
type FileSource,
|
||||
type Message,
|
||||
type Part,
|
||||
type Session,
|
||||
type SnapshotPart,
|
||||
type StepFinishPart,
|
||||
type StepStartPart,
|
||||
type SymbolSource,
|
||||
type TextPart,
|
||||
type TextPartInput,
|
||||
type ToolPart,
|
||||
type ToolStateCompleted,
|
||||
type ToolStateError,
|
||||
type ToolStatePending,
|
||||
type ToolStateRunning,
|
||||
type UserMessage,
|
||||
type SessionListResponse,
|
||||
type SessionDeleteResponse,
|
||||
type SessionAbortResponse,
|
||||
type SessionInitResponse,
|
||||
type SessionMessageResponse,
|
||||
type SessionMessagesResponse,
|
||||
type SessionSummarizeResponse,
|
||||
type SessionChatParams,
|
||||
type SessionInitParams,
|
||||
type SessionMessageParams,
|
||||
type SessionRevertParams,
|
||||
type SessionSummarizeParams,
|
||||
} from './session';
|
||||
@@ -1,64 +0,0 @@
|
||||
// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
|
||||
|
||||
import { APIResource } from '../../core/resource';
|
||||
import { APIPromise } from '../../core/api-promise';
|
||||
import { RequestOptions } from '../../internal/request-options';
|
||||
import { path } from '../../internal/utils/path';
|
||||
|
||||
export class Permissions extends APIResource {
|
||||
/**
|
||||
* Respond to a permission request
|
||||
*/
|
||||
respond(
|
||||
permissionID: string,
|
||||
params: PermissionRespondParams,
|
||||
options?: RequestOptions,
|
||||
): APIPromise<PermissionRespondResponse> {
|
||||
const { id, ...body } = params;
|
||||
return this._client.post(path`/session/${id}/permissions/${permissionID}`, { body, ...options });
|
||||
}
|
||||
}
|
||||
|
||||
export interface Permission {
|
||||
id: string;
|
||||
|
||||
messageID: string;
|
||||
|
||||
metadata: { [key: string]: unknown };
|
||||
|
||||
sessionID: string;
|
||||
|
||||
time: Permission.Time;
|
||||
|
||||
title: string;
|
||||
|
||||
toolCallID?: string;
|
||||
}
|
||||
|
||||
export namespace Permission {
|
||||
export interface Time {
|
||||
created: number;
|
||||
}
|
||||
}
|
||||
|
||||
export type PermissionRespondResponse = boolean;
|
||||
|
||||
export interface PermissionRespondParams {
|
||||
/**
|
||||
* Path param:
|
||||
*/
|
||||
id: string;
|
||||
|
||||
/**
|
||||
* Body param:
|
||||
*/
|
||||
response: 'once' | 'always' | 'reject';
|
||||
}
|
||||
|
||||
export declare namespace Permissions {
|
||||
export {
|
||||
type Permission as Permission,
|
||||
type PermissionRespondResponse as PermissionRespondResponse,
|
||||
type PermissionRespondParams as PermissionRespondParams,
|
||||
};
|
||||
}
|
||||
@@ -1,645 +0,0 @@
|
||||
// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
|
||||
|
||||
import { APIResource } from '../../core/resource';
|
||||
import * as SessionAPI from './session';
|
||||
import * as Shared from '../shared';
|
||||
import * as PermissionsAPI from './permissions';
|
||||
import { Permission, PermissionRespondParams, PermissionRespondResponse, Permissions } from './permissions';
|
||||
import { APIPromise } from '../../core/api-promise';
|
||||
import { RequestOptions } from '../../internal/request-options';
|
||||
import { path } from '../../internal/utils/path';
|
||||
|
||||
export class SessionResource extends APIResource {
|
||||
permissions: PermissionsAPI.Permissions = new PermissionsAPI.Permissions(this._client);
|
||||
|
||||
/**
|
||||
* Create a new session
|
||||
*/
|
||||
create(options?: RequestOptions): APIPromise<Session> {
|
||||
return this._client.post('/session', options);
|
||||
}
|
||||
|
||||
/**
|
||||
* List all sessions
|
||||
*/
|
||||
list(options?: RequestOptions): APIPromise<SessionListResponse> {
|
||||
return this._client.get('/session', options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a session and all its data
|
||||
*/
|
||||
delete(id: string, options?: RequestOptions): APIPromise<SessionDeleteResponse> {
|
||||
return this._client.delete(path`/session/${id}`, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Abort a session
|
||||
*/
|
||||
abort(id: string, options?: RequestOptions): APIPromise<SessionAbortResponse> {
|
||||
return this._client.post(path`/session/${id}/abort`, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and send a new message to a session
|
||||
*/
|
||||
chat(id: string, body: SessionChatParams, options?: RequestOptions): APIPromise<AssistantMessage> {
|
||||
return this._client.post(path`/session/${id}/message`, { body, ...options });
|
||||
}
|
||||
|
||||
/**
|
||||
* Analyze the app and create an AGENTS.md file
|
||||
*/
|
||||
init(id: string, body: SessionInitParams, options?: RequestOptions): APIPromise<SessionInitResponse> {
|
||||
return this._client.post(path`/session/${id}/init`, { body, ...options });
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a message from a session
|
||||
*/
|
||||
message(
|
||||
messageID: string,
|
||||
params: SessionMessageParams,
|
||||
options?: RequestOptions,
|
||||
): APIPromise<SessionMessageResponse> {
|
||||
const { id } = params;
|
||||
return this._client.get(path`/session/${id}/message/${messageID}`, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* List messages for a session
|
||||
*/
|
||||
messages(id: string, options?: RequestOptions): APIPromise<SessionMessagesResponse> {
|
||||
return this._client.get(path`/session/${id}/message`, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Revert a message
|
||||
*/
|
||||
revert(id: string, body: SessionRevertParams, options?: RequestOptions): APIPromise<Session> {
|
||||
return this._client.post(path`/session/${id}/revert`, { body, ...options });
|
||||
}
|
||||
|
||||
/**
|
||||
* Share a session
|
||||
*/
|
||||
share(id: string, options?: RequestOptions): APIPromise<Session> {
|
||||
return this._client.post(path`/session/${id}/share`, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Summarize the session
|
||||
*/
|
||||
summarize(
|
||||
id: string,
|
||||
body: SessionSummarizeParams,
|
||||
options?: RequestOptions,
|
||||
): APIPromise<SessionSummarizeResponse> {
|
||||
return this._client.post(path`/session/${id}/summarize`, { body, ...options });
|
||||
}
|
||||
|
||||
/**
|
||||
* Restore all reverted messages
|
||||
*/
|
||||
unrevert(id: string, options?: RequestOptions): APIPromise<Session> {
|
||||
return this._client.post(path`/session/${id}/unrevert`, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unshare the session
|
||||
*/
|
||||
unshare(id: string, options?: RequestOptions): APIPromise<Session> {
|
||||
return this._client.delete(path`/session/${id}/share`, options);
|
||||
}
|
||||
}
|
||||
|
||||
export interface AssistantMessage {
|
||||
id: string;
|
||||
|
||||
cost: number;
|
||||
|
||||
mode: string;
|
||||
|
||||
modelID: string;
|
||||
|
||||
path: AssistantMessage.Path;
|
||||
|
||||
providerID: string;
|
||||
|
||||
role: 'assistant';
|
||||
|
||||
sessionID: string;
|
||||
|
||||
system: Array<string>;
|
||||
|
||||
time: AssistantMessage.Time;
|
||||
|
||||
tokens: AssistantMessage.Tokens;
|
||||
|
||||
error?:
|
||||
| Shared.ProviderAuthError
|
||||
| Shared.UnknownError
|
||||
| AssistantMessage.MessageOutputLengthError
|
||||
| Shared.MessageAbortedError;
|
||||
|
||||
summary?: boolean;
|
||||
}
|
||||
|
||||
export namespace AssistantMessage {
|
||||
export interface Path {
|
||||
cwd: string;
|
||||
|
||||
root: string;
|
||||
}
|
||||
|
||||
export interface Time {
|
||||
created: number;
|
||||
|
||||
completed?: number;
|
||||
}
|
||||
|
||||
export interface Tokens {
|
||||
cache: Tokens.Cache;
|
||||
|
||||
input: number;
|
||||
|
||||
output: number;
|
||||
|
||||
reasoning: number;
|
||||
}
|
||||
|
||||
export namespace Tokens {
|
||||
export interface Cache {
|
||||
read: number;
|
||||
|
||||
write: number;
|
||||
}
|
||||
}
|
||||
|
||||
export interface MessageOutputLengthError {
|
||||
data: unknown;
|
||||
|
||||
name: 'MessageOutputLengthError';
|
||||
}
|
||||
}
|
||||
|
||||
export interface FilePart {
|
||||
id: string;
|
||||
|
||||
messageID: string;
|
||||
|
||||
mime: string;
|
||||
|
||||
sessionID: string;
|
||||
|
||||
type: 'file';
|
||||
|
||||
url: string;
|
||||
|
||||
filename?: string;
|
||||
|
||||
source?: FilePartSource;
|
||||
}
|
||||
|
||||
export interface FilePartInput {
|
||||
mime: string;
|
||||
|
||||
type: 'file';
|
||||
|
||||
url: string;
|
||||
|
||||
id?: string;
|
||||
|
||||
filename?: string;
|
||||
|
||||
source?: FilePartSource;
|
||||
}
|
||||
|
||||
export type FilePartSource = FileSource | SymbolSource;
|
||||
|
||||
export interface FilePartSourceText {
|
||||
end: number;
|
||||
|
||||
start: number;
|
||||
|
||||
value: string;
|
||||
}
|
||||
|
||||
export interface FileSource {
|
||||
path: string;
|
||||
|
||||
text: FilePartSourceText;
|
||||
|
||||
type: 'file';
|
||||
}
|
||||
|
||||
export type Message = UserMessage | AssistantMessage;
|
||||
|
||||
export type Part =
|
||||
| TextPart
|
||||
| FilePart
|
||||
| ToolPart
|
||||
| StepStartPart
|
||||
| StepFinishPart
|
||||
| SnapshotPart
|
||||
| Part.PatchPart;
|
||||
|
||||
export namespace Part {
|
||||
export interface PatchPart {
|
||||
id: string;
|
||||
|
||||
files: Array<string>;
|
||||
|
||||
hash: string;
|
||||
|
||||
messageID: string;
|
||||
|
||||
sessionID: string;
|
||||
|
||||
type: 'patch';
|
||||
}
|
||||
}
|
||||
|
||||
export interface Session {
|
||||
id: string;
|
||||
|
||||
time: Session.Time;
|
||||
|
||||
title: string;
|
||||
|
||||
version: string;
|
||||
|
||||
parentID?: string;
|
||||
|
||||
revert?: Session.Revert;
|
||||
|
||||
share?: Session.Share;
|
||||
}
|
||||
|
||||
export namespace Session {
|
||||
export interface Time {
|
||||
created: number;
|
||||
|
||||
updated: number;
|
||||
}
|
||||
|
||||
export interface Revert {
|
||||
messageID: string;
|
||||
|
||||
diff?: string;
|
||||
|
||||
partID?: string;
|
||||
|
||||
snapshot?: string;
|
||||
}
|
||||
|
||||
export interface Share {
|
||||
url: string;
|
||||
}
|
||||
}
|
||||
|
||||
export interface SnapshotPart {
|
||||
id: string;
|
||||
|
||||
messageID: string;
|
||||
|
||||
sessionID: string;
|
||||
|
||||
snapshot: string;
|
||||
|
||||
type: 'snapshot';
|
||||
}
|
||||
|
||||
export interface StepFinishPart {
|
||||
id: string;
|
||||
|
||||
cost: number;
|
||||
|
||||
messageID: string;
|
||||
|
||||
sessionID: string;
|
||||
|
||||
tokens: StepFinishPart.Tokens;
|
||||
|
||||
type: 'step-finish';
|
||||
}
|
||||
|
||||
export namespace StepFinishPart {
|
||||
export interface Tokens {
|
||||
cache: Tokens.Cache;
|
||||
|
||||
input: number;
|
||||
|
||||
output: number;
|
||||
|
||||
reasoning: number;
|
||||
}
|
||||
|
||||
export namespace Tokens {
|
||||
export interface Cache {
|
||||
read: number;
|
||||
|
||||
write: number;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export interface StepStartPart {
|
||||
id: string;
|
||||
|
||||
messageID: string;
|
||||
|
||||
sessionID: string;
|
||||
|
||||
type: 'step-start';
|
||||
}
|
||||
|
||||
export interface SymbolSource {
|
||||
kind: number;
|
||||
|
||||
name: string;
|
||||
|
||||
path: string;
|
||||
|
||||
range: SymbolSource.Range;
|
||||
|
||||
text: FilePartSourceText;
|
||||
|
||||
type: 'symbol';
|
||||
}
|
||||
|
||||
export namespace SymbolSource {
|
||||
export interface Range {
|
||||
end: Range.End;
|
||||
|
||||
start: Range.Start;
|
||||
}
|
||||
|
||||
export namespace Range {
|
||||
export interface End {
|
||||
character: number;
|
||||
|
||||
line: number;
|
||||
}
|
||||
|
||||
export interface Start {
|
||||
character: number;
|
||||
|
||||
line: number;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export interface TextPart {
|
||||
id: string;
|
||||
|
||||
messageID: string;
|
||||
|
||||
sessionID: string;
|
||||
|
||||
text: string;
|
||||
|
||||
type: 'text';
|
||||
|
||||
synthetic?: boolean;
|
||||
|
||||
time?: TextPart.Time;
|
||||
}
|
||||
|
||||
export namespace TextPart {
|
||||
export interface Time {
|
||||
start: number;
|
||||
|
||||
end?: number;
|
||||
}
|
||||
}
|
||||
|
||||
export interface TextPartInput {
|
||||
text: string;
|
||||
|
||||
type: 'text';
|
||||
|
||||
id?: string;
|
||||
|
||||
synthetic?: boolean;
|
||||
|
||||
time?: TextPartInput.Time;
|
||||
}
|
||||
|
||||
export namespace TextPartInput {
|
||||
export interface Time {
|
||||
start: number;
|
||||
|
||||
end?: number;
|
||||
}
|
||||
}
|
||||
|
||||
export interface ToolPart {
|
||||
id: string;
|
||||
|
||||
callID: string;
|
||||
|
||||
messageID: string;
|
||||
|
||||
sessionID: string;
|
||||
|
||||
state: ToolStatePending | ToolStateRunning | ToolStateCompleted | ToolStateError;
|
||||
|
||||
tool: string;
|
||||
|
||||
type: 'tool';
|
||||
}
|
||||
|
||||
export interface ToolStateCompleted {
|
||||
input: { [key: string]: unknown };
|
||||
|
||||
metadata: { [key: string]: unknown };
|
||||
|
||||
output: string;
|
||||
|
||||
status: 'completed';
|
||||
|
||||
time: ToolStateCompleted.Time;
|
||||
|
||||
title: string;
|
||||
}
|
||||
|
||||
export namespace ToolStateCompleted {
|
||||
export interface Time {
|
||||
end: number;
|
||||
|
||||
start: number;
|
||||
}
|
||||
}
|
||||
|
||||
export interface ToolStateError {
|
||||
error: string;
|
||||
|
||||
input: { [key: string]: unknown };
|
||||
|
||||
status: 'error';
|
||||
|
||||
time: ToolStateError.Time;
|
||||
}
|
||||
|
||||
export namespace ToolStateError {
|
||||
export interface Time {
|
||||
end: number;
|
||||
|
||||
start: number;
|
||||
}
|
||||
}
|
||||
|
||||
export interface ToolStatePending {
|
||||
status: 'pending';
|
||||
}
|
||||
|
||||
export interface ToolStateRunning {
|
||||
status: 'running';
|
||||
|
||||
time: ToolStateRunning.Time;
|
||||
|
||||
input?: unknown;
|
||||
|
||||
metadata?: { [key: string]: unknown };
|
||||
|
||||
title?: string;
|
||||
}
|
||||
|
||||
export namespace ToolStateRunning {
|
||||
export interface Time {
|
||||
start: number;
|
||||
}
|
||||
}
|
||||
|
||||
export interface UserMessage {
|
||||
id: string;
|
||||
|
||||
role: 'user';
|
||||
|
||||
sessionID: string;
|
||||
|
||||
time: UserMessage.Time;
|
||||
}
|
||||
|
||||
export namespace UserMessage {
|
||||
export interface Time {
|
||||
created: number;
|
||||
}
|
||||
}
|
||||
|
||||
export type SessionListResponse = Array<Session>;
|
||||
|
||||
export type SessionDeleteResponse = boolean;
|
||||
|
||||
export type SessionAbortResponse = boolean;
|
||||
|
||||
export type SessionInitResponse = boolean;
|
||||
|
||||
export interface SessionMessageResponse {
|
||||
info: Message;
|
||||
|
||||
parts: Array<Part>;
|
||||
}
|
||||
|
||||
export type SessionMessagesResponse = Array<SessionMessagesResponse.SessionMessagesResponseItem>;
|
||||
|
||||
export namespace SessionMessagesResponse {
|
||||
export interface SessionMessagesResponseItem {
|
||||
info: SessionAPI.Message;
|
||||
|
||||
parts: Array<SessionAPI.Part>;
|
||||
}
|
||||
}
|
||||
|
||||
export type SessionSummarizeResponse = boolean;
|
||||
|
||||
export interface SessionChatParams {
|
||||
modelID: string;
|
||||
|
||||
parts: Array<TextPartInput | FilePartInput>;
|
||||
|
||||
providerID: string;
|
||||
|
||||
messageID?: string;
|
||||
|
||||
mode?: string;
|
||||
|
||||
system?: string;
|
||||
|
||||
tools?: { [key: string]: boolean };
|
||||
}
|
||||
|
||||
export interface SessionInitParams {
|
||||
messageID: string;
|
||||
|
||||
modelID: string;
|
||||
|
||||
providerID: string;
|
||||
}
|
||||
|
||||
export interface SessionMessageParams {
|
||||
/**
|
||||
* Session ID
|
||||
*/
|
||||
id: string;
|
||||
}
|
||||
|
||||
export interface SessionRevertParams {
|
||||
messageID: string;
|
||||
|
||||
partID?: string;
|
||||
}
|
||||
|
||||
export interface SessionSummarizeParams {
|
||||
modelID: string;
|
||||
|
||||
providerID: string;
|
||||
}
|
||||
|
||||
SessionResource.Permissions = Permissions;
|
||||
|
||||
export declare namespace SessionResource {
|
||||
export {
|
||||
type AssistantMessage as AssistantMessage,
|
||||
type FilePart as FilePart,
|
||||
type FilePartInput as FilePartInput,
|
||||
type FilePartSource as FilePartSource,
|
||||
type FilePartSourceText as FilePartSourceText,
|
||||
type FileSource as FileSource,
|
||||
type Message as Message,
|
||||
type Part as Part,
|
||||
type Session as Session,
|
||||
type SnapshotPart as SnapshotPart,
|
||||
type StepFinishPart as StepFinishPart,
|
||||
type StepStartPart as StepStartPart,
|
||||
type SymbolSource as SymbolSource,
|
||||
type TextPart as TextPart,
|
||||
type TextPartInput as TextPartInput,
|
||||
type ToolPart as ToolPart,
|
||||
type ToolStateCompleted as ToolStateCompleted,
|
||||
type ToolStateError as ToolStateError,
|
||||
type ToolStatePending as ToolStatePending,
|
||||
type ToolStateRunning as ToolStateRunning,
|
||||
type UserMessage as UserMessage,
|
||||
type SessionListResponse as SessionListResponse,
|
||||
type SessionDeleteResponse as SessionDeleteResponse,
|
||||
type SessionAbortResponse as SessionAbortResponse,
|
||||
type SessionInitResponse as SessionInitResponse,
|
||||
type SessionMessageResponse as SessionMessageResponse,
|
||||
type SessionMessagesResponse as SessionMessagesResponse,
|
||||
type SessionSummarizeResponse as SessionSummarizeResponse,
|
||||
type SessionChatParams as SessionChatParams,
|
||||
type SessionInitParams as SessionInitParams,
|
||||
type SessionMessageParams as SessionMessageParams,
|
||||
type SessionRevertParams as SessionRevertParams,
|
||||
type SessionSummarizeParams as SessionSummarizeParams,
|
||||
};
|
||||
|
||||
export {
|
||||
Permissions as Permissions,
|
||||
type Permission as Permission,
|
||||
type PermissionRespondResponse as PermissionRespondResponse,
|
||||
type PermissionRespondParams as PermissionRespondParams,
|
||||
};
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
|
||||
|
||||
import Opencode from '@opencode-ai/sdk';
|
||||
|
||||
const client = new Opencode({ baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010' });
|
||||
|
||||
describe('resource permissions', () => {
|
||||
// skipped: tests are disabled for the time being
|
||||
test.skip('respond: only required params', async () => {
|
||||
const responsePromise = client.session.permissions.respond('permissionID', {
|
||||
id: 'id',
|
||||
response: 'once',
|
||||
});
|
||||
const rawResponse = await responsePromise.asResponse();
|
||||
expect(rawResponse).toBeInstanceOf(Response);
|
||||
const response = await responsePromise;
|
||||
expect(response).not.toBeInstanceOf(Response);
|
||||
const dataAndResponse = await responsePromise.withResponse();
|
||||
expect(dataAndResponse.data).toBe(response);
|
||||
expect(dataAndResponse.response).toBe(rawResponse);
|
||||
});
|
||||
|
||||
// skipped: tests are disabled for the time being
|
||||
test.skip('respond: required and optional params', async () => {
|
||||
const response = await client.session.permissions.respond('permissionID', { id: 'id', response: 'once' });
|
||||
});
|
||||
});
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@opencode/web",
|
||||
"type": "module",
|
||||
"version": "0.3.113",
|
||||
"version": "0.3.126",
|
||||
"scripts": {
|
||||
"dev": "astro dev",
|
||||
"dev:remote": "sst shell --stage=dev --target=Web astro dev",
|
||||
|
||||
@@ -230,6 +230,20 @@ You can also define agents using markdown files in `~/.config/opencode/agent/` o
|
||||
|
||||
You can disable providers that are loaded automatically through the `disabled_providers` option. This is useful when you want to prevent certain providers from being loaded even if their credentials are available.
|
||||
|
||||
The `disabled_providers` option accepts an array of provider IDs. When a provider is disabled:
|
||||
|
||||
- It won't be loaded even if environment variables are set
|
||||
- It won't be loaded even if API keys are configured through `opencode auth login`
|
||||
- The provider's models won't appear in the model selection list
|
||||
|
||||
|
||||
```json title="opencode.json"
|
||||
{
|
||||
"$schema": "https://opencode.ai/config.json",
|
||||
"disabled_providers": ["openai", "gemini"]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Formatters
|
||||
@@ -239,16 +253,21 @@ You can configure code formatters through the `formatter` option. See [Formatter
|
||||
```json title="opencode.json"
|
||||
{
|
||||
"$schema": "https://opencode.ai/config.json",
|
||||
"disabled_providers": ["openai", "gemini"]
|
||||
"formatter": {
|
||||
"prettier": {
|
||||
"disabled": true
|
||||
},
|
||||
"custom-prettier": {
|
||||
"command": ["npx", "prettier", "--write", "$FILE"],
|
||||
"environment": {
|
||||
"NODE_ENV": "development"
|
||||
},
|
||||
"extensions": [".js", ".ts", ".jsx", ".tsx"]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The `disabled_providers` option accepts an array of provider IDs. When a provider is disabled:
|
||||
|
||||
- It won't be loaded even if environment variables are set
|
||||
- It won't be loaded even if API keys are configured through `opencode auth login`
|
||||
- The provider's models won't appear in the model selection list
|
||||
|
||||
---
|
||||
|
||||
### Permissions
|
||||
|
||||
@@ -106,7 +106,7 @@ Here are some examples of how you can use opencode in GitHub.
|
||||
|
||||
And opencode will create a new branch, implement the changes, and open a PR with the changes.
|
||||
|
||||
- Review PRs and make changes
|
||||
- **Review PRs and make changes**
|
||||
|
||||
Leave the following comment on a GitHub PR.
|
||||
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
---
|
||||
title: Plugins
|
||||
description: Extend opencode with custom plugins.
|
||||
---
|
||||
|
||||
Plugins allow you to extend opencode's functionality by hooking into various events and customizing behavior. You can create plugins to add new features, integrate with external services, or modify opencode's default behavior.
|
||||
|
||||
---
|
||||
|
||||
## Creating a Plugin
|
||||
|
||||
A plugin is a JavaScript/TypeScript module that exports one or more plugin
|
||||
functions. Each function receives a context object and returns a hooks object.
|
||||
They are loaded from the `.opencode/plugin` directory either in your proejct or
|
||||
globally in `~/.config/opencode/plugin`.
|
||||
|
||||
### Basic Structure
|
||||
|
||||
```typescript title=".opencode/plugin/example.js"
|
||||
export const MyPlugin = async ({ app, client, $ }) => {
|
||||
console.log("Plugin initialized!")
|
||||
|
||||
return {
|
||||
// Hook implementations go here
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The plugin function receives:
|
||||
|
||||
- `app` - The opencode application instance
|
||||
- `client` - An opencode SDK client for interacting with the AI
|
||||
- `$` - Bun's shell API for executing commands
|
||||
|
||||
### TypeScript Support
|
||||
|
||||
For TypeScript plugins, you can import types from the plugin package:
|
||||
|
||||
```typescript title="my-plugin.ts"
|
||||
import type { Plugin } from "@opencode-ai/plugin"
|
||||
|
||||
export const MyPlugin: Plugin = async ({ app, client, $ }) => {
|
||||
return {
|
||||
// Type-safe hook implementations
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Examples
|
||||
|
||||
### Notification Plugin
|
||||
|
||||
Send notifications when certain events occur:
|
||||
|
||||
```javascript title=".opencode/plugin/notification.js"
|
||||
export const NotificationPlugin = async ({ client, $ }) => {
|
||||
return {
|
||||
event: async ({ event }) => {
|
||||
// Send notification on session completion
|
||||
if (event.type === "session.idle") {
|
||||
await $`osascript -e 'display notification "Session completed!" with title "opencode"'`
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### .env Protection
|
||||
|
||||
Integrate with external services:
|
||||
|
||||
```javascript title=".opencode/plugin/slack.js"
|
||||
export const EnvProtection = async ({ client, $ }) => {
|
||||
return {
|
||||
tool: {
|
||||
execute: {
|
||||
before: async (input, output) => {
|
||||
if (input.tool === "read" && output.args.filePath.includes(".env")) {
|
||||
throw new Error("Do not read .env files")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,16 @@
|
||||
diff --git a/node_modules/marked-shiki/.bun-tag-5eae3435af8a0229 b/.bun-tag-5eae3435af8a0229
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
|
||||
diff --git a/dist/index.js b/dist/index.js
|
||||
index 535885e8569626d08f205e76c4944e4ebd0decab..92b5695c1b05fc7db5d26128c8f948d43c91f88a 100644
|
||||
--- a/dist/index.js
|
||||
+++ b/dist/index.js
|
||||
@@ -4,7 +4,7 @@ function o(s = {}) {
|
||||
async: !0,
|
||||
async walkTokens(t) {
|
||||
if (t.type !== "code" || typeof e != "function") return;
|
||||
- const [a = "text", ...i] = t.lang.split(" "), { text: c } = t, r = await e(c, a, i), l = n ? n.replace("%l", String(a).toUpperCase()).replace("%s", r).replace("%t", c) : r;
|
||||
+ const [a = "text", ...i] = t.lang?.split(" "), { text: c } = t, r = await e(c, a, i), l = n ? n.replace("%l", String(a).toUpperCase()).replace("%s", r).replace("%t", c) : r;
|
||||
Object.assign(t, {
|
||||
type: "html",
|
||||
block: !0,
|
||||
+13
-9
@@ -2,6 +2,8 @@
|
||||
|
||||
import { $ } from "bun"
|
||||
|
||||
console.log("=== publishing ===\n")
|
||||
|
||||
const snapshot = process.env["OPENCODE_SNAPSHOT"] === "true"
|
||||
const version = snapshot
|
||||
? `0.0.0-${new Date().toISOString().slice(0, 16).replace(/[-:T]/g, "")}`
|
||||
@@ -10,26 +12,30 @@ if (!version) {
|
||||
throw new Error("OPENCODE_VERSION is required")
|
||||
}
|
||||
process.env["OPENCODE_VERSION"] = version
|
||||
console.log("version:", version)
|
||||
|
||||
const pkgjsons = await Array.fromAsync(
|
||||
new Bun.Glob("**/package.json").scan({
|
||||
absolute: true,
|
||||
}),
|
||||
)
|
||||
).then((arr) => arr.filter((x) => !x.includes("node_modules") && !x.includes("dist")))
|
||||
|
||||
const tree = await $`git add . && git write-tree`.text().then((x) => x.trim())
|
||||
for await (const file of new Bun.Glob("**/package.json").scan({
|
||||
absolute: true,
|
||||
})) {
|
||||
for (const file of pkgjsons) {
|
||||
let pkg = await Bun.file(file).text()
|
||||
pkg = pkg.replaceAll(/"version": "[^"]+"/g, `"version": "${version}"`)
|
||||
console.log("updated:", file)
|
||||
await Bun.file(file).write(pkg)
|
||||
}
|
||||
|
||||
console.log("\n=== opencode ===\n")
|
||||
await import(`../packages/opencode/script/publish.ts`)
|
||||
|
||||
console.log("\n=== sdk ===\n")
|
||||
await import(`../packages/sdk/js/script/publish.ts`)
|
||||
|
||||
console.log("\n=== plugin ===\n")
|
||||
await import(`../packages/plugin/script/publish.ts`)
|
||||
// await import(`../packages/sdk/stainless/generate.ts`)
|
||||
|
||||
if (!snapshot) {
|
||||
await $`git commit -am "release: v${version}"`
|
||||
@@ -43,9 +49,7 @@ if (snapshot) {
|
||||
await $`git push origin v${version} --no-verify`
|
||||
await $`git checkout dev`
|
||||
await $`git branch -D snapshot-${version}`
|
||||
for await (const file of new Bun.Glob("**/package.json").scan({
|
||||
absolute: true,
|
||||
})) {
|
||||
$`await git checkout ${tree} ${file}`
|
||||
for (const file of pkgjsons) {
|
||||
await $`git checkout ${tree} ${file}`
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"name": "opencode",
|
||||
"displayName": "opencode",
|
||||
"description": "opencode for VS Code",
|
||||
"version": "0.3.113",
|
||||
"version": "0.3.126",
|
||||
"publisher": "sst-dev",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
Reference in New Issue
Block a user