Merge branch 'dev' into llm-centralization
This commit is contained in:
commit
106a6bb08c
55 changed files with 804 additions and 327 deletions
1
STATS.md
1
STATS.md
|
|
@ -167,3 +167,4 @@
|
||||||
| 2025-12-09 | 1,011,488 (+10,590) | 973,922 (+16,773) | 1,985,410 (+27,363) |
|
| 2025-12-09 | 1,011,488 (+10,590) | 973,922 (+16,773) | 1,985,410 (+27,363) |
|
||||||
| 2025-12-10 | 1,025,891 (+14,403) | 991,708 (+17,786) | 2,017,599 (+32,189) |
|
| 2025-12-10 | 1,025,891 (+14,403) | 991,708 (+17,786) | 2,017,599 (+32,189) |
|
||||||
| 2025-12-11 | 1,045,110 (+19,219) | 1,010,559 (+18,851) | 2,055,669 (+38,070) |
|
| 2025-12-11 | 1,045,110 (+19,219) | 1,010,559 (+18,851) | 2,055,669 (+38,070) |
|
||||||
|
| 2025-12-12 | 1,061,340 (+16,230) | 1,030,838 (+20,279) | 2,092,178 (+36,509) |
|
||||||
|
|
|
||||||
12
bun.lock
12
bun.lock
|
|
@ -131,6 +131,7 @@
|
||||||
"@opencode-ai/util": "workspace:*",
|
"@opencode-ai/util": "workspace:*",
|
||||||
"@shikijs/transformers": "3.9.2",
|
"@shikijs/transformers": "3.9.2",
|
||||||
"@solid-primitives/active-element": "2.1.3",
|
"@solid-primitives/active-element": "2.1.3",
|
||||||
|
"@solid-primitives/audio": "1.4.2",
|
||||||
"@solid-primitives/event-bus": "1.1.2",
|
"@solid-primitives/event-bus": "1.1.2",
|
||||||
"@solid-primitives/resize-observer": "2.1.3",
|
"@solid-primitives/resize-observer": "2.1.3",
|
||||||
"@solid-primitives/scroll": "2.1.3",
|
"@solid-primitives/scroll": "2.1.3",
|
||||||
|
|
@ -355,9 +356,12 @@
|
||||||
"@tauri-apps/api": "^2",
|
"@tauri-apps/api": "^2",
|
||||||
"@tauri-apps/plugin-dialog": "~2",
|
"@tauri-apps/plugin-dialog": "~2",
|
||||||
"@tauri-apps/plugin-opener": "^2",
|
"@tauri-apps/plugin-opener": "^2",
|
||||||
|
"@tauri-apps/plugin-os": "~2",
|
||||||
"@tauri-apps/plugin-process": "~2",
|
"@tauri-apps/plugin-process": "~2",
|
||||||
"@tauri-apps/plugin-shell": "~2",
|
"@tauri-apps/plugin-shell": "~2",
|
||||||
|
"@tauri-apps/plugin-store": "~2",
|
||||||
"@tauri-apps/plugin-updater": "~2",
|
"@tauri-apps/plugin-updater": "~2",
|
||||||
|
"@tauri-apps/plugin-window-state": "~2",
|
||||||
"solid-js": "catalog:",
|
"solid-js": "catalog:",
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|
@ -1546,6 +1550,8 @@
|
||||||
|
|
||||||
"@solid-primitives/active-element": ["@solid-primitives/active-element@2.1.3", "", { "dependencies": { "@solid-primitives/event-listener": "^2.4.3", "@solid-primitives/utils": "^6.3.2" }, "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-9t5K4aR2naVDj950XU8OjnLgOg94a8k5wr6JNOPK+N5ESLsJDq42c1ZP8UKpewi1R+wplMMxiM6OPKRzbxJY7A=="],
|
"@solid-primitives/active-element": ["@solid-primitives/active-element@2.1.3", "", { "dependencies": { "@solid-primitives/event-listener": "^2.4.3", "@solid-primitives/utils": "^6.3.2" }, "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-9t5K4aR2naVDj950XU8OjnLgOg94a8k5wr6JNOPK+N5ESLsJDq42c1ZP8UKpewi1R+wplMMxiM6OPKRzbxJY7A=="],
|
||||||
|
|
||||||
|
"@solid-primitives/audio": ["@solid-primitives/audio@1.4.2", "", { "dependencies": { "@solid-primitives/static-store": "^0.1.2", "@solid-primitives/utils": "^6.3.2" }, "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-UMD3ORQfI5Ky8yuKPxidDiEazsjv/dsoiKK5yZxLnsgaeNR1Aym3/77h/qT1jBYeXUgj4DX6t7NMpFUSVr14OQ=="],
|
||||||
|
|
||||||
"@solid-primitives/event-bus": ["@solid-primitives/event-bus@1.1.2", "", { "dependencies": { "@solid-primitives/utils": "^6.3.2" }, "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-l+n10/51neGcMaP3ypYt21bXfoeWh8IaC8k7fYuY3ww2a8S1Zv2N2a7FF5Qn+waTu86l0V8/nRHjkyqVIZBYwA=="],
|
"@solid-primitives/event-bus": ["@solid-primitives/event-bus@1.1.2", "", { "dependencies": { "@solid-primitives/utils": "^6.3.2" }, "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-l+n10/51neGcMaP3ypYt21bXfoeWh8IaC8k7fYuY3ww2a8S1Zv2N2a7FF5Qn+waTu86l0V8/nRHjkyqVIZBYwA=="],
|
||||||
|
|
||||||
"@solid-primitives/event-listener": ["@solid-primitives/event-listener@2.4.3", "", { "dependencies": { "@solid-primitives/utils": "^6.3.2" }, "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-h4VqkYFv6Gf+L7SQj+Y6puigL/5DIi7x5q07VZET7AWcS+9/G3WfIE9WheniHWJs51OEkRB43w6lDys5YeFceg=="],
|
"@solid-primitives/event-listener": ["@solid-primitives/event-listener@2.4.3", "", { "dependencies": { "@solid-primitives/utils": "^6.3.2" }, "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-h4VqkYFv6Gf+L7SQj+Y6puigL/5DIi7x5q07VZET7AWcS+9/G3WfIE9WheniHWJs51OEkRB43w6lDys5YeFceg=="],
|
||||||
|
|
@ -1658,12 +1664,18 @@
|
||||||
|
|
||||||
"@tauri-apps/plugin-opener": ["@tauri-apps/plugin-opener@2.5.2", "", { "dependencies": { "@tauri-apps/api": "^2.8.0" } }, "sha512-ei/yRRoCklWHImwpCcDK3VhNXx+QXM9793aQ64YxpqVF0BDuuIlXhZgiAkc15wnPVav+IbkYhmDJIv5R326Mew=="],
|
"@tauri-apps/plugin-opener": ["@tauri-apps/plugin-opener@2.5.2", "", { "dependencies": { "@tauri-apps/api": "^2.8.0" } }, "sha512-ei/yRRoCklWHImwpCcDK3VhNXx+QXM9793aQ64YxpqVF0BDuuIlXhZgiAkc15wnPVav+IbkYhmDJIv5R326Mew=="],
|
||||||
|
|
||||||
|
"@tauri-apps/plugin-os": ["@tauri-apps/plugin-os@2.3.2", "", { "dependencies": { "@tauri-apps/api": "^2.8.0" } }, "sha512-n+nXWeuSeF9wcEsSPmRnBEGrRgOy6jjkSU+UVCOV8YUGKb2erhDOxis7IqRXiRVHhY8XMKks00BJ0OAdkpf6+A=="],
|
||||||
|
|
||||||
"@tauri-apps/plugin-process": ["@tauri-apps/plugin-process@2.3.1", "", { "dependencies": { "@tauri-apps/api": "^2.8.0" } }, "sha512-nCa4fGVaDL/B9ai03VyPOjfAHRHSBz5v6F/ObsB73r/dA3MHHhZtldaDMIc0V/pnUw9ehzr2iEG+XkSEyC0JJA=="],
|
"@tauri-apps/plugin-process": ["@tauri-apps/plugin-process@2.3.1", "", { "dependencies": { "@tauri-apps/api": "^2.8.0" } }, "sha512-nCa4fGVaDL/B9ai03VyPOjfAHRHSBz5v6F/ObsB73r/dA3MHHhZtldaDMIc0V/pnUw9ehzr2iEG+XkSEyC0JJA=="],
|
||||||
|
|
||||||
"@tauri-apps/plugin-shell": ["@tauri-apps/plugin-shell@2.3.3", "", { "dependencies": { "@tauri-apps/api": "^2.8.0" } }, "sha512-Xod+pRcFxmOWFWEnqH5yZcA7qwAMuaaDkMR1Sply+F8VfBj++CGnj2xf5UoialmjZ2Cvd8qrvSCbU+7GgNVsKQ=="],
|
"@tauri-apps/plugin-shell": ["@tauri-apps/plugin-shell@2.3.3", "", { "dependencies": { "@tauri-apps/api": "^2.8.0" } }, "sha512-Xod+pRcFxmOWFWEnqH5yZcA7qwAMuaaDkMR1Sply+F8VfBj++CGnj2xf5UoialmjZ2Cvd8qrvSCbU+7GgNVsKQ=="],
|
||||||
|
|
||||||
|
"@tauri-apps/plugin-store": ["@tauri-apps/plugin-store@2.4.1", "", { "dependencies": { "@tauri-apps/api": "^2.8.0" } }, "sha512-ckGSEzZ5Ii4Hf2D5x25Oqnm2Zf9MfDWAzR+volY0z/OOBz6aucPKEY0F649JvQ0Vupku6UJo7ugpGRDOFOunkA=="],
|
||||||
|
|
||||||
"@tauri-apps/plugin-updater": ["@tauri-apps/plugin-updater@2.9.0", "", { "dependencies": { "@tauri-apps/api": "^2.6.0" } }, "sha512-j++sgY8XpeDvzImTrzWA08OqqGqgkNyxczLD7FjNJJx/uXxMZFz5nDcfkyoI/rCjYuj2101Tci/r/HFmOmoxCg=="],
|
"@tauri-apps/plugin-updater": ["@tauri-apps/plugin-updater@2.9.0", "", { "dependencies": { "@tauri-apps/api": "^2.6.0" } }, "sha512-j++sgY8XpeDvzImTrzWA08OqqGqgkNyxczLD7FjNJJx/uXxMZFz5nDcfkyoI/rCjYuj2101Tci/r/HFmOmoxCg=="],
|
||||||
|
|
||||||
|
"@tauri-apps/plugin-window-state": ["@tauri-apps/plugin-window-state@2.4.1", "", { "dependencies": { "@tauri-apps/api": "^2.8.0" } }, "sha512-OuvdrzyY8Q5Dbzpj+GcrnV1iCeoZbcFdzMjanZMMcAEUNy/6PH5pxZPXpaZLOR7whlzXiuzx0L9EKZbH7zpdRw=="],
|
||||||
|
|
||||||
"@thisbeyond/solid-dnd": ["@thisbeyond/solid-dnd@0.7.5", "", { "peerDependencies": { "solid-js": "^1.5" } }, "sha512-DfI5ff+yYGpK9M21LhYwIPlbP2msKxN2ARwuu6GF8tT1GgNVDTI8VCQvH4TJFoVApP9d44izmAcTh/iTCH2UUw=="],
|
"@thisbeyond/solid-dnd": ["@thisbeyond/solid-dnd@0.7.5", "", { "peerDependencies": { "solid-js": "^1.5" } }, "sha512-DfI5ff+yYGpK9M21LhYwIPlbP2msKxN2ARwuu6GF8tT1GgNVDTI8VCQvH4TJFoVApP9d44izmAcTh/iTCH2UUw=="],
|
||||||
|
|
||||||
"@tokenizer/token": ["@tokenizer/token@0.3.0", "", {}, "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A=="],
|
"@tokenizer/token": ["@tokenizer/token@0.3.0", "", {}, "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A=="],
|
||||||
|
|
|
||||||
6
flake.lock
generated
6
flake.lock
generated
|
|
@ -2,11 +2,11 @@
|
||||||
"nodes": {
|
"nodes": {
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1765270179,
|
"lastModified": 1765425892,
|
||||||
"narHash": "sha256-g2a4MhRKu4ymR4xwo+I+auTknXt/+j37Lnf0Mvfl1rE=",
|
"narHash": "sha256-jlQpSkg2sK6IJVzTQBDyRxQZgKADC2HKMRfGCSgNMHo=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "677fbe97984e7af3175b6c121f3c39ee5c8d62c9",
|
"rev": "5d6bdbddb4695a62f0d00a3620b37a15275a5093",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|
|
||||||
|
|
@ -102,6 +102,7 @@ const ZEN_MODELS = [
|
||||||
new sst.Secret("ZEN_MODELS2"),
|
new sst.Secret("ZEN_MODELS2"),
|
||||||
new sst.Secret("ZEN_MODELS3"),
|
new sst.Secret("ZEN_MODELS3"),
|
||||||
new sst.Secret("ZEN_MODELS4"),
|
new sst.Secret("ZEN_MODELS4"),
|
||||||
|
new sst.Secret("ZEN_MODELS5"),
|
||||||
]
|
]
|
||||||
const STRIPE_SECRET_KEY = new sst.Secret("STRIPE_SECRET_KEY")
|
const STRIPE_SECRET_KEY = new sst.Secret("STRIPE_SECRET_KEY")
|
||||||
const AUTH_API_URL = new sst.Linkable("AUTH_API_URL", {
|
const AUTH_API_URL = new sst.Linkable("AUTH_API_URL", {
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
{
|
{
|
||||||
"nodeModules": "sha256-3GaqUwomnIUW8MqUi1jDVPHQ/C5Z+D9wMR//tAGxvSQ="
|
"nodeModules": "sha256-3CG0wAMQp2E6ghPUXbYaYifJorp9b1WvCtHD+o8Nhck="
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@ export const github = query(async () => {
|
||||||
release: {
|
release: {
|
||||||
name: release.name,
|
name: release.name,
|
||||||
url: release.html_url,
|
url: release.html_url,
|
||||||
|
tag_name: release.tag_name,
|
||||||
},
|
},
|
||||||
contributors: contributorCount,
|
contributors: contributorCount,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,15 +8,7 @@ import { Faq } from "~/component/faq"
|
||||||
import desktopAppIcon from "../../asset/lander/opencode-desktop-icon.png"
|
import desktopAppIcon from "../../asset/lander/opencode-desktop-icon.png"
|
||||||
import { Legal } from "~/component/legal"
|
import { Legal } from "~/component/legal"
|
||||||
import { config } from "~/config"
|
import { config } from "~/config"
|
||||||
import { createMemo } from "solid-js"
|
import { github } from "~/lib/github"
|
||||||
|
|
||||||
const getLatestRelease = query(async () => {
|
|
||||||
"use server"
|
|
||||||
const response = await fetch("https://api.github.com/repos/sst/opencode/releases/latest")
|
|
||||||
if (!response.ok) return null
|
|
||||||
const data = await response.json()
|
|
||||||
return data.tag_name as string
|
|
||||||
}, "latest-release")
|
|
||||||
|
|
||||||
function CopyStatus() {
|
function CopyStatus() {
|
||||||
return (
|
return (
|
||||||
|
|
@ -28,14 +20,14 @@ function CopyStatus() {
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function Download() {
|
export default function Download() {
|
||||||
const release = createAsync(() => getLatestRelease(), {
|
const githubData = createAsync(() => github(), {
|
||||||
deferStream: true,
|
deferStream: true,
|
||||||
})
|
})
|
||||||
const download = createMemo(() => {
|
const download = () => {
|
||||||
const version = release() ?? "v1.0.150"
|
const version = githubData()?.release.tag_name
|
||||||
if (!version) return null
|
if (!version) return null
|
||||||
return `https://github.com/sst/opencode/releases/download/${version}`
|
return `https://github.com/sst/opencode/releases/download/${version}`
|
||||||
})
|
}
|
||||||
const handleCopyClick = (command: string) => (event: Event) => {
|
const handleCopyClick = (command: string) => (event: Event) => {
|
||||||
const button = event.currentTarget as HTMLButtonElement
|
const button = event.currentTarget as HTMLButtonElement
|
||||||
navigator.clipboard.writeText(command)
|
navigator.clipboard.writeText(command)
|
||||||
|
|
|
||||||
|
|
@ -43,9 +43,12 @@ const getModelsInfo = query(async (workspaceID: string) => {
|
||||||
const pA = getPriority(idA)
|
const pA = getPriority(idA)
|
||||||
const pB = getPriority(idB)
|
const pB = getPriority(idB)
|
||||||
if (pA !== pB) return pA - pB
|
if (pA !== pB) return pA - pB
|
||||||
return modelA.name.localeCompare(modelB.name)
|
|
||||||
|
const modelAName = Array.isArray(modelA) ? modelA[0].name : modelA.name
|
||||||
|
const modelBName = Array.isArray(modelB) ? modelB[0].name : modelB.name
|
||||||
|
return modelAName.localeCompare(modelBName)
|
||||||
})
|
})
|
||||||
.map(([id, model]) => ({ id, name: model.name })),
|
.map(([id, model]) => ({ id, name: Array.isArray(model) ? model[0].name : model.name })),
|
||||||
disabled: await Model.listDisabled(),
|
disabled: await Model.listDisabled(),
|
||||||
}
|
}
|
||||||
}, workspaceID)
|
}, workspaceID)
|
||||||
|
|
|
||||||
|
|
@ -57,15 +57,17 @@ export async function handler(
|
||||||
const sessionId = input.request.headers.get("x-opencode-session") ?? ""
|
const sessionId = input.request.headers.get("x-opencode-session") ?? ""
|
||||||
const requestId = input.request.headers.get("x-opencode-request") ?? ""
|
const requestId = input.request.headers.get("x-opencode-request") ?? ""
|
||||||
const projectId = input.request.headers.get("x-opencode-project") ?? ""
|
const projectId = input.request.headers.get("x-opencode-project") ?? ""
|
||||||
|
const ocClient = input.request.headers.get("x-opencode-client") ?? ""
|
||||||
logger.metric({
|
logger.metric({
|
||||||
is_tream: isStream,
|
is_tream: isStream,
|
||||||
session: sessionId,
|
session: sessionId,
|
||||||
request: requestId,
|
request: requestId,
|
||||||
|
client: ocClient,
|
||||||
})
|
})
|
||||||
const zenData = ZenData.list()
|
const zenData = ZenData.list()
|
||||||
const modelInfo = validateModel(zenData, model)
|
const modelInfo = validateModel(zenData, model)
|
||||||
const dataDumper = createDataDumper(sessionId, requestId, projectId)
|
const dataDumper = createDataDumper(sessionId, requestId, projectId)
|
||||||
const trialLimiter = createTrialLimiter(modelInfo.trial?.limit, ip)
|
const trialLimiter = createTrialLimiter(modelInfo.trial, ip, ocClient)
|
||||||
const isTrial = await trialLimiter?.isTrial()
|
const isTrial = await trialLimiter?.isTrial()
|
||||||
const rateLimiter = createRateLimiter(modelInfo.id, modelInfo.rateLimit, ip)
|
const rateLimiter = createRateLimiter(modelInfo.id, modelInfo.rateLimit, ip)
|
||||||
await rateLimiter?.check()
|
await rateLimiter?.check()
|
||||||
|
|
@ -286,11 +288,14 @@ export async function handler(
|
||||||
}
|
}
|
||||||
|
|
||||||
function validateModel(zenData: ZenData, reqModel: string) {
|
function validateModel(zenData: ZenData, reqModel: string) {
|
||||||
if (!(reqModel in zenData.models)) {
|
if (!(reqModel in zenData.models)) throw new ModelError(`Model ${reqModel} not supported`)
|
||||||
throw new ModelError(`Model ${reqModel} not supported`)
|
|
||||||
}
|
|
||||||
const modelId = reqModel as keyof typeof zenData.models
|
const modelId = reqModel as keyof typeof zenData.models
|
||||||
const modelData = zenData.models[modelId]
|
const modelData = Array.isArray(zenData.models[modelId])
|
||||||
|
? zenData.models[modelId].find((model) => opts.format === model.formatFilter)
|
||||||
|
: zenData.models[modelId]
|
||||||
|
|
||||||
|
if (!modelData) throw new ModelError(`Model ${reqModel} not supported for format ${opts.format}`)
|
||||||
|
|
||||||
logger.metric({ model: modelId })
|
logger.metric({ model: modelId })
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,18 @@
|
||||||
import { Database, eq, sql } from "@opencode-ai/console-core/drizzle/index.js"
|
import { Database, eq, sql } from "@opencode-ai/console-core/drizzle/index.js"
|
||||||
import { IpTable } from "@opencode-ai/console-core/schema/ip.sql.js"
|
import { IpTable } from "@opencode-ai/console-core/schema/ip.sql.js"
|
||||||
import { UsageInfo } from "./provider/provider"
|
import { UsageInfo } from "./provider/provider"
|
||||||
|
import { ZenData } from "@opencode-ai/console-core/model.js"
|
||||||
|
|
||||||
export function createTrialLimiter(limit: number | undefined, ip: string) {
|
export function createTrialLimiter(trial: ZenData.Trial | undefined, ip: string, client: string) {
|
||||||
if (!limit) return
|
if (!trial) return
|
||||||
if (!ip) return
|
if (!ip) return
|
||||||
|
|
||||||
let trial: boolean
|
const limit =
|
||||||
|
trial.limits.find((limit) => limit.client === client)?.limit ??
|
||||||
|
trial.limits.find((limit) => limit.client === undefined)?.limit
|
||||||
|
if (!limit) return
|
||||||
|
|
||||||
|
let _isTrial: boolean
|
||||||
|
|
||||||
return {
|
return {
|
||||||
isTrial: async () => {
|
isTrial: async () => {
|
||||||
|
|
@ -20,11 +26,11 @@ export function createTrialLimiter(limit: number | undefined, ip: string) {
|
||||||
.then((rows) => rows[0]),
|
.then((rows) => rows[0]),
|
||||||
)
|
)
|
||||||
|
|
||||||
trial = (data?.usage ?? 0) < limit
|
_isTrial = (data?.usage ?? 0) < limit
|
||||||
return trial
|
return _isTrial
|
||||||
},
|
},
|
||||||
track: async (usageInfo: UsageInfo) => {
|
track: async (usageInfo: UsageInfo) => {
|
||||||
if (!trial) return
|
if (!_isTrial) return
|
||||||
const usage =
|
const usage =
|
||||||
usageInfo.inputTokens +
|
usageInfo.inputTokens +
|
||||||
usageInfo.outputTokens +
|
usageInfo.outputTokens +
|
||||||
|
|
|
||||||
|
|
@ -16,16 +16,19 @@ const value1 = lines.find((line) => line.startsWith("ZEN_MODELS1"))?.split("=")[
|
||||||
const value2 = lines.find((line) => line.startsWith("ZEN_MODELS2"))?.split("=")[1]
|
const value2 = lines.find((line) => line.startsWith("ZEN_MODELS2"))?.split("=")[1]
|
||||||
const value3 = lines.find((line) => line.startsWith("ZEN_MODELS3"))?.split("=")[1]
|
const value3 = lines.find((line) => line.startsWith("ZEN_MODELS3"))?.split("=")[1]
|
||||||
const value4 = lines.find((line) => line.startsWith("ZEN_MODELS4"))?.split("=")[1]
|
const value4 = lines.find((line) => line.startsWith("ZEN_MODELS4"))?.split("=")[1]
|
||||||
|
const value5 = lines.find((line) => line.startsWith("ZEN_MODELS5"))?.split("=")[1]
|
||||||
if (!value1) throw new Error("ZEN_MODELS1 not found")
|
if (!value1) throw new Error("ZEN_MODELS1 not found")
|
||||||
if (!value2) throw new Error("ZEN_MODELS2 not found")
|
if (!value2) throw new Error("ZEN_MODELS2 not found")
|
||||||
if (!value3) throw new Error("ZEN_MODELS3 not found")
|
if (!value3) throw new Error("ZEN_MODELS3 not found")
|
||||||
if (!value4) throw new Error("ZEN_MODELS4 not found")
|
if (!value4) throw new Error("ZEN_MODELS4 not found")
|
||||||
|
if (!value5) throw new Error("ZEN_MODELS5 not found")
|
||||||
|
|
||||||
// validate value
|
// validate value
|
||||||
ZenData.validate(JSON.parse(value1 + value2 + value3 + value4))
|
ZenData.validate(JSON.parse(value1 + value2 + value3 + value4 + value5))
|
||||||
|
|
||||||
// update the secret
|
// update the secret
|
||||||
await $`bun sst secret set ZEN_MODELS1 ${value1} --stage ${stage}`
|
await $`bun sst secret set ZEN_MODELS1 ${value1} --stage ${stage}`
|
||||||
await $`bun sst secret set ZEN_MODELS2 ${value2} --stage ${stage}`
|
await $`bun sst secret set ZEN_MODELS2 ${value2} --stage ${stage}`
|
||||||
await $`bun sst secret set ZEN_MODELS3 ${value3} --stage ${stage}`
|
await $`bun sst secret set ZEN_MODELS3 ${value3} --stage ${stage}`
|
||||||
await $`bun sst secret set ZEN_MODELS4 ${value4} --stage ${stage}`
|
await $`bun sst secret set ZEN_MODELS4 ${value4} --stage ${stage}`
|
||||||
|
await $`bun sst secret set ZEN_MODELS5 ${value5} --stage ${stage}`
|
||||||
|
|
|
||||||
|
|
@ -16,16 +16,19 @@ const value1 = lines.find((line) => line.startsWith("ZEN_MODELS1"))?.split("=")[
|
||||||
const value2 = lines.find((line) => line.startsWith("ZEN_MODELS2"))?.split("=")[1]
|
const value2 = lines.find((line) => line.startsWith("ZEN_MODELS2"))?.split("=")[1]
|
||||||
const value3 = lines.find((line) => line.startsWith("ZEN_MODELS3"))?.split("=")[1]
|
const value3 = lines.find((line) => line.startsWith("ZEN_MODELS3"))?.split("=")[1]
|
||||||
const value4 = lines.find((line) => line.startsWith("ZEN_MODELS4"))?.split("=")[1]
|
const value4 = lines.find((line) => line.startsWith("ZEN_MODELS4"))?.split("=")[1]
|
||||||
|
const value5 = lines.find((line) => line.startsWith("ZEN_MODELS5"))?.split("=")[1]
|
||||||
if (!value1) throw new Error("ZEN_MODELS1 not found")
|
if (!value1) throw new Error("ZEN_MODELS1 not found")
|
||||||
if (!value2) throw new Error("ZEN_MODELS2 not found")
|
if (!value2) throw new Error("ZEN_MODELS2 not found")
|
||||||
if (!value3) throw new Error("ZEN_MODELS3 not found")
|
if (!value3) throw new Error("ZEN_MODELS3 not found")
|
||||||
if (!value4) throw new Error("ZEN_MODELS4 not found")
|
if (!value4) throw new Error("ZEN_MODELS4 not found")
|
||||||
|
if (!value5) throw new Error("ZEN_MODELS5 not found")
|
||||||
|
|
||||||
// validate value
|
// validate value
|
||||||
ZenData.validate(JSON.parse(value1 + value2 + value3 + value4))
|
ZenData.validate(JSON.parse(value1 + value2 + value3 + value4 + value5))
|
||||||
|
|
||||||
// update the secret
|
// update the secret
|
||||||
await $`bun sst secret set ZEN_MODELS1 ${value1}`
|
await $`bun sst secret set ZEN_MODELS1 ${value1}`
|
||||||
await $`bun sst secret set ZEN_MODELS2 ${value2}`
|
await $`bun sst secret set ZEN_MODELS2 ${value2}`
|
||||||
await $`bun sst secret set ZEN_MODELS3 ${value3}`
|
await $`bun sst secret set ZEN_MODELS3 ${value3}`
|
||||||
await $`bun sst secret set ZEN_MODELS4 ${value4}`
|
await $`bun sst secret set ZEN_MODELS4 ${value4}`
|
||||||
|
await $`bun sst secret set ZEN_MODELS5 ${value5}`
|
||||||
|
|
|
||||||
|
|
@ -14,15 +14,17 @@ const oldValue1 = lines.find((line) => line.startsWith("ZEN_MODELS1"))?.split("=
|
||||||
const oldValue2 = lines.find((line) => line.startsWith("ZEN_MODELS2"))?.split("=")[1]
|
const oldValue2 = lines.find((line) => line.startsWith("ZEN_MODELS2"))?.split("=")[1]
|
||||||
const oldValue3 = lines.find((line) => line.startsWith("ZEN_MODELS3"))?.split("=")[1]
|
const oldValue3 = lines.find((line) => line.startsWith("ZEN_MODELS3"))?.split("=")[1]
|
||||||
const oldValue4 = lines.find((line) => line.startsWith("ZEN_MODELS4"))?.split("=")[1]
|
const oldValue4 = lines.find((line) => line.startsWith("ZEN_MODELS4"))?.split("=")[1]
|
||||||
|
const oldValue5 = lines.find((line) => line.startsWith("ZEN_MODELS5"))?.split("=")[1]
|
||||||
if (!oldValue1) throw new Error("ZEN_MODELS1 not found")
|
if (!oldValue1) throw new Error("ZEN_MODELS1 not found")
|
||||||
if (!oldValue2) throw new Error("ZEN_MODELS2 not found")
|
if (!oldValue2) throw new Error("ZEN_MODELS2 not found")
|
||||||
if (!oldValue3) throw new Error("ZEN_MODELS3 not found")
|
if (!oldValue3) throw new Error("ZEN_MODELS3 not found")
|
||||||
if (!oldValue4) throw new Error("ZEN_MODELS4 not found")
|
if (!oldValue4) throw new Error("ZEN_MODELS4 not found")
|
||||||
|
if (!oldValue5) throw new Error("ZEN_MODELS5 not found")
|
||||||
|
|
||||||
// store the prettified json to a temp file
|
// store the prettified json to a temp file
|
||||||
const filename = `models-${Date.now()}.json`
|
const filename = `models-${Date.now()}.json`
|
||||||
const tempFile = Bun.file(path.join(os.tmpdir(), filename))
|
const tempFile = Bun.file(path.join(os.tmpdir(), filename))
|
||||||
await tempFile.write(JSON.stringify(JSON.parse(oldValue1 + oldValue2 + oldValue3 + oldValue4), null, 2))
|
await tempFile.write(JSON.stringify(JSON.parse(oldValue1 + oldValue2 + oldValue3 + oldValue4 + oldValue5), null, 2))
|
||||||
console.log("tempFile", tempFile.name)
|
console.log("tempFile", tempFile.name)
|
||||||
|
|
||||||
// open temp file in vim and read the file on close
|
// open temp file in vim and read the file on close
|
||||||
|
|
@ -31,12 +33,15 @@ const newValue = JSON.stringify(JSON.parse(await tempFile.text()))
|
||||||
ZenData.validate(JSON.parse(newValue))
|
ZenData.validate(JSON.parse(newValue))
|
||||||
|
|
||||||
// update the secret
|
// update the secret
|
||||||
const chunk = Math.ceil(newValue.length / 4)
|
const chunk = Math.ceil(newValue.length / 5)
|
||||||
const newValue1 = newValue.slice(0, chunk)
|
const newValue1 = newValue.slice(0, chunk)
|
||||||
const newValue2 = newValue.slice(chunk, chunk * 2)
|
const newValue2 = newValue.slice(chunk, chunk * 2)
|
||||||
const newValue3 = newValue.slice(chunk * 2, chunk * 3)
|
const newValue3 = newValue.slice(chunk * 2, chunk * 3)
|
||||||
const newValue4 = newValue.slice(chunk * 3)
|
const newValue4 = newValue.slice(chunk * 3, chunk * 4)
|
||||||
|
const newValue5 = newValue.slice(chunk * 4)
|
||||||
|
|
||||||
await $`bun sst secret set ZEN_MODELS1 ${newValue1}`
|
await $`bun sst secret set ZEN_MODELS1 ${newValue1}`
|
||||||
await $`bun sst secret set ZEN_MODELS2 ${newValue2}`
|
await $`bun sst secret set ZEN_MODELS2 ${newValue2}`
|
||||||
await $`bun sst secret set ZEN_MODELS3 ${newValue3}`
|
await $`bun sst secret set ZEN_MODELS3 ${newValue3}`
|
||||||
await $`bun sst secret set ZEN_MODELS4 ${newValue4}`
|
await $`bun sst secret set ZEN_MODELS4 ${newValue4}`
|
||||||
|
await $`bun sst secret set ZEN_MODELS5 ${newValue5}`
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,17 @@ import { Resource } from "@opencode-ai/console-resource"
|
||||||
|
|
||||||
export namespace ZenData {
|
export namespace ZenData {
|
||||||
const FormatSchema = z.enum(["anthropic", "google", "openai", "oa-compat"])
|
const FormatSchema = z.enum(["anthropic", "google", "openai", "oa-compat"])
|
||||||
|
const TrialSchema = z.object({
|
||||||
|
provider: z.string(),
|
||||||
|
limits: z.array(
|
||||||
|
z.object({
|
||||||
|
limit: z.number(),
|
||||||
|
client: z.enum(["cli", "desktop"]).optional(),
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
})
|
||||||
export type Format = z.infer<typeof FormatSchema>
|
export type Format = z.infer<typeof FormatSchema>
|
||||||
|
export type Trial = z.infer<typeof TrialSchema>
|
||||||
|
|
||||||
const ModelCostSchema = z.object({
|
const ModelCostSchema = z.object({
|
||||||
input: z.number(),
|
input: z.number(),
|
||||||
|
|
@ -26,12 +36,7 @@ export namespace ZenData {
|
||||||
allowAnonymous: z.boolean().optional(),
|
allowAnonymous: z.boolean().optional(),
|
||||||
byokProvider: z.enum(["openai", "anthropic", "google"]).optional(),
|
byokProvider: z.enum(["openai", "anthropic", "google"]).optional(),
|
||||||
stickyProvider: z.boolean().optional(),
|
stickyProvider: z.boolean().optional(),
|
||||||
trial: z
|
trial: TrialSchema.optional(),
|
||||||
.object({
|
|
||||||
limit: z.number(),
|
|
||||||
provider: z.string(),
|
|
||||||
})
|
|
||||||
.optional(),
|
|
||||||
rateLimit: z.number().optional(),
|
rateLimit: z.number().optional(),
|
||||||
fallbackProvider: z.string().optional(),
|
fallbackProvider: z.string().optional(),
|
||||||
providers: z.array(
|
providers: z.array(
|
||||||
|
|
@ -53,7 +58,7 @@ export namespace ZenData {
|
||||||
})
|
})
|
||||||
|
|
||||||
const ModelsSchema = z.object({
|
const ModelsSchema = z.object({
|
||||||
models: z.record(z.string(), ModelSchema),
|
models: z.record(z.string(), z.union([ModelSchema, z.array(ModelSchema.extend({ formatFilter: FormatSchema }))])),
|
||||||
providers: z.record(z.string(), ProviderSchema),
|
providers: z.record(z.string(), ProviderSchema),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
@ -63,7 +68,11 @@ export namespace ZenData {
|
||||||
|
|
||||||
export const list = fn(z.void(), () => {
|
export const list = fn(z.void(), () => {
|
||||||
const json = JSON.parse(
|
const json = JSON.parse(
|
||||||
Resource.ZEN_MODELS1.value + Resource.ZEN_MODELS2.value + Resource.ZEN_MODELS3.value + Resource.ZEN_MODELS4.value,
|
Resource.ZEN_MODELS1.value +
|
||||||
|
Resource.ZEN_MODELS2.value +
|
||||||
|
Resource.ZEN_MODELS3.value +
|
||||||
|
Resource.ZEN_MODELS4.value +
|
||||||
|
Resource.ZEN_MODELS5.value,
|
||||||
)
|
)
|
||||||
return ModelsSchema.parse(json)
|
return ModelsSchema.parse(json)
|
||||||
})
|
})
|
||||||
|
|
|
||||||
12
packages/console/core/sst-env.d.ts
vendored
12
packages/console/core/sst-env.d.ts
vendored
|
|
@ -50,10 +50,6 @@ declare module "sst" {
|
||||||
"type": "sst.sst.Secret"
|
"type": "sst.sst.Secret"
|
||||||
"value": string
|
"value": string
|
||||||
}
|
}
|
||||||
"Enterprise": {
|
|
||||||
"type": "sst.cloudflare.SolidStart"
|
|
||||||
"url": string
|
|
||||||
}
|
|
||||||
"GITHUB_APP_ID": {
|
"GITHUB_APP_ID": {
|
||||||
"type": "sst.sst.Secret"
|
"type": "sst.sst.Secret"
|
||||||
"value": string
|
"value": string
|
||||||
|
|
@ -94,6 +90,10 @@ declare module "sst" {
|
||||||
"type": "sst.sst.Linkable"
|
"type": "sst.sst.Linkable"
|
||||||
"value": string
|
"value": string
|
||||||
}
|
}
|
||||||
|
"Teams": {
|
||||||
|
"type": "sst.cloudflare.SolidStart"
|
||||||
|
"url": string
|
||||||
|
}
|
||||||
"Web": {
|
"Web": {
|
||||||
"type": "sst.cloudflare.Astro"
|
"type": "sst.cloudflare.Astro"
|
||||||
"url": string
|
"url": string
|
||||||
|
|
@ -114,6 +114,10 @@ declare module "sst" {
|
||||||
"type": "sst.sst.Secret"
|
"type": "sst.sst.Secret"
|
||||||
"value": string
|
"value": string
|
||||||
}
|
}
|
||||||
|
"ZEN_MODELS5": {
|
||||||
|
"type": "sst.sst.Secret"
|
||||||
|
"value": string
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// cloudflare
|
// cloudflare
|
||||||
|
|
|
||||||
12
packages/console/function/sst-env.d.ts
vendored
12
packages/console/function/sst-env.d.ts
vendored
|
|
@ -50,10 +50,6 @@ declare module "sst" {
|
||||||
"type": "sst.sst.Secret"
|
"type": "sst.sst.Secret"
|
||||||
"value": string
|
"value": string
|
||||||
}
|
}
|
||||||
"Enterprise": {
|
|
||||||
"type": "sst.cloudflare.SolidStart"
|
|
||||||
"url": string
|
|
||||||
}
|
|
||||||
"GITHUB_APP_ID": {
|
"GITHUB_APP_ID": {
|
||||||
"type": "sst.sst.Secret"
|
"type": "sst.sst.Secret"
|
||||||
"value": string
|
"value": string
|
||||||
|
|
@ -94,6 +90,10 @@ declare module "sst" {
|
||||||
"type": "sst.sst.Linkable"
|
"type": "sst.sst.Linkable"
|
||||||
"value": string
|
"value": string
|
||||||
}
|
}
|
||||||
|
"Teams": {
|
||||||
|
"type": "sst.cloudflare.SolidStart"
|
||||||
|
"url": string
|
||||||
|
}
|
||||||
"Web": {
|
"Web": {
|
||||||
"type": "sst.cloudflare.Astro"
|
"type": "sst.cloudflare.Astro"
|
||||||
"url": string
|
"url": string
|
||||||
|
|
@ -114,6 +114,10 @@ declare module "sst" {
|
||||||
"type": "sst.sst.Secret"
|
"type": "sst.sst.Secret"
|
||||||
"value": string
|
"value": string
|
||||||
}
|
}
|
||||||
|
"ZEN_MODELS5": {
|
||||||
|
"type": "sst.sst.Secret"
|
||||||
|
"value": string
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// cloudflare
|
// cloudflare
|
||||||
|
|
|
||||||
12
packages/console/resource/sst-env.d.ts
vendored
12
packages/console/resource/sst-env.d.ts
vendored
|
|
@ -50,10 +50,6 @@ declare module "sst" {
|
||||||
"type": "sst.sst.Secret"
|
"type": "sst.sst.Secret"
|
||||||
"value": string
|
"value": string
|
||||||
}
|
}
|
||||||
"Enterprise": {
|
|
||||||
"type": "sst.cloudflare.SolidStart"
|
|
||||||
"url": string
|
|
||||||
}
|
|
||||||
"GITHUB_APP_ID": {
|
"GITHUB_APP_ID": {
|
||||||
"type": "sst.sst.Secret"
|
"type": "sst.sst.Secret"
|
||||||
"value": string
|
"value": string
|
||||||
|
|
@ -94,6 +90,10 @@ declare module "sst" {
|
||||||
"type": "sst.sst.Linkable"
|
"type": "sst.sst.Linkable"
|
||||||
"value": string
|
"value": string
|
||||||
}
|
}
|
||||||
|
"Teams": {
|
||||||
|
"type": "sst.cloudflare.SolidStart"
|
||||||
|
"url": string
|
||||||
|
}
|
||||||
"Web": {
|
"Web": {
|
||||||
"type": "sst.cloudflare.Astro"
|
"type": "sst.cloudflare.Astro"
|
||||||
"url": string
|
"url": string
|
||||||
|
|
@ -114,6 +114,10 @@ declare module "sst" {
|
||||||
"type": "sst.sst.Secret"
|
"type": "sst.sst.Secret"
|
||||||
"value": string
|
"value": string
|
||||||
}
|
}
|
||||||
|
"ZEN_MODELS5": {
|
||||||
|
"type": "sst.sst.Secret"
|
||||||
|
"value": string
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// cloudflare
|
// cloudflare
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@
|
||||||
<meta property="og:image" content="/social-share.png" />
|
<meta property="og:image" content="/social-share.png" />
|
||||||
<meta property="twitter:image" content="/social-share.png" />
|
<meta property="twitter:image" content="/social-share.png" />
|
||||||
</head>
|
</head>
|
||||||
<body class="antialiased overscroll-none select-none text-12-regular">
|
<body class="antialiased overscroll-none select-none text-12-regular overflow-hidden">
|
||||||
<script>
|
<script>
|
||||||
;(function () {
|
;(function () {
|
||||||
const savedTheme = localStorage.getItem("theme") || "oc-1"
|
const savedTheme = localStorage.getItem("theme") || "oc-1"
|
||||||
|
|
@ -22,7 +22,7 @@
|
||||||
})()
|
})()
|
||||||
</script>
|
</script>
|
||||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||||
<div id="root"></div>
|
<div id="root" class="flex flex-col h-screen"></div>
|
||||||
<script src="/src/entry.tsx" type="module"></script>
|
<script src="/src/entry.tsx" type="module"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,7 @@
|
||||||
"@opencode-ai/util": "workspace:*",
|
"@opencode-ai/util": "workspace:*",
|
||||||
"@shikijs/transformers": "3.9.2",
|
"@shikijs/transformers": "3.9.2",
|
||||||
"@solid-primitives/active-element": "2.1.3",
|
"@solid-primitives/active-element": "2.1.3",
|
||||||
|
"@solid-primitives/audio": "1.4.2",
|
||||||
"@solid-primitives/event-bus": "1.1.2",
|
"@solid-primitives/event-bus": "1.1.2",
|
||||||
"@solid-primitives/resize-observer": "2.1.3",
|
"@solid-primitives/resize-observer": "2.1.3",
|
||||||
"@solid-primitives/scroll": "2.1.3",
|
"@solid-primitives/scroll": "2.1.3",
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ import { LayoutProvider } from "./context/layout"
|
||||||
import { GlobalSDKProvider } from "./context/global-sdk"
|
import { GlobalSDKProvider } from "./context/global-sdk"
|
||||||
import { SessionProvider } from "./context/session"
|
import { SessionProvider } from "./context/session"
|
||||||
import { Show } from "solid-js"
|
import { Show } from "solid-js"
|
||||||
|
import { NotificationProvider } from "./context/notification"
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
interface Window {
|
interface Window {
|
||||||
|
|
@ -37,25 +38,27 @@ export function App() {
|
||||||
<GlobalSDKProvider url={url}>
|
<GlobalSDKProvider url={url}>
|
||||||
<GlobalSyncProvider>
|
<GlobalSyncProvider>
|
||||||
<LayoutProvider>
|
<LayoutProvider>
|
||||||
<MetaProvider>
|
<NotificationProvider>
|
||||||
<Font />
|
<MetaProvider>
|
||||||
<Router root={Layout}>
|
<Font />
|
||||||
<Route path="/" component={Home} />
|
<Router root={Layout}>
|
||||||
<Route path="/:dir" component={DirectoryLayout}>
|
<Route path="/" component={Home} />
|
||||||
<Route path="/" component={() => <Navigate href="session" />} />
|
<Route path="/:dir" component={DirectoryLayout}>
|
||||||
<Route
|
<Route path="/" component={() => <Navigate href="session" />} />
|
||||||
path="/session/:id?"
|
<Route
|
||||||
component={(p) => (
|
path="/session/:id?"
|
||||||
<Show when={p.params.id || true} keyed>
|
component={(p) => (
|
||||||
<SessionProvider>
|
<Show when={p.params.id || true} keyed>
|
||||||
<Session />
|
<SessionProvider>
|
||||||
</SessionProvider>
|
<Session />
|
||||||
</Show>
|
</SessionProvider>
|
||||||
)}
|
</Show>
|
||||||
/>
|
)}
|
||||||
</Route>
|
/>
|
||||||
</Router>
|
</Route>
|
||||||
</MetaProvider>
|
</Router>
|
||||||
|
</MetaProvider>
|
||||||
|
</NotificationProvider>
|
||||||
</LayoutProvider>
|
</LayoutProvider>
|
||||||
</GlobalSyncProvider>
|
</GlobalSyncProvider>
|
||||||
</GlobalSDKProvider>
|
</GlobalSDKProvider>
|
||||||
|
|
|
||||||
113
packages/desktop/src/components/header.tsx
Normal file
113
packages/desktop/src/components/header.tsx
Normal file
|
|
@ -0,0 +1,113 @@
|
||||||
|
import { useGlobalSync } from "@/context/global-sync"
|
||||||
|
import { useLayout } from "@/context/layout"
|
||||||
|
import { Session } from "@opencode-ai/sdk/v2/client"
|
||||||
|
import { Button } from "@opencode-ai/ui/button"
|
||||||
|
import { Icon } from "@opencode-ai/ui/icon"
|
||||||
|
import { Mark } from "@opencode-ai/ui/logo"
|
||||||
|
import { Select } from "@opencode-ai/ui/select"
|
||||||
|
import { Tooltip } from "@opencode-ai/ui/tooltip"
|
||||||
|
import { base64Decode } from "@opencode-ai/util/encode"
|
||||||
|
import { getFilename } from "@opencode-ai/util/path"
|
||||||
|
import { A, useParams } from "@solidjs/router"
|
||||||
|
import { createMemo, Show } from "solid-js"
|
||||||
|
|
||||||
|
export function Header(props: {
|
||||||
|
navigateToProject: (directory: string) => void
|
||||||
|
navigateToSession: (session: Session | undefined) => void
|
||||||
|
}) {
|
||||||
|
const globalSync = useGlobalSync()
|
||||||
|
const layout = useLayout()
|
||||||
|
const params = useParams()
|
||||||
|
const currentDirectory = createMemo(() => base64Decode(params.dir ?? ""))
|
||||||
|
const store = createMemo(() => globalSync.child(currentDirectory())[0])
|
||||||
|
const sessions = createMemo(() => store().session ?? [])
|
||||||
|
const currentSession = createMemo(() => sessions().find((s) => s.id === params.id))
|
||||||
|
|
||||||
|
return (
|
||||||
|
<header class="h-12 shrink-0 bg-background-base border-b border-border-weak-base flex" data-tauri-drag-region>
|
||||||
|
<A
|
||||||
|
href="/"
|
||||||
|
classList={{
|
||||||
|
"w-12 shrink-0 px-4 py-3.5": true,
|
||||||
|
"flex items-center justify-start self-stretch": true,
|
||||||
|
"border-r border-border-weak-base": true,
|
||||||
|
}}
|
||||||
|
style={{ width: layout.sidebar.opened() ? `${layout.sidebar.width()}px` : undefined }}
|
||||||
|
data-tauri-drag-region
|
||||||
|
>
|
||||||
|
<Mark class="shrink-0" />
|
||||||
|
</A>
|
||||||
|
<div class="pl-4 px-6 flex items-center justify-between gap-4 w-full">
|
||||||
|
<Show when={params.dir && layout.projects.list().length > 0}>
|
||||||
|
<div class="flex items-center gap-3">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<Select
|
||||||
|
options={layout.projects.list().map((project) => project.worktree)}
|
||||||
|
current={currentDirectory()}
|
||||||
|
label={(x) => getFilename(x)}
|
||||||
|
onSelect={(x) => (x ? props.navigateToProject(x) : undefined)}
|
||||||
|
class="text-14-regular text-text-base"
|
||||||
|
variant="ghost"
|
||||||
|
>
|
||||||
|
{/* @ts-ignore */}
|
||||||
|
{(i) => (
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<Icon name="folder" size="small" />
|
||||||
|
<div class="text-text-strong">{getFilename(i)}</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</Select>
|
||||||
|
<div class="text-text-weaker">/</div>
|
||||||
|
<Select
|
||||||
|
options={sessions()}
|
||||||
|
current={currentSession()}
|
||||||
|
placeholder="New session"
|
||||||
|
label={(x) => x.title}
|
||||||
|
value={(x) => x.id}
|
||||||
|
onSelect={props.navigateToSession}
|
||||||
|
class="text-14-regular text-text-base max-w-md"
|
||||||
|
variant="ghost"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<Show when={currentSession()}>
|
||||||
|
<Button as={A} href={`/${params.dir}/session`} icon="plus-small">
|
||||||
|
New session
|
||||||
|
</Button>
|
||||||
|
</Show>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-4">
|
||||||
|
<Tooltip
|
||||||
|
class="shrink-0"
|
||||||
|
value={
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<span>Toggle terminal</span>
|
||||||
|
<span class="text-icon-base text-12-medium">Ctrl `</span>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Button variant="ghost" class="group/terminal-toggle size-6 p-0" onClick={layout.terminal.toggle}>
|
||||||
|
<div class="relative flex items-center justify-center size-4 [&>*]:absolute [&>*]:inset-0">
|
||||||
|
<Icon
|
||||||
|
size="small"
|
||||||
|
name={layout.terminal.opened() ? "layout-bottom-full" : "layout-bottom"}
|
||||||
|
class="group-hover/terminal-toggle:hidden"
|
||||||
|
/>
|
||||||
|
<Icon
|
||||||
|
size="small"
|
||||||
|
name="layout-bottom-partial"
|
||||||
|
class="hidden group-hover/terminal-toggle:inline-block"
|
||||||
|
/>
|
||||||
|
<Icon
|
||||||
|
size="small"
|
||||||
|
name={layout.terminal.opened() ? "layout-bottom" : "layout-bottom-full"}
|
||||||
|
class="hidden group-active/terminal-toggle:inline-block"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</Button>
|
||||||
|
</Tooltip>
|
||||||
|
</div>
|
||||||
|
</Show>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -55,45 +55,20 @@ export const { use: useGlobalSync, provider: GlobalSyncProvider } = createSimple
|
||||||
const globalSDK = useGlobalSDK()
|
const globalSDK = useGlobalSDK()
|
||||||
const [globalStore, setGlobalStore] = createStore<{
|
const [globalStore, setGlobalStore] = createStore<{
|
||||||
ready: boolean
|
ready: boolean
|
||||||
|
path: Path
|
||||||
project: Project[]
|
project: Project[]
|
||||||
provider: ProviderListResponse
|
provider: ProviderListResponse
|
||||||
provider_auth: ProviderAuthResponse
|
provider_auth: ProviderAuthResponse
|
||||||
children: Record<string, State>
|
children: Record<string, State>
|
||||||
}>({
|
}>({
|
||||||
ready: false,
|
ready: false,
|
||||||
|
path: { state: "", config: "", worktree: "", directory: "", home: "" },
|
||||||
project: [],
|
project: [],
|
||||||
provider: { all: [], connected: [], default: {} },
|
provider: { all: [], connected: [], default: {} },
|
||||||
provider_auth: {},
|
provider_auth: {},
|
||||||
children: {},
|
children: {},
|
||||||
})
|
})
|
||||||
|
|
||||||
async function bootstrapInstance(directory: string) {
|
|
||||||
const [store, setStore] = child(directory)
|
|
||||||
const sdk = createOpencodeClient({
|
|
||||||
baseUrl: globalSDK.url,
|
|
||||||
directory,
|
|
||||||
})
|
|
||||||
const load = {
|
|
||||||
project: () => sdk.project.current().then((x) => setStore("project", x.data!.id)),
|
|
||||||
provider: () => sdk.provider.list().then((x) => setStore("provider", x.data!)),
|
|
||||||
path: () => sdk.path.get().then((x) => setStore("path", x.data!)),
|
|
||||||
agent: () => sdk.app.agents().then((x) => setStore("agent", x.data ?? [])),
|
|
||||||
session: () =>
|
|
||||||
sdk.session.list().then((x) => {
|
|
||||||
const sessions = (x.data ?? [])
|
|
||||||
.slice()
|
|
||||||
.sort((a, b) => a.id.localeCompare(b.id))
|
|
||||||
.slice(0, store.limit)
|
|
||||||
setStore("session", sessions)
|
|
||||||
}),
|
|
||||||
status: () => sdk.session.status().then((x) => setStore("session_status", x.data!)),
|
|
||||||
config: () => sdk.config.get().then((x) => setStore("config", x.data!)),
|
|
||||||
changes: () => sdk.file.status().then((x) => setStore("changes", x.data!)),
|
|
||||||
node: () => sdk.file.list({ path: "/" }).then((x) => setStore("node", x.data!)),
|
|
||||||
}
|
|
||||||
await Promise.all(Object.values(load).map((p) => p())).then(() => setStore("ready", true))
|
|
||||||
}
|
|
||||||
|
|
||||||
const children: Record<string, ReturnType<typeof createStore<State>>> = {}
|
const children: Record<string, ReturnType<typeof createStore<State>>> = {}
|
||||||
function child(directory: string) {
|
function child(directory: string) {
|
||||||
if (!children[directory]) {
|
if (!children[directory]) {
|
||||||
|
|
@ -120,6 +95,38 @@ export const { use: useGlobalSync, provider: GlobalSyncProvider } = createSimple
|
||||||
return children[directory]
|
return children[directory]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function loadSessions(directory: string) {
|
||||||
|
globalSDK.client.session.list({ directory }).then((x) => {
|
||||||
|
const sessions = (x.data ?? [])
|
||||||
|
.slice()
|
||||||
|
.filter((s) => !s.time.archived)
|
||||||
|
.sort((a, b) => a.id.localeCompare(b.id))
|
||||||
|
.slice(0, 5)
|
||||||
|
const [, setStore] = child(directory)
|
||||||
|
setStore("session", sessions)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async function bootstrapInstance(directory: string) {
|
||||||
|
const [, setStore] = child(directory)
|
||||||
|
const sdk = createOpencodeClient({
|
||||||
|
baseUrl: globalSDK.url,
|
||||||
|
directory,
|
||||||
|
})
|
||||||
|
const load = {
|
||||||
|
project: () => sdk.project.current().then((x) => setStore("project", x.data!.id)),
|
||||||
|
provider: () => sdk.provider.list().then((x) => setStore("provider", x.data!)),
|
||||||
|
path: () => sdk.path.get().then((x) => setStore("path", x.data!)),
|
||||||
|
agent: () => sdk.app.agents().then((x) => setStore("agent", x.data ?? [])),
|
||||||
|
session: () => loadSessions(directory),
|
||||||
|
status: () => sdk.session.status().then((x) => setStore("session_status", x.data!)),
|
||||||
|
config: () => sdk.config.get().then((x) => setStore("config", x.data!)),
|
||||||
|
changes: () => sdk.file.status().then((x) => setStore("changes", x.data!)),
|
||||||
|
node: () => sdk.file.list({ path: "/" }).then((x) => setStore("node", x.data!)),
|
||||||
|
}
|
||||||
|
await Promise.all(Object.values(load).map((p) => p())).then(() => setStore("ready", true))
|
||||||
|
}
|
||||||
|
|
||||||
globalSDK.event.listen((e) => {
|
globalSDK.event.listen((e) => {
|
||||||
const directory = e.name
|
const directory = e.name
|
||||||
const event = e.details
|
const event = e.details
|
||||||
|
|
@ -156,6 +163,17 @@ export const { use: useGlobalSync, provider: GlobalSyncProvider } = createSimple
|
||||||
}
|
}
|
||||||
case "session.updated": {
|
case "session.updated": {
|
||||||
const result = Binary.search(store.session, event.properties.info.id, (s) => s.id)
|
const result = Binary.search(store.session, event.properties.info.id, (s) => s.id)
|
||||||
|
if (event.properties.info.time.archived) {
|
||||||
|
if (result.found) {
|
||||||
|
setStore(
|
||||||
|
"session",
|
||||||
|
produce((draft) => {
|
||||||
|
draft.splice(result.index, 1)
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
if (result.found) {
|
if (result.found) {
|
||||||
setStore("session", result.index, reconcile(event.properties.info))
|
setStore("session", result.index, reconcile(event.properties.info))
|
||||||
break
|
break
|
||||||
|
|
@ -224,6 +242,9 @@ export const { use: useGlobalSync, provider: GlobalSyncProvider } = createSimple
|
||||||
|
|
||||||
async function bootstrap() {
|
async function bootstrap() {
|
||||||
return Promise.all([
|
return Promise.all([
|
||||||
|
globalSDK.client.path.get().then((x) => {
|
||||||
|
setGlobalStore("path", x.data!)
|
||||||
|
}),
|
||||||
globalSDK.client.project.list().then(async (x) => {
|
globalSDK.client.project.list().then(async (x) => {
|
||||||
setGlobalStore(
|
setGlobalStore(
|
||||||
"project",
|
"project",
|
||||||
|
|
@ -252,6 +273,9 @@ export const { use: useGlobalSync, provider: GlobalSyncProvider } = createSimple
|
||||||
},
|
},
|
||||||
child,
|
child,
|
||||||
bootstrap,
|
bootstrap,
|
||||||
|
project: {
|
||||||
|
loadSessions,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -7,15 +7,10 @@ import { useGlobalSDK } from "./global-sdk"
|
||||||
import { Project } from "@opencode-ai/sdk/v2"
|
import { Project } from "@opencode-ai/sdk/v2"
|
||||||
|
|
||||||
const AVATAR_COLOR_KEYS = ["pink", "mint", "orange", "purple", "cyan", "lime"] as const
|
const AVATAR_COLOR_KEYS = ["pink", "mint", "orange", "purple", "cyan", "lime"] as const
|
||||||
|
|
||||||
export type AvatarColorKey = (typeof AVATAR_COLOR_KEYS)[number]
|
export type AvatarColorKey = (typeof AVATAR_COLOR_KEYS)[number]
|
||||||
|
|
||||||
export function isAvatarColorKey(value: string): value is AvatarColorKey {
|
|
||||||
return AVATAR_COLOR_KEYS.includes(value as AvatarColorKey)
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getAvatarColors(key?: string) {
|
export function getAvatarColors(key?: string) {
|
||||||
if (key && isAvatarColorKey(key)) {
|
if (key && AVATAR_COLOR_KEYS.includes(key as AvatarColorKey)) {
|
||||||
return {
|
return {
|
||||||
background: `var(--avatar-background-${key})`,
|
background: `var(--avatar-background-${key})`,
|
||||||
foreground: `var(--avatar-text-${key})`,
|
foreground: `var(--avatar-text-${key})`,
|
||||||
|
|
@ -50,7 +45,7 @@ export const { use: useLayout, provider: LayoutProvider } = createSimpleContext(
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
name: "default-layout.v7",
|
name: "layout.v1",
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
const [ephemeral, setEphemeral] = createStore<{
|
const [ephemeral, setEphemeral] = createStore<{
|
||||||
|
|
@ -97,21 +92,10 @@ export const { use: useLayout, provider: LayoutProvider } = createSimpleContext(
|
||||||
const enriched = createMemo(() => store.projects.flatMap(enrich))
|
const enriched = createMemo(() => store.projects.flatMap(enrich))
|
||||||
const list = createMemo(() => enriched().flatMap(colorize))
|
const list = createMemo(() => enriched().flatMap(colorize))
|
||||||
|
|
||||||
async function loadProjectSessions(directory: string) {
|
|
||||||
const [, setStore] = globalSync.child(directory)
|
|
||||||
globalSdk.client.session.list({ directory }).then((x) => {
|
|
||||||
const sessions = (x.data ?? [])
|
|
||||||
.slice()
|
|
||||||
.sort((a, b) => a.id.localeCompare(b.id))
|
|
||||||
.slice(0, 5)
|
|
||||||
setStore("session", sessions)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
Promise.all(
|
Promise.all(
|
||||||
store.projects.map((project) => {
|
store.projects.map((project) => {
|
||||||
return loadProjectSessions(project.worktree)
|
return globalSync.project.loadSessions(project.worktree)
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
@ -121,7 +105,7 @@ export const { use: useLayout, provider: LayoutProvider } = createSimpleContext(
|
||||||
list,
|
list,
|
||||||
open(directory: string) {
|
open(directory: string) {
|
||||||
if (store.projects.find((x) => x.worktree === directory)) return
|
if (store.projects.find((x) => x.worktree === directory)) return
|
||||||
loadProjectSessions(directory)
|
globalSync.project.loadSessions(directory)
|
||||||
setStore("projects", (x) => [{ worktree: directory, expanded: true }, ...x])
|
setStore("projects", (x) => [{ worktree: directory, expanded: true }, ...x])
|
||||||
},
|
},
|
||||||
close(directory: string) {
|
close(directory: string) {
|
||||||
|
|
|
||||||
106
packages/desktop/src/context/notification.tsx
Normal file
106
packages/desktop/src/context/notification.tsx
Normal file
|
|
@ -0,0 +1,106 @@
|
||||||
|
import { createStore } from "solid-js/store"
|
||||||
|
import { createSimpleContext } from "@opencode-ai/ui/context"
|
||||||
|
import { makePersisted } from "@solid-primitives/storage"
|
||||||
|
import { useGlobalSDK } from "./global-sdk"
|
||||||
|
import { EventSessionError } from "@opencode-ai/sdk/v2"
|
||||||
|
import { makeAudioPlayer } from "@solid-primitives/audio"
|
||||||
|
import idleSound from "@opencode-ai/ui/audio/staplebops-01.aac"
|
||||||
|
|
||||||
|
type NotificationBase = {
|
||||||
|
directory?: string
|
||||||
|
session?: string
|
||||||
|
metadata?: any
|
||||||
|
time: number
|
||||||
|
viewed: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
type TurnCompleteNotification = NotificationBase & {
|
||||||
|
type: "turn-complete"
|
||||||
|
}
|
||||||
|
|
||||||
|
type ErrorNotification = NotificationBase & {
|
||||||
|
type: "error"
|
||||||
|
error: EventSessionError["properties"]["error"]
|
||||||
|
}
|
||||||
|
|
||||||
|
export type Notification = TurnCompleteNotification | ErrorNotification
|
||||||
|
|
||||||
|
export const { use: useNotification, provider: NotificationProvider } = createSimpleContext({
|
||||||
|
name: "Notification",
|
||||||
|
init: () => {
|
||||||
|
const idlePlayer = makeAudioPlayer(idleSound)
|
||||||
|
const globalSDK = useGlobalSDK()
|
||||||
|
|
||||||
|
const [store, setStore] = makePersisted(
|
||||||
|
createStore({
|
||||||
|
list: [] as Notification[],
|
||||||
|
}),
|
||||||
|
{
|
||||||
|
name: "notification.v1",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
// onMount(() => {
|
||||||
|
// const daysToKeep = 7
|
||||||
|
// // setStore("list", (n) => n.filter((n) => !n.viewed && n.time + 1000 * 60 * 60 * 24 * daysToKeep < Date.now()))
|
||||||
|
// })
|
||||||
|
|
||||||
|
globalSDK.event.listen((e) => {
|
||||||
|
const directory = e.name
|
||||||
|
const event = e.details
|
||||||
|
const base = {
|
||||||
|
directory,
|
||||||
|
time: Date.now(),
|
||||||
|
viewed: false,
|
||||||
|
}
|
||||||
|
switch (event.type) {
|
||||||
|
case "session.idle": {
|
||||||
|
idlePlayer.play()
|
||||||
|
const session = event.properties.sessionID
|
||||||
|
setStore("list", store.list.length, {
|
||||||
|
...base,
|
||||||
|
type: "turn-complete",
|
||||||
|
session,
|
||||||
|
})
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case "session.error": {
|
||||||
|
const session = event.properties.sessionID ?? "global"
|
||||||
|
// errorPlayer.play()
|
||||||
|
setStore("list", store.list.length, {
|
||||||
|
...base,
|
||||||
|
type: "error",
|
||||||
|
session,
|
||||||
|
error: "error" in event.properties ? event.properties.error : undefined,
|
||||||
|
})
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return {
|
||||||
|
session: {
|
||||||
|
all(session: string) {
|
||||||
|
return store.list.filter((n) => n.session === session)
|
||||||
|
},
|
||||||
|
unseen(session: string) {
|
||||||
|
return store.list.filter((n) => n.session === session && !n.viewed)
|
||||||
|
},
|
||||||
|
markViewed(session: string) {
|
||||||
|
setStore("list", (n) => n.session === session, "viewed", true)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
project: {
|
||||||
|
all(directory: string) {
|
||||||
|
return store.list.filter((n) => n.directory === directory)
|
||||||
|
},
|
||||||
|
unseen(directory: string) {
|
||||||
|
return store.list.filter((n) => n.directory === directory && !n.viewed)
|
||||||
|
},
|
||||||
|
markViewed(directory: string) {
|
||||||
|
setStore("list", (n) => n.directory === directory, "viewed", true)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
@ -65,6 +65,15 @@ export const { use: useSync, provider: SyncProvider } = createSimpleContext({
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
more: createMemo(() => store.session.length >= store.limit),
|
more: createMemo(() => store.session.length >= store.limit),
|
||||||
|
archive: async (sessionID: string) => {
|
||||||
|
await sdk.client.session.update({ sessionID, time: { archived: Date.now() } })
|
||||||
|
setStore(
|
||||||
|
produce((draft) => {
|
||||||
|
const match = Binary.search(draft.session, sessionID, (s) => s.id)
|
||||||
|
if (match.found) draft.session.splice(match.index, 1)
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
},
|
||||||
},
|
},
|
||||||
absolute,
|
absolute,
|
||||||
get directory() {
|
get directory() {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { useGlobalSync } from "@/context/global-sync"
|
import { useGlobalSync } from "@/context/global-sync"
|
||||||
import { For, Match, Show, Switch } from "solid-js"
|
import { createMemo, For, Match, Show, Switch } from "solid-js"
|
||||||
import { Button } from "@opencode-ai/ui/button"
|
import { Button } from "@opencode-ai/ui/button"
|
||||||
import { Logo } from "@opencode-ai/ui/logo"
|
import { Logo } from "@opencode-ai/ui/logo"
|
||||||
import { useLayout } from "@/context/layout"
|
import { useLayout } from "@/context/layout"
|
||||||
|
|
@ -14,6 +14,7 @@ export default function Home() {
|
||||||
const layout = useLayout()
|
const layout = useLayout()
|
||||||
const platform = usePlatform()
|
const platform = usePlatform()
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
|
const homedir = createMemo(() => sync.data.path.home)
|
||||||
|
|
||||||
function openProject(directory: string) {
|
function openProject(directory: string) {
|
||||||
layout.projects.open(directory)
|
layout.projects.open(directory)
|
||||||
|
|
@ -61,7 +62,7 @@ export default function Home() {
|
||||||
class="text-14-mono text-left justify-between px-3"
|
class="text-14-mono text-left justify-between px-3"
|
||||||
onClick={() => openProject(project.worktree)}
|
onClick={() => openProject(project.worktree)}
|
||||||
>
|
>
|
||||||
{project.worktree}
|
{project.worktree.replace(homedir(), "~")}
|
||||||
<div class="text-14-regular text-text-weak">
|
<div class="text-14-regular text-text-weak">
|
||||||
{DateTime.fromMillis(project.time.updated ?? project.time.created).toRelative()}
|
{DateTime.fromMillis(project.time.updated ?? project.time.created).toRelative()}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,21 @@
|
||||||
import { createEffect, createMemo, For, Match, onCleanup, onMount, ParentProps, Show, Switch, type JSX } from "solid-js"
|
import {
|
||||||
|
createEffect,
|
||||||
|
createMemo,
|
||||||
|
createSignal,
|
||||||
|
For,
|
||||||
|
Match,
|
||||||
|
onCleanup,
|
||||||
|
onMount,
|
||||||
|
ParentProps,
|
||||||
|
Show,
|
||||||
|
Switch,
|
||||||
|
type JSX,
|
||||||
|
} from "solid-js"
|
||||||
import { DateTime } from "luxon"
|
import { DateTime } from "luxon"
|
||||||
import { A, useNavigate, useParams } from "@solidjs/router"
|
import { A, useNavigate, useParams } from "@solidjs/router"
|
||||||
import { useLayout, getAvatarColors } from "@/context/layout"
|
import { useLayout, getAvatarColors } from "@/context/layout"
|
||||||
import { useGlobalSync } from "@/context/global-sync"
|
import { useGlobalSync } from "@/context/global-sync"
|
||||||
import { base64Decode, base64Encode } from "@opencode-ai/util/encode"
|
import { base64Decode, base64Encode } from "@opencode-ai/util/encode"
|
||||||
import { Mark } from "@opencode-ai/ui/logo"
|
|
||||||
import { Avatar } from "@opencode-ai/ui/avatar"
|
import { Avatar } from "@opencode-ai/ui/avatar"
|
||||||
import { ResizeHandle } from "@opencode-ai/ui/resize-handle"
|
import { ResizeHandle } from "@opencode-ai/ui/resize-handle"
|
||||||
import { Button } from "@opencode-ai/ui/button"
|
import { Button } from "@opencode-ai/ui/button"
|
||||||
|
|
@ -15,7 +26,6 @@ import { Tooltip } from "@opencode-ai/ui/tooltip"
|
||||||
import { Collapsible } from "@opencode-ai/ui/collapsible"
|
import { Collapsible } from "@opencode-ai/ui/collapsible"
|
||||||
import { DiffChanges } from "@opencode-ai/ui/diff-changes"
|
import { DiffChanges } from "@opencode-ai/ui/diff-changes"
|
||||||
import { getFilename } from "@opencode-ai/util/path"
|
import { getFilename } from "@opencode-ai/util/path"
|
||||||
import { Select } from "@opencode-ai/ui/select"
|
|
||||||
import { DropdownMenu } from "@opencode-ai/ui/dropdown-menu"
|
import { DropdownMenu } from "@opencode-ai/ui/dropdown-menu"
|
||||||
import { Session, Project, ProviderAuthMethod, ProviderAuthAuthorization } from "@opencode-ai/sdk/v2/client"
|
import { Session, Project, ProviderAuthMethod, ProviderAuthAuthorization } from "@opencode-ai/sdk/v2/client"
|
||||||
import { usePlatform } from "@/context/platform"
|
import { usePlatform } from "@/context/platform"
|
||||||
|
|
@ -42,6 +52,9 @@ import { TextField } from "@opencode-ai/ui/text-field"
|
||||||
import { showToast, Toast } from "@opencode-ai/ui/toast"
|
import { showToast, Toast } from "@opencode-ai/ui/toast"
|
||||||
import { useGlobalSDK } from "@/context/global-sdk"
|
import { useGlobalSDK } from "@/context/global-sdk"
|
||||||
import { Spinner } from "@opencode-ai/ui/spinner"
|
import { Spinner } from "@opencode-ai/ui/spinner"
|
||||||
|
import { useNotification } from "@/context/notification"
|
||||||
|
import { Binary } from "@opencode-ai/util/binary"
|
||||||
|
import { Header } from "@/components/header"
|
||||||
|
|
||||||
export default function Layout(props: ParentProps) {
|
export default function Layout(props: ParentProps) {
|
||||||
const [store, setStore] = createStore({
|
const [store, setStore] = createStore({
|
||||||
|
|
@ -54,10 +67,8 @@ export default function Layout(props: ParentProps) {
|
||||||
const globalSync = useGlobalSync()
|
const globalSync = useGlobalSync()
|
||||||
const layout = useLayout()
|
const layout = useLayout()
|
||||||
const platform = usePlatform()
|
const platform = usePlatform()
|
||||||
|
const notification = useNotification()
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
const currentDirectory = createMemo(() => base64Decode(params.dir ?? ""))
|
|
||||||
const sessions = createMemo(() => globalSync.child(currentDirectory())[0].session ?? [])
|
|
||||||
const currentSession = createMemo(() => sessions().find((s) => s.id === params.id))
|
|
||||||
const providers = useProviders()
|
const providers = useProviders()
|
||||||
|
|
||||||
function navigateToProject(directory: string | undefined) {
|
function navigateToProject(directory: string | undefined) {
|
||||||
|
|
@ -77,9 +88,11 @@ export default function Layout(props: ParentProps) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function closeProject(directory: string) {
|
function closeProject(directory: string) {
|
||||||
|
const index = layout.projects.list().findIndex((x) => x.worktree === directory)
|
||||||
|
const next = layout.projects.list()[index + 1]
|
||||||
layout.projects.close(directory)
|
layout.projects.close(directory)
|
||||||
// TODO: more intelligent navigation
|
if (next) navigateToProject(next.worktree)
|
||||||
navigate("/")
|
else navigate("/")
|
||||||
}
|
}
|
||||||
|
|
||||||
async function chooseProject() {
|
async function chooseProject() {
|
||||||
|
|
@ -105,6 +118,7 @@ export default function Layout(props: ParentProps) {
|
||||||
if (!params.dir || !params.id) return
|
if (!params.dir || !params.id) return
|
||||||
const directory = base64Decode(params.dir)
|
const directory = base64Decode(params.dir)
|
||||||
setStore("lastSession", directory, params.id)
|
setStore("lastSession", directory, params.id)
|
||||||
|
notification.session.markViewed(params.id)
|
||||||
})
|
})
|
||||||
|
|
||||||
createEffect(() => {
|
createEffect(() => {
|
||||||
|
|
@ -164,8 +178,51 @@ export default function Layout(props: ParentProps) {
|
||||||
return <></>
|
return <></>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const ProjectAvatar = (props: {
|
||||||
|
project: Project
|
||||||
|
class?: string
|
||||||
|
expandable?: boolean
|
||||||
|
notify?: boolean
|
||||||
|
}): JSX.Element => {
|
||||||
|
const notification = useNotification()
|
||||||
|
const notifications = createMemo(() => notification.project.unseen(props.project.worktree))
|
||||||
|
const hasError = createMemo(() => notifications().some((n) => n.type === "error"))
|
||||||
|
const name = createMemo(() => getFilename(props.project.worktree))
|
||||||
|
const mask = "radial-gradient(circle 5px at calc(100% - 2px) 2px, transparent 5px, black 5.5px)"
|
||||||
|
return (
|
||||||
|
<div class="relative size-6 shrink-0">
|
||||||
|
<Avatar
|
||||||
|
fallback={name()}
|
||||||
|
src={props.project.icon?.url}
|
||||||
|
{...getAvatarColors(props.project.icon?.color)}
|
||||||
|
class={`size-full ${props.class ?? ""}`}
|
||||||
|
style={
|
||||||
|
notifications().length > 0 && props.notify ? { "-webkit-mask-image": mask, "mask-image": mask } : undefined
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<Show when={props.expandable}>
|
||||||
|
<Icon
|
||||||
|
name="chevron-right"
|
||||||
|
size="large"
|
||||||
|
class="hidden size-full items-center justify-center text-text-subtle group-hover/session:flex group-data-[expanded]/trigger:rotate-90 transition-transform duration-50"
|
||||||
|
/>
|
||||||
|
</Show>
|
||||||
|
<Show when={notifications().length > 0 && props.notify}>
|
||||||
|
<div
|
||||||
|
classList={{
|
||||||
|
"absolute -top-0.5 -right-0.5 size-1.5 rounded-full": true,
|
||||||
|
"bg-icon-critical-base": hasError(),
|
||||||
|
"bg-text-interactive-base": !hasError(),
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Show>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
const ProjectVisual = (props: { project: Project & { expanded: boolean }; class?: string }): JSX.Element => {
|
const ProjectVisual = (props: { project: Project & { expanded: boolean }; class?: string }): JSX.Element => {
|
||||||
const name = createMemo(() => getFilename(props.project.worktree))
|
const name = createMemo(() => getFilename(props.project.worktree))
|
||||||
|
const current = createMemo(() => base64Decode(params.dir ?? ""))
|
||||||
return (
|
return (
|
||||||
<Switch>
|
<Switch>
|
||||||
<Match when={layout.sidebar.opened()}>
|
<Match when={layout.sidebar.opened()}>
|
||||||
|
|
@ -176,14 +233,7 @@ export default function Layout(props: ParentProps) {
|
||||||
class="flex items-center justify-between gap-3 w-full px-1 self-stretch h-8 border-none rounded-lg"
|
class="flex items-center justify-between gap-3 w-full px-1 self-stretch h-8 border-none rounded-lg"
|
||||||
>
|
>
|
||||||
<div class="flex items-center gap-3 p-0 text-left min-w-0 grow">
|
<div class="flex items-center gap-3 p-0 text-left min-w-0 grow">
|
||||||
<div class="size-6 shrink-0">
|
<ProjectAvatar project={props.project} />
|
||||||
<Avatar
|
|
||||||
fallback={name()}
|
|
||||||
src={props.project.icon?.url}
|
|
||||||
{...getAvatarColors(props.project.icon?.color)}
|
|
||||||
class="size-full"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<span class="truncate text-14-medium text-text-strong">{name()}</span>
|
<span class="truncate text-14-medium text-text-strong">{name()}</span>
|
||||||
</div>
|
</div>
|
||||||
</Button>
|
</Button>
|
||||||
|
|
@ -193,17 +243,10 @@ export default function Layout(props: ParentProps) {
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
size="large"
|
size="large"
|
||||||
class="flex items-center justify-center p-0 aspect-square border-none rounded-lg"
|
class="flex items-center justify-center p-0 aspect-square border-none rounded-lg"
|
||||||
data-selected={props.project.worktree === currentDirectory()}
|
data-selected={props.project.worktree === current()}
|
||||||
onClick={() => navigateToProject(props.project.worktree)}
|
onClick={() => navigateToProject(props.project.worktree)}
|
||||||
>
|
>
|
||||||
<div class="size-6 shrink-0">
|
<ProjectAvatar project={props.project} notify />
|
||||||
<Avatar
|
|
||||||
fallback={name()}
|
|
||||||
src={props.project.icon?.url}
|
|
||||||
{...getAvatarColors(props.project.icon?.color)}
|
|
||||||
class="size-full"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</Button>
|
</Button>
|
||||||
</Match>
|
</Match>
|
||||||
</Switch>
|
</Switch>
|
||||||
|
|
@ -211,35 +254,31 @@ export default function Layout(props: ParentProps) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const SortableProject = (props: { project: Project & { expanded: boolean } }): JSX.Element => {
|
const SortableProject = (props: { project: Project & { expanded: boolean } }): JSX.Element => {
|
||||||
|
const notification = useNotification()
|
||||||
const sortable = createSortable(props.project.worktree)
|
const sortable = createSortable(props.project.worktree)
|
||||||
const [projectStore] = globalSync.child(props.project.worktree)
|
|
||||||
const slug = createMemo(() => base64Encode(props.project.worktree))
|
const slug = createMemo(() => base64Encode(props.project.worktree))
|
||||||
const name = createMemo(() => getFilename(props.project.worktree))
|
const name = createMemo(() => getFilename(props.project.worktree))
|
||||||
|
const [store, setStore] = globalSync.child(props.project.worktree)
|
||||||
|
const sessions = createMemo(() => store.session ?? [])
|
||||||
|
const [expanded, setExpanded] = createSignal(true)
|
||||||
return (
|
return (
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
<div use:sortable classList={{ "opacity-30": sortable.isActiveDraggable }}>
|
<div use:sortable classList={{ "opacity-30": sortable.isActiveDraggable }}>
|
||||||
<Switch>
|
<Switch>
|
||||||
<Match when={layout.sidebar.opened()}>
|
<Match when={layout.sidebar.opened()}>
|
||||||
<Collapsible variant="ghost" defaultOpen class="gap-2 shrink-0">
|
<Collapsible variant="ghost" defaultOpen class="gap-2 shrink-0" onOpenChange={setExpanded}>
|
||||||
<Button
|
<Button
|
||||||
as={"div"}
|
as={"div"}
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
class="group/session flex items-center justify-between gap-3 w-full px-1 self-stretch h-auto border-none rounded-lg"
|
class="group/session flex items-center justify-between gap-3 w-full px-1 self-stretch h-auto border-none rounded-lg"
|
||||||
>
|
>
|
||||||
<Collapsible.Trigger class="group/trigger flex items-center gap-3 p-0 text-left min-w-0 grow border-none">
|
<Collapsible.Trigger class="group/trigger flex items-center gap-3 p-0 text-left min-w-0 grow border-none">
|
||||||
<div class="size-6 shrink-0">
|
<ProjectAvatar
|
||||||
<Avatar
|
project={props.project}
|
||||||
fallback={name()}
|
class="group-hover/session:hidden"
|
||||||
src={props.project.icon?.url}
|
expandable
|
||||||
{...getAvatarColors(props.project.icon?.color)}
|
notify={!expanded()}
|
||||||
class="size-full group-hover/session:hidden"
|
/>
|
||||||
/>
|
|
||||||
<Icon
|
|
||||||
name="chevron-right"
|
|
||||||
size="large"
|
|
||||||
class="hidden size-full items-center justify-center text-text-subtle group-hover/session:flex group-data-[expanded]/trigger:rotate-90 transition-transform duration-50"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<span class="truncate text-14-medium text-text-strong">{name()}</span>
|
<span class="truncate text-14-medium text-text-strong">{name()}</span>
|
||||||
</Collapsible.Trigger>
|
</Collapsible.Trigger>
|
||||||
<div class="flex invisible gap-1 items-center group-hover/session:visible has-[[data-expanded]]:visible">
|
<div class="flex invisible gap-1 items-center group-hover/session:visible has-[[data-expanded]]:visible">
|
||||||
|
|
@ -260,50 +299,102 @@ export default function Layout(props: ParentProps) {
|
||||||
</Button>
|
</Button>
|
||||||
<Collapsible.Content>
|
<Collapsible.Content>
|
||||||
<nav class="hidden @[4rem]:flex w-full flex-col gap-1.5">
|
<nav class="hidden @[4rem]:flex w-full flex-col gap-1.5">
|
||||||
<For each={projectStore.session}>
|
<For each={sessions()}>
|
||||||
{(session) => {
|
{(session) => {
|
||||||
const updated = createMemo(() => DateTime.fromMillis(session.time.updated))
|
const updated = createMemo(() => DateTime.fromMillis(session.time.updated))
|
||||||
|
const notifications = createMemo(() => notification.session.unseen(session.id))
|
||||||
|
const hasError = createMemo(() => notifications().some((n) => n.type === "error"))
|
||||||
|
async function archive(session: Session) {
|
||||||
|
await globalSDK.client.session.update({
|
||||||
|
directory: session.directory,
|
||||||
|
sessionID: session.id,
|
||||||
|
time: { archived: Date.now() },
|
||||||
|
})
|
||||||
|
setStore(
|
||||||
|
produce((draft) => {
|
||||||
|
const match = Binary.search(draft.session, session.id, (s) => s.id)
|
||||||
|
if (match.found) draft.session.splice(match.index, 1)
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<A
|
<A
|
||||||
data-active={session.id === params.id}
|
|
||||||
href={`${slug()}/session/${session.id}`}
|
href={`${slug()}/session/${session.id}`}
|
||||||
class="group/session focus:outline-none cursor-default"
|
class="group/session focus:outline-none cursor-default"
|
||||||
>
|
>
|
||||||
<Tooltip placement="right" value={session.title}>
|
<Tooltip placement="right" value={session.title}>
|
||||||
<div
|
<div
|
||||||
class="w-full pl-4 pr-2 py-1 rounded-md
|
class="relative w-full pl-4 pr-1 py-1 rounded-md
|
||||||
group-data-[active=true]/session:bg-surface-raised-base-hover
|
group-[.active]/session:bg-surface-raised-base-hover
|
||||||
group-hover/session:bg-surface-raised-base-hover
|
group-hover/session:bg-surface-raised-base-hover
|
||||||
group-focus/session:bg-surface-raised-base-hover"
|
group-focus/session:bg-surface-raised-base-hover"
|
||||||
>
|
>
|
||||||
<div class="flex items-center self-stretch gap-6 justify-between">
|
<div class="flex items-center self-stretch gap-6 justify-between">
|
||||||
<span class="text-14-regular text-text-strong overflow-hidden text-ellipsis truncate">
|
<span class="text-14-regular text-text-strong overflow-hidden text-ellipsis truncate">
|
||||||
{session.title}
|
{session.title}
|
||||||
</span>
|
</span>
|
||||||
<span class="text-12-regular text-text-weak text-right whitespace-nowrap">
|
<div class="shrink-0 group-hover/session:hidden mr-1">
|
||||||
{Math.abs(updated().diffNow().as("seconds")) < 60
|
<Switch>
|
||||||
? "Now"
|
<Match when={hasError()}>
|
||||||
: updated()
|
<div class="size-1.5 mr-1.5 rounded-full bg-text-diff-delete-base" />
|
||||||
.toRelative({
|
</Match>
|
||||||
style: "short",
|
<Match when={notifications().length > 0}>
|
||||||
unit: ["days", "hours", "minutes"],
|
<div class="size-1.5 mr-1.5 rounded-full bg-text-interactive-base" />
|
||||||
})
|
</Match>
|
||||||
?.replace(" ago", "")
|
<Match when={true}>
|
||||||
?.replace(/ days?/, "d")
|
<span class="text-12-regular text-text-weak text-right whitespace-nowrap">
|
||||||
?.replace(" min.", "m")
|
{Math.abs(updated().diffNow().as("seconds")) < 60
|
||||||
?.replace(" hr.", "h")}
|
? "Now"
|
||||||
</span>
|
: updated()
|
||||||
</div>
|
.toRelative({
|
||||||
<div class="hidden _flex justify-between items-center self-stretch">
|
style: "short",
|
||||||
<span class="text-12-regular text-text-weak">{`${session.summary?.files || "No"} file${session.summary?.files !== 1 ? "s" : ""} changed`}</span>
|
unit: ["days", "hours", "minutes"],
|
||||||
<Show when={session.summary}>{(summary) => <DiffChanges changes={summary()} />}</Show>
|
})
|
||||||
|
?.replace(" ago", "")
|
||||||
|
?.replace(/ days?/, "d")
|
||||||
|
?.replace(" min.", "m")
|
||||||
|
?.replace(" hr.", "h")}
|
||||||
|
</span>
|
||||||
|
</Match>
|
||||||
|
</Switch>
|
||||||
|
</div>
|
||||||
|
<div class="hidden group-hover/session:flex group-active/session:flex text-text-base gap-1">
|
||||||
|
{/* <IconButton icon="dot-grid" variant="ghost" /> */}
|
||||||
|
<Tooltip placement="right" value="Archive session">
|
||||||
|
<IconButton icon="archive" variant="ghost" onClick={() => archive(session)} />
|
||||||
|
</Tooltip>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<Show when={session.summary?.files}>
|
||||||
|
<div class="flex justify-between items-center self-stretch">
|
||||||
|
<span class="text-12-regular text-text-weak">{`${session.summary?.files || "No"} file${session.summary?.files !== 1 ? "s" : ""} changed`}</span>
|
||||||
|
<Show when={session.summary}>{(summary) => <DiffChanges changes={summary()} />}</Show>
|
||||||
|
</div>
|
||||||
|
</Show>
|
||||||
</div>
|
</div>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</A>
|
</A>
|
||||||
)
|
)
|
||||||
}}
|
}}
|
||||||
</For>
|
</For>
|
||||||
|
<Show when={sessions().length === 0}>
|
||||||
|
<A href={`${slug()}/session`} class="group/session focus:outline-none cursor-default">
|
||||||
|
<Tooltip placement="right" value="New session">
|
||||||
|
<div
|
||||||
|
class="relative w-full pl-4 pr-1 py-1 rounded-md
|
||||||
|
group-[.active]/session:bg-surface-raised-base-hover
|
||||||
|
group-hover/session:bg-surface-raised-base-hover
|
||||||
|
group-focus/session:bg-surface-raised-base-hover"
|
||||||
|
>
|
||||||
|
<div class="flex items-center self-stretch gap-6 justify-between">
|
||||||
|
<span class="text-14-regular text-text-strong overflow-hidden text-ellipsis truncate">
|
||||||
|
New session
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Tooltip>
|
||||||
|
</A>
|
||||||
|
</Show>
|
||||||
</nav>
|
</nav>
|
||||||
</Collapsible.Content>
|
</Collapsible.Content>
|
||||||
</Collapsible>
|
</Collapsible>
|
||||||
|
|
@ -332,93 +423,9 @@ export default function Layout(props: ParentProps) {
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div class="relative h-screen flex flex-col">
|
<div class="relative flex-1 min-h-0 flex flex-col">
|
||||||
<header class="h-12 shrink-0 bg-background-base border-b border-border-weak-base flex" data-tauri-drag-region>
|
<Header navigateToProject={navigateToProject} navigateToSession={navigateToSession} />
|
||||||
<A
|
<div class="flex-1 min-h-0 flex">
|
||||||
href="/"
|
|
||||||
classList={{
|
|
||||||
"w-12 shrink-0 px-4 py-3.5": true,
|
|
||||||
"flex items-center justify-start self-stretch": true,
|
|
||||||
"border-r border-border-weak-base": true,
|
|
||||||
}}
|
|
||||||
style={{ width: layout.sidebar.opened() ? `${layout.sidebar.width()}px` : undefined }}
|
|
||||||
data-tauri-drag-region
|
|
||||||
>
|
|
||||||
<Mark class="shrink-0" />
|
|
||||||
</A>
|
|
||||||
<div class="pl-4 px-6 flex items-center justify-between gap-4 w-full">
|
|
||||||
<Show when={params.dir && layout.projects.list().length > 0}>
|
|
||||||
<div class="flex items-center gap-3">
|
|
||||||
<div class="flex items-center gap-2">
|
|
||||||
<Select
|
|
||||||
options={layout.projects.list().map((project) => project.worktree)}
|
|
||||||
current={currentDirectory()}
|
|
||||||
label={(x) => getFilename(x)}
|
|
||||||
onSelect={(x) => (x ? navigateToProject(x) : undefined)}
|
|
||||||
class="text-14-regular text-text-base"
|
|
||||||
variant="ghost"
|
|
||||||
>
|
|
||||||
{/* @ts-ignore */}
|
|
||||||
{(i) => (
|
|
||||||
<div class="flex items-center gap-2">
|
|
||||||
<Icon name="folder" size="small" />
|
|
||||||
<div class="text-text-strong">{getFilename(i)}</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</Select>
|
|
||||||
<div class="text-text-weaker">/</div>
|
|
||||||
<Select
|
|
||||||
options={sessions()}
|
|
||||||
current={currentSession()}
|
|
||||||
placeholder="New session"
|
|
||||||
label={(x) => x.title}
|
|
||||||
value={(x) => x.id}
|
|
||||||
onSelect={navigateToSession}
|
|
||||||
class="text-14-regular text-text-base max-w-md"
|
|
||||||
variant="ghost"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<Show when={currentSession()}>
|
|
||||||
<Button as={A} href={`/${params.dir}/session`} icon="plus-small">
|
|
||||||
New session
|
|
||||||
</Button>
|
|
||||||
</Show>
|
|
||||||
</div>
|
|
||||||
<div class="flex items-center gap-4">
|
|
||||||
<Tooltip
|
|
||||||
class="shrink-0"
|
|
||||||
value={
|
|
||||||
<div class="flex items-center gap-2">
|
|
||||||
<span>Toggle terminal</span>
|
|
||||||
<span class="text-icon-base text-12-medium">Ctrl `</span>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<Button variant="ghost" class="group/terminal-toggle size-6 p-0" onClick={layout.terminal.toggle}>
|
|
||||||
<div class="relative flex items-center justify-center size-4 [&>*]:absolute [&>*]:inset-0">
|
|
||||||
<Icon
|
|
||||||
size="small"
|
|
||||||
name={layout.terminal.opened() ? "layout-bottom-full" : "layout-bottom"}
|
|
||||||
class="group-hover/terminal-toggle:hidden"
|
|
||||||
/>
|
|
||||||
<Icon
|
|
||||||
size="small"
|
|
||||||
name="layout-bottom-partial"
|
|
||||||
class="hidden group-hover/terminal-toggle:inline-block"
|
|
||||||
/>
|
|
||||||
<Icon
|
|
||||||
size="small"
|
|
||||||
name={layout.terminal.opened() ? "layout-bottom" : "layout-bottom-full"}
|
|
||||||
class="hidden group-active/terminal-toggle:inline-block"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</Button>
|
|
||||||
</Tooltip>
|
|
||||||
</div>
|
|
||||||
</Show>
|
|
||||||
</div>
|
|
||||||
</header>
|
|
||||||
<div class="h-[calc(100vh-3rem)] flex">
|
|
||||||
<div
|
<div
|
||||||
classList={{
|
classList={{
|
||||||
"relative @container w-12 pb-5 shrink-0 bg-background-base": true,
|
"relative @container w-12 pb-5 shrink-0 bg-background-base": true,
|
||||||
|
|
@ -501,7 +508,7 @@ export default function Layout(props: ParentProps) {
|
||||||
<Button
|
<Button
|
||||||
class="flex w-full text-left justify-start text-12-medium text-text-strong stroke-[1.5px] rounded-lg rounded-t-none shadow-none border-t border-border-weak-base pl-2.25 pb-px"
|
class="flex w-full text-left justify-start text-12-medium text-text-strong stroke-[1.5px] rounded-lg rounded-t-none shadow-none border-t border-border-weak-base pl-2.25 pb-px"
|
||||||
size="large"
|
size="large"
|
||||||
icon="plus-small"
|
icon="plus"
|
||||||
onClick={connectProvider}
|
onClick={connectProvider}
|
||||||
>
|
>
|
||||||
<Show when={layout.sidebar.opened()}>Connect provider</Show>
|
<Show when={layout.sidebar.opened()}>Connect provider</Show>
|
||||||
|
|
@ -515,7 +522,7 @@ export default function Layout(props: ParentProps) {
|
||||||
class="flex w-full text-left justify-start text-12-medium text-text-base stroke-[1.5px] rounded-lg px-2"
|
class="flex w-full text-left justify-start text-12-medium text-text-base stroke-[1.5px] rounded-lg px-2"
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
size="large"
|
size="large"
|
||||||
icon="plus-small"
|
icon="plus"
|
||||||
onClick={connectProvider}
|
onClick={connectProvider}
|
||||||
>
|
>
|
||||||
<Show when={layout.sidebar.opened()}>Connect provider</Show>
|
<Show when={layout.sidebar.opened()}>Connect provider</Show>
|
||||||
|
|
|
||||||
|
|
@ -675,7 +675,7 @@ export default function Page() {
|
||||||
<For each={session.terminal.all()}>{(terminal) => <SortableTerminalTab terminal={terminal} />}</For>
|
<For each={session.terminal.all()}>{(terminal) => <SortableTerminalTab terminal={terminal} />}</For>
|
||||||
</SortableProvider>
|
</SortableProvider>
|
||||||
<div class="h-full flex items-center justify-center">
|
<div class="h-full flex items-center justify-center">
|
||||||
<Tooltip value="Open file" class="flex items-center">
|
<Tooltip value="New Terminal" class="flex items-center">
|
||||||
<IconButton icon="plus-small" variant="ghost" iconSize="large" onClick={session.terminal.new} />
|
<IconButton icon="plus-small" variant="ghost" iconSize="large" onClick={session.terminal.new} />
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
12
packages/enterprise/sst-env.d.ts
vendored
12
packages/enterprise/sst-env.d.ts
vendored
|
|
@ -50,10 +50,6 @@ declare module "sst" {
|
||||||
"type": "sst.sst.Secret"
|
"type": "sst.sst.Secret"
|
||||||
"value": string
|
"value": string
|
||||||
}
|
}
|
||||||
"Enterprise": {
|
|
||||||
"type": "sst.cloudflare.SolidStart"
|
|
||||||
"url": string
|
|
||||||
}
|
|
||||||
"GITHUB_APP_ID": {
|
"GITHUB_APP_ID": {
|
||||||
"type": "sst.sst.Secret"
|
"type": "sst.sst.Secret"
|
||||||
"value": string
|
"value": string
|
||||||
|
|
@ -94,6 +90,10 @@ declare module "sst" {
|
||||||
"type": "sst.sst.Linkable"
|
"type": "sst.sst.Linkable"
|
||||||
"value": string
|
"value": string
|
||||||
}
|
}
|
||||||
|
"Teams": {
|
||||||
|
"type": "sst.cloudflare.SolidStart"
|
||||||
|
"url": string
|
||||||
|
}
|
||||||
"Web": {
|
"Web": {
|
||||||
"type": "sst.cloudflare.Astro"
|
"type": "sst.cloudflare.Astro"
|
||||||
"url": string
|
"url": string
|
||||||
|
|
@ -114,6 +114,10 @@ declare module "sst" {
|
||||||
"type": "sst.sst.Secret"
|
"type": "sst.sst.Secret"
|
||||||
"value": string
|
"value": string
|
||||||
}
|
}
|
||||||
|
"ZEN_MODELS5": {
|
||||||
|
"type": "sst.sst.Secret"
|
||||||
|
"value": string
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// cloudflare
|
// cloudflare
|
||||||
|
|
|
||||||
12
packages/function/sst-env.d.ts
vendored
12
packages/function/sst-env.d.ts
vendored
|
|
@ -50,10 +50,6 @@ declare module "sst" {
|
||||||
"type": "sst.sst.Secret"
|
"type": "sst.sst.Secret"
|
||||||
"value": string
|
"value": string
|
||||||
}
|
}
|
||||||
"Enterprise": {
|
|
||||||
"type": "sst.cloudflare.SolidStart"
|
|
||||||
"url": string
|
|
||||||
}
|
|
||||||
"GITHUB_APP_ID": {
|
"GITHUB_APP_ID": {
|
||||||
"type": "sst.sst.Secret"
|
"type": "sst.sst.Secret"
|
||||||
"value": string
|
"value": string
|
||||||
|
|
@ -94,6 +90,10 @@ declare module "sst" {
|
||||||
"type": "sst.sst.Linkable"
|
"type": "sst.sst.Linkable"
|
||||||
"value": string
|
"value": string
|
||||||
}
|
}
|
||||||
|
"Teams": {
|
||||||
|
"type": "sst.cloudflare.SolidStart"
|
||||||
|
"url": string
|
||||||
|
}
|
||||||
"Web": {
|
"Web": {
|
||||||
"type": "sst.cloudflare.Astro"
|
"type": "sst.cloudflare.Astro"
|
||||||
"url": string
|
"url": string
|
||||||
|
|
@ -114,6 +114,10 @@ declare module "sst" {
|
||||||
"type": "sst.sst.Secret"
|
"type": "sst.sst.Secret"
|
||||||
"value": string
|
"value": string
|
||||||
}
|
}
|
||||||
|
"ZEN_MODELS5": {
|
||||||
|
"type": "sst.sst.Secret"
|
||||||
|
"value": string
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// cloudflare
|
// cloudflare
|
||||||
|
|
|
||||||
|
|
@ -914,6 +914,8 @@ export namespace ACP {
|
||||||
{
|
{
|
||||||
sessionID,
|
sessionID,
|
||||||
directory,
|
directory,
|
||||||
|
providerID: model.providerID,
|
||||||
|
modelID: model.modelID,
|
||||||
},
|
},
|
||||||
{ throwOnError: true },
|
{ throwOnError: true },
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ const DiagnosticsCommand = cmd({
|
||||||
async handler(args) {
|
async handler(args) {
|
||||||
await bootstrap(process.cwd(), async () => {
|
await bootstrap(process.cwd(), async () => {
|
||||||
await LSP.touchFile(args.file, true)
|
await LSP.touchFile(args.file, true)
|
||||||
|
await Bun.sleep(1000)
|
||||||
process.stdout.write(JSON.stringify(await LSP.diagnostics(), null, 2) + EOL)
|
process.stdout.write(JSON.stringify(await LSP.diagnostics(), null, 2) + EOL)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
import { Installation } from "@/installation"
|
|
||||||
import { TextAttributes } from "@opentui/core"
|
import { TextAttributes } from "@opentui/core"
|
||||||
import { For } from "solid-js"
|
import { For } from "solid-js"
|
||||||
import { useTheme } from "@tui/context/theme"
|
import { useTheme } from "@tui/context/theme"
|
||||||
|
|
@ -14,8 +13,10 @@ export function Logo() {
|
||||||
<For each={LOGO_LEFT}>
|
<For each={LOGO_LEFT}>
|
||||||
{(line, index) => (
|
{(line, index) => (
|
||||||
<box flexDirection="row" gap={1}>
|
<box flexDirection="row" gap={1}>
|
||||||
<text fg={theme.textMuted}>{line}</text>
|
<text fg={theme.textMuted} selectable={false}>
|
||||||
<text fg={theme.text} attributes={TextAttributes.BOLD}>
|
{line}
|
||||||
|
</text>
|
||||||
|
<text fg={theme.text} attributes={TextAttributes.BOLD} selectable={false}>
|
||||||
{LOGO_RIGHT[index()]}
|
{LOGO_RIGHT[index()]}
|
||||||
</text>
|
</text>
|
||||||
</box>
|
</box>
|
||||||
|
|
|
||||||
|
|
@ -61,7 +61,7 @@ export namespace Clipboard {
|
||||||
const getCopyMethod = lazy(() => {
|
const getCopyMethod = lazy(() => {
|
||||||
const os = platform()
|
const os = platform()
|
||||||
|
|
||||||
if (os === "darwin" && Bun.which("oascript")) {
|
if (os === "darwin" && Bun.which("osascript")) {
|
||||||
console.log("clipboard: using osascript")
|
console.log("clipboard: using osascript")
|
||||||
return async (text: string) => {
|
return async (text: string) => {
|
||||||
const escaped = text.replace(/\\/g, "\\\\").replace(/"/g, '\\"')
|
const escaped = text.replace(/\\/g, "\\\\").replace(/"/g, '\\"')
|
||||||
|
|
|
||||||
|
|
@ -272,7 +272,7 @@ export namespace ProviderTransform {
|
||||||
const options: Record<string, any> = {}
|
const options: Record<string, any> = {}
|
||||||
|
|
||||||
if (model.providerID === "openai" || model.api.id.includes("gpt-5")) {
|
if (model.providerID === "openai" || model.api.id.includes("gpt-5")) {
|
||||||
if (model.api.id.includes("5.1")) {
|
if (model.api.id.includes("5.")) {
|
||||||
options["reasoningEffort"] = "low"
|
options["reasoningEffort"] = "low"
|
||||||
} else {
|
} else {
|
||||||
options["reasoningEffort"] = "minimal"
|
options["reasoningEffort"] = "minimal"
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@
|
||||||
<meta property="og:image" content="/social-share.png" />
|
<meta property="og:image" content="/social-share.png" />
|
||||||
<meta property="twitter:image" content="/social-share.png" />
|
<meta property="twitter:image" content="/social-share.png" />
|
||||||
</head>
|
</head>
|
||||||
<body class="antialiased overscroll-none select-none text-12-regular">
|
<body class="antialiased overscroll-none select-none text-12-regular overflow-hidden">
|
||||||
<script>
|
<script>
|
||||||
;(function () {
|
;(function () {
|
||||||
const savedTheme = localStorage.getItem("theme") || "oc-1"
|
const savedTheme = localStorage.getItem("theme") || "oc-1"
|
||||||
|
|
@ -22,7 +22,7 @@
|
||||||
})()
|
})()
|
||||||
</script>
|
</script>
|
||||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||||
<div id="root"></div>
|
<div id="root" class="flex flex-col h-screen"></div>
|
||||||
<script src="/src/index.tsx" type="module"></script>
|
<script src="/src/index.tsx" type="module"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
||||||
|
|
@ -16,9 +16,12 @@
|
||||||
"@tauri-apps/api": "^2",
|
"@tauri-apps/api": "^2",
|
||||||
"@tauri-apps/plugin-dialog": "~2",
|
"@tauri-apps/plugin-dialog": "~2",
|
||||||
"@tauri-apps/plugin-opener": "^2",
|
"@tauri-apps/plugin-opener": "^2",
|
||||||
|
"@tauri-apps/plugin-os": "~2",
|
||||||
"@tauri-apps/plugin-process": "~2",
|
"@tauri-apps/plugin-process": "~2",
|
||||||
"@tauri-apps/plugin-shell": "~2",
|
"@tauri-apps/plugin-shell": "~2",
|
||||||
|
"@tauri-apps/plugin-store": "~2",
|
||||||
"@tauri-apps/plugin-updater": "~2",
|
"@tauri-apps/plugin-updater": "~2",
|
||||||
|
"@tauri-apps/plugin-window-state": "~2",
|
||||||
"solid-js": "catalog:"
|
"solid-js": "catalog:"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|
|
||||||
129
packages/tauri/src-tauri/Cargo.lock
generated
129
packages/tauri/src-tauri/Cargo.lock
generated
|
|
@ -1256,6 +1256,16 @@ dependencies = [
|
||||||
"version_check",
|
"version_check",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "gethostname"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1bd49230192a3797a9a4d6abe9b3eed6f7fa4c8a8a4947977c6f80025f92cbd8"
|
||||||
|
dependencies = [
|
||||||
|
"rustix",
|
||||||
|
"windows-link 0.2.1",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "getrandom"
|
name = "getrandom"
|
||||||
version = "0.1.16"
|
version = "0.1.16"
|
||||||
|
|
@ -2309,6 +2319,16 @@ dependencies = [
|
||||||
"objc2-foundation 0.3.2",
|
"objc2-foundation 0.3.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "objc2-core-location"
|
||||||
|
version = "0.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ca347214e24bc973fc025fd0d36ebb179ff30536ed1f80252706db19ee452009"
|
||||||
|
dependencies = [
|
||||||
|
"objc2 0.6.3",
|
||||||
|
"objc2-foundation 0.3.2",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "objc2-core-text"
|
name = "objc2-core-text"
|
||||||
version = "0.3.2"
|
version = "0.3.2"
|
||||||
|
|
@ -2440,6 +2460,7 @@ checksum = "96c1358452b371bf9f104e21ec536d37a650eb10f7ee379fff67d2e08d537f1f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.10.0",
|
"bitflags 2.10.0",
|
||||||
"objc2 0.6.3",
|
"objc2 0.6.3",
|
||||||
|
"objc2-core-foundation",
|
||||||
"objc2-foundation 0.3.2",
|
"objc2-foundation 0.3.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
@ -2461,8 +2482,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d87d638e33c06f577498cbcc50491496a3ed4246998a7fbba7ccb98b1e7eab22"
|
checksum = "d87d638e33c06f577498cbcc50491496a3ed4246998a7fbba7ccb98b1e7eab22"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.10.0",
|
"bitflags 2.10.0",
|
||||||
|
"block2 0.6.2",
|
||||||
"objc2 0.6.3",
|
"objc2 0.6.3",
|
||||||
|
"objc2-cloud-kit",
|
||||||
|
"objc2-core-data",
|
||||||
"objc2-core-foundation",
|
"objc2-core-foundation",
|
||||||
|
"objc2-core-graphics",
|
||||||
|
"objc2-core-image",
|
||||||
|
"objc2-core-location",
|
||||||
|
"objc2-core-text",
|
||||||
|
"objc2-foundation 0.3.2",
|
||||||
|
"objc2-quartz-core 0.3.2",
|
||||||
|
"objc2-user-notifications",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "objc2-user-notifications"
|
||||||
|
version = "0.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9df9128cbbfef73cda168416ccf7f837b62737d748333bfe9ab71c245d76613e"
|
||||||
|
dependencies = [
|
||||||
|
"objc2 0.6.3",
|
||||||
"objc2-foundation 0.3.2",
|
"objc2-foundation 0.3.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
@ -2511,9 +2551,12 @@ dependencies = [
|
||||||
"tauri-build",
|
"tauri-build",
|
||||||
"tauri-plugin-dialog",
|
"tauri-plugin-dialog",
|
||||||
"tauri-plugin-opener",
|
"tauri-plugin-opener",
|
||||||
|
"tauri-plugin-os",
|
||||||
"tauri-plugin-process",
|
"tauri-plugin-process",
|
||||||
"tauri-plugin-shell",
|
"tauri-plugin-shell",
|
||||||
|
"tauri-plugin-store",
|
||||||
"tauri-plugin-updater",
|
"tauri-plugin-updater",
|
||||||
|
"tauri-plugin-window-state",
|
||||||
"tokio",
|
"tokio",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
@ -2533,6 +2576,22 @@ dependencies = [
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "os_info"
|
||||||
|
version = "3.13.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7c39b5918402d564846d5aba164c09a66cc88d232179dfd3e3c619a25a268392"
|
||||||
|
dependencies = [
|
||||||
|
"android_system_properties",
|
||||||
|
"log",
|
||||||
|
"nix",
|
||||||
|
"objc2 0.6.3",
|
||||||
|
"objc2-foundation 0.3.2",
|
||||||
|
"objc2-ui-kit",
|
||||||
|
"serde",
|
||||||
|
"windows-sys 0.61.2",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "os_pipe"
|
name = "os_pipe"
|
||||||
version = "1.2.3"
|
version = "1.2.3"
|
||||||
|
|
@ -3870,6 +3929,15 @@ dependencies = [
|
||||||
"syn 2.0.110",
|
"syn 2.0.110",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sys-locale"
|
||||||
|
version = "0.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8eab9a99a024a169fe8a903cf9d4a3b3601109bcc13bd9e3c6fff259138626c4"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "system-deps"
|
name = "system-deps"
|
||||||
version = "6.2.2"
|
version = "6.2.2"
|
||||||
|
|
@ -4144,6 +4212,24 @@ dependencies = [
|
||||||
"zbus",
|
"zbus",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tauri-plugin-os"
|
||||||
|
version = "2.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d8f08346c8deb39e96f86973da0e2d76cbb933d7ac9b750f6dc4daf955a6f997"
|
||||||
|
dependencies = [
|
||||||
|
"gethostname",
|
||||||
|
"log",
|
||||||
|
"os_info",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
"serialize-to-javascript",
|
||||||
|
"sys-locale",
|
||||||
|
"tauri",
|
||||||
|
"tauri-plugin",
|
||||||
|
"thiserror 2.0.17",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tauri-plugin-process"
|
name = "tauri-plugin-process"
|
||||||
version = "2.3.1"
|
version = "2.3.1"
|
||||||
|
|
@ -4175,6 +4261,22 @@ dependencies = [
|
||||||
"tokio",
|
"tokio",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tauri-plugin-store"
|
||||||
|
version = "2.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "59a77036340a97eb5bbe1b3209c31e5f27f75e6f92a52fd9dd4b211ef08bf310"
|
||||||
|
dependencies = [
|
||||||
|
"dunce",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
"tauri",
|
||||||
|
"tauri-plugin",
|
||||||
|
"thiserror 2.0.17",
|
||||||
|
"tokio",
|
||||||
|
"tracing",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tauri-plugin-updater"
|
name = "tauri-plugin-updater"
|
||||||
version = "2.9.0"
|
version = "2.9.0"
|
||||||
|
|
@ -4207,6 +4309,21 @@ dependencies = [
|
||||||
"zip",
|
"zip",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tauri-plugin-window-state"
|
||||||
|
version = "2.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "73736611e14142408d15353e21e3cca2f12a3cfb523ad0ce85999b6d2ef1a704"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 2.10.0",
|
||||||
|
"log",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
"tauri",
|
||||||
|
"tauri-plugin",
|
||||||
|
"thiserror 2.0.17",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tauri-runtime"
|
name = "tauri-runtime"
|
||||||
version = "2.9.1"
|
version = "2.9.1"
|
||||||
|
|
@ -4440,10 +4557,22 @@ dependencies = [
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
"signal-hook-registry",
|
"signal-hook-registry",
|
||||||
"socket2",
|
"socket2",
|
||||||
|
"tokio-macros",
|
||||||
"tracing",
|
"tracing",
|
||||||
"windows-sys 0.61.2",
|
"windows-sys 0.61.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tokio-macros"
|
||||||
|
version = "2.6.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.110",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tokio-rustls"
|
name = "tokio-rustls"
|
||||||
version = "0.26.4"
|
version = "0.26.4"
|
||||||
|
|
|
||||||
|
|
@ -23,9 +23,12 @@ tauri-plugin-opener = "2"
|
||||||
tauri-plugin-shell = "2"
|
tauri-plugin-shell = "2"
|
||||||
tauri-plugin-dialog = "2"
|
tauri-plugin-dialog = "2"
|
||||||
tauri-plugin-updater = "2"
|
tauri-plugin-updater = "2"
|
||||||
|
tauri-plugin-process = "2"
|
||||||
|
tauri-plugin-store = "2"
|
||||||
|
tauri-plugin-window-state = "2"
|
||||||
|
|
||||||
serde = { version = "1", features = ["derive"] }
|
serde = { version = "1", features = ["derive"] }
|
||||||
serde_json = "1"
|
serde_json = "1"
|
||||||
tokio = "1.48.0"
|
tokio = "1.48.0"
|
||||||
listeners = "0.3"
|
listeners = "0.3"
|
||||||
tauri-plugin-process = "2"
|
tauri-plugin-os = "2"
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,9 @@
|
||||||
"shell:default",
|
"shell:default",
|
||||||
"updater:default",
|
"updater:default",
|
||||||
"dialog:default",
|
"dialog:default",
|
||||||
"process:default"
|
"process:default",
|
||||||
|
"store:default",
|
||||||
|
"window-state:default",
|
||||||
|
"os:default"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,9 @@ use std::{
|
||||||
sync::{Arc, Mutex},
|
sync::{Arc, Mutex},
|
||||||
time::{Duration, Instant},
|
time::{Duration, Instant},
|
||||||
};
|
};
|
||||||
use tauri::{AppHandle, Manager, RunEvent, WebviewUrl, WebviewWindow};
|
use tauri::{
|
||||||
|
AppHandle, LogicalSize, Manager, Monitor, RunEvent, TitleBarStyle, WebviewUrl, WebviewWindow,
|
||||||
|
};
|
||||||
use tauri_plugin_dialog::{DialogExt, MessageDialogButtons, MessageDialogResult};
|
use tauri_plugin_dialog::{DialogExt, MessageDialogButtons, MessageDialogResult};
|
||||||
use tauri_plugin_shell::process::{CommandChild, CommandEvent};
|
use tauri_plugin_shell::process::{CommandChild, CommandEvent};
|
||||||
use tauri_plugin_shell::ShellExt;
|
use tauri_plugin_shell::ShellExt;
|
||||||
|
|
@ -107,6 +109,9 @@ pub fn run() {
|
||||||
let updater_enabled = option_env!("TAURI_SIGNING_PRIVATE_KEY").is_some();
|
let updater_enabled = option_env!("TAURI_SIGNING_PRIVATE_KEY").is_some();
|
||||||
|
|
||||||
let mut builder = tauri::Builder::default()
|
let mut builder = tauri::Builder::default()
|
||||||
|
.plugin(tauri_plugin_os::init())
|
||||||
|
.plugin(tauri_plugin_window_state::Builder::new().build())
|
||||||
|
.plugin(tauri_plugin_store::Builder::new().build())
|
||||||
.plugin(tauri_plugin_dialog::init())
|
.plugin(tauri_plugin_dialog::init())
|
||||||
.plugin(tauri_plugin_shell::init())
|
.plugin(tauri_plugin_shell::init())
|
||||||
.plugin(tauri_plugin_process::init())
|
.plugin(tauri_plugin_process::init())
|
||||||
|
|
@ -167,12 +172,18 @@ pub fn run() {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let primary_monitor = app.primary_monitor().ok().flatten();
|
||||||
|
let size = primary_monitor
|
||||||
|
.map(|m| m.size().to_logical(m.scale_factor()))
|
||||||
|
.unwrap_or(LogicalSize::new(1920, 1080));
|
||||||
|
|
||||||
let mut window_builder =
|
let mut window_builder =
|
||||||
WebviewWindow::builder(&app, "main", WebviewUrl::App("/".into()))
|
WebviewWindow::builder(&app, "main", WebviewUrl::App("/".into()))
|
||||||
.title("OpenCode")
|
.title("OpenCode")
|
||||||
.inner_size(800.0, 600.0)
|
.inner_size(size.width as f64, size.height as f64)
|
||||||
.decorations(true)
|
.decorations(true)
|
||||||
.zoom_hotkeys_enabled(true)
|
.zoom_hotkeys_enabled(true)
|
||||||
|
.title_bar_style(TitleBarStyle::Overlay)
|
||||||
.initialization_script(format!(
|
.initialization_script(format!(
|
||||||
r#"
|
r#"
|
||||||
window.__OPENCODE__ ??= {{}};
|
window.__OPENCODE__ ??= {{}};
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import { runUpdater } from "./updater"
|
||||||
import { onMount } from "solid-js"
|
import { onMount } from "solid-js"
|
||||||
import { open, save } from "@tauri-apps/plugin-dialog"
|
import { open, save } from "@tauri-apps/plugin-dialog"
|
||||||
import { open as shellOpen } from "@tauri-apps/plugin-shell"
|
import { open as shellOpen } from "@tauri-apps/plugin-shell"
|
||||||
|
import { type as ostype } from "@tauri-apps/plugin-os"
|
||||||
|
|
||||||
const root = document.getElementById("root")
|
const root = document.getElementById("root")
|
||||||
if (import.meta.env.DEV && !(root instanceof HTMLElement)) {
|
if (import.meta.env.DEV && !(root instanceof HTMLElement)) {
|
||||||
|
|
@ -54,6 +55,9 @@ render(() => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PlatformProvider value={platform}>
|
<PlatformProvider value={platform}>
|
||||||
|
{ostype() === "macos" && (
|
||||||
|
<div class="bg-background-base border-b border-border-weak-base h-8" data-tauri-drag-region />
|
||||||
|
)}
|
||||||
<App />
|
<App />
|
||||||
</PlatformProvider>
|
</PlatformProvider>
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,8 @@
|
||||||
"./styles/tailwind": "./src/styles/tailwind/index.css",
|
"./styles/tailwind": "./src/styles/tailwind/index.css",
|
||||||
"./icons/provider": "./src/components/provider-icons/types.ts",
|
"./icons/provider": "./src/components/provider-icons/types.ts",
|
||||||
"./icons/file-type": "./src/components/file-icons/types.ts",
|
"./icons/file-type": "./src/components/file-icons/types.ts",
|
||||||
"./fonts/*": "./src/assets/fonts/*"
|
"./fonts/*": "./src/assets/fonts/*",
|
||||||
|
"./audio/*": "./src/assets/audio/*"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"typecheck": "tsgo --noEmit",
|
"typecheck": "tsgo --noEmit",
|
||||||
|
|
|
||||||
BIN
packages/ui/src/assets/audio/staplebops-01.aac
Normal file
BIN
packages/ui/src/assets/audio/staplebops-01.aac
Normal file
Binary file not shown.
BIN
packages/ui/src/assets/audio/staplebops-02.aac
Normal file
BIN
packages/ui/src/assets/audio/staplebops-02.aac
Normal file
Binary file not shown.
BIN
packages/ui/src/assets/audio/staplebops-03.aac
Normal file
BIN
packages/ui/src/assets/audio/staplebops-03.aac
Normal file
Binary file not shown.
BIN
packages/ui/src/assets/audio/staplebops-04.aac
Normal file
BIN
packages/ui/src/assets/audio/staplebops-04.aac
Normal file
Binary file not shown.
BIN
packages/ui/src/assets/audio/staplebops-05.aac
Normal file
BIN
packages/ui/src/assets/audio/staplebops-05.aac
Normal file
Binary file not shown.
BIN
packages/ui/src/assets/audio/staplebops-06.aac
Normal file
BIN
packages/ui/src/assets/audio/staplebops-06.aac
Normal file
Binary file not shown.
BIN
packages/ui/src/assets/audio/staplebops-07.aac
Normal file
BIN
packages/ui/src/assets/audio/staplebops-07.aac
Normal file
Binary file not shown.
|
|
@ -4,6 +4,7 @@ const icons = {
|
||||||
"align-right": `<path d="M12.292 6.04167L16.2503 9.99998L12.292 13.9583M2.91699 9.99998H15.6253M17.0837 3.75V16.25" stroke="currentColor" stroke-linecap="square"/>`,
|
"align-right": `<path d="M12.292 6.04167L16.2503 9.99998L12.292 13.9583M2.91699 9.99998H15.6253M17.0837 3.75V16.25" stroke="currentColor" stroke-linecap="square"/>`,
|
||||||
"arrow-up": `<path fill-rule="evenodd" clip-rule="evenodd" d="M9.99991 2.24121L16.0921 8.33343L15.2083 9.21731L10.6249 4.63397V17.5001H9.37492V4.63398L4.7916 9.21731L3.90771 8.33343L9.99991 2.24121Z" fill="currentColor"/>`,
|
"arrow-up": `<path fill-rule="evenodd" clip-rule="evenodd" d="M9.99991 2.24121L16.0921 8.33343L15.2083 9.21731L10.6249 4.63397V17.5001H9.37492V4.63398L4.7916 9.21731L3.90771 8.33343L9.99991 2.24121Z" fill="currentColor"/>`,
|
||||||
"arrow-left": `<path d="M8.33464 4.58398L2.91797 10.0007L8.33464 15.4173M3.33464 10.0007H17.0846" stroke="currentColor" stroke-linecap="square"/>`,
|
"arrow-left": `<path d="M8.33464 4.58398L2.91797 10.0007L8.33464 15.4173M3.33464 10.0007H17.0846" stroke="currentColor" stroke-linecap="square"/>`,
|
||||||
|
archive: `<path d="M16.8747 6.24935H17.3747V5.74935H16.8747V6.24935ZM16.8747 16.8743V17.3743H17.3747V16.8743H16.8747ZM3.12467 16.8743H2.62467V17.3743H3.12467V16.8743ZM3.12467 6.24935V5.74935H2.62467V6.24935H3.12467ZM2.08301 2.91602V2.41602H1.58301V2.91602H2.08301ZM17.9163 2.91602H18.4163V2.41602H17.9163V2.91602ZM17.9163 6.24935V6.74935H18.4163V6.24935H17.9163ZM2.08301 6.24935H1.58301V6.74935H2.08301V6.24935ZM8.33301 9.08268H7.83301V10.0827H8.33301V9.58268V9.08268ZM11.6663 10.0827H12.1663V9.08268H11.6663V9.58268V10.0827ZM16.8747 6.24935H16.3747V16.8743H16.8747H17.3747V6.24935H16.8747ZM16.8747 16.8743V16.3743H3.12467V16.8743V17.3743H16.8747V16.8743ZM3.12467 16.8743H3.62467V6.24935H3.12467H2.62467V16.8743H3.12467ZM3.12467 6.24935V6.74935H16.8747V6.24935V5.74935H3.12467V6.24935ZM2.08301 2.91602V3.41602H17.9163V2.91602V2.41602H2.08301V2.91602ZM17.9163 2.91602H17.4163V6.24935H17.9163H18.4163V2.91602H17.9163ZM17.9163 6.24935V5.74935H2.08301V6.24935V6.74935H17.9163V6.24935ZM2.08301 6.24935H2.58301V2.91602H2.08301H1.58301V6.24935H2.08301ZM8.33301 9.58268V10.0827H11.6663V9.58268V9.08268H8.33301V9.58268Z" fill="currentColor"/>`,
|
||||||
"bubble-5": `<path d="M18.3327 9.99935C18.3327 5.57227 15.0919 2.91602 9.99935 2.91602C4.90676 2.91602 1.66602 5.57227 1.66602 9.99935C1.66602 11.1487 2.45505 13.1006 2.57637 13.3939C2.58707 13.4197 2.59766 13.4434 2.60729 13.4697C2.69121 13.6987 3.04209 14.9354 1.66602 16.7674C3.51787 17.6528 5.48453 16.1973 5.48453 16.1973C6.84518 16.9193 8.46417 17.0827 9.99935 17.0827C15.0919 17.0827 18.3327 14.4264 18.3327 9.99935Z" stroke="currentColor" stroke-linecap="square"/>`,
|
"bubble-5": `<path d="M18.3327 9.99935C18.3327 5.57227 15.0919 2.91602 9.99935 2.91602C4.90676 2.91602 1.66602 5.57227 1.66602 9.99935C1.66602 11.1487 2.45505 13.1006 2.57637 13.3939C2.58707 13.4197 2.59766 13.4434 2.60729 13.4697C2.69121 13.6987 3.04209 14.9354 1.66602 16.7674C3.51787 17.6528 5.48453 16.1973 5.48453 16.1973C6.84518 16.9193 8.46417 17.0827 9.99935 17.0827C15.0919 17.0827 18.3327 14.4264 18.3327 9.99935Z" stroke="currentColor" stroke-linecap="square"/>`,
|
||||||
"bullet-list": `<path d="M9.58329 13.7497H17.0833M9.58329 6.24967H17.0833M6.24996 6.24967C6.24996 7.17015 5.50377 7.91634 4.58329 7.91634C3.66282 7.91634 2.91663 7.17015 2.91663 6.24967C2.91663 5.3292 3.66282 4.58301 4.58329 4.58301C5.50377 4.58301 6.24996 5.3292 6.24996 6.24967ZM6.24996 13.7497C6.24996 14.6701 5.50377 15.4163 4.58329 15.4163C3.66282 15.4163 2.91663 14.6701 2.91663 13.7497C2.91663 12.8292 3.66282 12.083 4.58329 12.083C5.50377 12.083 6.24996 12.8292 6.24996 13.7497Z" stroke="currentColor" stroke-linecap="square"/>`,
|
"bullet-list": `<path d="M9.58329 13.7497H17.0833M9.58329 6.24967H17.0833M6.24996 6.24967C6.24996 7.17015 5.50377 7.91634 4.58329 7.91634C3.66282 7.91634 2.91663 7.17015 2.91663 6.24967C2.91663 5.3292 3.66282 4.58301 4.58329 4.58301C5.50377 4.58301 6.24996 5.3292 6.24996 6.24967ZM6.24996 13.7497C6.24996 14.6701 5.50377 15.4163 4.58329 15.4163C3.66282 15.4163 2.91663 14.6701 2.91663 13.7497C2.91663 12.8292 3.66282 12.083 4.58329 12.083C5.50377 12.083 6.24996 12.8292 6.24996 13.7497Z" stroke="currentColor" stroke-linecap="square"/>`,
|
||||||
"check-small": `<path d="M6.5 11.4412L8.97059 13.5L13.5 6.5" stroke="currentColor" stroke-linecap="square"/>`,
|
"check-small": `<path d="M6.5 11.4412L8.97059 13.5L13.5 6.5" stroke="currentColor" stroke-linecap="square"/>`,
|
||||||
|
|
@ -23,6 +24,7 @@ const icons = {
|
||||||
folder: `<path d="M2.08301 2.91675V16.2501H17.9163V5.41675H9.99967L8.33301 2.91675H2.08301Z" stroke="currentColor" stroke-linecap="round"/>`,
|
folder: `<path d="M2.08301 2.91675V16.2501H17.9163V5.41675H9.99967L8.33301 2.91675H2.08301Z" stroke="currentColor" stroke-linecap="round"/>`,
|
||||||
"magnifying-glass": `<path d="M15.8332 15.8337L13.0819 13.0824M14.6143 9.39088C14.6143 12.2759 12.2755 14.6148 9.39039 14.6148C6.50532 14.6148 4.1665 12.2759 4.1665 9.39088C4.1665 6.5058 6.50532 4.16699 9.39039 4.16699C12.2755 4.16699 14.6143 6.5058 14.6143 9.39088Z" stroke="currentColor" stroke-linecap="square"/>`,
|
"magnifying-glass": `<path d="M15.8332 15.8337L13.0819 13.0824M14.6143 9.39088C14.6143 12.2759 12.2755 14.6148 9.39039 14.6148C6.50532 14.6148 4.1665 12.2759 4.1665 9.39088C4.1665 6.5058 6.50532 4.16699 9.39039 4.16699C12.2755 4.16699 14.6143 6.5058 14.6143 9.39088Z" stroke="currentColor" stroke-linecap="square"/>`,
|
||||||
"plus-small": `<path d="M9.99984 5.41699V10.0003M9.99984 10.0003V14.5837M9.99984 10.0003H5.4165M9.99984 10.0003H14.5832" stroke="currentColor" stroke-linecap="square"/>`,
|
"plus-small": `<path d="M9.99984 5.41699V10.0003M9.99984 10.0003V14.5837M9.99984 10.0003H5.4165M9.99984 10.0003H14.5832" stroke="currentColor" stroke-linecap="square"/>`,
|
||||||
|
plus: `<path d="M9.9987 2.20703V9.9987M9.9987 9.9987V17.7904M9.9987 9.9987H2.20703M9.9987 9.9987H17.7904" stroke="currentColor" stroke-linecap="square"/>`,
|
||||||
"pencil-line": `<path d="M9.58301 17.9166H17.9163M17.9163 5.83325L14.1663 2.08325L2.08301 14.1666V17.9166H5.83301L17.9163 5.83325Z" stroke="currentColor" stroke-linecap="square"/>`,
|
"pencil-line": `<path d="M9.58301 17.9166H17.9163M17.9163 5.83325L14.1663 2.08325L2.08301 14.1666V17.9166H5.83301L17.9163 5.83325Z" stroke="currentColor" stroke-linecap="square"/>`,
|
||||||
mcp: `<g><path d="M0.972656 9.37176L9.5214 1.60019C10.7018 0.527151 12.6155 0.527151 13.7957 1.60019C14.9761 2.67321 14.9761 4.41295 13.7957 5.48599L7.3397 11.3552" stroke="currentColor" stroke-linecap="round"/><path d="M7.42871 11.2747L13.7957 5.48643C14.9761 4.41338 16.8898 4.41338 18.0702 5.48643L18.1147 5.52688C19.2951 6.59993 19.2951 8.33966 18.1147 9.4127L10.3831 16.4414C9.98966 16.7991 9.98966 17.379 10.3831 17.7366L11.9707 19.1799" stroke="currentColor" stroke-linecap="round"/><path d="M11.6587 3.54346L5.33619 9.29119C4.15584 10.3642 4.15584 12.1039 5.33619 13.177C6.51649 14.25 8.43019 14.25 9.61054 13.177L15.9331 7.42923" stroke="currentColor" stroke-linecap="round"/></g>`,
|
mcp: `<g><path d="M0.972656 9.37176L9.5214 1.60019C10.7018 0.527151 12.6155 0.527151 13.7957 1.60019C14.9761 2.67321 14.9761 4.41295 13.7957 5.48599L7.3397 11.3552" stroke="currentColor" stroke-linecap="round"/><path d="M7.42871 11.2747L13.7957 5.48643C14.9761 4.41338 16.8898 4.41338 18.0702 5.48643L18.1147 5.52688C19.2951 6.59993 19.2951 8.33966 18.1147 9.4127L10.3831 16.4414C9.98966 16.7991 9.98966 17.379 10.3831 17.7366L11.9707 19.1799" stroke="currentColor" stroke-linecap="round"/><path d="M11.6587 3.54346L5.33619 9.29119C4.15584 10.3642 4.15584 12.1039 5.33619 13.177C6.51649 14.25 8.43019 14.25 9.61054 13.177L15.9331 7.42923" stroke="currentColor" stroke-linecap="round"/></g>`,
|
||||||
glasses: `<path d="M0.416626 7.91667H1.66663M19.5833 7.91667H18.3333M11.866 7.57987C11.3165 7.26398 10.6793 7.08333 9.99996 7.08333C9.32061 7.08333 8.68344 7.26398 8.13389 7.57987M8.74996 10C8.74996 12.0711 7.07103 13.75 4.99996 13.75C2.92889 13.75 1.24996 12.0711 1.24996 10C1.24996 7.92893 2.92889 6.25 4.99996 6.25C7.07103 6.25 8.74996 7.92893 8.74996 10ZM18.75 10C18.75 12.0711 17.071 13.75 15 13.75C12.9289 13.75 11.25 12.0711 11.25 10C11.25 7.92893 12.9289 6.25 15 6.25C17.071 6.25 18.75 7.92893 18.75 10Z" stroke="currentColor" stroke-linecap="square"/>`,
|
glasses: `<path d="M0.416626 7.91667H1.66663M19.5833 7.91667H18.3333M11.866 7.57987C11.3165 7.26398 10.6793 7.08333 9.99996 7.08333C9.32061 7.08333 8.68344 7.26398 8.13389 7.57987M8.74996 10C8.74996 12.0711 7.07103 13.75 4.99996 13.75C2.92889 13.75 1.24996 12.0711 1.24996 10C1.24996 7.92893 2.92889 6.25 4.99996 6.25C7.07103 6.25 8.74996 7.92893 8.74996 10ZM18.75 10C18.75 12.0711 17.071 13.75 15 13.75C12.9289 13.75 11.25 12.0711 11.25 10C11.25 7.92893 12.9289 6.25 15 6.25C17.071 6.25 18.75 7.92893 18.75 10Z" stroke="currentColor" stroke-linecap="square"/>`,
|
||||||
|
|
@ -39,7 +41,7 @@ const icons = {
|
||||||
"square-arrow-top-right": `<path d="M7.91675 2.9165H2.91675V17.0832H17.0834V12.0832M12.0834 2.9165H17.0834V7.9165M9.58342 10.4165L16.6667 3.33317" stroke="currentColor" stroke-linecap="square"/>`,
|
"square-arrow-top-right": `<path d="M7.91675 2.9165H2.91675V17.0832H17.0834V12.0832M12.0834 2.9165H17.0834V7.9165M9.58342 10.4165L16.6667 3.33317" stroke="currentColor" stroke-linecap="square"/>`,
|
||||||
"speech-bubble": `<path d="M18.3334 10.0003C18.3334 5.57324 15.0927 2.91699 10.0001 2.91699C4.90749 2.91699 1.66675 5.57324 1.66675 10.0003C1.66675 11.1497 2.45578 13.1016 2.5771 13.3949C2.5878 13.4207 2.59839 13.4444 2.60802 13.4706C2.69194 13.6996 3.04282 14.9364 1.66675 16.7684C3.5186 17.6538 5.48526 16.1982 5.48526 16.1982C6.84592 16.9202 8.46491 17.0837 10.0001 17.0837C15.0927 17.0837 18.3334 14.4274 18.3334 10.0003Z" stroke="currentColor" stroke-linecap="square"/>`,
|
"speech-bubble": `<path d="M18.3334 10.0003C18.3334 5.57324 15.0927 2.91699 10.0001 2.91699C4.90749 2.91699 1.66675 5.57324 1.66675 10.0003C1.66675 11.1497 2.45578 13.1016 2.5771 13.3949C2.5878 13.4207 2.59839 13.4444 2.60802 13.4706C2.69194 13.6996 3.04282 14.9364 1.66675 16.7684C3.5186 17.6538 5.48526 16.1982 5.48526 16.1982C6.84592 16.9202 8.46491 17.0837 10.0001 17.0837C15.0927 17.0837 18.3334 14.4274 18.3334 10.0003Z" stroke="currentColor" stroke-linecap="square"/>`,
|
||||||
"folder-add-left": `<path d="M2.08333 9.58268V2.91602H8.33333L10 5.41602H17.9167V16.2493H8.75M3.75 12.0827V14.5827M3.75 14.5827V17.0827M3.75 14.5827H1.25M3.75 14.5827H6.25" stroke="currentColor" stroke-linecap="square"/>`,
|
"folder-add-left": `<path d="M2.08333 9.58268V2.91602H8.33333L10 5.41602H17.9167V16.2493H8.75M3.75 12.0827V14.5827M3.75 14.5827V17.0827M3.75 14.5827H1.25M3.75 14.5827H6.25" stroke="currentColor" stroke-linecap="square"/>`,
|
||||||
"settings-gear": `<path d="M9.99935 2.08398L17.0827 6.04227L17.0827 13.9589L9.99934 17.9172L2.91602 13.9592L2.91602 6.04225L9.99935 2.08398Z" stroke="currentColor" stroke-linecap="square"/><path d="M12.916 10.0006C12.916 11.6115 11.6102 12.9173 9.99937 12.9173C8.38854 12.9173 7.0827 11.6115 7.0827 10.0006C7.0827 8.38982 8.38854 7.08398 9.99937 7.08398C11.6102 7.08398 12.916 8.38982 12.916 10.0006Z" stroke="currentColor" stroke-linecap="square"/>`,
|
"settings-gear": ` <path d="M9.99999 1L18 5.49998L18 14.5001L9.99998 19L2 14.5003L2 5.49996L9.99999 1Z" stroke="currentColor" stroke-linecap="square"/><path d="M13.2941 10.0001C13.2941 11.8313 11.8193 13.3159 10 13.3159C8.18073 13.3159 6.7059 11.8313 6.7059 10.0001C6.7059 8.16879 8.18073 6.68425 10 6.68425C11.8193 6.68425 13.2941 8.16879 13.2941 10.0001Z" stroke="currentColor" stroke-linecap="square"/>`,
|
||||||
github: `<path d="M10.0001 1.62549C14.6042 1.62549 18.3334 5.35465 18.3334 9.95882C18.333 11.7049 17.785 13.4068 16.7666 14.8251C15.7482 16.2434 14.3107 17.3066 12.6563 17.8651C12.2397 17.9484 12.0834 17.688 12.0834 17.4692C12.0834 17.188 12.0938 16.2922 12.0938 15.1776C12.0938 14.3963 11.8334 13.8963 11.5313 13.6359C13.3855 13.4276 15.3334 12.7192 15.3334 9.52132C15.3334 8.60465 15.0105 7.86507 14.4792 7.28174C14.5626 7.0734 14.8542 6.21924 14.3959 5.0734C14.3959 5.0734 13.698 4.84424 12.1042 5.92757C11.4376 5.74007 10.7292 5.64632 10.0209 5.64632C9.31258 5.64632 8.60425 5.74007 7.93758 5.92757C6.34383 4.85465 5.64592 5.0734 5.64592 5.0734C5.18758 6.21924 5.47925 7.0734 5.56258 7.28174C5.03133 7.86507 4.70842 8.61507 4.70842 9.52132C4.70842 12.7088 6.64592 13.4276 8.50008 13.6359C8.2605 13.8442 8.04175 14.2088 7.96883 14.7505C7.48967 14.9692 6.29175 15.3234 5.54175 14.063C5.3855 13.813 4.91675 13.1984 4.2605 13.2088C3.56258 13.2192 3.97925 13.6047 4.27092 13.7609C4.62508 13.9588 5.03133 14.6984 5.12508 14.938C5.29175 15.4067 5.83342 16.3026 7.92717 15.9172C7.92717 16.6151 7.93758 17.2713 7.93758 17.4692C7.93758 17.688 7.78133 17.938 7.36467 17.8651C5.70491 17.3126 4.26126 16.2515 3.23851 14.8324C2.21576 13.4133 1.66583 11.7081 1.66675 9.95882C1.66675 5.35465 5.39592 1.62549 10.0001 1.62549Z" fill="currentColor"/>`,
|
github: `<path d="M10.0001 1.62549C14.6042 1.62549 18.3334 5.35465 18.3334 9.95882C18.333 11.7049 17.785 13.4068 16.7666 14.8251C15.7482 16.2434 14.3107 17.3066 12.6563 17.8651C12.2397 17.9484 12.0834 17.688 12.0834 17.4692C12.0834 17.188 12.0938 16.2922 12.0938 15.1776C12.0938 14.3963 11.8334 13.8963 11.5313 13.6359C13.3855 13.4276 15.3334 12.7192 15.3334 9.52132C15.3334 8.60465 15.0105 7.86507 14.4792 7.28174C14.5626 7.0734 14.8542 6.21924 14.3959 5.0734C14.3959 5.0734 13.698 4.84424 12.1042 5.92757C11.4376 5.74007 10.7292 5.64632 10.0209 5.64632C9.31258 5.64632 8.60425 5.74007 7.93758 5.92757C6.34383 4.85465 5.64592 5.0734 5.64592 5.0734C5.18758 6.21924 5.47925 7.0734 5.56258 7.28174C5.03133 7.86507 4.70842 8.61507 4.70842 9.52132C4.70842 12.7088 6.64592 13.4276 8.50008 13.6359C8.2605 13.8442 8.04175 14.2088 7.96883 14.7505C7.48967 14.9692 6.29175 15.3234 5.54175 14.063C5.3855 13.813 4.91675 13.1984 4.2605 13.2088C3.56258 13.2192 3.97925 13.6047 4.27092 13.7609C4.62508 13.9588 5.03133 14.6984 5.12508 14.938C5.29175 15.4067 5.83342 16.3026 7.92717 15.9172C7.92717 16.6151 7.93758 17.2713 7.93758 17.4692C7.93758 17.688 7.78133 17.938 7.36467 17.8651C5.70491 17.3126 4.26126 16.2515 3.23851 14.8324C2.21576 13.4133 1.66583 11.7081 1.66675 9.95882C1.66675 5.35465 5.39592 1.62549 10.0001 1.62549Z" fill="currentColor"/>`,
|
||||||
discord: `<path d="M16.0742 4.45014C14.9244 3.92097 13.7106 3.54556 12.4638 3.3335C12.2932 3.64011 12.1388 3.95557 12.0013 4.27856C10.6732 4.07738 9.32261 4.07738 7.99451 4.27856C7.85694 3.9556 7.70257 3.64014 7.53203 3.3335C6.28441 3.54735 5.06981 3.92365 3.91889 4.45291C1.63401 7.85128 1.01462 11.1652 1.32431 14.4322C2.6624 15.426 4.16009 16.1819 5.7523 16.6668C6.11082 16.1821 6.42806 15.6678 6.70066 15.1295C6.18289 14.9351 5.68315 14.6953 5.20723 14.4128C5.33249 14.3215 5.45499 14.2274 5.57336 14.136C6.95819 14.7907 8.46965 15.1302 9.99997 15.1302C11.5303 15.1302 13.0418 14.7907 14.4266 14.136C14.5463 14.2343 14.6688 14.3284 14.7927 14.4128C14.3159 14.6957 13.8152 14.9361 13.2965 15.1309C13.5688 15.669 13.8861 16.1828 14.2449 16.6668C15.8385 16.1838 17.3373 15.4283 18.6756 14.4335C19.039 10.645 18.0549 7.36145 16.0742 4.45014ZM7.09294 12.423C6.22992 12.423 5.51693 11.6357 5.51693 10.6671C5.51693 9.69852 6.20514 8.90427 7.09019 8.90427C7.97524 8.90427 8.68272 9.69852 8.66758 10.6671C8.65244 11.6357 7.97248 12.423 7.09294 12.423ZM12.907 12.423C12.0426 12.423 11.3324 11.6357 11.3324 10.6671C11.3324 9.69852 12.0206 8.90427 12.907 8.90427C13.7934 8.90427 14.4954 9.69852 14.4803 10.6671C14.4651 11.6357 13.7865 12.423 12.907 12.423Z" fill="currentColor"/>`,
|
discord: `<path d="M16.0742 4.45014C14.9244 3.92097 13.7106 3.54556 12.4638 3.3335C12.2932 3.64011 12.1388 3.95557 12.0013 4.27856C10.6732 4.07738 9.32261 4.07738 7.99451 4.27856C7.85694 3.9556 7.70257 3.64014 7.53203 3.3335C6.28441 3.54735 5.06981 3.92365 3.91889 4.45291C1.63401 7.85128 1.01462 11.1652 1.32431 14.4322C2.6624 15.426 4.16009 16.1819 5.7523 16.6668C6.11082 16.1821 6.42806 15.6678 6.70066 15.1295C6.18289 14.9351 5.68315 14.6953 5.20723 14.4128C5.33249 14.3215 5.45499 14.2274 5.57336 14.136C6.95819 14.7907 8.46965 15.1302 9.99997 15.1302C11.5303 15.1302 13.0418 14.7907 14.4266 14.136C14.5463 14.2343 14.6688 14.3284 14.7927 14.4128C14.3159 14.6957 13.8152 14.9361 13.2965 15.1309C13.5688 15.669 13.8861 16.1828 14.2449 16.6668C15.8385 16.1838 17.3373 15.4283 18.6756 14.4335C19.039 10.645 18.0549 7.36145 16.0742 4.45014ZM7.09294 12.423C6.22992 12.423 5.51693 11.6357 5.51693 10.6671C5.51693 9.69852 6.20514 8.90427 7.09019 8.90427C7.97524 8.90427 8.68272 9.69852 8.66758 10.6671C8.65244 11.6357 7.97248 12.423 7.09294 12.423ZM12.907 12.423C12.0426 12.423 11.3324 11.6357 11.3324 10.6671C11.3324 9.69852 12.0206 8.90427 12.907 8.90427C13.7934 8.90427 14.4954 9.69852 14.4803 10.6671C14.4651 11.6357 13.7865 12.423 12.907 12.423Z" fill="currentColor"/>`,
|
||||||
"layout-bottom": `<path d="M18.125 18.125L1.875 18.125L1.875 1.875L18.125 1.875L18.125 18.125ZM3.125 12.8308L3.125 16.875L16.875 16.875L16.875 12.8308L3.125 12.8308ZM3.125 3.125L3.125 11.5808L16.875 11.5808L16.875 3.125L3.125 3.125Z" fill="currentColor"/>`,
|
"layout-bottom": `<path d="M18.125 18.125L1.875 18.125L1.875 1.875L18.125 1.875L18.125 18.125ZM3.125 12.8308L3.125 16.875L16.875 16.875L16.875 12.8308L3.125 12.8308ZM3.125 3.125L3.125 11.5808L16.875 11.5808L16.875 3.125L3.125 3.125Z" fill="currentColor"/>`,
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@
|
||||||
border-radius: var(--radius-lg);
|
border-radius: var(--radius-lg);
|
||||||
border: 1px solid var(--border-weak-base);
|
border: 1px solid var(--border-weak-base);
|
||||||
background: var(--surface-float-base);
|
background: var(--surface-float-base);
|
||||||
color: var(--text-inverted-base);
|
color: var(--text-invert-base);
|
||||||
box-shadow: var(--shadow-md);
|
box-shadow: var(--shadow-md);
|
||||||
|
|
||||||
[data-slot="toast-inner"] {
|
[data-slot="toast-inner"] {
|
||||||
|
|
@ -80,7 +80,8 @@
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
|
||||||
[data-component="icon"] {
|
[data-component="icon"] {
|
||||||
color: rgba(253, 252, 252, 0.94);
|
color: var(--text-invert-stronger);
|
||||||
|
/* color: var(--icon-invert-base); */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -93,7 +94,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-slot="toast-title"] {
|
[data-slot="toast-title"] {
|
||||||
color: var(--text-inverted-strong);
|
color: var(--text-invert-strong);
|
||||||
|
|
||||||
/* text-14-medium */
|
/* text-14-medium */
|
||||||
font-family: var(--font-family-sans);
|
font-family: var(--font-family-sans);
|
||||||
|
|
@ -107,7 +108,8 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-slot="toast-description"] {
|
[data-slot="toast-description"] {
|
||||||
color: var(--text-inverted-base);
|
color: var(--text-invert-base);
|
||||||
|
text-wrap-style: pretty;
|
||||||
|
|
||||||
/* text-14-regular */
|
/* text-14-regular */
|
||||||
font-family: var(--font-family-sans);
|
font-family: var(--font-family-sans);
|
||||||
|
|
@ -132,7 +134,7 @@
|
||||||
padding: 0;
|
padding: 0;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
||||||
color: var(--text-inverted-strong);
|
color: var(--text-invert-strong);
|
||||||
font-family: var(--font-family-sans);
|
font-family: var(--font-family-sans);
|
||||||
font-size: var(--font-size-base);
|
font-size: var(--font-size-base);
|
||||||
font-weight: var(--font-weight-medium);
|
font-weight: var(--font-weight-medium);
|
||||||
|
|
@ -144,7 +146,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
&:last-child {
|
&:last-child {
|
||||||
color: var(--text-inverted-weak);
|
color: var(--text-invert-weak);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
--font-family-mono: "Berkeley Mono", "Berkeley Mono Fallback";
|
--font-family-mono: "Berkeley Mono", "Berkeley Mono Fallback";
|
||||||
--font-family-mono--font-feature-settings: "ss01" 1;
|
--font-family-mono--font-feature-settings: "ss01" 1;
|
||||||
|
|
||||||
--font-size-small: 12px;
|
--font-size-small: 13px;
|
||||||
--font-size-base: 14px;
|
--font-size-base: 14px;
|
||||||
--font-size-large: 16px;
|
--font-size-large: 16px;
|
||||||
--font-size-x-large: 20px;
|
--font-size-x-large: 20px;
|
||||||
|
|
@ -122,7 +122,7 @@
|
||||||
--surface-diff-hidden-weaker: var(--blue-light-1);
|
--surface-diff-hidden-weaker: var(--blue-light-1);
|
||||||
--surface-diff-hidden-strong: var(--blue-light-5);
|
--surface-diff-hidden-strong: var(--blue-light-5);
|
||||||
--surface-diff-hidden-stronger: var(--blue-light-9);
|
--surface-diff-hidden-stronger: var(--blue-light-9);
|
||||||
--surface-diff-add-base: var(--mint-light-3);
|
--surface-diff-add-base: #dafbe0;
|
||||||
--surface-diff-add-weak: var(--mint-light-2);
|
--surface-diff-add-weak: var(--mint-light-2);
|
||||||
--surface-diff-add-weaker: var(--mint-light-1);
|
--surface-diff-add-weaker: var(--mint-light-1);
|
||||||
--surface-diff-add-strong: var(--mint-light-5);
|
--surface-diff-add-strong: var(--mint-light-5);
|
||||||
|
|
@ -265,22 +265,22 @@
|
||||||
--icon-diff-add-active: var(--mint-light-12);
|
--icon-diff-add-active: var(--mint-light-12);
|
||||||
--icon-diff-delete-base: var(--ember-light-10);
|
--icon-diff-delete-base: var(--ember-light-10);
|
||||||
--icon-diff-delete-hover: var(--ember-light-11);
|
--icon-diff-delete-hover: var(--ember-light-11);
|
||||||
--syntax-comment: var(--text-weaker);
|
--syntax-comment: var(--text-weak);
|
||||||
--syntax-regexp: var(--text-base);
|
--syntax-regexp: var(--text-base);
|
||||||
--syntax-string: #007663;
|
--syntax-string: #006656;
|
||||||
--syntax-keyword: var(--text-weak);
|
--syntax-keyword: var(--text-weak);
|
||||||
--syntax-primitive: #fb7f51;
|
--syntax-primitive: #fb4804;
|
||||||
--syntax-operator: var(--text-weak);
|
--syntax-operator: var(--text-base);
|
||||||
--syntax-variable: var(--text-strong);
|
--syntax-variable: var(--text-strong);
|
||||||
--syntax-property: #ec6cc8;
|
--syntax-property: #ed6dc8;
|
||||||
--syntax-type: #738400;
|
--syntax-type: #596600;
|
||||||
--syntax-constant: #00b2b9;
|
--syntax-constant: #007b80;
|
||||||
--syntax-punctuation: var(--text-weaker);
|
--syntax-punctuation: var(--text-base);
|
||||||
--syntax-object: var(--text-strong);
|
--syntax-object: var(--text-strong);
|
||||||
--syntax-success: var(--apple-light-10);
|
--syntax-success: var(--apple-light-10);
|
||||||
--syntax-warning: var(--amber-light-10);
|
--syntax-warning: var(--amber-light-10);
|
||||||
--syntax-critical: var(--ember-light-9);
|
--syntax-critical: var(--ember-light-10);
|
||||||
--syntax-info: #0091a7;
|
--syntax-info: #0092a8;
|
||||||
--syntax-diff-add: var(--mint-light-11);
|
--syntax-diff-add: var(--mint-light-11);
|
||||||
--syntax-diff-delete: var(--ember-light-11);
|
--syntax-diff-delete: var(--ember-light-11);
|
||||||
--syntax-diff-unknown: #ff0000;
|
--syntax-diff-unknown: #ff0000;
|
||||||
|
|
@ -521,7 +521,7 @@
|
||||||
--icon-diff-add-active: var(--mint-dark-11);
|
--icon-diff-add-active: var(--mint-dark-11);
|
||||||
--icon-diff-delete-base: var(--ember-dark-9);
|
--icon-diff-delete-base: var(--ember-dark-9);
|
||||||
--icon-diff-delete-hover: var(--ember-dark-10);
|
--icon-diff-delete-hover: var(--ember-dark-10);
|
||||||
--syntax-comment: var(--text-weaker);
|
--syntax-comment: var(--text-weak);
|
||||||
--syntax-regexp: var(--text-base);
|
--syntax-regexp: var(--text-base);
|
||||||
--syntax-string: #00ceb9;
|
--syntax-string: #00ceb9;
|
||||||
--syntax-keyword: var(--text-weak);
|
--syntax-keyword: var(--text-weak);
|
||||||
|
|
@ -531,7 +531,7 @@
|
||||||
--syntax-property: #ff9ae2;
|
--syntax-property: #ff9ae2;
|
||||||
--syntax-type: #ecf58c;
|
--syntax-type: #ecf58c;
|
||||||
--syntax-constant: #93e9f6;
|
--syntax-constant: #93e9f6;
|
||||||
--syntax-punctuation: var(--text-weaker);
|
--syntax-punctuation: var(--text-weak);
|
||||||
--syntax-object: var(--text-strong);
|
--syntax-object: var(--text-strong);
|
||||||
--syntax-success: var(--apple-dark-10);
|
--syntax-success: var(--apple-dark-10);
|
||||||
--syntax-warning: var(--amber-dark-10);
|
--syntax-warning: var(--amber-dark-10);
|
||||||
|
|
@ -772,7 +772,7 @@ html[data-theme="oc-2-paper"] {
|
||||||
--icon-diff-add-active: var(--mint-light-12);
|
--icon-diff-add-active: var(--mint-light-12);
|
||||||
--icon-diff-delete-base: var(--ember-light-10);
|
--icon-diff-delete-base: var(--ember-light-10);
|
||||||
--icon-diff-delete-hover: var(--ember-light-11);
|
--icon-diff-delete-hover: var(--ember-light-11);
|
||||||
--syntax-comment: var(--text-weaker);
|
--syntax-comment: var(--text-weak);
|
||||||
--syntax-regexp: var(--text-base);
|
--syntax-regexp: var(--text-base);
|
||||||
--syntax-string: #007663;
|
--syntax-string: #007663;
|
||||||
--syntax-keyword: var(--text-weak);
|
--syntax-keyword: var(--text-weak);
|
||||||
|
|
@ -782,7 +782,7 @@ html[data-theme="oc-2-paper"] {
|
||||||
--syntax-property: #ec6cc8;
|
--syntax-property: #ec6cc8;
|
||||||
--syntax-type: #738400;
|
--syntax-type: #738400;
|
||||||
--syntax-constant: #00b2b9;
|
--syntax-constant: #00b2b9;
|
||||||
--syntax-punctuation: var(--text-weaker);
|
--syntax-punctuation: var(--text-weak);
|
||||||
--syntax-object: var(--text-strong);
|
--syntax-object: var(--text-strong);
|
||||||
--syntax-success: var(--apple-light-10);
|
--syntax-success: var(--apple-light-10);
|
||||||
--syntax-warning: var(--amber-light-10);
|
--syntax-warning: var(--amber-light-10);
|
||||||
|
|
@ -1008,7 +1008,7 @@ html[data-theme="oc-2-paper"] {
|
||||||
--icon-diff-add-active: var(--mint-light-12);
|
--icon-diff-add-active: var(--mint-light-12);
|
||||||
--icon-diff-delete-base: var(--ember-light-10);
|
--icon-diff-delete-base: var(--ember-light-10);
|
||||||
--icon-diff-delete-hover: var(--ember-light-11);
|
--icon-diff-delete-hover: var(--ember-light-11);
|
||||||
--syntax-comment: var(--text-weaker);
|
--syntax-comment: var(--text-weak);
|
||||||
--syntax-regexp: var(--text-base);
|
--syntax-regexp: var(--text-base);
|
||||||
--syntax-string: #007663;
|
--syntax-string: #007663;
|
||||||
--syntax-keyword: var(--text-weak);
|
--syntax-keyword: var(--text-weak);
|
||||||
|
|
@ -1018,7 +1018,7 @@ html[data-theme="oc-2-paper"] {
|
||||||
--syntax-property: #ec6cc8;
|
--syntax-property: #ec6cc8;
|
||||||
--syntax-type: #738400;
|
--syntax-type: #738400;
|
||||||
--syntax-constant: #00b2b9;
|
--syntax-constant: #00b2b9;
|
||||||
--syntax-punctuation: var(--text-weaker);
|
--syntax-punctuation: var(--text-weak);
|
||||||
--syntax-object: var(--text-strong);
|
--syntax-object: var(--text-strong);
|
||||||
--syntax-success: var(--apple-light-10);
|
--syntax-success: var(--apple-light-10);
|
||||||
--syntax-warning: var(--amber-light-10);
|
--syntax-warning: var(--amber-light-10);
|
||||||
|
|
|
||||||
|
|
@ -64,6 +64,7 @@ You can also access our models through the following API endpoints.
|
||||||
|
|
||||||
| Model | Model ID | Endpoint | AI SDK Package |
|
| Model | Model ID | Endpoint | AI SDK Package |
|
||||||
| ----------------- | ----------------- | ------------------------------------------------ | --------------------------- |
|
| ----------------- | ----------------- | ------------------------------------------------ | --------------------------- |
|
||||||
|
| GPT 5.2 | gpt-5.2 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` |
|
||||||
| GPT 5.1 | gpt-5.1 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` |
|
| GPT 5.1 | gpt-5.1 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` |
|
||||||
| GPT 5.1 Codex | gpt-5.1-codex | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` |
|
| GPT 5.1 Codex | gpt-5.1-codex | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` |
|
||||||
| GPT 5.1 Codex Max | gpt-5.1-codex-max | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` |
|
| GPT 5.1 Codex Max | gpt-5.1-codex-max | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` |
|
||||||
|
|
@ -122,6 +123,7 @@ We support a pay-as-you-go model. Below are the prices **per 1M tokens**.
|
||||||
| Claude Opus 4.1 | $15.00 | $75.00 | $1.50 | $18.75 |
|
| Claude Opus 4.1 | $15.00 | $75.00 | $1.50 | $18.75 |
|
||||||
| Gemini 3 Pro (≤ 200K tokens) | $2.00 | $12.00 | $0.20 | - |
|
| Gemini 3 Pro (≤ 200K tokens) | $2.00 | $12.00 | $0.20 | - |
|
||||||
| Gemini 3 Pro (> 200K tokens) | $4.00 | $18.00 | $0.40 | - |
|
| Gemini 3 Pro (> 200K tokens) | $4.00 | $18.00 | $0.40 | - |
|
||||||
|
| GPT 5.2 | $1.75 | $14.00 | $0.175 | - |
|
||||||
| GPT 5.1 | $1.07 | $8.50 | $0.107 | - |
|
| GPT 5.1 | $1.07 | $8.50 | $0.107 | - |
|
||||||
| GPT 5.1 Codex | $1.07 | $8.50 | $0.107 | - |
|
| GPT 5.1 Codex | $1.07 | $8.50 | $0.107 | - |
|
||||||
| GPT 5.1 Codex Max | $1.25 | $10.00 | $0.125 | - |
|
| GPT 5.1 Codex Max | $1.25 | $10.00 | $0.125 | - |
|
||||||
|
|
|
||||||
12
sst-env.d.ts
vendored
12
sst-env.d.ts
vendored
|
|
@ -65,10 +65,6 @@ declare module "sst" {
|
||||||
"type": "sst.sst.Secret"
|
"type": "sst.sst.Secret"
|
||||||
"value": string
|
"value": string
|
||||||
}
|
}
|
||||||
"Enterprise": {
|
|
||||||
"type": "sst.cloudflare.SolidStart"
|
|
||||||
"url": string
|
|
||||||
}
|
|
||||||
"EnterpriseStorage": {
|
"EnterpriseStorage": {
|
||||||
"name": string
|
"name": string
|
||||||
"type": "sst.cloudflare.Bucket"
|
"type": "sst.cloudflare.Bucket"
|
||||||
|
|
@ -120,6 +116,10 @@ declare module "sst" {
|
||||||
"type": "sst.sst.Linkable"
|
"type": "sst.sst.Linkable"
|
||||||
"value": string
|
"value": string
|
||||||
}
|
}
|
||||||
|
"Teams": {
|
||||||
|
"type": "sst.cloudflare.SolidStart"
|
||||||
|
"url": string
|
||||||
|
}
|
||||||
"Web": {
|
"Web": {
|
||||||
"type": "sst.cloudflare.Astro"
|
"type": "sst.cloudflare.Astro"
|
||||||
"url": string
|
"url": string
|
||||||
|
|
@ -140,6 +140,10 @@ declare module "sst" {
|
||||||
"type": "sst.sst.Secret"
|
"type": "sst.sst.Secret"
|
||||||
"value": string
|
"value": string
|
||||||
}
|
}
|
||||||
|
"ZEN_MODELS5": {
|
||||||
|
"type": "sst.sst.Secret"
|
||||||
|
"value": string
|
||||||
|
}
|
||||||
"ZenData": {
|
"ZenData": {
|
||||||
"name": string
|
"name": string
|
||||||
"type": "sst.cloudflare.Bucket"
|
"type": "sst.cloudflare.Bucket"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue