Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
585378cba0 | ||
|
|
8cd8393339 | ||
|
|
b184b2fb73 | ||
|
|
c88c2da9be | ||
|
|
9b04081ae0 | ||
|
|
7d2d87fa2c | ||
|
|
787f37b382 | ||
|
|
8fa1af851c | ||
|
|
73bc3e704e | ||
|
|
8d2feed30e | ||
|
|
2d8d4e5dee | ||
|
|
b3784588ae | ||
|
|
104d52bc38 | ||
|
|
dff1fe2d28 | ||
|
|
72ab4260ee | ||
|
|
9e9b4a0555 | ||
|
|
e53192889c | ||
|
|
23bbfb3d15 | ||
|
|
37da005a01 | ||
|
|
8b708242f1 | ||
|
|
339d2dcb98 | ||
|
|
bbc8678164 |
@@ -22,7 +22,7 @@
|
|||||||
},
|
},
|
||||||
"packages/app": {
|
"packages/app": {
|
||||||
"name": "@opencode-ai/app",
|
"name": "@opencode-ai/app",
|
||||||
"version": "1.0.213",
|
"version": "1.0.217",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@kobalte/core": "catalog:",
|
"@kobalte/core": "catalog:",
|
||||||
"@opencode-ai/sdk": "workspace:*",
|
"@opencode-ai/sdk": "workspace:*",
|
||||||
@@ -70,7 +70,7 @@
|
|||||||
},
|
},
|
||||||
"packages/console/app": {
|
"packages/console/app": {
|
||||||
"name": "@opencode-ai/console-app",
|
"name": "@opencode-ai/console-app",
|
||||||
"version": "1.0.213",
|
"version": "1.0.217",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@cloudflare/vite-plugin": "1.15.2",
|
"@cloudflare/vite-plugin": "1.15.2",
|
||||||
"@ibm/plex": "6.4.1",
|
"@ibm/plex": "6.4.1",
|
||||||
@@ -98,7 +98,7 @@
|
|||||||
},
|
},
|
||||||
"packages/console/core": {
|
"packages/console/core": {
|
||||||
"name": "@opencode-ai/console-core",
|
"name": "@opencode-ai/console-core",
|
||||||
"version": "1.0.213",
|
"version": "1.0.217",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@aws-sdk/client-sts": "3.782.0",
|
"@aws-sdk/client-sts": "3.782.0",
|
||||||
"@jsx-email/render": "1.1.1",
|
"@jsx-email/render": "1.1.1",
|
||||||
@@ -125,7 +125,7 @@
|
|||||||
},
|
},
|
||||||
"packages/console/function": {
|
"packages/console/function": {
|
||||||
"name": "@opencode-ai/console-function",
|
"name": "@opencode-ai/console-function",
|
||||||
"version": "1.0.213",
|
"version": "1.0.217",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ai-sdk/anthropic": "2.0.0",
|
"@ai-sdk/anthropic": "2.0.0",
|
||||||
"@ai-sdk/openai": "2.0.2",
|
"@ai-sdk/openai": "2.0.2",
|
||||||
@@ -149,7 +149,7 @@
|
|||||||
},
|
},
|
||||||
"packages/console/mail": {
|
"packages/console/mail": {
|
||||||
"name": "@opencode-ai/console-mail",
|
"name": "@opencode-ai/console-mail",
|
||||||
"version": "1.0.213",
|
"version": "1.0.217",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@jsx-email/all": "2.2.3",
|
"@jsx-email/all": "2.2.3",
|
||||||
"@jsx-email/cli": "1.4.3",
|
"@jsx-email/cli": "1.4.3",
|
||||||
@@ -173,7 +173,7 @@
|
|||||||
},
|
},
|
||||||
"packages/desktop": {
|
"packages/desktop": {
|
||||||
"name": "@opencode-ai/desktop",
|
"name": "@opencode-ai/desktop",
|
||||||
"version": "1.0.213",
|
"version": "1.0.217",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@opencode-ai/app": "workspace:*",
|
"@opencode-ai/app": "workspace:*",
|
||||||
"@solid-primitives/storage": "catalog:",
|
"@solid-primitives/storage": "catalog:",
|
||||||
@@ -201,7 +201,7 @@
|
|||||||
},
|
},
|
||||||
"packages/enterprise": {
|
"packages/enterprise": {
|
||||||
"name": "@opencode-ai/enterprise",
|
"name": "@opencode-ai/enterprise",
|
||||||
"version": "1.0.213",
|
"version": "1.0.217",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@opencode-ai/ui": "workspace:*",
|
"@opencode-ai/ui": "workspace:*",
|
||||||
"@opencode-ai/util": "workspace:*",
|
"@opencode-ai/util": "workspace:*",
|
||||||
@@ -230,7 +230,7 @@
|
|||||||
},
|
},
|
||||||
"packages/function": {
|
"packages/function": {
|
||||||
"name": "@opencode-ai/function",
|
"name": "@opencode-ai/function",
|
||||||
"version": "1.0.213",
|
"version": "1.0.217",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@octokit/auth-app": "8.0.1",
|
"@octokit/auth-app": "8.0.1",
|
||||||
"@octokit/rest": "catalog:",
|
"@octokit/rest": "catalog:",
|
||||||
@@ -246,7 +246,7 @@
|
|||||||
},
|
},
|
||||||
"packages/opencode": {
|
"packages/opencode": {
|
||||||
"name": "opencode",
|
"name": "opencode",
|
||||||
"version": "1.0.213",
|
"version": "1.0.217",
|
||||||
"bin": {
|
"bin": {
|
||||||
"opencode": "./bin/opencode",
|
"opencode": "./bin/opencode",
|
||||||
},
|
},
|
||||||
@@ -347,7 +347,7 @@
|
|||||||
},
|
},
|
||||||
"packages/plugin": {
|
"packages/plugin": {
|
||||||
"name": "@opencode-ai/plugin",
|
"name": "@opencode-ai/plugin",
|
||||||
"version": "1.0.213",
|
"version": "1.0.217",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@opencode-ai/sdk": "workspace:*",
|
"@opencode-ai/sdk": "workspace:*",
|
||||||
"zod": "catalog:",
|
"zod": "catalog:",
|
||||||
@@ -367,7 +367,7 @@
|
|||||||
},
|
},
|
||||||
"packages/sdk/js": {
|
"packages/sdk/js": {
|
||||||
"name": "@opencode-ai/sdk",
|
"name": "@opencode-ai/sdk",
|
||||||
"version": "1.0.213",
|
"version": "1.0.217",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@hey-api/openapi-ts": "0.88.1",
|
"@hey-api/openapi-ts": "0.88.1",
|
||||||
"@tsconfig/node22": "catalog:",
|
"@tsconfig/node22": "catalog:",
|
||||||
@@ -378,7 +378,7 @@
|
|||||||
},
|
},
|
||||||
"packages/slack": {
|
"packages/slack": {
|
||||||
"name": "@opencode-ai/slack",
|
"name": "@opencode-ai/slack",
|
||||||
"version": "1.0.213",
|
"version": "1.0.217",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@opencode-ai/sdk": "workspace:*",
|
"@opencode-ai/sdk": "workspace:*",
|
||||||
"@slack/bolt": "^3.17.1",
|
"@slack/bolt": "^3.17.1",
|
||||||
@@ -391,7 +391,7 @@
|
|||||||
},
|
},
|
||||||
"packages/ui": {
|
"packages/ui": {
|
||||||
"name": "@opencode-ai/ui",
|
"name": "@opencode-ai/ui",
|
||||||
"version": "1.0.213",
|
"version": "1.0.217",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@kobalte/core": "catalog:",
|
"@kobalte/core": "catalog:",
|
||||||
"@opencode-ai/sdk": "workspace:*",
|
"@opencode-ai/sdk": "workspace:*",
|
||||||
@@ -429,7 +429,7 @@
|
|||||||
},
|
},
|
||||||
"packages/util": {
|
"packages/util": {
|
||||||
"name": "@opencode-ai/util",
|
"name": "@opencode-ai/util",
|
||||||
"version": "1.0.213",
|
"version": "1.0.217",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"zod": "catalog:",
|
"zod": "catalog:",
|
||||||
},
|
},
|
||||||
@@ -440,7 +440,7 @@
|
|||||||
},
|
},
|
||||||
"packages/web": {
|
"packages/web": {
|
||||||
"name": "@opencode-ai/web",
|
"name": "@opencode-ai/web",
|
||||||
"version": "1.0.213",
|
"version": "1.0.217",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@astrojs/cloudflare": "12.6.3",
|
"@astrojs/cloudflare": "12.6.3",
|
||||||
"@astrojs/markdown-remark": "6.3.1",
|
"@astrojs/markdown-remark": "6.3.1",
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
"aarch64-darwin"
|
"aarch64-darwin"
|
||||||
"x86_64-darwin"
|
"x86_64-darwin"
|
||||||
];
|
];
|
||||||
lib = nixpkgs.lib;
|
inherit (nixpkgs) lib;
|
||||||
forEachSystem = lib.genAttrs systems;
|
forEachSystem = lib.genAttrs systems;
|
||||||
pkgsFor = system: nixpkgs.legacyPackages.${system};
|
pkgsFor = system: nixpkgs.legacyPackages.${system};
|
||||||
packageJson = builtins.fromJSON (builtins.readFile ./packages/opencode/package.json);
|
packageJson = builtins.fromJSON (builtins.readFile ./packages/opencode/package.json);
|
||||||
@@ -70,12 +70,12 @@
|
|||||||
in
|
in
|
||||||
{
|
{
|
||||||
default = mkPackage {
|
default = mkPackage {
|
||||||
version = packageJson.version;
|
inherit (packageJson) version;
|
||||||
src = ./.;
|
src = ./.;
|
||||||
scripts = ./nix/scripts;
|
scripts = ./nix/scripts;
|
||||||
target = bunTarget.${system};
|
target = bunTarget.${system};
|
||||||
modelsDev = "${modelsDev.${system}}/dist/_api.json";
|
modelsDev = "${modelsDev.${system}}/dist/_api.json";
|
||||||
mkNodeModules = mkNodeModules;
|
inherit mkNodeModules;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|||||||
+18
-10
@@ -1,18 +1,26 @@
|
|||||||
{ hash, lib, stdenvNoCC, bun, cacert, curl }:
|
{
|
||||||
|
hash,
|
||||||
|
lib,
|
||||||
|
stdenvNoCC,
|
||||||
|
bun,
|
||||||
|
cacert,
|
||||||
|
curl,
|
||||||
|
}:
|
||||||
args:
|
args:
|
||||||
stdenvNoCC.mkDerivation {
|
stdenvNoCC.mkDerivation {
|
||||||
pname = "opencode-node_modules";
|
pname = "opencode-node_modules";
|
||||||
version = args.version;
|
inherit (args) version src;
|
||||||
src = args.src;
|
|
||||||
|
|
||||||
impureEnvVars =
|
impureEnvVars = lib.fetchers.proxyImpureEnvVars ++ [
|
||||||
lib.fetchers.proxyImpureEnvVars
|
"GIT_PROXY_COMMAND"
|
||||||
++ [
|
"SOCKS_SERVER"
|
||||||
"GIT_PROXY_COMMAND"
|
];
|
||||||
"SOCKS_SERVER"
|
|
||||||
];
|
|
||||||
|
|
||||||
nativeBuildInputs = [ bun cacert curl ];
|
nativeBuildInputs = [
|
||||||
|
bun
|
||||||
|
cacert
|
||||||
|
curl
|
||||||
|
];
|
||||||
|
|
||||||
dontConfigure = true;
|
dontConfigure = true;
|
||||||
|
|
||||||
|
|||||||
+10
-7
@@ -1,7 +1,13 @@
|
|||||||
{ lib, stdenvNoCC, bun, ripgrep, makeBinaryWrapper }:
|
{
|
||||||
|
lib,
|
||||||
|
stdenvNoCC,
|
||||||
|
bun,
|
||||||
|
ripgrep,
|
||||||
|
makeBinaryWrapper,
|
||||||
|
}:
|
||||||
args:
|
args:
|
||||||
let
|
let
|
||||||
scripts = args.scripts;
|
inherit (args) scripts;
|
||||||
mkModules =
|
mkModules =
|
||||||
attrs:
|
attrs:
|
||||||
args.mkNodeModules (
|
args.mkNodeModules (
|
||||||
@@ -14,13 +20,10 @@ let
|
|||||||
in
|
in
|
||||||
stdenvNoCC.mkDerivation (finalAttrs: {
|
stdenvNoCC.mkDerivation (finalAttrs: {
|
||||||
pname = "opencode";
|
pname = "opencode";
|
||||||
version = args.version;
|
inherit (args) version src;
|
||||||
|
|
||||||
src = args.src;
|
|
||||||
|
|
||||||
node_modules = mkModules {
|
node_modules = mkModules {
|
||||||
version = finalAttrs.version;
|
inherit (finalAttrs) version src;
|
||||||
src = finalAttrs.src;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
nativeBuildInputs = [
|
nativeBuildInputs = [
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@opencode-ai/app",
|
"name": "@opencode-ai/app",
|
||||||
"version": "1.0.213",
|
"version": "1.0.217",
|
||||||
"description": "",
|
"description": "",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"exports": {
|
"exports": {
|
||||||
|
|||||||
@@ -46,6 +46,25 @@ export function DialogSelectServer() {
|
|||||||
|
|
||||||
const current = createMemo(() => items().find((x) => x === server.url) ?? items()[0])
|
const current = createMemo(() => items().find((x) => x === server.url) ?? items()[0])
|
||||||
|
|
||||||
|
const sortedItems = createMemo(() => {
|
||||||
|
const list = items()
|
||||||
|
if (!list.length) return list
|
||||||
|
const active = current()
|
||||||
|
const order = new Map(list.map((url, index) => [url, index] as const))
|
||||||
|
const rank = (value?: ServerStatus) => {
|
||||||
|
if (value?.healthy === true) return 0
|
||||||
|
if (value?.healthy === false) return 2
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
return list.slice().sort((a, b) => {
|
||||||
|
if (a === active) return -1
|
||||||
|
if (b === active) return 1
|
||||||
|
const diff = rank(store.status[a]) - rank(store.status[b])
|
||||||
|
if (diff !== 0) return diff
|
||||||
|
return (order.get(a) ?? 0) - (order.get(b) ?? 0)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
async function refreshHealth() {
|
async function refreshHealth() {
|
||||||
const results: Record<string, ServerStatus> = {}
|
const results: Record<string, ServerStatus> = {}
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
@@ -63,9 +82,14 @@ export function DialogSelectServer() {
|
|||||||
onCleanup(() => clearInterval(interval))
|
onCleanup(() => clearInterval(interval))
|
||||||
})
|
})
|
||||||
|
|
||||||
function select(value: string) {
|
function select(value: string, persist?: boolean) {
|
||||||
if (store.status[value]?.healthy === false) return
|
if (!persist && store.status[value]?.healthy === false) return
|
||||||
dialog.close()
|
dialog.close()
|
||||||
|
if (persist) {
|
||||||
|
server.add(value)
|
||||||
|
navigate("/")
|
||||||
|
return
|
||||||
|
}
|
||||||
server.setActive(value)
|
server.setActive(value)
|
||||||
navigate("/")
|
navigate("/")
|
||||||
}
|
}
|
||||||
@@ -87,7 +111,7 @@ export function DialogSelectServer() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
setStore("url", "")
|
setStore("url", "")
|
||||||
select(value)
|
select(value, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -96,7 +120,7 @@ export function DialogSelectServer() {
|
|||||||
<List
|
<List
|
||||||
search={{ placeholder: "Search servers", autofocus: true }}
|
search={{ placeholder: "Search servers", autofocus: true }}
|
||||||
emptyMessage="No servers yet"
|
emptyMessage="No servers yet"
|
||||||
items={items}
|
items={sortedItems}
|
||||||
key={(x) => x}
|
key={(x) => x}
|
||||||
current={current()}
|
current={current()}
|
||||||
onSelect={(x) => {
|
onSelect={(x) => {
|
||||||
|
|||||||
@@ -1115,11 +1115,17 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
|
|||||||
setStore("imageAttachments", [])
|
setStore("imageAttachments", [])
|
||||||
setStore("mode", "normal")
|
setStore("mode", "normal")
|
||||||
|
|
||||||
const model = {
|
const currentModel = local.model.current()
|
||||||
modelID: local.model.current()!.id,
|
const currentAgent = local.agent.current()
|
||||||
providerID: local.model.current()!.provider.id,
|
if (!currentModel || !currentAgent) {
|
||||||
|
console.warn("No agent or model available for prompt submission")
|
||||||
|
return
|
||||||
}
|
}
|
||||||
const agent = local.agent.current()!.name
|
const model = {
|
||||||
|
modelID: currentModel.id,
|
||||||
|
providerID: currentModel.provider.id,
|
||||||
|
}
|
||||||
|
const agent = currentAgent.name
|
||||||
|
|
||||||
if (isShellMode) {
|
if (isShellMode) {
|
||||||
sdk.client.session
|
sdk.client.session
|
||||||
@@ -1321,6 +1327,7 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
|
|||||||
onInput={handleInput}
|
onInput={handleInput}
|
||||||
onKeyDown={handleKeyDown}
|
onKeyDown={handleKeyDown}
|
||||||
classList={{
|
classList={{
|
||||||
|
"select-text": true,
|
||||||
"w-full px-5 py-3 pr-12 text-14-regular text-text-strong focus:outline-none whitespace-pre-wrap": true,
|
"w-full px-5 py-3 pr-12 text-14-regular text-text-strong focus:outline-none whitespace-pre-wrap": true,
|
||||||
"[&_[data-type=file]]:text-icon-info-active": true,
|
"[&_[data-type=file]]:text-icon-info-active": true,
|
||||||
"font-mono!": store.mode === "shell",
|
"font-mono!": store.mode === "shell",
|
||||||
@@ -1359,7 +1366,7 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
|
|||||||
>
|
>
|
||||||
<Select
|
<Select
|
||||||
options={local.agent.list().map((agent) => agent.name)}
|
options={local.agent.list().map((agent) => agent.name)}
|
||||||
current={local.agent.current().name}
|
current={local.agent.current()?.name ?? ""}
|
||||||
onSelect={local.agent.set}
|
onSelect={local.agent.set}
|
||||||
class="capitalize"
|
class="capitalize"
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
|
|||||||
@@ -233,6 +233,7 @@ export const Terminal = (props: TerminalProps) => {
|
|||||||
style={{ "background-color": terminalColors().background }}
|
style={{ "background-color": terminalColors().background }}
|
||||||
classList={{
|
classList={{
|
||||||
...(local.classList ?? {}),
|
...(local.classList ?? {}),
|
||||||
|
"select-text": true,
|
||||||
"size-full px-6 py-3 font-mono": true,
|
"size-full px-6 py-3 font-mono": true,
|
||||||
[local.class ?? ""]: !!local.class,
|
[local.class ?? ""]: !!local.class,
|
||||||
}}
|
}}
|
||||||
|
|||||||
@@ -65,23 +65,40 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({
|
|||||||
const agent = (() => {
|
const agent = (() => {
|
||||||
const list = createMemo(() => sync.data.agent.filter((x) => x.mode !== "subagent" && !x.hidden))
|
const list = createMemo(() => sync.data.agent.filter((x) => x.mode !== "subagent" && !x.hidden))
|
||||||
const [store, setStore] = createStore<{
|
const [store, setStore] = createStore<{
|
||||||
current: string
|
current?: string
|
||||||
}>({
|
}>({
|
||||||
current: list()[0].name,
|
current: list()[0]?.name,
|
||||||
})
|
})
|
||||||
return {
|
return {
|
||||||
list,
|
list,
|
||||||
current() {
|
current() {
|
||||||
return list().find((x) => x.name === store.current)!
|
const available = list()
|
||||||
|
if (available.length === 0) return undefined
|
||||||
|
return available.find((x) => x.name === store.current) ?? available[0]
|
||||||
},
|
},
|
||||||
set(name: string | undefined) {
|
set(name: string | undefined) {
|
||||||
setStore("current", name ?? list()[0].name)
|
const available = list()
|
||||||
|
if (available.length === 0) {
|
||||||
|
setStore("current", undefined)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (name && available.some((x) => x.name === name)) {
|
||||||
|
setStore("current", name)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
setStore("current", available[0].name)
|
||||||
},
|
},
|
||||||
move(direction: 1 | -1) {
|
move(direction: 1 | -1) {
|
||||||
let next = list().findIndex((x) => x.name === store.current) + direction
|
const available = list()
|
||||||
if (next < 0) next = list().length - 1
|
if (available.length === 0) {
|
||||||
if (next >= list().length) next = 0
|
setStore("current", undefined)
|
||||||
const value = list()[next]
|
return
|
||||||
|
}
|
||||||
|
let next = available.findIndex((x) => x.name === store.current) + direction
|
||||||
|
if (next < 0) next = available.length - 1
|
||||||
|
if (next >= available.length) next = 0
|
||||||
|
const value = available[next]
|
||||||
|
if (!value) return
|
||||||
setStore("current", value.name)
|
setStore("current", value.name)
|
||||||
if (value.model)
|
if (value.model)
|
||||||
model.set({
|
model.set({
|
||||||
@@ -182,11 +199,13 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({
|
|||||||
|
|
||||||
const current = createMemo(() => {
|
const current = createMemo(() => {
|
||||||
const a = agent.current()
|
const a = agent.current()
|
||||||
|
if (!a) return undefined
|
||||||
const key = getFirstValidModel(
|
const key = getFirstValidModel(
|
||||||
() => ephemeral.model[a.name],
|
() => ephemeral.model[a.name],
|
||||||
() => a.model,
|
() => a.model,
|
||||||
fallbackModel,
|
fallbackModel,
|
||||||
)!
|
)
|
||||||
|
if (!key) return undefined
|
||||||
return find(key)
|
return find(key)
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -232,7 +251,8 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({
|
|||||||
cycle,
|
cycle,
|
||||||
set(model: ModelKey | undefined, options?: { recent?: boolean }) {
|
set(model: ModelKey | undefined, options?: { recent?: boolean }) {
|
||||||
batch(() => {
|
batch(() => {
|
||||||
setEphemeral("model", agent.current().name, model ?? fallbackModel())
|
const currentAgent = agent.current()
|
||||||
|
if (currentAgent) setEphemeral("model", currentAgent.name, model ?? fallbackModel())
|
||||||
if (model) updateVisibility(model, "show")
|
if (model) updateVisibility(model, "show")
|
||||||
if (options?.recent && model) {
|
if (options?.recent && model) {
|
||||||
const uniq = uniqueBy([model, ...store.recent], (x) => x.providerID + x.modelID)
|
const uniq = uniqueBy([model, ...store.recent], (x) => x.providerID + x.modelID)
|
||||||
|
|||||||
@@ -23,6 +23,13 @@ export function serverDisplayName(url: string) {
|
|||||||
.split("/")[0]
|
.split("/")[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function projectsKey(url: string) {
|
||||||
|
if (!url) return ""
|
||||||
|
const host = url.replace(/^https?:\/\//, "").split(":")[0]
|
||||||
|
if (host === "localhost" || host === "127.0.0.1") return "local"
|
||||||
|
return url
|
||||||
|
}
|
||||||
|
|
||||||
export const { use: useServer, provider: ServerProvider } = createSimpleContext({
|
export const { use: useServer, provider: ServerProvider } = createSimpleContext({
|
||||||
name: "Server",
|
name: "Server",
|
||||||
init: (props: { defaultUrl: string }) => {
|
init: (props: { defaultUrl: string }) => {
|
||||||
@@ -41,6 +48,19 @@ export const { use: useServer, provider: ServerProvider } = createSimpleContext(
|
|||||||
function setActive(input: string) {
|
function setActive(input: string) {
|
||||||
const url = normalizeServerUrl(input)
|
const url = normalizeServerUrl(input)
|
||||||
if (!url) return
|
if (!url) return
|
||||||
|
setActiveRaw(url)
|
||||||
|
}
|
||||||
|
|
||||||
|
function add(input: string) {
|
||||||
|
const url = normalizeServerUrl(input)
|
||||||
|
if (!url) return
|
||||||
|
|
||||||
|
const fallback = normalizeServerUrl(props.defaultUrl)
|
||||||
|
if (fallback && url === fallback) {
|
||||||
|
setActiveRaw(url)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
batch(() => {
|
batch(() => {
|
||||||
if (!store.list.includes(url)) {
|
if (!store.list.includes(url)) {
|
||||||
setStore("list", store.list.length, url)
|
setStore("list", store.list.length, url)
|
||||||
@@ -64,15 +84,10 @@ export const { use: useServer, provider: ServerProvider } = createSimpleContext(
|
|||||||
|
|
||||||
createEffect(() => {
|
createEffect(() => {
|
||||||
if (!ready()) return
|
if (!ready()) return
|
||||||
|
if (active()) return
|
||||||
const url = normalizeServerUrl(props.defaultUrl)
|
const url = normalizeServerUrl(props.defaultUrl)
|
||||||
if (!url) return
|
if (!url) return
|
||||||
|
setActiveRaw(url)
|
||||||
batch(() => {
|
|
||||||
if (!store.list.includes(url)) {
|
|
||||||
setStore("list", store.list.length, url)
|
|
||||||
}
|
|
||||||
setActiveRaw(url)
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|
||||||
const isReady = createMemo(() => ready() && !!active())
|
const isReady = createMemo(() => ready() && !!active())
|
||||||
@@ -100,7 +115,8 @@ export const { use: useServer, provider: ServerProvider } = createSimpleContext(
|
|||||||
onCleanup(() => clearInterval(interval))
|
onCleanup(() => clearInterval(interval))
|
||||||
})
|
})
|
||||||
|
|
||||||
const projectsList = createMemo(() => store.projects[active()] ?? [])
|
const origin = createMemo(() => projectsKey(active()))
|
||||||
|
const projectsList = createMemo(() => store.projects[origin()] ?? [])
|
||||||
|
|
||||||
return {
|
return {
|
||||||
ready: isReady,
|
ready: isReady,
|
||||||
@@ -115,51 +131,51 @@ export const { use: useServer, provider: ServerProvider } = createSimpleContext(
|
|||||||
return store.list
|
return store.list
|
||||||
},
|
},
|
||||||
setActive,
|
setActive,
|
||||||
add: setActive,
|
add,
|
||||||
remove,
|
remove,
|
||||||
projects: {
|
projects: {
|
||||||
list: projectsList,
|
list: projectsList,
|
||||||
open(directory: string) {
|
open(directory: string) {
|
||||||
const url = active()
|
const key = origin()
|
||||||
if (!url) return
|
if (!key) return
|
||||||
const current = store.projects[url] ?? []
|
const current = store.projects[key] ?? []
|
||||||
if (current.find((x) => x.worktree === directory)) return
|
if (current.find((x) => x.worktree === directory)) return
|
||||||
setStore("projects", url, [{ worktree: directory, expanded: true }, ...current])
|
setStore("projects", key, [{ worktree: directory, expanded: true }, ...current])
|
||||||
},
|
},
|
||||||
close(directory: string) {
|
close(directory: string) {
|
||||||
const url = active()
|
const key = origin()
|
||||||
if (!url) return
|
if (!key) return
|
||||||
const current = store.projects[url] ?? []
|
const current = store.projects[key] ?? []
|
||||||
setStore(
|
setStore(
|
||||||
"projects",
|
"projects",
|
||||||
url,
|
key,
|
||||||
current.filter((x) => x.worktree !== directory),
|
current.filter((x) => x.worktree !== directory),
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
expand(directory: string) {
|
expand(directory: string) {
|
||||||
const url = active()
|
const key = origin()
|
||||||
if (!url) return
|
if (!key) return
|
||||||
const current = store.projects[url] ?? []
|
const current = store.projects[key] ?? []
|
||||||
const index = current.findIndex((x) => x.worktree === directory)
|
const index = current.findIndex((x) => x.worktree === directory)
|
||||||
if (index !== -1) setStore("projects", url, index, "expanded", true)
|
if (index !== -1) setStore("projects", key, index, "expanded", true)
|
||||||
},
|
},
|
||||||
collapse(directory: string) {
|
collapse(directory: string) {
|
||||||
const url = active()
|
const key = origin()
|
||||||
if (!url) return
|
if (!key) return
|
||||||
const current = store.projects[url] ?? []
|
const current = store.projects[key] ?? []
|
||||||
const index = current.findIndex((x) => x.worktree === directory)
|
const index = current.findIndex((x) => x.worktree === directory)
|
||||||
if (index !== -1) setStore("projects", url, index, "expanded", false)
|
if (index !== -1) setStore("projects", key, index, "expanded", false)
|
||||||
},
|
},
|
||||||
move(directory: string, toIndex: number) {
|
move(directory: string, toIndex: number) {
|
||||||
const url = active()
|
const key = origin()
|
||||||
if (!url) return
|
if (!key) return
|
||||||
const current = store.projects[url] ?? []
|
const current = store.projects[key] ?? []
|
||||||
const fromIndex = current.findIndex((x) => x.worktree === directory)
|
const fromIndex = current.findIndex((x) => x.worktree === directory)
|
||||||
if (fromIndex === -1 || fromIndex === toIndex) return
|
if (fromIndex === -1 || fromIndex === toIndex) return
|
||||||
const result = [...current]
|
const result = [...current]
|
||||||
const [item] = result.splice(fromIndex, 1)
|
const [item] = result.splice(fromIndex, 1)
|
||||||
result.splice(toIndex, 0, item)
|
result.splice(toIndex, 0, item)
|
||||||
setStore("projects", url, result)
|
setStore("projects", key, result)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1015,7 +1015,7 @@ export default function Layout(props: ParentProps) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div class="relative flex-1 min-h-0 flex flex-col">
|
<div class="relative flex-1 min-h-0 flex flex-col select-none [&_input]:select-text [&_textarea]:select-text [&_[contenteditable]]:select-text">
|
||||||
<Header
|
<Header
|
||||||
navigateToProject={navigateToProject}
|
navigateToProject={navigateToProject}
|
||||||
navigateToSession={navigateToSession}
|
navigateToSession={navigateToSession}
|
||||||
|
|||||||
@@ -858,7 +858,7 @@ export default function Page() {
|
|||||||
</Tabs.List>
|
</Tabs.List>
|
||||||
</div>
|
</div>
|
||||||
<Show when={diffs().length}>
|
<Show when={diffs().length}>
|
||||||
<Tabs.Content value="review" class="select-text flex flex-col h-full overflow-hidden contain-strict">
|
<Tabs.Content value="review" class="flex flex-col h-full overflow-hidden contain-strict">
|
||||||
<div class="relative pt-2 flex-1 min-h-0 overflow-hidden">
|
<div class="relative pt-2 flex-1 min-h-0 overflow-hidden">
|
||||||
<SessionReview
|
<SessionReview
|
||||||
classes={{
|
classes={{
|
||||||
@@ -884,7 +884,7 @@ export default function Page() {
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
return (
|
return (
|
||||||
<Tabs.Content value={tab} class="select-text mt-3">
|
<Tabs.Content value={tab} class="mt-3">
|
||||||
<Switch>
|
<Switch>
|
||||||
<Match when={file()}>
|
<Match when={file()}>
|
||||||
{(f) => (
|
{(f) => (
|
||||||
@@ -896,7 +896,7 @@ export default function Page() {
|
|||||||
cacheKey: checksum(f().content?.content ?? ""),
|
cacheKey: checksum(f().content?.content ?? ""),
|
||||||
}}
|
}}
|
||||||
overflow="scroll"
|
overflow="scroll"
|
||||||
class="pb-40"
|
class="select-text pb-40"
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</Match>
|
</Match>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@opencode-ai/console-app",
|
"name": "@opencode-ai/console-app",
|
||||||
"version": "1.0.213",
|
"version": "1.0.217",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"typecheck": "tsgo --noEmit",
|
"typecheck": "tsgo --noEmit",
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"$schema": "https://json.schemastore.org/package.json",
|
"$schema": "https://json.schemastore.org/package.json",
|
||||||
"name": "@opencode-ai/console-core",
|
"name": "@opencode-ai/console-core",
|
||||||
"version": "1.0.213",
|
"version": "1.0.217",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@opencode-ai/console-function",
|
"name": "@opencode-ai/console-function",
|
||||||
"version": "1.0.213",
|
"version": "1.0.217",
|
||||||
"$schema": "https://json.schemastore.org/package.json",
|
"$schema": "https://json.schemastore.org/package.json",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@opencode-ai/console-mail",
|
"name": "@opencode-ai/console-mail",
|
||||||
"version": "1.0.213",
|
"version": "1.0.217",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@jsx-email/all": "2.2.3",
|
"@jsx-email/all": "2.2.3",
|
||||||
"@jsx-email/cli": "1.4.3",
|
"@jsx-email/cli": "1.4.3",
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "@opencode-ai/desktop",
|
"name": "@opencode-ai/desktop",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "1.0.213",
|
"version": "1.0.217",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"typecheck": "tsgo -b",
|
"typecheck": "tsgo -b",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@opencode-ai/enterprise",
|
"name": "@opencode-ai/enterprise",
|
||||||
"version": "1.0.213",
|
"version": "1.0.217",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { FileRoutes } from "@solidjs/start/router"
|
|||||||
import { Font } from "@opencode-ai/ui/font"
|
import { Font } from "@opencode-ai/ui/font"
|
||||||
import { MetaProvider } from "@solidjs/meta"
|
import { MetaProvider } from "@solidjs/meta"
|
||||||
import { MarkedProvider } from "@opencode-ai/ui/context/marked"
|
import { MarkedProvider } from "@opencode-ai/ui/context/marked"
|
||||||
|
import { DialogProvider } from "@opencode-ai/ui/context/dialog"
|
||||||
import { Suspense } from "solid-js"
|
import { Suspense } from "solid-js"
|
||||||
import "./app.css"
|
import "./app.css"
|
||||||
import { Favicon } from "@opencode-ai/ui/favicon"
|
import { Favicon } from "@opencode-ai/ui/favicon"
|
||||||
@@ -12,11 +13,13 @@ export default function App() {
|
|||||||
<Router
|
<Router
|
||||||
root={(props) => (
|
root={(props) => (
|
||||||
<MetaProvider>
|
<MetaProvider>
|
||||||
<MarkedProvider>
|
<DialogProvider>
|
||||||
<Favicon />
|
<MarkedProvider>
|
||||||
<Font />
|
<Favicon />
|
||||||
<Suspense>{props.children}</Suspense>
|
<Font />
|
||||||
</MarkedProvider>
|
<Suspense>{props.children}</Suspense>
|
||||||
|
</MarkedProvider>
|
||||||
|
</DialogProvider>
|
||||||
</MetaProvider>
|
</MetaProvider>
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -162,11 +162,20 @@ export default function () {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<ErrorBoundary
|
<ErrorBoundary
|
||||||
fallback={(e) => {
|
fallback={(error) => {
|
||||||
|
if (SessionDataMissingError.isInstance(error)) {
|
||||||
|
return <NotFound />
|
||||||
|
}
|
||||||
|
console.error(error)
|
||||||
|
const details = error instanceof Error ? (error.stack ?? error.message) : String(error)
|
||||||
return (
|
return (
|
||||||
<Show when={e.message === "SessionDataMissingError"}>
|
<div class="min-h-screen w-full bg-background-base text-text-base flex flex-col items-center justify-center gap-4 p-6 text-center">
|
||||||
<NotFound />
|
<p class="text-16-medium">Unable to render this share.</p>
|
||||||
</Show>
|
<p class="text-14-regular text-text-weaker">Check the console for more details.</p>
|
||||||
|
<pre class="text-12-mono text-left whitespace-pre-wrap break-words w-full max-w-200 bg-background-stronger rounded-md p-4">
|
||||||
|
{details}
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
)
|
)
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
id = "opencode"
|
id = "opencode"
|
||||||
name = "OpenCode"
|
name = "OpenCode"
|
||||||
description = "The open source coding agent."
|
description = "The open source coding agent."
|
||||||
version = "1.0.213"
|
version = "1.0.217"
|
||||||
schema_version = 1
|
schema_version = 1
|
||||||
authors = ["Anomaly"]
|
authors = ["Anomaly"]
|
||||||
repository = "https://github.com/sst/opencode"
|
repository = "https://github.com/sst/opencode"
|
||||||
@@ -11,26 +11,26 @@ name = "OpenCode"
|
|||||||
icon = "./icons/opencode.svg"
|
icon = "./icons/opencode.svg"
|
||||||
|
|
||||||
[agent_servers.opencode.targets.darwin-aarch64]
|
[agent_servers.opencode.targets.darwin-aarch64]
|
||||||
archive = "https://github.com/sst/opencode/releases/download/v1.0.213/opencode-darwin-arm64.zip"
|
archive = "https://github.com/sst/opencode/releases/download/v1.0.217/opencode-darwin-arm64.zip"
|
||||||
cmd = "./opencode"
|
cmd = "./opencode"
|
||||||
args = ["acp"]
|
args = ["acp"]
|
||||||
|
|
||||||
[agent_servers.opencode.targets.darwin-x86_64]
|
[agent_servers.opencode.targets.darwin-x86_64]
|
||||||
archive = "https://github.com/sst/opencode/releases/download/v1.0.213/opencode-darwin-x64.zip"
|
archive = "https://github.com/sst/opencode/releases/download/v1.0.217/opencode-darwin-x64.zip"
|
||||||
cmd = "./opencode"
|
cmd = "./opencode"
|
||||||
args = ["acp"]
|
args = ["acp"]
|
||||||
|
|
||||||
[agent_servers.opencode.targets.linux-aarch64]
|
[agent_servers.opencode.targets.linux-aarch64]
|
||||||
archive = "https://github.com/sst/opencode/releases/download/v1.0.213/opencode-linux-arm64.tar.gz"
|
archive = "https://github.com/sst/opencode/releases/download/v1.0.217/opencode-linux-arm64.tar.gz"
|
||||||
cmd = "./opencode"
|
cmd = "./opencode"
|
||||||
args = ["acp"]
|
args = ["acp"]
|
||||||
|
|
||||||
[agent_servers.opencode.targets.linux-x86_64]
|
[agent_servers.opencode.targets.linux-x86_64]
|
||||||
archive = "https://github.com/sst/opencode/releases/download/v1.0.213/opencode-linux-x64.tar.gz"
|
archive = "https://github.com/sst/opencode/releases/download/v1.0.217/opencode-linux-x64.tar.gz"
|
||||||
cmd = "./opencode"
|
cmd = "./opencode"
|
||||||
args = ["acp"]
|
args = ["acp"]
|
||||||
|
|
||||||
[agent_servers.opencode.targets.windows-x86_64]
|
[agent_servers.opencode.targets.windows-x86_64]
|
||||||
archive = "https://github.com/sst/opencode/releases/download/v1.0.213/opencode-windows-x64.zip"
|
archive = "https://github.com/sst/opencode/releases/download/v1.0.217/opencode-windows-x64.zip"
|
||||||
cmd = "./opencode.exe"
|
cmd = "./opencode.exe"
|
||||||
args = ["acp"]
|
args = ["acp"]
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@opencode-ai/function",
|
"name": "@opencode-ai/function",
|
||||||
"version": "1.0.213",
|
"version": "1.0.217",
|
||||||
"$schema": "https://json.schemastore.org/package.json",
|
"$schema": "https://json.schemastore.org/package.json",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"$schema": "https://json.schemastore.org/package.json",
|
"$schema": "https://json.schemastore.org/package.json",
|
||||||
"version": "1.0.213",
|
"version": "1.0.217",
|
||||||
"name": "opencode",
|
"name": "opencode",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"private": true,
|
"private": true,
|
||||||
|
|||||||
@@ -349,6 +349,12 @@ export const AuthLoginCommand = cmd({
|
|||||||
prompts.log.info("You can create an api key at https://vercel.link/ai-gateway-token")
|
prompts.log.info("You can create an api key at https://vercel.link/ai-gateway-token")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (["cloudflare", "cloudflare-ai-gateway"].includes(provider)) {
|
||||||
|
prompts.log.info(
|
||||||
|
"Cloudflare AI Gateway can be configured with CLOUDFLARE_GATEWAY_ID, CLOUDFLARE_ACCOUNT_ID, and CLOUDFLARE_API_TOKEN environment variables. Read more: https://opencode.ai/docs/providers/#cloudflare-ai-gateway",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
const key = await prompts.password({
|
const key = await prompts.password({
|
||||||
message: "Enter your API key",
|
message: "Enter your API key",
|
||||||
validate: (x) => (x && x.length > 0 ? undefined : "Required"),
|
validate: (x) => (x && x.length > 0 ? undefined : "Required"),
|
||||||
|
|||||||
@@ -372,6 +372,15 @@ function App() {
|
|||||||
local.agent.move(1)
|
local.agent.move(1)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: "Variant cycle",
|
||||||
|
value: "variant.cycle",
|
||||||
|
keybind: "variant_cycle",
|
||||||
|
category: "Agent",
|
||||||
|
onSelect: () => {
|
||||||
|
local.model.variant.cycle()
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
title: "Agent cycle reverse",
|
title: "Agent cycle reverse",
|
||||||
value: "agent.cycle.reverse",
|
value: "agent.cycle.reverse",
|
||||||
|
|||||||
@@ -877,12 +877,6 @@ export function Prompt(props: PromptProps) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (keybind.match("variant_cycle", e)) {
|
|
||||||
e.preventDefault()
|
|
||||||
if (local.model.variant.list().length === 0) return
|
|
||||||
local.model.variant.cycle()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if (store.mode === "normal") autocomplete.onKeyDown(e)
|
if (store.mode === "normal") autocomplete.onKeyDown(e)
|
||||||
if (!autocomplete.visible) {
|
if (!autocomplete.visible) {
|
||||||
if (
|
if (
|
||||||
|
|||||||
@@ -115,11 +115,12 @@ export function DialogSelect<T>(props: DialogSelectProps<T>) {
|
|||||||
setStore("selected", currentIndex)
|
setStore("selected", currentIndex)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
scroll.scrollTo(0)
|
scroll?.scrollTo(0)
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
|
||||||
function move(direction: number) {
|
function move(direction: number) {
|
||||||
|
if (flat().length === 0) return
|
||||||
let next = store.selected + direction
|
let next = store.selected + direction
|
||||||
if (next < 0) next = flat().length - 1
|
if (next < 0) next = flat().length - 1
|
||||||
if (next >= flat().length) next = 0
|
if (next >= flat().length) next = 0
|
||||||
@@ -129,6 +130,7 @@ export function DialogSelect<T>(props: DialogSelectProps<T>) {
|
|||||||
function moveTo(next: number) {
|
function moveTo(next: number) {
|
||||||
setStore("selected", next)
|
setStore("selected", next)
|
||||||
props.onMove?.(selected()!)
|
props.onMove?.(selected()!)
|
||||||
|
if (!scroll) return
|
||||||
const target = scroll.getChildren().find((child) => {
|
const target = scroll.getChildren().find((child) => {
|
||||||
return child.id === JSON.stringify(selected()?.value)
|
return child.id === JSON.stringify(selected()?.value)
|
||||||
})
|
})
|
||||||
@@ -172,7 +174,7 @@ export function DialogSelect<T>(props: DialogSelectProps<T>) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
let scroll: ScrollBoxRenderable
|
let scroll: ScrollBoxRenderable | undefined
|
||||||
const ref: DialogSelectRef<T> = {
|
const ref: DialogSelectRef<T> = {
|
||||||
get filter() {
|
get filter() {
|
||||||
return store.filter
|
return store.filter
|
||||||
@@ -213,61 +215,70 @@ export function DialogSelect<T>(props: DialogSelectProps<T>) {
|
|||||||
/>
|
/>
|
||||||
</box>
|
</box>
|
||||||
</box>
|
</box>
|
||||||
<scrollbox
|
<Show
|
||||||
paddingLeft={1}
|
when={grouped().length > 0}
|
||||||
paddingRight={1}
|
fallback={
|
||||||
scrollbarOptions={{ visible: false }}
|
<box paddingLeft={4} paddingRight={4} paddingTop={1}>
|
||||||
ref={(r: ScrollBoxRenderable) => (scroll = r)}
|
<text fg={theme.textMuted}>No results found</text>
|
||||||
maxHeight={height()}
|
</box>
|
||||||
|
}
|
||||||
>
|
>
|
||||||
<For each={grouped()}>
|
<scrollbox
|
||||||
{([category, options], index) => (
|
paddingLeft={1}
|
||||||
<>
|
paddingRight={1}
|
||||||
<Show when={category}>
|
scrollbarOptions={{ visible: false }}
|
||||||
<box paddingTop={index() > 0 ? 1 : 0} paddingLeft={3}>
|
ref={(r: ScrollBoxRenderable) => (scroll = r)}
|
||||||
<text fg={theme.accent} attributes={TextAttributes.BOLD}>
|
maxHeight={height()}
|
||||||
{category}
|
>
|
||||||
</text>
|
<For each={grouped()}>
|
||||||
</box>
|
{([category, options], index) => (
|
||||||
</Show>
|
<>
|
||||||
<For each={options}>
|
<Show when={category}>
|
||||||
{(option) => {
|
<box paddingTop={index() > 0 ? 1 : 0} paddingLeft={3}>
|
||||||
const active = createMemo(() => isDeepEqual(option.value, selected()?.value))
|
<text fg={theme.accent} attributes={TextAttributes.BOLD}>
|
||||||
const current = createMemo(() => isDeepEqual(option.value, props.current))
|
{category}
|
||||||
return (
|
</text>
|
||||||
<box
|
</box>
|
||||||
id={JSON.stringify(option.value)}
|
</Show>
|
||||||
flexDirection="row"
|
<For each={options}>
|
||||||
onMouseUp={() => {
|
{(option) => {
|
||||||
option.onSelect?.(dialog)
|
const active = createMemo(() => isDeepEqual(option.value, selected()?.value))
|
||||||
props.onSelect?.(option)
|
const current = createMemo(() => isDeepEqual(option.value, props.current))
|
||||||
}}
|
return (
|
||||||
onMouseOver={() => {
|
<box
|
||||||
const index = filtered().findIndex((x) => isDeepEqual(x.value, option.value))
|
id={JSON.stringify(option.value)}
|
||||||
if (index === -1) return
|
flexDirection="row"
|
||||||
moveTo(index)
|
onMouseUp={() => {
|
||||||
}}
|
option.onSelect?.(dialog)
|
||||||
backgroundColor={active() ? (option.bg ?? theme.primary) : RGBA.fromInts(0, 0, 0, 0)}
|
props.onSelect?.(option)
|
||||||
paddingLeft={current() || option.gutter ? 1 : 3}
|
}}
|
||||||
paddingRight={3}
|
onMouseOver={() => {
|
||||||
gap={1}
|
const index = filtered().findIndex((x) => isDeepEqual(x.value, option.value))
|
||||||
>
|
if (index === -1) return
|
||||||
<Option
|
moveTo(index)
|
||||||
title={option.title}
|
}}
|
||||||
footer={option.footer}
|
backgroundColor={active() ? (option.bg ?? theme.primary) : RGBA.fromInts(0, 0, 0, 0)}
|
||||||
description={option.description !== category ? option.description : undefined}
|
paddingLeft={current() || option.gutter ? 1 : 3}
|
||||||
active={active()}
|
paddingRight={3}
|
||||||
current={current()}
|
gap={1}
|
||||||
gutter={option.gutter}
|
>
|
||||||
/>
|
<Option
|
||||||
</box>
|
title={option.title}
|
||||||
)
|
footer={option.footer}
|
||||||
}}
|
description={option.description !== category ? option.description : undefined}
|
||||||
</For>
|
active={active()}
|
||||||
</>
|
current={current()}
|
||||||
)}
|
gutter={option.gutter}
|
||||||
</For>
|
/>
|
||||||
</scrollbox>
|
</box>
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
</For>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</For>
|
||||||
|
</scrollbox>
|
||||||
|
</Show>
|
||||||
<Show when={keybinds().length} fallback={<box flexShrink={0} />}>
|
<Show when={keybinds().length} fallback={<box flexShrink={0} />}>
|
||||||
<box paddingRight={2} paddingLeft={4} flexDirection="row" gap={2} flexShrink={0} paddingTop={1}>
|
<box paddingRight={2} paddingLeft={4} flexDirection="row" gap={2} flexShrink={0} paddingTop={1}>
|
||||||
<For each={keybinds()}>
|
<For each={keybinds()}>
|
||||||
|
|||||||
@@ -104,7 +104,23 @@ export namespace Server {
|
|||||||
timer.stop()
|
timer.stop()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.use(cors())
|
.use(
|
||||||
|
cors({
|
||||||
|
origin(input) {
|
||||||
|
if (!input) return
|
||||||
|
|
||||||
|
if (input.startsWith("http://localhost:")) return input
|
||||||
|
if (input.startsWith("http://127.0.0.1:")) return input
|
||||||
|
if (input === "tauri://localhost") return input
|
||||||
|
|
||||||
|
// *.opencode.ai (https only, adjust if needed)
|
||||||
|
if (/^https:\/\/([a-z0-9-]+\.)*opencode\.ai$/.test(input)) {
|
||||||
|
return input
|
||||||
|
}
|
||||||
|
return
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
)
|
||||||
.get(
|
.get(
|
||||||
"/global/health",
|
"/global/health",
|
||||||
describeRoute({
|
describeRoute({
|
||||||
|
|||||||
@@ -240,7 +240,7 @@ You are producing plain text that will later be styled by the CLI. Follow these
|
|||||||
- Choose descriptive names that fit the content
|
- Choose descriptive names that fit the content
|
||||||
- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`
|
- Keep headers short (1–3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`
|
||||||
- Leave no blank line before the first bullet under a header.
|
- Leave no blank line before the first bullet under a header.
|
||||||
- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.
|
- Section headers should only be used where they genuinely improve scannability; avoid fragmenting the answer.
|
||||||
|
|
||||||
**Bullets**
|
**Bullets**
|
||||||
|
|
||||||
@@ -289,7 +289,7 @@ When referencing files in your response, make sure to include the relevant start
|
|||||||
- Don’t nest bullets or create deep hierarchies.
|
- Don’t nest bullets or create deep hierarchies.
|
||||||
- Don’t output ANSI escape codes directly — the CLI renderer applies them.
|
- Don’t output ANSI escape codes directly — the CLI renderer applies them.
|
||||||
- Don’t cram unrelated keywords into a single bullet; split for clarity.
|
- Don’t cram unrelated keywords into a single bullet; split for clarity.
|
||||||
- Don’t let keyword lists run long — wrap or reformat for scanability.
|
- Don’t let keyword lists run long — wrap or reformat for scannability.
|
||||||
|
|
||||||
Generally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.
|
Generally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with what’s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ is a critical violation. ZERO exceptions.
|
|||||||
|
|
||||||
## Responsibility
|
## Responsibility
|
||||||
|
|
||||||
Your current responsibility is to think, read, search, and delegate explore agents to construct a well formed plan that accomplishes the goal the user wants to achieve. Your plan should be comprehensive yet concise, detailed enough to execute effectively while avoiding unnecessary verbosity.
|
Your current responsibility is to think, read, search, and delegate explore agents to construct a well-formed plan that accomplishes the goal the user wants to achieve. Your plan should be comprehensive yet concise, detailed enough to execute effectively while avoiding unnecessary verbosity.
|
||||||
|
|
||||||
Ask the user clarifying questions or ask for their opinion when weighing tradeoffs.
|
Ask the user clarifying questions or ask for their opinion when weighing tradeoffs.
|
||||||
|
|
||||||
@@ -22,5 +22,5 @@ Ask the user clarifying questions or ask for their opinion when weighing tradeof
|
|||||||
|
|
||||||
## Important
|
## Important
|
||||||
|
|
||||||
The user indicated that they do not want you to execute yet -- you MUST NOT make any edits, run any non-readonly tools (including changing configs or making commits), or otherwise make any changes to the system. This supercedes any other instructions you have received.
|
The user indicated that they do not want you to execute yet -- you MUST NOT make any edits, run any non-readonly tools (including changing configs or making commits), or otherwise make any changes to the system. This supersedes any other instructions you have received.
|
||||||
</system-reminder>
|
</system-reminder>
|
||||||
|
|||||||
@@ -280,7 +280,7 @@ export const BashTool = Tool.define("bash", async () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (timedOut) {
|
if (timedOut) {
|
||||||
resultMetadata.push(`bash tool terminated commmand after exceeding timeout ${timeout} ms`)
|
resultMetadata.push(`bash tool terminated command after exceeding timeout ${timeout} ms`)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (aborted) {
|
if (aborted) {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
Launch a new agent to handle complex, multi-step tasks autonomously.
|
Launch a new agent to handle complex, multistep tasks autonomously.
|
||||||
|
|
||||||
Available agent types and the tools they have access to:
|
Available agent types and the tools they have access to:
|
||||||
{agents}
|
{agents}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ It also helps the user understand the progress of the task and overall progress
|
|||||||
## When to Use This Tool
|
## When to Use This Tool
|
||||||
Use this tool proactively in these scenarios:
|
Use this tool proactively in these scenarios:
|
||||||
|
|
||||||
1. Complex multi-step tasks - When a task requires 3 or more distinct steps or actions
|
1. Complex multistep tasks - When a task requires 3 or more distinct steps or actions
|
||||||
2. Non-trivial and complex tasks - Tasks that require careful planning or multiple operations
|
2. Non-trivial and complex tasks - Tasks that require careful planning or multiple operations
|
||||||
3. User explicitly requests todo list - When the user directly asks you to use the todo list
|
3. User explicitly requests todo list - When the user directly asks you to use the todo list
|
||||||
4. User provides multiple tasks - When users provide a list of things to be done (numbered or comma-separated)
|
4. User provides multiple tasks - When users provide a list of things to be done (numbered or comma-separated)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"$schema": "https://json.schemastore.org/package.json",
|
"$schema": "https://json.schemastore.org/package.json",
|
||||||
"name": "@opencode-ai/plugin",
|
"name": "@opencode-ai/plugin",
|
||||||
"version": "1.0.213",
|
"version": "1.0.217",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"typecheck": "tsgo --noEmit",
|
"typecheck": "tsgo --noEmit",
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"$schema": "https://json.schemastore.org/package.json",
|
"$schema": "https://json.schemastore.org/package.json",
|
||||||
"name": "@opencode-ai/sdk",
|
"name": "@opencode-ai/sdk",
|
||||||
"version": "1.0.213",
|
"version": "1.0.217",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"typecheck": "tsgo --noEmit",
|
"typecheck": "tsgo --noEmit",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@opencode-ai/slack",
|
"name": "@opencode-ai/slack",
|
||||||
"version": "1.0.213",
|
"version": "1.0.217",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "bun run src/index.ts",
|
"dev": "bun run src/index.ts",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@opencode-ai/ui",
|
"name": "@opencode-ai/ui",
|
||||||
"version": "1.0.213",
|
"version": "1.0.217",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"exports": {
|
"exports": {
|
||||||
"./*": "./src/components/*.tsx",
|
"./*": "./src/components/*.tsx",
|
||||||
|
|||||||
@@ -377,6 +377,18 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[data-component="user-message"] [data-slot="user-message-text"],
|
||||||
|
[data-component="text-part"],
|
||||||
|
[data-component="reasoning-part"],
|
||||||
|
[data-component="tool-error"],
|
||||||
|
[data-component="tool-output"],
|
||||||
|
[data-component="edit-content"],
|
||||||
|
[data-component="write-content"],
|
||||||
|
[data-component="todos"],
|
||||||
|
[data-component="diagnostics"] {
|
||||||
|
user-select: text;
|
||||||
|
}
|
||||||
|
|
||||||
[data-component="tool-part-wrapper"] {
|
[data-component="tool-part-wrapper"] {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
||||||
|
|||||||
@@ -65,6 +65,10 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[data-slot="accordion-content"] {
|
||||||
|
user-select: text;
|
||||||
|
}
|
||||||
|
|
||||||
[data-slot="session-review-trigger-content"] {
|
[data-slot="session-review-trigger-content"] {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|||||||
@@ -116,6 +116,11 @@
|
|||||||
color: var(--text-weak);
|
color: var(--text-weak);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[data-slot="session-turn-markdown"],
|
||||||
|
[data-slot="session-turn-accordion"] [data-slot="accordion-content"] {
|
||||||
|
user-select: text;
|
||||||
|
}
|
||||||
|
|
||||||
[data-slot="session-turn-markdown"] {
|
[data-slot="session-turn-markdown"] {
|
||||||
&[data-diffs="true"] {
|
&[data-diffs="true"] {
|
||||||
font-size: 15px;
|
font-size: 15px;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@opencode-ai/util",
|
"name": "@opencode-ai/util",
|
||||||
"version": "1.0.213",
|
"version": "1.0.217",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"exports": {
|
"exports": {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "@opencode-ai/web",
|
"name": "@opencode-ai/web",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"version": "1.0.213",
|
"version": "1.0.217",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "astro dev",
|
"dev": "astro dev",
|
||||||
"dev:remote": "VITE_API_URL=https://api.opencode.ai astro dev",
|
"dev:remote": "VITE_API_URL=https://api.opencode.ai astro dev",
|
||||||
|
|||||||
@@ -118,6 +118,29 @@ You can disable a keybind by adding the key to your config with a value of "none
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## Desktop prompt shortcuts
|
||||||
|
|
||||||
|
The OpenCode desktop app prompt input supports common Readline/Emacs-style shortcuts for editing text. These are built-in and currently not configurable via `opencode.json`.
|
||||||
|
|
||||||
|
| Shortcut | Action |
|
||||||
|
| -------- | ---------------------------------------- |
|
||||||
|
| `ctrl+a` | Move to start of current line |
|
||||||
|
| `ctrl+e` | Move to end of current line |
|
||||||
|
| `ctrl+b` | Move cursor back one character |
|
||||||
|
| `ctrl+f` | Move cursor forward one character |
|
||||||
|
| `alt+b` | Move cursor back one word |
|
||||||
|
| `alt+f` | Move cursor forward one word |
|
||||||
|
| `ctrl+d` | Delete character under cursor |
|
||||||
|
| `ctrl+k` | Kill to end of line |
|
||||||
|
| `ctrl+u` | Kill to start of line |
|
||||||
|
| `ctrl+w` | Kill previous word |
|
||||||
|
| `alt+d` | Kill next word |
|
||||||
|
| `ctrl+y` | Yank (paste) last killed text |
|
||||||
|
| `ctrl+t` | Transpose characters |
|
||||||
|
| `ctrl+g` | Cancel popovers / abort running response |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Shift+Enter
|
## Shift+Enter
|
||||||
|
|
||||||
Some terminals don't send modifier keys with Enter by default. You may need to configure your terminal to send `Shift+Enter` as an escape sequence.
|
Some terminals don't send modifier keys with Enter by default. You may need to configure your terminal to send `Shift+Enter` as an escape sequence.
|
||||||
|
|||||||
@@ -230,6 +230,10 @@ export const NotificationPlugin = async ({ project, client, $, directory, worktr
|
|||||||
|
|
||||||
We are using `osascript` to run AppleScript on macOS. Here we are using it to send notifications.
|
We are using `osascript` to run AppleScript on macOS. Here we are using it to send notifications.
|
||||||
|
|
||||||
|
:::note
|
||||||
|
If you’re using the OpenCode desktop app, it can send system notifications automatically when a response is ready or when a session errors.
|
||||||
|
:::
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### .env protection
|
### .env protection
|
||||||
|
|||||||
@@ -283,13 +283,19 @@ await client.session.prompt({
|
|||||||
|
|
||||||
### Files
|
### Files
|
||||||
|
|
||||||
| Method | Description | Response |
|
| Method | Description | Response |
|
||||||
| ------------------------- | ---------------------------- | ------------------------------------------------------------------------------------------- |
|
| ------------------------- | ---------------------------------- | ------------------------------------------------------------------------------------------- |
|
||||||
| `find.text({ query })` | Search for text in files | Array of match objects with `path`, `lines`, `line_number`, `absolute_offset`, `submatches` |
|
| `find.text({ query })` | Search for text in files | Array of match objects with `path`, `lines`, `line_number`, `absolute_offset`, `submatches` |
|
||||||
| `find.files({ query })` | Find files by name | `string[]` (file paths) |
|
| `find.files({ query })` | Find files and directories by name | `string[]` (paths) |
|
||||||
| `find.symbols({ query })` | Find workspace symbols | <a href={typesUrl}><code>Symbol[]</code></a> |
|
| `find.symbols({ query })` | Find workspace symbols | <a href={typesUrl}><code>Symbol[]</code></a> |
|
||||||
| `file.read({ query })` | Read a file | `{ type: "raw" \| "patch", content: string }` |
|
| `file.read({ query })` | Read a file | `{ type: "raw" \| "patch", content: string }` |
|
||||||
| `file.status({ query? })` | Get status for tracked files | <a href={typesUrl}><code>File[]</code></a> |
|
| `file.status({ query? })` | Get status for tracked files | <a href={typesUrl}><code>File[]</code></a> |
|
||||||
|
|
||||||
|
`find.files` supports a few optional query fields:
|
||||||
|
|
||||||
|
- `type`: `"file"` or `"directory"`
|
||||||
|
- `directory`: override the project root for the search
|
||||||
|
- `limit`: max results (1–200)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -302,7 +308,11 @@ const textResults = await client.find.text({
|
|||||||
})
|
})
|
||||||
|
|
||||||
const files = await client.find.files({
|
const files = await client.find.files({
|
||||||
query: { query: "*.ts" },
|
query: { query: "*.ts", type: "file" },
|
||||||
|
})
|
||||||
|
|
||||||
|
const directories = await client.find.files({
|
||||||
|
query: { query: "packages", type: "directory", limit: 20 },
|
||||||
})
|
})
|
||||||
|
|
||||||
const content = await client.file.read({
|
const content = await client.file.read({
|
||||||
|
|||||||
@@ -173,14 +173,22 @@ The opencode server exposes the following APIs.
|
|||||||
|
|
||||||
### Files
|
### Files
|
||||||
|
|
||||||
| Method | Path | Description | Response |
|
| Method | Path | Description | Response |
|
||||||
| ------ | ------------------------ | ---------------------------- | ------------------------------------------------------------------------------------------- |
|
| ------ | ------------------------ | ---------------------------------- | ------------------------------------------------------------------------------------------- |
|
||||||
| `GET` | `/find?pattern=<pat>` | Search for text in files | Array of match objects with `path`, `lines`, `line_number`, `absolute_offset`, `submatches` |
|
| `GET` | `/find?pattern=<pat>` | Search for text in files | Array of match objects with `path`, `lines`, `line_number`, `absolute_offset`, `submatches` |
|
||||||
| `GET` | `/find/file?query=<q>` | Find files by name | `string[]` (file paths) |
|
| `GET` | `/find/file?query=<q>` | Find files and directories by name | `string[]` (paths) |
|
||||||
| `GET` | `/find/symbol?query=<q>` | Find workspace symbols | <a href={typesUrl}><code>Symbol[]</code></a> |
|
| `GET` | `/find/symbol?query=<q>` | Find workspace symbols | <a href={typesUrl}><code>Symbol[]</code></a> |
|
||||||
| `GET` | `/file?path=<path>` | List files and directories | <a href={typesUrl}><code>FileNode[]</code></a> |
|
| `GET` | `/file?path=<path>` | List files and directories | <a href={typesUrl}><code>FileNode[]</code></a> |
|
||||||
| `GET` | `/file/content?path=<p>` | Read a file | <a href={typesUrl}><code>FileContent</code></a> |
|
| `GET` | `/file/content?path=<p>` | Read a file | <a href={typesUrl}><code>FileContent</code></a> |
|
||||||
| `GET` | `/file/status` | Get status for tracked files | <a href={typesUrl}><code>File[]</code></a> |
|
| `GET` | `/file/status` | Get status for tracked files | <a href={typesUrl}><code>File[]</code></a> |
|
||||||
|
|
||||||
|
#### `/find/file` query parameters
|
||||||
|
|
||||||
|
- `query` (required) — search string (fuzzy match)
|
||||||
|
- `type` (optional) — limit results to `"file"` or `"directory"`
|
||||||
|
- `directory` (optional) — override the project root for the search
|
||||||
|
- `limit` (optional) — max results (1–200)
|
||||||
|
- `dirs` (optional) — legacy flag (`"false"` returns only files)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
"name": "opencode",
|
"name": "opencode",
|
||||||
"displayName": "opencode",
|
"displayName": "opencode",
|
||||||
"description": "opencode for VS Code",
|
"description": "opencode for VS Code",
|
||||||
"version": "1.0.213",
|
"version": "1.0.217",
|
||||||
"publisher": "sst-dev",
|
"publisher": "sst-dev",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
|
|||||||
Reference in New Issue
Block a user