Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a0b17439f9 | |||
| 1261b7d333 | |||
| a3f38e0533 | |||
| 681a257df6 | |||
| 586207adb4 | |||
| a58dbb3b5c | |||
| 131d8e5778 | |||
| 0cf0294787 |
@@ -26,7 +26,7 @@ jobs:
|
||||
- uses: ./.github/actions/setup-bun
|
||||
|
||||
- name: Run opencode
|
||||
uses: sst/opencode/github@latest
|
||||
uses: anomalyco/opencode/github@latest
|
||||
env:
|
||||
OPENCODE_API_KEY: ${{ secrets.OPENCODE_API_KEY }}
|
||||
OPENCODE_PERMISSION: '{"bash": "deny"}'
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
"module": "index.ts",
|
||||
"type": "module",
|
||||
"private": true,
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@types/bun": "catalog:"
|
||||
},
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"name": "@opencode-ai/console-app",
|
||||
"version": "1.0.224",
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"typecheck": "tsgo --noEmit",
|
||||
"dev": "vite dev --host 0.0.0.0",
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
"version": "1.0.224",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@aws-sdk/client-sts": "3.782.0",
|
||||
"@jsx-email/render": "1.1.1",
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
"$schema": "https://json.schemastore.org/package.json",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"typecheck": "tsgo --noEmit"
|
||||
},
|
||||
|
||||
@@ -17,5 +17,6 @@
|
||||
"scripts": {
|
||||
"dev": "email preview emails/templates"
|
||||
},
|
||||
"type": "module"
|
||||
"type": "module",
|
||||
"license": "MIT"
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/package.json",
|
||||
"name": "@opencode-ai/console-resource",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@cloudflare/workers-types": "catalog:"
|
||||
},
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
"private": true,
|
||||
"version": "1.0.224",
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"typecheck": "tsgo -b",
|
||||
"predev": "bun ./scripts/predev.ts",
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
"version": "1.0.224",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"typecheck": "tsgo --noEmit",
|
||||
"dev": "vite dev",
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
"$schema": "https://json.schemastore.org/package.json",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@cloudflare/workers-types": "catalog:",
|
||||
"@tsconfig/node22": "22.0.2",
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
"version": "1.0.224",
|
||||
"name": "opencode",
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"typecheck": "tsgo --noEmit",
|
||||
|
||||
@@ -549,6 +549,13 @@ function App() {
|
||||
})
|
||||
})
|
||||
|
||||
sdk.event.on(TuiEvent.SessionSelect.type, (evt) => {
|
||||
route.navigate({
|
||||
type: "session",
|
||||
sessionID: evt.properties.sessionID,
|
||||
})
|
||||
})
|
||||
|
||||
sdk.event.on(SessionApi.Event.Deleted.type, (evt) => {
|
||||
if (route.data.type === "session" && route.data.sessionID === evt.properties.info.id) {
|
||||
route.navigate({ type: "home" })
|
||||
|
||||
@@ -37,4 +37,10 @@ export const TuiEvent = {
|
||||
duration: z.number().default(5000).optional().describe("Duration in milliseconds"),
|
||||
}),
|
||||
),
|
||||
SessionSelect: BusEvent.define(
|
||||
"tui.session.select",
|
||||
z.object({
|
||||
sessionID: z.string().regex(/^ses/).describe("Session ID to navigate to"),
|
||||
}),
|
||||
),
|
||||
}
|
||||
|
||||
@@ -45,6 +45,8 @@ export const LANGUAGE_EXTENSIONS: Record<string, string> = {
|
||||
".ini": "ini",
|
||||
".java": "java",
|
||||
".js": "javascript",
|
||||
".kt": "kotlin",
|
||||
".kts": "kotlin",
|
||||
".jsx": "javascriptreact",
|
||||
".json": "json",
|
||||
".tex": "latex",
|
||||
|
||||
@@ -1209,6 +1209,85 @@ export namespace LSPServer {
|
||||
},
|
||||
}
|
||||
|
||||
export const KotlinLS: Info = {
|
||||
id: "kotlin-ls",
|
||||
extensions: [".kt", ".kts"],
|
||||
root: NearestRoot(["build.gradle", "build.gradle.kts", "settings.gradle.kts", "pom.xml"]),
|
||||
async spawn(root) {
|
||||
const distPath = path.join(Global.Path.bin, "kotlin-ls")
|
||||
const launcherScript =
|
||||
process.platform === "win32" ? path.join(distPath, "kotlin-lsp.cmd") : path.join(distPath, "kotlin-lsp.sh")
|
||||
const installed = await Bun.file(launcherScript).exists()
|
||||
if (!installed) {
|
||||
if (Flag.OPENCODE_DISABLE_LSP_DOWNLOAD) return
|
||||
log.info("Downloading Kotlin Language Server from GitHub.")
|
||||
|
||||
const releaseResponse = await fetch("https://api.github.com/repos/Kotlin/kotlin-lsp/releases/latest")
|
||||
if (!releaseResponse.ok) {
|
||||
log.error("Failed to fetch kotlin-lsp release info")
|
||||
return
|
||||
}
|
||||
|
||||
const release = await releaseResponse.json()
|
||||
const version = release.name?.replace(/^v/, "")
|
||||
|
||||
if (!version) {
|
||||
log.error("Could not determine Kotlin LSP version from release")
|
||||
return
|
||||
}
|
||||
|
||||
const platform = process.platform
|
||||
const arch = process.arch
|
||||
|
||||
let kotlinArch: string = arch
|
||||
if (arch === "arm64") kotlinArch = "aarch64"
|
||||
else if (arch === "x64") kotlinArch = "x64"
|
||||
|
||||
let kotlinPlatform: string = platform
|
||||
if (platform === "darwin") kotlinPlatform = "mac"
|
||||
else if (platform === "linux") kotlinPlatform = "linux"
|
||||
else if (platform === "win32") kotlinPlatform = "win"
|
||||
|
||||
const supportedCombos = ["mac-x64", "mac-aarch64", "linux-x64", "linux-aarch64", "win-x64", "win-aarch64"]
|
||||
|
||||
const combo = `${kotlinPlatform}-${kotlinArch}`
|
||||
|
||||
if (!supportedCombos.includes(combo)) {
|
||||
log.error(`Platform ${platform}/${arch} is not supported by Kotlin LSP`)
|
||||
return
|
||||
}
|
||||
|
||||
const assetName = `kotlin-lsp-${version}-${kotlinPlatform}-${kotlinArch}.zip`
|
||||
const releaseURL = `https://download-cdn.jetbrains.com/kotlin-lsp/${version}/${assetName}`
|
||||
|
||||
await fs.mkdir(distPath, { recursive: true })
|
||||
const archivePath = path.join(distPath, "kotlin-ls.zip")
|
||||
await $`curl -L -o '${archivePath}' '${releaseURL}'`.quiet().nothrow()
|
||||
const ok = await Archive.extractZip(archivePath, distPath)
|
||||
.then(() => true)
|
||||
.catch((error) => {
|
||||
log.error("Failed to extract Kotlin LS archive", { error })
|
||||
return false
|
||||
})
|
||||
if (!ok) return
|
||||
await fs.rm(archivePath, { force: true })
|
||||
if (process.platform !== "win32") {
|
||||
await $`chmod +x ${launcherScript}`.quiet().nothrow()
|
||||
}
|
||||
log.info("Installed Kotlin Language Server", { path: launcherScript })
|
||||
}
|
||||
if (!(await Bun.file(launcherScript).exists())) {
|
||||
log.error(`Failed to locate the Kotlin LS launcher script in the installed directory: ${distPath}.`)
|
||||
return
|
||||
}
|
||||
return {
|
||||
process: spawn(launcherScript, ["--stdio"], {
|
||||
cwd: root,
|
||||
}),
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
export const YamlLS: Info = {
|
||||
id: "yaml-ls",
|
||||
extensions: [".yaml", ".yml"],
|
||||
|
||||
@@ -39,8 +39,9 @@ export namespace Plugin {
|
||||
const lastAtIndex = plugin.lastIndexOf("@")
|
||||
const pkg = lastAtIndex > 0 ? plugin.substring(0, lastAtIndex) : plugin
|
||||
const version = lastAtIndex > 0 ? plugin.substring(lastAtIndex + 1) : "latest"
|
||||
const builtin = BUILTIN.some((x) => x.startsWith(pkg + "@"))
|
||||
plugin = await BunProc.install(pkg, version).catch((err) => {
|
||||
if (BUILTIN.includes(pkg)) return ""
|
||||
if (builtin) return ""
|
||||
throw err
|
||||
})
|
||||
if (!plugin) continue
|
||||
|
||||
@@ -974,6 +974,7 @@ export namespace Server {
|
||||
return c.json(true)
|
||||
},
|
||||
)
|
||||
|
||||
.post(
|
||||
"/session/:sessionID/share",
|
||||
describeRoute({
|
||||
@@ -2600,6 +2601,32 @@ export namespace Server {
|
||||
return c.json(true)
|
||||
},
|
||||
)
|
||||
.post(
|
||||
"/tui/select-session",
|
||||
describeRoute({
|
||||
summary: "Select session",
|
||||
description: "Navigate the TUI to display the specified session.",
|
||||
operationId: "tui.selectSession",
|
||||
responses: {
|
||||
200: {
|
||||
description: "Session selected successfully",
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: resolver(z.boolean()),
|
||||
},
|
||||
},
|
||||
},
|
||||
...errors(400, 404),
|
||||
},
|
||||
}),
|
||||
validator("json", TuiEvent.SessionSelect.properties),
|
||||
async (c) => {
|
||||
const { sessionID } = c.req.valid("json")
|
||||
await Session.get(sessionID)
|
||||
await Bus.publish(TuiEvent.SessionSelect, { sessionID })
|
||||
return c.json(true)
|
||||
},
|
||||
)
|
||||
.route("/tui/control", TuiRoute)
|
||||
.put(
|
||||
"/auth/:providerID",
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
import { describe, expect, test } from "bun:test"
|
||||
import path from "path"
|
||||
import { Session } from "../../src/session"
|
||||
import { Log } from "../../src/util/log"
|
||||
import { Instance } from "../../src/project/instance"
|
||||
import { Server } from "../../src/server/server"
|
||||
|
||||
const projectRoot = path.join(__dirname, "../..")
|
||||
Log.init({ print: false })
|
||||
|
||||
describe("tui.selectSession endpoint", () => {
|
||||
test("should return 200 when called with valid session", async () => {
|
||||
await Instance.provide({
|
||||
directory: projectRoot,
|
||||
fn: async () => {
|
||||
// #given
|
||||
const session = await Session.create({})
|
||||
|
||||
// #when
|
||||
const app = Server.App()
|
||||
const response = await app.request("/tui/select-session", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ sessionID: session.id }),
|
||||
})
|
||||
|
||||
// #then
|
||||
expect(response.status).toBe(200)
|
||||
const body = await response.json()
|
||||
expect(body).toBe(true)
|
||||
|
||||
await Session.remove(session.id)
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
test("should return 404 when session does not exist", async () => {
|
||||
await Instance.provide({
|
||||
directory: projectRoot,
|
||||
fn: async () => {
|
||||
// #given
|
||||
const nonExistentSessionID = "ses_nonexistent123"
|
||||
|
||||
// #when
|
||||
const app = Server.App()
|
||||
const response = await app.request("/tui/select-session", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ sessionID: nonExistentSessionID }),
|
||||
})
|
||||
|
||||
// #then
|
||||
expect(response.status).toBe(404)
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
test("should return 400 when session ID format is invalid", async () => {
|
||||
await Instance.provide({
|
||||
directory: projectRoot,
|
||||
fn: async () => {
|
||||
// #given
|
||||
const invalidSessionID = "invalid_session_id"
|
||||
|
||||
// #when
|
||||
const app = Server.App()
|
||||
const response = await app.request("/tui/select-session", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ sessionID: invalidSessionID }),
|
||||
})
|
||||
|
||||
// #then
|
||||
expect(response.status).toBe(400)
|
||||
},
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -3,6 +3,7 @@
|
||||
"name": "@opencode-ai/plugin",
|
||||
"version": "1.0.224",
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"typecheck": "tsgo --noEmit",
|
||||
"build": "tsc"
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/package",
|
||||
"name": "@opencode-ai/script",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@types/bun": "catalog:"
|
||||
},
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
"name": "@opencode-ai/sdk",
|
||||
"version": "1.0.224",
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"typecheck": "tsgo --noEmit",
|
||||
"build": "./script/build.ts"
|
||||
|
||||
@@ -19,6 +19,7 @@ import type {
|
||||
EventSubscribeResponses,
|
||||
EventTuiCommandExecute,
|
||||
EventTuiPromptAppend,
|
||||
EventTuiSessionSelect,
|
||||
EventTuiToastShow,
|
||||
FileListResponses,
|
||||
FilePartInput,
|
||||
@@ -144,6 +145,8 @@ import type {
|
||||
TuiOpenThemesResponses,
|
||||
TuiPublishErrors,
|
||||
TuiPublishResponses,
|
||||
TuiSelectSessionErrors,
|
||||
TuiSelectSessionResponses,
|
||||
TuiShowToastResponses,
|
||||
TuiSubmitPromptResponses,
|
||||
VcsGetResponses,
|
||||
@@ -2688,7 +2691,7 @@ export class Tui extends HeyApiClient {
|
||||
public publish<ThrowOnError extends boolean = false>(
|
||||
parameters?: {
|
||||
directory?: string
|
||||
body?: EventTuiPromptAppend | EventTuiCommandExecute | EventTuiToastShow
|
||||
body?: EventTuiPromptAppend | EventTuiCommandExecute | EventTuiToastShow | EventTuiSessionSelect
|
||||
},
|
||||
options?: Options<never, ThrowOnError>,
|
||||
) {
|
||||
@@ -2705,6 +2708,41 @@ export class Tui extends HeyApiClient {
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Select session
|
||||
*
|
||||
* Navigate the TUI to display the specified session.
|
||||
*/
|
||||
public selectSession<ThrowOnError extends boolean = false>(
|
||||
parameters?: {
|
||||
directory?: string
|
||||
sessionID?: string
|
||||
},
|
||||
options?: Options<never, ThrowOnError>,
|
||||
) {
|
||||
const params = buildClientParams(
|
||||
[parameters],
|
||||
[
|
||||
{
|
||||
args: [
|
||||
{ in: "query", key: "directory" },
|
||||
{ in: "body", key: "sessionID" },
|
||||
],
|
||||
},
|
||||
],
|
||||
)
|
||||
return (options?.client ?? this.client).post<TuiSelectSessionResponses, TuiSelectSessionErrors, ThrowOnError>({
|
||||
url: "/tui/select-session",
|
||||
...options,
|
||||
...params,
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
...options?.headers,
|
||||
...params.headers,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
control = new Control({ client: this.client })
|
||||
}
|
||||
|
||||
|
||||
@@ -592,6 +592,16 @@ export type EventTuiToastShow = {
|
||||
}
|
||||
}
|
||||
|
||||
export type EventTuiSessionSelect = {
|
||||
type: "tui.session.select"
|
||||
properties: {
|
||||
/**
|
||||
* Session ID to navigate to
|
||||
*/
|
||||
sessionID: string
|
||||
}
|
||||
}
|
||||
|
||||
export type EventMcpToolsChanged = {
|
||||
type: "mcp.tools.changed"
|
||||
properties: {
|
||||
@@ -776,6 +786,7 @@ export type Event =
|
||||
| EventTuiPromptAppend
|
||||
| EventTuiCommandExecute
|
||||
| EventTuiToastShow
|
||||
| EventTuiSessionSelect
|
||||
| EventMcpToolsChanged
|
||||
| EventCommandExecuted
|
||||
| EventSessionCreated
|
||||
@@ -4310,7 +4321,7 @@ export type TuiShowToastResponses = {
|
||||
export type TuiShowToastResponse = TuiShowToastResponses[keyof TuiShowToastResponses]
|
||||
|
||||
export type TuiPublishData = {
|
||||
body?: EventTuiPromptAppend | EventTuiCommandExecute | EventTuiToastShow
|
||||
body?: EventTuiPromptAppend | EventTuiCommandExecute | EventTuiToastShow | EventTuiSessionSelect
|
||||
path?: never
|
||||
query?: {
|
||||
directory?: string
|
||||
@@ -4336,6 +4347,42 @@ export type TuiPublishResponses = {
|
||||
|
||||
export type TuiPublishResponse = TuiPublishResponses[keyof TuiPublishResponses]
|
||||
|
||||
export type TuiSelectSessionData = {
|
||||
body?: {
|
||||
/**
|
||||
* Session ID to navigate to
|
||||
*/
|
||||
sessionID: string
|
||||
}
|
||||
path?: never
|
||||
query?: {
|
||||
directory?: string
|
||||
}
|
||||
url: "/tui/select-session"
|
||||
}
|
||||
|
||||
export type TuiSelectSessionErrors = {
|
||||
/**
|
||||
* Bad request
|
||||
*/
|
||||
400: BadRequestError
|
||||
/**
|
||||
* Not found
|
||||
*/
|
||||
404: NotFoundError
|
||||
}
|
||||
|
||||
export type TuiSelectSessionError = TuiSelectSessionErrors[keyof TuiSelectSessionErrors]
|
||||
|
||||
export type TuiSelectSessionResponses = {
|
||||
/**
|
||||
* Session selected successfully
|
||||
*/
|
||||
200: boolean
|
||||
}
|
||||
|
||||
export type TuiSelectSessionResponse = TuiSelectSessionResponses[keyof TuiSelectSessionResponses]
|
||||
|
||||
export type TuiControlNextData = {
|
||||
body?: never
|
||||
path?: never
|
||||
|
||||
@@ -4956,6 +4956,9 @@
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.tui.toast.show"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.tui.session.select"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -4970,6 +4973,77 @@
|
||||
]
|
||||
}
|
||||
},
|
||||
"/tui/select-session": {
|
||||
"post": {
|
||||
"operationId": "tui.selectSession",
|
||||
"parameters": [
|
||||
{
|
||||
"in": "query",
|
||||
"name": "directory",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"summary": "Select session",
|
||||
"description": "Navigate the TUI to display the specified session.",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Session selected successfully",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad request",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/BadRequestError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "Not found",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/NotFoundError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"requestBody": {
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"sessionID": {
|
||||
"description": "Session ID to navigate to",
|
||||
"type": "string",
|
||||
"pattern": "^ses"
|
||||
}
|
||||
},
|
||||
"required": ["sessionID"]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"x-codeSamples": [
|
||||
{
|
||||
"lang": "js",
|
||||
"source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.tui.selectSession({\n ...\n})"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"/tui/control/next": {
|
||||
"get": {
|
||||
"operationId": "tui.control.next",
|
||||
@@ -6794,6 +6868,27 @@
|
||||
},
|
||||
"required": ["type", "properties"]
|
||||
},
|
||||
"Event.tui.session.select": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"const": "tui.session.select"
|
||||
},
|
||||
"properties": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"sessionID": {
|
||||
"description": "Session ID to navigate to",
|
||||
"type": "string",
|
||||
"pattern": "^ses"
|
||||
}
|
||||
},
|
||||
"required": ["sessionID"]
|
||||
}
|
||||
},
|
||||
"required": ["type", "properties"]
|
||||
},
|
||||
"Event.mcp.tools.changed": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -7338,6 +7433,9 @@
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.tui.toast.show"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.tui.session.select"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/Event.mcp.tools.changed"
|
||||
},
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"name": "@opencode-ai/slack",
|
||||
"version": "1.0.224",
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"dev": "bun run src/index.ts",
|
||||
"typecheck": "tsgo --noEmit"
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"name": "@opencode-ai/ui",
|
||||
"version": "1.0.224",
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
"exports": {
|
||||
"./*": "./src/components/*.tsx",
|
||||
"./pierre": "./src/pierre/index.ts",
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
"version": "1.0.224",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
"exports": {
|
||||
"./*": "./src/*.ts"
|
||||
},
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"name": "@opencode-ai/web",
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
"version": "1.0.224",
|
||||
"scripts": {
|
||||
"dev": "astro dev",
|
||||
|
||||
@@ -38,6 +38,7 @@ You can also check out [awesome-opencode](https://github.com/awesome-opencode/aw
|
||||
| [opencode-skillful](https://github.com/zenobi-us/opencode-skillful) | Allow OpenCode agents to lazy load prompts on demand with skill discovery and injection |
|
||||
| [opencode-supermemory](https://github.com/supermemoryai/opencode-supermemory) | Persistent memory across sessions using Supermemory |
|
||||
| [@plannotator/opencode](https://github.com/backnotprop/plannotator/tree/main/apps/opencode-plugin) | Interactive plan review with visual annotation and private/offline sharing |
|
||||
| [@openspoon/subtask2](https://github.com/spoons-and-mirrors/subtask2) | Extend opencode /commands into a powerful orchestration system with granular flow control |
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@ OpenCode comes with several built-in LSP servers for popular languages:
|
||||
| gleam | .gleam | `gleam` command available |
|
||||
| gopls | .go | `go` command available |
|
||||
| jdtls | .java | `Java SDK (version 21+)` installed |
|
||||
| kotlin-ls | .kt, .kts | Auto-installs for Kotlin projects |
|
||||
| lua-ls | .lua | Auto-installs for Lua projects |
|
||||
| nixd | .nix | `nixd` command available |
|
||||
| ocaml-lsp | .ml, .mli | `ocamllsp` command available |
|
||||
|
||||
Reference in New Issue
Block a user