From 272349b8da4d33f29b9249e55d7bd4055659ba60 Mon Sep 17 00:00:00 2001 From: "Jared A. Scheel" Date: Tue, 4 Nov 2025 15:40:29 -0600 Subject: [PATCH 001/218] Add support for `uv format` in formatters (#3916) --- packages/opencode/src/format/formatter.ts | 15 +++++++++++++++ packages/web/src/content/docs/formatters.mdx | 1 + 2 files changed, 16 insertions(+) diff --git a/packages/opencode/src/format/formatter.ts b/packages/opencode/src/format/formatter.ts index d2a9eee8..baa39906 100644 --- a/packages/opencode/src/format/formatter.ts +++ b/packages/opencode/src/format/formatter.ts @@ -177,6 +177,21 @@ export const ruff: Info = { }, } +export const uvformat: Info = { + name: "uv format", + command: ["uv", "format", "--", "$FILE"], + extensions: [".py", ".pyi"], + async enabled() { + if (await ruff.enabled()) return false + if (Bun.which("uv") !== null) { + const proc = Bun.spawn(["uv", "format", "--help"], { stderr: "pipe", stdout: "pipe" }) + const code = await proc.exited + return code === 0 + } + return false + }, +} + export const rubocop: Info = { name: "rubocop", command: ["rubocop", "--autocorrect", "$FILE"], diff --git a/packages/web/src/content/docs/formatters.mdx b/packages/web/src/content/docs/formatters.mdx index 8853ca33..4b46a4f6 100644 --- a/packages/web/src/content/docs/formatters.mdx +++ b/packages/web/src/content/docs/formatters.mdx @@ -21,6 +21,7 @@ OpenCode comes with several built-in formatters for popular languages and framew | clang-format | .c, .cpp, .h, .hpp, .ino, and [more](https://clang.llvm.org/docs/ClangFormat.html) | `.clang-format` config file | | ktlint | .kt, .kts | `ktlint` command available | | ruff | .py, .pyi | `ruff` command available with config | +| uv | .py, .pyi | `uv` command available | | rubocop | .rb, .rake, .gemspec, .ru | `rubocop` command available | | standardrb | .rb, .rake, .gemspec, .ru | `standardrb` command available | | htmlbeautifier | .erb, .html.erb | `htmlbeautifier` command available | From 678ca757c97ed7992ad905fd7c9add4282a484e6 Mon Sep 17 00:00:00 2001 From: Aiden Cline Date: Tue, 4 Nov 2025 16:08:31 -0600 Subject: [PATCH 002/218] fix: permissions not responding to esc --- packages/opencode/src/cli/cmd/tui/routes/session/index.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx b/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx index f37be32f..ccd12819 100644 --- a/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx +++ b/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx @@ -120,6 +120,7 @@ export function Session() { if (evt.name === "return") return "once" if (evt.name === "a") return "always" if (evt.name === "d") return "reject" + if (evt.name === "escape") return "reject" return }) if (response) { From 71b04ffa99a3215316083dcf4d5e15afb3193958 Mon Sep 17 00:00:00 2001 From: Dax Raad Date: Tue, 4 Nov 2025 14:33:38 -0500 Subject: [PATCH 003/218] add command bar option to interrupt session --- .../src/cli/cmd/tui/component/prompt/index.tsx | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx b/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx index 785eb7e4..cf497407 100644 --- a/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx +++ b/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx @@ -156,10 +156,11 @@ export function Prompt(props: PromptProps) { title: "Interrupt session", value: "session.interrupt", keybind: "session_interrupt", + disabled: status() !== "working", category: "Session", - disabled: true, onSelect: (dialog) => { if (!props.sessionID) return + if (autocomplete.visible) return sdk.client.session.abort({ path: { id: props.sessionID, @@ -602,16 +603,6 @@ export function Prompt(props: PromptProps) { ) input.cursorOffset = input.plainText.length } - if (!autocomplete.visible) { - if (keybind.match("session_interrupt", e) && props.sessionID) { - sdk.client.session.abort({ - path: { - id: props.sessionID, - }, - }) - return - } - } }} onSubmit={submit} onPaste={async (event: PasteEvent) => { From 8d6a03cc898c0b982b7a05419d41a07e8db579f8 Mon Sep 17 00:00:00 2001 From: Frank Date: Tue, 4 Nov 2025 16:51:38 -0500 Subject: [PATCH 004/218] zen: custom reload amount --- .../console/app/src/routes/stripe/webhook.ts | 265 +++++++++--------- .../[id]/billing/billing-section.module.css | 51 ++++ .../[id]/billing/billing-section.tsx | 187 ++++++++---- .../[id]/billing/monthly-limit-section.tsx | 32 +-- .../[id]/billing/reload-section.module.css | 202 +++++++++++++ .../workspace/[id]/billing/reload-section.tsx | 162 +++++++++-- .../app/src/routes/workspace/[id]/index.tsx | 42 +-- .../app/src/routes/workspace/common.tsx | 33 ++- .../app/src/routes/zen/util/handler.ts | 6 +- packages/console/core/src/billing.ts | 61 ++-- 10 files changed, 767 insertions(+), 274 deletions(-) diff --git a/packages/console/app/src/routes/stripe/webhook.ts b/packages/console/app/src/routes/stripe/webhook.ts index cc44f867..d8d85725 100644 --- a/packages/console/app/src/routes/stripe/webhook.ts +++ b/packages/console/app/src/routes/stripe/webhook.ts @@ -13,146 +13,157 @@ export async function POST(input: APIEvent) { input.request.headers.get("stripe-signature")!, Resource.STRIPE_WEBHOOK_SECRET.value, ) - console.log(body.type, JSON.stringify(body, null, 2)) - if (body.type === "customer.updated") { - // check default payment method changed - const prevInvoiceSettings = body.data.previous_attributes?.invoice_settings ?? {} - if (!("default_payment_method" in prevInvoiceSettings)) return - const customerID = body.data.object.id - const paymentMethodID = body.data.object.invoice_settings.default_payment_method as string + return (async () => { + if (body.type === "customer.updated") { + // check default payment method changed + const prevInvoiceSettings = body.data.previous_attributes?.invoice_settings ?? {} + if (!("default_payment_method" in prevInvoiceSettings)) return "ignored" - if (!customerID) throw new Error("Customer ID not found") - if (!paymentMethodID) throw new Error("Payment method ID not found") + const customerID = body.data.object.id + const paymentMethodID = body.data.object.invoice_settings.default_payment_method as string - const paymentMethod = await Billing.stripe().paymentMethods.retrieve(paymentMethodID) - await Database.use(async (tx) => { - await tx - .update(BillingTable) - .set({ - paymentMethodID, - paymentMethodLast4: paymentMethod.card?.last4 ?? null, - paymentMethodType: paymentMethod.type, - }) - .where(eq(BillingTable.customerID, customerID)) - }) - } - if (body.type === "checkout.session.completed") { - const workspaceID = body.data.object.metadata?.workspaceID - const customerID = body.data.object.customer as string - const paymentID = body.data.object.payment_intent as string - const invoiceID = body.data.object.invoice as string - const amount = body.data.object.amount_total + if (!customerID) throw new Error("Customer ID not found") + if (!paymentMethodID) throw new Error("Payment method ID not found") - if (!workspaceID) throw new Error("Workspace ID not found") - if (!customerID) throw new Error("Customer ID not found") - if (!amount) throw new Error("Amount not found") - if (!paymentID) throw new Error("Payment ID not found") - if (!invoiceID) throw new Error("Invoice ID not found") - - await Actor.provide("system", { workspaceID }, async () => { - const customer = await Billing.get() - if (customer?.customerID && customer.customerID !== customerID) - throw new Error("Customer ID mismatch") - - // set customer metadata - if (!customer?.customerID) { - await Billing.stripe().customers.update(customerID, { - metadata: { - workspaceID, - }, - }) - } - - // get payment method for the payment intent - const paymentIntent = await Billing.stripe().paymentIntents.retrieve(paymentID, { - expand: ["payment_method"], - }) - const paymentMethod = paymentIntent.payment_method - if (!paymentMethod || typeof paymentMethod === "string") - throw new Error("Payment method not expanded") - - const oldBillingInfo = await Database.use((tx) => - tx - .select({ - customerID: BillingTable.customerID, - }) - .from(BillingTable) - .where(eq(BillingTable.workspaceID, workspaceID)) - .then((rows) => rows[0]), - ) - - await Database.transaction(async (tx) => { + const paymentMethod = await Billing.stripe().paymentMethods.retrieve(paymentMethodID) + await Database.use(async (tx) => { await tx .update(BillingTable) .set({ - balance: sql`${BillingTable.balance} + ${centsToMicroCents(Billing.CHARGE_AMOUNT)}`, - customerID, - paymentMethodID: paymentMethod.id, + paymentMethodID, paymentMethodLast4: paymentMethod.card?.last4 ?? null, paymentMethodType: paymentMethod.type, - // enable reload if first time enabling billing - ...(oldBillingInfo?.customerID - ? {} - : { - reload: true, - reloadError: null, - timeReloadError: null, - }), }) - .where(eq(BillingTable.workspaceID, workspaceID)) - await tx.insert(PaymentTable).values({ - workspaceID, - id: Identifier.create("payment"), - amount: centsToMicroCents(Billing.CHARGE_AMOUNT), - paymentID, - invoiceID, - customerID, + .where(eq(BillingTable.customerID, customerID)) + }) + } + if (body.type === "checkout.session.completed") { + const workspaceID = body.data.object.metadata?.workspaceID + const amountInCents = + body.data.object.metadata?.amount && parseInt(body.data.object.metadata?.amount) + const customerID = body.data.object.customer as string + const paymentID = body.data.object.payment_intent as string + const invoiceID = body.data.object.invoice as string + + if (!workspaceID) throw new Error("Workspace ID not found") + if (!customerID) throw new Error("Customer ID not found") + if (!amountInCents) throw new Error("Amount not found") + if (!paymentID) throw new Error("Payment ID not found") + if (!invoiceID) throw new Error("Invoice ID not found") + + await Actor.provide("system", { workspaceID }, async () => { + const customer = await Billing.get() + if (customer?.customerID && customer.customerID !== customerID) + throw new Error("Customer ID mismatch") + + // set customer metadata + if (!customer?.customerID) { + await Billing.stripe().customers.update(customerID, { + metadata: { + workspaceID, + }, + }) + } + + // get payment method for the payment intent + const paymentIntent = await Billing.stripe().paymentIntents.retrieve(paymentID, { + expand: ["payment_method"], + }) + const paymentMethod = paymentIntent.payment_method + if (!paymentMethod || typeof paymentMethod === "string") + throw new Error("Payment method not expanded") + + await Database.transaction(async (tx) => { + await tx + .update(BillingTable) + .set({ + balance: sql`${BillingTable.balance} + ${centsToMicroCents(amountInCents)}`, + customerID, + paymentMethodID: paymentMethod.id, + paymentMethodLast4: paymentMethod.card?.last4 ?? null, + paymentMethodType: paymentMethod.type, + // enable reload if first time enabling billing + ...(customer?.customerID + ? {} + : { + reload: true, + reloadError: null, + timeReloadError: null, + }), + }) + .where(eq(BillingTable.workspaceID, workspaceID)) + await tx.insert(PaymentTable).values({ + workspaceID, + id: Identifier.create("payment"), + amount: centsToMicroCents(amountInCents), + paymentID, + invoiceID, + customerID, + }) }) }) + } + if (body.type === "charge.refunded") { + const customerID = body.data.object.customer as string + const paymentIntentID = body.data.object.payment_intent as string + if (!customerID) throw new Error("Customer ID not found") + if (!paymentIntentID) throw new Error("Payment ID not found") + + const workspaceID = await Database.use((tx) => + tx + .select({ + workspaceID: BillingTable.workspaceID, + }) + .from(BillingTable) + .where(eq(BillingTable.customerID, customerID)) + .then((rows) => rows[0]?.workspaceID), + ) + if (!workspaceID) throw new Error("Workspace ID not found") + + const amount = await Database.use((tx) => + tx + .select({ + amount: PaymentTable.amount, + }) + .from(PaymentTable) + .where( + and( + eq(PaymentTable.paymentID, paymentIntentID), + eq(PaymentTable.workspaceID, workspaceID), + ), + ) + .then((rows) => rows[0]?.amount), + ) + if (!amount) throw new Error("Payment not found") + + await Database.transaction(async (tx) => { + await tx + .update(PaymentTable) + .set({ + timeRefunded: new Date(body.created * 1000), + }) + .where( + and( + eq(PaymentTable.paymentID, paymentIntentID), + eq(PaymentTable.workspaceID, workspaceID), + ), + ) + + await tx + .update(BillingTable) + .set({ + balance: sql`${BillingTable.balance} - ${amount}`, + }) + .where(eq(BillingTable.workspaceID, workspaceID)) + }) + } + })() + .then((message) => { + return Response.json({ message: message ?? "done" }, { status: 200 }) }) - } - if (body.type === "charge.refunded") { - const customerID = body.data.object.customer as string - const paymentIntentID = body.data.object.payment_intent as string - if (!customerID) throw new Error("Customer ID not found") - if (!paymentIntentID) throw new Error("Payment ID not found") - - const workspaceID = await Database.use((tx) => - tx - .select({ - workspaceID: BillingTable.workspaceID, - }) - .from(BillingTable) - .where(eq(BillingTable.customerID, customerID)) - .then((rows) => rows[0]?.workspaceID), - ) - if (!workspaceID) throw new Error("Workspace ID not found") - - await Database.transaction(async (tx) => { - await tx - .update(PaymentTable) - .set({ - timeRefunded: new Date(body.created * 1000), - }) - .where( - and( - eq(PaymentTable.paymentID, paymentIntentID), - eq(PaymentTable.workspaceID, workspaceID), - ), - ) - - await tx - .update(BillingTable) - .set({ - balance: sql`${BillingTable.balance} - ${centsToMicroCents(Billing.CHARGE_AMOUNT)}`, - }) - .where(eq(BillingTable.workspaceID, workspaceID)) + .catch((error: any) => { + return Response.json({ message: error.message }, { status: 500 }) }) - } - - console.log("finished handling") - - return Response.json("ok", { status: 200 }) } diff --git a/packages/console/app/src/routes/workspace/[id]/billing/billing-section.module.css b/packages/console/app/src/routes/workspace/[id]/billing/billing-section.module.css index e0a80ef7..aef008a4 100644 --- a/packages/console/app/src/routes/workspace/[id]/billing/billing-section.module.css +++ b/packages/console/app/src/routes/workspace/[id]/billing/billing-section.module.css @@ -71,6 +71,57 @@ flex: 1; } + [data-slot="add-balance-form-container"] { + display: flex; + flex-direction: column; + gap: var(--space-2); + } + + [data-slot="add-balance-form"] { + display: flex; + flex-direction: row; + align-items: center; + gap: var(--space-3); + + label { + font-size: var(--font-size-sm); + font-weight: 500; + color: var(--color-text-muted); + white-space: nowrap; + } + + input[data-component="input"] { + padding: var(--space-2) var(--space-3); + border: 1px solid var(--color-border); + border-radius: var(--border-radius-sm); + background-color: var(--color-bg); + color: var(--color-text); + font-size: var(--font-size-sm); + line-height: 1.5; + + &:focus { + outline: none; + border-color: var(--color-accent); + box-shadow: 0 0 0 3px var(--color-accent-alpha); + } + + &::placeholder { + color: var(--color-text-disabled); + } + } + + [data-slot="form-actions"] { + display: flex; + gap: var(--space-2); + } + } + + [data-slot="form-error"] { + color: var(--color-danger); + font-size: var(--font-size-sm); + line-height: 1.4; + } + [data-slot="credit-card"] { padding: var(--space-2) var(--space-4); background-color: var(--color-bg-surface); diff --git a/packages/console/app/src/routes/workspace/[id]/billing/billing-section.tsx b/packages/console/app/src/routes/workspace/[id]/billing/billing-section.tsx index c0723136..9e51bbe1 100644 --- a/packages/console/app/src/routes/workspace/[id]/billing/billing-section.tsx +++ b/packages/console/app/src/routes/workspace/[id]/billing/billing-section.tsx @@ -1,24 +1,80 @@ -import { action, useParams, useAction, createAsync, useSubmission } from "@solidjs/router" -import { createMemo, Match, Show, Switch } from "solid-js" +import { action, useParams, useAction, createAsync, useSubmission, json } from "@solidjs/router" +import { createMemo, Match, Show, Switch, createEffect } from "solid-js" +import { createStore } from "solid-js/store" import { Billing } from "@opencode-ai/console-core/billing.js" import { withActor } from "~/context/auth.withActor" import { IconCreditCard, IconStripe } from "~/component/icon" import styles from "./billing-section.module.css" -import { createCheckoutUrl, queryBillingInfo } from "../../common" +import { createCheckoutUrl, formatBalance, queryBillingInfo } from "../../common" const createSessionUrl = action(async (workspaceID: string, returnUrl: string) => { "use server" - return withActor(() => Billing.generateSessionUrl({ returnUrl }), workspaceID) + return json( + await withActor( + () => + Billing.generateSessionUrl({ returnUrl }) + .then((data) => ({ error: undefined, data })) + .catch((e) => ({ + error: e.message as string, + data: undefined, + })), + workspaceID, + ), + { revalidate: queryBillingInfo.key }, + ) }, "sessionUrl") export function BillingSection() { const params = useParams() // ORIGINAL CODE - COMMENTED OUT FOR TESTING - const balanceInfo = createAsync(() => queryBillingInfo(params.id)) - const createCheckoutUrlAction = useAction(createCheckoutUrl) - const createCheckoutUrlSubmission = useSubmission(createCheckoutUrl) - const createSessionUrlAction = useAction(createSessionUrl) - const createSessionUrlSubmission = useSubmission(createSessionUrl) + const billingInfo = createAsync(() => queryBillingInfo(params.id)) + const checkoutAction = useAction(createCheckoutUrl) + const checkoutSubmission = useSubmission(createCheckoutUrl) + const sessionAction = useAction(createSessionUrl) + const sessionSubmission = useSubmission(createSessionUrl) + const [store, setStore] = createStore({ + showAddBalanceForm: false, + addBalanceAmount: "", + checkoutRedirecting: false, + sessionRedirecting: false, + }) + const balance = createMemo(() => formatBalance(billingInfo()?.balance ?? 0)) + + async function onClickCheckout() { + const amount = parseInt(store.addBalanceAmount) + const baseUrl = window.location.href + + const checkout = await checkoutAction(params.id, amount, baseUrl, baseUrl) + if (checkout && checkout.data) { + setStore("checkoutRedirecting", true) + window.location.href = checkout.data + } + } + + async function onClickSession() { + const baseUrl = window.location.href + const sessionUrl = await sessionAction(params.id, baseUrl) + if (sessionUrl && sessionUrl.data) { + setStore("sessionRedirecting", true) + window.location.href = sessionUrl.data + } + } + + function showAddBalanceForm() { + while (true) { + checkoutSubmission.clear() + if (!checkoutSubmission.result) break + } + setStore({ + showAddBalanceForm: true, + addBalanceAmount: billingInfo()!.reloadAmount.toString(), + }) + } + + function hideAddBalanceForm() { + setStore("showAddBalanceForm", false) + checkoutSubmission.clear() + } // DUMMY DATA FOR TESTING - UNCOMMENT ONE OF THE SCENARIOS BELOW @@ -72,10 +128,6 @@ export function BillingSection() { // timeReloadError: null as Date | null // }) - const balanceAmount = createMemo(() => { - return ((balanceInfo()?.balance ?? 0) / 100000000).toFixed(2) - }) - return (
@@ -88,81 +140,110 @@ export function BillingSection() {
- - ${balanceAmount() === "-0.00" ? "0.00" : balanceAmount()} - + ${balance()} Current Balance
- +
- + +
+
+ + {(err: any) =>
{err()}
} +
+
+ } > - {createCheckoutUrlSubmission.pending ? "Loading..." : "Add Balance"} - + +
}> - +
- + ----} > •••• - {balanceInfo()?.paymentMethodLast4} + {billingInfo()?.paymentMethodLast4} - + Linked to Stripe
- + diff --git a/packages/console/app/src/routes/workspace/[id]/billing/monthly-limit-section.tsx b/packages/console/app/src/routes/workspace/[id]/billing/monthly-limit-section.tsx index dbeda115..b28b072d 100644 --- a/packages/console/app/src/routes/workspace/[id]/billing/monthly-limit-section.tsx +++ b/packages/console/app/src/routes/workspace/[id]/billing/monthly-limit-section.tsx @@ -1,16 +1,10 @@ -import { json, query, action, useParams, createAsync, useSubmission } from "@solidjs/router" +import { json, action, useParams, createAsync, useSubmission } from "@solidjs/router" import { createEffect, Show } from "solid-js" import { createStore } from "solid-js/store" import { withActor } from "~/context/auth.withActor" import { Billing } from "@opencode-ai/console-core/billing.js" import styles from "./monthly-limit-section.module.css" - -const getBillingInfo = query(async (workspaceID: string) => { - "use server" - return withActor(async () => { - return await Billing.get() - }, workspaceID) -}, "billing.get") +import { queryBillingInfo } from "../../common" const setMonthlyLimit = action(async (form: FormData) => { "use server" @@ -28,7 +22,7 @@ const setMonthlyLimit = action(async (form: FormData) => { .catch((e) => ({ error: e.message as string })), workspaceID, ), - { revalidate: getBillingInfo.key }, + { revalidate: queryBillingInfo.key }, ) }, "billing.setMonthlyLimit") @@ -36,7 +30,7 @@ export function MonthlyLimitSection() { const params = useParams() const submission = useSubmission(setMonthlyLimit) const [store, setStore] = createStore({ show: false }) - const balanceInfo = createAsync(() => getBillingInfo(params.id)) + const billingInfo = createAsync(() => queryBillingInfo(params.id)) let input: HTMLInputElement @@ -73,8 +67,8 @@ export function MonthlyLimitSection() {
- {balanceInfo()?.monthlyLimit ? $ : null} - {balanceInfo()?.monthlyLimit ?? "-"} + {billingInfo()?.monthlyLimit ? $ : null} + {billingInfo()?.monthlyLimit ?? "-"}
- No spending limit set.

}> + No spending limit set.

} + >

- Current usage for {new Date().toLocaleDateString("en-US", { month: "long", timeZone: "UTC" })} is $ + Current usage for{" "} + {new Date().toLocaleDateString("en-US", { month: "long", timeZone: "UTC" })} is $ {(() => { - const dateLastUsed = balanceInfo()?.timeMonthlyUsageUpdated + const dateLastUsed = billingInfo()?.timeMonthlyUsageUpdated if (!dateLastUsed) return "0" const current = new Date().toLocaleDateString("en-US", { @@ -128,7 +126,7 @@ export function MonthlyLimitSection() { timeZone: "UTC", }) if (current !== lastUsed) return "0" - return ((balanceInfo()?.monthlyUsage ?? 0) / 100000000).toFixed(2) + return ((billingInfo()?.monthlyUsage ?? 0) / 100000000).toFixed(2) })()} .

diff --git a/packages/console/app/src/routes/workspace/[id]/billing/reload-section.module.css b/packages/console/app/src/routes/workspace/[id]/billing/reload-section.module.css index 08fb8524..11ab789b 100644 --- a/packages/console/app/src/routes/workspace/[id]/billing/reload-section.module.css +++ b/packages/console/app/src/routes/workspace/[id]/billing/reload-section.module.css @@ -34,6 +34,206 @@ } } + [data-slot="create-form"] { + display: flex; + flex-direction: column; + gap: var(--space-3); + padding: var(--space-4); + border: 1px solid var(--color-border); + border-radius: var(--border-radius-sm); + margin-top: var(--space-4); + + [data-slot="form-field"] { + display: flex; + flex-direction: column; + gap: var(--space-2); + + label { + display: flex; + flex-direction: column; + gap: var(--space-2); + } + + [data-slot="field-label"] { + font-size: var(--font-size-sm); + font-weight: 500; + color: var(--color-text-muted); + } + + [data-slot="toggle-container"] { + display: flex; + align-items: center; + } + + input[data-component="input"] { + flex: 1; + padding: var(--space-2) var(--space-3); + border: 1px solid var(--color-border); + border-radius: var(--border-radius-sm); + background-color: var(--color-bg); + color: var(--color-text); + font-size: var(--font-size-sm); + font-family: var(--font-mono); + + &:focus { + outline: none; + border-color: var(--color-accent); + } + + &::placeholder { + color: var(--color-text-disabled); + } + } + } + + [data-slot="input-row"] { + display: flex; + flex-direction: row; + gap: var(--space-3); + + @media (max-width: 40rem) { + flex-direction: column; + gap: var(--space-2); + } + } + + [data-slot="input-field"] { + display: flex; + flex-direction: column; + gap: var(--space-1); + flex: 1; + + p { + line-height: 1.2; + margin: 0; + color: var(--color-text-muted); + font-size: var(--font-size-sm); + } + + input[data-component="input"] { + flex: 1; + padding: var(--space-2) var(--space-3); + border: 1px solid var(--color-border); + border-radius: var(--border-radius-sm); + background-color: var(--color-bg); + color: var(--color-text); + font-size: var(--font-size-sm); + line-height: 1.5; + min-width: 0; + + &:focus { + outline: none; + border-color: var(--color-accent); + box-shadow: 0 0 0 3px var(--color-accent-alpha); + } + + &::placeholder { + color: var(--color-text-disabled); + } + + &:disabled { + opacity: 0.5; + cursor: not-allowed; + background-color: var(--color-bg-surface); + } + } + + [data-slot="field-with-connector"] { + display: flex; + align-items: center; + gap: var(--space-2); + + [data-slot="field-connector"] { + font-size: var(--font-size-sm); + color: var(--color-text-muted); + white-space: nowrap; + } + + input[data-component="input"] { + flex: 1; + min-width: 80px; + } + } + } + + [data-slot="form-actions"] { + display: flex; + gap: var(--space-2); + margin-top: var(--space-1); + } + + [data-slot="form-error"] { + color: var(--color-danger); + font-size: var(--font-size-sm); + line-height: 1.4; + margin-top: calc(var(--space-1) * -1); + } + + [data-slot="model-toggle-label"] { + position: relative; + display: inline-block; + width: 2.5rem; + height: 1.5rem; + cursor: pointer; + + input { + opacity: 0; + width: 0; + height: 0; + } + + span { + position: absolute; + inset: 0; + background-color: #ccc; + border: 1px solid #bbb; + border-radius: 1.5rem; + transition: all 0.3s ease; + cursor: pointer; + + &::before { + content: ""; + position: absolute; + top: 50%; + left: 0.125rem; + width: 1.25rem; + height: 1.25rem; + background-color: white; + border: 1px solid #ddd; + border-radius: 50%; + transform: translateY(-50%); + transition: all 0.3s ease; + } + } + + input:checked + span { + background-color: #21ad0e; + border-color: #148605; + + &::before { + transform: translateX(1rem) translateY(-50%); + } + } + + &:hover span { + box-shadow: 0 0 0 2px rgba(34, 197, 94, 0.2); + } + + input:checked:hover + span { + box-shadow: 0 0 0 2px rgba(34, 197, 94, 0.3); + } + + &:has(input:disabled) { + cursor: not-allowed; + } + + input:disabled + span { + opacity: 0.5; + cursor: not-allowed; + } + } + } + [data-slot="reload-error"] { display: flex; align-items: center; @@ -54,6 +254,8 @@ gap: var(--space-2); margin: 0; flex-shrink: 0; + padding: 0; + border: none; } } } diff --git a/packages/console/app/src/routes/workspace/[id]/billing/reload-section.tsx b/packages/console/app/src/routes/workspace/[id]/billing/reload-section.tsx index 6be6ddf3..57267a95 100644 --- a/packages/console/app/src/routes/workspace/[id]/billing/reload-section.tsx +++ b/packages/console/app/src/routes/workspace/[id]/billing/reload-section.tsx @@ -1,17 +1,19 @@ -import { json, query, action, useParams, createAsync, useSubmission } from "@solidjs/router" -import { Show } from "solid-js" +import { json, action, useParams, createAsync, useSubmission } from "@solidjs/router" +import { createEffect, Show } from "solid-js" +import { createStore } from "solid-js/store" import { withActor } from "~/context/auth.withActor" import { Billing } from "@opencode-ai/console-core/billing.js" import { Database, eq } from "@opencode-ai/console-core/drizzle/index.js" import { BillingTable } from "@opencode-ai/console-core/schema/billing.sql.js" import styles from "./reload-section.module.css" +import { queryBillingInfo } from "../../common" const reload = action(async (form: FormData) => { "use server" const workspaceID = form.get("workspaceID")?.toString() if (!workspaceID) return { error: "Workspace ID is required" } return json(await withActor(() => Billing.reload(), workspaceID), { - revalidate: getBillingInfo.key, + revalidate: queryBillingInfo.key, }) }, "billing.reload") @@ -20,12 +22,27 @@ const setReload = action(async (form: FormData) => { const workspaceID = form.get("workspaceID")?.toString() if (!workspaceID) return { error: "Workspace ID is required" } const reloadValue = form.get("reload")?.toString() === "true" + const amountStr = form.get("reloadAmount")?.toString() + const triggerStr = form.get("reloadTrigger")?.toString() + + const reloadAmount = amountStr && amountStr.trim() !== "" ? parseInt(amountStr) : null + const reloadTrigger = triggerStr && triggerStr.trim() !== "" ? parseInt(triggerStr) : null + + if (reloadValue) { + if (reloadAmount === null || reloadAmount < Billing.RELOAD_AMOUNT_MIN) + return { error: `Reload amount must be at least $${Billing.RELOAD_AMOUNT_MIN}` } + if (reloadTrigger === null || reloadTrigger < Billing.RELOAD_TRIGGER_MIN) + return { error: `Balance trigger must be at least $${Billing.RELOAD_TRIGGER_MIN}` } + } + return json( await Database.use((tx) => tx .update(BillingTable) .set({ reload: reloadValue, + ...(reloadAmount !== null ? { reloadAmount } : {}), + ...(reloadTrigger !== null ? { reloadTrigger } : {}), ...(reloadValue ? { reloadError: null, @@ -35,22 +52,47 @@ const setReload = action(async (form: FormData) => { }) .where(eq(BillingTable.workspaceID, workspaceID)), ), - { revalidate: getBillingInfo.key }, + { revalidate: queryBillingInfo.key }, ) }, "billing.setReload") -const getBillingInfo = query(async (workspaceID: string) => { - "use server" - return withActor(async () => { - return await Billing.get() - }, workspaceID) -}, "billing.get") - export function ReloadSection() { const params = useParams() - const balanceInfo = createAsync(() => getBillingInfo(params.id)) + const billingInfo = createAsync(() => queryBillingInfo(params.id)) const setReloadSubmission = useSubmission(setReload) const reloadSubmission = useSubmission(reload) + const [store, setStore] = createStore({ + show: false, + reload: false, + reloadAmount: "", + reloadTrigger: "", + }) + + createEffect(() => { + if ( + !setReloadSubmission.pending && + setReloadSubmission.result && + !(setReloadSubmission.result as any).error + ) { + setStore("show", false) + } + }) + + function show() { + while (true) { + setReloadSubmission.clear() + if (!setReloadSubmission.result) break + } + const info = billingInfo()! + setStore("show", true) + setStore("reload", info.reload ? true : true) + setStore("reloadAmount", info.reloadAmount.toString()) + setStore("reloadTrigger", info.reloadTrigger.toString()) + } + + function hide() { + setStore("show", false) + } return (
@@ -58,43 +100,101 @@ export function ReloadSection() {

Auto Reload

Auto reload is disabled. Enable to automatically reload when balance is low.

+

+ Auto reload is disabled. Enable to automatically reload when balance is low. +

} >

- We'll automatically reload $20 (+$1.23 processing fee) when it reaches{" "} - $5. + Auto reload is enabled. We'll reload ${billingInfo()?.reloadAmount}{" "} + (+$1.23 processing fee) when balance reaches ${billingInfo()?.reloadTrigger}.

-
- - - -
+
+ +
+
+ +
+ +
+
+

Reload $

+ setStore("reloadAmount", e.currentTarget.value)} + placeholder={billingInfo()?.reloadAmount.toString()} + disabled={!store.reload} + /> +
+
+

When balance reaches $

+ setStore("reloadTrigger", e.currentTarget.value)} + placeholder={billingInfo()?.reloadTrigger.toString()} + disabled={!store.reload} + /> +
+
+ + + {(err: any) =>
{err()}
} +
+ +
+ + +
+
+
- +

Reload failed at{" "} - {balanceInfo()?.timeReloadError!.toLocaleString("en-US", { + {billingInfo()?.timeReloadError!.toLocaleString("en-US", { month: "short", day: "numeric", hour: "numeric", minute: "2-digit", second: "2-digit", })} - . Reason: {balanceInfo()?.reloadError?.replace(/\.$/, "")}. Please update your payment + . Reason: {billingInfo()?.reloadError?.replace(/\.$/, "")}. Please update your payment method and try again.

diff --git a/packages/console/app/src/routes/workspace/[id]/index.tsx b/packages/console/app/src/routes/workspace/[id]/index.tsx index 8f7678f2..2e7f7d64 100644 --- a/packages/console/app/src/routes/workspace/[id]/index.tsx +++ b/packages/console/app/src/routes/workspace/[id]/index.tsx @@ -1,22 +1,32 @@ +import { Show, createMemo } from "solid-js" +import { createStore } from "solid-js/store" +import { createAsync, useParams, useAction, useSubmission } from "@solidjs/router" import { NewUserSection } from "./new-user-section" import { UsageSection } from "./usage-section" import { ModelSection } from "./model-section" import { ProviderSection } from "./provider-section" import { IconLogo } from "~/component/icon" -import { createAsync, useParams, useAction, useSubmission } from "@solidjs/router" -import { querySessionInfo, queryBillingInfo, createCheckoutUrl } from "../common" -import { Show, createMemo } from "solid-js" +import { querySessionInfo, queryBillingInfo, createCheckoutUrl, formatBalance } from "../common" export default function () { const params = useParams() const userInfo = createAsync(() => querySessionInfo(params.id)) const billingInfo = createAsync(() => queryBillingInfo(params.id)) - const createCheckoutUrlAction = useAction(createCheckoutUrl) - const createCheckoutUrlSubmission = useSubmission(createCheckoutUrl) - - const balanceAmount = createMemo(() => { - return ((billingInfo()?.balance ?? 0) / 100000000).toFixed(2) + const checkoutAction = useAction(createCheckoutUrl) + const checkoutSubmission = useSubmission(createCheckoutUrl) + const [store, setStore] = createStore({ + checkoutRedirecting: false, }) + const balance = createMemo(() => formatBalance(billingInfo()?.balance ?? 0)) + + async function onClickCheckout() { + const baseUrl = window.location.href + const checkout = await checkoutAction(params.id, billingInfo()!.reloadAmount, baseUrl, baseUrl) + if (checkout && checkout.data) { + setStore("checkoutRedirecting", true) + window.location.href = checkout.data + } + } return (
@@ -38,21 +48,17 @@ export default function () { } > - Current balance ${balanceAmount() === "-0.00" ? "0.00" : balanceAmount()} + Current balance ${balance()} diff --git a/packages/console/app/src/routes/workspace/common.tsx b/packages/console/app/src/routes/workspace/common.tsx index 69bfebe9..5b638192 100644 --- a/packages/console/app/src/routes/workspace/common.tsx +++ b/packages/console/app/src/routes/workspace/common.tsx @@ -1,6 +1,6 @@ import { Resource } from "@opencode-ai/console-resource" import { Actor } from "@opencode-ai/console-core/actor.js" -import { action, query } from "@solidjs/router" +import { action, json, query } from "@solidjs/router" import { withActor } from "~/context/auth.withActor" import { Billing } from "@opencode-ai/console-core/billing.js" import { User } from "@opencode-ai/console-core/user.js" @@ -34,6 +34,11 @@ export function formatDateUTC(date: Date) { return date.toLocaleDateString("en-US", options) } +export function formatBalance(amount: number) { + const balance = ((amount ?? 0) / 100000000).toFixed(2) + return balance === "-0.00" ? "0.00" : balance +} + export async function getLastSeenWorkspaceID() { "use server" return withActor(async () => { @@ -71,14 +76,34 @@ export const querySessionInfo = query(async (workspaceID: string) => { }, "session.get") export const createCheckoutUrl = action( - async (workspaceID: string, successUrl: string, cancelUrl: string) => { + async (workspaceID: string, amount: number, successUrl: string, cancelUrl: string) => { "use server" - return withActor(() => Billing.generateCheckoutUrl({ successUrl, cancelUrl }), workspaceID) + return json( + await withActor( + () => + Billing.generateCheckoutUrl({ amount, successUrl, cancelUrl }) + .then((data) => ({ error: undefined, data })) + .catch((e) => ({ + error: e.message as string, + data: undefined, + })), + workspaceID, + ), + ) }, "checkoutUrl", ) export const queryBillingInfo = query(async (workspaceID: string) => { "use server" - return withActor(() => Billing.get(), workspaceID) + return withActor(async () => { + const billing = await Billing.get() + return { + ...billing, + reloadAmount: billing.reloadAmount ?? Billing.RELOAD_AMOUNT, + reloadAmountMin: Billing.RELOAD_AMOUNT_MIN, + reloadTrigger: billing.reloadTrigger ?? Billing.RELOAD_TRIGGER, + reloadTriggerMin: Billing.RELOAD_TRIGGER_MIN, + } + }, workspaceID) }, "billing.get") diff --git a/packages/console/app/src/routes/zen/util/handler.ts b/packages/console/app/src/routes/zen/util/handler.ts index 0d46e858..deab7ded 100644 --- a/packages/console/app/src/routes/zen/util/handler.ts +++ b/packages/console/app/src/routes/zen/util/handler.ts @@ -281,6 +281,7 @@ export async function handler( monthlyLimit: BillingTable.monthlyLimit, monthlyUsage: BillingTable.monthlyUsage, timeMonthlyUsageUpdated: BillingTable.timeMonthlyUsageUpdated, + reloadTrigger: BillingTable.reloadTrigger, }, user: { id: UserTable.id, @@ -532,7 +533,10 @@ export async function handler( and( eq(BillingTable.workspaceID, authInfo.workspaceID), eq(BillingTable.reload, true), - lt(BillingTable.balance, centsToMicroCents(Billing.CHARGE_THRESHOLD)), + lt( + BillingTable.balance, + centsToMicroCents((authInfo.billing.reloadTrigger ?? Billing.RELOAD_TRIGGER) * 100), + ), or( isNull(BillingTable.timeReloadLockedTill), lt(BillingTable.timeReloadLockedTill, sql`now()`), diff --git a/packages/console/core/src/billing.ts b/packages/console/core/src/billing.ts index 70bf1bc3..34871814 100644 --- a/packages/console/core/src/billing.ts +++ b/packages/console/core/src/billing.ts @@ -10,13 +10,12 @@ import { centsToMicroCents } from "./util/price" import { User } from "./user" export namespace Billing { - export const CHARGE_NAME = "opencode credits" - export const CHARGE_FEE_NAME = "processing fee" - export const CHARGE_AMOUNT = 2000 // $20 - export const CHARGE_AMOUNT_DOLLAR = 20 - export const CHARGE_FEE = 123 // Stripe fee 4.4% + $0.30 - export const CHARGE_THRESHOLD_DOLLAR = 5 - export const CHARGE_THRESHOLD = 500 // $5 + export const ITEM_CREDIT_NAME = "opencode credits" + export const ITEM_FEE_NAME = "processing fee" + export const RELOAD_AMOUNT = 20 + export const RELOAD_AMOUNT_MIN = 10 + export const RELOAD_TRIGGER = 5 + export const RELOAD_TRIGGER_MIN = 5 export const stripe = () => new Stripe(Resource.STRIPE_SECRET_KEY.value, { apiVersion: "2025-03-31.basil", @@ -33,6 +32,8 @@ export namespace Billing { paymentMethodLast4: BillingTable.paymentMethodLast4, balance: BillingTable.balance, reload: BillingTable.reload, + reloadAmount: BillingTable.reloadAmount, + reloadTrigger: BillingTable.reloadTrigger, monthlyLimit: BillingTable.monthlyLimit, monthlyUsage: BillingTable.monthlyUsage, timeMonthlyUsageUpdated: BillingTable.timeMonthlyUsageUpdated, @@ -67,17 +68,28 @@ export namespace Billing { ) } + export const calculateFeeInCents = (x: number) => { + // math: x = total - (total * 0.044 + 0.30) + // math: x = total * (1-0.044) - 0.30 + // math: (x + 0.30) / 0.956 = total + return Math.round(((x + 30) / 0.956) * 0.044 + 30) + } + export const reload = async () => { - const { customerID, paymentMethodID } = await Database.use((tx) => + const billing = await Database.use((tx) => tx .select({ customerID: BillingTable.customerID, paymentMethodID: BillingTable.paymentMethodID, + reloadAmount: BillingTable.reloadAmount, }) .from(BillingTable) .where(eq(BillingTable.workspaceID, Actor.workspace())) .then((rows) => rows[0]), ) + const customerID = billing.customerID + const paymentMethodID = billing.paymentMethodID + const amountInCents = (billing.reloadAmount ?? Billing.RELOAD_AMOUNT) * 100 const paymentID = Identifier.create("payment") let invoice try { @@ -89,18 +101,18 @@ export namespace Billing { currency: "usd", }) await Billing.stripe().invoiceItems.create({ - amount: Billing.CHARGE_AMOUNT, + amount: amountInCents, currency: "usd", customer: customerID!, - description: CHARGE_NAME, invoice: draft.id!, + description: ITEM_CREDIT_NAME, }) await Billing.stripe().invoiceItems.create({ - amount: Billing.CHARGE_FEE, + amount: calculateFeeInCents(amountInCents), currency: "usd", customer: customerID!, - description: CHARGE_FEE_NAME, invoice: draft.id!, + description: ITEM_FEE_NAME, }) await Billing.stripe().invoices.finalizeInvoice(draft.id!) invoice = await Billing.stripe().invoices.pay(draft.id!, { @@ -128,7 +140,7 @@ export namespace Billing { await tx .update(BillingTable) .set({ - balance: sql`${BillingTable.balance} + ${centsToMicroCents(CHARGE_AMOUNT)}`, + balance: sql`${BillingTable.balance} + ${centsToMicroCents(amountInCents)}`, reloadError: null, timeReloadError: null, }) @@ -136,7 +148,7 @@ export namespace Billing { await tx.insert(PaymentTable).values({ workspaceID: Actor.workspace(), id: paymentID, - amount: centsToMicroCents(CHARGE_AMOUNT), + amount: centsToMicroCents(amountInCents), invoiceID: invoice.id!, paymentID: invoice.payments?.data[0].payment.payment_intent as string, customerID, @@ -159,13 +171,19 @@ export namespace Billing { z.object({ successUrl: z.string(), cancelUrl: z.string(), + amount: z.number().optional(), }), async (input) => { const user = Actor.assert("user") - const { successUrl, cancelUrl } = input + const { successUrl, cancelUrl, amount } = input + + if (amount !== undefined && amount < Billing.RELOAD_AMOUNT_MIN) { + throw new Error(`Amount must be at least $${Billing.RELOAD_AMOUNT_MIN}`) + } const email = await User.getAuthEmail(user.properties.userID) const customer = await Billing.get() + const amountInCents = (amount ?? customer.reloadAmount ?? Billing.RELOAD_AMOUNT) * 100 const session = await Billing.stripe().checkout.sessions.create({ mode: "payment", billing_address_collection: "required", @@ -173,20 +191,16 @@ export namespace Billing { { price_data: { currency: "usd", - product_data: { - name: CHARGE_NAME, - }, - unit_amount: CHARGE_AMOUNT, + product_data: { name: ITEM_CREDIT_NAME }, + unit_amount: amountInCents, }, quantity: 1, }, { price_data: { currency: "usd", - product_data: { - name: CHARGE_FEE_NAME, - }, - unit_amount: CHARGE_FEE, + product_data: { name: ITEM_FEE_NAME }, + unit_amount: calculateFeeInCents(amountInCents), }, quantity: 1, }, @@ -218,6 +232,7 @@ export namespace Billing { }, metadata: { workspaceID: Actor.workspace(), + amount: amountInCents.toString(), }, success_url: successUrl, cancel_url: cancelUrl, From 9fb49ab87b4fbf3890ef6db80602abbbe517f176 Mon Sep 17 00:00:00 2001 From: Frank Date: Tue, 4 Nov 2025 17:14:31 -0500 Subject: [PATCH 005/218] wip: zen --- .../src/routes/workspace/[id]/billing/reload-section.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/console/app/src/routes/workspace/[id]/billing/reload-section.tsx b/packages/console/app/src/routes/workspace/[id]/billing/reload-section.tsx index 57267a95..50d00ef3 100644 --- a/packages/console/app/src/routes/workspace/[id]/billing/reload-section.tsx +++ b/packages/console/app/src/routes/workspace/[id]/billing/reload-section.tsx @@ -182,8 +182,8 @@ export function ReloadSection() {
-
- + +

Reload failed at{" "} @@ -204,8 +204,8 @@ export function ReloadSection() {

- -
+
+
) } From 16e2bded5b9c47ac6e05c7623ae0800921874f0e Mon Sep 17 00:00:00 2001 From: Frank Date: Tue, 4 Nov 2025 17:24:18 -0500 Subject: [PATCH 006/218] wip: zen --- .../routes/workspace/[id]/billing/monthly-limit-section.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/console/app/src/routes/workspace/[id]/billing/monthly-limit-section.tsx b/packages/console/app/src/routes/workspace/[id]/billing/monthly-limit-section.tsx index b28b072d..e6461ac8 100644 --- a/packages/console/app/src/routes/workspace/[id]/billing/monthly-limit-section.tsx +++ b/packages/console/app/src/routes/workspace/[id]/billing/monthly-limit-section.tsx @@ -62,7 +62,7 @@ export function MonthlyLimitSection() {

Monthly Limit

-

Set a monthly spending limit for your account.

+

Set a monthly usage limit for your account.

@@ -106,7 +106,7 @@ export function MonthlyLimitSection() {
No spending limit set.

} + fallback={

No usage limit set.

} >

Current usage for{" "} From ee9aa24a554f356529d3dcb32b702be8adf555b1 Mon Sep 17 00:00:00 2001 From: Jay V Date: Tue, 4 Nov 2025 17:27:13 -0500 Subject: [PATCH 007/218] ignore: update meta description to use proper OpenCode capitalization --- packages/console/app/src/app.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/console/app/src/app.tsx b/packages/console/app/src/app.tsx index bc396121..7976f6b3 100644 --- a/packages/console/app/src/app.tsx +++ b/packages/console/app/src/app.tsx @@ -12,7 +12,10 @@ export default function App() { root={(props) => ( opencode - + {props.children} )} From d3e080894ca9eb6432fb93d85d2e74d230921e14 Mon Sep 17 00:00:00 2001 From: Frank Date: Tue, 4 Nov 2025 17:54:06 -0500 Subject: [PATCH 008/218] wip: zen --- packages/console/app/src/routes/workspace/[id]/model-section.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/console/app/src/routes/workspace/[id]/model-section.tsx b/packages/console/app/src/routes/workspace/[id]/model-section.tsx index 964f7dac..223d69fc 100644 --- a/packages/console/app/src/routes/workspace/[id]/model-section.tsx +++ b/packages/console/app/src/routes/workspace/[id]/model-section.tsx @@ -31,6 +31,7 @@ const getModelsInfo = query(async (workspaceID: string) => { return { all: Object.entries(ZenData.list().models) .filter(([id, _model]) => !["claude-3-5-haiku", "minimax-m2"].includes(id)) + .filter(([id, _model]) => !id.startsWith("an-")) .sort(([_idA, modelA], [_idB, modelB]) => modelA.name.localeCompare(modelB.name)) .map(([id, model]) => ({ id, name: model.name })), disabled: await Model.listDisabled(), From 01b9148c04d9812c43843b867c1a9ded8f186a68 Mon Sep 17 00:00:00 2001 From: Aiden Cline Date: Tue, 4 Nov 2025 17:29:27 -0600 Subject: [PATCH 009/218] fix: image reading error, also add error toast for event bus --- packages/opencode/src/cli/cmd/tui/app.tsx | 21 +++++++ packages/opencode/src/session/prompt.ts | 76 +++++++++++++++-------- 2 files changed, 72 insertions(+), 25 deletions(-) diff --git a/packages/opencode/src/cli/cmd/tui/app.tsx b/packages/opencode/src/cli/cmd/tui/app.tsx index e57ef8cd..1fba51cb 100644 --- a/packages/opencode/src/cli/cmd/tui/app.tsx +++ b/packages/opencode/src/cli/cmd/tui/app.tsx @@ -367,6 +367,27 @@ function App() { } }) + event.on(SessionApi.Event.Error.type, (evt) => { + const error = evt.properties.error + const message = (() => { + if (!error) return "An error occured" + + if (typeof error === "object") { + const data = error.data + if ("message" in data && typeof data.message === "string") { + return data.message + } + } + return String(error) + })() + + toast.show({ + variant: "error", + message, + duration: 5000, + }) + }) + return ( - t.execute(args, { - sessionID: input.sessionID, - abort: new AbortController().signal, - agent: input.agent!, - messageID: info.id, - extra: { bypassCwdCheck: true }, - metadata: async () => {}, - }), - ) - return [ + + const pieces: MessageV2.Part[] = [ { id: Identifier.ascending("part"), messageID: info.id, @@ -754,21 +746,55 @@ export namespace SessionPrompt { synthetic: true, text: `Called the Read tool with the following input: ${JSON.stringify(args)}`, }, - { - id: Identifier.ascending("part"), - messageID: info.id, - sessionID: input.sessionID, - type: "text", - synthetic: true, - text: result.output, - }, - { - ...part, - id: part.id ?? Identifier.ascending("part"), - messageID: info.id, - sessionID: input.sessionID, - }, ] + + await ReadTool.init() + .then(async (t) => { + const result = await t.execute(args, { + sessionID: input.sessionID, + abort: new AbortController().signal, + agent: input.agent!, + messageID: info.id, + extra: { bypassCwdCheck: true }, + metadata: async () => {}, + }) + pieces.push( + { + id: Identifier.ascending("part"), + messageID: info.id, + sessionID: input.sessionID, + type: "text", + synthetic: true, + text: result.output, + }, + { + ...part, + id: part.id ?? Identifier.ascending("part"), + messageID: info.id, + sessionID: input.sessionID, + }, + ) + }) + .catch((error) => { + log.error("failed to read file", { error }) + const message = error instanceof Error ? error.message : error.toString() + Bus.publish(Session.Event.Error, { + sessionID: input.sessionID, + error: new NamedError.Unknown({ + message, + }).toObject(), + }) + pieces.push({ + id: Identifier.ascending("part"), + messageID: info.id, + sessionID: input.sessionID, + type: "text", + synthetic: true, + text: `Read tool failed to read ${filepath} with the following error: ${message}`, + }) + }) + + return pieces } if (part.mime === "application/x-directory") { From ebca25462edcf535b055e00f3476187646c9f8cb Mon Sep 17 00:00:00 2001 From: Dax Raad Date: Tue, 4 Nov 2025 18:45:39 -0500 Subject: [PATCH 010/218] tui: fix session abort when autocomplete is visible --- packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx b/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx index cf497407..349026e9 100644 --- a/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx +++ b/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx @@ -161,6 +161,7 @@ export function Prompt(props: PromptProps) { onSelect: (dialog) => { if (!props.sessionID) return if (autocomplete.visible) return + if (!input.focused) return sdk.client.session.abort({ path: { id: props.sessionID, From f51bd91af49fcc3339c11a86a463fc7d7e2489b2 Mon Sep 17 00:00:00 2001 From: opencode Date: Wed, 5 Nov 2025 00:12:19 +0000 Subject: [PATCH 011/218] release: v1.0.24 --- bun.lock | 22 +++++++++++----------- packages/console/app/package.json | 2 +- packages/console/core/package.json | 2 +- packages/console/function/package.json | 2 +- packages/console/mail/package.json | 2 +- packages/desktop/package.json | 2 +- packages/function/package.json | 2 +- packages/opencode/package.json | 2 +- packages/plugin/package.json | 2 +- packages/sdk/js/package.json | 2 +- packages/slack/package.json | 2 +- packages/ui/package.json | 2 +- packages/web/package.json | 2 +- sdks/vscode/package.json | 2 +- 14 files changed, 24 insertions(+), 24 deletions(-) diff --git a/bun.lock b/bun.lock index e18ad950..53ed347d 100644 --- a/bun.lock +++ b/bun.lock @@ -39,7 +39,7 @@ }, "packages/console/core": { "name": "@opencode-ai/console-core", - "version": "1.0.23", + "version": "1.0.24", "dependencies": { "@aws-sdk/client-sts": "3.782.0", "@jsx-email/render": "1.1.1", @@ -66,7 +66,7 @@ }, "packages/console/function": { "name": "@opencode-ai/console-function", - "version": "1.0.23", + "version": "1.0.24", "dependencies": { "@ai-sdk/anthropic": "2.0.0", "@ai-sdk/openai": "2.0.2", @@ -90,7 +90,7 @@ }, "packages/console/mail": { "name": "@opencode-ai/console-mail", - "version": "1.0.23", + "version": "1.0.24", "dependencies": { "@jsx-email/all": "2.2.3", "@jsx-email/cli": "1.4.3", @@ -111,7 +111,7 @@ }, "packages/desktop": { "name": "@opencode-ai/desktop", - "version": "1.0.23", + "version": "1.0.24", "dependencies": { "@kobalte/core": "catalog:", "@opencode-ai/sdk": "workspace:*", @@ -150,7 +150,7 @@ }, "packages/function": { "name": "@opencode-ai/function", - "version": "1.0.23", + "version": "1.0.24", "dependencies": { "@octokit/auth-app": "8.0.1", "@octokit/rest": "22.0.0", @@ -166,7 +166,7 @@ }, "packages/opencode": { "name": "opencode", - "version": "1.0.23", + "version": "1.0.24", "bin": { "opencode": "./bin/opencode", }, @@ -243,7 +243,7 @@ }, "packages/plugin": { "name": "@opencode-ai/plugin", - "version": "1.0.23", + "version": "1.0.24", "dependencies": { "@opencode-ai/sdk": "workspace:*", "zod": "catalog:", @@ -263,7 +263,7 @@ }, "packages/sdk/js": { "name": "@opencode-ai/sdk", - "version": "1.0.23", + "version": "1.0.24", "devDependencies": { "@hey-api/openapi-ts": "0.81.0", "@tsconfig/node22": "catalog:", @@ -274,7 +274,7 @@ }, "packages/slack": { "name": "@opencode-ai/slack", - "version": "1.0.23", + "version": "1.0.24", "dependencies": { "@opencode-ai/sdk": "workspace:*", "@slack/bolt": "^3.17.1", @@ -287,7 +287,7 @@ }, "packages/ui": { "name": "@opencode-ai/ui", - "version": "1.0.23", + "version": "1.0.24", "dependencies": { "@kobalte/core": "catalog:", "@opencode-ai/sdk": "workspace:*", @@ -317,7 +317,7 @@ }, "packages/web": { "name": "@opencode-ai/web", - "version": "1.0.23", + "version": "1.0.24", "dependencies": { "@astrojs/cloudflare": "12.6.3", "@astrojs/markdown-remark": "6.3.1", diff --git a/packages/console/app/package.json b/packages/console/app/package.json index 7e06d824..a367a679 100644 --- a/packages/console/app/package.json +++ b/packages/console/app/package.json @@ -7,7 +7,7 @@ "dev:remote": "VITE_AUTH_URL=https://auth.dev.opencode.ai bun sst shell --stage=dev bun dev", "build": "vinxi build && ../../opencode/script/schema.ts ./.output/public/config.json", "start": "vinxi start", - "version": "1.0.23" + "version": "1.0.24" }, "dependencies": { "@ibm/plex": "6.4.1", diff --git a/packages/console/core/package.json b/packages/console/core/package.json index c1ab2347..738c41e7 100644 --- a/packages/console/core/package.json +++ b/packages/console/core/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@opencode-ai/console-core", - "version": "1.0.23", + "version": "1.0.24", "private": true, "type": "module", "dependencies": { diff --git a/packages/console/function/package.json b/packages/console/function/package.json index 0c6e0288..b014e441 100644 --- a/packages/console/function/package.json +++ b/packages/console/function/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/console-function", - "version": "1.0.23", + "version": "1.0.24", "$schema": "https://json.schemastore.org/package.json", "private": true, "type": "module", diff --git a/packages/console/mail/package.json b/packages/console/mail/package.json index 30e772b6..3355d754 100644 --- a/packages/console/mail/package.json +++ b/packages/console/mail/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/console-mail", - "version": "1.0.23", + "version": "1.0.24", "dependencies": { "@jsx-email/all": "2.2.3", "@jsx-email/cli": "1.4.3", diff --git a/packages/desktop/package.json b/packages/desktop/package.json index 34188445..d74dd95b 100644 --- a/packages/desktop/package.json +++ b/packages/desktop/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/desktop", - "version": "1.0.23", + "version": "1.0.24", "description": "", "type": "module", "scripts": { diff --git a/packages/function/package.json b/packages/function/package.json index eeb842ca..a001b92c 100644 --- a/packages/function/package.json +++ b/packages/function/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/function", - "version": "1.0.23", + "version": "1.0.24", "$schema": "https://json.schemastore.org/package.json", "private": true, "type": "module", diff --git a/packages/opencode/package.json b/packages/opencode/package.json index 3e4f5c02..841f972b 100644 --- a/packages/opencode/package.json +++ b/packages/opencode/package.json @@ -1,6 +1,6 @@ { "$schema": "https://json.schemastore.org/package.json", - "version": "1.0.23", + "version": "1.0.24", "name": "opencode", "type": "module", "private": true, diff --git a/packages/plugin/package.json b/packages/plugin/package.json index 0ad4afe6..ec0ca9ac 100644 --- a/packages/plugin/package.json +++ b/packages/plugin/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@opencode-ai/plugin", - "version": "1.0.23", + "version": "1.0.24", "type": "module", "scripts": { "typecheck": "tsgo --noEmit", diff --git a/packages/sdk/js/package.json b/packages/sdk/js/package.json index d4de9ca1..8e4b5b6a 100644 --- a/packages/sdk/js/package.json +++ b/packages/sdk/js/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@opencode-ai/sdk", - "version": "1.0.23", + "version": "1.0.24", "type": "module", "scripts": { "typecheck": "tsgo --noEmit", diff --git a/packages/slack/package.json b/packages/slack/package.json index f9392ef3..9de763e6 100644 --- a/packages/slack/package.json +++ b/packages/slack/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/slack", - "version": "1.0.23", + "version": "1.0.24", "type": "module", "scripts": { "dev": "bun run src/index.ts", diff --git a/packages/ui/package.json b/packages/ui/package.json index 585a249b..6f5dd1e9 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/ui", - "version": "1.0.23", + "version": "1.0.24", "type": "module", "exports": { ".": "./src/components/index.ts", diff --git a/packages/web/package.json b/packages/web/package.json index 2de696b3..63d2b8e9 100644 --- a/packages/web/package.json +++ b/packages/web/package.json @@ -1,7 +1,7 @@ { "name": "@opencode-ai/web", "type": "module", - "version": "1.0.23", + "version": "1.0.24", "scripts": { "dev": "astro dev", "dev:remote": "VITE_API_URL=https://api.opencode.ai astro dev", diff --git a/sdks/vscode/package.json b/sdks/vscode/package.json index 6a8ed497..ec4902ea 100644 --- a/sdks/vscode/package.json +++ b/sdks/vscode/package.json @@ -2,7 +2,7 @@ "name": "opencode", "displayName": "opencode", "description": "opencode for VS Code", - "version": "1.0.23", + "version": "1.0.24", "publisher": "sst-dev", "repository": { "type": "git", From 04546c0873b6c379b9a4c92b7301249eea009b0b Mon Sep 17 00:00:00 2001 From: Kyle F Butts Date: Tue, 4 Nov 2025 18:18:33 -0600 Subject: [PATCH 012/218] Add support for `R formatter` in formatters (#3918) Co-authored-by: Aiden Cline --- packages/opencode/src/bun/index.ts | 5 ++- packages/opencode/src/format/formatter.ts | 44 +++++++++++++++++++- packages/opencode/src/format/index.ts | 1 + packages/web/src/content/docs/formatters.mdx | 1 + 4 files changed, 49 insertions(+), 2 deletions(-) diff --git a/packages/opencode/src/bun/index.ts b/packages/opencode/src/bun/index.ts index 5f184727..2a8b48ef 100644 --- a/packages/opencode/src/bun/index.ts +++ b/packages/opencode/src/bun/index.ts @@ -8,7 +8,10 @@ import { readableStreamToText } from "bun" export namespace BunProc { const log = Log.create({ service: "bun" }) - export async function run(cmd: string[], options?: Bun.SpawnOptions.OptionsObject) { + export async function run( + cmd: string[], + options?: Bun.SpawnOptions.OptionsObject, + ) { log.info("running", { cmd: [which(), ...cmd], ...options, diff --git a/packages/opencode/src/format/formatter.ts b/packages/opencode/src/format/formatter.ts index baa39906..a8b8e9de 100644 --- a/packages/opencode/src/format/formatter.ts +++ b/packages/opencode/src/format/formatter.ts @@ -1,3 +1,4 @@ +import { readableStreamToText } from "bun" import { BunProc } from "../bun" import { Instance } from "../project/instance" import { Filesystem } from "../util/filesystem" @@ -131,7 +132,21 @@ export const zig: Info = { export const clang: Info = { name: "clang-format", command: ["clang-format", "-i", "$FILE"], - extensions: [".c", ".cc", ".cpp", ".cxx", ".c++", ".h", ".hh", ".hpp", ".hxx", ".h++", ".ino", ".C", ".H"], + extensions: [ + ".c", + ".cc", + ".cpp", + ".cxx", + ".c++", + ".h", + ".hh", + ".hpp", + ".hxx", + ".h++", + ".ino", + ".C", + ".H", + ], async enabled() { const items = await Filesystem.findUp(".clang-format", Instance.directory, Instance.worktree) return items.length > 0 @@ -177,6 +192,33 @@ export const ruff: Info = { }, } +export const rlang: Info = { + name: "air", + command: ["air", "format", "$FILE"], + extensions: [".R"], + async enabled() { + const airPath = Bun.which("air") + if (airPath == null) return false + + try { + const proc = Bun.spawn(["air", "--help"], { + stdout: "pipe", + stderr: "pipe", + }) + await proc.exited + const output = await readableStreamToText(proc.stdout) + + // Check for "Air: An R language server and formatter" + const firstLine = output.split("\n")[0] + const hasR = firstLine.includes("R language") + const hasFormatter = firstLine.includes("formatter") + return hasR && hasFormatter + } catch (error) { + return false + } + }, +} + export const uvformat: Info = { name: "uv format", command: ["uv", "format", "--", "$FILE"], diff --git a/packages/opencode/src/format/index.ts b/packages/opencode/src/format/index.ts index b4294093..e307496c 100644 --- a/packages/opencode/src/format/index.ts +++ b/packages/opencode/src/format/index.ts @@ -69,6 +69,7 @@ export namespace Format { log.info("checking", { name: item.name, ext }) if (!item.extensions.includes(ext)) continue if (!(await isEnabled(item))) continue + log.info("enabled", { name: item.name, ext }) result.push(item) } return result diff --git a/packages/web/src/content/docs/formatters.mdx b/packages/web/src/content/docs/formatters.mdx index 4b46a4f6..9fc41a53 100644 --- a/packages/web/src/content/docs/formatters.mdx +++ b/packages/web/src/content/docs/formatters.mdx @@ -25,6 +25,7 @@ OpenCode comes with several built-in formatters for popular languages and framew | rubocop | .rb, .rake, .gemspec, .ru | `rubocop` command available | | standardrb | .rb, .rake, .gemspec, .ru | `standardrb` command available | | htmlbeautifier | .erb, .html.erb | `htmlbeautifier` command available | +| air | .R | `air` command available | So if your project has `prettier` in your `package.json`, OpenCode will automatically use it. From 234db24f1f995d680d2e33002f13b03b1eacba79 Mon Sep 17 00:00:00 2001 From: Dax Raad Date: Tue, 4 Nov 2025 20:46:01 -0500 Subject: [PATCH 013/218] tui: fix command validation to prevent invalid commands from being executed --- .../src/cli/cmd/tui/component/prompt/index.tsx | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx b/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx index 349026e9..d66b8e0a 100644 --- a/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx +++ b/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx @@ -28,6 +28,7 @@ import { useExit } from "../../context/exit" import { Clipboard } from "../../util/clipboard" import type { FilePart } from "@opencode-ai/sdk" import { TuiEvent } from "../../event" +import { iife } from "@/util/iife" export type PromptProps = { sessionID?: string @@ -363,8 +364,15 @@ export function Prompt(props: PromptProps) { }, }) setStore("mode", "normal") - } else if (inputText.startsWith("/")) { - const [command, ...args] = inputText.split(" ") + } else if ( + inputText.startsWith("/") && + iife(() => { + const command = inputText.split(" ")[0].slice(1) + console.log(command) + return sync.data.command.some((x) => x.name === command) + }) + ) { + let [command, ...args] = inputText.split(" ") sdk.client.session.command({ path: { id: sessionID, From 3b1ab444fdbae7f62e5e0d8d226a4a9b63396d5f Mon Sep 17 00:00:00 2001 From: Err Date: Tue, 4 Nov 2025 22:47:05 -0600 Subject: [PATCH 014/218] feat: add Clojure syntax highlighting support (#3912) Co-authored-by: opencode-agent[bot] Co-authored-by: rekram1-node --- packages/opencode/parsers-config.ts | 9 +++++++++ packages/opencode/src/lsp/language.ts | 3 +++ 2 files changed, 12 insertions(+) diff --git a/packages/opencode/parsers-config.ts b/packages/opencode/parsers-config.ts index cfa00454..ef149524 100644 --- a/packages/opencode/parsers-config.ts +++ b/packages/opencode/parsers-config.ts @@ -203,5 +203,14 @@ export default { ], }, }, + { + filetype: "clojure", + wasm: "https://github.com/sogaiu/tree-sitter-clojure/releases/download/v0.0.13/tree-sitter-clojure.wasm", + queries: { + highlights: [ + "https://raw.githubusercontent.com/nvim-treesitter/nvim-treesitter/refs/heads/master/queries/clojure/highlights.scm", + ], + }, + }, ], } diff --git a/packages/opencode/src/lsp/language.ts b/packages/opencode/src/lsp/language.ts index b7bcd8e9..7980f05e 100644 --- a/packages/opencode/src/lsp/language.ts +++ b/packages/opencode/src/lsp/language.ts @@ -4,6 +4,9 @@ export const LANGUAGE_EXTENSIONS: Record = { ".bib": "bibtex", ".bibtex": "bibtex", ".clj": "clojure", + ".cljs": "clojure", + ".cljc": "clojure", + ".edn": "clojure", ".coffee": "coffeescript", ".c": "c", ".cpp": "cpp", From b90c0b5facae4b8690e1d1ca3efe8e8e4e7ec5f2 Mon Sep 17 00:00:00 2001 From: Christian Stewart Date: Tue, 4 Nov 2025 21:02:45 -0800 Subject: [PATCH 015/218] feat(tui): add /export and /copy commands (#3883) Signed-off-by: Christian Stewart --- .../cmd/tui/component/prompt/autocomplete.tsx | 10 ++ .../src/cli/cmd/tui/routes/session/index.tsx | 102 ++++++++++++++++++ 2 files changed, 112 insertions(+) diff --git a/packages/opencode/src/cli/cmd/tui/component/prompt/autocomplete.tsx b/packages/opencode/src/cli/cmd/tui/component/prompt/autocomplete.tsx index a4c1f33d..172ae8a0 100644 --- a/packages/opencode/src/cli/cmd/tui/component/prompt/autocomplete.tsx +++ b/packages/opencode/src/cli/cmd/tui/component/prompt/autocomplete.tsx @@ -243,6 +243,16 @@ export function Autocomplete(props: { description: "rename session", onSelect: () => command.trigger("session.rename"), }, + { + display: "/copy", + description: "copy session transcript to clipboard", + onSelect: () => command.trigger("session.copy"), + }, + { + display: "/export", + description: "export session transcript to file", + onSelect: () => command.trigger("session.export"), + }, { display: "/timeline", description: "jump to message", diff --git a/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx b/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx index ccd12819..9fa844b7 100644 --- a/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx +++ b/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx @@ -65,6 +65,9 @@ import parsers from "../../../../../../parsers-config.ts" import { Clipboard } from "../../util/clipboard" import { Toast, useToast } from "../../ui/toast" import { useKV } from "../../context/kv.tsx" +import { Editor } from "../../util/editor" +import { Global } from "@/global" +import fs from "fs/promises" addDefaultParsers(parsers.parsers) @@ -446,6 +449,105 @@ export function Session() { dialog.clear() }, }, + { + title: "Copy session transcript", + value: "session.copy", + keybind: "session_copy", + category: "Session", + onSelect: async (dialog) => { + try { + // Format session transcript as markdown + const sessionData = session() + const sessionMessages = messages() + + let transcript = `# ${sessionData.title}\n\n` + transcript += `**Session ID:** ${sessionData.id}\n` + transcript += `**Created:** ${new Date(sessionData.time.created).toLocaleString()}\n` + transcript += `**Updated:** ${new Date(sessionData.time.updated).toLocaleString()}\n\n` + transcript += `---\n\n` + + for (const msg of sessionMessages) { + const parts = sync.data.part[msg.id] ?? [] + const role = msg.role === "user" ? "User" : "Assistant" + transcript += `## ${role}\n\n` + + for (const part of parts) { + if (part.type === "text" && !part.synthetic) { + transcript += `${part.text}\n\n` + } else if (part.type === "tool") { + transcript += `\`\`\`\nTool: ${part.tool}\n\`\`\`\n\n` + } + } + + transcript += `---\n\n` + } + + // Copy to clipboard + await Clipboard.copy(transcript) + toast.show({ message: "Session transcript copied to clipboard!", variant: "success" }) + } catch (error) { + toast.show({ message: "Failed to copy session transcript", variant: "error" }) + } + dialog.clear() + }, + }, + { + title: "Export session transcript to file", + value: "session.export", + keybind: "session_export", + category: "Session", + onSelect: async (dialog) => { + try { + // Format session transcript as markdown + const sessionData = session() + const sessionMessages = messages() + + let transcript = `# ${sessionData.title}\n\n` + transcript += `**Session ID:** ${sessionData.id}\n` + transcript += `**Created:** ${new Date(sessionData.time.created).toLocaleString()}\n` + transcript += `**Updated:** ${new Date(sessionData.time.updated).toLocaleString()}\n\n` + transcript += `---\n\n` + + for (const msg of sessionMessages) { + const parts = sync.data.part[msg.id] ?? [] + const role = msg.role === "user" ? "User" : "Assistant" + transcript += `## ${role}\n\n` + + for (const part of parts) { + if (part.type === "text" && !part.synthetic) { + transcript += `${part.text}\n\n` + } else if (part.type === "tool") { + transcript += `\`\`\`\nTool: ${part.tool}\n\`\`\`\n\n` + } + } + + transcript += `---\n\n` + } + + // Save to file in data directory + const exportDir = path.join(Global.Path.data, "exports") + await fs.mkdir(exportDir, { recursive: true }) + + const timestamp = new Date().toISOString().replace(/[:.]/g, "-") + const filename = `session-${sessionData.id.slice(0, 8)}-${timestamp}.md` + const filepath = path.join(exportDir, filename) + + await Bun.write(filepath, transcript) + + // Open with EDITOR if available + const result = await Editor.open({ value: transcript, renderer }) + if (result !== undefined) { + // User edited the file, save the changes + await Bun.write(filepath, result) + } + + toast.show({ message: `Session exported to ${filename}`, variant: "success" }) + } catch (error) { + toast.show({ message: "Failed to export session", variant: "error" }) + } + dialog.clear() + }, + }, { title: "Next child session", value: "session.child.next", From 3ebec2435a4c9dd9b5080fbb1d2591a8836305b8 Mon Sep 17 00:00:00 2001 From: Aiden Cline Date: Tue, 4 Nov 2025 23:37:09 -0600 Subject: [PATCH 016/218] allow @ agents to work even if not first thing in prompt --- .../src/cli/cmd/tui/component/prompt/autocomplete.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/opencode/src/cli/cmd/tui/component/prompt/autocomplete.tsx b/packages/opencode/src/cli/cmd/tui/component/prompt/autocomplete.tsx index 172ae8a0..aea10bca 100644 --- a/packages/opencode/src/cli/cmd/tui/component/prompt/autocomplete.tsx +++ b/packages/opencode/src/cli/cmd/tui/component/prompt/autocomplete.tsx @@ -164,7 +164,6 @@ export function Autocomplete(props: { ) const agents = createMemo(() => { - if (store.index !== 0) return [] const agents = sync.data.agent return agents .filter((agent) => !agent.builtIn && agent.mode !== "primary") @@ -395,7 +394,9 @@ export function Autocomplete(props: { return } // Check if a space was typed after the trigger character - const currentText = props.input().getTextRange(store.index + 1, props.input().cursorOffset + 1) + const currentText = props + .input() + .getTextRange(store.index + 1, props.input().cursorOffset + 1) if (currentText.includes(" ")) { hide() } From 1e0596bc46fcd130257174e6691c74484391f905 Mon Sep 17 00:00:00 2001 From: Aiden Cline <63023139+rekram1-node@users.noreply.github.com> Date: Wed, 5 Nov 2025 00:50:48 -0600 Subject: [PATCH 017/218] ACP: update package, fix slash command bug (#3906) --- bun.lock | 4 +- packages/opencode/package.json | 4 +- packages/opencode/src/acp/agent.ts | 86 +++++++++++++++++++--------- packages/opencode/src/acp/session.ts | 7 ++- packages/opencode/src/acp/types.ts | 1 + packages/opencode/src/mcp/index.ts | 20 ++++++- 6 files changed, 87 insertions(+), 35 deletions(-) diff --git a/bun.lock b/bun.lock index 53ed347d..866ce447 100644 --- a/bun.lock +++ b/bun.lock @@ -173,7 +173,7 @@ "dependencies": { "@actions/core": "1.11.1", "@actions/github": "6.0.1", - "@agentclientprotocol/sdk": "0.4.9", + "@agentclientprotocol/sdk": "0.5.1", "@clack/prompts": "1.0.0-alpha.1", "@hono/standard-validator": "0.1.5", "@hono/zod-validator": "catalog:", @@ -401,7 +401,7 @@ "@adobe/css-tools": ["@adobe/css-tools@4.4.4", "", {}, "sha512-Elp+iwUx5rN5+Y8xLt5/GRoG20WGoDCQ/1Fb+1LiGtvwbDavuSk0jhD/eZdckHAuzcDzccnkv+rEjyWfRx18gg=="], - "@agentclientprotocol/sdk": ["@agentclientprotocol/sdk@0.4.9", "", { "dependencies": { "zod": "^3.0.0" } }, "sha512-ExwH828LaTGoTTjxuw49l+fwOLA+Yx0+qkWn1TcHMOsY5mVI9CUfkj7ZDhv2klgZ7mJeT+lxX/Dn/KINv1AkNQ=="], + "@agentclientprotocol/sdk": ["@agentclientprotocol/sdk@0.5.1", "", { "dependencies": { "zod": "^3.0.0" } }, "sha512-9bq2TgjhLBSUSC5jE04MEe+Hqw8YePzKghhYZ9QcjOyonY3q2oJfX6GoSO83hURpEnsqEPIrex6VZN3+61fBJg=="], "@ai-sdk/amazon-bedrock": ["@ai-sdk/amazon-bedrock@2.2.10", "", { "dependencies": { "@ai-sdk/provider": "1.1.3", "@ai-sdk/provider-utils": "2.2.8", "@smithy/eventstream-codec": "^4.0.1", "@smithy/util-utf8": "^4.0.0", "aws4fetch": "^1.0.20" }, "peerDependencies": { "zod": "^3.0.0" } }, "sha512-icLGO7Q0NinnHIPgT+y1QjHVwH4HwV+brWbvM+FfCG2Afpa89PyKa3Ret91kGjZpBgM/xnj1B7K5eM+rRlsXQA=="], diff --git a/packages/opencode/package.json b/packages/opencode/package.json index 841f972b..d9fe076f 100644 --- a/packages/opencode/package.json +++ b/packages/opencode/package.json @@ -43,7 +43,7 @@ "dependencies": { "@actions/core": "1.11.1", "@actions/github": "6.0.1", - "@agentclientprotocol/sdk": "0.4.9", + "@agentclientprotocol/sdk": "0.5.1", "@clack/prompts": "1.0.0-alpha.1", "@hono/standard-validator": "0.1.5", "@hono/zod-validator": "catalog:", @@ -57,8 +57,8 @@ "@opentui/core": "0.1.33", "@opentui/solid": "0.1.33", "@parcel/watcher": "2.5.1", - "@solid-primitives/event-bus": "1.1.2", "@pierre/precision-diffs": "catalog:", + "@solid-primitives/event-bus": "1.1.2", "@standard-schema/spec": "1.0.0", "@zip.js/zip.js": "2.7.62", "ai": "catalog:", diff --git a/packages/opencode/src/acp/agent.ts b/packages/opencode/src/acp/agent.ts index 1eae36e6..47bac4e5 100644 --- a/packages/opencode/src/acp/agent.ts +++ b/packages/opencode/src/acp/agent.ts @@ -1,9 +1,12 @@ import { + RequestError, type Agent as ACPAgent, type AgentSideConnection, type AuthenticateRequest, + type AuthMethod, type CancelNotification, type InitializeRequest, + type InitializeResponse, type LoadSessionRequest, type NewSessionRequest, type PermissionOption, @@ -33,6 +36,7 @@ import type { Config } from "@/config/config" import { MCP } from "@/mcp" import { Todo } from "@/session/todo" import { z } from "zod" +import { LoadAPIKeyError } from "ai" export namespace ACP { const log = Log.create({ service: "acp-agent" }) @@ -302,9 +306,26 @@ export namespace ACP { }) } - async initialize(params: InitializeRequest) { + async initialize(params: InitializeRequest): Promise { log.info("initialize", { protocolVersion: params.protocolVersion }) + const authMethod: AuthMethod = { + description: "Run `opencode auth login` in the terminal", + name: "Login with opencode", + id: "opencode-login", + } + + // If client supports terminal-auth capability, use that instead. + if (params.clientCapabilities?._meta?.["terminal-auth"] === true) { + authMethod._meta = { + "terminal-auth": { + command: "opencode", + args: ["auth", "login"], + label: "OpenCode Login", + }, + } + } + return { protocolVersion: 1, agentCapabilities: { @@ -325,10 +346,9 @@ export namespace ACP { id: "opencode-login", }, ], - _meta: { - opencode: { - version: Installation.VERSION, - }, + agentInfo: { + name: "OpenCode", + version: Installation.VERSION, }, } } @@ -338,21 +358,31 @@ export namespace ACP { } async newSession(params: NewSessionRequest) { - const model = await defaultModel(this.config) - const session = await this.sessionManager.create(params.cwd, params.mcpServers, model) + try { + const model = await defaultModel(this.config) + const session = await this.sessionManager.create(params.cwd, params.mcpServers, model) - log.info("creating_session", { mcpServers: params.mcpServers.length }) - const load = await this.loadSession({ - cwd: params.cwd, - mcpServers: params.mcpServers, - sessionId: session.id, - }) + log.info("creating_session", { mcpServers: params.mcpServers.length }) + const load = await this.loadSession({ + cwd: params.cwd, + mcpServers: params.mcpServers, + sessionId: session.id, + }) - return { - sessionId: session.id, - models: load.models, - modes: load.modes, - _meta: {}, + return { + sessionId: session.id, + models: load.models, + modes: load.modes, + _meta: {}, + } + } catch (e) { + const error = MessageV2.fromError(e, { + providerID: this.config.defaultModel?.providerID ?? "unknown", + }) + if (LoadAPIKeyError.isInstance(error)) { + throw RequestError.authRequired() + } + throw e } } @@ -387,16 +417,6 @@ export namespace ACP { description: "compact the session", }) - setTimeout(() => { - this.connection.sessionUpdate({ - sessionId, - update: { - sessionUpdate: "available_commands_update", - availableCommands, - }, - }) - }, 0) - const availableModes = (await Agents.list()) .filter((agent) => agent.mode !== "subagent") .map((agent) => ({ @@ -437,6 +457,16 @@ export namespace ACP { }), ) + setTimeout(() => { + this.connection.sessionUpdate({ + sessionId, + update: { + sessionUpdate: "available_commands_update", + availableCommands, + }, + }) + }, 0) + return { sessionId, models: { diff --git a/packages/opencode/src/acp/session.ts b/packages/opencode/src/acp/session.ts index 5d45ee28..d3ab73d2 100644 --- a/packages/opencode/src/acp/session.ts +++ b/packages/opencode/src/acp/session.ts @@ -6,13 +6,18 @@ import type { ACPSessionState } from "./types" export class ACPSessionManager { private sessions = new Map() - async create(cwd: string, mcpServers: McpServer[], model?: ACPSessionState["model"]): Promise { + async create( + cwd: string, + mcpServers: McpServer[], + model?: ACPSessionState["model"], + ): Promise { const session = await Session.create({ title: `ACP Session ${crypto.randomUUID()}` }) const sessionId = session.id const resolvedModel = model ?? (await Provider.defaultModel()) const state: ACPSessionState = { id: sessionId, + parentId: session.parentID, cwd, mcpServers, createdAt: new Date(), diff --git a/packages/opencode/src/acp/types.ts b/packages/opencode/src/acp/types.ts index 56308cb7..119b335c 100644 --- a/packages/opencode/src/acp/types.ts +++ b/packages/opencode/src/acp/types.ts @@ -2,6 +2,7 @@ import type { McpServer } from "@agentclientprotocol/sdk" export interface ACPSessionState { id: string + parentId?: string cwd: string mcpServers: McpServer[] createdAt: Date diff --git a/packages/opencode/src/mcp/index.ts b/packages/opencode/src/mcp/index.ts index d6de4a59..fbc88703 100644 --- a/packages/opencode/src/mcp/index.ts +++ b/packages/opencode/src/mcp/index.ts @@ -77,7 +77,15 @@ export namespace MCP { } }, async (state) => { - await Promise.all(Object.values(state.clients).map((client) => client.close())) + await Promise.all( + Object.values(state.clients).map((client) => + client.close().catch((error) => { + log.error("Failed to close MCP client", { + error, + }) + }), + ), + ) }, ) @@ -201,7 +209,15 @@ export namespace MCP { const result = await withTimeout(mcpClient.tools(), mcp.timeout ?? 5000).catch(() => {}) if (!result) { - await mcpClient.close() + await mcpClient.close().catch((error) => { + log.error("Failed to close MCP client", { + error, + }) + }) + status = { + status: "failed", + error: "Failed to get tools", + } return { mcpClient: undefined, status: { From 7269c2316d1165b30fc8778e63320a9fc594176a Mon Sep 17 00:00:00 2001 From: opencode Date: Wed, 5 Nov 2025 07:00:07 +0000 Subject: [PATCH 018/218] release: v1.0.25 --- bun.lock | 22 +++++++++++----------- packages/console/app/package.json | 2 +- packages/console/core/package.json | 2 +- packages/console/function/package.json | 2 +- packages/console/mail/package.json | 2 +- packages/desktop/package.json | 2 +- packages/function/package.json | 2 +- packages/opencode/package.json | 2 +- packages/plugin/package.json | 2 +- packages/sdk/js/package.json | 2 +- packages/slack/package.json | 2 +- packages/ui/package.json | 2 +- packages/web/package.json | 2 +- sdks/vscode/package.json | 2 +- 14 files changed, 24 insertions(+), 24 deletions(-) diff --git a/bun.lock b/bun.lock index 866ce447..679f837e 100644 --- a/bun.lock +++ b/bun.lock @@ -39,7 +39,7 @@ }, "packages/console/core": { "name": "@opencode-ai/console-core", - "version": "1.0.24", + "version": "1.0.25", "dependencies": { "@aws-sdk/client-sts": "3.782.0", "@jsx-email/render": "1.1.1", @@ -66,7 +66,7 @@ }, "packages/console/function": { "name": "@opencode-ai/console-function", - "version": "1.0.24", + "version": "1.0.25", "dependencies": { "@ai-sdk/anthropic": "2.0.0", "@ai-sdk/openai": "2.0.2", @@ -90,7 +90,7 @@ }, "packages/console/mail": { "name": "@opencode-ai/console-mail", - "version": "1.0.24", + "version": "1.0.25", "dependencies": { "@jsx-email/all": "2.2.3", "@jsx-email/cli": "1.4.3", @@ -111,7 +111,7 @@ }, "packages/desktop": { "name": "@opencode-ai/desktop", - "version": "1.0.24", + "version": "1.0.25", "dependencies": { "@kobalte/core": "catalog:", "@opencode-ai/sdk": "workspace:*", @@ -150,7 +150,7 @@ }, "packages/function": { "name": "@opencode-ai/function", - "version": "1.0.24", + "version": "1.0.25", "dependencies": { "@octokit/auth-app": "8.0.1", "@octokit/rest": "22.0.0", @@ -166,7 +166,7 @@ }, "packages/opencode": { "name": "opencode", - "version": "1.0.24", + "version": "1.0.25", "bin": { "opencode": "./bin/opencode", }, @@ -243,7 +243,7 @@ }, "packages/plugin": { "name": "@opencode-ai/plugin", - "version": "1.0.24", + "version": "1.0.25", "dependencies": { "@opencode-ai/sdk": "workspace:*", "zod": "catalog:", @@ -263,7 +263,7 @@ }, "packages/sdk/js": { "name": "@opencode-ai/sdk", - "version": "1.0.24", + "version": "1.0.25", "devDependencies": { "@hey-api/openapi-ts": "0.81.0", "@tsconfig/node22": "catalog:", @@ -274,7 +274,7 @@ }, "packages/slack": { "name": "@opencode-ai/slack", - "version": "1.0.24", + "version": "1.0.25", "dependencies": { "@opencode-ai/sdk": "workspace:*", "@slack/bolt": "^3.17.1", @@ -287,7 +287,7 @@ }, "packages/ui": { "name": "@opencode-ai/ui", - "version": "1.0.24", + "version": "1.0.25", "dependencies": { "@kobalte/core": "catalog:", "@opencode-ai/sdk": "workspace:*", @@ -317,7 +317,7 @@ }, "packages/web": { "name": "@opencode-ai/web", - "version": "1.0.24", + "version": "1.0.25", "dependencies": { "@astrojs/cloudflare": "12.6.3", "@astrojs/markdown-remark": "6.3.1", diff --git a/packages/console/app/package.json b/packages/console/app/package.json index a367a679..63eee203 100644 --- a/packages/console/app/package.json +++ b/packages/console/app/package.json @@ -7,7 +7,7 @@ "dev:remote": "VITE_AUTH_URL=https://auth.dev.opencode.ai bun sst shell --stage=dev bun dev", "build": "vinxi build && ../../opencode/script/schema.ts ./.output/public/config.json", "start": "vinxi start", - "version": "1.0.24" + "version": "1.0.25" }, "dependencies": { "@ibm/plex": "6.4.1", diff --git a/packages/console/core/package.json b/packages/console/core/package.json index 738c41e7..e3d04c2f 100644 --- a/packages/console/core/package.json +++ b/packages/console/core/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@opencode-ai/console-core", - "version": "1.0.24", + "version": "1.0.25", "private": true, "type": "module", "dependencies": { diff --git a/packages/console/function/package.json b/packages/console/function/package.json index b014e441..bbef6422 100644 --- a/packages/console/function/package.json +++ b/packages/console/function/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/console-function", - "version": "1.0.24", + "version": "1.0.25", "$schema": "https://json.schemastore.org/package.json", "private": true, "type": "module", diff --git a/packages/console/mail/package.json b/packages/console/mail/package.json index 3355d754..c15f8580 100644 --- a/packages/console/mail/package.json +++ b/packages/console/mail/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/console-mail", - "version": "1.0.24", + "version": "1.0.25", "dependencies": { "@jsx-email/all": "2.2.3", "@jsx-email/cli": "1.4.3", diff --git a/packages/desktop/package.json b/packages/desktop/package.json index d74dd95b..8eb2786d 100644 --- a/packages/desktop/package.json +++ b/packages/desktop/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/desktop", - "version": "1.0.24", + "version": "1.0.25", "description": "", "type": "module", "scripts": { diff --git a/packages/function/package.json b/packages/function/package.json index a001b92c..803911f5 100644 --- a/packages/function/package.json +++ b/packages/function/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/function", - "version": "1.0.24", + "version": "1.0.25", "$schema": "https://json.schemastore.org/package.json", "private": true, "type": "module", diff --git a/packages/opencode/package.json b/packages/opencode/package.json index d9fe076f..ea3e721d 100644 --- a/packages/opencode/package.json +++ b/packages/opencode/package.json @@ -1,6 +1,6 @@ { "$schema": "https://json.schemastore.org/package.json", - "version": "1.0.24", + "version": "1.0.25", "name": "opencode", "type": "module", "private": true, diff --git a/packages/plugin/package.json b/packages/plugin/package.json index ec0ca9ac..5935ff8a 100644 --- a/packages/plugin/package.json +++ b/packages/plugin/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@opencode-ai/plugin", - "version": "1.0.24", + "version": "1.0.25", "type": "module", "scripts": { "typecheck": "tsgo --noEmit", diff --git a/packages/sdk/js/package.json b/packages/sdk/js/package.json index 8e4b5b6a..5aa94bf3 100644 --- a/packages/sdk/js/package.json +++ b/packages/sdk/js/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@opencode-ai/sdk", - "version": "1.0.24", + "version": "1.0.25", "type": "module", "scripts": { "typecheck": "tsgo --noEmit", diff --git a/packages/slack/package.json b/packages/slack/package.json index 9de763e6..0805f4b4 100644 --- a/packages/slack/package.json +++ b/packages/slack/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/slack", - "version": "1.0.24", + "version": "1.0.25", "type": "module", "scripts": { "dev": "bun run src/index.ts", diff --git a/packages/ui/package.json b/packages/ui/package.json index 6f5dd1e9..83af3a26 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/ui", - "version": "1.0.24", + "version": "1.0.25", "type": "module", "exports": { ".": "./src/components/index.ts", diff --git a/packages/web/package.json b/packages/web/package.json index 63d2b8e9..89848290 100644 --- a/packages/web/package.json +++ b/packages/web/package.json @@ -1,7 +1,7 @@ { "name": "@opencode-ai/web", "type": "module", - "version": "1.0.24", + "version": "1.0.25", "scripts": { "dev": "astro dev", "dev:remote": "VITE_API_URL=https://api.opencode.ai astro dev", diff --git a/sdks/vscode/package.json b/sdks/vscode/package.json index ec4902ea..96fc935b 100644 --- a/sdks/vscode/package.json +++ b/sdks/vscode/package.json @@ -2,7 +2,7 @@ "name": "opencode", "displayName": "opencode", "description": "opencode for VS Code", - "version": "1.0.24", + "version": "1.0.25", "publisher": "sst-dev", "repository": { "type": "git", From 2db76fc6dd03b58e372675275dd6d48663c593c5 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Wed, 5 Nov 2025 12:04:41 +0000 Subject: [PATCH 019/218] ignore: update download stats 2025-11-05 --- STATS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/STATS.md b/STATS.md index 27c8d283..28a0e3da 100644 --- a/STATS.md +++ b/STATS.md @@ -130,3 +130,4 @@ | 2025-11-02 | 644,067 (+7,967) | 590,004 (+8,198) | 1,234,071 (+16,165) | | 2025-11-03 | 653,130 (+9,063) | 597,139 (+7,135) | 1,250,269 (+16,198) | | 2025-11-04 | 663,912 (+10,782) | 608,056 (+10,917) | 1,271,968 (+21,699) | +| 2025-11-05 | 675,074 (+11,162) | 619,690 (+11,634) | 1,294,764 (+22,796) | From 03f7f182605d178aa6e3b3533d76eb0a6361940f Mon Sep 17 00:00:00 2001 From: Aiden Cline Date: Wed, 5 Nov 2025 09:36:38 -0600 Subject: [PATCH 020/218] ci: adjust auto label --- .github/workflows/auto-label-tui.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/auto-label-tui.yml b/.github/workflows/auto-label-tui.yml index 834562e1..73cccf92 100644 --- a/.github/workflows/auto-label-tui.yml +++ b/.github/workflows/auto-label-tui.yml @@ -20,8 +20,8 @@ jobs: const title = issue.title; const description = issue.body || ''; - // Check for web/desktop keywords - const webPattern = /\b(web|desktop)\b/i; + // Check for "opencode web" or desktop keywords + const webPattern = /(opencode web|\bdesktop\b)/i; const isWebRelated = webPattern.test(title) || webPattern.test(description); // Check for version patterns like v1.0.x or 1.0.x From c9dfe6d9649c637729d8d4d1cdb0791105c7c98b Mon Sep 17 00:00:00 2001 From: Matthew Fitzpatrick Date: Wed, 5 Nov 2025 07:47:11 -0800 Subject: [PATCH 021/218] docs: include "limit" example (#3925) Co-authored-by: opencode-agent[bot] Co-authored-by: rekram1-node --- packages/web/src/content/docs/providers.mdx | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/packages/web/src/content/docs/providers.mdx b/packages/web/src/content/docs/providers.mdx index 41e6308f..6409acee 100644 --- a/packages/web/src/content/docs/providers.mdx +++ b/packages/web/src/content/docs/providers.mdx @@ -482,7 +482,6 @@ To use Google Vertex AI with OpenCode: 4. Run the `/models` command to select a model like _Kimi-K2-Instruct_ or _GLM-4.6_. - --- ### LM Studio @@ -935,9 +934,9 @@ You can use any OpenAI-compatible provider with opencode. Most modern AI provide ##### Example -Here's an example setting the `apiKey` and `headers` options. +Here's an example setting the `apiKey`, `headers`, and model `limit` options. -```json title="opencode.json" {9,11} +```json title="opencode.json" {9,11,17-20} { "$schema": "https://opencode.ai/config.json", "provider": { @@ -953,7 +952,11 @@ Here's an example setting the `apiKey` and `headers` options. }, "models": { "my-model-name": { - "name": "My Model Display Name" + "name": "My Model Display Name", + "limit": { + "context": 200000, + "output": 65536 + } } } } @@ -961,7 +964,14 @@ Here's an example setting the `apiKey` and `headers` options. } ``` -We are setting the `apiKey` using the `env` variable syntax, [learn more](/docs/config#env-vars). +Configuration details: + +- **apiKey**: Set using `env` variable syntax, [learn more](/docs/config#env-vars). +- **headers**: Custom headers sent with each request. +- **limit.context**: Maximum input tokens the model accepts. +- **limit.output**: Maximum tokens the model can generate. + +The `limit` fields allow OpenCode to understand how much context you have left. Standard providers pull these from models.dev automatically. --- From 77c65b18b521aad07aa306952b9e0a4172bf2765 Mon Sep 17 00:00:00 2001 From: Aiden Cline Date: Wed, 5 Nov 2025 10:13:04 -0600 Subject: [PATCH 022/218] tweak: normalize escape keybind --- packages/opencode/src/util/keybind.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/opencode/src/util/keybind.ts b/packages/opencode/src/util/keybind.ts index 96619416..5beaf9aa 100644 --- a/packages/opencode/src/util/keybind.ts +++ b/packages/opencode/src/util/keybind.ts @@ -64,6 +64,9 @@ export namespace Keybind { case "leader": info.leader = true break + case "esc": + info.name = "escape" + break default: info.name = part break From af7b9e77d1f68b66e4ec3c1dd79efccf6bb53b07 Mon Sep 17 00:00:00 2001 From: Aiden Cline Date: Wed, 5 Nov 2025 10:14:08 -0600 Subject: [PATCH 023/218] fix: eu-west-2 aws bedrock issue --- packages/opencode/src/provider/provider.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/opencode/src/provider/provider.ts b/packages/opencode/src/provider/provider.ts index 3be091df..2ed072e5 100644 --- a/packages/opencode/src/provider/provider.ts +++ b/packages/opencode/src/provider/provider.ts @@ -118,6 +118,7 @@ export namespace Provider { case "eu": { const regionRequiresPrefix = [ "eu-west-1", + "eu-west-2", "eu-west-3", "eu-north-1", "eu-central-1", From 53998a2fedc55262aca8b049eacbed3d710a46e5 Mon Sep 17 00:00:00 2001 From: Filip <34747899+neriousy@users.noreply.github.com> Date: Wed, 5 Nov 2025 18:26:28 +0100 Subject: [PATCH 024/218] chore: remove unused patch tool from registry (to avoid accidental inclusions of it) (#3938) --- packages/opencode/src/tool/registry.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/packages/opencode/src/tool/registry.ts b/packages/opencode/src/tool/registry.ts index 4ea70f28..c4d54597 100644 --- a/packages/opencode/src/tool/registry.ts +++ b/packages/opencode/src/tool/registry.ts @@ -3,7 +3,6 @@ import { EditTool } from "./edit" import { GlobTool } from "./glob" import { GrepTool } from "./grep" import { ListTool } from "./ls" -import { PatchTool } from "./patch" import { ReadTool } from "./read" import { TaskTool } from "./task" import { TodoWriteTool, TodoReadTool } from "./todo" @@ -82,7 +81,6 @@ export namespace ToolRegistry { GlobTool, GrepTool, ListTool, - PatchTool, ReadTool, WriteTool, TodoWriteTool, @@ -113,11 +111,9 @@ export namespace ToolRegistry { agent: Agent.Info, ): Promise> { const result: Record = {} - result["patch"] = false if (agent.permission.edit === "deny") { result["edit"] = false - result["patch"] = false result["write"] = false } if (agent.permission.bash["*"] === "deny" && Object.keys(agent.permission.bash).length === 1) { From ee8b81269bdd40dde0987e7796ae0ebcd8ebc3ab Mon Sep 17 00:00:00 2001 From: monke-yo <94365786+monke-yo@users.noreply.github.com> Date: Wed, 5 Nov 2025 23:01:01 +0530 Subject: [PATCH 025/218] feat: add --attach flag to opencode run (#3889) --- packages/opencode/src/cli/cmd/run.ts | 407 +++++++++++++------------- packages/web/src/content/docs/cli.mdx | 12 + 2 files changed, 222 insertions(+), 197 deletions(-) diff --git a/packages/opencode/src/cli/cmd/run.ts b/packages/opencode/src/cli/cmd/run.ts index a979f8ba..39b0a55f 100644 --- a/packages/opencode/src/cli/cmd/run.ts +++ b/packages/opencode/src/cli/cmd/run.ts @@ -1,21 +1,14 @@ import type { Argv } from "yargs" import path from "path" -import { Bus } from "../../bus" -import { Provider } from "../../provider/provider" -import { Session } from "../../session" import { UI } from "../ui" import { cmd } from "./cmd" import { Flag } from "../../flag/flag" -import { Config } from "../../config/config" import { bootstrap } from "../bootstrap" -import { MessageV2 } from "../../session/message-v2" -import { Identifier } from "../../id/id" -import { Agent } from "../../agent/agent" import { Command } from "../../command" -import { SessionPrompt } from "../../session/prompt" import { EOL } from "os" -import { Permission } from "@/permission" import { select } from "@clack/prompts" +import { createOpencodeClient, type OpencodeClient } from "@opencode-ai/sdk" +import { Server } from "../../server/server" const TOOL: Record = { todowrite: ["Todo", UI.Style.TEXT_WARNING_BOLD], @@ -84,11 +77,19 @@ export const RunCommand = cmd({ type: "string", describe: "title for the session (uses truncated prompt if no value provided)", }) + .option("attach", { + type: "string", + describe: "attach to a running opencode server (e.g., http://localhost:4096)", + }) + .option("port", { + type: "number", + describe: "port for the local server (defaults to random port if no value provided)", + }) }, handler: async (args) => { let message = args.message.join(" ") - let fileParts: any[] = [] + const fileParts: any[] = [] if (args.file) { const files = Array.isArray(args.file) ? args.file : [args.file] @@ -124,79 +125,8 @@ export const RunCommand = cmd({ process.exit(1) } - await bootstrap(process.cwd(), async () => { - if (args.command) { - const exists = await Command.get(args.command) - if (!exists) { - UI.error(`Command "${args.command}" not found`) - process.exit(1) - } - } - const session = await (async () => { - if (args.continue) { - const it = Session.list() - try { - for await (const s of it) { - if (s.parentID === undefined) { - return s - } - } - return - } finally { - await it.return() - } - } - - if (args.session) return Session.get(args.session) - - const title = (() => { - if (args.title !== undefined) { - if (args.title === "") { - return message.slice(0, 50) + (message.length > 50 ? "..." : "") - } - return args.title - } - return undefined - })() - - return Session.create({ - title, - }) - })() - - if (!session) { - UI.error("Session not found") - process.exit(1) - } - - const cfg = await Config.get() - if (cfg.share === "auto" || Flag.OPENCODE_AUTO_SHARE || args.share) { - try { - await Session.share(session.id) - UI.println(UI.Style.TEXT_INFO_BOLD + "~ https://opencode.ai/s/" + session.id.slice(-8)) - } catch (error) { - if (error instanceof Error && error.message.includes("disabled")) { - UI.println(UI.Style.TEXT_DANGER_BOLD + "! " + error.message) - } else { - throw error - } - } - } - - const agent = await (async () => { - if (args.agent) return Agent.get(args.agent) - const build = Agent.get("build") - if (build) return build - return Agent.list().then((x) => x[0]) - })() - - const { providerID, modelID } = await (async () => { - if (args.model) return Provider.parseModel(args.model) - if (agent.model) return agent.model - return await Provider.defaultModel() - })() - - function printEvent(color: string, type: string, title: string) { + const execute = async (sdk: OpencodeClient, sessionID: string) => { + const printEvent = (color: string, type: string, title: string) => { UI.println( color + `|`, UI.Style.TEXT_NORMAL + UI.Style.TEXT_DIM + ` ${type.padEnd(7, " ")}`, @@ -205,135 +135,218 @@ export const RunCommand = cmd({ ) } - function outputJsonEvent(type: string, data: any) { + const outputJsonEvent = (type: string, data: any) => { if (args.format === "json") { - const jsonEvent = { - type, - timestamp: Date.now(), - sessionID: session?.id, - ...data, - } - process.stdout.write(JSON.stringify(jsonEvent) + EOL) + process.stdout.write(JSON.stringify({ type, timestamp: Date.now(), sessionID, ...data }) + EOL) return true } return false } - const messageID = Identifier.ascending("message") - - Bus.subscribe(MessageV2.Event.PartUpdated, async (evt) => { - if (evt.properties.part.sessionID !== session.id) return - if (evt.properties.part.messageID === messageID) return - const part = evt.properties.part - - if (part.type === "tool" && part.state.status === "completed") { - if (outputJsonEvent("tool_use", { part })) return - const [tool, color] = TOOL[part.tool] ?? [part.tool, UI.Style.TEXT_INFO_BOLD] - const title = - part.state.title || - (Object.keys(part.state.input).length > 0 - ? JSON.stringify(part.state.input) - : "Unknown") - - printEvent(color, tool, title) - - if (part.tool === "bash" && part.state.output && part.state.output.trim()) { - UI.println() - UI.println(part.state.output) - } - } - - if (part.type === "step-start") { - if (outputJsonEvent("step_start", { part })) return - } - - if (part.type === "step-finish") { - if (outputJsonEvent("step_finish", { part })) return - } - - if (part.type === "text") { - const text = part.text - const isPiped = !process.stdout.isTTY - - if (part.time?.end) { - if (outputJsonEvent("text", { part })) return - if (!isPiped) UI.println() - process.stdout.write((isPiped ? text : UI.markdown(text)) + EOL) - if (!isPiped) UI.println() - } - } - }) - + const events = await sdk.event.subscribe() let errorMsg: string | undefined - Bus.subscribe(Session.Event.Error, async (evt) => { - const { sessionID, error } = evt.properties - if (sessionID !== session.id || !error) return - let err = String(error.name) - if ("data" in error && error.data && "message" in error.data) { - err = error.data.message + const eventProcessor = (async () => { + for await (const event of events.stream) { + if (event.type === "message.part.updated") { + const part = event.properties.part + if (part.sessionID !== sessionID) continue + + if (part.type === "tool" && part.state.status === "completed") { + if (outputJsonEvent("tool_use", { part })) continue + const [tool, color] = TOOL[part.tool] ?? [part.tool, UI.Style.TEXT_INFO_BOLD] + const title = + part.state.title || + (Object.keys(part.state.input).length > 0 ? JSON.stringify(part.state.input) : "Unknown") + printEvent(color, tool, title) + if (part.tool === "bash" && part.state.output?.trim()) { + UI.println() + UI.println(part.state.output) + } + } + + if (part.type === "step-start") { + if (outputJsonEvent("step_start", { part })) continue + } + + if (part.type === "step-finish") { + if (outputJsonEvent("step_finish", { part })) continue + } + + if (part.type === "text" && part.time?.end) { + if (outputJsonEvent("text", { part })) continue + const isPiped = !process.stdout.isTTY + if (!isPiped) UI.println() + process.stdout.write((isPiped ? part.text : UI.markdown(part.text)) + EOL) + if (!isPiped) UI.println() + } + } + + if (event.type === "session.error") { + const props = event.properties + if (props.sessionID !== sessionID || !props.error) continue + let err = String(props.error.name) + if ("data" in props.error && props.error.data && "message" in props.error.data) { + err = String(props.error.data.message) + } + errorMsg = errorMsg ? errorMsg + EOL + err : err + if (outputJsonEvent("error", { error: props.error })) continue + UI.error(err) + } + + if (event.type === "session.idle" && event.properties.sessionID === sessionID) { + break + } + + if (event.type === "permission.updated") { + const permission = event.properties + if (permission.sessionID !== sessionID) continue + const result = await select({ + message: `Permission required to run: ${permission.title}`, + options: [ + { value: "once", label: "Allow once" }, + { value: "always", label: "Always allow" }, + { value: "reject", label: "Reject" }, + ], + initialValue: "once", + }).catch(() => "reject") + const response = (result.toString().includes("cancel") ? "reject" : result) as + | "once" + | "always" + | "reject" + await sdk.postSessionIdPermissionsPermissionId({ + path: { id: sessionID, permissionID: permission.id }, + body: { response }, + }) + } } - errorMsg = errorMsg ? errorMsg + EOL + err : err + })() - if (outputJsonEvent("error", { error })) return - UI.error(err) - }) - - Bus.subscribe(Permission.Event.Updated, async (evt) => { - const permission = evt.properties - const message = `Permission required to run: ${permission.title}` - - const result = await select({ - message, - options: [ - { value: "once", label: "Allow once" }, - { value: "always", label: "Always allow" }, - { value: "reject", label: "Reject" }, - ], - initialValue: "once", - }).catch(() => "reject") - const response = (result.toString().includes("cancel") ? "reject" : result) as - | "once" - | "always" - | "reject" - - Permission.respond({ - sessionID: session.id, - permissionID: permission.id, - response, - }) - }) - - await (async () => { - if (args.command) { - return await SessionPrompt.command({ - messageID, - sessionID: session.id, - agent: agent.name, - model: providerID + "/" + modelID, + if (args.command) { + await sdk.session.command({ + path: { id: sessionID }, + body: { + agent: args.agent || "build", + model: args.model, command: args.command, arguments: message, - }) - } - return await SessionPrompt.prompt({ - sessionID: session.id, - messageID, - model: { - providerID, - modelID, }, - agent: agent.name, - parts: [ - ...fileParts, - { - id: Identifier.ascending("part"), - type: "text", - text: message, - }, - ], }) - })() + } else { + const modelParam = args.model + ? (() => { + const [providerID, modelID] = args.model.split("/") + return { providerID, modelID } + })() + : undefined + await sdk.session.prompt({ + path: { id: sessionID }, + body: { + agent: args.agent || "build", + model: modelParam, + parts: [...fileParts, { type: "text", text: message }], + }, + }) + } + + await eventProcessor if (errorMsg) process.exit(1) + } + + if (args.attach) { + const sdk = createOpencodeClient({ baseUrl: args.attach }) + + const sessionID = await (async () => { + if (args.continue) { + const result = await sdk.session.list() + return result.data?.find((s) => !s.parentID)?.id + } + if (args.session) return args.session + + const title = + args.title !== undefined + ? args.title === "" + ? message.slice(0, 50) + (message.length > 50 ? "..." : "") + : args.title + : undefined + + const result = await sdk.session.create({ body: title ? { title } : {} }) + return result.data?.id + })() + + if (!sessionID) { + UI.error("Session not found") + process.exit(1) + } + + const cfgResult = await sdk.config.get() + if (cfgResult.data && (cfgResult.data.share === "auto" || Flag.OPENCODE_AUTO_SHARE || args.share)) { + const shareResult = await sdk.session.share({ path: { id: sessionID } }).catch((error) => { + if (error instanceof Error && error.message.includes("disabled")) { + UI.println(UI.Style.TEXT_DANGER_BOLD + "! " + error.message) + } + return { error } + }) + if (!shareResult.error) { + UI.println(UI.Style.TEXT_INFO_BOLD + "~ https://opencode.ai/s/" + sessionID.slice(-8)) + } + } + + return await execute(sdk, sessionID) + } + + await bootstrap(process.cwd(), async () => { + const server = Server.listen({ port: args.port ?? 0, hostname: "127.0.0.1" }) + const sdk = createOpencodeClient({ baseUrl: `http://${server.hostname}:${server.port}` }) + + if (args.command) { + const exists = await Command.get(args.command) + if (!exists) { + server.stop() + UI.error(`Command "${args.command}" not found`) + process.exit(1) + } + } + + const sessionID = await (async () => { + if (args.continue) { + const result = await sdk.session.list() + return result.data?.find((s) => !s.parentID)?.id + } + if (args.session) return args.session + + const title = + args.title !== undefined + ? args.title === "" + ? message.slice(0, 50) + (message.length > 50 ? "..." : "") + : args.title + : undefined + + const result = await sdk.session.create({ body: title ? { title } : {} }) + return result.data?.id + })() + + if (!sessionID) { + server.stop() + UI.error("Session not found") + process.exit(1) + } + + const cfgResult = await sdk.config.get() + if (cfgResult.data && (cfgResult.data.share === "auto" || Flag.OPENCODE_AUTO_SHARE || args.share)) { + const shareResult = await sdk.session.share({ path: { id: sessionID } }).catch((error) => { + if (error instanceof Error && error.message.includes("disabled")) { + UI.println(UI.Style.TEXT_DANGER_BOLD + "! " + error.message) + } + return { error } + }) + if (!shareResult.error) { + UI.println(UI.Style.TEXT_INFO_BOLD + "~ https://opencode.ai/s/" + sessionID.slice(-8)) + } + } + + await execute(sdk, sessionID) + server.stop() }) }, }) diff --git a/packages/web/src/content/docs/cli.mdx b/packages/web/src/content/docs/cli.mdx index 1312442d..083db369 100644 --- a/packages/web/src/content/docs/cli.mdx +++ b/packages/web/src/content/docs/cli.mdx @@ -184,6 +184,16 @@ This is useful for scripting, automation, or when you want a quick answer withou opencode run Explain the use of context in Go ``` +You can also attach to a running `opencode serve` instance to avoid MCP server cold boot times on every run: + +```bash +# Start a headless server in one terminal +opencode serve + +# In another terminal, run commands that attach to it +opencode run --attach http://localhost:4096 "Explain async/await in JavaScript" +``` + #### Flags | Flag | Short | Description | @@ -197,6 +207,8 @@ opencode run Explain the use of context in Go | `--file` | `-f` | File(s) to attach to message | | `--format` | | Format: default (formatted) or json (raw JSON events) | | `--title` | | Title for the session (uses truncated prompt if no value provided) | +| `--attach` | | Attach to a running opencode server (e.g., http://localhost:4096) | +| `--port` | | Port for the local server (defaults to random port) | --- From 37e564139fc1b46a66f916280a3baf3e3e399bf2 Mon Sep 17 00:00:00 2001 From: Dax Raad Date: Wed, 5 Nov 2025 12:32:13 -0500 Subject: [PATCH 026/218] tui: lower paste summary threshold to trigger on shorter content --- packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx b/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx index d66b8e0a..c3ae1407 100644 --- a/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx +++ b/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx @@ -650,7 +650,10 @@ export function Prompt(props: PromptProps) { } catch {} const lineCount = (pastedContent.match(/\n/g)?.length ?? 0) + 1 - if (lineCount >= 5 && !sync.data.config.experimental?.disable_paste_summary) { + if ( + (lineCount >= 3 || pastedContent.length > 150) && + !sync.data.config.experimental?.disable_paste_summary + ) { event.preventDefault() const currentOffset = input.visualCursor.offset const virtualText = `[Pasted ~${lineCount} lines]` From 69a499f80786b2656121cee4469f39df2e6c40e7 Mon Sep 17 00:00:00 2001 From: OpeOginni <107570612+OpeOginni@users.noreply.github.com> Date: Wed, 5 Nov 2025 18:33:30 +0100 Subject: [PATCH 027/218] fix(tui): restructure Sidebar component to be scrollable (#3946) --- .../cli/cmd/tui/routes/session/sidebar.tsx | 258 +++++++++--------- 1 file changed, 130 insertions(+), 128 deletions(-) diff --git a/packages/opencode/src/cli/cmd/tui/routes/session/sidebar.tsx b/packages/opencode/src/cli/cmd/tui/routes/session/sidebar.tsx index c63297db..2f1451a5 100644 --- a/packages/opencode/src/cli/cmd/tui/routes/session/sidebar.tsx +++ b/packages/opencode/src/cli/cmd/tui/routes/session/sidebar.tsx @@ -40,136 +40,138 @@ export function Sidebar(props: { sessionID: string }) { return ( - - - - {session().title} - - - {session().share!.url} + + + + + {session().title} + + + {session().share!.url} + + + + + Context + + {context()?.tokens ?? 0} tokens + {context()?.percentage ?? 0}% used + {cost()} spent + + 0}> + + + MCP + + + {([key, item]) => ( + + + • + + + {key}{" "} + + + Connected + + {(val) => {val().error}} + + Disabled in configuration + + + + + )} + + + + 0}> + + + LSP + + + {(item) => ( + + + • + + + {item.id} {item.root} + + + )} + + + + + + + Modified Files + + + {(item) => { + const file = createMemo(() => { + const splits = item.file.split(path.sep).filter(Boolean) + const last = splits.at(-1)! + const rest = splits.slice(0, -1).join(path.sep) + return Locale.truncateMiddle(rest, 30 - last.length) + "/" + last + }) + return ( + + + {file()} + + + + +{item.additions} + + + -{item.deletions} + + + + ) + }} + + + + 0}> + + + Todo + + + {(todo) => ( + + [{todo.status === "completed" ? "✓" : " "}] {todo.content} + + )} + + - - - Context - - {context()?.tokens ?? 0} tokens - {context()?.percentage ?? 0}% used - {cost()} spent - - 0}> - - - MCP - - - {([key, item]) => ( - - - • - - - {key}{" "} - - - Connected - - {(val) => {val().error}} - - Disabled in configuration - - - - - )} - - - - 0}> - - - LSP - - - {(item) => ( - - - • - - - {item.id} {item.root} - - - )} - - - - - - - Modified Files - - - {(item) => { - const file = createMemo(() => { - const splits = item.file.split(path.sep).filter(Boolean) - const last = splits.at(-1)! - const rest = splits.slice(0, -1).join(path.sep) - return Locale.truncateMiddle(rest, 30 - last.length) + "/" + last - }) - return ( - - - {file()} - - - - +{item.additions} - - - -{item.deletions} - - - - ) - }} - - - - 0}> - - - Todo - - - {(todo) => ( - - [{todo.status === "completed" ? "✓" : " "}] {todo.content} - - )} - - - - + ) } From d525fbf82940442d8d47265b7d7d0a9af8c282bc Mon Sep 17 00:00:00 2001 From: Adam <2363879+adamdotdevin@users.noreply.github.com> Date: Wed, 5 Nov 2025 11:55:31 -0600 Subject: [PATCH 028/218] feat(desktop): session router, interrupt agent, visual cleanup --- bun.lock | 27 +- package.json | 2 +- packages/desktop/package.json | 1 + .../src/components/message-progress.tsx | 11 +- .../desktop/src/components/prompt-input.tsx | 223 +++-- packages/desktop/src/context/local.tsx | 176 +--- packages/desktop/src/context/session.tsx | 213 +++++ packages/desktop/src/context/sync.tsx | 14 +- packages/desktop/src/index.tsx | 10 +- packages/desktop/src/pages/index.tsx | 857 ------------------ packages/desktop/src/pages/layout.tsx | 75 ++ packages/desktop/src/pages/session-layout.tsx | 12 + packages/desktop/src/pages/session.tsx | 693 ++++++++++++++ packages/ui/src/components/code.tsx | 5 +- packages/ui/src/components/diff.tsx | 1 + packages/ui/src/components/icon.tsx | 1 + packages/ui/src/components/input.tsx | 23 +- packages/ui/src/components/list.tsx | 8 +- packages/ui/src/components/select-dialog.tsx | 22 +- packages/ui/src/components/select.css | 12 +- packages/ui/src/components/select.tsx | 18 +- 21 files changed, 1259 insertions(+), 1145 deletions(-) create mode 100644 packages/desktop/src/context/session.tsx delete mode 100644 packages/desktop/src/pages/index.tsx create mode 100644 packages/desktop/src/pages/layout.tsx create mode 100644 packages/desktop/src/pages/session-layout.tsx create mode 100644 packages/desktop/src/pages/session.tsx diff --git a/bun.lock b/bun.lock index 679f837e..af3e4f2d 100644 --- a/bun.lock +++ b/bun.lock @@ -121,6 +121,7 @@ "@solid-primitives/event-bus": "1.1.2", "@solid-primitives/resize-observer": "2.1.3", "@solid-primitives/scroll": "2.1.3", + "@solid-primitives/storage": "4.3.3", "@solidjs/meta": "catalog:", "@solidjs/router": "0.15.3", "@thisbeyond/solid-dnd": "0.7.5", @@ -364,7 +365,7 @@ "@hono/zod-validator": "0.4.2", "@kobalte/core": "0.13.11", "@openauthjs/openauth": "0.0.0-20250322224806", - "@pierre/precision-diffs": "0.4.1", + "@pierre/precision-diffs": "0.4.2", "@solidjs/meta": "0.29.4", "@tailwindcss/vite": "4.1.11", "@tsconfig/bun": "1.0.9", @@ -1033,7 +1034,7 @@ "@petamoriken/float16": ["@petamoriken/float16@3.9.3", "", {}, "sha512-8awtpHXCx/bNpFt4mt2xdkgtgVvKqty8VbjHI/WWWQuEw+KLzFot3f4+LkQY9YmOtq7A5GdOnqoIC8Pdygjk2g=="], - "@pierre/precision-diffs": ["@pierre/precision-diffs@0.4.1", "", { "dependencies": { "@shikijs/core": "3.13.0", "@shikijs/transformers": "3.13.0", "diff": "8.0.2", "fast-deep-equal": "3.1.3", "hast-util-to-html": "9.0.5", "shiki": "3.13.0" }, "peerDependencies": { "react": "^18.3.1 || ^19.0.0", "react-dom": "^18.3.1 || ^19.0.0" } }, "sha512-AoozHakINGyNJFgbYc/1PlDK0yunrAxbtXEMBe9fdu8RLkNjVtYRTLw7EF2mM/YuVoVRjj2HT/2VJ4a2rMyDOA=="], + "@pierre/precision-diffs": ["@pierre/precision-diffs@0.4.2", "", { "dependencies": { "@shikijs/core": "3.14.0", "@shikijs/transformers": "3.14.0", "diff": "8.0.2", "fast-deep-equal": "3.1.3", "hast-util-to-html": "9.0.5", "shiki": "3.14.0" }, "peerDependencies": { "react": "^18.3.1 || ^19.0.0", "react-dom": "^18.3.1 || ^19.0.0" } }, "sha512-C6LbruH24BCp4awI47D5iMtVaZZD6GkzqBoDw+Sfu7DB3hC9y/rZr1C2BD7AUzAKwByTfFnh16Zp11ipfPqLKw=="], "@pkgjs/parseargs": ["@pkgjs/parseargs@0.11.0", "", {}, "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg=="], @@ -1309,6 +1310,8 @@ "@solid-primitives/static-store": ["@solid-primitives/static-store@0.1.2", "", { "dependencies": { "@solid-primitives/utils": "^6.3.2" }, "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-ReK+5O38lJ7fT+L6mUFvUr6igFwHBESZF+2Ug842s7fvlVeBdIVEdTCErygff6w7uR6+jrr7J8jQo+cYrEq4Iw=="], + "@solid-primitives/storage": ["@solid-primitives/storage@4.3.3", "", { "dependencies": { "@solid-primitives/utils": "^6.3.2" }, "peerDependencies": { "@tauri-apps/plugin-store": "*", "solid-js": "^1.6.12" }, "optionalPeers": ["@tauri-apps/plugin-store"] }, "sha512-ACbNwMZ1s8VAvld6EUXkDkX/US3IhtlPLxg6+B2s9MwNUugwdd51I98LPEaHrdLpqPmyzqgoJe0TxEFlf3Dqrw=="], + "@solid-primitives/trigger": ["@solid-primitives/trigger@1.2.2", "", { "dependencies": { "@solid-primitives/utils": "^6.3.2" }, "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-IWoptVc0SWYgmpBPpCMehS5b07+tpFcvw15tOQ3QbXedSYn6KP8zCjPkHNzMxcOvOicTneleeZDP7lqmz+PQ6g=="], "@solid-primitives/utils": ["@solid-primitives/utils@6.3.2", "", { "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-hZ/M/qr25QOCcwDPOHtGjxTD8w2mNyVAYvcfgwzBHq2RwNqHNdDNsMZYap20+ruRwW4A3Cdkczyoz0TSxLCAPQ=="], @@ -3725,11 +3728,11 @@ "@parcel/watcher-wasm/napi-wasm": ["napi-wasm@1.1.3", "", { "bundled": true }, "sha512-h/4nMGsHjZDCYmQVNODIrYACVJ+I9KItbG+0si6W/jSjdA9JbWDoU4LLeMXVcEQGHjttI2tuXqDrbGF7qkUHHg=="], - "@pierre/precision-diffs/@shikijs/core": ["@shikijs/core@3.13.0", "", { "dependencies": { "@shikijs/types": "3.13.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4", "hast-util-to-html": "^9.0.5" } }, "sha512-3P8rGsg2Eh2qIHekwuQjzWhKI4jV97PhvYjYUzGqjvJfqdQPz+nMlfWahU24GZAyW1FxFI1sYjyhfh5CoLmIUA=="], + "@pierre/precision-diffs/@shikijs/core": ["@shikijs/core@3.14.0", "", { "dependencies": { "@shikijs/types": "3.14.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4", "hast-util-to-html": "^9.0.5" } }, "sha512-qRSeuP5vlYHCNUIrpEBQFO7vSkR7jn7Kv+5X3FO/zBKVDGQbcnlScD3XhkrHi/R8Ltz0kEjvFR9Szp/XMRbFMw=="], - "@pierre/precision-diffs/@shikijs/transformers": ["@shikijs/transformers@3.13.0", "", { "dependencies": { "@shikijs/core": "3.13.0", "@shikijs/types": "3.13.0" } }, "sha512-833lcuVzcRiG+fXvgslWsM2f4gHpjEgui1ipIknSizRuTgMkNZupiXE5/TVJ6eSYfhNBFhBZKkReKWO2GgYmqA=="], + "@pierre/precision-diffs/@shikijs/transformers": ["@shikijs/transformers@3.14.0", "", { "dependencies": { "@shikijs/core": "3.14.0", "@shikijs/types": "3.14.0" } }, "sha512-i67zQnY9wLMMnKasonVW1L9fKneSLZDj1ePsA4o0AZWU4uUobmJY9baRDa36z+a9/g0aG76/2tybQvm4hrwxIQ=="], - "@pierre/precision-diffs/shiki": ["shiki@3.13.0", "", { "dependencies": { "@shikijs/core": "3.13.0", "@shikijs/engine-javascript": "3.13.0", "@shikijs/engine-oniguruma": "3.13.0", "@shikijs/langs": "3.13.0", "@shikijs/themes": "3.13.0", "@shikijs/types": "3.13.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-aZW4l8Og16CokuCLf8CF8kq+KK2yOygapU5m3+hoGw0Mdosc6fPitjM+ujYarppj5ZIKGyPDPP1vqmQhr+5/0g=="], + "@pierre/precision-diffs/shiki": ["shiki@3.14.0", "", { "dependencies": { "@shikijs/core": "3.14.0", "@shikijs/engine-javascript": "3.14.0", "@shikijs/engine-oniguruma": "3.14.0", "@shikijs/langs": "3.14.0", "@shikijs/themes": "3.14.0", "@shikijs/types": "3.14.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-J0yvpLI7LSig3Z3acIuDLouV5UCKQqu8qOArwMx+/yPVC3WRMgrP67beaG8F+j4xfEWE0eVC4GeBCIXeOPra1g=="], "@poppinss/dumper/supports-color": ["supports-color@10.2.2", "", {}, "sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g=="], @@ -4327,19 +4330,19 @@ "@opentui/solid/@babel/core/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], - "@pierre/precision-diffs/@shikijs/core/@shikijs/types": ["@shikijs/types@3.13.0", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-oM9P+NCFri/mmQ8LoFGVfVyemm5Hi27330zuOBp0annwJdKH1kOLndw3zCtAVDehPLg9fKqoEx3Ht/wNZxolfw=="], + "@pierre/precision-diffs/@shikijs/core/@shikijs/types": ["@shikijs/types@3.14.0", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-bQGgC6vrY8U/9ObG1Z/vTro+uclbjjD/uG58RvfxKZVD5p9Yc1ka3tVyEFy7BNJLzxuWyHH5NWynP9zZZS59eQ=="], - "@pierre/precision-diffs/@shikijs/transformers/@shikijs/types": ["@shikijs/types@3.13.0", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-oM9P+NCFri/mmQ8LoFGVfVyemm5Hi27330zuOBp0annwJdKH1kOLndw3zCtAVDehPLg9fKqoEx3Ht/wNZxolfw=="], + "@pierre/precision-diffs/@shikijs/transformers/@shikijs/types": ["@shikijs/types@3.14.0", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-bQGgC6vrY8U/9ObG1Z/vTro+uclbjjD/uG58RvfxKZVD5p9Yc1ka3tVyEFy7BNJLzxuWyHH5NWynP9zZZS59eQ=="], - "@pierre/precision-diffs/shiki/@shikijs/engine-javascript": ["@shikijs/engine-javascript@3.13.0", "", { "dependencies": { "@shikijs/types": "3.13.0", "@shikijs/vscode-textmate": "^10.0.2", "oniguruma-to-es": "^4.3.3" } }, "sha512-Ty7xv32XCp8u0eQt8rItpMs6rU9Ki6LJ1dQOW3V/56PKDcpvfHPnYFbsx5FFUP2Yim34m/UkazidamMNVR4vKg=="], + "@pierre/precision-diffs/shiki/@shikijs/engine-javascript": ["@shikijs/engine-javascript@3.14.0", "", { "dependencies": { "@shikijs/types": "3.14.0", "@shikijs/vscode-textmate": "^10.0.2", "oniguruma-to-es": "^4.3.3" } }, "sha512-3v1kAXI2TsWQuwv86cREH/+FK9Pjw3dorVEykzQDhwrZj0lwsHYlfyARaKmn6vr5Gasf8aeVpb8JkzeWspxOLQ=="], - "@pierre/precision-diffs/shiki/@shikijs/engine-oniguruma": ["@shikijs/engine-oniguruma@3.13.0", "", { "dependencies": { "@shikijs/types": "3.13.0", "@shikijs/vscode-textmate": "^10.0.2" } }, "sha512-O42rBGr4UDSlhT2ZFMxqM7QzIU+IcpoTMzb3W7AlziI1ZF7R8eS2M0yt5Ry35nnnTX/LTLXFPUjRFCIW+Operg=="], + "@pierre/precision-diffs/shiki/@shikijs/engine-oniguruma": ["@shikijs/engine-oniguruma@3.14.0", "", { "dependencies": { "@shikijs/types": "3.14.0", "@shikijs/vscode-textmate": "^10.0.2" } }, "sha512-TNcYTYMbJyy+ZjzWtt0bG5y4YyMIWC2nyePz+CFMWqm+HnZZyy9SWMgo8Z6KBJVIZnx8XUXS8U2afO6Y0g1Oug=="], - "@pierre/precision-diffs/shiki/@shikijs/langs": ["@shikijs/langs@3.13.0", "", { "dependencies": { "@shikijs/types": "3.13.0" } }, "sha512-672c3WAETDYHwrRP0yLy3W1QYB89Hbpj+pO4KhxK6FzIrDI2FoEXNiNCut6BQmEApYLfuYfpgOZaqbY+E9b8wQ=="], + "@pierre/precision-diffs/shiki/@shikijs/langs": ["@shikijs/langs@3.14.0", "", { "dependencies": { "@shikijs/types": "3.14.0" } }, "sha512-DIB2EQY7yPX1/ZH7lMcwrK5pl+ZkP/xoSpUzg9YC8R+evRCCiSQ7yyrvEyBsMnfZq4eBzLzBlugMyTAf13+pzg=="], - "@pierre/precision-diffs/shiki/@shikijs/themes": ["@shikijs/themes@3.13.0", "", { "dependencies": { "@shikijs/types": "3.13.0" } }, "sha512-Vxw1Nm1/Od8jyA7QuAenaV78BG2nSr3/gCGdBkLpfLscddCkzkL36Q5b67SrLLfvAJTOUzW39x4FHVCFriPVgg=="], + "@pierre/precision-diffs/shiki/@shikijs/themes": ["@shikijs/themes@3.14.0", "", { "dependencies": { "@shikijs/types": "3.14.0" } }, "sha512-fAo/OnfWckNmv4uBoUu6dSlkcBc+SA1xzj5oUSaz5z3KqHtEbUypg/9xxgJARtM6+7RVm0Q6Xnty41xA1ma1IA=="], - "@pierre/precision-diffs/shiki/@shikijs/types": ["@shikijs/types@3.13.0", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-oM9P+NCFri/mmQ8LoFGVfVyemm5Hi27330zuOBp0annwJdKH1kOLndw3zCtAVDehPLg9fKqoEx3Ht/wNZxolfw=="], + "@pierre/precision-diffs/shiki/@shikijs/types": ["@shikijs/types@3.14.0", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-bQGgC6vrY8U/9ObG1Z/vTro+uclbjjD/uG58RvfxKZVD5p9Yc1ka3tVyEFy7BNJLzxuWyHH5NWynP9zZZS59eQ=="], "@slack/web-api/p-queue/eventemitter3": ["eventemitter3@4.0.7", "", {}, "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw=="], diff --git a/package.json b/package.json index 55125896..de6c62a5 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,7 @@ "@tsconfig/bun": "1.0.9", "@cloudflare/workers-types": "4.20251008.0", "@openauthjs/openauth": "0.0.0-20250322224806", - "@pierre/precision-diffs": "0.4.1", + "@pierre/precision-diffs": "0.4.2", "@solidjs/meta": "0.29.4", "@tailwindcss/vite": "4.1.11", "diff": "8.0.2", diff --git a/packages/desktop/package.json b/packages/desktop/package.json index 8eb2786d..094e71b0 100644 --- a/packages/desktop/package.json +++ b/packages/desktop/package.json @@ -31,6 +31,7 @@ "@solid-primitives/event-bus": "1.1.2", "@solid-primitives/resize-observer": "2.1.3", "@solid-primitives/scroll": "2.1.3", + "@solid-primitives/storage": "4.3.3", "@solidjs/meta": "catalog:", "@solidjs/router": "0.15.3", "@thisbeyond/solid-dnd": "0.7.5", diff --git a/packages/desktop/src/components/message-progress.tsx b/packages/desktop/src/components/message-progress.tsx index c0037f57..a9be2ae5 100644 --- a/packages/desktop/src/components/message-progress.tsx +++ b/packages/desktop/src/components/message-progress.tsx @@ -70,9 +70,8 @@ export function MessageProgress(props: { assistantMessages: () => AssistantMessa const lastPart = createMemo(() => resolvedParts().slice(-1)?.at(0)) const rawStatus = createMemo(() => { - const defaultStatus = "Working..." const last = lastPart() - if (!last) return defaultStatus + if (!last) return undefined if (last.type === "tool") { switch (last.tool) { @@ -102,7 +101,7 @@ export function MessageProgress(props: { assistantMessages: () => AssistantMessa } else if (last.type === "text") { return "Gathering thoughts..." } - return defaultStatus + return undefined }) const [status, setStatus] = createSignal(rawStatus()) @@ -111,11 +110,11 @@ export function MessageProgress(props: { assistantMessages: () => AssistantMessa createEffect(() => { const newStatus = rawStatus() - if (newStatus === status()) return + if (newStatus === status() || !newStatus) return const timeSinceLastChange = Date.now() - lastStatusChange - if (timeSinceLastChange >= 1000) { + if (timeSinceLastChange >= 1500) { setStatus(newStatus) lastStatusChange = Date.now() if (statusTimeout) { @@ -145,7 +144,7 @@ export function MessageProgress(props: { assistantMessages: () => AssistantMessa {/* )} */} {/* */}

- {status()} + {status() ?? "Considering next steps..."}
0}>
void class?: string ref?: (el: HTMLDivElement) => void } export const PromptInput: Component = (props) => { + const navigate = useNavigate() + const sdk = useSDK() + const sync = useSync() const local = useLocal() + const session = useSession() let editorRef!: HTMLDivElement - const defaultParts = [{ type: "text", content: "", start: 0, end: 0 } as const] const [store, setStore] = createStore<{ - contentParts: ContentPart[] popoverIsOpen: boolean }>({ - contentParts: defaultParts, popoverIsOpen: false, }) - const isEmpty = createMemo(() => isEqual(store.contentParts, defaultParts)) + createEffect(() => { + session.id + editorRef.focus() + }) + const isFocused = createFocusSignal(() => editorRef) const handlePaste = (event: ClipboardEvent) => { @@ -71,14 +61,16 @@ export const PromptInput: Component = (props) => { } }) + const handleFileSelect = (path: string | undefined) => { + if (!path) return + addPart({ type: "file", path, content: "@" + getFilename(path), start: 0, end: 0 }) + setStore("popoverIsOpen", false) + } + const { flat, active, onInput, onKeyDown, refetch } = useFilteredList({ items: local.file.searchFilesAndDirectories, key: (x) => x, - onSelect: (path) => { - if (!path) return - addPart({ type: "file", path, content: "@" + getFilename(path), start: 0, end: 0 }) - setStore("popoverIsOpen", false) - }, + onSelect: handleFileSelect, }) createEffect(() => { @@ -88,10 +80,10 @@ export const PromptInput: Component = (props) => { createEffect( on( - () => store.contentParts, + () => session.prompt.current(), (currentParts) => { const domParts = parseFromDOM() - if (isEqual(currentParts, domParts)) return + if (isPromptEqual(currentParts, domParts)) return const selection = window.getSelection() let cursorPosition: number | null = null @@ -122,8 +114,18 @@ export const PromptInput: Component = (props) => { ), ) - const parseFromDOM = (): ContentPart[] => { - const newParts: ContentPart[] = [] + createEffect( + on( + () => session.prompt.cursor(), + (cursor) => { + if (cursor === undefined) return + queueMicrotask(() => setCursorPosition(editorRef, cursor)) + }, + ), + ) + + const parseFromDOM = (): Prompt => { + const newParts: Prompt = [] let position = 0 editorRef.childNodes.forEach((node) => { if (node.nodeType === Node.TEXT_NODE) { @@ -150,7 +152,7 @@ export const PromptInput: Component = (props) => { } } }) - if (newParts.length === 0) newParts.push(...defaultParts) + if (newParts.length === 0) newParts.push(...DEFAULT_PROMPT) return newParts } @@ -167,12 +169,15 @@ export const PromptInput: Component = (props) => { setStore("popoverIsOpen", false) } - setStore("contentParts", rawParts) + session.prompt.set(rawParts, cursorPosition) } const addPart = (part: ContentPart) => { const cursorPosition = getCursorPosition(editorRef) - const rawText = store.contentParts.map((p) => p.content).join("") + const rawText = session.prompt + .current() + .map((p) => p.content) + .join("") const textBeforeCursor = rawText.substring(0, cursorPosition) const atMatch = textBeforeCursor.match(/@(\S*)$/) @@ -198,7 +203,7 @@ export const PromptInput: Component = (props) => { parts: nextParts, inserted, cursorPositionAfter, - } = store.contentParts.reduce( + } = session.prompt.current().reduce( (acc, item) => { if (acc.inserted) { acc.parts.push({ ...item, start: acc.runningIndex, end: acc.runningIndex + item.content.length }) @@ -257,7 +262,7 @@ export const PromptInput: Component = (props) => { ) if (!inserted) { - const baseParts = store.contentParts.filter((item) => !(item.type === "text" && item.content === "")) + const baseParts = session.prompt.current().filter((item) => !(item.type === "text" && item.content === "")) const runningIndex = baseParts.reduce((sum, p) => sum + p.content.length, 0) const appendedAcc = { parts: [...baseParts] as ContentPart[], runningIndex } if (part.type === "text") { @@ -270,20 +275,27 @@ export const PromptInput: Component = (props) => { end: appendedAcc.runningIndex + part.content.length, }) } - const next = appendedAcc.parts.length > 0 ? appendedAcc.parts : defaultParts - setStore("contentParts", next) - setStore("popoverIsOpen", false) + const next = appendedAcc.parts.length > 0 ? appendedAcc.parts : DEFAULT_PROMPT const nextCursor = rawText.length + part.content.length + session.prompt.set(next, nextCursor) + setStore("popoverIsOpen", false) queueMicrotask(() => setCursorPosition(editorRef, nextCursor)) return } - setStore("contentParts", nextParts) + session.prompt.set(nextParts, cursorPositionAfter) setStore("popoverIsOpen", false) queueMicrotask(() => setCursorPosition(editorRef, cursorPositionAfter)) } + const abort = () => + sdk.client.session.abort({ + path: { + id: session.id!, + }, + }) + const handleKeyDown = (event: KeyboardEvent) => { if (store.popoverIsOpen && (event.key === "ArrowUp" || event.key === "ArrowDown" || event.key === "Enter")) { onKeyDown(event) @@ -293,14 +305,101 @@ export const PromptInput: Component = (props) => { if (event.key === "Enter" && !event.shiftKey) { handleSubmit(event) } + if (event.key === "Escape") { + if (store.popoverIsOpen) { + setStore("popoverIsOpen", false) + } else if (session.working()) { + abort() + } + } } - const handleSubmit = (event: Event) => { + const handleSubmit = async (event: Event) => { event.preventDefault() - if (store.contentParts.length > 0) { - props.onSubmit([...store.contentParts]) - setStore("contentParts", defaultParts) + const text = session.prompt + .current() + .map((part) => part.content) + .join("") + if (text.trim().length === 0) { + if (session.working()) abort() + return } + + let existing = session.info() + if (!existing) { + const created = await sdk.client.session.create() + existing = created.data ?? undefined + } + if (!existing) return + + navigate(`/session/${existing.id}`) + if (!session.id) { + // session.layout.setOpenedTabs( + // session.layout.copyTabs("", session.id) + } + session.layout.setActiveTab(undefined) + const toAbsolutePath = (path: string) => (path.startsWith("/") ? path : sync.absolute(path)) + + const attachments = session.prompt.current().filter((part) => part.type === "file") + + // const activeFile = local.context.active() + // if (activeFile) { + // registerAttachment( + // activeFile.path, + // activeFile.selection, + // activeFile.name ?? formatAttachmentLabel(activeFile.path, activeFile.selection), + // ) + // } + + // for (const contextFile of local.context.all()) { + // registerAttachment( + // contextFile.path, + // contextFile.selection, + // formatAttachmentLabel(contextFile.path, contextFile.selection), + // ) + // } + + const attachmentParts = attachments.map((attachment) => { + const absolute = toAbsolutePath(attachment.path) + const query = attachment.selection + ? `?start=${attachment.selection.startLine}&end=${attachment.selection.endLine}` + : "" + return { + type: "file" as const, + mime: "text/plain", + url: `file://${absolute}${query}`, + filename: getFilename(attachment.path), + source: { + type: "file" as const, + text: { + value: attachment.content, + start: attachment.start, + end: attachment.end, + }, + path: absolute, + }, + } + }) + + session.prompt.set(DEFAULT_PROMPT, 0) + + await sdk.client.session.prompt({ + path: { id: existing.id }, + body: { + agent: local.agent.current()!.name, + model: { + modelID: local.model.current()!.id, + providerID: local.model.current()!.provider.id, + }, + parts: [ + { + type: "text", + text, + }, + ...attachmentParts, + ], + }, + }) } return ( @@ -310,11 +409,12 @@ export const PromptInput: Component = (props) => { 0} fallback={
No matching files
}> {(i) => ( -
handleFileSelect(i)} >
@@ -326,7 +426,7 @@ export const PromptInput: Component = (props) => {
-
+ )}
@@ -354,7 +454,7 @@ export const PromptInput: Component = (props) => { "[&>[data-type=file]]:text-icon-info-active": true, }} /> - +
Plan and build anything
@@ -419,29 +519,18 @@ export const PromptInput: Component = (props) => { )}
- + ) } -function isEqual(arrA: ContentPart[], arrB: ContentPart[]): boolean { - if (arrA.length !== arrB.length) return false - for (let i = 0; i < arrA.length; i++) { - const partA = arrA[i] - const partB = arrB[i] - if (partA.type !== partB.type) return false - if (partA.type === "text" && partA.content !== (partB as TextPart).content) { - return false - } - if (partA.type === "file" && partA.path !== (partB as FileAttachmentPart).path) { - return false - } - } - return true -} - function getCursorPosition(parent: HTMLElement): number { const selection = window.getSelection() if (!selection || selection.rangeCount === 0) return 0 diff --git a/packages/desktop/src/context/local.tsx b/packages/desktop/src/context/local.tsx index 8fc05c45..cef6c555 100644 --- a/packages/desktop/src/context/local.tsx +++ b/packages/desktop/src/context/local.tsx @@ -195,18 +195,10 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({ const file = (() => { const [store, setStore] = createStore<{ node: Record - // opened: string[] - // active?: string }>({ node: Object.fromEntries(sync.data.node.map((x) => [x.path, x])), - // opened: [], }) - // const active = createMemo(() => { - // if (!store.active) return undefined - // return store.node[store.active] - // }) - // const opened = createMemo(() => store.opened.map((x) => store.node[x])) const changeset = createMemo(() => new Set(sync.data.changes.map((f) => f.path))) const changes = createMemo(() => Array.from(changeset()).sort((a, b) => a.localeCompare(b))) @@ -247,18 +239,18 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({ return false } - const resetNode = (path: string) => { - setStore("node", path, { - loaded: undefined, - pinned: undefined, - content: undefined, - selection: undefined, - scrollTop: undefined, - folded: undefined, - view: undefined, - selectedChange: undefined, - }) - } + // const resetNode = (path: string) => { + // setStore("node", path, { + // loaded: undefined, + // pinned: undefined, + // content: undefined, + // selection: undefined, + // scrollTop: undefined, + // folded: undefined, + // view: undefined, + // selectedChange: undefined, + // }) + // } const relative = (path: string) => path.replace(sync.data.path.directory + "/", "") @@ -333,31 +325,21 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({ sdk.event.listen((e) => { const event = e.details switch (event.type) { - case "message.part.updated": - const part = event.properties.part - if (part.type === "tool" && part.state.status === "completed") { - switch (part.tool) { - case "read": - break - case "edit": - // load(part.state.input["filePath"] as string) - break - default: - break - } - } - break case "file.watcher.updated": - // setTimeout(sync.load.changes, 1000) - // const relativePath = relative(event.properties.file) - // if (relativePath.startsWith(".git/")) return - // load(relativePath) + const relativePath = relative(event.properties.file) + if (relativePath.startsWith(".git/")) return + load(relativePath) break } }) return { - node: (path: string) => store.node[path], + node: async (path: string) => { + if (!store.node[path]) { + await init(path) + } + return store.node[path] + }, update: (path: string, node: LocalFile) => setStore("node", path, reconcile(node)), open, load, @@ -417,121 +399,6 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({ searchFiles, searchFilesAndDirectories, relative, - // active, - // opened, - // close(path: string) { - // setStore("opened", (opened) => opened.filter((x) => x !== path)) - // if (store.active === path) { - // const index = store.opened.findIndex((f) => f === path) - // const previous = store.opened[Math.max(0, index - 1)] - // setStore("active", previous) - // } - // resetNode(path) - // }, - // move(path: string, to: number) { - // const index = store.opened.findIndex((f) => f === path) - // if (index === -1) return - // setStore( - // "opened", - // produce((opened) => { - // opened.splice(to, 0, opened.splice(index, 1)[0]) - // }), - // ) - // setStore("node", path, "pinned", true) - // }, - } - })() - - const session = (() => { - const [store, setStore] = createStore<{ - active?: string - tabs: Record< - string, - { - active?: string - opened: string[] - } - > - }>({ - tabs: { - "": { - opened: [], - }, - }, - }) - - const active = createMemo(() => { - if (!store.active) return undefined - return sync.session.get(store.active) - }) - - createEffect(() => { - if (!store.active) return - sync.session.sync(store.active) - - if (!store.tabs[store.active]) { - setStore("tabs", store.active, { - opened: [], - }) - } - }) - - const tabs = createMemo(() => store.tabs[store.active ?? ""]) - - return { - active, - setActive(sessionId: string | undefined) { - setStore("active", sessionId) - }, - clearActive() { - setStore("active", undefined) - }, - tabs, - copyTabs(from: string, to: string) { - setStore("tabs", to, { - opened: store.tabs[from]?.opened ?? [], - }) - }, - setActiveTab(tab: string | undefined) { - setStore("tabs", store.active ?? "", "active", tab) - }, - async open(tab: string) { - if (tab !== "chat") { - await file.open(tab) - } - if (!tabs()?.opened?.includes(tab)) { - setStore("tabs", store.active ?? "", "opened", [...(tabs()?.opened ?? []), tab]) - } - setStore("tabs", store.active ?? "", "active", tab) - }, - close(tab: string) { - batch(() => { - if (!tabs()) return - setStore("tabs", store.active ?? "", { - active: tabs()!.active, - opened: tabs()!.opened.filter((x) => x !== tab), - }) - if (tabs()!.active === tab) { - const index = tabs()!.opened.findIndex((f) => f === tab) - const previous = tabs()!.opened[Math.max(0, index - 1)] - setStore("tabs", store.active ?? "", "active", previous) - } - }) - }, - move(tab: string, to: number) { - if (!tabs()) return - const index = tabs()!.opened.findIndex((f) => f === tab) - if (index === -1) return - setStore( - "tabs", - store.active ?? "", - "opened", - produce((opened) => { - opened.splice(to, 0, opened.splice(index, 1)[0]) - }), - ) - // setStore("node", path, "pinned", true) - }, } })() @@ -593,7 +460,6 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({ model, agent, file, - session, context, } return result diff --git a/packages/desktop/src/context/session.tsx b/packages/desktop/src/context/session.tsx new file mode 100644 index 00000000..77ab3bc2 --- /dev/null +++ b/packages/desktop/src/context/session.tsx @@ -0,0 +1,213 @@ +import { createStore, produce } from "solid-js/store" +import { createSimpleContext } from "./helper" +import { batch, createEffect, createMemo } from "solid-js" +import { useSync } from "./sync" +import { makePersisted } from "@solid-primitives/storage" +import { TextSelection, useLocal } from "./local" +import { pipe, sumBy } from "remeda" +import { AssistantMessage } from "@opencode-ai/sdk" + +export const { use: useSession, provider: SessionProvider } = createSimpleContext({ + name: "Session", + init: (props: { sessionId?: string }) => { + const sync = useSync() + const local = useLocal() + + const [store, setStore] = makePersisted( + createStore<{ + prompt: Prompt + cursorPosition?: number + messageId?: string + tabs: { + active?: string + opened: string[] + } + }>({ + prompt: [{ type: "text", content: "", start: 0, end: 0 }], + tabs: { + opened: [], + }, + }), + { + name: props.sessionId ?? "new-session", + }, + ) + + createEffect(() => { + if (!props.sessionId) return + sync.session.sync(props.sessionId) + }) + + const info = createMemo(() => (props.sessionId ? sync.session.get(props.sessionId) : undefined)) + const messages = createMemo(() => (props.sessionId ? (sync.data.message[props.sessionId] ?? []) : [])) + const userMessages = createMemo(() => + messages() + .filter((m) => m.role === "user") + .sort((a, b) => b.id.localeCompare(a.id)), + ) + const lastUserMessage = createMemo(() => { + return userMessages()?.at(0) + }) + const activeMessage = createMemo(() => { + if (!store.messageId) return lastUserMessage() + return userMessages()?.find((m) => m.id === store.messageId) + }) + const working = createMemo(() => { + if (!props.sessionId) return false + const last = lastUserMessage() + if (!last) return false + const assistantMessages = sync.data.message[props.sessionId]?.filter( + (m) => m.role === "assistant" && m.parentID == last?.id, + ) as AssistantMessage[] + const error = assistantMessages?.find((m) => m?.error)?.error + return !last?.summary?.body && !error + }) + + const cost = createMemo(() => { + const total = pipe( + messages(), + sumBy((x) => (x.role === "assistant" ? x.cost : 0)), + ) + return new Intl.NumberFormat("en-US", { + style: "currency", + currency: "USD", + }).format(total) + }) + + const last = createMemo( + () => messages().findLast((x) => x.role === "assistant" && x.tokens.output > 0) as AssistantMessage, + ) + const model = createMemo(() => + last() ? sync.data.provider.find((x) => x.id === last().providerID)?.models[last().modelID] : undefined, + ) + + const tokens = createMemo(() => { + if (!last()) return + const tokens = last().tokens + return tokens.input + tokens.output + tokens.reasoning + tokens.cache.read + tokens.cache.write + }) + + const context = createMemo(() => { + const total = tokens() + const limit = model()?.limit.context + if (!total || !limit) return 0 + return Math.round((total / limit) * 100) + }) + + return { + id: props.sessionId, + info, + working, + prompt: { + current: createMemo(() => store.prompt), + cursor: createMemo(() => store.cursorPosition), + dirty: createMemo(() => !isPromptEqual(store.prompt, DEFAULT_PROMPT)), + set(prompt: Prompt, cursorPosition?: number) { + batch(() => { + setStore("prompt", prompt) + if (cursorPosition !== undefined) setStore("cursorPosition", cursorPosition) + }) + }, + }, + messages: { + all: messages, + user: userMessages, + last: lastUserMessage, + active: activeMessage, + setActive(id: string | undefined) { + setStore("messageId", id) + }, + }, + usage: { + tokens, + cost, + context, + }, + layout: { + tabs: store.tabs, + setActiveTab(tab: string | undefined) { + setStore("tabs", "active", tab) + }, + setOpenedTabs(tabs: string[]) { + setStore("tabs", "opened", tabs) + }, + async openTab(tab: string) { + if (tab === "chat") { + setStore("tabs", "active", undefined) + return + } + if (tab.startsWith("file://")) { + await local.file.open(tab.replace("file://", "")) + } + if (!store.tabs.opened.includes(tab)) { + setStore("tabs", "opened", [...store.tabs.opened, tab]) + } + setStore("tabs", "active", tab) + }, + closeTab(tab: string) { + batch(() => { + setStore( + "tabs", + "opened", + store.tabs.opened.filter((x) => x !== tab), + ) + if (store.tabs.active === tab) { + const index = store.tabs.opened.findIndex((f) => f === tab) + const previous = store.tabs.opened[Math.max(0, index - 1)] + setStore("tabs", "active", previous) + } + }) + }, + moveTab(tab: string, to: number) { + const index = store.tabs.opened.findIndex((f) => f === tab) + if (index === -1) return + setStore( + "tabs", + "opened", + produce((opened) => { + opened.splice(to, 0, opened.splice(index, 1)[0]) + }), + ) + // setStore("node", path, "pinned", true) + }, + }, + } + }, +}) + +interface PartBase { + content: string + start: number + end: number +} + +export interface TextPart extends PartBase { + type: "text" +} + +export interface FileAttachmentPart extends PartBase { + type: "file" + path: string + selection?: TextSelection +} + +export type ContentPart = TextPart | FileAttachmentPart +export type Prompt = ContentPart[] + +export const DEFAULT_PROMPT: Prompt = [{ type: "text", content: "", start: 0, end: 0 }] + +export function isPromptEqual(promptA: Prompt, promptB: Prompt): boolean { + if (promptA.length !== promptB.length) return false + for (let i = 0; i < promptA.length; i++) { + const partA = promptA[i] + const partB = promptB[i] + if (partA.type !== partB.type) return false + if (partA.type === "text" && partA.content !== (partB as TextPart).content) { + return false + } + if (partA.type === "file" && partA.path !== (partB as FileAttachmentPart).path) { + return false + } + } + return true +} diff --git a/packages/desktop/src/context/sync.tsx b/packages/desktop/src/context/sync.tsx index 06fc0567..c60206b0 100644 --- a/packages/desktop/src/context/sync.tsx +++ b/packages/desktop/src/context/sync.tsx @@ -1,16 +1,4 @@ -import type { - Message, - Agent, - Provider, - Session, - Part, - Config, - Path, - File, - FileNode, - Project, - Command, -} from "@opencode-ai/sdk" +import type { Message, Agent, Provider, Session, Part, Config, Path, File, FileNode, Project } from "@opencode-ai/sdk" import { createStore, produce, reconcile } from "solid-js/store" import { createMemo } from "solid-js" import { Binary } from "@/utils/binary" diff --git a/packages/desktop/src/index.tsx b/packages/desktop/src/index.tsx index 9fe5da2f..de9994af 100644 --- a/packages/desktop/src/index.tsx +++ b/packages/desktop/src/index.tsx @@ -7,7 +7,9 @@ import { Fonts, ShikiProvider, MarkedProvider } from "@opencode-ai/ui" import { SDKProvider } from "./context/sdk" import { SyncProvider } from "./context/sync" import { LocalProvider } from "./context/local" -import Home from "@/pages" +import Layout from "@/pages/layout" +import SessionLayout from "@/pages/session-layout" +import Session from "@/pages/session" const host = import.meta.env.VITE_OPENCODE_SERVER_HOST ?? "127.0.0.1" const port = import.meta.env.VITE_OPENCODE_SERVER_PORT ?? "4096" @@ -32,8 +34,10 @@ render( - - + + + + diff --git a/packages/desktop/src/pages/index.tsx b/packages/desktop/src/pages/index.tsx deleted file mode 100644 index 5f04c3db..00000000 --- a/packages/desktop/src/pages/index.tsx +++ /dev/null @@ -1,857 +0,0 @@ -import { - Button, - List, - SelectDialog, - Tooltip, - IconButton, - Tabs, - Icon, - Accordion, - Diff, - Collapsible, - DiffChanges, - Message, - Typewriter, - Card, - Code, -} from "@opencode-ai/ui" -import { FileIcon } from "@/ui" -import FileTree from "@/components/file-tree" -import { MessageProgress } from "@/components/message-progress" -import { For, onCleanup, onMount, Show, Match, Switch, createSignal, createEffect, createMemo } from "solid-js" -import { useLocal, type LocalFile } from "@/context/local" -import { createStore } from "solid-js/store" -import { getDirectory, getFilename } from "@/utils" -import { ContentPart, PromptInput } from "@/components/prompt-input" -import { DateTime } from "luxon" -import { - DragDropProvider, - DragDropSensors, - DragOverlay, - SortableProvider, - closestCenter, - createSortable, - useDragDropContext, -} from "@thisbeyond/solid-dnd" -import type { DragEvent, Transformer } from "@thisbeyond/solid-dnd" -import type { JSX } from "solid-js" -import { useSync } from "@/context/sync" -import { useSDK } from "@/context/sdk" -import { type AssistantMessage as AssistantMessageType } from "@opencode-ai/sdk" -import { Markdown } from "@opencode-ai/ui" -import { Spinner } from "@/components/spinner" - -export default function Page() { - const local = useLocal() - const sync = useSync() - const sdk = useSDK() - const [store, setStore] = createStore({ - clickTimer: undefined as number | undefined, - fileSelectOpen: false, - }) - let inputRef!: HTMLDivElement - let messageScrollElement!: HTMLDivElement - const [activeItem, setActiveItem] = createSignal(undefined) - - const MOD = typeof navigator === "object" && /(Mac|iPod|iPhone|iPad)/.test(navigator.platform) ? "Meta" : "Control" - - onMount(() => { - document.addEventListener("keydown", handleKeyDown) - }) - - onCleanup(() => { - document.removeEventListener("keydown", handleKeyDown) - }) - - const handleKeyDown = (event: KeyboardEvent) => { - if (event.getModifierState(MOD) && event.shiftKey && event.key.toLowerCase() === "p") { - event.preventDefault() - return - } - if (event.getModifierState(MOD) && event.key.toLowerCase() === "p") { - event.preventDefault() - setStore("fileSelectOpen", true) - return - } - - const focused = document.activeElement === inputRef - if (focused) { - if (event.key === "Escape") { - inputRef?.blur() - } - return - } - - // if (local.file.active()) { - // const active = local.file.active()! - // if (event.key === "Enter" && active.selection) { - // local.context.add({ - // type: "file", - // path: active.path, - // selection: { ...active.selection }, - // }) - // return - // } - // - // if (event.getModifierState(MOD)) { - // if (event.key.toLowerCase() === "a") { - // return - // } - // if (event.key.toLowerCase() === "c") { - // return - // } - // } - // } - - if (event.key.length === 1 && event.key !== "Unidentified" && !(event.ctrlKey || event.metaKey)) { - inputRef?.focus() - } - } - - const resetClickTimer = () => { - if (!store.clickTimer) return - clearTimeout(store.clickTimer) - setStore("clickTimer", undefined) - } - - const startClickTimer = () => { - const newClickTimer = setTimeout(() => { - setStore("clickTimer", undefined) - }, 300) - setStore("clickTimer", newClickTimer as unknown as number) - } - - const handleFileClick = async (file: LocalFile) => { - if (store.clickTimer) { - resetClickTimer() - local.file.update(file.path, { ...file, pinned: true }) - } else { - local.file.open(file.path) - startClickTimer() - } - } - - // const navigateChange = (dir: 1 | -1) => { - // const active = local.file.active() - // if (!active) return - // const current = local.file.changeIndex(active.path) - // const next = current === undefined ? (dir === 1 ? 0 : -1) : current + dir - // local.file.setChangeIndex(active.path, next) - // } - - const handleTabChange = (path: string) => { - local.session.setActiveTab(path) - if (path === "chat") return - local.session.open(path) - } - - const handleTabClose = (file: LocalFile) => { - local.session.close(file.path) - } - - const handleDragStart = (event: unknown) => { - const id = getDraggableId(event) - if (!id) return - setActiveItem(id) - } - - const handleDragOver = (event: DragEvent) => { - const { draggable, droppable } = event - if (draggable && droppable) { - const currentFiles = local.session.tabs()?.opened.map((file) => file) - const fromIndex = currentFiles?.indexOf(draggable.id.toString()) - const toIndex = currentFiles?.indexOf(droppable.id.toString()) - if (fromIndex !== toIndex && toIndex !== undefined) { - local.session.move(draggable.id.toString(), toIndex) - } - } - } - - const handleDragEnd = () => { - setActiveItem(undefined) - } - - // const scrollDiffItem = (element: HTMLElement) => { - // element.scrollIntoView({ block: "start", behavior: "instant" }) - // } - - const handleDiffTriggerClick = (event: MouseEvent) => { - // disabling scroll to diff for now - return - // const target = event.currentTarget as HTMLElement - // queueMicrotask(() => { - // if (target.getAttribute("aria-expanded") !== "true") return - // const item = target.closest('[data-slot="accordion-item"]') as HTMLElement | null - // if (!item) return - // scrollDiffItem(item) - // }) - } - - const handlePromptSubmit = async (parts: ContentPart[]) => { - const existingSession = local.session.active() - let session = existingSession - if (!session) { - const created = await sdk.client.session.create() - session = created.data ?? undefined - } - if (!session) return - - local.session.setActive(session.id) - if (!existingSession) { - local.session.copyTabs("", session.id) - } - local.session.setActiveTab(undefined) - const toAbsolutePath = (path: string) => (path.startsWith("/") ? path : sync.absolute(path)) - - const text = parts.map((part) => part.content).join("") - const attachments = parts.filter((part) => part.type === "file") - - // const activeFile = local.context.active() - // if (activeFile) { - // registerAttachment( - // activeFile.path, - // activeFile.selection, - // activeFile.name ?? formatAttachmentLabel(activeFile.path, activeFile.selection), - // ) - // } - - // for (const contextFile of local.context.all()) { - // registerAttachment( - // contextFile.path, - // contextFile.selection, - // formatAttachmentLabel(contextFile.path, contextFile.selection), - // ) - // } - - const attachmentParts = attachments.map((attachment) => { - const absolute = toAbsolutePath(attachment.path) - const query = attachment.selection - ? `?start=${attachment.selection.startLine}&end=${attachment.selection.endLine}` - : "" - return { - type: "file" as const, - mime: "text/plain", - url: `file://${absolute}${query}`, - filename: getFilename(attachment.path), - source: { - type: "file" as const, - text: { - value: attachment.content, - start: attachment.start, - end: attachment.end, - }, - path: absolute, - }, - } - }) - - await sdk.client.session.prompt({ - path: { id: session.id }, - body: { - agent: local.agent.current()!.name, - model: { - modelID: local.model.current()!.id, - providerID: local.model.current()!.provider.id, - }, - parts: [ - { - type: "text", - text, - }, - ...attachmentParts, - ], - }, - }) - } - - const handleNewSession = () => { - local.session.setActive(undefined) - inputRef?.focus() - } - - const TabVisual = (props: { file: LocalFile }): JSX.Element => { - return ( -
- - - {props.file.name} - - -
- ) - } - - const SortableTab = (props: { - file: LocalFile - onTabClick: (file: LocalFile) => void - onTabClose: (file: LocalFile) => void - }): JSX.Element => { - const sortable = createSortable(props.file.path) - - return ( - // @ts-ignore -
- -
- props.onTabClick(props.file)} - > - - props.onTabClose(props.file)} - /> - -
-
-
- ) - } - - const ConstrainDragYAxis = (): JSX.Element => { - const context = useDragDropContext() - if (!context) return <> - const [, { onDragStart, onDragEnd, addTransformer, removeTransformer }] = context - const transformer: Transformer = { - id: "constrain-y-axis", - order: 100, - callback: (transform) => ({ ...transform, y: 0 }), - } - onDragStart((event) => { - const id = getDraggableId(event) - if (!id) return - addTransformer("draggables", id, transformer) - }) - onDragEnd((event) => { - const id = getDraggableId(event) - if (!id) return - removeTransformer("draggables", id, transformer.id) - }) - return <> - } - - const getDraggableId = (event: unknown): string | undefined => { - if (typeof event !== "object" || event === null) return undefined - if (!("draggable" in event)) return undefined - const draggable = (event as { draggable?: { id?: unknown } }).draggable - if (!draggable) return undefined - return typeof draggable.id === "string" ? draggable.id : undefined - } - - return ( -
- -
-
-
- {getFilename(sync.data.path.directory)} -
-
- - x.id} - current={local.session.active()} - onSelect={(s) => local.session.setActive(s?.id)} - onHover={(s) => (!!s ? sync.session.sync(s?.id) : undefined)} - > - {(session) => { - const diffs = createMemo(() => session.summary?.diffs ?? []) - const filesChanged = createMemo(() => diffs().length) - const updated = DateTime.fromMillis(session.time.updated) - return ( - -
-
- - {session.title} - - - {Math.abs(updated.diffNow().as("seconds")) < 60 - ? "Now" - : updated - .toRelative({ style: "short", unit: ["days", "hours", "minutes"] }) - ?.replace(" ago", "") - ?.replace(/ days?/, "d") - ?.replace(" min.", "m") - ?.replace(" hr.", "h")} - -
-
- {`${filesChanged() || "No"} file${filesChanged() !== 1 ? "s" : ""} changed`} - -
-
-
- ) - }} -
-
-
-
- - - - -
- - -
Chat
- {/* */} - {/* */} - {/*
{local.session.context() ?? 0}%
*/} - {/*
*/} -
- {/* Review */} - - - {(file) => ( - - )} - - -
- setStore("fileSelectOpen", true)} - /> -
-
-
- -
- -
New session
-
- -
- {getDirectory(sync.data.path.directory)} - {getFilename(sync.data.path.directory)} -
-
-
- -
- Last modified  - - {DateTime.fromMillis(sync.data.project.time.created).toRelative()} - -
-
-
- } - > - {(session) => { - const [store, setStore] = createStore<{ - messageId?: string - }>() - - const messages = createMemo(() => sync.data.message[session().id] ?? []) - const userMessages = createMemo(() => - messages() - .filter((m) => m.role === "user") - .sort((a, b) => b.id.localeCompare(a.id)), - ) - const lastUserMessage = createMemo(() => { - return userMessages()?.at(0) - }) - const activeMessage = createMemo(() => { - if (!store.messageId) return lastUserMessage() - return userMessages()?.find((m) => m.id === store.messageId) - }) - - return ( -
-
- 1}> - - -
- - {(message) => { - const isActive = createMemo(() => activeMessage()?.id === message.id) - const [titled, setTitled] = createSignal(!!message.summary?.title) - const assistantMessages = createMemo(() => { - return sync.data.message[session().id]?.filter( - (m) => m.role === "assistant" && m.parentID == message.id, - ) as AssistantMessageType[] - }) - const error = createMemo(() => assistantMessages().find((m) => m?.error)?.error) - const [completed, setCompleted] = createSignal(!!message.summary?.body || !!error()) - const [expanded, setExpanded] = createSignal(false) - const parts = createMemo(() => sync.data.part[message.id]) - const title = createMemo(() => message.summary?.title) - const summary = createMemo(() => message.summary?.body) - const diffs = createMemo(() => message.summary?.diffs ?? []) - const hasToolPart = createMemo(() => - assistantMessages() - ?.flatMap((m) => sync.data.part[m.id]) - .some((p) => p?.type === "tool"), - ) - const working = createMemo(() => !summary() && !error()) - - // allowing time for the animations to finish - createEffect(() => { - title() - setTimeout(() => setTitled(!!title()), 10_000) - }) - createEffect(() => { - const complete = !!summary() || !!error() - setTimeout(() => setCompleted(complete), 1200) - }) - - return ( - -
- {/* Title */} -
-
- - } - > -

- {title()} -

-
-
-
-
- -
- {/* Summary */} - -
-
-

- - Summary - Response - -

- - {(summary) => ( - *]:fade-up-text": !diffs().length }} - text={summary()} - /> - )} - -
- - - {(diff) => ( - - - -
-
- -
- - - {getDirectory(diff.file)}‎ - - - - {getFilename(diff.file)} - -
-
-
- - -
-
-
-
- - - -
- )} -
-
-
-
- - - {error()?.data?.message as string} - - - {/* Response */} -
- - - - - - - -
-
- - Hide details - Show details - -
- -
-
- -
- - {(assistantMessage) => { - const parts = createMemo( - () => sync.data.part[assistantMessage.id], - ) - return - }} - - - - {error()?.data?.message as string} - - -
-
-
-
-
-
-
-
- ) - }} -
-
-
-
- ) - }} - -
- - {/* */} - - {(file) => ( - - {(() => { - { - /* const view = local.file.view(file) */ - } - { - /* const showRaw = view === "raw" || !file.content?.diff */ - } - { - /* const code = showRaw ? (file.content?.content ?? "") : (file.content?.diff ?? "") */ - } - const node = local.file.node(file) - return ( - - ) - })()} - - )} - - - - {(() => { - const id = activeItem() - if (!id) return null - const draggedFile = local.file.node(id) - if (!draggedFile) return null - return ( -
- -
- ) - })()} -
- -
- { - inputRef = el - }} - onSubmit={handlePromptSubmit} - /> -
- - } - > -
    - - {(path) => ( -
  • - -
  • - )} -
    -
- -
- - - - x} - onOpenChange={(open) => setStore("fileSelectOpen", open)} - onSelect={(x) => (x ? local.session.open(x) : undefined)} - > - {(i) => ( -
-
- -
- - {getDirectory(i)} - - {getFilename(i)} -
-
-
-
- )} -
-
- - ) -} diff --git a/packages/desktop/src/pages/layout.tsx b/packages/desktop/src/pages/layout.tsx new file mode 100644 index 00000000..afec9ee3 --- /dev/null +++ b/packages/desktop/src/pages/layout.tsx @@ -0,0 +1,75 @@ +import { Button, Tooltip, DiffChanges } from "@opencode-ai/ui" +import { createMemo, ParentProps } from "solid-js" +import { getFilename } from "@/utils" +import { DateTime } from "luxon" +import { useSync } from "@/context/sync" +import { VList } from "virtua/solid" +import { A, useParams } from "@solidjs/router" + +export default function Layout(props: ParentProps) { + const params = useParams() + const sync = useSync() + return ( +
+ +
+
+
+ {getFilename(sync.data.path.directory)} +
+ +
+
{props.children}
+
+
+ ) +} diff --git a/packages/desktop/src/pages/session-layout.tsx b/packages/desktop/src/pages/session-layout.tsx new file mode 100644 index 00000000..9a24608f --- /dev/null +++ b/packages/desktop/src/pages/session-layout.tsx @@ -0,0 +1,12 @@ +import { Show, type ParentProps } from "solid-js" +import { SessionProvider } from "@/context/session" +import { useParams } from "@solidjs/router" + +export default function Layout(props: ParentProps) { + const params = useParams() + return ( + + {props.children} + + ) +} diff --git a/packages/desktop/src/pages/session.tsx b/packages/desktop/src/pages/session.tsx new file mode 100644 index 00000000..9c633f4f --- /dev/null +++ b/packages/desktop/src/pages/session.tsx @@ -0,0 +1,693 @@ +import { + SelectDialog, + IconButton, + Tabs, + Icon, + Accordion, + Diff, + Collapsible, + DiffChanges, + Message, + Typewriter, + Card, + Code, + Tooltip, + ProgressCircle, +} from "@opencode-ai/ui" +import { FileIcon } from "@/ui" +import { MessageProgress } from "@/components/message-progress" +import { + For, + onCleanup, + onMount, + Show, + Match, + Switch, + createSignal, + createEffect, + createMemo, + createResource, +} from "solid-js" +import { useLocal, type LocalFile } from "@/context/local" +import { createStore } from "solid-js/store" +import { getDirectory, getFilename } from "@/utils" +import { PromptInput } from "@/components/prompt-input" +import { DateTime } from "luxon" +import { + DragDropProvider, + DragDropSensors, + DragOverlay, + SortableProvider, + closestCenter, + createSortable, + useDragDropContext, +} from "@thisbeyond/solid-dnd" +import type { DragEvent, Transformer } from "@thisbeyond/solid-dnd" +import type { JSX } from "solid-js" +import { useSync } from "@/context/sync" +import { type AssistantMessage as AssistantMessageType } from "@opencode-ai/sdk" +import { Markdown } from "@opencode-ai/ui" +import { Spinner } from "@/components/spinner" +import { useSession } from "@/context/session" + +export default function Page() { + const local = useLocal() + const sync = useSync() + const session = useSession() + const [store, setStore] = createStore({ + clickTimer: undefined as number | undefined, + fileSelectOpen: false, + activeDraggable: undefined as string | undefined, + }) + let inputRef!: HTMLDivElement + let messageScrollElement!: HTMLDivElement + + const MOD = typeof navigator === "object" && /(Mac|iPod|iPhone|iPad)/.test(navigator.platform) ? "Meta" : "Control" + + onMount(() => { + document.addEventListener("keydown", handleKeyDown) + }) + + onCleanup(() => { + document.removeEventListener("keydown", handleKeyDown) + }) + + const handleKeyDown = (event: KeyboardEvent) => { + if (event.getModifierState(MOD) && event.shiftKey && event.key.toLowerCase() === "p") { + event.preventDefault() + return + } + if (event.getModifierState(MOD) && event.key.toLowerCase() === "p") { + event.preventDefault() + setStore("fileSelectOpen", true) + return + } + + const focused = document.activeElement === inputRef + if (focused) { + if (event.key === "Escape") { + inputRef?.blur() + } + return + } + + // if (local.file.active()) { + // const active = local.file.active()! + // if (event.key === "Enter" && active.selection) { + // local.context.add({ + // type: "file", + // path: active.path, + // selection: { ...active.selection }, + // }) + // return + // } + // + // if (event.getModifierState(MOD)) { + // if (event.key.toLowerCase() === "a") { + // return + // } + // if (event.key.toLowerCase() === "c") { + // return + // } + // } + // } + + if (event.key.length === 1 && event.key !== "Unidentified" && !(event.ctrlKey || event.metaKey)) { + inputRef?.focus() + } + } + + const resetClickTimer = () => { + if (!store.clickTimer) return + clearTimeout(store.clickTimer) + setStore("clickTimer", undefined) + } + + const startClickTimer = () => { + const newClickTimer = setTimeout(() => { + setStore("clickTimer", undefined) + }, 300) + setStore("clickTimer", newClickTimer as unknown as number) + } + + const handleTabClick = async (tab: string) => { + if (store.clickTimer) { + resetClickTimer() + // local.file.update(file.path, { ...file, pinned: true }) + } else { + if (tab.startsWith("file://")) { + local.file.open(tab.replace("file://", "")) + } + startClickTimer() + } + } + + const handleDragStart = (event: unknown) => { + const id = getDraggableId(event) + if (!id) return + setStore("activeDraggable", id) + } + + const handleDragOver = (event: DragEvent) => { + const { draggable, droppable } = event + if (draggable && droppable) { + const currentTabs = session.layout.tabs.opened + const fromIndex = currentTabs?.indexOf(draggable.id.toString()) + const toIndex = currentTabs?.indexOf(droppable.id.toString()) + if (fromIndex !== toIndex && toIndex !== undefined) { + session.layout.moveTab(draggable.id.toString(), toIndex) + } + } + } + + const handleDragEnd = () => { + setStore("activeDraggable", undefined) + } + + const FileVisual = (props: { file: LocalFile }): JSX.Element => { + return ( +
+ + + {props.file.name} + + +
+ ) + } + + const SortableTab = (props: { + tab: string + onTabClick: (tab: string) => void + onTabClose: (tab: string) => void + }): JSX.Element => { + const sortable = createSortable(props.tab) + + const [file] = createResource( + () => props.tab, + async (tab) => { + if (tab.startsWith("file://")) { + return local.file.node(tab.replace("file://", "")) + } + return undefined + }, + ) + + return ( + // @ts-ignore +
+
+ props.onTabClick(props.tab)}> + + {(f) => } + + props.onTabClose(props.tab)} + /> + +
+
+ ) + } + + const ConstrainDragYAxis = (): JSX.Element => { + const context = useDragDropContext() + if (!context) return <> + const [, { onDragStart, onDragEnd, addTransformer, removeTransformer }] = context + const transformer: Transformer = { + id: "constrain-y-axis", + order: 100, + callback: (transform) => ({ ...transform, y: 0 }), + } + onDragStart((event) => { + const id = getDraggableId(event) + if (!id) return + addTransformer("draggables", id, transformer) + }) + onDragEnd((event) => { + const id = getDraggableId(event) + if (!id) return + removeTransformer("draggables", id, transformer.id) + }) + return <> + } + + const getDraggableId = (event: unknown): string | undefined => { + if (typeof event !== "object" || event === null) return undefined + if (!("draggable" in event)) return undefined + const draggable = (event as { draggable?: { id?: unknown } }).draggable + if (!draggable) return undefined + return typeof draggable.id === "string" ? draggable.id : undefined + } + + return ( +
+ + + + +
+ + +
Chat
+ + +
{session.usage.context() ?? 0}%
+
+
+ {/* Review */} + + + {(tab) => } + + +
+ setStore("fileSelectOpen", true)} + /> +
+
+
+ +
+ +
New session
+
+ +
+ {getDirectory(sync.data.path.directory)} + {getFilename(sync.data.path.directory)} +
+
+
+ +
+ Last modified  + + {DateTime.fromMillis(sync.data.project.time.created).toRelative()} + +
+
+
+ } + > + {(_) => { + return ( +
+
+ 1}> + + +
+ + {(message) => { + const isActive = createMemo(() => session.messages.active()?.id === message.id) + const [titled, setTitled] = createSignal(!!message.summary?.title) + const assistantMessages = createMemo(() => { + if (!session.id) return [] + return sync.data.message[session.id]?.filter( + (m) => m.role === "assistant" && m.parentID == message.id, + ) as AssistantMessageType[] + }) + const error = createMemo(() => assistantMessages().find((m) => m?.error)?.error) + const [completed, setCompleted] = createSignal(!!message.summary?.body || !!error()) + const [detailsExpanded, setDetailsExpanded] = createSignal(false) + const parts = createMemo(() => sync.data.part[message.id]) + const hasToolPart = createMemo(() => + assistantMessages() + ?.flatMap((m) => sync.data.part[m.id]) + .some((p) => p?.type === "tool"), + ) + const working = createMemo(() => !message.summary?.body && !error()) + + // allowing time for the animations to finish + createEffect(() => { + const title = message.summary?.title + setTimeout(() => setTitled(!!title), 10_000) + }) + createEffect(() => { + const summary = message.summary?.body + const complete = !!summary || !!error() + setTimeout(() => setCompleted(complete), 1200) + }) + + return ( + +
+ {/* Title */} +
+
+ + } + > +

+ {message.summary?.title} +

+
+
+
+
+ +
+ {/* Summary */} + +
+
+

+ + Summary + Response + +

+ + {(summary) => ( + *]:fade-up-text": !message.summary?.diffs?.length, + }} + text={summary()} + /> + )} + +
+ + + {(diff) => ( + + + +
+
+ +
+ + + {getDirectory(diff.file)}‎ + + + + {getFilename(diff.file)} + +
+
+
+ + +
+
+
+
+ + + +
+ )} +
+
+
+
+ + + {error()?.data?.message as string} + + + {/* Response */} +
+ + + + + + + +
+
+ + Hide details + Show details + +
+ +
+
+ +
+ + {(assistantMessage) => { + const parts = createMemo(() => sync.data.part[assistantMessage.id]) + return + }} + + + + {error()?.data?.message as string} + + +
+
+
+
+
+
+
+
+ ) + }} +
+
+
+
+ ) + }} + +
+ + {/* */} + + {(tab) => { + const [file] = createResource( + () => tab, + async (tab) => { + if (tab.startsWith("file://")) { + return local.file.node(tab.replace("file://", "")) + } + return undefined + }, + ) + return ( + + + + {(f) => ( + + )} + + + + ) + }} + + + + + {(draggedFile) => { + const [file] = createResource( + () => draggedFile(), + async (tab) => { + if (tab.startsWith("file://")) { + return local.file.node(tab.replace("file://", "")) + } + return undefined + }, + ) + return ( +
+ {(f) => } +
+ ) + }} +
+
+ +
+ { + inputRef = el + }} + /> +
+ + }> +
    + + {(path) => ( +
  • + +
  • + )} +
    +
+ + + + x} + onOpenChange={(open) => setStore("fileSelectOpen", open)} + onSelect={(x) => (x ? session.layout.openTab("file://" + x) : undefined)} + > + {(i) => ( +
+
+ +
+ + {getDirectory(i)} + + {getFilename(i)} +
+
+
+
+ )} +
+
+ + ) +} diff --git a/packages/ui/src/components/code.tsx b/packages/ui/src/components/code.tsx index f1c7efad..a3164978 100644 --- a/packages/ui/src/components/code.tsx +++ b/packages/ui/src/components/code.tsx @@ -11,20 +11,21 @@ export type CodeProps = FileOptions & { export function Code(props: CodeProps) { let container!: HTMLDivElement const [local, others] = splitProps(props, ["file", "class", "classList", "annotations"]) - const file = () => local.file createEffect(() => { const instance = new File({ theme: { dark: "oc-1-dark", light: "oc-1-light" }, // or any Shiki theme overflow: "wrap", // or 'scroll' themeType: "system", // 'system', 'light', or 'dark' + disableFileHeader: true, disableLineNumbers: false, // optional // lang: 'typescript', // optional - auto-detected from filename if not provided ...others, }) + container.innerHTML = "" instance.render({ - file: file(), + file: local.file, lineAnnotations: local.annotations, containerWrapper: container, }) diff --git a/packages/ui/src/components/diff.tsx b/packages/ui/src/components/diff.tsx index f3ca74a8..6297a642 100644 --- a/packages/ui/src/components/diff.tsx +++ b/packages/ui/src/components/diff.tsx @@ -154,6 +154,7 @@ export function Diff(props: DiffProps) { ...others, }) + container.innerHTML = "" instance.render({ oldFile: local.before, newFile: local.after, diff --git a/packages/ui/src/components/icon.tsx b/packages/ui/src/components/icon.tsx index a2e12729..61799720 100644 --- a/packages/ui/src/components/icon.tsx +++ b/packages/ui/src/components/icon.tsx @@ -150,6 +150,7 @@ const newIcons = { "code-lines": ``, "square-arrow-top-right": ``, "circle-ban-sign": ``, + stop: ``, } export interface IconProps extends ComponentProps<"svg"> { diff --git a/packages/ui/src/components/input.tsx b/packages/ui/src/components/input.tsx index 509e242c..55e84c3a 100644 --- a/packages/ui/src/components/input.tsx +++ b/packages/ui/src/components/input.tsx @@ -2,22 +2,37 @@ import { TextField as Kobalte } from "@kobalte/core/text-field" import { Show, splitProps } from "solid-js" import type { ComponentProps } from "solid-js" -export interface InputProps extends ComponentProps { +export interface InputProps + extends ComponentProps, + Pick, "value" | "onChange" | "onKeyDown"> { label?: string hideLabel?: boolean description?: string } export function Input(props: InputProps) { - const [local, others] = splitProps(props, ["class", "label", "hideLabel", "description", "placeholder"]) + const [local, others] = splitProps(props, [ + "class", + "label", + "hideLabel", + "description", + "value", + "onChange", + "onKeyDown", + ]) return ( - + {local.label} - + {local.description} diff --git a/packages/ui/src/components/list.tsx b/packages/ui/src/components/list.tsx index aaba61fd..766979ae 100644 --- a/packages/ui/src/components/list.tsx +++ b/packages/ui/src/components/list.tsx @@ -62,7 +62,13 @@ export function List(props: ListProps) { }) return ( - + {(item) => ( - - {(session) => { - const updated = createMemo(() => DateTime.fromMillis(session.time.updated)) - return ( - - -
+
+ + + ) + }} + + + + + +
{props.children}
From 306f45f04a3cb282e2d88082d9afe222eb397573 Mon Sep 17 00:00:00 2001 From: Dax Raad Date: Wed, 5 Nov 2025 18:04:31 -0500 Subject: [PATCH 046/218] add opencode import command to restore sessions from JSON exports --- packages/opencode/src/cli/cmd/import.ts | 51 +++++++++++++++++++++++++ packages/opencode/src/index.ts | 2 + 2 files changed, 53 insertions(+) create mode 100644 packages/opencode/src/cli/cmd/import.ts diff --git a/packages/opencode/src/cli/cmd/import.ts b/packages/opencode/src/cli/cmd/import.ts new file mode 100644 index 00000000..eeb2e688 --- /dev/null +++ b/packages/opencode/src/cli/cmd/import.ts @@ -0,0 +1,51 @@ +import type { Argv } from "yargs" +import { Session } from "../../session" +import { cmd } from "./cmd" +import { bootstrap } from "../bootstrap" +import { UI } from "../ui" +import { Storage } from "../../storage/storage" +import { Instance } from "../../project/instance" +import { EOL } from "os" + +export const ImportCommand = cmd({ + command: "import ", + describe: "import session data from JSON file", + builder: (yargs: Argv) => { + return yargs.positional("file", { + describe: "path to JSON file to import", + type: "string", + demandOption: true, + }) + }, + handler: async (args) => { + await bootstrap(process.cwd(), async () => { + const file = Bun.file(args.file as string) + const exists = await file.exists() + if (!exists) { + UI.error(`File not found: ${args.file}`) + process.exit(1) + } + + const exportData = (await file.json()) as { + info: Session.Info + messages: Array<{ + info: any + parts: any[] + }> + } + + await Storage.write(["session", Instance.project.id, exportData.info.id], exportData.info) + + for (const msg of exportData.messages) { + await Storage.write(["message", exportData.info.id, msg.info.id], msg.info) + + for (const part of msg.parts) { + await Storage.write(["part", msg.info.id, part.id], part) + } + } + + process.stdout.write(`Imported session: ${exportData.info.id}`) + process.stdout.write(EOL) + }) + }, +}) diff --git a/packages/opencode/src/index.ts b/packages/opencode/src/index.ts index 7fd7aeb1..01580699 100644 --- a/packages/opencode/src/index.ts +++ b/packages/opencode/src/index.ts @@ -17,6 +17,7 @@ import { StatsCommand } from "./cli/cmd/stats" import { McpCommand } from "./cli/cmd/mcp" import { GithubCommand } from "./cli/cmd/github" import { ExportCommand } from "./cli/cmd/export" +import { ImportCommand } from "./cli/cmd/import" import { AttachCommand } from "./cli/cmd/tui/attach" import { TuiThreadCommand } from "./cli/cmd/tui/thread" import { TuiSpawnCommand } from "./cli/cmd/tui/spawn" @@ -87,6 +88,7 @@ const cli = yargs(hideBin(process.argv)) .command(ModelsCommand) .command(StatsCommand) .command(ExportCommand) + .command(ImportCommand) .command(GithubCommand) .fail((msg) => { if ( From e316050bf573c657e4b38da0a8ac9230a9880a08 Mon Sep 17 00:00:00 2001 From: Dax Raad Date: Wed, 5 Nov 2025 18:27:19 -0500 Subject: [PATCH 047/218] temporarily remove bun strip ansi due to bug --- packages/opencode/src/cli/cmd/import.ts | 16 +++++++--------- .../src/cli/cmd/tui/routes/session/index.tsx | 2 +- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/packages/opencode/src/cli/cmd/import.ts b/packages/opencode/src/cli/cmd/import.ts index eeb2e688..afebadc3 100644 --- a/packages/opencode/src/cli/cmd/import.ts +++ b/packages/opencode/src/cli/cmd/import.ts @@ -2,7 +2,6 @@ import type { Argv } from "yargs" import { Session } from "../../session" import { cmd } from "./cmd" import { bootstrap } from "../bootstrap" -import { UI } from "../ui" import { Storage } from "../../storage/storage" import { Instance } from "../../project/instance" import { EOL } from "os" @@ -19,20 +18,19 @@ export const ImportCommand = cmd({ }, handler: async (args) => { await bootstrap(process.cwd(), async () => { - const file = Bun.file(args.file as string) - const exists = await file.exists() - if (!exists) { - UI.error(`File not found: ${args.file}`) - process.exit(1) - } - - const exportData = (await file.json()) as { + const file = Bun.file(args.file) + const exportData = (await file.json().catch(() => {})) as { info: Session.Info messages: Array<{ info: any parts: any[] }> } + if (!exportData) { + process.stdout.write(`File not found: ${args.file}`) + process.stdout.write(EOL) + return + } await Storage.write(["session", Instance.project.id, exportData.info.id], exportData.info) diff --git a/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx b/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx index 0adde4c8..1968987d 100644 --- a/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx +++ b/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx @@ -1171,7 +1171,7 @@ ToolRegistry.register({ name: "bash", container: "block", render(props) { - const output = createMemo(() => Bun.stripANSI(props.metadata.output?.trim() ?? "")) + const output = createMemo(() => props.metadata.output?.trim() ?? "") const { theme } = useTheme() return ( <> From c9ae89a38b3330456c1349c40b757248eba00c43 Mon Sep 17 00:00:00 2001 From: opencode Date: Wed, 5 Nov 2025 23:32:22 +0000 Subject: [PATCH 048/218] release: v1.0.30 --- bun.lock | 22 +++++++++++----------- packages/console/app/package.json | 2 +- packages/console/core/package.json | 2 +- packages/console/function/package.json | 2 +- packages/console/mail/package.json | 2 +- packages/desktop/package.json | 2 +- packages/function/package.json | 2 +- packages/opencode/package.json | 2 +- packages/plugin/package.json | 2 +- packages/sdk/js/package.json | 2 +- packages/slack/package.json | 2 +- packages/ui/package.json | 2 +- packages/web/package.json | 2 +- sdks/vscode/package.json | 2 +- 14 files changed, 24 insertions(+), 24 deletions(-) diff --git a/bun.lock b/bun.lock index ea7e22cd..1706cd77 100644 --- a/bun.lock +++ b/bun.lock @@ -39,7 +39,7 @@ }, "packages/console/core": { "name": "@opencode-ai/console-core", - "version": "1.0.29", + "version": "1.0.30", "dependencies": { "@aws-sdk/client-sts": "3.782.0", "@jsx-email/render": "1.1.1", @@ -66,7 +66,7 @@ }, "packages/console/function": { "name": "@opencode-ai/console-function", - "version": "1.0.29", + "version": "1.0.30", "dependencies": { "@ai-sdk/anthropic": "2.0.0", "@ai-sdk/openai": "2.0.2", @@ -90,7 +90,7 @@ }, "packages/console/mail": { "name": "@opencode-ai/console-mail", - "version": "1.0.29", + "version": "1.0.30", "dependencies": { "@jsx-email/all": "2.2.3", "@jsx-email/cli": "1.4.3", @@ -111,7 +111,7 @@ }, "packages/desktop": { "name": "@opencode-ai/desktop", - "version": "1.0.29", + "version": "1.0.30", "dependencies": { "@kobalte/core": "catalog:", "@opencode-ai/sdk": "workspace:*", @@ -151,7 +151,7 @@ }, "packages/function": { "name": "@opencode-ai/function", - "version": "1.0.29", + "version": "1.0.30", "dependencies": { "@octokit/auth-app": "8.0.1", "@octokit/rest": "22.0.0", @@ -167,7 +167,7 @@ }, "packages/opencode": { "name": "opencode", - "version": "1.0.29", + "version": "1.0.30", "bin": { "opencode": "./bin/opencode", }, @@ -244,7 +244,7 @@ }, "packages/plugin": { "name": "@opencode-ai/plugin", - "version": "1.0.29", + "version": "1.0.30", "dependencies": { "@opencode-ai/sdk": "workspace:*", "zod": "catalog:", @@ -264,7 +264,7 @@ }, "packages/sdk/js": { "name": "@opencode-ai/sdk", - "version": "1.0.29", + "version": "1.0.30", "devDependencies": { "@hey-api/openapi-ts": "0.81.0", "@tsconfig/node22": "catalog:", @@ -275,7 +275,7 @@ }, "packages/slack": { "name": "@opencode-ai/slack", - "version": "1.0.29", + "version": "1.0.30", "dependencies": { "@opencode-ai/sdk": "workspace:*", "@slack/bolt": "^3.17.1", @@ -288,7 +288,7 @@ }, "packages/ui": { "name": "@opencode-ai/ui", - "version": "1.0.29", + "version": "1.0.30", "dependencies": { "@kobalte/core": "catalog:", "@opencode-ai/sdk": "workspace:*", @@ -318,7 +318,7 @@ }, "packages/web": { "name": "@opencode-ai/web", - "version": "1.0.29", + "version": "1.0.30", "dependencies": { "@astrojs/cloudflare": "12.6.3", "@astrojs/markdown-remark": "6.3.1", diff --git a/packages/console/app/package.json b/packages/console/app/package.json index 29f64f0c..3b12a686 100644 --- a/packages/console/app/package.json +++ b/packages/console/app/package.json @@ -7,7 +7,7 @@ "dev:remote": "VITE_AUTH_URL=https://auth.dev.opencode.ai bun sst shell --stage=dev bun dev", "build": "vinxi build && ../../opencode/script/schema.ts ./.output/public/config.json", "start": "vinxi start", - "version": "1.0.29" + "version": "1.0.30" }, "dependencies": { "@ibm/plex": "6.4.1", diff --git a/packages/console/core/package.json b/packages/console/core/package.json index 1c5a400e..4c9b6792 100644 --- a/packages/console/core/package.json +++ b/packages/console/core/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@opencode-ai/console-core", - "version": "1.0.29", + "version": "1.0.30", "private": true, "type": "module", "dependencies": { diff --git a/packages/console/function/package.json b/packages/console/function/package.json index e9ab76ac..b0721092 100644 --- a/packages/console/function/package.json +++ b/packages/console/function/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/console-function", - "version": "1.0.29", + "version": "1.0.30", "$schema": "https://json.schemastore.org/package.json", "private": true, "type": "module", diff --git a/packages/console/mail/package.json b/packages/console/mail/package.json index cb4d10df..7bd6061f 100644 --- a/packages/console/mail/package.json +++ b/packages/console/mail/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/console-mail", - "version": "1.0.29", + "version": "1.0.30", "dependencies": { "@jsx-email/all": "2.2.3", "@jsx-email/cli": "1.4.3", diff --git a/packages/desktop/package.json b/packages/desktop/package.json index 77a5d643..edadbc9a 100644 --- a/packages/desktop/package.json +++ b/packages/desktop/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/desktop", - "version": "1.0.29", + "version": "1.0.30", "description": "", "type": "module", "scripts": { diff --git a/packages/function/package.json b/packages/function/package.json index bc3dc0c3..ce393910 100644 --- a/packages/function/package.json +++ b/packages/function/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/function", - "version": "1.0.29", + "version": "1.0.30", "$schema": "https://json.schemastore.org/package.json", "private": true, "type": "module", diff --git a/packages/opencode/package.json b/packages/opencode/package.json index 3a7d7016..cf4c87a2 100644 --- a/packages/opencode/package.json +++ b/packages/opencode/package.json @@ -1,6 +1,6 @@ { "$schema": "https://json.schemastore.org/package.json", - "version": "1.0.29", + "version": "1.0.30", "name": "opencode", "type": "module", "private": true, diff --git a/packages/plugin/package.json b/packages/plugin/package.json index 55609034..a8531f0c 100644 --- a/packages/plugin/package.json +++ b/packages/plugin/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@opencode-ai/plugin", - "version": "1.0.29", + "version": "1.0.30", "type": "module", "scripts": { "typecheck": "tsgo --noEmit", diff --git a/packages/sdk/js/package.json b/packages/sdk/js/package.json index e875c4af..64c2c8ed 100644 --- a/packages/sdk/js/package.json +++ b/packages/sdk/js/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@opencode-ai/sdk", - "version": "1.0.29", + "version": "1.0.30", "type": "module", "scripts": { "typecheck": "tsgo --noEmit", diff --git a/packages/slack/package.json b/packages/slack/package.json index 93efe207..d7ed96b0 100644 --- a/packages/slack/package.json +++ b/packages/slack/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/slack", - "version": "1.0.29", + "version": "1.0.30", "type": "module", "scripts": { "dev": "bun run src/index.ts", diff --git a/packages/ui/package.json b/packages/ui/package.json index 2329f858..96a3aa43 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/ui", - "version": "1.0.29", + "version": "1.0.30", "type": "module", "exports": { ".": "./src/components/index.ts", diff --git a/packages/web/package.json b/packages/web/package.json index 9978202f..57724979 100644 --- a/packages/web/package.json +++ b/packages/web/package.json @@ -1,7 +1,7 @@ { "name": "@opencode-ai/web", "type": "module", - "version": "1.0.29", + "version": "1.0.30", "scripts": { "dev": "astro dev", "dev:remote": "VITE_API_URL=https://api.opencode.ai astro dev", diff --git a/sdks/vscode/package.json b/sdks/vscode/package.json index f0ef9ad7..a53147d8 100644 --- a/sdks/vscode/package.json +++ b/sdks/vscode/package.json @@ -2,7 +2,7 @@ "name": "opencode", "displayName": "opencode", "description": "opencode for VS Code", - "version": "1.0.29", + "version": "1.0.30", "publisher": "sst-dev", "repository": { "type": "git", From 2a9b6a85dee84d974c3808488b5b4ea3eb93abed Mon Sep 17 00:00:00 2001 From: Dax Raad Date: Wed, 5 Nov 2025 18:35:59 -0500 Subject: [PATCH 049/218] core: ensure export command output can be piped without UI interference --- packages/opencode/src/cli/cmd/export.ts | 18 ++++++++++++++---- packages/opencode/src/util/log.ts | 21 ++++++++++++++------- 2 files changed, 28 insertions(+), 11 deletions(-) diff --git a/packages/opencode/src/cli/cmd/export.ts b/packages/opencode/src/cli/cmd/export.ts index 82952f1f..4e040abd 100644 --- a/packages/opencode/src/cli/cmd/export.ts +++ b/packages/opencode/src/cli/cmd/export.ts @@ -18,10 +18,13 @@ export const ExportCommand = cmd({ handler: async (args) => { await bootstrap(process.cwd(), async () => { let sessionID = args.sessionID + process.stderr.write(`Exporting session: ${sessionID ?? "latest"}`) if (!sessionID) { UI.empty() - prompts.intro("Export session") + prompts.intro("Export session", { + output: process.stderr, + }) const sessions = [] for await (const session of Session.list()) { @@ -29,8 +32,12 @@ export const ExportCommand = cmd({ } if (sessions.length === 0) { - prompts.log.error("No sessions found") - prompts.outro("Done") + prompts.log.error("No sessions found", { + output: process.stderr, + }) + prompts.outro("Done", { + output: process.stderr, + }) return } @@ -44,6 +51,7 @@ export const ExportCommand = cmd({ value: session.id, hint: `${new Date(session.time.updated).toLocaleString()} • ${session.id.slice(-8)}`, })), + output: process.stderr, }) if (prompts.isCancel(selectedSession)) { @@ -52,7 +60,9 @@ export const ExportCommand = cmd({ sessionID = selectedSession as string - prompts.outro("Exporting session...") + prompts.outro("Exporting session...", { + output: process.stderr, + }) } try { diff --git a/packages/opencode/src/util/log.ts b/packages/opencode/src/util/log.ts index 46306956..6b31952f 100644 --- a/packages/opencode/src/util/log.ts +++ b/packages/opencode/src/util/log.ts @@ -4,7 +4,9 @@ import { Global } from "../global" import z from "zod" export namespace Log { - export const Level = z.enum(["DEBUG", "INFO", "WARN", "ERROR"]).meta({ ref: "LogLevel", description: "Log level" }) + export const Level = z + .enum(["DEBUG", "INFO", "WARN", "ERROR"]) + .meta({ ref: "LogLevel", description: "Log level" }) export type Level = z.infer const levelPriority: Record = { @@ -50,6 +52,7 @@ export namespace Log { export function file() { return logpath } + let write: (msg: string) => void export async function init(options: Options) { if (options.level) level = options.level @@ -62,7 +65,7 @@ export namespace Log { const logfile = Bun.file(logpath) await fs.truncate(logpath).catch(() => {}) const writer = logfile.writer() - process.stderr.write = (msg) => { + write = (msg) => { writer.write(msg) writer.flush() return true @@ -118,27 +121,31 @@ export namespace Log { const next = new Date() const diff = next.getTime() - last last = next.getTime() - return [next.toISOString().split(".")[0], "+" + diff + "ms", prefix, message].filter(Boolean).join(" ") + "\n" + return ( + [next.toISOString().split(".")[0], "+" + diff + "ms", prefix, message] + .filter(Boolean) + .join(" ") + "\n" + ) } const result: Logger = { debug(message?: any, extra?: Record) { if (shouldLog("DEBUG")) { - process.stderr.write("DEBUG " + build(message, extra)) + write("DEBUG " + build(message, extra)) } }, info(message?: any, extra?: Record) { if (shouldLog("INFO")) { - process.stderr.write("INFO " + build(message, extra)) + write("INFO " + build(message, extra)) } }, error(message?: any, extra?: Record) { if (shouldLog("ERROR")) { - process.stderr.write("ERROR " + build(message, extra)) + write("ERROR " + build(message, extra)) } }, warn(message?: any, extra?: Record) { if (shouldLog("WARN")) { - process.stderr.write("WARN " + build(message, extra)) + write("WARN " + build(message, extra)) } }, tag(key: string, value: string) { From 8b26a1f9bdb61e636cd93d023bb1d17cbc505bf1 Mon Sep 17 00:00:00 2001 From: Sebastian Herrlinger Date: Thu, 6 Nov 2025 01:38:49 +0100 Subject: [PATCH 050/218] upgrade to opentui 0.1.35, mitigating disappearing content and crashes --- bun.lock | 20 ++++--------------- packages/opencode/package.json | 4 ++-- .../src/cli/cmd/tui/routes/session/index.tsx | 1 + 3 files changed, 7 insertions(+), 18 deletions(-) diff --git a/bun.lock b/bun.lock index 1706cd77..7b73d7b0 100644 --- a/bun.lock +++ b/bun.lock @@ -185,8 +185,8 @@ "@opencode-ai/plugin": "workspace:*", "@opencode-ai/script": "workspace:*", "@opencode-ai/sdk": "workspace:*", - "@opentui/core": "0.1.33", - "@opentui/solid": "0.1.33", + "@opentui/core": "0.1.35", + "@opentui/solid": "0.1.35", "@parcel/watcher": "2.5.1", "@pierre/precision-diffs": "catalog:", "@solid-primitives/event-bus": "1.1.2", @@ -962,21 +962,9 @@ "@opentelemetry/api": ["@opentelemetry/api@1.9.0", "", {}, "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg=="], - "@opentui/core": ["@opentui/core@0.1.33", "", { "dependencies": { "bun-ffi-structs": "^0.1.0", "jimp": "1.6.0", "yoga-layout": "3.2.1" }, "optionalDependencies": { "@dimforge/rapier2d-simd-compat": "^0.17.3", "@opentui/core-darwin-arm64": "0.1.33", "@opentui/core-darwin-x64": "0.1.33", "@opentui/core-linux-arm64": "0.1.33", "@opentui/core-linux-x64": "0.1.33", "@opentui/core-win32-arm64": "0.1.33", "@opentui/core-win32-x64": "0.1.33", "bun-webgpu": "0.1.3", "planck": "^1.4.2", "three": "0.177.0" }, "peerDependencies": { "web-tree-sitter": "0.25.10" } }, "sha512-vwHdrPIqnsY6YnG2JTNhenHSsx+HUPYrQTBZdmEfCj9ROGVzKgUKbSDH1xGK2OtSNRb2KVBg4XaMpq0bie6afQ=="], + "@opentui/core": ["@opentui/core@0.1.35", "", { "dependencies": { "bun-ffi-structs": "^0.1.0", "jimp": "1.6.0", "yoga-layout": "3.2.1" }, "optionalDependencies": { "@dimforge/rapier2d-simd-compat": "^0.17.3", "@opentui/core-darwin-arm64": "0.1.35", "@opentui/core-darwin-x64": "0.1.35", "@opentui/core-linux-arm64": "0.1.35", "@opentui/core-linux-x64": "0.1.35", "@opentui/core-win32-arm64": "0.1.35", "@opentui/core-win32-x64": "0.1.35", "bun-webgpu": "0.1.3", "planck": "^1.4.2", "three": "0.177.0" }, "peerDependencies": { "web-tree-sitter": "0.25.10" } }, "sha512-t7xUaie+ri7ROXcWWLrQ0XY0Mo2kH6gqyagZrNRgUjH1zudqPBYJddiw7Kc9LMuPtV8usPzlzjXIny+EzuawkA=="], - "@opentui/core-darwin-arm64": ["@opentui/core-darwin-arm64@0.1.33", "", { "os": "darwin", "cpu": "arm64" }, "sha512-JBvzcP2V7fT9KxFAMenHRd/t72qPP5IL5kzge2uok1T7t2nw3Wa+CWI5s6FYP42p2b1W9qZkv5Fno5gA7OAYuQ=="], - - "@opentui/core-darwin-x64": ["@opentui/core-darwin-x64@0.1.33", "", { "os": "darwin", "cpu": "x64" }, "sha512-x7DY6VCkAky10z/2o4UkkuNW/nIvoX7uAh3dJOHWZCLbiKywSFvFk3QZVVcH5BMk4tOOophYTzika4s4HpaeMg=="], - - "@opentui/core-linux-arm64": ["@opentui/core-linux-arm64@0.1.33", "", { "os": "linux", "cpu": "arm64" }, "sha512-bBc1EdkVxsLBtqGjXM2BYpBJLa57ogcrSADSZbc5cQkPu0muSGzUwBbVnVZJUjWEfk6n5jcd4dDmLezVoQga0A=="], - - "@opentui/core-linux-x64": ["@opentui/core-linux-x64@0.1.33", "", { "os": "linux", "cpu": "x64" }, "sha512-3oVL5mrLlKLUc1lc4v7xS3BJ9N7PnnimbGwAvlnVpfaAygotAs1XkPcjsUe6ItMnSJyi0FWiDHUE2+GiDtM5Nw=="], - - "@opentui/core-win32-arm64": ["@opentui/core-win32-arm64@0.1.33", "", { "os": "win32", "cpu": "arm64" }, "sha512-Q68v7wssE+r0OG1KIGfi7m3fnu8KOK4ZNg9ML6EwE47VF9/bqgUe+6fPiXh5mmHzTwof7nAOdXCf052av5/upQ=="], - - "@opentui/core-win32-x64": ["@opentui/core-win32-x64@0.1.33", "", { "os": "win32", "cpu": "x64" }, "sha512-PvuchmUnbMCUXXMzfle/WTzhNGIdJ6RGCCoclx3YVUyNUVuUicPf42OEV+td2m81/Hr3CgcLn98HYX1TLIzPrw=="], - - "@opentui/solid": ["@opentui/solid@0.1.33", "", { "dependencies": { "@babel/core": "7.28.0", "@babel/preset-typescript": "7.27.1", "@opentui/core": "0.1.33", "babel-plugin-module-resolver": "5.0.2", "babel-preset-solid": "1.9.9", "s-js": "^0.4.9" }, "peerDependencies": { "solid-js": "1.9.9" } }, "sha512-bWSALdGJ2j51zwZ2gK1ZIBxFgauHq+V1ejEnyd4XamYMdWfpAKU+AUWDVLbpx1T9XG1oAnycJZfYX7BsZdVOOg=="], + "@opentui/solid": ["@opentui/solid@0.1.35", "", { "dependencies": { "@babel/core": "7.28.0", "@babel/preset-typescript": "7.27.1", "@opentui/core": "0.1.35", "babel-plugin-module-resolver": "5.0.2", "babel-preset-solid": "1.9.9", "s-js": "^0.4.9" }, "peerDependencies": { "solid-js": "1.9.9" } }, "sha512-VIhPmnZstthNpDWZzouOE6YzEnLHI3HbuT9wL6wf0K7Fp0kJEGUA7dlYscSpX9ZBY15B7COnIkSagC/C7hUQkw=="], "@oslojs/asn1": ["@oslojs/asn1@1.0.0", "", { "dependencies": { "@oslojs/binary": "1.0.0" } }, "sha512-zw/wn0sj0j0QKbIXfIlnEcTviaCzYOY3V5rAyjR6YtOByFtJiT574+8p9Wlach0lZH9fddD4yb9laEAIl4vXQA=="], diff --git a/packages/opencode/package.json b/packages/opencode/package.json index cf4c87a2..b2d3e8c7 100644 --- a/packages/opencode/package.json +++ b/packages/opencode/package.json @@ -54,8 +54,8 @@ "@opencode-ai/plugin": "workspace:*", "@opencode-ai/script": "workspace:*", "@opencode-ai/sdk": "workspace:*", - "@opentui/core": "0.1.33", - "@opentui/solid": "0.1.33", + "@opentui/core": "0.1.35", + "@opentui/solid": "0.1.35", "@parcel/watcher": "2.5.1", "@pierre/precision-diffs": "catalog:", "@solid-primitives/event-bus": "1.1.2", diff --git a/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx b/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx index 1968987d..37820759 100644 --- a/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx +++ b/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx @@ -1011,6 +1011,7 @@ function TextPart(props: { part: TextPart; message: AssistantMessage }) { Date: Wed, 5 Nov 2025 20:00:09 -0500 Subject: [PATCH 051/218] fix log --- packages/opencode/src/util/log.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/opencode/src/util/log.ts b/packages/opencode/src/util/log.ts index 6b31952f..548f6b2b 100644 --- a/packages/opencode/src/util/log.ts +++ b/packages/opencode/src/util/log.ts @@ -52,7 +52,7 @@ export namespace Log { export function file() { return logpath } - let write: (msg: string) => void + let write = process.stderr.write export async function init(options: Options) { if (options.level) level = options.level @@ -65,7 +65,7 @@ export namespace Log { const logfile = Bun.file(logpath) await fs.truncate(logpath).catch(() => {}) const writer = logfile.writer() - write = (msg) => { + write = (msg: any) => { writer.write(msg) writer.flush() return true From 247ce447760f6afbf9c522865fbfc43a15e2cefc Mon Sep 17 00:00:00 2001 From: Dax Raad Date: Wed, 5 Nov 2025 20:01:57 -0500 Subject: [PATCH 052/218] fix log --- packages/opencode/src/util/log.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/opencode/src/util/log.ts b/packages/opencode/src/util/log.ts index 548f6b2b..5b013c05 100644 --- a/packages/opencode/src/util/log.ts +++ b/packages/opencode/src/util/log.ts @@ -52,7 +52,7 @@ export namespace Log { export function file() { return logpath } - let write = process.stderr.write + let write = (msg: any) => Bun.stderr.write(msg) export async function init(options: Options) { if (options.level) level = options.level @@ -68,7 +68,6 @@ export namespace Log { write = (msg: any) => { writer.write(msg) writer.flush() - return true } } From 6555a33eff502268bfa008c12fb61c556261a917 Mon Sep 17 00:00:00 2001 From: Dax Raad Date: Wed, 5 Nov 2025 20:14:31 -0500 Subject: [PATCH 053/218] type errors --- packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx | 3 ++- packages/opencode/src/util/log.ts | 5 +++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx b/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx index c3ae1407..663e4f52 100644 --- a/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx +++ b/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx @@ -8,6 +8,7 @@ import { t, dim, fg, + type KeyBinding, } from "@opentui/core" import { createEffect, createMemo, Match, Switch, type JSX, onMount, batch } from "solid-js" import { useLocal } from "@tui/context/local" @@ -84,7 +85,7 @@ export function Prompt(props: PromptProps) { shift: binding.shift || undefined, action: "submit" as const, })), - ] + ] satisfies KeyBinding[] }) const fileStyleId = syntax().getStyleId("extmark.file")! diff --git a/packages/opencode/src/util/log.ts b/packages/opencode/src/util/log.ts index 5b013c05..e771a903 100644 --- a/packages/opencode/src/util/log.ts +++ b/packages/opencode/src/util/log.ts @@ -65,9 +65,10 @@ export namespace Log { const logfile = Bun.file(logpath) await fs.truncate(logpath).catch(() => {}) const writer = logfile.writer() - write = (msg: any) => { - writer.write(msg) + write = async (msg: any) => { + const num = writer.write(msg) writer.flush() + return num } } From ef25650cedb46af3ba7ea6632761d496d2179f53 Mon Sep 17 00:00:00 2001 From: Dax Raad Date: Wed, 5 Nov 2025 20:30:40 -0500 Subject: [PATCH 054/218] regen bunlock --- bun.lock | 201 ++++++++++++++++++++++++++++++++----------------------- 1 file changed, 116 insertions(+), 85 deletions(-) diff --git a/bun.lock b/bun.lock index 7b73d7b0..50481cb7 100644 --- a/bun.lock +++ b/bun.lock @@ -352,7 +352,6 @@ "trustedDependencies": [ "sharp", "esbuild", - "tree-sitter", "web-tree-sitter", "tree-sitter-bash", ], @@ -572,7 +571,7 @@ "@cloudflare/kv-asset-handler": ["@cloudflare/kv-asset-handler@0.4.0", "", { "dependencies": { "mime": "^3.0.0" } }, "sha512-+tv3z+SPp+gqTIcImN9o0hqE9xyfQjI1XD9pL6NuKjua9B1y7mNYv0S9cP+QEbA4ppVgGZEmKOvHX5G5Ei1CVA=="], - "@cloudflare/unenv-preset": ["@cloudflare/unenv-preset@2.7.8", "", { "peerDependencies": { "unenv": "2.0.0-rc.21", "workerd": "^1.20250927.0" }, "optionalPeers": ["workerd"] }, "sha512-Ky929MfHh+qPhwCapYrRPwPVHtA2Ioex/DbGZyskGyNRDe9Ru3WThYZivyNVaPy5ergQSgMs9OKrM9Ajtz9F6w=="], + "@cloudflare/unenv-preset": ["@cloudflare/unenv-preset@2.7.9", "", { "peerDependencies": { "unenv": "2.0.0-rc.24", "workerd": "^1.20250927.0" }, "optionalPeers": ["workerd"] }, "sha512-Drm7qlTKnvncEv+DANiQNEonq0H0LyIsoFZYJ6tJ8OhAoy5udIE8yp6BsVDYcIjcYLIybp4M7c/P7ly/56SoHg=="], "@cloudflare/workerd-darwin-64": ["@cloudflare/workerd-darwin-64@1.20251011.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-0DirVP+Z82RtZLlK2B+VhLOkk+ShBqDYO/jhcRw4oVlp0TOvk3cOVZChrt3+y3NV8Y/PYgTEywzLKFSziK4wCg=="], @@ -602,7 +601,7 @@ "@drizzle-team/brocli": ["@drizzle-team/brocli@0.10.2", "", {}, "sha512-z33Il7l5dKjUgGULTqBsQBQwckHh5AbIuxhdsIxDDiZAzBOrZO6q9ogcWC65kU382AfynTfgNumVcNIjuIua6w=="], - "@emnapi/runtime": ["@emnapi/runtime@1.6.0", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-obtUmAHTMjll499P+D9A3axeJFlhdjOWdKUNs/U6QIGT7V5RjcUW1xToAzjvmgTSQhDbYn/NwfTRoJcQ2rNBxA=="], + "@emnapi/runtime": ["@emnapi/runtime@1.7.0", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-oAYoQnCYaQZKVS53Fq23ceWMRxq5EhQsE0x0RdQ55jT7wagMu5k+fS39v1fiSLrtrLQlXwVINenqhLMtTrV/1Q=="], "@emotion/is-prop-valid": ["@emotion/is-prop-valid@0.8.8", "", { "dependencies": { "@emotion/memoize": "0.7.4" } }, "sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA=="], @@ -612,57 +611,57 @@ "@esbuild-kit/esm-loader": ["@esbuild-kit/esm-loader@2.6.5", "", { "dependencies": { "@esbuild-kit/core-utils": "^3.3.2", "get-tsconfig": "^4.7.0" } }, "sha512-FxEMIkJKnodyA1OaCUoEvbYRkoZlLZ4d/eXFu9Fh8CbBBgP5EmZxrfTRyN0qpXZ4vOvqnE5YdRdcrmUUXuU+dA=="], - "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.11", "", { "os": "aix", "cpu": "ppc64" }, "sha512-Xt1dOL13m8u0WE8iplx9Ibbm+hFAO0GsU2P34UNoDGvZYkY8ifSiy6Zuc1lYxfG7svWE2fzqCUmFp5HCn51gJg=="], + "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.12", "", { "os": "aix", "cpu": "ppc64" }, "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA=="], - "@esbuild/android-arm": ["@esbuild/android-arm@0.25.11", "", { "os": "android", "cpu": "arm" }, "sha512-uoa7dU+Dt3HYsethkJ1k6Z9YdcHjTrSb5NUy66ZfZaSV8hEYGD5ZHbEMXnqLFlbBflLsl89Zke7CAdDJ4JI+Gg=="], + "@esbuild/android-arm": ["@esbuild/android-arm@0.25.12", "", { "os": "android", "cpu": "arm" }, "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg=="], - "@esbuild/android-arm64": ["@esbuild/android-arm64@0.25.11", "", { "os": "android", "cpu": "arm64" }, "sha512-9slpyFBc4FPPz48+f6jyiXOx/Y4v34TUeDDXJpZqAWQn/08lKGeD8aDp9TMn9jDz2CiEuHwfhRmGBvpnd/PWIQ=="], + "@esbuild/android-arm64": ["@esbuild/android-arm64@0.25.12", "", { "os": "android", "cpu": "arm64" }, "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg=="], - "@esbuild/android-x64": ["@esbuild/android-x64@0.25.11", "", { "os": "android", "cpu": "x64" }, "sha512-Sgiab4xBjPU1QoPEIqS3Xx+R2lezu0LKIEcYe6pftr56PqPygbB7+szVnzoShbx64MUupqoE0KyRlN7gezbl8g=="], + "@esbuild/android-x64": ["@esbuild/android-x64@0.25.12", "", { "os": "android", "cpu": "x64" }, "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg=="], - "@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.25.11", "", { "os": "darwin", "cpu": "arm64" }, "sha512-VekY0PBCukppoQrycFxUqkCojnTQhdec0vevUL/EDOCnXd9LKWqD/bHwMPzigIJXPhC59Vd1WFIL57SKs2mg4w=="], + "@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.25.12", "", { "os": "darwin", "cpu": "arm64" }, "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg=="], - "@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.25.11", "", { "os": "darwin", "cpu": "x64" }, "sha512-+hfp3yfBalNEpTGp9loYgbknjR695HkqtY3d3/JjSRUyPg/xd6q+mQqIb5qdywnDxRZykIHs3axEqU6l1+oWEQ=="], + "@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.25.12", "", { "os": "darwin", "cpu": "x64" }, "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA=="], - "@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.25.11", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-CmKjrnayyTJF2eVuO//uSjl/K3KsMIeYeyN7FyDBjsR3lnSJHaXlVoAK8DZa7lXWChbuOk7NjAc7ygAwrnPBhA=="], + "@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.25.12", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg=="], - "@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.25.11", "", { "os": "freebsd", "cpu": "x64" }, "sha512-Dyq+5oscTJvMaYPvW3x3FLpi2+gSZTCE/1ffdwuM6G1ARang/mb3jvjxs0mw6n3Lsw84ocfo9CrNMqc5lTfGOw=="], + "@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.25.12", "", { "os": "freebsd", "cpu": "x64" }, "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ=="], - "@esbuild/linux-arm": ["@esbuild/linux-arm@0.25.11", "", { "os": "linux", "cpu": "arm" }, "sha512-TBMv6B4kCfrGJ8cUPo7vd6NECZH/8hPpBHHlYI3qzoYFvWu2AdTvZNuU/7hsbKWqu/COU7NIK12dHAAqBLLXgw=="], + "@esbuild/linux-arm": ["@esbuild/linux-arm@0.25.12", "", { "os": "linux", "cpu": "arm" }, "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw=="], - "@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.25.11", "", { "os": "linux", "cpu": "arm64" }, "sha512-Qr8AzcplUhGvdyUF08A1kHU3Vr2O88xxP0Tm8GcdVOUm25XYcMPp2YqSVHbLuXzYQMf9Bh/iKx7YPqECs6ffLA=="], + "@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.25.12", "", { "os": "linux", "cpu": "arm64" }, "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ=="], - "@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.25.11", "", { "os": "linux", "cpu": "ia32" }, "sha512-TmnJg8BMGPehs5JKrCLqyWTVAvielc615jbkOirATQvWWB1NMXY77oLMzsUjRLa0+ngecEmDGqt5jiDC6bfvOw=="], + "@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.25.12", "", { "os": "linux", "cpu": "ia32" }, "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA=="], - "@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.25.11", "", { "os": "linux", "cpu": "none" }, "sha512-DIGXL2+gvDaXlaq8xruNXUJdT5tF+SBbJQKbWy/0J7OhU8gOHOzKmGIlfTTl6nHaCOoipxQbuJi7O++ldrxgMw=="], + "@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.25.12", "", { "os": "linux", "cpu": "none" }, "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng=="], - "@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.25.11", "", { "os": "linux", "cpu": "none" }, "sha512-Osx1nALUJu4pU43o9OyjSCXokFkFbyzjXb6VhGIJZQ5JZi8ylCQ9/LFagolPsHtgw6himDSyb5ETSfmp4rpiKQ=="], + "@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.25.12", "", { "os": "linux", "cpu": "none" }, "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw=="], - "@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.25.11", "", { "os": "linux", "cpu": "ppc64" }, "sha512-nbLFgsQQEsBa8XSgSTSlrnBSrpoWh7ioFDUmwo158gIm5NNP+17IYmNWzaIzWmgCxq56vfr34xGkOcZ7jX6CPw=="], + "@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.25.12", "", { "os": "linux", "cpu": "ppc64" }, "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA=="], - "@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.25.11", "", { "os": "linux", "cpu": "none" }, "sha512-HfyAmqZi9uBAbgKYP1yGuI7tSREXwIb438q0nqvlpxAOs3XnZ8RsisRfmVsgV486NdjD7Mw2UrFSw51lzUk1ww=="], + "@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.25.12", "", { "os": "linux", "cpu": "none" }, "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w=="], - "@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.25.11", "", { "os": "linux", "cpu": "s390x" }, "sha512-HjLqVgSSYnVXRisyfmzsH6mXqyvj0SA7pG5g+9W7ESgwA70AXYNpfKBqh1KbTxmQVaYxpzA/SvlB9oclGPbApw=="], + "@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.25.12", "", { "os": "linux", "cpu": "s390x" }, "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg=="], - "@esbuild/linux-x64": ["@esbuild/linux-x64@0.25.11", "", { "os": "linux", "cpu": "x64" }, "sha512-HSFAT4+WYjIhrHxKBwGmOOSpphjYkcswF449j6EjsjbinTZbp8PJtjsVK1XFJStdzXdy/jaddAep2FGY+wyFAQ=="], + "@esbuild/linux-x64": ["@esbuild/linux-x64@0.25.12", "", { "os": "linux", "cpu": "x64" }, "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw=="], - "@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.25.11", "", { "os": "none", "cpu": "arm64" }, "sha512-hr9Oxj1Fa4r04dNpWr3P8QKVVsjQhqrMSUzZzf+LZcYjZNqhA3IAfPQdEh1FLVUJSiu6sgAwp3OmwBfbFgG2Xg=="], + "@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.25.12", "", { "os": "none", "cpu": "arm64" }, "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg=="], - "@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.25.11", "", { "os": "none", "cpu": "x64" }, "sha512-u7tKA+qbzBydyj0vgpu+5h5AeudxOAGncb8N6C9Kh1N4n7wU1Xw1JDApsRjpShRpXRQlJLb9wY28ELpwdPcZ7A=="], + "@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.25.12", "", { "os": "none", "cpu": "x64" }, "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ=="], - "@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.25.11", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-Qq6YHhayieor3DxFOoYM1q0q1uMFYb7cSpLD2qzDSvK1NAvqFi8Xgivv0cFC6J+hWVw2teCYltyy9/m/14ryHg=="], + "@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.25.12", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A=="], - "@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.25.11", "", { "os": "openbsd", "cpu": "x64" }, "sha512-CN+7c++kkbrckTOz5hrehxWN7uIhFFlmS/hqziSFVWpAzpWrQoAG4chH+nN3Be+Kzv/uuo7zhX716x3Sn2Jduw=="], + "@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.25.12", "", { "os": "openbsd", "cpu": "x64" }, "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw=="], - "@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.25.11", "", { "os": "none", "cpu": "arm64" }, "sha512-rOREuNIQgaiR+9QuNkbkxubbp8MSO9rONmwP5nKncnWJ9v5jQ4JxFnLu4zDSRPf3x4u+2VN4pM4RdyIzDty/wQ=="], + "@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.25.12", "", { "os": "none", "cpu": "arm64" }, "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg=="], - "@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.25.11", "", { "os": "sunos", "cpu": "x64" }, "sha512-nq2xdYaWxyg9DcIyXkZhcYulC6pQ2FuCgem3LI92IwMgIZ69KHeY8T4Y88pcwoLIjbed8n36CyKoYRDygNSGhA=="], + "@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.25.12", "", { "os": "sunos", "cpu": "x64" }, "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w=="], - "@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.25.11", "", { "os": "win32", "cpu": "arm64" }, "sha512-3XxECOWJq1qMZ3MN8srCJ/QfoLpL+VaxD/WfNRm1O3B4+AZ/BnLVgFbUV3eiRYDMXetciH16dwPbbHqwe1uU0Q=="], + "@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.25.12", "", { "os": "win32", "cpu": "arm64" }, "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg=="], - "@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.25.11", "", { "os": "win32", "cpu": "ia32" }, "sha512-3ukss6gb9XZ8TlRyJlgLn17ecsK4NSQTmdIXRASVsiS2sQ6zPPZklNJT5GR5tE/MUarymmy8kCEf5xPCNCqVOA=="], + "@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.25.12", "", { "os": "win32", "cpu": "ia32" }, "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ=="], - "@esbuild/win32-x64": ["@esbuild/win32-x64@0.25.11", "", { "os": "win32", "cpu": "x64" }, "sha512-D7Hpz6A2L4hzsRpPaCYkQnGOotdUpDzSGRIv9I+1ITdHROSFUWW95ZPZWQmGka1Fg7W3zFJowyn9WGwMJ0+KPA=="], + "@esbuild/win32-x64": ["@esbuild/win32-x64@0.25.12", "", { "os": "win32", "cpu": "x64" }, "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA=="], "@expressive-code/core": ["@expressive-code/core@0.41.3", "", { "dependencies": { "@ctrl/tinycolor": "^4.0.4", "hast-util-select": "^6.0.2", "hast-util-to-html": "^9.0.1", "hast-util-to-text": "^4.0.1", "hastscript": "^9.0.0", "postcss": "^8.4.38", "postcss-nested": "^6.0.1", "unist-util-visit": "^5.0.0", "unist-util-visit-parents": "^6.0.1" } }, "sha512-9qzohqU7O0+JwMEEgQhnBPOw5DtsQRBXhW++5fvEywsuX44vCGGof1SL5OvPElvNgaWZ4pFZAFSlkNOkGyLwSQ=="], @@ -964,6 +963,18 @@ "@opentui/core": ["@opentui/core@0.1.35", "", { "dependencies": { "bun-ffi-structs": "^0.1.0", "jimp": "1.6.0", "yoga-layout": "3.2.1" }, "optionalDependencies": { "@dimforge/rapier2d-simd-compat": "^0.17.3", "@opentui/core-darwin-arm64": "0.1.35", "@opentui/core-darwin-x64": "0.1.35", "@opentui/core-linux-arm64": "0.1.35", "@opentui/core-linux-x64": "0.1.35", "@opentui/core-win32-arm64": "0.1.35", "@opentui/core-win32-x64": "0.1.35", "bun-webgpu": "0.1.3", "planck": "^1.4.2", "three": "0.177.0" }, "peerDependencies": { "web-tree-sitter": "0.25.10" } }, "sha512-t7xUaie+ri7ROXcWWLrQ0XY0Mo2kH6gqyagZrNRgUjH1zudqPBYJddiw7Kc9LMuPtV8usPzlzjXIny+EzuawkA=="], + "@opentui/core-darwin-arm64": ["@opentui/core-darwin-arm64@0.1.35", "", { "os": "darwin", "cpu": "arm64" }, "sha512-mSu6sS4a8DBejMqr06xtRdLtS+8m4oRzFVNtiKuY1T9PL74SnRmUl3VFxseY19ZMSVVAz/7hHPFX+ttmoT2pEw=="], + + "@opentui/core-darwin-x64": ["@opentui/core-darwin-x64@0.1.35", "", { "os": "darwin", "cpu": "x64" }, "sha512-HqIbf25OSJgsxfe+G6ZvpsGolj1V8yTIXrAUcRSqCmw/Xdp82JqTnI6zx1cxQSllVmF4SxT+WwTRG216DE5MMw=="], + + "@opentui/core-linux-arm64": ["@opentui/core-linux-arm64@0.1.35", "", { "os": "linux", "cpu": "arm64" }, "sha512-zNZpKg2fxZTsMJAjW3M9Il+1if61oe+d3m98hPm1i/UDtM+Fj8pkU0XBnsIJHfP5GVNnVHuLksXDpqmHquNmOg=="], + + "@opentui/core-linux-x64": ["@opentui/core-linux-x64@0.1.35", "", { "os": "linux", "cpu": "x64" }, "sha512-KKLw9Po+KC0u0JWG9p1bCWKro3dzSg56QQ8Y9CR/wT2ywTatNrtiYeymoeft3BogWSz65PxQr7Dw8kwdUOD3yQ=="], + + "@opentui/core-win32-arm64": ["@opentui/core-win32-arm64@0.1.35", "", { "os": "win32", "cpu": "arm64" }, "sha512-5ycmzf0D8SkaR4xlTZqneegFt4w4RK2Q9yZC3ZiAclNMtffVnWOkK/3zIpCwTdi2I1wHPVG0doX6pi0EUM7f2A=="], + + "@opentui/core-win32-x64": ["@opentui/core-win32-x64@0.1.35", "", { "os": "win32", "cpu": "x64" }, "sha512-m/l9NkzT/asdpPPN0525z5JcYiHc++feIisqmHS1+IfqirTDuReyKk7HxU3MydxrFcsp1LBMCxFipWiYV2V9hw=="], + "@opentui/solid": ["@opentui/solid@0.1.35", "", { "dependencies": { "@babel/core": "7.28.0", "@babel/preset-typescript": "7.27.1", "@opentui/core": "0.1.35", "babel-plugin-module-resolver": "5.0.2", "babel-preset-solid": "1.9.9", "s-js": "^0.4.9" }, "peerDependencies": { "solid-js": "1.9.9" } }, "sha512-VIhPmnZstthNpDWZzouOE6YzEnLHI3HbuT9wL6wf0K7Fp0kJEGUA7dlYscSpX9ZBY15B7COnIkSagC/C7hUQkw=="], "@oslojs/asn1": ["@oslojs/asn1@1.0.0", "", { "dependencies": { "@oslojs/binary": "1.0.0" } }, "sha512-zw/wn0sj0j0QKbIXfIlnEcTviaCzYOY3V5rAyjR6YtOByFtJiT574+8p9Wlach0lZH9fddD4yb9laEAIl4vXQA=="], @@ -1030,7 +1041,7 @@ "@poppinss/colors": ["@poppinss/colors@4.1.5", "", { "dependencies": { "kleur": "^4.1.5" } }, "sha512-FvdDqtcRCtz6hThExcFOgW0cWX+xwSMWcRuQe5ZEb2m7cVQOAVZOIMt+/v9RxGiD9/OY16qJBXK4CVKWAPalBw=="], - "@poppinss/dumper": ["@poppinss/dumper@0.6.4", "", { "dependencies": { "@poppinss/colors": "^4.1.5", "@sindresorhus/is": "^7.0.2", "supports-color": "^10.0.0" } }, "sha512-iG0TIdqv8xJ3Lt9O8DrPRxw1MRLjNpoqiSGU03P/wNLP/s0ra0udPJ1J2Tx5M0J3H/cVyEgpbn8xUKRY9j59kQ=="], + "@poppinss/dumper": ["@poppinss/dumper@0.6.5", "", { "dependencies": { "@poppinss/colors": "^4.1.5", "@sindresorhus/is": "^7.0.2", "supports-color": "^10.0.0" } }, "sha512-NBdYIb90J7LfOI32dOewKI1r7wnkiH6m920puQ3qHUeZkxNkQiFnXVWoE6YtFSv6QOiPPf7ys6i+HWWecDz7sw=="], "@poppinss/exception": ["@poppinss/exception@1.2.2", "", {}, "sha512-m7bpKCD4QMlFCjA/nKTs23fuvoVFoA83brRKmObCUNmi/9tVu8Ve3w4YQAnJu4q3Tjf5fr685HYIC/IA2zHRSg=="], @@ -1176,7 +1187,7 @@ "@shikijs/vscode-textmate": ["@shikijs/vscode-textmate@10.0.2", "", {}, "sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg=="], - "@sindresorhus/is": ["@sindresorhus/is@7.1.0", "", {}, "sha512-7F/yz2IphV39hiS2zB4QYVkivrptHHh0K8qJJd9HhuWSdvf8AN7NpebW3CcDZDBQsUPMoDKWsY2WWgW7bqOcfA=="], + "@sindresorhus/is": ["@sindresorhus/is@7.1.1", "", {}, "sha512-rO92VvpgMc3kfiTjGT52LEtJ8Yc5kCWhZjLQ3LwlA4pSgPpQO7bVpYXParOD8Jwf+cVQECJo3yP/4I8aZtUQTQ=="], "@sindresorhus/merge-streams": ["@sindresorhus/merge-streams@4.0.0", "", {}, "sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ=="], @@ -1194,7 +1205,7 @@ "@smithy/abort-controller": ["@smithy/abort-controller@4.2.4", "", { "dependencies": { "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-Z4DUr/AkgyFf1bOThW2HwzREagee0sB5ycl+hDiSZOfRLW8ZgrOjDi6g8mHH19yyU5E2A/64W3z6SMIf5XiUSQ=="], - "@smithy/config-resolver": ["@smithy/config-resolver@4.4.1", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.4", "@smithy/types": "^4.8.1", "@smithy/util-config-provider": "^4.2.0", "@smithy/util-endpoints": "^3.2.4", "@smithy/util-middleware": "^4.2.4", "tslib": "^2.6.2" } }, "sha512-BciDJ5hkyYEGBBKMbjGB1A/Zq8bYZ41Zo9BMnGdKF6QD1fY4zIkYx6zui/0CHaVGnv6h0iy8y4rnPX9CPCAPyQ=="], + "@smithy/config-resolver": ["@smithy/config-resolver@4.4.2", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.4", "@smithy/types": "^4.8.1", "@smithy/util-config-provider": "^4.2.0", "@smithy/util-endpoints": "^3.2.4", "@smithy/util-middleware": "^4.2.4", "tslib": "^2.6.2" } }, "sha512-4Jys0ni2tB2VZzgslbEgszZyMdTkPOFGA8g+So/NjR8oy6Qwaq4eSwsrRI+NMtb0Dq4kqCzGUu/nGUx7OM/xfw=="], "@smithy/core": ["@smithy/core@3.17.2", "", { "dependencies": { "@smithy/middleware-serde": "^4.2.4", "@smithy/protocol-http": "^5.3.4", "@smithy/types": "^4.8.1", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-middleware": "^4.2.4", "@smithy/util-stream": "^4.5.5", "@smithy/util-utf8": "^4.2.0", "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" } }, "sha512-n3g4Nl1Te+qGPDbNFAYf+smkRVB+JhFsGy9uJXXZQEufoP4u0r+WLh6KvTDolCswaagysDc/afS1yvb2jnj1gQ=="], @@ -1256,7 +1267,7 @@ "@smithy/util-defaults-mode-browser": ["@smithy/util-defaults-mode-browser@4.3.5", "", { "dependencies": { "@smithy/property-provider": "^4.2.4", "@smithy/smithy-client": "^4.9.2", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-GwaGjv/QLuL/QHQaqhf/maM7+MnRFQQs7Bsl6FlaeK6lm6U7mV5AAnVabw68cIoMl5FQFyKK62u7RWRzWL25OQ=="], - "@smithy/util-defaults-mode-node": ["@smithy/util-defaults-mode-node@4.2.7", "", { "dependencies": { "@smithy/config-resolver": "^4.4.1", "@smithy/credential-provider-imds": "^4.2.4", "@smithy/node-config-provider": "^4.3.4", "@smithy/property-provider": "^4.2.4", "@smithy/smithy-client": "^4.9.2", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-6hinjVqec0WYGsqN7h9hL/ywfULmJJNXGXnNZW7jrIn/cFuC/aVlVaiDfBIJEvKcOrmN8/EgsW69eY0gXABeHw=="], + "@smithy/util-defaults-mode-node": ["@smithy/util-defaults-mode-node@4.2.8", "", { "dependencies": { "@smithy/config-resolver": "^4.4.2", "@smithy/credential-provider-imds": "^4.2.4", "@smithy/node-config-provider": "^4.3.4", "@smithy/property-provider": "^4.2.4", "@smithy/smithy-client": "^4.9.2", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-gIoTf9V/nFSIZ0TtgDNLd+Ws59AJvijmMDYrOozoMHPJaG9cMRdqNO50jZTlbM6ydzQYY8L/mQ4tKSw/TB+s6g=="], "@smithy/util-endpoints": ["@smithy/util-endpoints@3.2.4", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.4", "@smithy/types": "^4.8.1", "tslib": "^2.6.2" } }, "sha512-f+nBDhgYRCmUEDKEQb6q0aCcOTXRDqH5wWaFHJxt4anB4pKHlgGoYP3xtioKXH64e37ANUkzWf6p4Mnv1M5/Vg=="], @@ -1310,7 +1321,7 @@ "@solidjs/start": ["@solidjs/start@1.2.0", "", { "dependencies": { "@tanstack/server-functions-plugin": "1.121.21", "@vinxi/plugin-directives": "^0.5.0", "@vinxi/server-components": "^0.5.0", "cookie-es": "^2.0.0", "defu": "^6.1.2", "error-stack-parser": "^2.1.4", "html-to-image": "^1.11.11", "radix3": "^1.1.0", "seroval": "^1.0.2", "seroval-plugins": "^1.0.2", "shiki": "^1.26.1", "source-map-js": "^1.0.2", "terracotta": "^1.0.4", "tinyglobby": "^0.2.2", "vite-plugin-solid": "^2.11.1" }, "peerDependencies": { "vinxi": "^0.5.7" } }, "sha512-SRv1g3R+4sxZnxCBPK1IedtLKsPhPJ7W/Yv4xEHjM4jJGPWi3ed35/yd0D5zhRK0C7zJIkZKbhnR/S3g8JUD5w=="], - "@speed-highlight/core": ["@speed-highlight/core@1.2.8", "", {}, "sha512-IGytNtnUnPIobIbOq5Y6LIlqiHNX+vnToQIS7lj6L5819C+rA8TXRDkkG8vePsiBOGcoW9R6i+dp2YBUKdB09Q=="], + "@speed-highlight/core": ["@speed-highlight/core@1.2.12", "", {}, "sha512-uilwrK0Ygyri5dToHYdZSjcvpS2ZwX0w5aSt3GCEN9hrjxWCoeV4Z2DTXuxjwbntaLQIEEAlCeNQss5SoHvAEA=="], "@standard-community/standard-json": ["@standard-community/standard-json@0.3.5", "", { "peerDependencies": { "@standard-schema/spec": "^1.0.0", "@types/json-schema": "^7.0.15", "@valibot/to-json-schema": "^1.3.0", "arktype": "^2.1.20", "effect": "^3.16.8", "quansync": "^0.2.11", "sury": "^10.0.0", "typebox": "^1.0.17", "valibot": "^1.1.0", "zod": "^3.25.0 || ^4.0.0", "zod-to-json-schema": "^3.24.5" }, "optionalPeers": ["@valibot/to-json-schema", "arktype", "effect", "sury", "typebox", "valibot", "zod", "zod-to-json-schema"] }, "sha512-4+ZPorwDRt47i+O7RjyuaxHRK/37QY/LmgxlGrRrSTLYoFatEOzvqIc85GTlM18SFZ5E91C+v0o/M37wZPpUHA=="], @@ -1438,7 +1449,7 @@ "@types/scheduler": ["@types/scheduler@0.26.0", "", {}, "sha512-WFHp9YUJQ6CKshqoC37iOlHnQSmxNc795UhB26CyBBttrN9svdIrUjl/NjnNmfcwtncN0h/0PPAFWv9ovP8mLA=="], - "@types/send": ["@types/send@0.17.6", "", { "dependencies": { "@types/mime": "^1", "@types/node": "*" } }, "sha512-Uqt8rPBE8SY0RK8JB1EzVOIZ32uqy8HwdxCnoCOsYrvnswqmFZ/k+9Ikidlk/ImhsdvBsloHbAlewb2IEBV/Og=="], + "@types/send": ["@types/send@1.2.1", "", { "dependencies": { "@types/node": "*" } }, "sha512-arsCikDvlU99zl1g69TcAB3mzZPpxgw0UQnaHeC1Nwb015xp8bknZv5rIfri9xTOcMuaVgvabfIRA7PSZVuZIQ=="], "@types/serve-static": ["@types/serve-static@1.15.10", "", { "dependencies": { "@types/http-errors": "*", "@types/node": "*", "@types/send": "<1" } }, "sha512-tRs1dB+g8Itk72rlSI2ZrW6vZg0YrLI81iQSTkMmOqnqCaNr/8Ek4VwWcN5vZgCYWbg/JJSGBlUaYGAOP73qBw=="], @@ -1580,7 +1591,7 @@ "aws4fetch": ["aws4fetch@1.0.20", "", {}, "sha512-/djoAN709iY65ETD6LKCtyyEI04XIBP5xVvfmNxsEP0uJB5tyaGBztSryRr4HqMStr9R06PisQE7m9zDTXKu6g=="], - "axios": ["axios@1.13.1", "", { "dependencies": { "follow-redirects": "^1.15.6", "form-data": "^4.0.4", "proxy-from-env": "^1.1.0" } }, "sha512-hU4EGxxt+j7TQijx1oYdAjw4xuIp1wRQSsbMFwSthCWeBQur1eF+qJ5iQ5sN3Tw8YRzQNKb8jszgBdMDVqwJcw=="], + "axios": ["axios@1.13.2", "", { "dependencies": { "follow-redirects": "^1.15.6", "form-data": "^4.0.4", "proxy-from-env": "^1.1.0" } }, "sha512-VPk9ebNqPcy5lRGuSlKx752IlDatOjT9paPlm8A7yOuW2Fbvp4X3JznJtT4f0GzGLLiWE9W8onz51SqLYwzGaA=="], "axobject-query": ["axobject-query@4.1.0", "", {}, "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ=="], @@ -1608,13 +1619,13 @@ "bare-stream": ["bare-stream@2.7.0", "", { "dependencies": { "streamx": "^2.21.0" }, "peerDependencies": { "bare-buffer": "*", "bare-events": "*" }, "optionalPeers": ["bare-buffer", "bare-events"] }, "sha512-oyXQNicV1y8nc2aKffH+BUHFRXmx6VrPzlnaEvMhram0nPBrKcEdcyBg5r08D0i8VxngHFAiVyn1QKXpSG0B8A=="], - "bare-url": ["bare-url@2.3.1", "", { "dependencies": { "bare-path": "^3.0.0" } }, "sha512-v2yl0TnaZTdEnelkKtXZGnotiV6qATBlnNuUMrHl6v9Lmmrh9mw9RYyImPU7/4RahumSwQS1k2oKXcRfXcbjJw=="], + "bare-url": ["bare-url@2.3.2", "", { "dependencies": { "bare-path": "^3.0.0" } }, "sha512-ZMq4gd9ngV5aTMa5p9+UfY0b3skwhHELaDkhEHetMdX0LRkW9kzaym4oo/Eh+Ghm0CCDuMTsRIGM/ytUc1ZYmw=="], "base-64": ["base-64@1.0.0", "", {}, "sha512-kwDPIFCGx0NZHog36dj+tHiwP4QMzsZ3AgMViUBKI0+V5n4U0ufTCUMhnQ04diaRI8EX/QcPfql7zlhZ7j4zgg=="], "base64-js": ["base64-js@1.5.1", "", {}, "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="], - "baseline-browser-mapping": ["baseline-browser-mapping@2.8.21", "", { "bin": { "baseline-browser-mapping": "dist/cli.js" } }, "sha512-JU0h5APyQNsHOlAM7HnQnPToSDQoEBZqzu/YBlqDnEeymPnZDREeXJA3KBMQee+dKteAxZ2AtvQEvVYdZf241Q=="], + "baseline-browser-mapping": ["baseline-browser-mapping@2.8.25", "", { "bin": { "baseline-browser-mapping": "dist/cli.js" } }, "sha512-2NovHVesVF5TXefsGX1yzx1xgr7+m9JQenvz6FQY3qd+YXkKkYiv+vTCc7OriP9mcDZpTC5mAOYN4ocd29+erA=="], "bcp-47": ["bcp-47@2.1.0", "", { "dependencies": { "is-alphabetical": "^2.0.0", "is-alphanumerical": "^2.0.0", "is-decimal": "^2.0.0" } }, "sha512-9IIS3UPrvIa1Ej+lVDdDwO7zLehjqsaByECw0bu2RRGP73jALm6FYbzI5gWbgHLvNdkvfXB5YrSbocZdOS0c0w=="], @@ -1692,7 +1703,7 @@ "camelcase-css": ["camelcase-css@2.0.1", "", {}, "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA=="], - "caniuse-lite": ["caniuse-lite@1.0.30001752", "", {}, "sha512-vKUk7beoukxE47P5gcVNKkDRzXdVofotshHwfR9vmpeFKxmI5PBpgOMC18LUJUA/DvJ70Y7RveasIBraqsyO/g=="], + "caniuse-lite": ["caniuse-lite@1.0.30001753", "", {}, "sha512-Bj5H35MD/ebaOV4iDLqPEtiliTN29qkGtEHCwawWn4cYm+bPJM2NsaP30vtZcnERClMzp52J4+aw2UNbK4o+zw=="], "ccount": ["ccount@2.0.1", "", {}, "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg=="], @@ -1910,7 +1921,7 @@ "ee-first": ["ee-first@1.1.1", "", {}, "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="], - "electron-to-chromium": ["electron-to-chromium@1.5.244", "", {}, "sha512-OszpBN7xZX4vWMPJwB9illkN/znA8M36GQqQxi6MNy9axWxhOfJyZZJtSLQCpEFLHP2xK33BiWx9aIuIEXVCcw=="], + "electron-to-chromium": ["electron-to-chromium@1.5.245", "", {}, "sha512-rdmGfW47ZhL/oWEJAY4qxRtdly2B98ooTJ0pdEI4jhVLZ6tNf8fPtov2wS1IRKwFJT92le3x4Knxiwzl7cPPpQ=="], "emoji-regex": ["emoji-regex@10.6.0", "", {}, "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A=="], @@ -1952,7 +1963,7 @@ "esast-util-from-js": ["esast-util-from-js@2.0.1", "", { "dependencies": { "@types/estree-jsx": "^1.0.0", "acorn": "^8.0.0", "esast-util-from-estree": "^2.0.0", "vfile-message": "^4.0.0" } }, "sha512-8Ja+rNJ0Lt56Pcf3TAmpBZjmx8ZcK5Ts4cAzIOjsjevg9oSXJnl6SUQ2EevU8tv3h6ZLWmoKL5H4fgWvdvfETw=="], - "esbuild": ["esbuild@0.25.11", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.11", "@esbuild/android-arm": "0.25.11", "@esbuild/android-arm64": "0.25.11", "@esbuild/android-x64": "0.25.11", "@esbuild/darwin-arm64": "0.25.11", "@esbuild/darwin-x64": "0.25.11", "@esbuild/freebsd-arm64": "0.25.11", "@esbuild/freebsd-x64": "0.25.11", "@esbuild/linux-arm": "0.25.11", "@esbuild/linux-arm64": "0.25.11", "@esbuild/linux-ia32": "0.25.11", "@esbuild/linux-loong64": "0.25.11", "@esbuild/linux-mips64el": "0.25.11", "@esbuild/linux-ppc64": "0.25.11", "@esbuild/linux-riscv64": "0.25.11", "@esbuild/linux-s390x": "0.25.11", "@esbuild/linux-x64": "0.25.11", "@esbuild/netbsd-arm64": "0.25.11", "@esbuild/netbsd-x64": "0.25.11", "@esbuild/openbsd-arm64": "0.25.11", "@esbuild/openbsd-x64": "0.25.11", "@esbuild/openharmony-arm64": "0.25.11", "@esbuild/sunos-x64": "0.25.11", "@esbuild/win32-arm64": "0.25.11", "@esbuild/win32-ia32": "0.25.11", "@esbuild/win32-x64": "0.25.11" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-KohQwyzrKTQmhXDW1PjCv3Tyspn9n5GcY2RTDqeORIdIJY8yKIF7sTSopFmn/wpMPW4rdPXI0UE5LJLuq3bx0Q=="], + "esbuild": ["esbuild@0.25.12", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.12", "@esbuild/android-arm": "0.25.12", "@esbuild/android-arm64": "0.25.12", "@esbuild/android-x64": "0.25.12", "@esbuild/darwin-arm64": "0.25.12", "@esbuild/darwin-x64": "0.25.12", "@esbuild/freebsd-arm64": "0.25.12", "@esbuild/freebsd-x64": "0.25.12", "@esbuild/linux-arm": "0.25.12", "@esbuild/linux-arm64": "0.25.12", "@esbuild/linux-ia32": "0.25.12", "@esbuild/linux-loong64": "0.25.12", "@esbuild/linux-mips64el": "0.25.12", "@esbuild/linux-ppc64": "0.25.12", "@esbuild/linux-riscv64": "0.25.12", "@esbuild/linux-s390x": "0.25.12", "@esbuild/linux-x64": "0.25.12", "@esbuild/netbsd-arm64": "0.25.12", "@esbuild/netbsd-x64": "0.25.12", "@esbuild/openbsd-arm64": "0.25.12", "@esbuild/openbsd-x64": "0.25.12", "@esbuild/openharmony-arm64": "0.25.12", "@esbuild/sunos-x64": "0.25.12", "@esbuild/win32-arm64": "0.25.12", "@esbuild/win32-ia32": "0.25.12", "@esbuild/win32-x64": "0.25.12" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg=="], "esbuild-plugin-copy": ["esbuild-plugin-copy@2.1.1", "", { "dependencies": { "chalk": "^4.1.2", "chokidar": "^3.5.3", "fs-extra": "^10.0.1", "globby": "^11.0.3" }, "peerDependencies": { "esbuild": ">= 0.14.0" } }, "sha512-Bk66jpevTcV8KMFzZI1P7MZKZ+uDcrZm2G2egZ2jNIvVnivDpodZI+/KnpL3Jnap0PBdIHU7HwFGB8r+vV5CVw=="], @@ -2656,7 +2667,7 @@ "mimic-response": ["mimic-response@3.1.0", "", {}, "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ=="], - "miniflare": ["miniflare@4.20251011.1", "", { "dependencies": { "@cspotcode/source-map-support": "0.8.1", "acorn": "8.14.0", "acorn-walk": "8.3.2", "exit-hook": "2.2.1", "glob-to-regexp": "0.4.1", "sharp": "^0.33.5", "stoppable": "1.1.0", "undici": "7.14.0", "workerd": "1.20251011.0", "ws": "8.18.0", "youch": "4.1.0-beta.10", "zod": "3.22.3" }, "bin": { "miniflare": "bootstrap.js" } }, "sha512-Qbw1Z8HTYM1adWl6FAtzhrj34/6dPRDPwdYOx21dkae8a/EaxbMzRIPbb4HKVGMVvtqbK1FaRCgDLVLolNzGHg=="], + "miniflare": ["miniflare@4.20251011.2", "", { "dependencies": { "@cspotcode/source-map-support": "0.8.1", "acorn": "8.14.0", "acorn-walk": "8.3.2", "exit-hook": "2.2.1", "glob-to-regexp": "0.4.1", "sharp": "^0.33.5", "stoppable": "1.1.0", "undici": "7.14.0", "workerd": "1.20251011.0", "ws": "8.18.0", "youch": "4.1.0-beta.10", "zod": "3.22.3" }, "bin": { "miniflare": "bootstrap.js" } }, "sha512-5oAaz6lqZus4QFwzEJiNtgpjZR2TBVwBeIhOW33V4gu+l23EukpKja831tFIX2o6sOD/hqZmKZHplOrWl3YGtQ=="], "minimatch": ["minimatch@10.0.3", "", { "dependencies": { "@isaacs/brace-expansion": "^5.0.0" } }, "sha512-IPZ167aShDZZUMdRk66cyQAW3qr0WzbHkPdMYa8bzZhlHhO3jALbKdxcaak7W9FfT2rZNpQuUu4Od7ILEpXSaw=="], @@ -2740,11 +2751,11 @@ "object.assign": ["object.assign@4.1.7", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", "define-properties": "^1.2.1", "es-object-atoms": "^1.0.0", "has-symbols": "^1.1.0", "object-keys": "^1.1.1" } }, "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw=="], - "ofetch": ["ofetch@1.5.0", "", { "dependencies": { "destr": "^2.0.5", "node-fetch-native": "^1.6.7", "ufo": "^1.6.1" } }, "sha512-A7llJ7eZyziA5xq9//3ZurA8OhFqtS99K5/V1sLBJ5j137CM/OAjlbA/TEJXBuOWwOfLqih+oH5U3ran4za1FQ=="], + "ofetch": ["ofetch@1.5.1", "", { "dependencies": { "destr": "^2.0.5", "node-fetch-native": "^1.6.7", "ufo": "^1.6.1" } }, "sha512-2W4oUZlVaqAPAil6FUg/difl6YhqhUR7x2eZY4bQCko22UXg3hptq9KLQdqFClV+Wu85UX7hNtdGTngi/1BxcA=="], "ohash": ["ohash@2.0.11", "", {}, "sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ=="], - "oidc-token-hash": ["oidc-token-hash@5.1.1", "", {}, "sha512-D7EmwxJV6DsEB6vOFLrBM2OzsVgQzgPWyHlV2OOAVj772n+WTXpudC9e9u5BVKQnYwaD30Ivhi9b+4UeBcGu9g=="], + "oidc-token-hash": ["oidc-token-hash@5.2.0", "", {}, "sha512-6gj2m8cJZ+iSW8bm0FXdGF0YhIQbKrfP4yWTNzxc31U6MOjfEmB1rHvlYvxI1B7t7BCi1F2vYTT6YhtQRG4hxw=="], "omggif": ["omggif@1.0.10", "", {}, "sha512-LMJTtvgc/nugXj0Vcrrs68Mn2D1r0zf630VNtqtpI1FEO7e+O9FP4gqs9AcnBaSEeoHIPm28u6qgPR0oyEpGSw=="], @@ -3234,7 +3245,7 @@ "strtok3": ["strtok3@6.3.0", "", { "dependencies": { "@tokenizer/token": "^0.3.0", "peek-readable": "^4.1.0" } }, "sha512-fZtbhtvI9I48xDSywd/somNqgUHl2L2cstmXCCif0itOf96jeW18MBSyrLuNicYQVkvpOxkZtkzujiTJ9LW5Jw=="], - "style-to-js": ["style-to-js@1.1.18", "", { "dependencies": { "style-to-object": "1.0.11" } }, "sha512-JFPn62D4kJaPTnhFUI244MThx+FEGbi+9dw1b9yBBQ+1CZpV7QAT8kUtJ7b7EUNdHajjF/0x8fT+16oLJoojLg=="], + "style-to-js": ["style-to-js@1.1.19", "", { "dependencies": { "style-to-object": "1.0.12" } }, "sha512-Ev+SgeqiNGT1ufsXyVC5RrJRXdrkRJ1Gol9Qw7Pb72YCKJXrBvP0ckZhBeVSrw2m06DJpei2528uIpjMb4TsoQ=="], "style-to-object": ["style-to-object@1.0.12", "", { "dependencies": { "inline-style-parser": "0.2.6" } }, "sha512-ddJqYnoT4t97QvN2C95bCgt+m7AAgXjVnkk/jxAfmp7EAB8nnqqZYEbMd3em7/vEomDb2LAQKAy1RFfv41mdNw=="], @@ -3262,7 +3273,7 @@ "terracotta": ["terracotta@1.0.6", "", { "dependencies": { "solid-use": "^0.9.0" }, "peerDependencies": { "solid-js": "^1.8" } }, "sha512-yVrmT/Lg6a3tEbeYEJH8ksb1PYkR5FA9k5gr1TchaSNIiA2ZWs5a+koEbePXwlBP0poaV7xViZ/v50bQFcMgqw=="], - "terser": ["terser@5.44.0", "", { "dependencies": { "@jridgewell/source-map": "^0.3.3", "acorn": "^8.15.0", "commander": "^2.20.0", "source-map-support": "~0.5.20" }, "bin": { "terser": "bin/terser" } }, "sha512-nIVck8DK+GM/0Frwd+nIhZ84pR/BX7rmXMfYwyg+Sri5oGVE99/E3KvXqpC2xHFxyqXyGHTKBSioxxplrO4I4w=="], + "terser": ["terser@5.44.1", "", { "dependencies": { "@jridgewell/source-map": "^0.3.3", "acorn": "^8.15.0", "commander": "^2.20.0", "source-map-support": "~0.5.20" }, "bin": { "terser": "bin/terser" } }, "sha512-t/R3R/n0MSwnnazuPpPNVO60LX0SKL45pyl9YlvxIdkH0Of7D5qM2EVe+yASRIlY5pZ73nclYJfNANGWPwFDZw=="], "text-decoder": ["text-decoder@1.2.3", "", { "dependencies": { "b4a": "^1.6.4" } }, "sha512-3/o9z3X0X0fTupwsYvR03pJ/DjWuqqrfwBgTQzdWDiQSm9KitAyz/9WqsT2JQW7KV2m+bC2ol/zqpW37NHxLaA=="], @@ -3296,8 +3307,6 @@ "tr46": ["tr46@0.0.3", "", {}, "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="], - "tree-sitter": ["tree-sitter@0.25.0", "", { "dependencies": { "node-addon-api": "^8.3.0", "node-gyp-build": "^4.8.4" } }, "sha512-PGZZzFW63eElZJDe/b/R/LbsjDDYJa5UEjLZJB59RQsMX+fo0j54fqBPn1MGKav/QNa0JR0zBiVaikYDWCj5KQ=="], - "tree-sitter-bash": ["tree-sitter-bash@0.25.0", "", { "dependencies": { "node-addon-api": "^8.2.1", "node-gyp-build": "^4.8.2" }, "peerDependencies": { "tree-sitter": "^0.25.0" }, "optionalPeers": ["tree-sitter"] }, "sha512-gZtlj9+qFS81qKxpLfD6H0UssQ3QBc/F0nKkPsiFDyfQF2YBqYvglFJUzchrPpVhZe9kLZTrJ9n2J6lmka69Vg=="], "trim-lines": ["trim-lines@3.0.1", "", {}, "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg=="], @@ -3412,7 +3421,7 @@ "unplugin-utils": ["unplugin-utils@0.3.1", "", { "dependencies": { "pathe": "^2.0.3", "picomatch": "^4.0.3" } }, "sha512-5lWVjgi6vuHhJ526bI4nlCOmkCIF3nnfXkCMDeMJrtdvxTs6ZFCM8oNufGTsDbKv/tJ/xj8RpvXjRuPBZJuJog=="], - "unstorage": ["unstorage@1.17.1", "", { "dependencies": { "anymatch": "^3.1.3", "chokidar": "^4.0.3", "destr": "^2.0.5", "h3": "^1.15.4", "lru-cache": "^10.4.3", "node-fetch-native": "^1.6.7", "ofetch": "^1.4.1", "ufo": "^1.6.1" }, "peerDependencies": { "@azure/app-configuration": "^1.8.0", "@azure/cosmos": "^4.2.0", "@azure/data-tables": "^13.3.0", "@azure/identity": "^4.6.0", "@azure/keyvault-secrets": "^4.9.0", "@azure/storage-blob": "^12.26.0", "@capacitor/preferences": "^6.0.3 || ^7.0.0", "@deno/kv": ">=0.9.0", "@netlify/blobs": "^6.5.0 || ^7.0.0 || ^8.1.0 || ^9.0.0 || ^10.0.0", "@planetscale/database": "^1.19.0", "@upstash/redis": "^1.34.3", "@vercel/blob": ">=0.27.1", "@vercel/functions": "^2.2.12 || ^3.0.0", "@vercel/kv": "^1.0.1", "aws4fetch": "^1.0.20", "db0": ">=0.2.1", "idb-keyval": "^6.2.1", "ioredis": "^5.4.2", "uploadthing": "^7.4.4" }, "optionalPeers": ["@azure/app-configuration", "@azure/cosmos", "@azure/data-tables", "@azure/identity", "@azure/keyvault-secrets", "@azure/storage-blob", "@capacitor/preferences", "@deno/kv", "@netlify/blobs", "@planetscale/database", "@upstash/redis", "@vercel/blob", "@vercel/functions", "@vercel/kv", "aws4fetch", "db0", "idb-keyval", "ioredis", "uploadthing"] }, "sha512-KKGwRTT0iVBCErKemkJCLs7JdxNVfqTPc/85ae1XES0+bsHbc/sFBfVi5kJp156cc51BHinIH2l3k0EZ24vOBQ=="], + "unstorage": ["unstorage@1.17.2", "", { "dependencies": { "anymatch": "^3.1.3", "chokidar": "^4.0.3", "destr": "^2.0.5", "h3": "^1.15.4", "lru-cache": "^10.4.3", "node-fetch-native": "^1.6.7", "ofetch": "^1.5.0", "ufo": "^1.6.1" }, "peerDependencies": { "@azure/app-configuration": "^1.8.0", "@azure/cosmos": "^4.2.0", "@azure/data-tables": "^13.3.0", "@azure/identity": "^4.6.0", "@azure/keyvault-secrets": "^4.9.0", "@azure/storage-blob": "^12.26.0", "@capacitor/preferences": "^6.0.3 || ^7.0.0", "@deno/kv": ">=0.9.0", "@netlify/blobs": "^6.5.0 || ^7.0.0 || ^8.1.0 || ^9.0.0 || ^10.0.0", "@planetscale/database": "^1.19.0", "@upstash/redis": "^1.34.3", "@vercel/blob": ">=0.27.1", "@vercel/functions": "^2.2.12 || ^3.0.0", "@vercel/kv": "^1.0.1", "aws4fetch": "^1.0.20", "db0": ">=0.2.1", "idb-keyval": "^6.2.1", "ioredis": "^5.4.2", "uploadthing": "^7.4.4" }, "optionalPeers": ["@azure/app-configuration", "@azure/cosmos", "@azure/data-tables", "@azure/identity", "@azure/keyvault-secrets", "@azure/storage-blob", "@capacitor/preferences", "@deno/kv", "@netlify/blobs", "@planetscale/database", "@upstash/redis", "@vercel/blob", "@vercel/functions", "@vercel/kv", "aws4fetch", "db0", "idb-keyval", "ioredis", "uploadthing"] }, "sha512-cKEsD6iBWJgOMJ6vW1ID/SYuqNf8oN4yqRk8OYqaVQ3nnkJXOT1PSpaMh2QfzLs78UN5kSNRD2c/mgjT8tX7+w=="], "untun": ["untun@0.1.3", "", { "dependencies": { "citty": "^0.1.5", "consola": "^3.2.3", "pathe": "^1.1.1" }, "bin": { "untun": "bin/untun.mjs" } }, "sha512-4luGP9LMYszMRZwsvyUd9MrxgEGZdZuZgpVQHEEX0lCYFESasVRvZd0EYpCkOIbJKHMuv0LskpXc/8Un+MJzEQ=="], @@ -3498,7 +3507,7 @@ "workerd": ["workerd@1.20251011.0", "", { "optionalDependencies": { "@cloudflare/workerd-darwin-64": "1.20251011.0", "@cloudflare/workerd-darwin-arm64": "1.20251011.0", "@cloudflare/workerd-linux-64": "1.20251011.0", "@cloudflare/workerd-linux-arm64": "1.20251011.0", "@cloudflare/workerd-windows-64": "1.20251011.0" }, "bin": { "workerd": "bin/workerd" } }, "sha512-Dq35TLPEJAw7BuYQMkN3p9rge34zWMU2Gnd4DSJFeVqld4+DAO2aPG7+We2dNIAyM97S8Y9BmHulbQ00E0HC7Q=="], - "wrangler": ["wrangler@4.45.3", "", { "dependencies": { "@cloudflare/kv-asset-handler": "0.4.0", "@cloudflare/unenv-preset": "2.7.8", "blake3-wasm": "2.1.5", "esbuild": "0.25.4", "miniflare": "4.20251011.1", "path-to-regexp": "6.3.0", "unenv": "2.0.0-rc.21", "workerd": "1.20251011.0" }, "optionalDependencies": { "fsevents": "~2.3.2" }, "peerDependencies": { "@cloudflare/workers-types": "^4.20251011.0" }, "optionalPeers": ["@cloudflare/workers-types"], "bin": { "wrangler": "bin/wrangler.js", "wrangler2": "bin/wrangler.js" } }, "sha512-0ddEA9t4HeBgSVTVTcqtBHl7Z5CorWZ8tGgTQCP5XuL+9E1TJRwS6t/zzG51Ruwjb17SZYCaLchoM8V629S8cw=="], + "wrangler": ["wrangler@4.45.4", "", { "dependencies": { "@cloudflare/kv-asset-handler": "0.4.0", "@cloudflare/unenv-preset": "2.7.9", "blake3-wasm": "2.1.5", "esbuild": "0.25.4", "miniflare": "4.20251011.2", "path-to-regexp": "6.3.0", "unenv": "2.0.0-rc.24", "workerd": "1.20251011.0" }, "optionalDependencies": { "fsevents": "~2.3.2" }, "peerDependencies": { "@cloudflare/workers-types": "^4.20251011.0" }, "optionalPeers": ["@cloudflare/workers-types"], "bin": { "wrangler": "bin/wrangler.js", "wrangler2": "bin/wrangler.js" } }, "sha512-niXT7B463wQi7WXIHjYK8txgWhuKQLrGmhjoR58SnPhlkq4wGjd3rFrkVyRc/O58clGTfs672BSGOph4XMoQKw=="], "wrap-ansi": ["wrap-ansi@9.0.2", "", { "dependencies": { "ansi-styles": "^6.2.1", "string-width": "^7.0.0", "strip-ansi": "^7.1.0" } }, "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww=="], @@ -3536,7 +3545,7 @@ "yoga-layout": ["yoga-layout@3.2.1", "", {}, "sha512-0LPOt3AxKqMdFBZA3HBAt/t/8vIKq7VaQYbuA8WxCgung+p9TVyKRYdpvCb80HcdTN2NkbIKbhNwKUfm3tQywQ=="], - "youch": ["youch@4.1.0-beta.11", "", { "dependencies": { "@poppinss/colors": "^4.1.5", "@poppinss/dumper": "^0.6.4", "@speed-highlight/core": "^1.2.7", "cookie": "^1.0.2", "youch-core": "^0.3.3" } }, "sha512-sQi6PERyO/mT8w564ojOVeAlYTtVQmC2GaktQAf+IdI75/GKIggosBuvyVXvEV+FATAT6RbLdIjFoiIId4ozoQ=="], + "youch": ["youch@4.1.0-beta.12", "", { "dependencies": { "@poppinss/colors": "^4.1.5", "@poppinss/dumper": "^0.6.5", "@speed-highlight/core": "^1.2.9", "cookie-es": "^2.0.0", "youch-core": "^0.3.3" } }, "sha512-X+AQ2EdigcZb2h1XQmBMm19TrrfKXxEXWpnf8ThbARwiiSf/pA7MvRTCj5VHCI9z3vjJBsDeqWWyvaI9Bfp9Pg=="], "youch-core": ["youch-core@0.3.3", "", { "dependencies": { "@poppinss/exception": "^1.2.2", "error-stack-parser-es": "^1.0.5" } }, "sha512-ho7XuGjLaJ2hWHoK8yFnsUGy2Y5uDpqSTq1FkHLK4/oqKtyUU1AFbOOxY4IpC9f0fTLjwYbslUz0Po5BpD1wrA=="], @@ -3580,6 +3589,8 @@ "@astrojs/markdown-remark/@astrojs/internal-helpers": ["@astrojs/internal-helpers@0.6.1", "", {}, "sha512-l5Pqf6uZu31aG+3Lv8nl/3s4DbUzdlxTWDof4pEpto6GUJNhhCbelVi9dEyurOVyqaelwmS9oSyOWOENSfgo9A=="], + "@astrojs/markdown-remark/shiki": ["shiki@3.14.0", "", { "dependencies": { "@shikijs/core": "3.14.0", "@shikijs/engine-javascript": "3.14.0", "@shikijs/engine-oniguruma": "3.14.0", "@shikijs/langs": "3.14.0", "@shikijs/themes": "3.14.0", "@shikijs/types": "3.14.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-J0yvpLI7LSig3Z3acIuDLouV5UCKQqu8qOArwMx+/yPVC3WRMgrP67beaG8F+j4xfEWE0eVC4GeBCIXeOPra1g=="], + "@astrojs/mdx/@astrojs/markdown-remark": ["@astrojs/markdown-remark@6.3.8", "", { "dependencies": { "@astrojs/internal-helpers": "0.7.4", "@astrojs/prism": "3.3.0", "github-slugger": "^2.0.0", "hast-util-from-html": "^2.0.3", "hast-util-to-text": "^4.0.2", "import-meta-resolve": "^4.2.0", "js-yaml": "^4.1.0", "mdast-util-definitions": "^6.0.0", "rehype-raw": "^7.0.0", "rehype-stringify": "^10.0.1", "remark-gfm": "^4.0.1", "remark-parse": "^11.0.0", "remark-rehype": "^11.1.2", "remark-smartypants": "^3.0.2", "shiki": "^3.13.0", "smol-toml": "^1.4.2", "unified": "^11.0.5", "unist-util-remove-position": "^5.0.0", "unist-util-visit": "^5.0.0", "unist-util-visit-parents": "^6.0.1", "vfile": "^6.0.3" } }, "sha512-uFNyFWadnULWK2cOw4n0hLKeu+xaVWeuECdP10cQ3K2fkybtTlhb7J7TcScdjmS8Yps7oje9S/ehYMfZrhrgCg=="], "@astrojs/sitemap/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], @@ -3600,13 +3611,13 @@ "@cloudflare/kv-asset-handler/mime": ["mime@3.0.0", "", { "bin": { "mime": "cli.js" } }, "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A=="], - "@cloudflare/unenv-preset/unenv": ["unenv@2.0.0-rc.21", "", { "dependencies": { "defu": "^6.1.4", "exsolve": "^1.0.7", "ohash": "^2.0.11", "pathe": "^2.0.3", "ufo": "^1.6.1" } }, "sha512-Wj7/AMtE9MRnAXa6Su3Lk0LNCfqDYgfwVjwRFVum9U7wsto1imuHqk4kTm7Jni+5A0Hn7dttL6O/zjvUvoo+8A=="], + "@cloudflare/unenv-preset/unenv": ["unenv@2.0.0-rc.24", "", { "dependencies": { "pathe": "^2.0.3" } }, "sha512-i7qRCmY42zmCwnYlh9H2SvLEypEFGye5iRmEMKjcGi7zk9UquigRjFtTLz0TYqr0ZGLZhaMHl/foy1bZR+Cwlw=="], "@cspotcode/source-map-support/@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.9", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.0.3", "@jridgewell/sourcemap-codec": "^1.4.10" } }, "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ=="], "@esbuild-kit/core-utils/esbuild": ["esbuild@0.18.20", "", { "optionalDependencies": { "@esbuild/android-arm": "0.18.20", "@esbuild/android-arm64": "0.18.20", "@esbuild/android-x64": "0.18.20", "@esbuild/darwin-arm64": "0.18.20", "@esbuild/darwin-x64": "0.18.20", "@esbuild/freebsd-arm64": "0.18.20", "@esbuild/freebsd-x64": "0.18.20", "@esbuild/linux-arm": "0.18.20", "@esbuild/linux-arm64": "0.18.20", "@esbuild/linux-ia32": "0.18.20", "@esbuild/linux-loong64": "0.18.20", "@esbuild/linux-mips64el": "0.18.20", "@esbuild/linux-ppc64": "0.18.20", "@esbuild/linux-riscv64": "0.18.20", "@esbuild/linux-s390x": "0.18.20", "@esbuild/linux-x64": "0.18.20", "@esbuild/netbsd-x64": "0.18.20", "@esbuild/openbsd-x64": "0.18.20", "@esbuild/sunos-x64": "0.18.20", "@esbuild/win32-arm64": "0.18.20", "@esbuild/win32-ia32": "0.18.20", "@esbuild/win32-x64": "0.18.20" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA=="], - "@expressive-code/plugin-shiki/shiki": ["shiki@3.13.0", "", { "dependencies": { "@shikijs/core": "3.13.0", "@shikijs/engine-javascript": "3.13.0", "@shikijs/engine-oniguruma": "3.13.0", "@shikijs/langs": "3.13.0", "@shikijs/themes": "3.13.0", "@shikijs/types": "3.13.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-aZW4l8Og16CokuCLf8CF8kq+KK2yOygapU5m3+hoGw0Mdosc6fPitjM+ujYarppj5ZIKGyPDPP1vqmQhr+5/0g=="], + "@expressive-code/plugin-shiki/shiki": ["shiki@3.14.0", "", { "dependencies": { "@shikijs/core": "3.14.0", "@shikijs/engine-javascript": "3.14.0", "@shikijs/engine-oniguruma": "3.14.0", "@shikijs/langs": "3.14.0", "@shikijs/themes": "3.14.0", "@shikijs/types": "3.14.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-J0yvpLI7LSig3Z3acIuDLouV5UCKQqu8qOArwMx+/yPVC3WRMgrP67beaG8F+j4xfEWE0eVC4GeBCIXeOPra1g=="], "@hono/zod-validator/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], @@ -3748,9 +3759,9 @@ "@tailwindcss/node/jiti": ["jiti@2.6.1", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ=="], - "@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.6.0", "", { "dependencies": { "@emnapi/wasi-threads": "1.1.0", "tslib": "^2.4.0" }, "bundled": true }, "sha512-zq/ay+9fNIJJtJiZxdTnXS20PllcYMX3OE23ESc4HK/bdYu3cOWYVhsOhVnXALfU/uqJIxn5NBPd9z4v+SfoSg=="], + "@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.7.0", "", { "dependencies": { "@emnapi/wasi-threads": "1.1.0", "tslib": "^2.4.0" }, "bundled": true }, "sha512-pJdKGq/1iquWYtv1RRSljZklxHCOCAJFJrImO5ZLKPJVJlVUcs8yFwNQlqS0Lo8xT1VAXXTCZocF9n26FWEKsw=="], - "@tailwindcss/oxide-wasm32-wasi/@emnapi/runtime": ["@emnapi/runtime@1.6.0", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-obtUmAHTMjll499P+D9A3axeJFlhdjOWdKUNs/U6QIGT7V5RjcUW1xToAzjvmgTSQhDbYn/NwfTRoJcQ2rNBxA=="], + "@tailwindcss/oxide-wasm32-wasi/@emnapi/runtime": ["@emnapi/runtime@1.7.0", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-oAYoQnCYaQZKVS53Fq23ceWMRxq5EhQsE0x0RdQ55jT7wagMu5k+fS39v1fiSLrtrLQlXwVINenqhLMtTrV/1Q=="], "@tailwindcss/oxide-wasm32-wasi/@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.1.0", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ=="], @@ -3766,6 +3777,8 @@ "@tanstack/server-functions-plugin/@babel/code-frame": ["@babel/code-frame@7.26.2", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.25.9", "js-tokens": "^4.0.0", "picocolors": "^1.0.0" } }, "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ=="], + "@types/serve-static/@types/send": ["@types/send@0.17.6", "", { "dependencies": { "@types/mime": "^1", "@types/node": "*" } }, "sha512-Uqt8rPBE8SY0RK8JB1EzVOIZ32uqy8HwdxCnoCOsYrvnswqmFZ/k+9Ikidlk/ImhsdvBsloHbAlewb2IEBV/Og=="], + "@vercel/nft/estree-walker": ["estree-walker@2.0.2", "", {}, "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="], "@vercel/nft/glob": ["glob@10.4.5", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg=="], @@ -3792,10 +3805,10 @@ "astro/diff": ["diff@5.2.0", "", {}, "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A=="], - "astro/semver": ["semver@7.7.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="], - "astro/sharp": ["sharp@0.33.5", "", { "dependencies": { "color": "^4.2.3", "detect-libc": "^2.0.3", "semver": "^7.6.3" }, "optionalDependencies": { "@img/sharp-darwin-arm64": "0.33.5", "@img/sharp-darwin-x64": "0.33.5", "@img/sharp-libvips-darwin-arm64": "1.0.4", "@img/sharp-libvips-darwin-x64": "1.0.4", "@img/sharp-libvips-linux-arm": "1.0.5", "@img/sharp-libvips-linux-arm64": "1.0.4", "@img/sharp-libvips-linux-s390x": "1.0.4", "@img/sharp-libvips-linux-x64": "1.0.4", "@img/sharp-libvips-linuxmusl-arm64": "1.0.4", "@img/sharp-libvips-linuxmusl-x64": "1.0.4", "@img/sharp-linux-arm": "0.33.5", "@img/sharp-linux-arm64": "0.33.5", "@img/sharp-linux-s390x": "0.33.5", "@img/sharp-linux-x64": "0.33.5", "@img/sharp-linuxmusl-arm64": "0.33.5", "@img/sharp-linuxmusl-x64": "0.33.5", "@img/sharp-wasm32": "0.33.5", "@img/sharp-win32-ia32": "0.33.5", "@img/sharp-win32-x64": "0.33.5" } }, "sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw=="], + "astro/shiki": ["shiki@3.14.0", "", { "dependencies": { "@shikijs/core": "3.14.0", "@shikijs/engine-javascript": "3.14.0", "@shikijs/engine-oniguruma": "3.14.0", "@shikijs/langs": "3.14.0", "@shikijs/themes": "3.14.0", "@shikijs/types": "3.14.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-J0yvpLI7LSig3Z3acIuDLouV5UCKQqu8qOArwMx+/yPVC3WRMgrP67beaG8F+j4xfEWE0eVC4GeBCIXeOPra1g=="], + "astro/vite": ["vite@6.4.1", "", { "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.4.4", "picomatch": "^4.0.2", "postcss": "^8.5.3", "rollup": "^4.34.9", "tinyglobby": "^0.2.13" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", "jiti": ">=1.21.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g=="], "astro/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], @@ -3840,7 +3853,7 @@ "dir-glob/path-type": ["path-type@4.0.0", "", {}, "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw=="], - "dot-prop/type-fest": ["type-fest@5.1.0", "", { "dependencies": { "tagged-tag": "^1.0.0" } }, "sha512-wQ531tuWvB6oK+pchHIu5lHe5f5wpSCqB8Kf4dWQRbOYc9HTge7JL0G4Qd44bh6QuJCccIzL3bugb8GI0MwHrg=="], + "dot-prop/type-fest": ["type-fest@5.2.0", "", { "dependencies": { "tagged-tag": "^1.0.0" } }, "sha512-xxCJm+Bckc6kQBknN7i9fnP/xobQRsRQxR01CztFkp/h++yfVxUUcmMgfR2HttJx/dpWjS9ubVuyspJv24Q9DA=="], "drizzle-kit/esbuild": ["esbuild@0.19.12", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.19.12", "@esbuild/android-arm": "0.19.12", "@esbuild/android-arm64": "0.19.12", "@esbuild/android-x64": "0.19.12", "@esbuild/darwin-arm64": "0.19.12", "@esbuild/darwin-x64": "0.19.12", "@esbuild/freebsd-arm64": "0.19.12", "@esbuild/freebsd-x64": "0.19.12", "@esbuild/linux-arm": "0.19.12", "@esbuild/linux-arm64": "0.19.12", "@esbuild/linux-ia32": "0.19.12", "@esbuild/linux-loong64": "0.19.12", "@esbuild/linux-mips64el": "0.19.12", "@esbuild/linux-ppc64": "0.19.12", "@esbuild/linux-riscv64": "0.19.12", "@esbuild/linux-s390x": "0.19.12", "@esbuild/linux-x64": "0.19.12", "@esbuild/netbsd-x64": "0.19.12", "@esbuild/openbsd-x64": "0.19.12", "@esbuild/sunos-x64": "0.19.12", "@esbuild/win32-arm64": "0.19.12", "@esbuild/win32-ia32": "0.19.12", "@esbuild/win32-x64": "0.19.12" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg=="], @@ -3876,8 +3889,6 @@ "gaxios/uuid": ["uuid@9.0.1", "", { "bin": { "uuid": "dist/bin/uuid" } }, "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA=="], - "gel/semver": ["semver@7.7.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="], - "giget/pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="], "giget/tar": ["tar@6.2.1", "", { "dependencies": { "chownr": "^2.0.0", "fs-minipass": "^2.0.0", "minipass": "^5.0.0", "minizlib": "^2.1.1", "mkdirp": "^1.0.3", "yallist": "^4.0.0" } }, "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A=="], @@ -4020,9 +4031,7 @@ "send/mime": ["mime@1.6.0", "", { "bin": { "mime": "cli.js" } }, "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg=="], - "sharp/semver": ["semver@7.7.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="], - - "sitemap/sax": ["sax@1.4.1", "", {}, "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg=="], + "sitemap/sax": ["sax@1.4.3", "", {}, "sha512-yqYn1JhPczigF94DMS+shiDMjDowYO6y9+wB/4WgO0Y19jWYk0lQ4tuG5KI7kj4FTp1wxPj5IFfcrz/s1c3jjQ=="], "source-map-support/source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="], @@ -4038,8 +4047,6 @@ "strip-literal/js-tokens": ["js-tokens@9.0.1", "", {}, "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ=="], - "style-to-js/style-to-object": ["style-to-object@1.0.11", "", { "dependencies": { "inline-style-parser": "0.2.4" } }, "sha512-5A560JmXr7wDyGLK12Nq/EYS38VkGlglVzkis1JEdbGWSnbQIEhZzTJhzURXN5/8WwwFCs/f/VVcmkTppbXLow=="], - "sucrase/commander": ["commander@4.1.1", "", {}, "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA=="], "sucrase/glob": ["glob@10.4.5", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg=="], @@ -4050,8 +4057,6 @@ "token-types/ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="], - "tree-sitter/node-addon-api": ["node-addon-api@8.5.0", "", {}, "sha512-/bRZty2mXUIFY/xU5HLvveNHlswNJej+RnxBjOMkidWfwZzgTbPG1E3K5TOxRLOR+5hX7bSofy8yf1hZevMS8A=="], - "tree-sitter-bash/node-addon-api": ["node-addon-api@8.5.0", "", {}, "sha512-/bRZty2mXUIFY/xU5HLvveNHlswNJej+RnxBjOMkidWfwZzgTbPG1E3K5TOxRLOR+5hX7bSofy8yf1hZevMS8A=="], "tw-to-css/postcss": ["postcss@8.4.31", "", { "dependencies": { "nanoid": "^3.3.6", "picocolors": "^1.0.0", "source-map-js": "^1.0.2" } }, "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ=="], @@ -4088,7 +4093,7 @@ "wrangler/esbuild": ["esbuild@0.25.4", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.4", "@esbuild/android-arm": "0.25.4", "@esbuild/android-arm64": "0.25.4", "@esbuild/android-x64": "0.25.4", "@esbuild/darwin-arm64": "0.25.4", "@esbuild/darwin-x64": "0.25.4", "@esbuild/freebsd-arm64": "0.25.4", "@esbuild/freebsd-x64": "0.25.4", "@esbuild/linux-arm": "0.25.4", "@esbuild/linux-arm64": "0.25.4", "@esbuild/linux-ia32": "0.25.4", "@esbuild/linux-loong64": "0.25.4", "@esbuild/linux-mips64el": "0.25.4", "@esbuild/linux-ppc64": "0.25.4", "@esbuild/linux-riscv64": "0.25.4", "@esbuild/linux-s390x": "0.25.4", "@esbuild/linux-x64": "0.25.4", "@esbuild/netbsd-arm64": "0.25.4", "@esbuild/netbsd-x64": "0.25.4", "@esbuild/openbsd-arm64": "0.25.4", "@esbuild/openbsd-x64": "0.25.4", "@esbuild/sunos-x64": "0.25.4", "@esbuild/win32-arm64": "0.25.4", "@esbuild/win32-ia32": "0.25.4", "@esbuild/win32-x64": "0.25.4" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-8pgjLUcUjcgDg+2Q4NYXnPbo/vncAY4UmyaCm0jZevERqCHZIaWwdJHkf8XQtu4AxSKCdvrUbT0XUr1IdZzI8Q=="], - "wrangler/unenv": ["unenv@2.0.0-rc.21", "", { "dependencies": { "defu": "^6.1.4", "exsolve": "^1.0.7", "ohash": "^2.0.11", "pathe": "^2.0.3", "ufo": "^1.6.1" } }, "sha512-Wj7/AMtE9MRnAXa6Su3Lk0LNCfqDYgfwVjwRFVum9U7wsto1imuHqk4kTm7Jni+5A0Hn7dttL6O/zjvUvoo+8A=="], + "wrangler/unenv": ["unenv@2.0.0-rc.24", "", { "dependencies": { "pathe": "^2.0.3" } }, "sha512-i7qRCmY42zmCwnYlh9H2SvLEypEFGye5iRmEMKjcGi7zk9UquigRjFtTLz0TYqr0ZGLZhaMHl/foy1bZR+Cwlw=="], "wrap-ansi/ansi-styles": ["ansi-styles@6.2.3", "", {}, "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg=="], @@ -4124,11 +4129,23 @@ "@actions/github/@octokit/request-error/@octokit/types": ["@octokit/types@13.10.0", "", { "dependencies": { "@octokit/openapi-types": "^24.2.0" } }, "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA=="], + "@astrojs/markdown-remark/shiki/@shikijs/core": ["@shikijs/core@3.14.0", "", { "dependencies": { "@shikijs/types": "3.14.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4", "hast-util-to-html": "^9.0.5" } }, "sha512-qRSeuP5vlYHCNUIrpEBQFO7vSkR7jn7Kv+5X3FO/zBKVDGQbcnlScD3XhkrHi/R8Ltz0kEjvFR9Szp/XMRbFMw=="], + + "@astrojs/markdown-remark/shiki/@shikijs/engine-javascript": ["@shikijs/engine-javascript@3.14.0", "", { "dependencies": { "@shikijs/types": "3.14.0", "@shikijs/vscode-textmate": "^10.0.2", "oniguruma-to-es": "^4.3.3" } }, "sha512-3v1kAXI2TsWQuwv86cREH/+FK9Pjw3dorVEykzQDhwrZj0lwsHYlfyARaKmn6vr5Gasf8aeVpb8JkzeWspxOLQ=="], + + "@astrojs/markdown-remark/shiki/@shikijs/engine-oniguruma": ["@shikijs/engine-oniguruma@3.14.0", "", { "dependencies": { "@shikijs/types": "3.14.0", "@shikijs/vscode-textmate": "^10.0.2" } }, "sha512-TNcYTYMbJyy+ZjzWtt0bG5y4YyMIWC2nyePz+CFMWqm+HnZZyy9SWMgo8Z6KBJVIZnx8XUXS8U2afO6Y0g1Oug=="], + + "@astrojs/markdown-remark/shiki/@shikijs/langs": ["@shikijs/langs@3.14.0", "", { "dependencies": { "@shikijs/types": "3.14.0" } }, "sha512-DIB2EQY7yPX1/ZH7lMcwrK5pl+ZkP/xoSpUzg9YC8R+evRCCiSQ7yyrvEyBsMnfZq4eBzLzBlugMyTAf13+pzg=="], + + "@astrojs/markdown-remark/shiki/@shikijs/themes": ["@shikijs/themes@3.14.0", "", { "dependencies": { "@shikijs/types": "3.14.0" } }, "sha512-fAo/OnfWckNmv4uBoUu6dSlkcBc+SA1xzj5oUSaz5z3KqHtEbUypg/9xxgJARtM6+7RVm0Q6Xnty41xA1ma1IA=="], + + "@astrojs/markdown-remark/shiki/@shikijs/types": ["@shikijs/types@3.14.0", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-bQGgC6vrY8U/9ObG1Z/vTro+uclbjjD/uG58RvfxKZVD5p9Yc1ka3tVyEFy7BNJLzxuWyHH5NWynP9zZZS59eQ=="], + "@astrojs/mdx/@astrojs/markdown-remark/@astrojs/internal-helpers": ["@astrojs/internal-helpers@0.7.4", "", {}, "sha512-lDA9MqE8WGi7T/t2BMi+EAXhs4Vcvr94Gqx3q15cFEz8oFZMO4/SFBqYr/UcmNlvW+35alowkVj+w9VhLvs5Cw=="], "@astrojs/mdx/@astrojs/markdown-remark/@astrojs/prism": ["@astrojs/prism@3.3.0", "", { "dependencies": { "prismjs": "^1.30.0" } }, "sha512-q8VwfU/fDZNoDOf+r7jUnMC2//H2l0TuQ6FkGJL8vD8nw/q5KiL3DS1KKBI3QhI9UQhpJ5dc7AtqfbXWuOgLCQ=="], - "@astrojs/mdx/@astrojs/markdown-remark/shiki": ["shiki@3.13.0", "", { "dependencies": { "@shikijs/core": "3.13.0", "@shikijs/engine-javascript": "3.13.0", "@shikijs/engine-oniguruma": "3.13.0", "@shikijs/langs": "3.13.0", "@shikijs/themes": "3.13.0", "@shikijs/types": "3.13.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-aZW4l8Og16CokuCLf8CF8kq+KK2yOygapU5m3+hoGw0Mdosc6fPitjM+ujYarppj5ZIKGyPDPP1vqmQhr+5/0g=="], + "@astrojs/mdx/@astrojs/markdown-remark/shiki": ["shiki@3.14.0", "", { "dependencies": { "@shikijs/core": "3.14.0", "@shikijs/engine-javascript": "3.14.0", "@shikijs/engine-oniguruma": "3.14.0", "@shikijs/langs": "3.14.0", "@shikijs/themes": "3.14.0", "@shikijs/types": "3.14.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-J0yvpLI7LSig3Z3acIuDLouV5UCKQqu8qOArwMx+/yPVC3WRMgrP67beaG8F+j4xfEWE0eVC4GeBCIXeOPra1g=="], "@aws-crypto/sha256-browser/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@2.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA=="], @@ -4182,17 +4199,17 @@ "@esbuild-kit/core-utils/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.18.20", "", { "os": "win32", "cpu": "x64" }, "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ=="], - "@expressive-code/plugin-shiki/shiki/@shikijs/core": ["@shikijs/core@3.13.0", "", { "dependencies": { "@shikijs/types": "3.13.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4", "hast-util-to-html": "^9.0.5" } }, "sha512-3P8rGsg2Eh2qIHekwuQjzWhKI4jV97PhvYjYUzGqjvJfqdQPz+nMlfWahU24GZAyW1FxFI1sYjyhfh5CoLmIUA=="], + "@expressive-code/plugin-shiki/shiki/@shikijs/core": ["@shikijs/core@3.14.0", "", { "dependencies": { "@shikijs/types": "3.14.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4", "hast-util-to-html": "^9.0.5" } }, "sha512-qRSeuP5vlYHCNUIrpEBQFO7vSkR7jn7Kv+5X3FO/zBKVDGQbcnlScD3XhkrHi/R8Ltz0kEjvFR9Szp/XMRbFMw=="], - "@expressive-code/plugin-shiki/shiki/@shikijs/engine-javascript": ["@shikijs/engine-javascript@3.13.0", "", { "dependencies": { "@shikijs/types": "3.13.0", "@shikijs/vscode-textmate": "^10.0.2", "oniguruma-to-es": "^4.3.3" } }, "sha512-Ty7xv32XCp8u0eQt8rItpMs6rU9Ki6LJ1dQOW3V/56PKDcpvfHPnYFbsx5FFUP2Yim34m/UkazidamMNVR4vKg=="], + "@expressive-code/plugin-shiki/shiki/@shikijs/engine-javascript": ["@shikijs/engine-javascript@3.14.0", "", { "dependencies": { "@shikijs/types": "3.14.0", "@shikijs/vscode-textmate": "^10.0.2", "oniguruma-to-es": "^4.3.3" } }, "sha512-3v1kAXI2TsWQuwv86cREH/+FK9Pjw3dorVEykzQDhwrZj0lwsHYlfyARaKmn6vr5Gasf8aeVpb8JkzeWspxOLQ=="], - "@expressive-code/plugin-shiki/shiki/@shikijs/engine-oniguruma": ["@shikijs/engine-oniguruma@3.13.0", "", { "dependencies": { "@shikijs/types": "3.13.0", "@shikijs/vscode-textmate": "^10.0.2" } }, "sha512-O42rBGr4UDSlhT2ZFMxqM7QzIU+IcpoTMzb3W7AlziI1ZF7R8eS2M0yt5Ry35nnnTX/LTLXFPUjRFCIW+Operg=="], + "@expressive-code/plugin-shiki/shiki/@shikijs/engine-oniguruma": ["@shikijs/engine-oniguruma@3.14.0", "", { "dependencies": { "@shikijs/types": "3.14.0", "@shikijs/vscode-textmate": "^10.0.2" } }, "sha512-TNcYTYMbJyy+ZjzWtt0bG5y4YyMIWC2nyePz+CFMWqm+HnZZyy9SWMgo8Z6KBJVIZnx8XUXS8U2afO6Y0g1Oug=="], - "@expressive-code/plugin-shiki/shiki/@shikijs/langs": ["@shikijs/langs@3.13.0", "", { "dependencies": { "@shikijs/types": "3.13.0" } }, "sha512-672c3WAETDYHwrRP0yLy3W1QYB89Hbpj+pO4KhxK6FzIrDI2FoEXNiNCut6BQmEApYLfuYfpgOZaqbY+E9b8wQ=="], + "@expressive-code/plugin-shiki/shiki/@shikijs/langs": ["@shikijs/langs@3.14.0", "", { "dependencies": { "@shikijs/types": "3.14.0" } }, "sha512-DIB2EQY7yPX1/ZH7lMcwrK5pl+ZkP/xoSpUzg9YC8R+evRCCiSQ7yyrvEyBsMnfZq4eBzLzBlugMyTAf13+pzg=="], - "@expressive-code/plugin-shiki/shiki/@shikijs/themes": ["@shikijs/themes@3.13.0", "", { "dependencies": { "@shikijs/types": "3.13.0" } }, "sha512-Vxw1Nm1/Od8jyA7QuAenaV78BG2nSr3/gCGdBkLpfLscddCkzkL36Q5b67SrLLfvAJTOUzW39x4FHVCFriPVgg=="], + "@expressive-code/plugin-shiki/shiki/@shikijs/themes": ["@shikijs/themes@3.14.0", "", { "dependencies": { "@shikijs/types": "3.14.0" } }, "sha512-fAo/OnfWckNmv4uBoUu6dSlkcBc+SA1xzj5oUSaz5z3KqHtEbUypg/9xxgJARtM6+7RVm0Q6Xnty41xA1ma1IA=="], - "@expressive-code/plugin-shiki/shiki/@shikijs/types": ["@shikijs/types@3.13.0", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-oM9P+NCFri/mmQ8LoFGVfVyemm5Hi27330zuOBp0annwJdKH1kOLndw3zCtAVDehPLg9fKqoEx3Ht/wNZxolfw=="], + "@expressive-code/plugin-shiki/shiki/@shikijs/types": ["@shikijs/types@3.14.0", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-bQGgC6vrY8U/9ObG1Z/vTro+uclbjjD/uG58RvfxKZVD5p9Yc1ka3tVyEFy7BNJLzxuWyHH5NWynP9zZZS59eQ=="], "@isaacs/cliui/string-width/emoji-regex": ["emoji-regex@9.2.2", "", {}, "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="], @@ -4370,6 +4387,20 @@ "archiver-utils/glob/path-scurry": ["path-scurry@1.11.1", "", { "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" } }, "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA=="], + "astro/sharp/semver": ["semver@7.7.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="], + + "astro/shiki/@shikijs/core": ["@shikijs/core@3.14.0", "", { "dependencies": { "@shikijs/types": "3.14.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4", "hast-util-to-html": "^9.0.5" } }, "sha512-qRSeuP5vlYHCNUIrpEBQFO7vSkR7jn7Kv+5X3FO/zBKVDGQbcnlScD3XhkrHi/R8Ltz0kEjvFR9Szp/XMRbFMw=="], + + "astro/shiki/@shikijs/engine-javascript": ["@shikijs/engine-javascript@3.14.0", "", { "dependencies": { "@shikijs/types": "3.14.0", "@shikijs/vscode-textmate": "^10.0.2", "oniguruma-to-es": "^4.3.3" } }, "sha512-3v1kAXI2TsWQuwv86cREH/+FK9Pjw3dorVEykzQDhwrZj0lwsHYlfyARaKmn6vr5Gasf8aeVpb8JkzeWspxOLQ=="], + + "astro/shiki/@shikijs/engine-oniguruma": ["@shikijs/engine-oniguruma@3.14.0", "", { "dependencies": { "@shikijs/types": "3.14.0", "@shikijs/vscode-textmate": "^10.0.2" } }, "sha512-TNcYTYMbJyy+ZjzWtt0bG5y4YyMIWC2nyePz+CFMWqm+HnZZyy9SWMgo8Z6KBJVIZnx8XUXS8U2afO6Y0g1Oug=="], + + "astro/shiki/@shikijs/langs": ["@shikijs/langs@3.14.0", "", { "dependencies": { "@shikijs/types": "3.14.0" } }, "sha512-DIB2EQY7yPX1/ZH7lMcwrK5pl+ZkP/xoSpUzg9YC8R+evRCCiSQ7yyrvEyBsMnfZq4eBzLzBlugMyTAf13+pzg=="], + + "astro/shiki/@shikijs/themes": ["@shikijs/themes@3.14.0", "", { "dependencies": { "@shikijs/types": "3.14.0" } }, "sha512-fAo/OnfWckNmv4uBoUu6dSlkcBc+SA1xzj5oUSaz5z3KqHtEbUypg/9xxgJARtM6+7RVm0Q6Xnty41xA1ma1IA=="], + + "astro/shiki/@shikijs/types": ["@shikijs/types@3.14.0", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-bQGgC6vrY8U/9ObG1Z/vTro+uclbjjD/uG58RvfxKZVD5p9Yc1ka3tVyEFy7BNJLzxuWyHH5NWynP9zZZS59eQ=="], + "axios/form-data/mime-types": ["mime-types@2.1.35", "", { "dependencies": { "mime-db": "1.52.0" } }, "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw=="], "babel-plugin-module-resolver/glob/minimatch": ["minimatch@8.0.4", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-W0Wvr9HyFXZRGIDgCicunpQ299OKXs9RgZfaukz4qAW/pJhcpUfupc9c+OObPOFueNy8VSrZgEmDtk6Kh4WzDA=="], @@ -4378,6 +4409,8 @@ "babel-plugin-module-resolver/glob/path-scurry": ["path-scurry@1.11.1", "", { "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" } }, "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA=="], + "bl/buffer/ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="], + "body-parser/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], "c12/pkg-types/pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="], @@ -4490,7 +4523,7 @@ "opencontrol/@modelcontextprotocol/sdk/zod-to-json-schema": ["zod-to-json-schema@3.24.5", "", { "peerDependencies": { "zod": "^3.24.1" } }, "sha512-/AuWwMP+YqiPbsJx5D6TfgRTc4kTLjsh5SOcd4bLsfUg2RcEXrFMJl1DGgdHy2aCfsIA/cr/1JM0xcB2GZji8g=="], - "parse-bmfont-xml/xml2js/sax": ["sax@1.4.1", "", {}, "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg=="], + "parse-bmfont-xml/xml2js/sax": ["sax@1.4.3", "", {}, "sha512-yqYn1JhPczigF94DMS+shiDMjDowYO6y9+wB/4WgO0Y19jWYk0lQ4tuG5KI7kj4FTp1wxPj5IFfcrz/s1c3jjQ=="], "pkg-up/find-up/locate-path": ["locate-path@3.0.0", "", { "dependencies": { "p-locate": "^3.0.0", "path-exists": "^3.0.0" } }, "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A=="], @@ -4514,8 +4547,6 @@ "string-width-cjs/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], - "style-to-js/style-to-object/inline-style-parser": ["inline-style-parser@0.2.4", "", {}, "sha512-0aO8FkhNZlj/ZIbNi7Lxxr12obT7cL1moPfE4tg1LkX7LlLfC6DeX4l2ZEud1ukP9jNQyNnfzQVqwbwmAATY4Q=="], - "sucrase/glob/jackspeak": ["jackspeak@3.4.3", "", { "dependencies": { "@isaacs/cliui": "^8.0.2" }, "optionalDependencies": { "@pkgjs/parseargs": "^0.11.0" } }, "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw=="], "sucrase/glob/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], @@ -4598,17 +4629,17 @@ "@actions/github/@octokit/request/@octokit/types/@octokit/openapi-types": ["@octokit/openapi-types@24.2.0", "", {}, "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg=="], - "@astrojs/mdx/@astrojs/markdown-remark/shiki/@shikijs/core": ["@shikijs/core@3.13.0", "", { "dependencies": { "@shikijs/types": "3.13.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4", "hast-util-to-html": "^9.0.5" } }, "sha512-3P8rGsg2Eh2qIHekwuQjzWhKI4jV97PhvYjYUzGqjvJfqdQPz+nMlfWahU24GZAyW1FxFI1sYjyhfh5CoLmIUA=="], + "@astrojs/mdx/@astrojs/markdown-remark/shiki/@shikijs/core": ["@shikijs/core@3.14.0", "", { "dependencies": { "@shikijs/types": "3.14.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4", "hast-util-to-html": "^9.0.5" } }, "sha512-qRSeuP5vlYHCNUIrpEBQFO7vSkR7jn7Kv+5X3FO/zBKVDGQbcnlScD3XhkrHi/R8Ltz0kEjvFR9Szp/XMRbFMw=="], - "@astrojs/mdx/@astrojs/markdown-remark/shiki/@shikijs/engine-javascript": ["@shikijs/engine-javascript@3.13.0", "", { "dependencies": { "@shikijs/types": "3.13.0", "@shikijs/vscode-textmate": "^10.0.2", "oniguruma-to-es": "^4.3.3" } }, "sha512-Ty7xv32XCp8u0eQt8rItpMs6rU9Ki6LJ1dQOW3V/56PKDcpvfHPnYFbsx5FFUP2Yim34m/UkazidamMNVR4vKg=="], + "@astrojs/mdx/@astrojs/markdown-remark/shiki/@shikijs/engine-javascript": ["@shikijs/engine-javascript@3.14.0", "", { "dependencies": { "@shikijs/types": "3.14.0", "@shikijs/vscode-textmate": "^10.0.2", "oniguruma-to-es": "^4.3.3" } }, "sha512-3v1kAXI2TsWQuwv86cREH/+FK9Pjw3dorVEykzQDhwrZj0lwsHYlfyARaKmn6vr5Gasf8aeVpb8JkzeWspxOLQ=="], - "@astrojs/mdx/@astrojs/markdown-remark/shiki/@shikijs/engine-oniguruma": ["@shikijs/engine-oniguruma@3.13.0", "", { "dependencies": { "@shikijs/types": "3.13.0", "@shikijs/vscode-textmate": "^10.0.2" } }, "sha512-O42rBGr4UDSlhT2ZFMxqM7QzIU+IcpoTMzb3W7AlziI1ZF7R8eS2M0yt5Ry35nnnTX/LTLXFPUjRFCIW+Operg=="], + "@astrojs/mdx/@astrojs/markdown-remark/shiki/@shikijs/engine-oniguruma": ["@shikijs/engine-oniguruma@3.14.0", "", { "dependencies": { "@shikijs/types": "3.14.0", "@shikijs/vscode-textmate": "^10.0.2" } }, "sha512-TNcYTYMbJyy+ZjzWtt0bG5y4YyMIWC2nyePz+CFMWqm+HnZZyy9SWMgo8Z6KBJVIZnx8XUXS8U2afO6Y0g1Oug=="], - "@astrojs/mdx/@astrojs/markdown-remark/shiki/@shikijs/langs": ["@shikijs/langs@3.13.0", "", { "dependencies": { "@shikijs/types": "3.13.0" } }, "sha512-672c3WAETDYHwrRP0yLy3W1QYB89Hbpj+pO4KhxK6FzIrDI2FoEXNiNCut6BQmEApYLfuYfpgOZaqbY+E9b8wQ=="], + "@astrojs/mdx/@astrojs/markdown-remark/shiki/@shikijs/langs": ["@shikijs/langs@3.14.0", "", { "dependencies": { "@shikijs/types": "3.14.0" } }, "sha512-DIB2EQY7yPX1/ZH7lMcwrK5pl+ZkP/xoSpUzg9YC8R+evRCCiSQ7yyrvEyBsMnfZq4eBzLzBlugMyTAf13+pzg=="], - "@astrojs/mdx/@astrojs/markdown-remark/shiki/@shikijs/themes": ["@shikijs/themes@3.13.0", "", { "dependencies": { "@shikijs/types": "3.13.0" } }, "sha512-Vxw1Nm1/Od8jyA7QuAenaV78BG2nSr3/gCGdBkLpfLscddCkzkL36Q5b67SrLLfvAJTOUzW39x4FHVCFriPVgg=="], + "@astrojs/mdx/@astrojs/markdown-remark/shiki/@shikijs/themes": ["@shikijs/themes@3.14.0", "", { "dependencies": { "@shikijs/types": "3.14.0" } }, "sha512-fAo/OnfWckNmv4uBoUu6dSlkcBc+SA1xzj5oUSaz5z3KqHtEbUypg/9xxgJARtM6+7RVm0Q6Xnty41xA1ma1IA=="], - "@astrojs/mdx/@astrojs/markdown-remark/shiki/@shikijs/types": ["@shikijs/types@3.13.0", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-oM9P+NCFri/mmQ8LoFGVfVyemm5Hi27330zuOBp0annwJdKH1kOLndw3zCtAVDehPLg9fKqoEx3Ht/wNZxolfw=="], + "@astrojs/mdx/@astrojs/markdown-remark/shiki/@shikijs/types": ["@shikijs/types@3.14.0", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-bQGgC6vrY8U/9ObG1Z/vTro+uclbjjD/uG58RvfxKZVD5p9Yc1ka3tVyEFy7BNJLzxuWyHH5NWynP9zZZS59eQ=="], "@aws-crypto/sha256-browser/@smithy/util-utf8/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@2.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA=="], @@ -4740,7 +4771,7 @@ "@solidjs/start/shiki/@shikijs/engine-javascript/oniguruma-to-es/regex-recursion": ["regex-recursion@5.1.1", "", { "dependencies": { "regex": "^5.1.1", "regex-utilities": "^2.3.0" } }, "sha512-ae7SBCbzVNrIjgSbh7wMznPcQel1DNlDtzensnFxpiNpXt1U2ju/bHugH422r+4LAVS1FpW1YCwilmnNsjum9w=="], - "nitropack/c12/giget/nypm/tinyexec": ["tinyexec@1.0.1", "", {}, "sha512-5uC6DDlmeqiOwCPmK9jMSdOuZTh8bU39Ys6yidB+UTt5hfZUPGAypSgFRiEp+jbi9qH40BLDvy85jIU88wKSqw=="], + "nitropack/c12/giget/nypm/tinyexec": ["tinyexec@1.0.2", "", {}, "sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg=="], "opencontrol/@modelcontextprotocol/sdk/express/accepts/negotiator": ["negotiator@1.0.0", "", {}, "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg=="], From e136a40771fc02b16fdf7c08e294225b9678a312 Mon Sep 17 00:00:00 2001 From: Dax Raad Date: Wed, 5 Nov 2025 20:31:13 -0500 Subject: [PATCH 055/218] ignore tmp type rrror --- packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx b/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx index 663e4f52..c977f731 100644 --- a/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx +++ b/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx @@ -539,7 +539,8 @@ export function Prompt(props: PromptProps) { syncExtmarksWithPromptParts() }} keyBindings={textareaKeybindings()} - onKeyDown={async (e: KeyEvent) => { + // TODO: fix this any + onKeyDown={async (e: any) => { if (props.disabled) { e.preventDefault() return From c7031dfd77219312c450b5ea846b66a4b1a7db27 Mon Sep 17 00:00:00 2001 From: opencode Date: Thu, 6 Nov 2025 01:35:40 +0000 Subject: [PATCH 056/218] release: v1.0.31 --- bun.lock | 22 +++++++++++----------- packages/console/app/package.json | 2 +- packages/console/core/package.json | 2 +- packages/console/function/package.json | 2 +- packages/console/mail/package.json | 2 +- packages/desktop/package.json | 2 +- packages/function/package.json | 2 +- packages/opencode/package.json | 2 +- packages/plugin/package.json | 2 +- packages/sdk/js/package.json | 2 +- packages/slack/package.json | 2 +- packages/ui/package.json | 2 +- packages/web/package.json | 2 +- sdks/vscode/package.json | 2 +- 14 files changed, 24 insertions(+), 24 deletions(-) diff --git a/bun.lock b/bun.lock index 50481cb7..d41ed5b1 100644 --- a/bun.lock +++ b/bun.lock @@ -39,7 +39,7 @@ }, "packages/console/core": { "name": "@opencode-ai/console-core", - "version": "1.0.30", + "version": "1.0.31", "dependencies": { "@aws-sdk/client-sts": "3.782.0", "@jsx-email/render": "1.1.1", @@ -66,7 +66,7 @@ }, "packages/console/function": { "name": "@opencode-ai/console-function", - "version": "1.0.30", + "version": "1.0.31", "dependencies": { "@ai-sdk/anthropic": "2.0.0", "@ai-sdk/openai": "2.0.2", @@ -90,7 +90,7 @@ }, "packages/console/mail": { "name": "@opencode-ai/console-mail", - "version": "1.0.30", + "version": "1.0.31", "dependencies": { "@jsx-email/all": "2.2.3", "@jsx-email/cli": "1.4.3", @@ -111,7 +111,7 @@ }, "packages/desktop": { "name": "@opencode-ai/desktop", - "version": "1.0.30", + "version": "1.0.31", "dependencies": { "@kobalte/core": "catalog:", "@opencode-ai/sdk": "workspace:*", @@ -151,7 +151,7 @@ }, "packages/function": { "name": "@opencode-ai/function", - "version": "1.0.30", + "version": "1.0.31", "dependencies": { "@octokit/auth-app": "8.0.1", "@octokit/rest": "22.0.0", @@ -167,7 +167,7 @@ }, "packages/opencode": { "name": "opencode", - "version": "1.0.30", + "version": "1.0.31", "bin": { "opencode": "./bin/opencode", }, @@ -244,7 +244,7 @@ }, "packages/plugin": { "name": "@opencode-ai/plugin", - "version": "1.0.30", + "version": "1.0.31", "dependencies": { "@opencode-ai/sdk": "workspace:*", "zod": "catalog:", @@ -264,7 +264,7 @@ }, "packages/sdk/js": { "name": "@opencode-ai/sdk", - "version": "1.0.30", + "version": "1.0.31", "devDependencies": { "@hey-api/openapi-ts": "0.81.0", "@tsconfig/node22": "catalog:", @@ -275,7 +275,7 @@ }, "packages/slack": { "name": "@opencode-ai/slack", - "version": "1.0.30", + "version": "1.0.31", "dependencies": { "@opencode-ai/sdk": "workspace:*", "@slack/bolt": "^3.17.1", @@ -288,7 +288,7 @@ }, "packages/ui": { "name": "@opencode-ai/ui", - "version": "1.0.30", + "version": "1.0.31", "dependencies": { "@kobalte/core": "catalog:", "@opencode-ai/sdk": "workspace:*", @@ -318,7 +318,7 @@ }, "packages/web": { "name": "@opencode-ai/web", - "version": "1.0.30", + "version": "1.0.31", "dependencies": { "@astrojs/cloudflare": "12.6.3", "@astrojs/markdown-remark": "6.3.1", diff --git a/packages/console/app/package.json b/packages/console/app/package.json index 3b12a686..d44f2060 100644 --- a/packages/console/app/package.json +++ b/packages/console/app/package.json @@ -7,7 +7,7 @@ "dev:remote": "VITE_AUTH_URL=https://auth.dev.opencode.ai bun sst shell --stage=dev bun dev", "build": "vinxi build && ../../opencode/script/schema.ts ./.output/public/config.json", "start": "vinxi start", - "version": "1.0.30" + "version": "1.0.31" }, "dependencies": { "@ibm/plex": "6.4.1", diff --git a/packages/console/core/package.json b/packages/console/core/package.json index 4c9b6792..52cd15a2 100644 --- a/packages/console/core/package.json +++ b/packages/console/core/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@opencode-ai/console-core", - "version": "1.0.30", + "version": "1.0.31", "private": true, "type": "module", "dependencies": { diff --git a/packages/console/function/package.json b/packages/console/function/package.json index b0721092..320d5512 100644 --- a/packages/console/function/package.json +++ b/packages/console/function/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/console-function", - "version": "1.0.30", + "version": "1.0.31", "$schema": "https://json.schemastore.org/package.json", "private": true, "type": "module", diff --git a/packages/console/mail/package.json b/packages/console/mail/package.json index 7bd6061f..7fd3f40f 100644 --- a/packages/console/mail/package.json +++ b/packages/console/mail/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/console-mail", - "version": "1.0.30", + "version": "1.0.31", "dependencies": { "@jsx-email/all": "2.2.3", "@jsx-email/cli": "1.4.3", diff --git a/packages/desktop/package.json b/packages/desktop/package.json index edadbc9a..b2483eaf 100644 --- a/packages/desktop/package.json +++ b/packages/desktop/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/desktop", - "version": "1.0.30", + "version": "1.0.31", "description": "", "type": "module", "scripts": { diff --git a/packages/function/package.json b/packages/function/package.json index ce393910..7ea38ad3 100644 --- a/packages/function/package.json +++ b/packages/function/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/function", - "version": "1.0.30", + "version": "1.0.31", "$schema": "https://json.schemastore.org/package.json", "private": true, "type": "module", diff --git a/packages/opencode/package.json b/packages/opencode/package.json index b2d3e8c7..783707ef 100644 --- a/packages/opencode/package.json +++ b/packages/opencode/package.json @@ -1,6 +1,6 @@ { "$schema": "https://json.schemastore.org/package.json", - "version": "1.0.30", + "version": "1.0.31", "name": "opencode", "type": "module", "private": true, diff --git a/packages/plugin/package.json b/packages/plugin/package.json index a8531f0c..44146c5f 100644 --- a/packages/plugin/package.json +++ b/packages/plugin/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@opencode-ai/plugin", - "version": "1.0.30", + "version": "1.0.31", "type": "module", "scripts": { "typecheck": "tsgo --noEmit", diff --git a/packages/sdk/js/package.json b/packages/sdk/js/package.json index 64c2c8ed..a89c29dd 100644 --- a/packages/sdk/js/package.json +++ b/packages/sdk/js/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@opencode-ai/sdk", - "version": "1.0.30", + "version": "1.0.31", "type": "module", "scripts": { "typecheck": "tsgo --noEmit", diff --git a/packages/slack/package.json b/packages/slack/package.json index d7ed96b0..9879db9d 100644 --- a/packages/slack/package.json +++ b/packages/slack/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/slack", - "version": "1.0.30", + "version": "1.0.31", "type": "module", "scripts": { "dev": "bun run src/index.ts", diff --git a/packages/ui/package.json b/packages/ui/package.json index 96a3aa43..653ba92e 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/ui", - "version": "1.0.30", + "version": "1.0.31", "type": "module", "exports": { ".": "./src/components/index.ts", diff --git a/packages/web/package.json b/packages/web/package.json index 57724979..dc230766 100644 --- a/packages/web/package.json +++ b/packages/web/package.json @@ -1,7 +1,7 @@ { "name": "@opencode-ai/web", "type": "module", - "version": "1.0.30", + "version": "1.0.31", "scripts": { "dev": "astro dev", "dev:remote": "VITE_API_URL=https://api.opencode.ai astro dev", diff --git a/sdks/vscode/package.json b/sdks/vscode/package.json index a53147d8..471f3bdb 100644 --- a/sdks/vscode/package.json +++ b/sdks/vscode/package.json @@ -2,7 +2,7 @@ "name": "opencode", "displayName": "opencode", "description": "opencode for VS Code", - "version": "1.0.30", + "version": "1.0.31", "publisher": "sst-dev", "repository": { "type": "git", From 5a84b9f4674f624fe0117d66d5d1af48886fb345 Mon Sep 17 00:00:00 2001 From: Dax Raad Date: Wed, 5 Nov 2025 20:38:23 -0500 Subject: [PATCH 057/218] temporarily use strip-ansi package till bun bug is fixed --- bun.lock | 1 + packages/opencode/package.json | 1 + packages/opencode/src/cli/cmd/tui/routes/session/index.tsx | 3 ++- 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/bun.lock b/bun.lock index d41ed5b1..ccfa89aa 100644 --- a/bun.lock +++ b/bun.lock @@ -208,6 +208,7 @@ "partial-json": "0.1.7", "remeda": "catalog:", "solid-js": "catalog:", + "strip-ansi": "7.1.2", "tree-sitter-bash": "0.25.0", "turndown": "7.2.0", "ulid": "catalog:", diff --git a/packages/opencode/package.json b/packages/opencode/package.json index 783707ef..10e3adf9 100644 --- a/packages/opencode/package.json +++ b/packages/opencode/package.json @@ -77,6 +77,7 @@ "partial-json": "0.1.7", "remeda": "catalog:", "solid-js": "catalog:", + "strip-ansi": "7.1.2", "tree-sitter-bash": "0.25.0", "turndown": "7.2.0", "ulid": "catalog:", diff --git a/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx b/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx index 37820759..de8b2b89 100644 --- a/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx +++ b/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx @@ -68,6 +68,7 @@ import { useKV } from "../../context/kv.tsx" import { Editor } from "../../util/editor" import { Global } from "@/global" import fs from "fs/promises" +import stripAnsi from "strip-ansi" addDefaultParsers(parsers.parsers) @@ -1172,7 +1173,7 @@ ToolRegistry.register({ name: "bash", container: "block", render(props) { - const output = createMemo(() => props.metadata.output?.trim() ?? "") + const output = createMemo(() => stripAnsi(props.metadata.output?.trim() ?? "")) const { theme } = useTheme() return ( <> From bb6acc0ec6d8c01644b4b3bc5f47b36afa6948ca Mon Sep 17 00:00:00 2001 From: opencode Date: Thu, 6 Nov 2025 01:43:35 +0000 Subject: [PATCH 058/218] release: v1.0.32 --- bun.lock | 22 +++++++++++----------- packages/console/app/package.json | 2 +- packages/console/core/package.json | 2 +- packages/console/function/package.json | 2 +- packages/console/mail/package.json | 2 +- packages/desktop/package.json | 2 +- packages/function/package.json | 2 +- packages/opencode/package.json | 2 +- packages/plugin/package.json | 2 +- packages/sdk/js/package.json | 2 +- packages/slack/package.json | 2 +- packages/ui/package.json | 2 +- packages/web/package.json | 2 +- sdks/vscode/package.json | 2 +- 14 files changed, 24 insertions(+), 24 deletions(-) diff --git a/bun.lock b/bun.lock index ccfa89aa..3165da34 100644 --- a/bun.lock +++ b/bun.lock @@ -39,7 +39,7 @@ }, "packages/console/core": { "name": "@opencode-ai/console-core", - "version": "1.0.31", + "version": "1.0.32", "dependencies": { "@aws-sdk/client-sts": "3.782.0", "@jsx-email/render": "1.1.1", @@ -66,7 +66,7 @@ }, "packages/console/function": { "name": "@opencode-ai/console-function", - "version": "1.0.31", + "version": "1.0.32", "dependencies": { "@ai-sdk/anthropic": "2.0.0", "@ai-sdk/openai": "2.0.2", @@ -90,7 +90,7 @@ }, "packages/console/mail": { "name": "@opencode-ai/console-mail", - "version": "1.0.31", + "version": "1.0.32", "dependencies": { "@jsx-email/all": "2.2.3", "@jsx-email/cli": "1.4.3", @@ -111,7 +111,7 @@ }, "packages/desktop": { "name": "@opencode-ai/desktop", - "version": "1.0.31", + "version": "1.0.32", "dependencies": { "@kobalte/core": "catalog:", "@opencode-ai/sdk": "workspace:*", @@ -151,7 +151,7 @@ }, "packages/function": { "name": "@opencode-ai/function", - "version": "1.0.31", + "version": "1.0.32", "dependencies": { "@octokit/auth-app": "8.0.1", "@octokit/rest": "22.0.0", @@ -167,7 +167,7 @@ }, "packages/opencode": { "name": "opencode", - "version": "1.0.31", + "version": "1.0.32", "bin": { "opencode": "./bin/opencode", }, @@ -245,7 +245,7 @@ }, "packages/plugin": { "name": "@opencode-ai/plugin", - "version": "1.0.31", + "version": "1.0.32", "dependencies": { "@opencode-ai/sdk": "workspace:*", "zod": "catalog:", @@ -265,7 +265,7 @@ }, "packages/sdk/js": { "name": "@opencode-ai/sdk", - "version": "1.0.31", + "version": "1.0.32", "devDependencies": { "@hey-api/openapi-ts": "0.81.0", "@tsconfig/node22": "catalog:", @@ -276,7 +276,7 @@ }, "packages/slack": { "name": "@opencode-ai/slack", - "version": "1.0.31", + "version": "1.0.32", "dependencies": { "@opencode-ai/sdk": "workspace:*", "@slack/bolt": "^3.17.1", @@ -289,7 +289,7 @@ }, "packages/ui": { "name": "@opencode-ai/ui", - "version": "1.0.31", + "version": "1.0.32", "dependencies": { "@kobalte/core": "catalog:", "@opencode-ai/sdk": "workspace:*", @@ -319,7 +319,7 @@ }, "packages/web": { "name": "@opencode-ai/web", - "version": "1.0.31", + "version": "1.0.32", "dependencies": { "@astrojs/cloudflare": "12.6.3", "@astrojs/markdown-remark": "6.3.1", diff --git a/packages/console/app/package.json b/packages/console/app/package.json index d44f2060..3172193f 100644 --- a/packages/console/app/package.json +++ b/packages/console/app/package.json @@ -7,7 +7,7 @@ "dev:remote": "VITE_AUTH_URL=https://auth.dev.opencode.ai bun sst shell --stage=dev bun dev", "build": "vinxi build && ../../opencode/script/schema.ts ./.output/public/config.json", "start": "vinxi start", - "version": "1.0.31" + "version": "1.0.32" }, "dependencies": { "@ibm/plex": "6.4.1", diff --git a/packages/console/core/package.json b/packages/console/core/package.json index 52cd15a2..3f5aca73 100644 --- a/packages/console/core/package.json +++ b/packages/console/core/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@opencode-ai/console-core", - "version": "1.0.31", + "version": "1.0.32", "private": true, "type": "module", "dependencies": { diff --git a/packages/console/function/package.json b/packages/console/function/package.json index 320d5512..db6712c5 100644 --- a/packages/console/function/package.json +++ b/packages/console/function/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/console-function", - "version": "1.0.31", + "version": "1.0.32", "$schema": "https://json.schemastore.org/package.json", "private": true, "type": "module", diff --git a/packages/console/mail/package.json b/packages/console/mail/package.json index 7fd3f40f..75d82be2 100644 --- a/packages/console/mail/package.json +++ b/packages/console/mail/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/console-mail", - "version": "1.0.31", + "version": "1.0.32", "dependencies": { "@jsx-email/all": "2.2.3", "@jsx-email/cli": "1.4.3", diff --git a/packages/desktop/package.json b/packages/desktop/package.json index b2483eaf..4e870b99 100644 --- a/packages/desktop/package.json +++ b/packages/desktop/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/desktop", - "version": "1.0.31", + "version": "1.0.32", "description": "", "type": "module", "scripts": { diff --git a/packages/function/package.json b/packages/function/package.json index 7ea38ad3..55996a80 100644 --- a/packages/function/package.json +++ b/packages/function/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/function", - "version": "1.0.31", + "version": "1.0.32", "$schema": "https://json.schemastore.org/package.json", "private": true, "type": "module", diff --git a/packages/opencode/package.json b/packages/opencode/package.json index 10e3adf9..3062ffca 100644 --- a/packages/opencode/package.json +++ b/packages/opencode/package.json @@ -1,6 +1,6 @@ { "$schema": "https://json.schemastore.org/package.json", - "version": "1.0.31", + "version": "1.0.32", "name": "opencode", "type": "module", "private": true, diff --git a/packages/plugin/package.json b/packages/plugin/package.json index 44146c5f..6cc844b0 100644 --- a/packages/plugin/package.json +++ b/packages/plugin/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@opencode-ai/plugin", - "version": "1.0.31", + "version": "1.0.32", "type": "module", "scripts": { "typecheck": "tsgo --noEmit", diff --git a/packages/sdk/js/package.json b/packages/sdk/js/package.json index a89c29dd..3cd80647 100644 --- a/packages/sdk/js/package.json +++ b/packages/sdk/js/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@opencode-ai/sdk", - "version": "1.0.31", + "version": "1.0.32", "type": "module", "scripts": { "typecheck": "tsgo --noEmit", diff --git a/packages/slack/package.json b/packages/slack/package.json index 9879db9d..8b734d17 100644 --- a/packages/slack/package.json +++ b/packages/slack/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/slack", - "version": "1.0.31", + "version": "1.0.32", "type": "module", "scripts": { "dev": "bun run src/index.ts", diff --git a/packages/ui/package.json b/packages/ui/package.json index 653ba92e..3633ea5e 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/ui", - "version": "1.0.31", + "version": "1.0.32", "type": "module", "exports": { ".": "./src/components/index.ts", diff --git a/packages/web/package.json b/packages/web/package.json index dc230766..a3747f39 100644 --- a/packages/web/package.json +++ b/packages/web/package.json @@ -1,7 +1,7 @@ { "name": "@opencode-ai/web", "type": "module", - "version": "1.0.31", + "version": "1.0.32", "scripts": { "dev": "astro dev", "dev:remote": "VITE_API_URL=https://api.opencode.ai astro dev", diff --git a/sdks/vscode/package.json b/sdks/vscode/package.json index 471f3bdb..df75dd4c 100644 --- a/sdks/vscode/package.json +++ b/sdks/vscode/package.json @@ -2,7 +2,7 @@ "name": "opencode", "displayName": "opencode", "description": "opencode for VS Code", - "version": "1.0.31", + "version": "1.0.32", "publisher": "sst-dev", "repository": { "type": "git", From 6e553f7e200c074b9645bd897ec73e977f3969ff Mon Sep 17 00:00:00 2001 From: Sebastian Herrlinger Date: Thu, 6 Nov 2025 02:40:52 +0100 Subject: [PATCH 059/218] upgrade to opentui v0.1.36 --- bun.lock | 20 ++++++++++---------- packages/opencode/package.json | 4 ++-- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/bun.lock b/bun.lock index 3165da34..ca5b62ef 100644 --- a/bun.lock +++ b/bun.lock @@ -185,8 +185,8 @@ "@opencode-ai/plugin": "workspace:*", "@opencode-ai/script": "workspace:*", "@opencode-ai/sdk": "workspace:*", - "@opentui/core": "0.1.35", - "@opentui/solid": "0.1.35", + "@opentui/core": "0.1.36", + "@opentui/solid": "0.1.36", "@parcel/watcher": "2.5.1", "@pierre/precision-diffs": "catalog:", "@solid-primitives/event-bus": "1.1.2", @@ -962,21 +962,21 @@ "@opentelemetry/api": ["@opentelemetry/api@1.9.0", "", {}, "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg=="], - "@opentui/core": ["@opentui/core@0.1.35", "", { "dependencies": { "bun-ffi-structs": "^0.1.0", "jimp": "1.6.0", "yoga-layout": "3.2.1" }, "optionalDependencies": { "@dimforge/rapier2d-simd-compat": "^0.17.3", "@opentui/core-darwin-arm64": "0.1.35", "@opentui/core-darwin-x64": "0.1.35", "@opentui/core-linux-arm64": "0.1.35", "@opentui/core-linux-x64": "0.1.35", "@opentui/core-win32-arm64": "0.1.35", "@opentui/core-win32-x64": "0.1.35", "bun-webgpu": "0.1.3", "planck": "^1.4.2", "three": "0.177.0" }, "peerDependencies": { "web-tree-sitter": "0.25.10" } }, "sha512-t7xUaie+ri7ROXcWWLrQ0XY0Mo2kH6gqyagZrNRgUjH1zudqPBYJddiw7Kc9LMuPtV8usPzlzjXIny+EzuawkA=="], + "@opentui/core": ["@opentui/core@0.1.36", "", { "dependencies": { "bun-ffi-structs": "^0.1.0", "jimp": "1.6.0", "yoga-layout": "3.2.1" }, "optionalDependencies": { "@dimforge/rapier2d-simd-compat": "^0.17.3", "@opentui/core-darwin-arm64": "0.1.36", "@opentui/core-darwin-x64": "0.1.36", "@opentui/core-linux-arm64": "0.1.36", "@opentui/core-linux-x64": "0.1.36", "@opentui/core-win32-arm64": "0.1.36", "@opentui/core-win32-x64": "0.1.36", "bun-webgpu": "0.1.3", "planck": "^1.4.2", "three": "0.177.0" }, "peerDependencies": { "web-tree-sitter": "0.25.10" } }, "sha512-urDrj33udJ0dJGkZv+T5U0mCFBOOvUt9Tvqkrj8aRvi6kN0Bc5d2COuWcpAKo0TO9/PvjSwHC+CMnw2Sr46/ug=="], - "@opentui/core-darwin-arm64": ["@opentui/core-darwin-arm64@0.1.35", "", { "os": "darwin", "cpu": "arm64" }, "sha512-mSu6sS4a8DBejMqr06xtRdLtS+8m4oRzFVNtiKuY1T9PL74SnRmUl3VFxseY19ZMSVVAz/7hHPFX+ttmoT2pEw=="], + "@opentui/core-darwin-arm64": ["@opentui/core-darwin-arm64@0.1.36", "", { "os": "darwin", "cpu": "arm64" }, "sha512-/fb0k1H0CeTroVt2UoEAcVrEx1cIYy4B2zfX0MrwUkIfXi36aoIBnisBeYvyCpsQfxFAkyLYCCA3NzaYEyC5hg=="], - "@opentui/core-darwin-x64": ["@opentui/core-darwin-x64@0.1.35", "", { "os": "darwin", "cpu": "x64" }, "sha512-HqIbf25OSJgsxfe+G6ZvpsGolj1V8yTIXrAUcRSqCmw/Xdp82JqTnI6zx1cxQSllVmF4SxT+WwTRG216DE5MMw=="], + "@opentui/core-darwin-x64": ["@opentui/core-darwin-x64@0.1.36", "", { "os": "darwin", "cpu": "x64" }, "sha512-PZMydJbSDUoEWqZsyEV8+FSwMT+r7mWFL0ABgdALI3AOrSr7Z8dMcRnFWl8LhriuHS589THvETJEN28L4q/E2Q=="], - "@opentui/core-linux-arm64": ["@opentui/core-linux-arm64@0.1.35", "", { "os": "linux", "cpu": "arm64" }, "sha512-zNZpKg2fxZTsMJAjW3M9Il+1if61oe+d3m98hPm1i/UDtM+Fj8pkU0XBnsIJHfP5GVNnVHuLksXDpqmHquNmOg=="], + "@opentui/core-linux-arm64": ["@opentui/core-linux-arm64@0.1.36", "", { "os": "linux", "cpu": "arm64" }, "sha512-ATR+vdtraZEC/gHR1mQa/NYPlqFNBpsnnJAGepQmcxm85VceLYM701QaaIgNAwyYXiP6RQN1ZCv06MD1Ph1m4w=="], - "@opentui/core-linux-x64": ["@opentui/core-linux-x64@0.1.35", "", { "os": "linux", "cpu": "x64" }, "sha512-KKLw9Po+KC0u0JWG9p1bCWKro3dzSg56QQ8Y9CR/wT2ywTatNrtiYeymoeft3BogWSz65PxQr7Dw8kwdUOD3yQ=="], + "@opentui/core-linux-x64": ["@opentui/core-linux-x64@0.1.36", "", { "os": "linux", "cpu": "x64" }, "sha512-INsnPtcZVx68C+0Vd0L9+akDwNbWblUDqLmY9CftfmeLFubzvJXNRYTBvr7lX68fcst6Ho+0beUxyUoClKc0rg=="], - "@opentui/core-win32-arm64": ["@opentui/core-win32-arm64@0.1.35", "", { "os": "win32", "cpu": "arm64" }, "sha512-5ycmzf0D8SkaR4xlTZqneegFt4w4RK2Q9yZC3ZiAclNMtffVnWOkK/3zIpCwTdi2I1wHPVG0doX6pi0EUM7f2A=="], + "@opentui/core-win32-arm64": ["@opentui/core-win32-arm64@0.1.36", "", { "os": "win32", "cpu": "arm64" }, "sha512-x9lDZTL+xE8jsG1hP4pdsqCsZBu77JNR/ze5F7ZQkYQEC6Zl/XJtL1YT08nUlWOu4NMSws2xXV0lS/sJkbEgPA=="], - "@opentui/core-win32-x64": ["@opentui/core-win32-x64@0.1.35", "", { "os": "win32", "cpu": "x64" }, "sha512-m/l9NkzT/asdpPPN0525z5JcYiHc++feIisqmHS1+IfqirTDuReyKk7HxU3MydxrFcsp1LBMCxFipWiYV2V9hw=="], + "@opentui/core-win32-x64": ["@opentui/core-win32-x64@0.1.36", "", { "os": "win32", "cpu": "x64" }, "sha512-WVU+qtAfJe8ikPWbw8Hfli15GuQTMKiceTkF5lql5AQYy7PKYtGTzWszxOZKeUU1/eEd2X4REi8Bn0TprEMxYw=="], - "@opentui/solid": ["@opentui/solid@0.1.35", "", { "dependencies": { "@babel/core": "7.28.0", "@babel/preset-typescript": "7.27.1", "@opentui/core": "0.1.35", "babel-plugin-module-resolver": "5.0.2", "babel-preset-solid": "1.9.9", "s-js": "^0.4.9" }, "peerDependencies": { "solid-js": "1.9.9" } }, "sha512-VIhPmnZstthNpDWZzouOE6YzEnLHI3HbuT9wL6wf0K7Fp0kJEGUA7dlYscSpX9ZBY15B7COnIkSagC/C7hUQkw=="], + "@opentui/solid": ["@opentui/solid@0.1.36", "", { "dependencies": { "@babel/core": "7.28.0", "@babel/preset-typescript": "7.27.1", "@opentui/core": "0.1.36", "babel-plugin-module-resolver": "5.0.2", "babel-preset-solid": "1.9.9", "s-js": "^0.4.9" }, "peerDependencies": { "solid-js": "1.9.9" } }, "sha512-oHI01kZgyNecvXRFyQKJEDC5TCcsvfTPxHCa/XjbcZzH2qE2rfYMUF0mpwlLqoY9b3pm3w7Tpa8upzi1euBGJg=="], "@oslojs/asn1": ["@oslojs/asn1@1.0.0", "", { "dependencies": { "@oslojs/binary": "1.0.0" } }, "sha512-zw/wn0sj0j0QKbIXfIlnEcTviaCzYOY3V5rAyjR6YtOByFtJiT574+8p9Wlach0lZH9fddD4yb9laEAIl4vXQA=="], diff --git a/packages/opencode/package.json b/packages/opencode/package.json index 3062ffca..b292ec13 100644 --- a/packages/opencode/package.json +++ b/packages/opencode/package.json @@ -54,8 +54,8 @@ "@opencode-ai/plugin": "workspace:*", "@opencode-ai/script": "workspace:*", "@opencode-ai/sdk": "workspace:*", - "@opentui/core": "0.1.35", - "@opentui/solid": "0.1.35", + "@opentui/core": "0.1.36", + "@opentui/solid": "0.1.36", "@parcel/watcher": "2.5.1", "@pierre/precision-diffs": "catalog:", "@solid-primitives/event-bus": "1.1.2", From 0a5a02043c37d677fc336a7685ab3b4e5a66f1f2 Mon Sep 17 00:00:00 2001 From: Dax Raad Date: Wed, 5 Nov 2025 21:13:35 -0500 Subject: [PATCH 060/218] tui: move debug shortcuts to command palette for better discoverability --- packages/opencode/src/cli/cmd/tui/app.tsx | 29 +++++++++++++---------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/packages/opencode/src/cli/cmd/tui/app.tsx b/packages/opencode/src/cli/cmd/tui/app.tsx index 1c309e89..c382a0f1 100644 --- a/packages/opencode/src/cli/cmd/tui/app.tsx +++ b/packages/opencode/src/cli/cmd/tui/app.tsx @@ -176,19 +176,6 @@ function App() { const { theme, mode, setMode } = useTheme() const exit = useExit() - useKeyboard(async (evt) => { - if (!Installation.isLocal()) return - if (evt.meta && evt.name === "t") { - renderer.toggleDebugOverlay() - return - } - - if (evt.meta && evt.name === "d") { - renderer.console.toggle() - return - } - }) - createEffect(() => { console.log(JSON.stringify(route.data)) }) @@ -310,6 +297,22 @@ function App() { onSelect: exit, category: "System", }, + { + title: "Toggle debug panel", + value: "app.debug", + onSelect: (dialog) => { + renderer.toggleDebugOverlay() + dialog.clear() + }, + }, + { + title: "Toggle console", + value: "app.fps", + onSelect: (dialog) => { + renderer.console.toggle() + dialog.clear() + }, + }, ]) createEffect(() => { From 86247b8ea96d629a5831927195c0d4a4d97b1e3d Mon Sep 17 00:00:00 2001 From: opencode Date: Thu, 6 Nov 2025 02:18:41 +0000 Subject: [PATCH 061/218] release: v1.0.33 --- bun.lock | 22 +++++++++++----------- packages/console/app/package.json | 2 +- packages/console/core/package.json | 2 +- packages/console/function/package.json | 2 +- packages/console/mail/package.json | 2 +- packages/desktop/package.json | 2 +- packages/function/package.json | 2 +- packages/opencode/package.json | 2 +- packages/plugin/package.json | 2 +- packages/sdk/js/package.json | 2 +- packages/slack/package.json | 2 +- packages/ui/package.json | 2 +- packages/web/package.json | 2 +- sdks/vscode/package.json | 2 +- 14 files changed, 24 insertions(+), 24 deletions(-) diff --git a/bun.lock b/bun.lock index ca5b62ef..d3fa9343 100644 --- a/bun.lock +++ b/bun.lock @@ -39,7 +39,7 @@ }, "packages/console/core": { "name": "@opencode-ai/console-core", - "version": "1.0.32", + "version": "1.0.33", "dependencies": { "@aws-sdk/client-sts": "3.782.0", "@jsx-email/render": "1.1.1", @@ -66,7 +66,7 @@ }, "packages/console/function": { "name": "@opencode-ai/console-function", - "version": "1.0.32", + "version": "1.0.33", "dependencies": { "@ai-sdk/anthropic": "2.0.0", "@ai-sdk/openai": "2.0.2", @@ -90,7 +90,7 @@ }, "packages/console/mail": { "name": "@opencode-ai/console-mail", - "version": "1.0.32", + "version": "1.0.33", "dependencies": { "@jsx-email/all": "2.2.3", "@jsx-email/cli": "1.4.3", @@ -111,7 +111,7 @@ }, "packages/desktop": { "name": "@opencode-ai/desktop", - "version": "1.0.32", + "version": "1.0.33", "dependencies": { "@kobalte/core": "catalog:", "@opencode-ai/sdk": "workspace:*", @@ -151,7 +151,7 @@ }, "packages/function": { "name": "@opencode-ai/function", - "version": "1.0.32", + "version": "1.0.33", "dependencies": { "@octokit/auth-app": "8.0.1", "@octokit/rest": "22.0.0", @@ -167,7 +167,7 @@ }, "packages/opencode": { "name": "opencode", - "version": "1.0.32", + "version": "1.0.33", "bin": { "opencode": "./bin/opencode", }, @@ -245,7 +245,7 @@ }, "packages/plugin": { "name": "@opencode-ai/plugin", - "version": "1.0.32", + "version": "1.0.33", "dependencies": { "@opencode-ai/sdk": "workspace:*", "zod": "catalog:", @@ -265,7 +265,7 @@ }, "packages/sdk/js": { "name": "@opencode-ai/sdk", - "version": "1.0.32", + "version": "1.0.33", "devDependencies": { "@hey-api/openapi-ts": "0.81.0", "@tsconfig/node22": "catalog:", @@ -276,7 +276,7 @@ }, "packages/slack": { "name": "@opencode-ai/slack", - "version": "1.0.32", + "version": "1.0.33", "dependencies": { "@opencode-ai/sdk": "workspace:*", "@slack/bolt": "^3.17.1", @@ -289,7 +289,7 @@ }, "packages/ui": { "name": "@opencode-ai/ui", - "version": "1.0.32", + "version": "1.0.33", "dependencies": { "@kobalte/core": "catalog:", "@opencode-ai/sdk": "workspace:*", @@ -319,7 +319,7 @@ }, "packages/web": { "name": "@opencode-ai/web", - "version": "1.0.32", + "version": "1.0.33", "dependencies": { "@astrojs/cloudflare": "12.6.3", "@astrojs/markdown-remark": "6.3.1", diff --git a/packages/console/app/package.json b/packages/console/app/package.json index 3172193f..46918335 100644 --- a/packages/console/app/package.json +++ b/packages/console/app/package.json @@ -7,7 +7,7 @@ "dev:remote": "VITE_AUTH_URL=https://auth.dev.opencode.ai bun sst shell --stage=dev bun dev", "build": "vinxi build && ../../opencode/script/schema.ts ./.output/public/config.json", "start": "vinxi start", - "version": "1.0.32" + "version": "1.0.33" }, "dependencies": { "@ibm/plex": "6.4.1", diff --git a/packages/console/core/package.json b/packages/console/core/package.json index 3f5aca73..ec8a9e91 100644 --- a/packages/console/core/package.json +++ b/packages/console/core/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@opencode-ai/console-core", - "version": "1.0.32", + "version": "1.0.33", "private": true, "type": "module", "dependencies": { diff --git a/packages/console/function/package.json b/packages/console/function/package.json index db6712c5..8fcaede9 100644 --- a/packages/console/function/package.json +++ b/packages/console/function/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/console-function", - "version": "1.0.32", + "version": "1.0.33", "$schema": "https://json.schemastore.org/package.json", "private": true, "type": "module", diff --git a/packages/console/mail/package.json b/packages/console/mail/package.json index 75d82be2..08e09bc9 100644 --- a/packages/console/mail/package.json +++ b/packages/console/mail/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/console-mail", - "version": "1.0.32", + "version": "1.0.33", "dependencies": { "@jsx-email/all": "2.2.3", "@jsx-email/cli": "1.4.3", diff --git a/packages/desktop/package.json b/packages/desktop/package.json index 4e870b99..a1352843 100644 --- a/packages/desktop/package.json +++ b/packages/desktop/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/desktop", - "version": "1.0.32", + "version": "1.0.33", "description": "", "type": "module", "scripts": { diff --git a/packages/function/package.json b/packages/function/package.json index 55996a80..b271d0e0 100644 --- a/packages/function/package.json +++ b/packages/function/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/function", - "version": "1.0.32", + "version": "1.0.33", "$schema": "https://json.schemastore.org/package.json", "private": true, "type": "module", diff --git a/packages/opencode/package.json b/packages/opencode/package.json index b292ec13..d583df4a 100644 --- a/packages/opencode/package.json +++ b/packages/opencode/package.json @@ -1,6 +1,6 @@ { "$schema": "https://json.schemastore.org/package.json", - "version": "1.0.32", + "version": "1.0.33", "name": "opencode", "type": "module", "private": true, diff --git a/packages/plugin/package.json b/packages/plugin/package.json index 6cc844b0..3a57ef85 100644 --- a/packages/plugin/package.json +++ b/packages/plugin/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@opencode-ai/plugin", - "version": "1.0.32", + "version": "1.0.33", "type": "module", "scripts": { "typecheck": "tsgo --noEmit", diff --git a/packages/sdk/js/package.json b/packages/sdk/js/package.json index 3cd80647..02b3f0bf 100644 --- a/packages/sdk/js/package.json +++ b/packages/sdk/js/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@opencode-ai/sdk", - "version": "1.0.32", + "version": "1.0.33", "type": "module", "scripts": { "typecheck": "tsgo --noEmit", diff --git a/packages/slack/package.json b/packages/slack/package.json index 8b734d17..47b661c0 100644 --- a/packages/slack/package.json +++ b/packages/slack/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/slack", - "version": "1.0.32", + "version": "1.0.33", "type": "module", "scripts": { "dev": "bun run src/index.ts", diff --git a/packages/ui/package.json b/packages/ui/package.json index 3633ea5e..a63e63d7 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/ui", - "version": "1.0.32", + "version": "1.0.33", "type": "module", "exports": { ".": "./src/components/index.ts", diff --git a/packages/web/package.json b/packages/web/package.json index a3747f39..0352ff97 100644 --- a/packages/web/package.json +++ b/packages/web/package.json @@ -1,7 +1,7 @@ { "name": "@opencode-ai/web", "type": "module", - "version": "1.0.32", + "version": "1.0.33", "scripts": { "dev": "astro dev", "dev:remote": "VITE_API_URL=https://api.opencode.ai astro dev", diff --git a/sdks/vscode/package.json b/sdks/vscode/package.json index df75dd4c..d8108acc 100644 --- a/sdks/vscode/package.json +++ b/sdks/vscode/package.json @@ -2,7 +2,7 @@ "name": "opencode", "displayName": "opencode", "description": "opencode for VS Code", - "version": "1.0.32", + "version": "1.0.33", "publisher": "sst-dev", "repository": { "type": "git", From 2cc072b3dc0a75fd01e68f0803cc3de43ee14039 Mon Sep 17 00:00:00 2001 From: Dax Raad Date: Wed, 5 Nov 2025 21:26:58 -0500 Subject: [PATCH 062/218] enable scrollbar --- packages/opencode/src/cli/cmd/tui/app.tsx | 2 ++ .../opencode/src/cli/cmd/tui/routes/session/index.tsx | 10 +++++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/packages/opencode/src/cli/cmd/tui/app.tsx b/packages/opencode/src/cli/cmd/tui/app.tsx index c382a0f1..9d30ed6d 100644 --- a/packages/opencode/src/cli/cmd/tui/app.tsx +++ b/packages/opencode/src/cli/cmd/tui/app.tsx @@ -299,6 +299,7 @@ function App() { }, { title: "Toggle debug panel", + category: "System", value: "app.debug", onSelect: (dialog) => { renderer.toggleDebugOverlay() @@ -307,6 +308,7 @@ function App() { }, { title: "Toggle console", + category: "System", value: "app.fps", onSelect: (dialog) => { renderer.console.toggle() diff --git a/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx b/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx index de8b2b89..c7c0e4a2 100644 --- a/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx +++ b/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx @@ -677,7 +677,15 @@ export function Session() { (scroll = r)} - scrollbarOptions={{ visible: false }} + scrollbarOptions={{ + trackOptions: { + backgroundColor: theme.backgroundElement, + foregroundColor: theme.primary, + }, + arrowOptions: { + foregroundColor: theme.primary, + }, + }} stickyScroll={true} stickyStart="bottom" flexGrow={1} From 11d6005b77dcf190e8a72f1beba8e89c2b397e41 Mon Sep 17 00:00:00 2001 From: Dax Raad Date: Wed, 5 Nov 2025 21:30:40 -0500 Subject: [PATCH 063/218] tui: reduce scrollbar visual prominence for less distracting interface --- packages/opencode/src/cli/cmd/tui/routes/session/index.tsx | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx b/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx index c7c0e4a2..971ed817 100644 --- a/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx +++ b/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx @@ -680,10 +680,7 @@ export function Session() { scrollbarOptions={{ trackOptions: { backgroundColor: theme.backgroundElement, - foregroundColor: theme.primary, - }, - arrowOptions: { - foregroundColor: theme.primary, + foregroundColor: theme.border, }, }} stickyScroll={true} From 7c098c8849ef25eae38219fb6effa919476e6162 Mon Sep 17 00:00:00 2001 From: opencode Date: Thu, 6 Nov 2025 02:35:17 +0000 Subject: [PATCH 064/218] release: v1.0.34 --- bun.lock | 22 +++++++++++----------- packages/console/app/package.json | 2 +- packages/console/core/package.json | 2 +- packages/console/function/package.json | 2 +- packages/console/mail/package.json | 2 +- packages/desktop/package.json | 2 +- packages/function/package.json | 2 +- packages/opencode/package.json | 2 +- packages/plugin/package.json | 2 +- packages/sdk/js/package.json | 2 +- packages/slack/package.json | 2 +- packages/ui/package.json | 2 +- packages/web/package.json | 2 +- sdks/vscode/package.json | 2 +- 14 files changed, 24 insertions(+), 24 deletions(-) diff --git a/bun.lock b/bun.lock index d3fa9343..2a2fb35b 100644 --- a/bun.lock +++ b/bun.lock @@ -39,7 +39,7 @@ }, "packages/console/core": { "name": "@opencode-ai/console-core", - "version": "1.0.33", + "version": "1.0.34", "dependencies": { "@aws-sdk/client-sts": "3.782.0", "@jsx-email/render": "1.1.1", @@ -66,7 +66,7 @@ }, "packages/console/function": { "name": "@opencode-ai/console-function", - "version": "1.0.33", + "version": "1.0.34", "dependencies": { "@ai-sdk/anthropic": "2.0.0", "@ai-sdk/openai": "2.0.2", @@ -90,7 +90,7 @@ }, "packages/console/mail": { "name": "@opencode-ai/console-mail", - "version": "1.0.33", + "version": "1.0.34", "dependencies": { "@jsx-email/all": "2.2.3", "@jsx-email/cli": "1.4.3", @@ -111,7 +111,7 @@ }, "packages/desktop": { "name": "@opencode-ai/desktop", - "version": "1.0.33", + "version": "1.0.34", "dependencies": { "@kobalte/core": "catalog:", "@opencode-ai/sdk": "workspace:*", @@ -151,7 +151,7 @@ }, "packages/function": { "name": "@opencode-ai/function", - "version": "1.0.33", + "version": "1.0.34", "dependencies": { "@octokit/auth-app": "8.0.1", "@octokit/rest": "22.0.0", @@ -167,7 +167,7 @@ }, "packages/opencode": { "name": "opencode", - "version": "1.0.33", + "version": "1.0.34", "bin": { "opencode": "./bin/opencode", }, @@ -245,7 +245,7 @@ }, "packages/plugin": { "name": "@opencode-ai/plugin", - "version": "1.0.33", + "version": "1.0.34", "dependencies": { "@opencode-ai/sdk": "workspace:*", "zod": "catalog:", @@ -265,7 +265,7 @@ }, "packages/sdk/js": { "name": "@opencode-ai/sdk", - "version": "1.0.33", + "version": "1.0.34", "devDependencies": { "@hey-api/openapi-ts": "0.81.0", "@tsconfig/node22": "catalog:", @@ -276,7 +276,7 @@ }, "packages/slack": { "name": "@opencode-ai/slack", - "version": "1.0.33", + "version": "1.0.34", "dependencies": { "@opencode-ai/sdk": "workspace:*", "@slack/bolt": "^3.17.1", @@ -289,7 +289,7 @@ }, "packages/ui": { "name": "@opencode-ai/ui", - "version": "1.0.33", + "version": "1.0.34", "dependencies": { "@kobalte/core": "catalog:", "@opencode-ai/sdk": "workspace:*", @@ -319,7 +319,7 @@ }, "packages/web": { "name": "@opencode-ai/web", - "version": "1.0.33", + "version": "1.0.34", "dependencies": { "@astrojs/cloudflare": "12.6.3", "@astrojs/markdown-remark": "6.3.1", diff --git a/packages/console/app/package.json b/packages/console/app/package.json index 46918335..6221f396 100644 --- a/packages/console/app/package.json +++ b/packages/console/app/package.json @@ -7,7 +7,7 @@ "dev:remote": "VITE_AUTH_URL=https://auth.dev.opencode.ai bun sst shell --stage=dev bun dev", "build": "vinxi build && ../../opencode/script/schema.ts ./.output/public/config.json", "start": "vinxi start", - "version": "1.0.33" + "version": "1.0.34" }, "dependencies": { "@ibm/plex": "6.4.1", diff --git a/packages/console/core/package.json b/packages/console/core/package.json index ec8a9e91..9b415ed4 100644 --- a/packages/console/core/package.json +++ b/packages/console/core/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@opencode-ai/console-core", - "version": "1.0.33", + "version": "1.0.34", "private": true, "type": "module", "dependencies": { diff --git a/packages/console/function/package.json b/packages/console/function/package.json index 8fcaede9..7b149369 100644 --- a/packages/console/function/package.json +++ b/packages/console/function/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/console-function", - "version": "1.0.33", + "version": "1.0.34", "$schema": "https://json.schemastore.org/package.json", "private": true, "type": "module", diff --git a/packages/console/mail/package.json b/packages/console/mail/package.json index 08e09bc9..55ec7aa0 100644 --- a/packages/console/mail/package.json +++ b/packages/console/mail/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/console-mail", - "version": "1.0.33", + "version": "1.0.34", "dependencies": { "@jsx-email/all": "2.2.3", "@jsx-email/cli": "1.4.3", diff --git a/packages/desktop/package.json b/packages/desktop/package.json index a1352843..eeb9b954 100644 --- a/packages/desktop/package.json +++ b/packages/desktop/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/desktop", - "version": "1.0.33", + "version": "1.0.34", "description": "", "type": "module", "scripts": { diff --git a/packages/function/package.json b/packages/function/package.json index b271d0e0..55a0eaa3 100644 --- a/packages/function/package.json +++ b/packages/function/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/function", - "version": "1.0.33", + "version": "1.0.34", "$schema": "https://json.schemastore.org/package.json", "private": true, "type": "module", diff --git a/packages/opencode/package.json b/packages/opencode/package.json index d583df4a..283ee35e 100644 --- a/packages/opencode/package.json +++ b/packages/opencode/package.json @@ -1,6 +1,6 @@ { "$schema": "https://json.schemastore.org/package.json", - "version": "1.0.33", + "version": "1.0.34", "name": "opencode", "type": "module", "private": true, diff --git a/packages/plugin/package.json b/packages/plugin/package.json index 3a57ef85..93cd51f7 100644 --- a/packages/plugin/package.json +++ b/packages/plugin/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@opencode-ai/plugin", - "version": "1.0.33", + "version": "1.0.34", "type": "module", "scripts": { "typecheck": "tsgo --noEmit", diff --git a/packages/sdk/js/package.json b/packages/sdk/js/package.json index 02b3f0bf..c77789e1 100644 --- a/packages/sdk/js/package.json +++ b/packages/sdk/js/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@opencode-ai/sdk", - "version": "1.0.33", + "version": "1.0.34", "type": "module", "scripts": { "typecheck": "tsgo --noEmit", diff --git a/packages/slack/package.json b/packages/slack/package.json index 47b661c0..4284981e 100644 --- a/packages/slack/package.json +++ b/packages/slack/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/slack", - "version": "1.0.33", + "version": "1.0.34", "type": "module", "scripts": { "dev": "bun run src/index.ts", diff --git a/packages/ui/package.json b/packages/ui/package.json index a63e63d7..a5caadeb 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/ui", - "version": "1.0.33", + "version": "1.0.34", "type": "module", "exports": { ".": "./src/components/index.ts", diff --git a/packages/web/package.json b/packages/web/package.json index 0352ff97..e0f30c30 100644 --- a/packages/web/package.json +++ b/packages/web/package.json @@ -1,7 +1,7 @@ { "name": "@opencode-ai/web", "type": "module", - "version": "1.0.33", + "version": "1.0.34", "scripts": { "dev": "astro dev", "dev:remote": "VITE_API_URL=https://api.opencode.ai astro dev", diff --git a/sdks/vscode/package.json b/sdks/vscode/package.json index d8108acc..f114e1a6 100644 --- a/sdks/vscode/package.json +++ b/sdks/vscode/package.json @@ -2,7 +2,7 @@ "name": "opencode", "displayName": "opencode", "description": "opencode for VS Code", - "version": "1.0.33", + "version": "1.0.34", "publisher": "sst-dev", "repository": { "type": "git", From afe85089490032cc00161e35c6eff210f3fa10db Mon Sep 17 00:00:00 2001 From: Dax Raad Date: Thu, 6 Nov 2025 00:37:44 -0500 Subject: [PATCH 065/218] fix homebrew upgrade --- packages/opencode/src/installation/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/opencode/src/installation/index.ts b/packages/opencode/src/installation/index.ts index 323810e3..f4209e5b 100644 --- a/packages/opencode/src/installation/index.ts +++ b/packages/opencode/src/installation/index.ts @@ -132,6 +132,7 @@ export namespace Installation { const formula = await getBrewFormula() cmd = $`brew install ${formula}`.env({ HOMEBREW_NO_AUTO_UPDATE: "1", + ...process.env, }) break } From cc6d5c8ddd94e5d831ac89f0564b0582cdaad2bc Mon Sep 17 00:00:00 2001 From: opencode Date: Thu, 6 Nov 2025 05:42:24 +0000 Subject: [PATCH 066/218] release: v1.0.35 --- bun.lock | 22 +++++++++++----------- packages/console/app/package.json | 2 +- packages/console/core/package.json | 2 +- packages/console/function/package.json | 2 +- packages/console/mail/package.json | 2 +- packages/desktop/package.json | 2 +- packages/function/package.json | 2 +- packages/opencode/package.json | 2 +- packages/plugin/package.json | 2 +- packages/sdk/js/package.json | 2 +- packages/slack/package.json | 2 +- packages/ui/package.json | 2 +- packages/web/package.json | 2 +- sdks/vscode/package.json | 2 +- 14 files changed, 24 insertions(+), 24 deletions(-) diff --git a/bun.lock b/bun.lock index 2a2fb35b..a49f0093 100644 --- a/bun.lock +++ b/bun.lock @@ -39,7 +39,7 @@ }, "packages/console/core": { "name": "@opencode-ai/console-core", - "version": "1.0.34", + "version": "1.0.35", "dependencies": { "@aws-sdk/client-sts": "3.782.0", "@jsx-email/render": "1.1.1", @@ -66,7 +66,7 @@ }, "packages/console/function": { "name": "@opencode-ai/console-function", - "version": "1.0.34", + "version": "1.0.35", "dependencies": { "@ai-sdk/anthropic": "2.0.0", "@ai-sdk/openai": "2.0.2", @@ -90,7 +90,7 @@ }, "packages/console/mail": { "name": "@opencode-ai/console-mail", - "version": "1.0.34", + "version": "1.0.35", "dependencies": { "@jsx-email/all": "2.2.3", "@jsx-email/cli": "1.4.3", @@ -111,7 +111,7 @@ }, "packages/desktop": { "name": "@opencode-ai/desktop", - "version": "1.0.34", + "version": "1.0.35", "dependencies": { "@kobalte/core": "catalog:", "@opencode-ai/sdk": "workspace:*", @@ -151,7 +151,7 @@ }, "packages/function": { "name": "@opencode-ai/function", - "version": "1.0.34", + "version": "1.0.35", "dependencies": { "@octokit/auth-app": "8.0.1", "@octokit/rest": "22.0.0", @@ -167,7 +167,7 @@ }, "packages/opencode": { "name": "opencode", - "version": "1.0.34", + "version": "1.0.35", "bin": { "opencode": "./bin/opencode", }, @@ -245,7 +245,7 @@ }, "packages/plugin": { "name": "@opencode-ai/plugin", - "version": "1.0.34", + "version": "1.0.35", "dependencies": { "@opencode-ai/sdk": "workspace:*", "zod": "catalog:", @@ -265,7 +265,7 @@ }, "packages/sdk/js": { "name": "@opencode-ai/sdk", - "version": "1.0.34", + "version": "1.0.35", "devDependencies": { "@hey-api/openapi-ts": "0.81.0", "@tsconfig/node22": "catalog:", @@ -276,7 +276,7 @@ }, "packages/slack": { "name": "@opencode-ai/slack", - "version": "1.0.34", + "version": "1.0.35", "dependencies": { "@opencode-ai/sdk": "workspace:*", "@slack/bolt": "^3.17.1", @@ -289,7 +289,7 @@ }, "packages/ui": { "name": "@opencode-ai/ui", - "version": "1.0.34", + "version": "1.0.35", "dependencies": { "@kobalte/core": "catalog:", "@opencode-ai/sdk": "workspace:*", @@ -319,7 +319,7 @@ }, "packages/web": { "name": "@opencode-ai/web", - "version": "1.0.34", + "version": "1.0.35", "dependencies": { "@astrojs/cloudflare": "12.6.3", "@astrojs/markdown-remark": "6.3.1", diff --git a/packages/console/app/package.json b/packages/console/app/package.json index 6221f396..457a823d 100644 --- a/packages/console/app/package.json +++ b/packages/console/app/package.json @@ -7,7 +7,7 @@ "dev:remote": "VITE_AUTH_URL=https://auth.dev.opencode.ai bun sst shell --stage=dev bun dev", "build": "vinxi build && ../../opencode/script/schema.ts ./.output/public/config.json", "start": "vinxi start", - "version": "1.0.34" + "version": "1.0.35" }, "dependencies": { "@ibm/plex": "6.4.1", diff --git a/packages/console/core/package.json b/packages/console/core/package.json index 9b415ed4..fe2fde6f 100644 --- a/packages/console/core/package.json +++ b/packages/console/core/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@opencode-ai/console-core", - "version": "1.0.34", + "version": "1.0.35", "private": true, "type": "module", "dependencies": { diff --git a/packages/console/function/package.json b/packages/console/function/package.json index 7b149369..ab270d54 100644 --- a/packages/console/function/package.json +++ b/packages/console/function/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/console-function", - "version": "1.0.34", + "version": "1.0.35", "$schema": "https://json.schemastore.org/package.json", "private": true, "type": "module", diff --git a/packages/console/mail/package.json b/packages/console/mail/package.json index 55ec7aa0..131b9145 100644 --- a/packages/console/mail/package.json +++ b/packages/console/mail/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/console-mail", - "version": "1.0.34", + "version": "1.0.35", "dependencies": { "@jsx-email/all": "2.2.3", "@jsx-email/cli": "1.4.3", diff --git a/packages/desktop/package.json b/packages/desktop/package.json index eeb9b954..b7183d67 100644 --- a/packages/desktop/package.json +++ b/packages/desktop/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/desktop", - "version": "1.0.34", + "version": "1.0.35", "description": "", "type": "module", "scripts": { diff --git a/packages/function/package.json b/packages/function/package.json index 55a0eaa3..ca92e33d 100644 --- a/packages/function/package.json +++ b/packages/function/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/function", - "version": "1.0.34", + "version": "1.0.35", "$schema": "https://json.schemastore.org/package.json", "private": true, "type": "module", diff --git a/packages/opencode/package.json b/packages/opencode/package.json index 283ee35e..c396d5c0 100644 --- a/packages/opencode/package.json +++ b/packages/opencode/package.json @@ -1,6 +1,6 @@ { "$schema": "https://json.schemastore.org/package.json", - "version": "1.0.34", + "version": "1.0.35", "name": "opencode", "type": "module", "private": true, diff --git a/packages/plugin/package.json b/packages/plugin/package.json index 93cd51f7..c510b519 100644 --- a/packages/plugin/package.json +++ b/packages/plugin/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@opencode-ai/plugin", - "version": "1.0.34", + "version": "1.0.35", "type": "module", "scripts": { "typecheck": "tsgo --noEmit", diff --git a/packages/sdk/js/package.json b/packages/sdk/js/package.json index c77789e1..97830ba1 100644 --- a/packages/sdk/js/package.json +++ b/packages/sdk/js/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@opencode-ai/sdk", - "version": "1.0.34", + "version": "1.0.35", "type": "module", "scripts": { "typecheck": "tsgo --noEmit", diff --git a/packages/slack/package.json b/packages/slack/package.json index 4284981e..543f1bbc 100644 --- a/packages/slack/package.json +++ b/packages/slack/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/slack", - "version": "1.0.34", + "version": "1.0.35", "type": "module", "scripts": { "dev": "bun run src/index.ts", diff --git a/packages/ui/package.json b/packages/ui/package.json index a5caadeb..d1889af6 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/ui", - "version": "1.0.34", + "version": "1.0.35", "type": "module", "exports": { ".": "./src/components/index.ts", diff --git a/packages/web/package.json b/packages/web/package.json index e0f30c30..df95ff76 100644 --- a/packages/web/package.json +++ b/packages/web/package.json @@ -1,7 +1,7 @@ { "name": "@opencode-ai/web", "type": "module", - "version": "1.0.34", + "version": "1.0.35", "scripts": { "dev": "astro dev", "dev:remote": "VITE_API_URL=https://api.opencode.ai astro dev", diff --git a/sdks/vscode/package.json b/sdks/vscode/package.json index f114e1a6..fd516fb1 100644 --- a/sdks/vscode/package.json +++ b/sdks/vscode/package.json @@ -2,7 +2,7 @@ "name": "opencode", "displayName": "opencode", "description": "opencode for VS Code", - "version": "1.0.34", + "version": "1.0.35", "publisher": "sst-dev", "repository": { "type": "git", From e52bfab79db9ab064ebfd2620d7bba32db23a460 Mon Sep 17 00:00:00 2001 From: Frank Date: Thu, 6 Nov 2025 00:37:16 -0500 Subject: [PATCH 067/218] Update sst --- bun.lock | 20 ++++++++++---------- package.json | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/bun.lock b/bun.lock index a49f0093..8dd6cae2 100644 --- a/bun.lock +++ b/bun.lock @@ -11,7 +11,7 @@ "@tsconfig/bun": "catalog:", "husky": "9.1.7", "prettier": "3.6.2", - "sst": "3.17.19", + "sst": "3.17.22", "turbo": "2.5.6", }, }, @@ -3178,23 +3178,23 @@ "sqlstring": ["sqlstring@2.3.3", "", {}, "sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg=="], - "sst": ["sst@3.17.19", "", { "dependencies": { "aws-sdk": "2.1692.0", "aws4fetch": "1.0.18", "jose": "5.2.3", "opencontrol": "0.0.6", "openid-client": "5.6.4" }, "optionalDependencies": { "sst-darwin-arm64": "3.17.19", "sst-darwin-x64": "3.17.19", "sst-linux-arm64": "3.17.19", "sst-linux-x64": "3.17.19", "sst-linux-x86": "3.17.19", "sst-win32-arm64": "3.17.19", "sst-win32-x64": "3.17.19", "sst-win32-x86": "3.17.19" }, "bin": { "sst": "bin/sst.mjs" } }, "sha512-j0FlQhFZW+QWCczzqfPr6fZAF0Um7lP1tbGdd7zkbjFlxdk9BUBI4CYXUnopC6KaTMtjvpfg3XRF7v0bDc9g+A=="], + "sst": ["sst@3.17.22", "", { "dependencies": { "aws-sdk": "2.1692.0", "aws4fetch": "1.0.18", "jose": "5.2.3", "opencontrol": "0.0.6", "openid-client": "5.6.4" }, "optionalDependencies": { "sst-darwin-arm64": "3.17.22", "sst-darwin-x64": "3.17.22", "sst-linux-arm64": "3.17.22", "sst-linux-x64": "3.17.22", "sst-linux-x86": "3.17.22", "sst-win32-arm64": "3.17.22", "sst-win32-x64": "3.17.22", "sst-win32-x86": "3.17.22" }, "bin": { "sst": "bin/sst.mjs" } }, "sha512-C+XMTbm6fx+7eT+ESAMATqG7qV7+pyVfxYQb6osdH3jd4u91QW1VU/xlEru+RU1rs1ZE58ixXdRP75UGPn+gog=="], - "sst-darwin-arm64": ["sst-darwin-arm64@3.17.19", "", { "os": "darwin", "cpu": "arm64" }, "sha512-6FeEgPqXkRT3o5qV0xktJ1eUiscJiPLBcGaxOxIEClpkVggZM83hO7Nizx/cAaAMhr1XQhbOZcKYueDHPdUY+Q=="], + "sst-darwin-arm64": ["sst-darwin-arm64@3.17.22", "", { "os": "darwin", "cpu": "arm64" }, "sha512-B2pKq1dWc60+7HfXQ6/9etskxxNv9axxlQKveCLQAuG2a3mmtv2/jcR0Ch3mvSTGtW+KfhzUXda2kj7nZ/phBA=="], - "sst-darwin-x64": ["sst-darwin-x64@3.17.19", "", { "os": "darwin", "cpu": "x64" }, "sha512-/z78dxfLHG8FtOhpjMnYSpKSdQjfdyKbq+cL3eud2+g2BQr7IyQ8BWNGimk2oadh38V3r6dO1/5aVJh3x3l1rg=="], + "sst-darwin-x64": ["sst-darwin-x64@3.17.22", "", { "os": "darwin", "cpu": "x64" }, "sha512-flikYqXvhwwrS6x2FDOde+MQODHaZCIbUkVHYO3/gYo99rbAMQ8VpC/3LXnmnPEQkLOwWCSzLp4S4F9nG/PW2g=="], - "sst-linux-arm64": ["sst-linux-arm64@3.17.19", "", { "os": "linux", "cpu": "arm64" }, "sha512-vbcMjiuLVxZ7352ajGlMqsS4J5AkAYvjLmsEALySUBVQhJUO9U7pk2P+Orfn702ZcO+6+NkGG9AL/g3K9EM1Tg=="], + "sst-linux-arm64": ["sst-linux-arm64@3.17.22", "", { "os": "linux", "cpu": "arm64" }, "sha512-+pyD8Oej9js8XeCCebiEIde02vC5hc+bLl2/jR02K+9gYkGVJ6n5bkT8AlR8zWdS4FJKPyeJYUfjliT1T33j+g=="], - "sst-linux-x64": ["sst-linux-x64@3.17.19", "", { "os": "linux", "cpu": "x64" }, "sha512-gkNNmuHyvKjcb7RwMyoUH4wtgd7/bH7vUlMbcVsDzwt38y7+iTxyPMbcihucw42wDQRaDJtkDneSqj08U+MTFQ=="], + "sst-linux-x64": ["sst-linux-x64@3.17.22", "", { "os": "linux", "cpu": "x64" }, "sha512-A5p941edP9wgfgsbLUMeEPvi9JExj0OSaxgtFAC6/6BYoW4zruGAPzq206Ln6dNYP3gRdo5TJbSjio3F0ot8qg=="], - "sst-linux-x86": ["sst-linux-x86@3.17.19", "", { "os": "linux", "cpu": "none" }, "sha512-Bsvunkh4onZRVv4Rxq7bT/63qQOg2KJoQKhAQtFkJdbri/cOA2QWkzqH8+pC5Sv9rSvbcIJAEIhMXILC0pqCJw=="], + "sst-linux-x86": ["sst-linux-x86@3.17.22", "", { "os": "linux", "cpu": "none" }, "sha512-pFDIi+ZwH8GOvy5He9wsbAjRGf/sTGhGE/V480w0A6itb9BC4jQ9sblJkk3Jx/fP2g27pKN2RNz+ifOU+GrUYQ=="], - "sst-win32-arm64": ["sst-win32-arm64@3.17.19", "", { "os": "win32", "cpu": "arm64" }, "sha512-dKxR4v24AODJLHiT9yNena0JUgyz3cHyCi6HZyxyG3dXyWncMe1ZXMXIgs1ZEUcU4XeYM2HVy+Nnz4KB1US1Kg=="], + "sst-win32-arm64": ["sst-win32-arm64@3.17.22", "", { "os": "win32", "cpu": "arm64" }, "sha512-9KaIrk+Z6hLDNi9GShf9NLrZi9jC/NNGpUAn6HvTXr8c6HUyQzg6takMH8nrISGCPn92y+IYWqdglaqbgnJTog=="], - "sst-win32-x64": ["sst-win32-x64@3.17.19", "", { "os": "win32", "cpu": "x64" }, "sha512-zgxSkGWZ1dewAr4R3slN/d3X9yumQDvAUOlJiX/6QE9Z67t/XNlow4+5i3L2oz4WHAFi59Un12YxbfM+RsBDmA=="], + "sst-win32-x64": ["sst-win32-x64@3.17.22", "", { "os": "win32", "cpu": "x64" }, "sha512-cvzyet4octGHK7w05jPUSPmUdlAWyh8IzjB8Pcs873K9AUGJEtQCftOKZjXaFdIG9DTvFWCCBi9zdzClxT9jJg=="], - "sst-win32-x86": ["sst-win32-x86@3.17.19", "", { "os": "win32", "cpu": "none" }, "sha512-z8S0kyb0ibz9Q3cNYDpcKYX47jys7j/mdebC8HUhtED1qKEAfqQ1vsR+zvWyN64Z9Ijj7aPi1KwNV6Et3d7F8g=="], + "sst-win32-x86": ["sst-win32-x86@3.17.22", "", { "os": "win32", "cpu": "none" }, "sha512-ol5icDJuHzG+AjbGbCIQoF8z3oiikTF9CtccdK/udqEF861DnngWzM99IY5TJvmJlN+38yOV0MY4XI5hM6SEQA=="], "stackframe": ["stackframe@1.3.4", "", {}, "sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw=="], diff --git a/package.json b/package.json index de6c62a5..e0bf476c 100644 --- a/package.json +++ b/package.json @@ -52,7 +52,7 @@ "@tsconfig/bun": "catalog:", "husky": "9.1.7", "prettier": "3.6.2", - "sst": "3.17.19", + "sst": "3.17.22", "turbo": "2.5.6" }, "dependencies": { From 49e4cfb286858a80ce8227ec4387b71a9f172777 Mon Sep 17 00:00:00 2001 From: "opencode-agent[bot]" <219766164+opencode-agent[bot]@users.noreply.github.com> Date: Thu, 6 Nov 2025 01:09:59 -0600 Subject: [PATCH 068/218] =?UTF-8?q?Added=20big=20dot=20(=E2=97=8F)=20indic?= =?UTF-8?q?ator=20for=20current=20session=20in=20modal=20(#3980)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: opencode-agent[bot] Co-authored-by: rekram1-node Co-authored-by: Aiden Cline --- .../src/cli/cmd/tui/component/dialog-session-list.tsx | 5 +++++ packages/opencode/src/cli/cmd/tui/ui/dialog-select.tsx | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/packages/opencode/src/cli/cmd/tui/component/dialog-session-list.tsx b/packages/opencode/src/cli/cmd/tui/component/dialog-session-list.tsx index 4a720aa1..95792ad8 100644 --- a/packages/opencode/src/cli/cmd/tui/component/dialog-session-list.tsx +++ b/packages/opencode/src/cli/cmd/tui/component/dialog-session-list.tsx @@ -20,6 +20,10 @@ export function DialogSessionList() { const deleteKeybind = "ctrl+d" + const currentSessionID = createMemo(() => + route.data.type === "session" ? route.data.sessionID : undefined + ) + const options = createMemo(() => { const today = new Date().toDateString() return sync.data.session @@ -50,6 +54,7 @@ export function DialogSessionList() { title="Sessions" options={options()} limit={50} + current={currentSessionID()} onMove={() => { setToDelete(undefined) }} diff --git a/packages/opencode/src/cli/cmd/tui/ui/dialog-select.tsx b/packages/opencode/src/cli/cmd/tui/ui/dialog-select.tsx index 1c37b981..6dd0b5cd 100644 --- a/packages/opencode/src/cli/cmd/tui/ui/dialog-select.tsx +++ b/packages/opencode/src/cli/cmd/tui/ui/dialog-select.tsx @@ -273,6 +273,11 @@ function Option(props: { const { theme } = useTheme() return ( <> + + + ● + + Date: Thu, 6 Nov 2025 12:04:56 +0000 Subject: [PATCH 069/218] ignore: update download stats 2025-11-06 --- STATS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/STATS.md b/STATS.md index 28a0e3da..56d6d39f 100644 --- a/STATS.md +++ b/STATS.md @@ -131,3 +131,4 @@ | 2025-11-03 | 653,130 (+9,063) | 597,139 (+7,135) | 1,250,269 (+16,198) | | 2025-11-04 | 663,912 (+10,782) | 608,056 (+10,917) | 1,271,968 (+21,699) | | 2025-11-05 | 675,074 (+11,162) | 619,690 (+11,634) | 1,294,764 (+22,796) | +| 2025-11-06 | 686,252 (+11,178) | 630,885 (+11,195) | 1,317,137 (+22,373) | From ab345cf0dac4378163292a5fb99b102bb2922ee1 Mon Sep 17 00:00:00 2001 From: Adam <2363879+adamdotdevin@users.noreply.github.com> Date: Thu, 6 Nov 2025 06:05:08 -0600 Subject: [PATCH 070/218] feat(desktop): better tooltips --- .../desktop/src/components/prompt-input.tsx | 36 +++++++--- packages/ui/src/components/icon.tsx | 1 + packages/ui/src/components/tooltip.css | 69 ++++++++++--------- packages/ui/src/components/tooltip.tsx | 8 +-- 4 files changed, 68 insertions(+), 46 deletions(-) diff --git a/packages/desktop/src/components/prompt-input.tsx b/packages/desktop/src/components/prompt-input.tsx index 7dc67f6a..cad1f209 100644 --- a/packages/desktop/src/components/prompt-input.tsx +++ b/packages/desktop/src/components/prompt-input.tsx @@ -1,6 +1,6 @@ -import { Button, Icon, IconButton, Select, SelectDialog } from "@opencode-ai/ui" +import { Button, Icon, IconButton, Select, SelectDialog, Tooltip } from "@opencode-ai/ui" import { useFilteredList } from "@opencode-ai/ui/hooks" -import { createEffect, on, Component, Show, For, onMount, onCleanup } from "solid-js" +import { createEffect, on, Component, Show, For, onMount, onCleanup, Switch, Match } from "solid-js" import { createStore } from "solid-js/store" import { FileIcon } from "@/ui" import { getDirectory, getFilename } from "@/utils" @@ -519,12 +519,32 @@ export const PromptInput: Component = (props) => { )} - + + +
+ Stop + ESC +
+
+ +
+ Send + +
+
+ + } + > + +
diff --git a/packages/ui/src/components/icon.tsx b/packages/ui/src/components/icon.tsx index 61799720..2e96b9d8 100644 --- a/packages/ui/src/components/icon.tsx +++ b/packages/ui/src/components/icon.tsx @@ -151,6 +151,7 @@ const newIcons = { "square-arrow-top-right": ``, "circle-ban-sign": ``, stop: ``, + enter: ``, } export interface IconProps extends ComponentProps<"svg"> { diff --git a/packages/ui/src/components/tooltip.css b/packages/ui/src/components/tooltip.css index 0577365d..92825aca 100644 --- a/packages/ui/src/components/tooltip.css +++ b/packages/ui/src/components/tooltip.css @@ -6,54 +6,55 @@ [data-component="tooltip"] { z-index: 1000; max-width: 320px; - border-radius: 12px; + border-radius: 6px; background-color: var(--surface-float-base); - color: var(--white); - padding: 2px 12px 2px 12px; + color: rgba(253, 252, 252, 0.94); + padding: 2px 8px; + border: 0.5px solid rgba(253, 252, 252, 0.2); box-shadow: var(--shadow-md); pointer-events: none !important; - transition: all 150ms ease-out; - transform: translate3d(0, 0, 0); - transform-origin: var(--kb-tooltip-content-transform-origin); + /* transition: all 150ms ease-out; */ + /* transform: translate3d(0, 0, 0); */ + /* transform-origin: var(--kb-tooltip-content-transform-origin); */ - /* text-14-regular */ + /* text-12-medium */ font-family: var(--font-family-sans); - font-size: var(--font-size-base); + font-size: var(--font-size-small); font-style: normal; - font-weight: var(--font-weight-regular); - line-height: var(--line-height-large); /* 171.429% */ + font-weight: var(--font-weight-medium); + line-height: var(--line-height-large); /* 166.667% */ letter-spacing: var(--letter-spacing-normal); &[data-expanded] { opacity: 1; - transform: translate3d(0, 0, 0); + /* transform: translate3d(0, 0, 0); */ } &[data-closed] { opacity: 0; } - &[data-placement="top"] { - &[data-closed] { - transform: translate3d(0, 4px, 0); - } - } - - &[data-placement="bottom"] { - &[data-closed] { - transform: translate3d(0, -4px, 0); - } - } - - &[data-placement="left"] { - &[data-closed] { - transform: translate3d(4px, 0, 0); - } - } - - &[data-placement="right"] { - &[data-closed] { - transform: translate3d(-4px, 0, 0); - } - } + /* &[data-placement="top"] { */ + /* &[data-closed] { */ + /* transform: translate3d(0, 4px, 0); */ + /* } */ + /* } */ + /**/ + /* &[data-placement="bottom"] { */ + /* &[data-closed] { */ + /* transform: translate3d(0, -4px, 0); */ + /* } */ + /* } */ + /**/ + /* &[data-placement="left"] { */ + /* &[data-closed] { */ + /* transform: translate3d(4px, 0, 0); */ + /* } */ + /* } */ + /**/ + /* &[data-placement="right"] { */ + /* &[data-closed] { */ + /* transform: translate3d(-4px, 0, 0); */ + /* } */ + /* } */ } diff --git a/packages/ui/src/components/tooltip.tsx b/packages/ui/src/components/tooltip.tsx index ff13c8d6..c3d1947d 100644 --- a/packages/ui/src/components/tooltip.tsx +++ b/packages/ui/src/components/tooltip.tsx @@ -1,9 +1,9 @@ import { Tooltip as KobalteTooltip } from "@kobalte/core/tooltip" -import { children, createEffect, createSignal, splitProps } from "solid-js" +import { children, createEffect, createSignal, splitProps, type JSX } from "solid-js" import type { ComponentProps } from "solid-js" export interface TooltipProps extends ComponentProps { - value: string | (() => string) + value: JSX.Element class?: string } @@ -29,13 +29,13 @@ export function Tooltip(props: TooltipProps) { }) return ( - + {c()} - {typeof others.value === "function" ? others.value() : others.value} + {others.value} {/* */} From 146bae82cb584c253a42ed4565d423d9cded93a6 Mon Sep 17 00:00:00 2001 From: Adam <2363879+adamdotdevin@users.noreply.github.com> Date: Thu, 6 Nov 2025 06:24:39 -0600 Subject: [PATCH 071/218] fix(desktop): button styles --- packages/desktop/src/pages/layout.tsx | 9 +++------ packages/ui/src/components/button.css | 8 +++----- 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/packages/desktop/src/pages/layout.tsx b/packages/desktop/src/pages/layout.tsx index 1d966960..85f55e8b 100644 --- a/packages/desktop/src/pages/layout.tsx +++ b/packages/desktop/src/pages/layout.tsx @@ -3,7 +3,6 @@ import { createMemo, For, ParentProps, Show } from "solid-js" import { getFilename } from "@/utils" import { DateTime } from "luxon" import { useSync } from "@/context/sync" -import { VList } from "virtua/solid" import { A, useParams } from "@solidjs/router" export default function Layout(props: ParentProps) { @@ -19,11 +18,9 @@ export default function Layout(props: ParentProps) { {getFilename(sync.data.path.directory)}
- - - +
diff --git a/packages/desktop/src/context/local.tsx b/packages/desktop/src/context/local.tsx index cef6c555..9dacc710 100644 --- a/packages/desktop/src/context/local.tsx +++ b/packages/desktop/src/context/local.tsx @@ -5,6 +5,7 @@ import type { FileContent, FileNode, Model, Provider, File as FileStatus } from import { createSimpleContext } from "./helper" import { useSDK } from "./sdk" import { useSync } from "./sync" +import { makePersisted } from "@solid-primitives/storage" export type LocalFile = FileNode & Partial<{ @@ -456,11 +457,45 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({ } })() + const layout = (() => { + const [store, setStore] = makePersisted( + createStore({ + sidebar: { + opened: true, + width: 240, + }, + }), + { + name: "layout", + }, + ) + + return { + sidebar: { + opened: createMemo(() => store.sidebar.opened), + open() { + setStore("sidebar", "opened", true) + }, + close() { + setStore("sidebar", "opened", false) + }, + toggle() { + setStore("sidebar", "opened", (x) => !x) + }, + width: createMemo(() => store.sidebar.width), + resize(width: number) { + setStore("sidebar", "width", width) + }, + }, + } + })() + const result = { model, agent, file, context, + layout, } return result }, diff --git a/packages/desktop/src/pages/layout.tsx b/packages/desktop/src/pages/layout.tsx index 85f55e8b..e1560acc 100644 --- a/packages/desktop/src/pages/layout.tsx +++ b/packages/desktop/src/pages/layout.tsx @@ -1,27 +1,42 @@ -import { Button, Tooltip, DiffChanges } from "@opencode-ai/ui" +import { Button, Tooltip, DiffChanges, IconButton } from "@opencode-ai/ui" import { createMemo, For, ParentProps, Show } from "solid-js" -import { getFilename } from "@/utils" import { DateTime } from "luxon" import { useSync } from "@/context/sync" import { A, useParams } from "@solidjs/router" +import { useLocal } from "@/context/local" export default function Layout(props: ParentProps) { const params = useParams() const sync = useSync() + const local = useLocal() return (
-
-
- {getFilename(sync.data.path.directory)} -
-
- -
+
+
+
+ + + +
+
+ + + + +
+ +
+ + + + +
{props.children}
diff --git a/packages/ui/src/components/button.css b/packages/ui/src/components/button.css index f5a08067..f76d7465 100644 --- a/packages/ui/src/components/button.css +++ b/packages/ui/src/components/button.css @@ -7,6 +7,7 @@ border-radius: 6px; text-decoration: none; user-select: none; + cursor: default; outline: none; &[data-variant="primary"] { @@ -93,11 +94,12 @@ gap: 8px; + /* text-12-medium */ font-family: var(--font-family-sans); - font-size: var(--font-size-base); + font-size: var(--font-size-small); font-style: normal; font-weight: var(--font-weight-medium); - line-height: var(--line-height-large); /* 171.429% */ + line-height: var(--line-height-large); /* 166.667% */ letter-spacing: var(--letter-spacing-normal); } diff --git a/packages/ui/src/components/icon-button.css b/packages/ui/src/components/icon-button.css index 6fe95fcc..a491074f 100644 --- a/packages/ui/src/components/icon-button.css +++ b/packages/ui/src/components/icon-button.css @@ -2,20 +2,11 @@ display: inline-flex; align-items: center; justify-content: center; - border-radius: 100%; + border-radius: 6px; text-decoration: none; user-select: none; aspect-ratio: 1; - - &:disabled { - background-color: var(--icon-strong-disabled); - color: var(--icon-invert-base); - cursor: not-allowed; - } - - &:focus { - outline: none; - } + flex-shrink: 0; &[data-variant="primary"] { background-color: var(--icon-strong-base); @@ -51,45 +42,62 @@ } &[data-variant="secondary"] { + border: transparent; background-color: var(--button-secondary-base); color: var(--text-strong); + box-shadow: var(--shadow-xs-border); &:hover:not(:disabled) { - background-color: var(--surface-hover); + background-color: var(--button-secondary-hover); } &:active:not(:disabled) { - background-color: var(--surface-active); + background-color: var(--button-secondary-base); } &:focus:not(:disabled) { - background-color: var(--surface-focus); + background-color: var(--button-secondary-base); + } + &:focus-visible:not(:active) { + background-color: var(--button-secondary-base); + box-shadow: var(--shadow-xs-border-focus); + } + &:focus-visible:active { + box-shadow: none; + } + + [data-slot="icon"] { + color: var(--icon-strong-base); } } &[data-variant="ghost"] { background-color: transparent; + /* color: var(--icon-base); */ [data-slot="icon"] { - color: var(--icon-weak-base); - - &:hover:not(:disabled) { - color: var(--icon-weak-hover); - } - &:active:not(:disabled) { - color: var(--icon-string-active); - } + color: var(--icon-base); } - /* color: var(--text-strong); */ - /**/ - /* &:hover:not(:disabled) { */ - /* background-color: var(--surface-hover); */ - /* } */ - /* &:active:not(:disabled) { */ - /* background-color: var(--surface-active); */ - /* } */ - /* &:focus:not(:disabled) { */ - /* background-color: var(--surface-focus); */ - /* } */ + &:hover:not(:disabled) { + background-color: var(--surface-base-hover); + + [data-slot="icon"] { + color: var(--icon-hover); + } + } + &:active:not(:disabled) { + [data-slot="icon"] { + color: var(--icon-active); + } + } + &:selected:not(:disabled) { + background-color: var(--surface-base-active); + [data-slot="icon"] { + color: var(--icon-selected); + } + } + &:focus:not(:disabled) { + background-color: var(--surface-focus); + } } &[data-size="normal"] { @@ -103,9 +111,14 @@ &[data-size="large"] { height: 32px; - padding: 0 8px 0 6px; + /* padding: 0 8px 0 6px; */ gap: 8px; + [data-slot="icon"] { + height: 16px; + width: 16px; + } + /* text-12-medium */ font-family: var(--font-family-sans); font-size: var(--font-size-small); @@ -114,4 +127,14 @@ line-height: var(--line-height-large); /* 166.667% */ letter-spacing: var(--letter-spacing-normal); } + + &:disabled { + background-color: var(--icon-strong-disabled); + color: var(--icon-invert-base); + cursor: not-allowed; + } + + &:focus { + outline: none; + } } diff --git a/packages/ui/src/components/icon-button.tsx b/packages/ui/src/components/icon-button.tsx index abc82609..fccdebd0 100644 --- a/packages/ui/src/components/icon-button.tsx +++ b/packages/ui/src/components/icon-button.tsx @@ -2,7 +2,7 @@ import { Button as Kobalte } from "@kobalte/core/button" import { type ComponentProps, splitProps } from "solid-js" import { Icon, IconProps } from "./icon" -export interface IconButtonProps { +export interface IconButtonProps extends ComponentProps { icon: IconProps["name"] size?: "normal" | "large" iconSize?: IconProps["size"] @@ -22,7 +22,11 @@ export function IconButton(props: ComponentProps<"button"> & IconButtonProps) { [split.class ?? ""]: !!split.class, }} > - + ) } diff --git a/packages/ui/src/components/icon.tsx b/packages/ui/src/components/icon.tsx index 2e96b9d8..082bbea9 100644 --- a/packages/ui/src/components/icon.tsx +++ b/packages/ui/src/components/icon.tsx @@ -152,6 +152,8 @@ const newIcons = { "circle-ban-sign": ``, stop: ``, enter: ``, + "layout-left": ``, + "speech-bubble": ``, } export interface IconProps extends ComponentProps<"svg"> { diff --git a/packages/ui/src/components/tabs.css b/packages/ui/src/components/tabs.css index 1d786fb4..67f28928 100644 --- a/packages/ui/src/components/tabs.css +++ b/packages/ui/src/components/tabs.css @@ -7,7 +7,7 @@ overflow: clip; [data-slot="list"] { - height: 40px; + height: 48px; width: 100%; position: relative; display: flex; @@ -39,7 +39,7 @@ [data-slot="trigger"] { position: relative; height: 100%; - padding: 8px 24px; + padding: 14px 24px; display: flex; align-items: center; color: var(--text-base); diff --git a/packages/web/astro.config.mjs b/packages/web/astro.config.mjs index 24987ca3..d67bebe0 100644 --- a/packages/web/astro.config.mjs +++ b/packages/web/astro.config.mjs @@ -110,6 +110,7 @@ export default defineConfig({ ], redirects: { "/discord": "https://discord.gg/opencode", + "/desktop-feedback": "https://discord.gg/h5TNnkFVNy", }, }) From 81ab127f6321e53a3d3e39fcc26c88d5443a7900 Mon Sep 17 00:00:00 2001 From: Adam <2363879+adamdotdevin@users.noreply.github.com> Date: Thu, 6 Nov 2025 09:49:39 -0600 Subject: [PATCH 073/218] fix(desktop): demo type error --- packages/ui/src/demo.tsx | 35 ++++++++++++++++++++++++++++------- 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/packages/ui/src/demo.tsx b/packages/ui/src/demo.tsx index 5893ca75..6d60c25a 100644 --- a/packages/ui/src/demo.tsx +++ b/packages/ui/src/demo.tsx @@ -126,7 +126,7 @@ const Demo: Component = () => { - `Dynamic tooltip: ${new Date().toLocaleTimeString()}`} placement="top"> +
@@ -141,7 +141,9 @@ const Demo: Component = () => { setInputValue(e.currentTarget.value)} + onInput={(e: InputEvent & { currentTarget: HTMLInputElement }) => + setInputValue(e.currentTarget.value) + } /> @@ -158,8 +160,15 @@ const Demo: Component = () => { checked={checked()} onChange={setChecked} /> - - + + { Example Dialog - This is an example dialog with a title and description. -
+ + This is an example dialog with a title and description. + +
@@ -249,7 +267,10 @@ const Demo: Component = () => {
-

Kobalte is a UI toolkit for building accessible web apps and design systems with SolidJS.

+

+ Kobalte is a UI toolkit for building accessible web apps and design systems with + SolidJS. +

From 492bf51a0dfa4fd278337b6e75da807048d44ff1 Mon Sep 17 00:00:00 2001 From: Adam <2363879+adamdotdevin@users.noreply.github.com> Date: Thu, 6 Nov 2025 09:56:46 -0600 Subject: [PATCH 074/218] fix(desktop): sidebar collapsed width --- packages/desktop/src/pages/layout.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/desktop/src/pages/layout.tsx b/packages/desktop/src/pages/layout.tsx index e1560acc..c5957a2d 100644 --- a/packages/desktop/src/pages/layout.tsx +++ b/packages/desktop/src/pages/layout.tsx @@ -16,7 +16,7 @@ export default function Layout(props: ParentProps) {
Date: Thu, 6 Nov 2025 11:25:37 -0500 Subject: [PATCH 075/218] fix undo command breaking other commands --- .../opencode/src/cli/cmd/tui/component/prompt/autocomplete.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/opencode/src/cli/cmd/tui/component/prompt/autocomplete.tsx b/packages/opencode/src/cli/cmd/tui/component/prompt/autocomplete.tsx index f40d4036..88ca3242 100644 --- a/packages/opencode/src/cli/cmd/tui/component/prompt/autocomplete.tsx +++ b/packages/opencode/src/cli/cmd/tui/component/prompt/autocomplete.tsx @@ -210,7 +210,6 @@ export function Autocomplete(props: { display: "/undo", description: "undo the last message", onSelect: () => { - hide() command.trigger("session.undo") }, }, @@ -374,7 +373,7 @@ export function Autocomplete(props: { function hide() { const text = props.input().plainText - if (store.visible === "/" && !text.endsWith(" ")) { + if (store.visible === "/" && !text.endsWith(" ") && text.startsWith("/")) { const cursor = props.input().logicalCursor props.input().deleteRange(0, 0, cursor.row, cursor.col) } From 065f656fb00adf9287dee38ddb13928048f56d3d Mon Sep 17 00:00:00 2001 From: Aiden Cline Date: Thu, 6 Nov 2025 10:39:32 -0600 Subject: [PATCH 076/218] chore: rm hanging test --- packages/opencode/test/tool/patch.test.ts | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/packages/opencode/test/tool/patch.test.ts b/packages/opencode/test/tool/patch.test.ts index a34d7718..78d1fecb 100644 --- a/packages/opencode/test/tool/patch.test.ts +++ b/packages/opencode/test/tool/patch.test.ts @@ -53,22 +53,6 @@ describe("tool.patch", () => { }) }) - test("should reject files outside working directory", async () => { - await Instance.provide({ - directory: "/tmp", - fn: async () => { - const maliciousPatch = `*** Begin Patch -*** Add File: /etc/passwd -+malicious content -*** End Patch` - - await expect(patchTool.execute({ patchText: maliciousPatch }, ctx)).rejects.toThrow( - "is not in the current working directory", - ) - }, - }) - }) - test("should handle simple add file operation", async () => { await using fixture = await tmpdir() From 67f3c934fec7e118de90fe845c262a4d75ce03ba Mon Sep 17 00:00:00 2001 From: Dax Raad Date: Thu, 6 Nov 2025 11:42:46 -0500 Subject: [PATCH 077/218] fix tests --- packages/opencode/src/permission/index.ts | 38 ++++++++++++++++++++--- packages/opencode/test/tool/patch.test.ts | 25 ++++++++++++--- 2 files changed, 53 insertions(+), 10 deletions(-) diff --git a/packages/opencode/src/permission/index.ts b/packages/opencode/src/permission/index.ts index eb541049..fbcda6cf 100644 --- a/packages/opencode/src/permission/index.ts +++ b/packages/opencode/src/permission/index.ts @@ -75,12 +75,23 @@ export namespace Permission { async (state) => { for (const pending of Object.values(state.pending)) { for (const item of Object.values(pending)) { - item.reject(new RejectedError(item.info.sessionID, item.info.id, item.info.callID, item.info.metadata)) + item.reject( + new RejectedError( + item.info.sessionID, + item.info.id, + item.info.callID, + item.info.metadata, + ), + ) } } }, ) + export function pending() { + return state().pending + } + export async function ask(input: { type: Info["type"] title: Info["title"] @@ -139,7 +150,11 @@ export namespace Permission { export const Response = z.enum(["once", "always", "reject"]) export type Response = z.infer - export function respond(input: { sessionID: Info["sessionID"]; permissionID: Info["id"]; response: Response }) { + export function respond(input: { + sessionID: Info["sessionID"] + permissionID: Info["id"] + response: Response + }) { log.info("response", input) const { pending, approved } = state() const match = pending[input.sessionID]?.[input.permissionID] @@ -151,7 +166,14 @@ export namespace Permission { response: input.response, }) if (input.response === "reject") { - match.reject(new RejectedError(input.sessionID, input.permissionID, match.info.callID, match.info.metadata)) + match.reject( + new RejectedError( + input.sessionID, + input.permissionID, + match.info.callID, + match.info.metadata, + ), + ) return } match.resolve() @@ -166,7 +188,11 @@ export namespace Permission { for (const item of Object.values(items)) { const itemKeys = toKeys(item.info.pattern, item.info.type) if (covered(itemKeys, approved[input.sessionID])) { - respond({ sessionID: item.info.sessionID, permissionID: item.info.id, response: input.response }) + respond({ + sessionID: item.info.sessionID, + permissionID: item.info.id, + response: input.response, + }) } } } @@ -179,7 +205,9 @@ export namespace Permission { public readonly toolCallID?: string, public readonly metadata?: Record, ) { - super(`The user rejected permission to use this specific tool call. You may try again with different parameters.`) + super( + `The user rejected permission to use this specific tool call. You may try again with different parameters.`, + ) } } } diff --git a/packages/opencode/test/tool/patch.test.ts b/packages/opencode/test/tool/patch.test.ts index 78d1fecb..141759db 100644 --- a/packages/opencode/test/tool/patch.test.ts +++ b/packages/opencode/test/tool/patch.test.ts @@ -3,6 +3,7 @@ import path from "path" import { PatchTool } from "../../src/tool/patch" import { Instance } from "../../src/project/instance" import { tmpdir } from "../fixture/fixture" +import { Permission } from "../../src/permission" import * as fs from "fs/promises" const ctx = { @@ -21,9 +22,7 @@ describe("tool.patch", () => { await Instance.provide({ directory: "/tmp", fn: async () => { - await expect(patchTool.execute({ patchText: "" }, ctx)).rejects.toThrow( - "patchText is required", - ) + expect(patchTool.execute({ patchText: "" }, ctx)).rejects.toThrow("patchText is required") }, }) }) @@ -32,7 +31,7 @@ describe("tool.patch", () => { await Instance.provide({ directory: "/tmp", fn: async () => { - await expect(patchTool.execute({ patchText: "invalid patch" }, ctx)).rejects.toThrow( + expect(patchTool.execute({ patchText: "invalid patch" }, ctx)).rejects.toThrow( "Failed to parse patch", ) }, @@ -46,13 +45,29 @@ describe("tool.patch", () => { const emptyPatch = `*** Begin Patch *** End Patch` - await expect(patchTool.execute({ patchText: emptyPatch }, ctx)).rejects.toThrow( + expect(patchTool.execute({ patchText: emptyPatch }, ctx)).rejects.toThrow( "No file changes found in patch", ) }, }) }) + test("should ask permission for files outside working directory", async () => { + await Instance.provide({ + directory: "/tmp", + fn: async () => { + const maliciousPatch = `*** Begin Patch +*** Add File: /etc/passwd ++malicious content +*** End Patch` + patchTool.execute({ patchText: maliciousPatch }, ctx) + // TODO: this sucks + await new Promise((resolve) => setTimeout(resolve, 100)) + expect(Permission.pending()[ctx.sessionID]).toBeDefined() + }, + }) + }) + test("should handle simple add file operation", async () => { await using fixture = await tmpdir() From d8bcf1f5f3923f6130cd8be02b67a565da1dfa19 Mon Sep 17 00:00:00 2001 From: Aiden Cline Date: Thu, 6 Nov 2025 11:46:42 -0600 Subject: [PATCH 078/218] ci: update auto label --- .github/workflows/auto-label-tui.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/auto-label-tui.yml b/.github/workflows/auto-label-tui.yml index 73cccf92..8f2d80b5 100644 --- a/.github/workflows/auto-label-tui.yml +++ b/.github/workflows/auto-label-tui.yml @@ -20,8 +20,8 @@ jobs: const title = issue.title; const description = issue.body || ''; - // Check for "opencode web" or desktop keywords - const webPattern = /(opencode web|\bdesktop\b)/i; + // Check for "opencode web" keyword + const webPattern = /(opencode web)/i; const isWebRelated = webPattern.test(title) || webPattern.test(description); // Check for version patterns like v1.0.x or 1.0.x From 8729edc5e059a9a29346044b016a6e05d9aca835 Mon Sep 17 00:00:00 2001 From: Aiden Cline Date: Thu, 6 Nov 2025 11:55:57 -0600 Subject: [PATCH 079/218] update import command to accept share links --- packages/opencode/src/cli/cmd/import.ts | 57 ++++++++++++++++++++++--- 1 file changed, 52 insertions(+), 5 deletions(-) diff --git a/packages/opencode/src/cli/cmd/import.ts b/packages/opencode/src/cli/cmd/import.ts index afebadc3..ef7d243f 100644 --- a/packages/opencode/src/cli/cmd/import.ts +++ b/packages/opencode/src/cli/cmd/import.ts @@ -8,26 +8,73 @@ import { EOL } from "os" export const ImportCommand = cmd({ command: "import ", - describe: "import session data from JSON file", + describe: "import session data from JSON file or URL", builder: (yargs: Argv) => { return yargs.positional("file", { - describe: "path to JSON file to import", + describe: "path to JSON file or opencode.ai share URL", type: "string", demandOption: true, }) }, handler: async (args) => { await bootstrap(process.cwd(), async () => { - const file = Bun.file(args.file) - const exportData = (await file.json().catch(() => {})) as { + let exportData: { info: Session.Info messages: Array<{ info: any parts: any[] }> + } | undefined + + const isUrl = args.file.startsWith("http://") || args.file.startsWith("https://") + + if (isUrl) { + const urlMatch = args.file.match(/https?:\/\/opencode\.ai\/s\/([a-zA-Z0-9_-]+)/) + if (!urlMatch) { + process.stdout.write(`Invalid URL format. Expected: https://opencode.ai/s/`) + process.stdout.write(EOL) + return + } + + const slug = urlMatch[1] + const response = await fetch(`https://api.opencode.ai/share_data?id=${slug}`) + + if (!response.ok) { + process.stdout.write(`Failed to fetch share data: ${response.statusText}`) + process.stdout.write(EOL) + return + } + + const data = await response.json() + + if (!data.info || !data.messages || Object.keys(data.messages).length === 0) { + process.stdout.write(`Share not found: ${slug}`) + process.stdout.write(EOL) + return + } + + exportData = { + info: data.info, + messages: Object.values(data.messages).map((msg: any) => { + const { parts, ...info } = msg + return { + info, + parts, + } + }), + } + } else { + const file = Bun.file(args.file) + exportData = await file.json().catch(() => {}) + if (!exportData) { + process.stdout.write(`File not found: ${args.file}`) + process.stdout.write(EOL) + return + } } + if (!exportData) { - process.stdout.write(`File not found: ${args.file}`) + process.stdout.write(`Failed to read session data`) process.stdout.write(EOL) return } From 1ea3a8eb9beeb7d510fd29164ea741acec1ee04d Mon Sep 17 00:00:00 2001 From: Dax Raad Date: Thu, 6 Nov 2025 13:03:02 -0500 Subject: [PATCH 080/218] big format --- AGENTS.md | 46 +- github/sst-env.d.ts | 2 +- ...2480f80fa29b850af461dce619c0b2f-audit.json | 28 +- .../console/app/src/component/dropdown.css | 2 +- packages/console/app/src/component/faq.tsx | 5 +- packages/console/app/src/component/icon.tsx | 133 +++++- packages/console/app/src/component/modal.css | 2 +- .../console/app/src/routes/auth/authorize.ts | 5 +- .../console/app/src/routes/brand/index.css | 11 +- packages/console/app/src/routes/user-menu.css | 2 +- .../app/src/routes/workspace-picker.css | 2 +- .../app/src/routes/workspace-picker.tsx | 11 +- packages/console/app/src/routes/workspace.css | 2 +- .../[id]/billing/billing-section.module.css | 2 +- .../billing/monthly-limit-section.module.css | 2 +- .../[id]/billing/payment-section.tsx | 5 +- .../[id]/billing/reload-section.module.css | 1 - .../[id]/keys/key-section.module.css | 9 +- .../workspace/[id]/keys/key-section.tsx | 10 +- .../workspace/[id]/members/member-section.tsx | 7 +- .../workspace/[id]/members/role-dropdown.css | 2 +- .../[id]/new-user-section.module.css | 2 +- .../workspace/[id]/new-user-section.tsx | 15 +- .../[id]/provider-section.module.css | 3 +- .../workspace/[id]/provider-section.tsx | 20 +- .../[id]/settings/settings-section.module.css | 6 +- packages/console/app/src/routes/zen/index.tsx | 132 ++++-- .../src/routes/zen/util/provider/anthropic.ts | 61 ++- .../zen/util/provider/openai-compatible.ts | 35 +- .../src/routes/zen/util/provider/openai.ts | 79 +++- packages/console/app/src/style/token/font.css | 3 +- packages/console/app/sst-env.d.ts | 2 +- .../core/migrations/meta/0018_snapshot.json | 57 +-- .../core/migrations/meta/0019_snapshot.json | 57 +-- .../core/migrations/meta/0020_snapshot.json | 57 +-- .../core/migrations/meta/0021_snapshot.json | 57 +-- .../core/migrations/meta/0022_snapshot.json | 62 +-- .../core/migrations/meta/0023_snapshot.json | 70 +-- .../core/migrations/meta/0024_snapshot.json | 70 +-- .../core/migrations/meta/0025_snapshot.json | 70 +-- .../core/migrations/meta/0026_snapshot.json | 65 +-- .../core/migrations/meta/0027_snapshot.json | 65 +-- .../core/migrations/meta/0028_snapshot.json | 65 +-- .../core/migrations/meta/0029_snapshot.json | 65 +-- .../core/migrations/meta/0030_snapshot.json | 75 +--- .../core/migrations/meta/0031_snapshot.json | 85 +--- .../core/migrations/meta/0032_snapshot.json | 85 +--- .../core/migrations/meta/0033_snapshot.json | 85 +--- .../core/migrations/meta/0034_snapshot.json | 90 +--- .../core/migrations/meta/0035_snapshot.json | 90 +--- .../core/migrations/meta/0036_snapshot.json | 98 +---- .../core/migrations/meta/0037_snapshot.json | 98 +---- .../core/migrations/meta/_journal.json | 2 +- packages/console/core/src/aws.ts | 53 +-- packages/console/core/src/drizzle/index.ts | 10 +- packages/console/core/src/key.ts | 10 +- packages/console/core/src/provider.ts | 11 +- packages/console/core/src/schema/auth.sql.ts | 9 +- packages/console/core/src/schema/model.sql.ts | 5 +- .../console/core/src/schema/provider.sql.ts | 5 +- packages/console/core/src/schema/user.sql.ts | 10 +- packages/console/core/src/user.ts | 28 +- packages/console/core/sst-env.d.ts | 138 +++--- packages/console/function/sst-env.d.ts | 138 +++--- .../mail/emails/templates/InviteEmail.tsx | 25 +- packages/console/mail/sst-env.d.ts | 2 +- packages/console/resource/sst-env.d.ts | 138 +++--- packages/desktop/src/sst-env.d.ts | 6 +- packages/desktop/sst-env.d.ts | 2 +- packages/function/src/api.ts | 6 +- packages/function/sst-env.d.ts | 138 +++--- packages/opencode/script/postinstall.mjs | 7 +- packages/opencode/script/schema.ts | 15 +- packages/opencode/src/agent/agent.ts | 18 +- packages/opencode/src/bus/index.ts | 10 +- packages/opencode/src/cli/cmd/auth.ts | 405 +++++++++--------- packages/opencode/src/cli/cmd/debug/lsp.ts | 6 +- .../opencode/src/cli/cmd/debug/ripgrep.ts | 7 +- .../opencode/src/cli/cmd/debug/snapshot.ts | 3 +- packages/opencode/src/cli/cmd/generate.ts | 2 +- packages/opencode/src/cli/cmd/github.ts | 60 ++- packages/opencode/src/cli/cmd/run.ts | 18 +- .../cli/cmd/tui/component/dialog-model.tsx | 6 +- .../cmd/tui/component/dialog-session-list.tsx | 4 +- .../src/cli/cmd/tui/component/logo.tsx | 14 +- .../src/cli/cmd/tui/context/route.tsx | 8 +- .../opencode/src/cli/cmd/tui/context/sync.tsx | 1 + .../cli/cmd/tui/context/theme/nightowl.json | 2 +- .../cmd/tui/routes/session/dialog-message.tsx | 4 +- .../tui/routes/session/dialog-timeline.tsx | 12 +- .../src/cli/cmd/tui/routes/session/index.tsx | 5 +- packages/opencode/src/cli/cmd/tui/spawn.ts | 7 +- .../src/cli/cmd/tui/ui/dialog-confirm.tsx | 4 +- .../opencode/src/cli/cmd/tui/util/editor.ts | 5 +- packages/opencode/src/cli/cmd/upgrade.ts | 4 +- packages/opencode/src/config/config.ts | 5 +- packages/opencode/src/file/fzf.ts | 4 +- packages/opencode/src/file/ripgrep.ts | 11 +- packages/opencode/src/file/time.ts | 5 +- packages/opencode/src/file/watcher.ts | 6 +- packages/opencode/src/id/id.ts | 6 +- packages/opencode/src/lsp/client.ts | 25 +- packages/opencode/src/patch/index.ts | 211 +++++---- packages/opencode/src/provider/transform.ts | 18 +- packages/opencode/src/server/server.ts | 2 +- packages/opencode/src/session/compaction.ts | 34 +- packages/opencode/src/session/lock.ts | 5 +- packages/opencode/src/session/message-v2.ts | 35 +- packages/opencode/src/session/message.ts | 23 +- packages/opencode/src/session/prompt.ts | 3 - packages/opencode/src/session/revert.ts | 4 +- packages/opencode/src/session/system.ts | 9 +- packages/opencode/src/session/todo.ts | 4 +- packages/opencode/src/share/share.ts | 9 +- packages/opencode/src/snapshot/index.ts | 25 +- packages/opencode/src/tool/edit.ts | 30 +- packages/opencode/src/tool/grep.ts | 10 +- packages/opencode/src/tool/ls.ts | 9 +- packages/opencode/src/tool/lsp-diagnostics.ts | 4 +- packages/opencode/src/tool/multiedit.ts | 9 +- packages/opencode/src/tool/read.ts | 12 +- packages/opencode/src/tool/registry.ts | 7 +- packages/opencode/src/tool/task.ts | 12 +- packages/opencode/src/tool/webfetch.ts | 10 +- packages/opencode/src/tool/write.ts | 8 +- packages/opencode/src/util/binary.ts | 6 +- packages/opencode/src/util/defer.ts | 4 +- packages/opencode/src/util/eventloop.ts | 10 +- packages/opencode/src/util/lock.ts | 7 +- packages/opencode/src/util/rpc.ts | 5 +- packages/opencode/src/util/wildcard.ts | 17 +- packages/opencode/sst-env.d.ts | 2 +- packages/opencode/test/patch/patch.test.ts | 139 +++--- packages/opencode/test/session/retry.test.ts | 4 +- packages/opencode/test/util/wildcard.test.ts | 13 +- packages/plugin/package.json | 2 +- packages/plugin/src/index.ts | 5 +- packages/plugin/sst-env.d.ts | 2 +- packages/script/sst-env.d.ts | 2 +- packages/sdk/go/.github/workflows/ci.yml | 14 +- packages/sdk/go/.release-please-manifest.json | 2 +- packages/sdk/go/CHANGELOG.md | 147 ++++--- packages/sdk/go/release-please-config.json | 7 +- packages/sdk/js/package.json | 2 +- packages/sdk/js/src/server.ts | 16 +- packages/sdk/js/sst-env.d.ts | 2 +- packages/sdk/python/README.md | 18 +- packages/sdk/python/docs/generation.md | 3 + packages/sdk/python/docs/index.md | 1 + packages/sdk/python/docs/installation.md | 5 + packages/sdk/python/docs/publishing.md | 3 + packages/sdk/python/docs/testing.md | 1 + packages/sdk/python/mkdocs.yml | 2 +- packages/slack/src/index.ts | 15 +- packages/slack/sst-env.d.ts | 2 +- .../ui/src/assets/favicon/site.webmanifest | 2 +- packages/ui/src/components/checkbox.tsx | 13 +- packages/ui/src/components/dialog.tsx | 6 +- packages/ui/src/styles/base.css | 4 +- packages/ui/src/styles/tailwind/colors.css | 2 +- packages/ui/src/styles/theme.css | 17 +- packages/ui/sst-env.d.ts | 2 +- packages/ui/tsconfig.json | 11 +- packages/web/config.mjs | 3 +- packages/web/src/components/Share.tsx | 46 +- packages/web/src/components/icons/index.tsx | 9 +- packages/web/src/components/share/common.tsx | 7 +- .../web/src/components/share/content-code.tsx | 6 +- .../web/src/components/share/content-diff.tsx | 20 +- .../web/src/components/share/copy-button.tsx | 6 +- packages/web/src/components/share/part.tsx | 115 ++++- packages/web/src/content/docs/1-0.mdx | 3 +- packages/web/src/content/docs/index.mdx | 24 +- packages/web/src/content/docs/permissions.mdx | 1 - packages/web/src/content/docs/rules.mdx | 6 +- .../web/src/content/docs/troubleshooting.mdx | 2 +- packages/web/src/styles/custom.css | 29 +- packages/web/sst-env.d.ts | 2 +- script/format.ts | 2 +- script/stats.ts | 14 +- sdks/vscode/src/extension.ts | 133 +++--- sdks/vscode/sst-env.d.ts | 2 +- sst-env.d.ts | 150 +++---- 183 files changed, 2629 insertions(+), 2497 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 9c6111b0..22b305da 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -21,27 +21,27 @@ json { - "recipient_name": "multi_tool_use.parallel", - "parameters": { - "tool_uses": [ - { - "recipient_name": "functions.read", - "parameters": { - "filePath": "path/to/file.tsx" - } - }, - { - "recipient_name": "functions.read", - "parameters": { - "filePath": "path/to/file.ts" - } - }, - { - "recipient_name": "functions.read", - "parameters": { - "filePath": "path/to/file.md" - } - } - ] - } +"recipient_name": "multi_tool_use.parallel", +"parameters": { +"tool_uses": [ +{ +"recipient_name": "functions.read", +"parameters": { +"filePath": "path/to/file.tsx" +} +}, +{ +"recipient_name": "functions.read", +"parameters": { +"filePath": "path/to/file.ts" +} +}, +{ +"recipient_name": "functions.read", +"parameters": { +"filePath": "path/to/file.md" +} +} +] +} } diff --git a/github/sst-env.d.ts b/github/sst-env.d.ts index f742a120..6b69016e 100644 --- a/github/sst-env.d.ts +++ b/github/sst-env.d.ts @@ -6,4 +6,4 @@ /// import "sst" -export {} \ No newline at end of file +export {} diff --git a/logs/.2c5480b3b2480f80fa29b850af461dce619c0b2f-audit.json b/logs/.2c5480b3b2480f80fa29b850af461dce619c0b2f-audit.json index 7c57ef35..41cb01a2 100644 --- a/logs/.2c5480b3b2480f80fa29b850af461dce619c0b2f-audit.json +++ b/logs/.2c5480b3b2480f80fa29b850af461dce619c0b2f-audit.json @@ -1,15 +1,15 @@ { - "keep": { - "days": true, - "amount": 14 - }, - "auditLog": "/home/thdxr/dev/projects/sst/opencode/logs/.2c5480b3b2480f80fa29b850af461dce619c0b2f-audit.json", - "files": [ - { - "date": 1759827172859, - "name": "/home/thdxr/dev/projects/sst/opencode/logs/mcp-puppeteer-2025-10-07.log", - "hash": "a3d98b26edd793411b968a0d24cfeee8332138e282023c3b83ec169d55c67f16" - } - ], - "hashType": "sha256" -} \ No newline at end of file + "keep": { + "days": true, + "amount": 14 + }, + "auditLog": "/home/thdxr/dev/projects/sst/opencode/logs/.2c5480b3b2480f80fa29b850af461dce619c0b2f-audit.json", + "files": [ + { + "date": 1759827172859, + "name": "/home/thdxr/dev/projects/sst/opencode/logs/mcp-puppeteer-2025-10-07.log", + "hash": "a3d98b26edd793411b968a0d24cfeee8332138e282023c3b83ec169d55c67f16" + } + ], + "hashType": "sha256" +} diff --git a/packages/console/app/src/component/dropdown.css b/packages/console/app/src/component/dropdown.css index 982367c6..242940e6 100644 --- a/packages/console/app/src/component/dropdown.css +++ b/packages/console/app/src/component/dropdown.css @@ -77,4 +77,4 @@ background-color: var(--color-accent-alpha); } } -} \ No newline at end of file +} diff --git a/packages/console/app/src/component/faq.tsx b/packages/console/app/src/component/faq.tsx index 753a0dce..47dca951 100644 --- a/packages/console/app/src/component/faq.tsx +++ b/packages/console/app/src/component/faq.tsx @@ -13,7 +13,10 @@ export function Faq(props: ParentProps & { question: string }) { fill="currentColor" xmlns="http://www.w3.org/2000/svg" > - + ) { - - + + - + ) { fill-opacity="0.2" /> - - + + @@ -40,9 +61,21 @@ export function IconLogo(props: JSX.SvgSVGAttributes) { - - - + + + @@ -53,16 +86,40 @@ export function IconLogo(props: JSX.SvgSVGAttributes) { - - + + - - + + - - + + ) @@ -70,7 +127,14 @@ export function IconLogo(props: JSX.SvgSVGAttributes) { export function IconCopy(props: JSX.SvgSVGAttributes) { return ( - + ) { export function IconCheck(props: JSX.SvgSVGAttributes) { return ( - - + + ) } @@ -113,7 +189,14 @@ export function IconStripe(props: JSX.SvgSVGAttributes) { export function IconChevron(props: JSX.SvgSVGAttributes) { return ( - + ) { export function IconWorkspaceLogo(props: JSX.SvgSVGAttributes) { return ( - + ) @@ -144,7 +234,10 @@ export function IconOpenAI(props: JSX.SvgSVGAttributes) { export function IconAnthropic(props: JSX.SvgSVGAttributes) { return ( - + {(workspace) => ( - handleSelectWorkspace(workspace.id)}> + handleSelectWorkspace(workspace.id)} + > {workspace.name || workspace.slug} )} @@ -95,7 +98,11 @@ export function WorkspacePicker() { - setStore("showForm", false)} title="Create New Workspace"> + setStore("showForm", false)} + title="Create New Workspace" + >
{key.email} - + {key.timeUsed ? formatDateForTable(key.timeUsed) : "-"} diff --git a/packages/console/app/src/routes/workspace/[id]/members/member-section.tsx b/packages/console/app/src/routes/workspace/[id]/members/member-section.tsx index 5aa1b969..4b2a12fd 100644 --- a/packages/console/app/src/routes/workspace/[id]/members/member-section.tsx +++ b/packages/console/app/src/routes/workspace/[id]/members/member-section.tsx @@ -85,7 +85,12 @@ const updateMember = action(async (form: FormData) => { ) }, "member.update") -function MemberRow(props: { member: any; workspaceID: string; actorID: string; actorRole: string }) { +function MemberRow(props: { + member: any + workspaceID: string + actorID: string + actorRole: string +}) { const submission = useSubmission(updateMember) const isCurrentUser = () => props.actorID === props.member.id const isAdmin = () => props.actorRole === "admin" diff --git a/packages/console/app/src/routes/workspace/[id]/members/role-dropdown.css b/packages/console/app/src/routes/workspace/[id]/members/role-dropdown.css index 29f55a97..7a64fd9c 100644 --- a/packages/console/app/src/routes/workspace/[id]/members/role-dropdown.css +++ b/packages/console/app/src/routes/workspace/[id]/members/role-dropdown.css @@ -69,4 +69,4 @@ } } } -} \ No newline at end of file +} diff --git a/packages/console/app/src/routes/workspace/[id]/new-user-section.module.css b/packages/console/app/src/routes/workspace/[id]/new-user-section.module.css index aaad823a..bb58df79 100644 --- a/packages/console/app/src/routes/workspace/[id]/new-user-section.module.css +++ b/packages/console/app/src/routes/workspace/[id]/new-user-section.module.css @@ -140,4 +140,4 @@ } } } -} \ No newline at end of file +} diff --git a/packages/console/app/src/routes/workspace/[id]/new-user-section.tsx b/packages/console/app/src/routes/workspace/[id]/new-user-section.tsx index 65edc684..7b949c66 100644 --- a/packages/console/app/src/routes/workspace/[id]/new-user-section.tsx +++ b/packages/console/app/src/routes/workspace/[id]/new-user-section.tsx @@ -43,15 +43,24 @@ export function NewUserSection() {

Tested & Verified Models

-

We've benchmarked and tested models specifically for coding agents to ensure the best performance.

+

+ We've benchmarked and tested models specifically for coding agents to ensure the best + performance. +

Highest Quality

-

Access models configured for optimal performance - no downgrades or routing to cheaper providers.

+

+ Access models configured for optimal performance - no downgrades or routing to cheaper + providers. +

No Lock-in

-

Use Zen with any coding agent, and continue using other providers with opencode whenever you want.

+

+ Use Zen with any coding agent, and continue using other providers with opencode + whenever you want. +

diff --git a/packages/console/app/src/routes/workspace/[id]/provider-section.module.css b/packages/console/app/src/routes/workspace/[id]/provider-section.module.css index 1a450d3d..1dc7085b 100644 --- a/packages/console/app/src/routes/workspace/[id]/provider-section.module.css +++ b/packages/console/app/src/routes/workspace/[id]/provider-section.module.css @@ -128,7 +128,6 @@ } @media (max-width: 40rem) { - th, td { padding: var(--space-2) var(--space-3); @@ -136,4 +135,4 @@ } } } -} \ No newline at end of file +} diff --git a/packages/console/app/src/routes/workspace/[id]/provider-section.tsx b/packages/console/app/src/routes/workspace/[id]/provider-section.tsx index 6ec8477b..67314fbd 100644 --- a/packages/console/app/src/routes/workspace/[id]/provider-section.tsx +++ b/packages/console/app/src/routes/workspace/[id]/provider-section.tsx @@ -22,7 +22,9 @@ const removeProvider = action(async (form: FormData) => { if (!provider) return { error: "Provider is required" } const workspaceID = form.get("workspaceID")?.toString() if (!workspaceID) return { error: "Workspace ID is required" } - return json(await withActor(() => Provider.remove({ provider }), workspaceID), { revalidate: listProviders.key }) + return json(await withActor(() => Provider.remove({ provider }), workspaceID), { + revalidate: listProviders.key, + }) }, "provider.remove") const saveProvider = action(async (form: FormData) => { @@ -53,7 +55,10 @@ const listProviders = query(async (workspaceID: string) => { function ProviderRow(props: { provider: Provider }) { const params = useParams() const providers = createAsync(() => listProviders(params.id)) - const saveSubmission = useSubmission(saveProvider, ([fd]) => fd.get("provider")?.toString() === props.provider.key) + const saveSubmission = useSubmission( + saveProvider, + ([fd]) => fd.get("provider")?.toString() === props.provider.key, + ) const removeSubmission = useSubmission( removeProvider, ([fd]) => fd.get("provider")?.toString() === props.provider.key, @@ -89,9 +94,16 @@ function ProviderRow(props: { provider: Provider }) { {providerData() ? maskCredentials(providerData()!.credentials) : "-"}} + fallback={ + {providerData() ? maskCredentials(providerData()!.credentials) : "-"} + } > -
+
(input = r)} diff --git a/packages/console/app/src/routes/workspace/[id]/settings/settings-section.module.css b/packages/console/app/src/routes/workspace/[id]/settings/settings-section.module.css index 058fbe30..6764a053 100644 --- a/packages/console/app/src/routes/workspace/[id]/settings/settings-section.module.css +++ b/packages/console/app/src/routes/workspace/[id]/settings/settings-section.module.css @@ -31,7 +31,7 @@ margin: 0; } - >button { + > button { align-self: flex-start; } } @@ -80,7 +80,7 @@ } } - >button[type="reset"] { + > button[type="reset"] { align-self: flex-start; } @@ -91,4 +91,4 @@ margin-top: calc(var(--space-1) * -1); } } -} \ No newline at end of file +} diff --git a/packages/console/app/src/routes/zen/index.tsx b/packages/console/app/src/routes/zen/index.tsx index 08e58e16..92cc0a50 100644 --- a/packages/console/app/src/routes/zen/index.tsx +++ b/packages/console/app/src/routes/zen/index.tsx @@ -28,7 +28,10 @@ export default function Home() { createAsync(() => checkLoggedIn()) return (
- + OpenCode Zen | A curated set of reliable optimized models for coding agents @@ -44,13 +47,19 @@ export default function Home() { zen logo dark Reliable optimized models for coding agents

- Zen gives you access to a curated set of AI models that OpenCode has tested and benchmarked specifically - for coding agents. No need to worry about inconsistent performance and quality, use validated models - that work. + Zen gives you access to a curated set of AI models that OpenCode has tested and + benchmarked specifically for coding agents. No need to worry about inconsistent + performance and quality, use validated models that work.

- +
- - + +
- +
- +
- + Get started with Zen - +

- Add $20 Pay as you go balance (+$1.23 card processing fee) + Add $20 Pay as you go balance{" "} + (+$1.23 card processing fee)

Use with any agent. Set monthly spend limits. Cancel any time.

-
@@ -140,8 +191,8 @@ export default function Home() {

What problem is Zen solving?

- There are so many models available, but only a few work well with coding agents. Most providers - configure them differently with varying results. + There are so many models available, but only a few work well with coding agents. + Most providers configure them differently with varying results.

We're fixing this for everyone, not just OpenCode users.

@@ -176,14 +227,15 @@ export default function Home() {
  • [2]
  • [3]
    - Auto-top up - when your balance reaches $5 we’ll automatically add $20 + Auto-top up - when your balance reaches $5 we’ll automatically + add $20
  • @@ -195,8 +247,9 @@ export default function Home() {
    [*]

    - All Zen models are hosted in the US. Providers follow a zero-retention policy and do not use your data - for model training, with the following exceptions. + All Zen models are hosted in the US. Providers follow a zero-retention policy and + do not use your data for model training, with the{" "} + following exceptions.

    @@ -251,7 +304,8 @@ export default function Home() { ex-Head of Design, Laravel
    - With @OpenCode Zen I know all the models are tested and perfect for coding agents. + With @OpenCode Zen I know all the models are tested and perfect for + coding agents.
    @@ -275,38 +329,44 @@ export default function Home() {
    • - Zen is a curated set of AI models tested and benchmarked for coding agents created by the team behind - OpenCode. + Zen is a curated set of AI models tested and benchmarked for coding agents created + by the team behind OpenCode.
    • - Zen only provides models that have been specifically tested and benchmarked for coding agents. You - wouldn’t use a butter knife to cut steak, don’t use poor models for coding. + Zen only provides models that have been specifically tested and benchmarked for + coding agents. You wouldn’t use a butter knife to cut steak, don’t use poor models + for coding.
    • - Zen is not for profit. Zen passes through the costs from the model providers to you. The higher Zen’s - usage the more OpenCode can negotiate better rates and pass those to you. + Zen is not for profit. Zen passes through the costs from the model providers to + you. The higher Zen’s usage the more OpenCode can negotiate better rates and pass + those to you.
    • - Zen charges per request with zero markups, so you pay exactly what - the model provider charges. Your total cost depends on usage, and you can set monthly spend limits in - your account. To cover costs, OpenCode adds only a small payment processing fee of - $1.23 per $20 balance top-up. + Zen charges per request with zero markups, so you + pay exactly what the model provider charges. Your total cost depends on usage, and + you can set monthly spend limits in your account. To cover + costs, OpenCode adds only a small payment processing fee of $1.23 per $20 balance + top-up.
    • - All Zen models are hosted in the US. Providers follow a zero-retention policy and do not use your data - for model training, with the following exceptions. + All Zen models are hosted in the US. Providers follow a zero-retention policy and + do not use your data for model training, with the{" "} + following exceptions.
    • - Yes, you can set monthly spending limits in your account. + + Yes, you can set monthly spending limits in your account. +
    • @@ -315,8 +375,8 @@ export default function Home() {
    • - While Zen works great with OpenCode, you can use Zen with any agent. Follow the setup instructions in - your preferred coding agent. + While Zen works great with OpenCode, you can use Zen with any agent. Follow the + setup instructions in your preferred coding agent.
    diff --git a/packages/console/app/src/routes/zen/util/provider/anthropic.ts b/packages/console/app/src/routes/zen/util/provider/anthropic.ts index 603d8917..f4e8dc44 100644 --- a/packages/console/app/src/routes/zen/util/provider/anthropic.ts +++ b/packages/console/app/src/routes/zen/util/provider/anthropic.ts @@ -98,7 +98,10 @@ export function fromAnthropicRequest(body: any): CommonRequest { typeof (src as any).media_type === "string" && typeof (src as any).data === "string" ) - return { type: "image_url", image_url: { url: `data:${(src as any).media_type};base64,${(src as any).data}` } } + return { + type: "image_url", + image_url: { url: `data:${(src as any).media_type};base64,${(src as any).data}` }, + } return undefined } @@ -120,12 +123,15 @@ export function fromAnthropicRequest(body: any): CommonRequest { if ((p as any).type === "tool_result") { const id = (p as any).tool_use_id const content = - typeof (p as any).content === "string" ? (p as any).content : JSON.stringify((p as any).content) + typeof (p as any).content === "string" + ? (p as any).content + : JSON.stringify((p as any).content) msgs.push({ role: "tool", tool_call_id: id, content }) } } if (partsOut.length > 0) { - if (partsOut.length === 1 && partsOut[0].type === "text") msgs.push({ role: "user", content: partsOut[0].text }) + if (partsOut.length === 1 && partsOut[0].type === "text") + msgs.push({ role: "user", content: partsOut[0].text }) else msgs.push({ role: "user", content: partsOut }) } continue @@ -137,7 +143,8 @@ export function fromAnthropicRequest(body: any): CommonRequest { const tcs: any[] = [] for (const p of partsIn) { if (!p || !(p as any).type) continue - if ((p as any).type === "text" && typeof (p as any).text === "string") texts.push((p as any).text) + if ((p as any).type === "text" && typeof (p as any).text === "string") + texts.push((p as any).text) if ((p as any).type === "tool_use") { const name = (p as any).name const id = (p as any).id @@ -165,7 +172,11 @@ export function fromAnthropicRequest(body: any): CommonRequest { .filter((t: any) => t && typeof t === "object" && "input_schema" in t) .map((t: any) => ({ type: "function", - function: { name: (t as any).name, description: (t as any).description, parameters: (t as any).input_schema }, + function: { + name: (t as any).name, + description: (t as any).description, + parameters: (t as any).input_schema, + }, })) : undefined @@ -203,7 +214,9 @@ export function fromAnthropicRequest(body: any): CommonRequest { export function toAnthropicRequest(body: CommonRequest) { if (!body || typeof body !== "object") return body - const sysIn = Array.isArray(body.messages) ? body.messages.filter((m: any) => m && m.role === "system") : [] + const sysIn = Array.isArray(body.messages) + ? body.messages.filter((m: any) => m && m.role === "system") + : [] let ccCount = 0 const cc = () => { ccCount++ @@ -354,7 +367,9 @@ export function fromAnthropicResponse(resp: any): CommonResponse { const idIn = (resp as any).id const id = - typeof idIn === "string" ? idIn.replace(/^msg_/, "chatcmpl_") : `chatcmpl_${Math.random().toString(36).slice(2)}` + typeof idIn === "string" + ? idIn.replace(/^msg_/, "chatcmpl_") + : `chatcmpl_${Math.random().toString(36).slice(2)}` const model = (resp as any).model const blocks: any[] = Array.isArray((resp as any).content) ? (resp as any).content : [] @@ -397,7 +412,9 @@ export function fromAnthropicResponse(resp: any): CommonResponse { const ct = typeof (u as any).output_tokens === "number" ? (u as any).output_tokens : undefined const total = pt != null && ct != null ? pt + ct : undefined const cached = - typeof (u as any).cache_read_input_tokens === "number" ? (u as any).cache_read_input_tokens : undefined + typeof (u as any).cache_read_input_tokens === "number" + ? (u as any).cache_read_input_tokens + : undefined const details = cached != null ? { cached_tokens: cached } : undefined return { prompt_tokens: pt, @@ -452,7 +469,12 @@ export function toAnthropicResponse(resp: CommonResponse) { } catch { input = (tc as any).function.arguments } - content.push({ type: "tool_use", id: (tc as any).id, name: (tc as any).function.name, input }) + content.push({ + type: "tool_use", + id: (tc as any).id, + name: (tc as any).function.name, + input, + }) } } } @@ -511,13 +533,22 @@ export function fromAnthropicChunk(chunk: string): CommonChunk | string { if (json.type === "content_block_start") { const cb = json.content_block if (cb?.type === "text") { - out.choices.push({ index: json.index ?? 0, delta: { role: "assistant", content: "" }, finish_reason: null }) + out.choices.push({ + index: json.index ?? 0, + delta: { role: "assistant", content: "" }, + finish_reason: null, + }) } else if (cb?.type === "tool_use") { out.choices.push({ index: json.index ?? 0, delta: { tool_calls: [ - { index: json.index ?? 0, id: cb.id, type: "function", function: { name: cb.name, arguments: "" } }, + { + index: json.index ?? 0, + id: cb.id, + type: "function", + function: { name: cb.name, arguments: "" }, + }, ], }, finish_reason: null, @@ -532,7 +563,9 @@ export function fromAnthropicChunk(chunk: string): CommonChunk | string { } else if (d?.type === "input_json_delta") { out.choices.push({ index: json.index ?? 0, - delta: { tool_calls: [{ index: json.index ?? 0, function: { arguments: d.partial_json } }] }, + delta: { + tool_calls: [{ index: json.index ?? 0, function: { arguments: d.partial_json } }], + }, finish_reason: null, }) } @@ -558,7 +591,9 @@ export function fromAnthropicChunk(chunk: string): CommonChunk | string { prompt_tokens: u.input_tokens, completion_tokens: u.output_tokens, total_tokens: (u.input_tokens || 0) + (u.output_tokens || 0), - ...(u.cache_read_input_tokens ? { prompt_tokens_details: { cached_tokens: u.cache_read_input_tokens } } : {}), + ...(u.cache_read_input_tokens + ? { prompt_tokens_details: { cached_tokens: u.cache_read_input_tokens } } + : {}), } } diff --git a/packages/console/app/src/routes/zen/util/provider/openai-compatible.ts b/packages/console/app/src/routes/zen/util/provider/openai-compatible.ts index daf65027..d6998572 100644 --- a/packages/console/app/src/routes/zen/util/provider/openai-compatible.ts +++ b/packages/console/app/src/routes/zen/util/provider/openai-compatible.ts @@ -57,7 +57,8 @@ export const oaCompatHelper = { const inputTokens = usage.prompt_tokens ?? 0 const outputTokens = usage.completion_tokens ?? 0 const reasoningTokens = usage.completion_tokens_details?.reasoning_tokens ?? undefined - const cacheReadTokens = usage.cached_tokens ?? usage.prompt_tokens_details?.cached_tokens ?? undefined + const cacheReadTokens = + usage.cached_tokens ?? usage.prompt_tokens_details?.cached_tokens ?? undefined return { inputTokens: inputTokens - (cacheReadTokens ?? 0), outputTokens, @@ -79,7 +80,8 @@ export function fromOaCompatibleRequest(body: any): CommonRequest { if (!m || !m.role) continue if (m.role === "system") { - if (typeof m.content === "string" && m.content.length > 0) msgsOut.push({ role: "system", content: m.content }) + if (typeof m.content === "string" && m.content.length > 0) + msgsOut.push({ role: "system", content: m.content }) continue } @@ -90,10 +92,12 @@ export function fromOaCompatibleRequest(body: any): CommonRequest { const parts: any[] = [] for (const p of m.content) { if (!p || !p.type) continue - if (p.type === "text" && typeof p.text === "string") parts.push({ type: "text", text: p.text }) + if (p.type === "text" && typeof p.text === "string") + parts.push({ type: "text", text: p.text }) if (p.type === "image_url") parts.push({ type: "image_url", image_url: p.image_url }) } - if (parts.length === 1 && parts[0].type === "text") msgsOut.push({ role: "user", content: parts[0].text }) + if (parts.length === 1 && parts[0].type === "text") + msgsOut.push({ role: "user", content: parts[0].text }) else if (parts.length > 0) msgsOut.push({ role: "user", content: parts }) } continue @@ -137,7 +141,8 @@ export function toOaCompatibleRequest(body: CommonRequest) { if (p.type === "image_url" && p.image_url) return { type: "image_url", image_url: p.image_url } const s = (p as any).source if (!s || typeof s !== "object") return undefined - if (s.type === "url" && typeof s.url === "string") return { type: "image_url", image_url: { url: s.url } } + if (s.type === "url" && typeof s.url === "string") + return { type: "image_url", image_url: { url: s.url } } if (s.type === "base64" && typeof s.media_type === "string" && typeof s.data === "string") return { type: "image_url", image_url: { url: `data:${s.media_type};base64,${s.data}` } } return undefined @@ -147,7 +152,8 @@ export function toOaCompatibleRequest(body: CommonRequest) { if (!m || !m.role) continue if (m.role === "system") { - if (typeof m.content === "string" && m.content.length > 0) msgsOut.push({ role: "system", content: m.content }) + if (typeof m.content === "string" && m.content.length > 0) + msgsOut.push({ role: "system", content: m.content }) continue } @@ -160,11 +166,13 @@ export function toOaCompatibleRequest(body: CommonRequest) { const parts: any[] = [] for (const p of m.content) { if (!p || !p.type) continue - if (p.type === "text" && typeof p.text === "string") parts.push({ type: "text", text: p.text }) + if (p.type === "text" && typeof p.text === "string") + parts.push({ type: "text", text: p.text }) const ip = toImg(p) if (ip) parts.push(ip) } - if (parts.length === 1 && parts[0].type === "text") msgsOut.push({ role: "user", content: parts[0].text }) + if (parts.length === 1 && parts[0].type === "text") + msgsOut.push({ role: "user", content: parts[0].text }) else if (parts.length > 0) msgsOut.push({ role: "user", content: parts }) } continue @@ -317,7 +325,9 @@ export function toOaCompatibleResponse(resp: CommonResponse) { const idIn = (resp as any).id const id = - typeof idIn === "string" ? idIn.replace(/^msg_/, "chatcmpl_") : `chatcmpl_${Math.random().toString(36).slice(2)}` + typeof idIn === "string" + ? idIn.replace(/^msg_/, "chatcmpl_") + : `chatcmpl_${Math.random().toString(36).slice(2)}` const model = (resp as any).model const blocks: any[] = Array.isArray((resp as any).content) ? (resp as any).content : [] @@ -359,7 +369,8 @@ export function toOaCompatibleResponse(resp: CommonResponse) { const pt = typeof u.input_tokens === "number" ? u.input_tokens : undefined const ct = typeof u.output_tokens === "number" ? u.output_tokens : undefined const total = pt != null && ct != null ? pt + ct : undefined - const cached = typeof u.cache_read_input_tokens === "number" ? u.cache_read_input_tokens : undefined + const cached = + typeof u.cache_read_input_tokens === "number" ? u.cache_read_input_tokens : undefined const details = cached != null ? { cached_tokens: cached } : undefined return { prompt_tokens: pt, @@ -532,7 +543,9 @@ export function toOaCompatibleChunk(chunk: CommonChunk): string { total_tokens: chunk.usage.total_tokens, ...(chunk.usage.prompt_tokens_details?.cached_tokens ? { - prompt_tokens_details: { cached_tokens: chunk.usage.prompt_tokens_details.cached_tokens }, + prompt_tokens_details: { + cached_tokens: chunk.usage.prompt_tokens_details.cached_tokens, + }, } : {}), } diff --git a/packages/console/app/src/routes/zen/util/provider/openai.ts b/packages/console/app/src/routes/zen/util/provider/openai.ts index d1730099..fa0776b7 100644 --- a/packages/console/app/src/routes/zen/util/provider/openai.ts +++ b/packages/console/app/src/routes/zen/util/provider/openai.ts @@ -77,13 +77,20 @@ export function fromOpenaiRequest(body: any): CommonRequest { typeof (s as any).media_type === "string" && typeof (s as any).data === "string" ) - return { type: "image_url", image_url: { url: `data:${(s as any).media_type};base64,${(s as any).data}` } } + return { + type: "image_url", + image_url: { url: `data:${(s as any).media_type};base64,${(s as any).data}` }, + } return undefined } const msgs: any[] = [] - const inMsgs = Array.isArray(body.input) ? body.input : Array.isArray(body.messages) ? body.messages : [] + const inMsgs = Array.isArray(body.input) + ? body.input + : Array.isArray(body.messages) + ? body.messages + : [] for (const m of inMsgs) { if (!m) continue @@ -96,7 +103,9 @@ export function fromOpenaiRequest(body: any): CommonRequest { const args = typeof a === "string" ? a : JSON.stringify(a ?? {}) msgs.push({ role: "assistant", - tool_calls: [{ id: (m as any).id, type: "function", function: { name, arguments: args } }], + tool_calls: [ + { id: (m as any).id, type: "function", function: { name, arguments: args } }, + ], }) } if ((m as any).type === "function_call_output") { @@ -113,7 +122,8 @@ export function fromOpenaiRequest(body: any): CommonRequest { if (typeof c === "string" && c.length > 0) msgs.push({ role: "system", content: c }) if (Array.isArray(c)) { const t = c.find((p: any) => p && typeof p.text === "string") - if (t && typeof t.text === "string" && t.text.length > 0) msgs.push({ role: "system", content: t.text }) + if (t && typeof t.text === "string" && t.text.length > 0) + msgs.push({ role: "system", content: t.text }) } continue } @@ -126,18 +136,24 @@ export function fromOpenaiRequest(body: any): CommonRequest { const parts: any[] = [] for (const p of c) { if (!p || !(p as any).type) continue - if (((p as any).type === "text" || (p as any).type === "input_text") && typeof (p as any).text === "string") + if ( + ((p as any).type === "text" || (p as any).type === "input_text") && + typeof (p as any).text === "string" + ) parts.push({ type: "text", text: (p as any).text }) const ip = toImg(p) if (ip) parts.push(ip) if ((p as any).type === "tool_result") { const id = (p as any).tool_call_id const content = - typeof (p as any).content === "string" ? (p as any).content : JSON.stringify((p as any).content) + typeof (p as any).content === "string" + ? (p as any).content + : JSON.stringify((p as any).content) msgs.push({ role: "tool", tool_call_id: id, content }) } } - if (parts.length === 1 && parts[0].type === "text") msgs.push({ role: "user", content: parts[0].text }) + if (parts.length === 1 && parts[0].type === "text") + msgs.push({ role: "user", content: parts[0].text }) else if (parts.length > 0) msgs.push({ role: "user", content: parts }) } continue @@ -153,7 +169,11 @@ export function fromOpenaiRequest(body: any): CommonRequest { } if ((m as any).role === "tool") { - msgs.push({ role: "tool", tool_call_id: (m as any).tool_call_id, content: (m as any).content }) + msgs.push({ + role: "tool", + tool_call_id: (m as any).tool_call_id, + content: (m as any).content, + }) continue } } @@ -210,7 +230,10 @@ export function toOpenaiRequest(body: CommonRequest) { typeof (s as any).media_type === "string" && typeof (s as any).data === "string" ) - return { type: "input_image", image_url: { url: `data:${(s as any).media_type};base64,${(s as any).data}` } } + return { + type: "input_image", + image_url: { url: `data:${(s as any).media_type};base64,${(s as any).data}` }, + } return undefined } @@ -257,7 +280,10 @@ export function toOpenaiRequest(body: CommonRequest) { } if ((m as any).role === "tool") { - const out = typeof (m as any).content === "string" ? (m as any).content : JSON.stringify((m as any).content) + const out = + typeof (m as any).content === "string" + ? (m as any).content + : JSON.stringify((m as any).content) input.push({ type: "function_call_output", call_id: (m as any).tool_call_id, output: out }) continue } @@ -325,7 +351,9 @@ export function fromOpenaiResponse(resp: any): CommonResponse { const idIn = (r as any).id const id = - typeof idIn === "string" ? idIn.replace(/^resp_/, "chatcmpl_") : `chatcmpl_${Math.random().toString(36).slice(2)}` + typeof idIn === "string" + ? idIn.replace(/^resp_/, "chatcmpl_") + : `chatcmpl_${Math.random().toString(36).slice(2)}` const model = (r as any).model ?? (resp as any).model const out = Array.isArray((r as any).output) ? (r as any).output : [] @@ -452,7 +480,9 @@ export function toOpenaiResponse(resp: CommonResponse) { })() return { - id: (resp as any).id?.replace(/^chatcmpl_/, "resp_") ?? `resp_${Math.random().toString(36).slice(2)}`, + id: + (resp as any).id?.replace(/^chatcmpl_/, "resp_") ?? + `resp_${Math.random().toString(36).slice(2)}`, object: "response", model: (resp as any).model, output: outputItems, @@ -498,7 +528,9 @@ export function fromOpenaiChunk(chunk: string): CommonChunk | string { if (typeof name === "string" && name.length > 0) { out.choices.push({ index: 0, - delta: { tool_calls: [{ index: 0, id, type: "function", function: { name, arguments: "" } }] }, + delta: { + tool_calls: [{ index: 0, id, type: "function", function: { name, arguments: "" } }], + }, finish_reason: null, }) } @@ -555,7 +587,12 @@ export function toOpenaiChunk(chunk: CommonChunk): string { const model = chunk.model if (d.content) { - const data = { id, type: "response.output_text.delta", delta: d.content, response: { id, model } } + const data = { + id, + type: "response.output_text.delta", + delta: d.content, + response: { id, model }, + } return `event: response.output_text.delta\ndata: ${JSON.stringify(data)}` } @@ -565,7 +602,13 @@ export function toOpenaiChunk(chunk: CommonChunk): string { const data = { type: "response.output_item.added", output_index: 0, - item: { id: tc.id, type: "function_call", name: tc.function.name, call_id: tc.id, arguments: "" }, + item: { + id: tc.id, + type: "function_call", + name: tc.function.name, + call_id: tc.id, + arguments: "", + }, } return `event: response.output_item.added\ndata: ${JSON.stringify(data)}` } @@ -593,7 +636,11 @@ export function toOpenaiChunk(chunk: CommonChunk): string { } : undefined - const data: any = { id, type: "response.completed", response: { id, model, ...(usage ? { usage } : {}) } } + const data: any = { + id, + type: "response.completed", + response: { id, model, ...(usage ? { usage } : {}) }, + } return `event: response.completed\ndata: ${JSON.stringify(data)}` } diff --git a/packages/console/app/src/style/token/font.css b/packages/console/app/src/style/token/font.css index 67143e66..dc0d298f 100644 --- a/packages/console/app/src/style/token/font.css +++ b/packages/console/app/src/style/token/font.css @@ -15,6 +15,7 @@ body { --font-size-9xl: 8rem; --font-mono: - "IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; + "IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", + "Courier New", monospace; --font-sans: var(--font-mono); } diff --git a/packages/console/app/sst-env.d.ts b/packages/console/app/sst-env.d.ts index 9b9de732..bd558821 100644 --- a/packages/console/app/sst-env.d.ts +++ b/packages/console/app/sst-env.d.ts @@ -6,4 +6,4 @@ /// import "sst" -export {} \ No newline at end of file +export {} diff --git a/packages/console/core/migrations/meta/0018_snapshot.json b/packages/console/core/migrations/meta/0018_snapshot.json index 398ba261..3e3c64c7 100644 --- a/packages/console/core/migrations/meta/0018_snapshot.json +++ b/packages/console/core/migrations/meta/0018_snapshot.json @@ -48,9 +48,7 @@ "indexes": { "email": { "name": "email", - "columns": [ - "email" - ], + "columns": ["email"], "isUnique": true } }, @@ -180,9 +178,7 @@ "indexes": { "global_customer_id": { "name": "global_customer_id", - "columns": [ - "customer_id" - ], + "columns": ["customer_id"], "isUnique": true } }, @@ -190,10 +186,7 @@ "compositePrimaryKeys": { "billing_workspace_id_id_pk": { "name": "billing_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -280,10 +273,7 @@ "compositePrimaryKeys": { "payment_workspace_id_id_pk": { "name": "payment_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -398,10 +388,7 @@ "compositePrimaryKeys": { "usage_workspace_id_id_pk": { "name": "usage_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -486,17 +473,12 @@ "indexes": { "global_key": { "name": "global_key", - "columns": [ - "key" - ], + "columns": ["key"], "isUnique": true }, "name": { "name": "name", - "columns": [ - "workspace_id", - "name" - ], + "columns": ["workspace_id", "name"], "isUnique": true } }, @@ -504,10 +486,7 @@ "compositePrimaryKeys": { "key_workspace_id_id_pk": { "name": "key_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -599,10 +578,7 @@ "indexes": { "user_email": { "name": "user_email", - "columns": [ - "workspace_id", - "email" - ], + "columns": ["workspace_id", "email"], "isUnique": true } }, @@ -610,10 +586,7 @@ "compositePrimaryKeys": { "user_workspace_id_id_pk": { "name": "user_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -670,9 +643,7 @@ "indexes": { "slug": { "name": "slug", - "columns": [ - "slug" - ], + "columns": ["slug"], "isUnique": true } }, @@ -680,9 +651,7 @@ "compositePrimaryKeys": { "workspace_id": { "name": "workspace_id", - "columns": [ - "id" - ] + "columns": ["id"] } }, "uniqueConstraints": {}, @@ -699,4 +668,4 @@ "tables": {}, "indexes": {} } -} \ No newline at end of file +} diff --git a/packages/console/core/migrations/meta/0019_snapshot.json b/packages/console/core/migrations/meta/0019_snapshot.json index 8f1afeb5..9a0d4d24 100644 --- a/packages/console/core/migrations/meta/0019_snapshot.json +++ b/packages/console/core/migrations/meta/0019_snapshot.json @@ -48,9 +48,7 @@ "indexes": { "email": { "name": "email", - "columns": [ - "email" - ], + "columns": ["email"], "isUnique": true } }, @@ -180,9 +178,7 @@ "indexes": { "global_customer_id": { "name": "global_customer_id", - "columns": [ - "customer_id" - ], + "columns": ["customer_id"], "isUnique": true } }, @@ -190,10 +186,7 @@ "compositePrimaryKeys": { "billing_workspace_id_id_pk": { "name": "billing_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -280,10 +273,7 @@ "compositePrimaryKeys": { "payment_workspace_id_id_pk": { "name": "payment_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -398,10 +388,7 @@ "compositePrimaryKeys": { "usage_workspace_id_id_pk": { "name": "usage_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -486,17 +473,12 @@ "indexes": { "global_key": { "name": "global_key", - "columns": [ - "key" - ], + "columns": ["key"], "isUnique": true }, "name": { "name": "name", - "columns": [ - "workspace_id", - "name" - ], + "columns": ["workspace_id", "name"], "isUnique": true } }, @@ -504,10 +486,7 @@ "compositePrimaryKeys": { "key_workspace_id_id_pk": { "name": "key_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -599,10 +578,7 @@ "indexes": { "user_email": { "name": "user_email", - "columns": [ - "workspace_id", - "email" - ], + "columns": ["workspace_id", "email"], "isUnique": true } }, @@ -610,10 +586,7 @@ "compositePrimaryKeys": { "user_workspace_id_id_pk": { "name": "user_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -670,9 +643,7 @@ "indexes": { "slug": { "name": "slug", - "columns": [ - "slug" - ], + "columns": ["slug"], "isUnique": true } }, @@ -680,9 +651,7 @@ "compositePrimaryKeys": { "workspace_id": { "name": "workspace_id", - "columns": [ - "id" - ] + "columns": ["id"] } }, "uniqueConstraints": {}, @@ -699,4 +668,4 @@ "tables": {}, "indexes": {} } -} \ No newline at end of file +} diff --git a/packages/console/core/migrations/meta/0020_snapshot.json b/packages/console/core/migrations/meta/0020_snapshot.json index 662093f5..9defceb5 100644 --- a/packages/console/core/migrations/meta/0020_snapshot.json +++ b/packages/console/core/migrations/meta/0020_snapshot.json @@ -48,9 +48,7 @@ "indexes": { "email": { "name": "email", - "columns": [ - "email" - ], + "columns": ["email"], "isUnique": true } }, @@ -180,9 +178,7 @@ "indexes": { "global_customer_id": { "name": "global_customer_id", - "columns": [ - "customer_id" - ], + "columns": ["customer_id"], "isUnique": true } }, @@ -190,10 +186,7 @@ "compositePrimaryKeys": { "billing_workspace_id_id_pk": { "name": "billing_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -280,10 +273,7 @@ "compositePrimaryKeys": { "payment_workspace_id_id_pk": { "name": "payment_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -398,10 +388,7 @@ "compositePrimaryKeys": { "usage_workspace_id_id_pk": { "name": "usage_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -486,17 +473,12 @@ "indexes": { "global_key": { "name": "global_key", - "columns": [ - "key" - ], + "columns": ["key"], "isUnique": true }, "name": { "name": "name", - "columns": [ - "workspace_id", - "name" - ], + "columns": ["workspace_id", "name"], "isUnique": true } }, @@ -504,10 +486,7 @@ "compositePrimaryKeys": { "key_workspace_id_id_pk": { "name": "key_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -592,10 +571,7 @@ "indexes": { "user_email": { "name": "user_email", - "columns": [ - "workspace_id", - "email" - ], + "columns": ["workspace_id", "email"], "isUnique": true } }, @@ -603,10 +579,7 @@ "compositePrimaryKeys": { "user_workspace_id_id_pk": { "name": "user_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -663,9 +636,7 @@ "indexes": { "slug": { "name": "slug", - "columns": [ - "slug" - ], + "columns": ["slug"], "isUnique": true } }, @@ -673,9 +644,7 @@ "compositePrimaryKeys": { "workspace_id": { "name": "workspace_id", - "columns": [ - "id" - ] + "columns": ["id"] } }, "uniqueConstraints": {}, @@ -692,4 +661,4 @@ "tables": {}, "indexes": {} } -} \ No newline at end of file +} diff --git a/packages/console/core/migrations/meta/0021_snapshot.json b/packages/console/core/migrations/meta/0021_snapshot.json index b285e34f..64d3e9d2 100644 --- a/packages/console/core/migrations/meta/0021_snapshot.json +++ b/packages/console/core/migrations/meta/0021_snapshot.json @@ -48,9 +48,7 @@ "indexes": { "email": { "name": "email", - "columns": [ - "email" - ], + "columns": ["email"], "isUnique": true } }, @@ -180,9 +178,7 @@ "indexes": { "global_customer_id": { "name": "global_customer_id", - "columns": [ - "customer_id" - ], + "columns": ["customer_id"], "isUnique": true } }, @@ -190,10 +186,7 @@ "compositePrimaryKeys": { "billing_workspace_id_id_pk": { "name": "billing_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -280,10 +273,7 @@ "compositePrimaryKeys": { "payment_workspace_id_id_pk": { "name": "payment_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -398,10 +388,7 @@ "compositePrimaryKeys": { "usage_workspace_id_id_pk": { "name": "usage_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -486,17 +473,12 @@ "indexes": { "global_key": { "name": "global_key", - "columns": [ - "key" - ], + "columns": ["key"], "isUnique": true }, "name": { "name": "name", - "columns": [ - "workspace_id", - "name" - ], + "columns": ["workspace_id", "name"], "isUnique": true } }, @@ -504,10 +486,7 @@ "compositePrimaryKeys": { "key_workspace_id_id_pk": { "name": "key_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -599,10 +578,7 @@ "indexes": { "user_email": { "name": "user_email", - "columns": [ - "workspace_id", - "email" - ], + "columns": ["workspace_id", "email"], "isUnique": true } }, @@ -610,10 +586,7 @@ "compositePrimaryKeys": { "user_workspace_id_id_pk": { "name": "user_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -670,9 +643,7 @@ "indexes": { "slug": { "name": "slug", - "columns": [ - "slug" - ], + "columns": ["slug"], "isUnique": true } }, @@ -680,9 +651,7 @@ "compositePrimaryKeys": { "workspace_id": { "name": "workspace_id", - "columns": [ - "id" - ] + "columns": ["id"] } }, "uniqueConstraints": {}, @@ -699,4 +668,4 @@ "tables": {}, "indexes": {} } -} \ No newline at end of file +} diff --git a/packages/console/core/migrations/meta/0022_snapshot.json b/packages/console/core/migrations/meta/0022_snapshot.json index 9486ee34..8a1c4e7d 100644 --- a/packages/console/core/migrations/meta/0022_snapshot.json +++ b/packages/console/core/migrations/meta/0022_snapshot.json @@ -48,9 +48,7 @@ "indexes": { "email": { "name": "email", - "columns": [ - "email" - ], + "columns": ["email"], "isUnique": true } }, @@ -180,9 +178,7 @@ "indexes": { "global_customer_id": { "name": "global_customer_id", - "columns": [ - "customer_id" - ], + "columns": ["customer_id"], "isUnique": true } }, @@ -190,10 +186,7 @@ "compositePrimaryKeys": { "billing_workspace_id_id_pk": { "name": "billing_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -280,10 +273,7 @@ "compositePrimaryKeys": { "payment_workspace_id_id_pk": { "name": "payment_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -398,10 +388,7 @@ "compositePrimaryKeys": { "usage_workspace_id_id_pk": { "name": "usage_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -486,17 +473,12 @@ "indexes": { "global_key": { "name": "global_key", - "columns": [ - "key" - ], + "columns": ["key"], "isUnique": true }, "name": { "name": "name", - "columns": [ - "workspace_id", - "name" - ], + "columns": ["workspace_id", "name"], "isUnique": true } }, @@ -504,10 +486,7 @@ "compositePrimaryKeys": { "key_workspace_id_id_pk": { "name": "key_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -613,18 +592,12 @@ "indexes": { "user_account_id": { "name": "user_account_id", - "columns": [ - "workspace_id", - "account_id" - ], + "columns": ["workspace_id", "account_id"], "isUnique": true }, "user_email": { "name": "user_email", - "columns": [ - "workspace_id", - "email" - ], + "columns": ["workspace_id", "email"], "isUnique": true } }, @@ -632,10 +605,7 @@ "compositePrimaryKeys": { "user_workspace_id_id_pk": { "name": "user_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -692,9 +662,7 @@ "indexes": { "slug": { "name": "slug", - "columns": [ - "slug" - ], + "columns": ["slug"], "isUnique": true } }, @@ -702,9 +670,7 @@ "compositePrimaryKeys": { "workspace_id": { "name": "workspace_id", - "columns": [ - "id" - ] + "columns": ["id"] } }, "uniqueConstraints": {}, @@ -721,4 +687,4 @@ "tables": {}, "indexes": {} } -} \ No newline at end of file +} diff --git a/packages/console/core/migrations/meta/0023_snapshot.json b/packages/console/core/migrations/meta/0023_snapshot.json index 8a40e42a..4f6f6628 100644 --- a/packages/console/core/migrations/meta/0023_snapshot.json +++ b/packages/console/core/migrations/meta/0023_snapshot.json @@ -48,9 +48,7 @@ "indexes": { "email": { "name": "email", - "columns": [ - "email" - ], + "columns": ["email"], "isUnique": true } }, @@ -180,9 +178,7 @@ "indexes": { "global_customer_id": { "name": "global_customer_id", - "columns": [ - "customer_id" - ], + "columns": ["customer_id"], "isUnique": true } }, @@ -190,10 +186,7 @@ "compositePrimaryKeys": { "billing_workspace_id_id_pk": { "name": "billing_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -280,10 +273,7 @@ "compositePrimaryKeys": { "payment_workspace_id_id_pk": { "name": "payment_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -398,10 +388,7 @@ "compositePrimaryKeys": { "usage_workspace_id_id_pk": { "name": "usage_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -486,17 +473,12 @@ "indexes": { "global_key": { "name": "global_key", - "columns": [ - "key" - ], + "columns": ["key"], "isUnique": true }, "name": { "name": "name", - "columns": [ - "workspace_id", - "name" - ], + "columns": ["workspace_id", "name"], "isUnique": true } }, @@ -504,10 +486,7 @@ "compositePrimaryKeys": { "key_workspace_id_id_pk": { "name": "key_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -613,32 +592,22 @@ "indexes": { "user_account_id": { "name": "user_account_id", - "columns": [ - "workspace_id", - "account_id" - ], + "columns": ["workspace_id", "account_id"], "isUnique": true }, "user_email": { "name": "user_email", - "columns": [ - "workspace_id", - "email" - ], + "columns": ["workspace_id", "email"], "isUnique": true }, "global_account_id": { "name": "global_account_id", - "columns": [ - "account_id" - ], + "columns": ["account_id"], "isUnique": false }, "global_email": { "name": "global_email", - "columns": [ - "email" - ], + "columns": ["email"], "isUnique": false } }, @@ -646,10 +615,7 @@ "compositePrimaryKeys": { "user_workspace_id_id_pk": { "name": "user_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -706,9 +672,7 @@ "indexes": { "slug": { "name": "slug", - "columns": [ - "slug" - ], + "columns": ["slug"], "isUnique": true } }, @@ -716,9 +680,7 @@ "compositePrimaryKeys": { "workspace_id": { "name": "workspace_id", - "columns": [ - "id" - ] + "columns": ["id"] } }, "uniqueConstraints": {}, @@ -735,4 +697,4 @@ "tables": {}, "indexes": {} } -} \ No newline at end of file +} diff --git a/packages/console/core/migrations/meta/0024_snapshot.json b/packages/console/core/migrations/meta/0024_snapshot.json index 4f50945d..1ef25970 100644 --- a/packages/console/core/migrations/meta/0024_snapshot.json +++ b/packages/console/core/migrations/meta/0024_snapshot.json @@ -48,9 +48,7 @@ "indexes": { "email": { "name": "email", - "columns": [ - "email" - ], + "columns": ["email"], "isUnique": true } }, @@ -180,9 +178,7 @@ "indexes": { "global_customer_id": { "name": "global_customer_id", - "columns": [ - "customer_id" - ], + "columns": ["customer_id"], "isUnique": true } }, @@ -190,10 +186,7 @@ "compositePrimaryKeys": { "billing_workspace_id_id_pk": { "name": "billing_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -280,10 +273,7 @@ "compositePrimaryKeys": { "payment_workspace_id_id_pk": { "name": "payment_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -398,10 +388,7 @@ "compositePrimaryKeys": { "usage_workspace_id_id_pk": { "name": "usage_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -486,17 +473,12 @@ "indexes": { "global_key": { "name": "global_key", - "columns": [ - "key" - ], + "columns": ["key"], "isUnique": true }, "name": { "name": "name", - "columns": [ - "workspace_id", - "name" - ], + "columns": ["workspace_id", "name"], "isUnique": true } }, @@ -504,10 +486,7 @@ "compositePrimaryKeys": { "key_workspace_id_id_pk": { "name": "key_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -599,32 +578,22 @@ "indexes": { "user_account_id": { "name": "user_account_id", - "columns": [ - "workspace_id", - "account_id" - ], + "columns": ["workspace_id", "account_id"], "isUnique": true }, "user_email": { "name": "user_email", - "columns": [ - "workspace_id", - "email" - ], + "columns": ["workspace_id", "email"], "isUnique": true }, "global_account_id": { "name": "global_account_id", - "columns": [ - "account_id" - ], + "columns": ["account_id"], "isUnique": false }, "global_email": { "name": "global_email", - "columns": [ - "email" - ], + "columns": ["email"], "isUnique": false } }, @@ -632,10 +601,7 @@ "compositePrimaryKeys": { "user_workspace_id_id_pk": { "name": "user_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -692,9 +658,7 @@ "indexes": { "slug": { "name": "slug", - "columns": [ - "slug" - ], + "columns": ["slug"], "isUnique": true } }, @@ -702,9 +666,7 @@ "compositePrimaryKeys": { "workspace_id": { "name": "workspace_id", - "columns": [ - "id" - ] + "columns": ["id"] } }, "uniqueConstraints": {}, @@ -721,4 +683,4 @@ "tables": {}, "indexes": {} } -} \ No newline at end of file +} diff --git a/packages/console/core/migrations/meta/0025_snapshot.json b/packages/console/core/migrations/meta/0025_snapshot.json index 4b0cef0c..6746a6e8 100644 --- a/packages/console/core/migrations/meta/0025_snapshot.json +++ b/packages/console/core/migrations/meta/0025_snapshot.json @@ -48,9 +48,7 @@ "indexes": { "email": { "name": "email", - "columns": [ - "email" - ], + "columns": ["email"], "isUnique": true } }, @@ -180,9 +178,7 @@ "indexes": { "global_customer_id": { "name": "global_customer_id", - "columns": [ - "customer_id" - ], + "columns": ["customer_id"], "isUnique": true } }, @@ -190,10 +186,7 @@ "compositePrimaryKeys": { "billing_workspace_id_id_pk": { "name": "billing_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -280,10 +273,7 @@ "compositePrimaryKeys": { "payment_workspace_id_id_pk": { "name": "payment_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -398,10 +388,7 @@ "compositePrimaryKeys": { "usage_workspace_id_id_pk": { "name": "usage_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -493,17 +480,12 @@ "indexes": { "global_key": { "name": "global_key", - "columns": [ - "key" - ], + "columns": ["key"], "isUnique": true }, "name": { "name": "name", - "columns": [ - "workspace_id", - "name" - ], + "columns": ["workspace_id", "name"], "isUnique": true } }, @@ -511,10 +493,7 @@ "compositePrimaryKeys": { "key_workspace_id_id_pk": { "name": "key_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -606,32 +585,22 @@ "indexes": { "user_account_id": { "name": "user_account_id", - "columns": [ - "workspace_id", - "account_id" - ], + "columns": ["workspace_id", "account_id"], "isUnique": true }, "user_email": { "name": "user_email", - "columns": [ - "workspace_id", - "email" - ], + "columns": ["workspace_id", "email"], "isUnique": true }, "global_account_id": { "name": "global_account_id", - "columns": [ - "account_id" - ], + "columns": ["account_id"], "isUnique": false }, "global_email": { "name": "global_email", - "columns": [ - "email" - ], + "columns": ["email"], "isUnique": false } }, @@ -639,10 +608,7 @@ "compositePrimaryKeys": { "user_workspace_id_id_pk": { "name": "user_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -699,9 +665,7 @@ "indexes": { "slug": { "name": "slug", - "columns": [ - "slug" - ], + "columns": ["slug"], "isUnique": true } }, @@ -709,9 +673,7 @@ "compositePrimaryKeys": { "workspace_id": { "name": "workspace_id", - "columns": [ - "id" - ] + "columns": ["id"] } }, "uniqueConstraints": {}, @@ -728,4 +690,4 @@ "tables": {}, "indexes": {} } -} \ No newline at end of file +} diff --git a/packages/console/core/migrations/meta/0026_snapshot.json b/packages/console/core/migrations/meta/0026_snapshot.json index 543ab44c..d3c7dc49 100644 --- a/packages/console/core/migrations/meta/0026_snapshot.json +++ b/packages/console/core/migrations/meta/0026_snapshot.json @@ -48,9 +48,7 @@ "indexes": { "email": { "name": "email", - "columns": [ - "email" - ], + "columns": ["email"], "isUnique": true } }, @@ -180,9 +178,7 @@ "indexes": { "global_customer_id": { "name": "global_customer_id", - "columns": [ - "customer_id" - ], + "columns": ["customer_id"], "isUnique": true } }, @@ -190,10 +186,7 @@ "compositePrimaryKeys": { "billing_workspace_id_id_pk": { "name": "billing_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -280,10 +273,7 @@ "compositePrimaryKeys": { "payment_workspace_id_id_pk": { "name": "payment_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -398,10 +388,7 @@ "compositePrimaryKeys": { "usage_workspace_id_id_pk": { "name": "usage_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -493,9 +480,7 @@ "indexes": { "global_key": { "name": "global_key", - "columns": [ - "key" - ], + "columns": ["key"], "isUnique": true } }, @@ -503,10 +488,7 @@ "compositePrimaryKeys": { "key_workspace_id_id_pk": { "name": "key_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -598,32 +580,22 @@ "indexes": { "user_account_id": { "name": "user_account_id", - "columns": [ - "workspace_id", - "account_id" - ], + "columns": ["workspace_id", "account_id"], "isUnique": true }, "user_email": { "name": "user_email", - "columns": [ - "workspace_id", - "email" - ], + "columns": ["workspace_id", "email"], "isUnique": true }, "global_account_id": { "name": "global_account_id", - "columns": [ - "account_id" - ], + "columns": ["account_id"], "isUnique": false }, "global_email": { "name": "global_email", - "columns": [ - "email" - ], + "columns": ["email"], "isUnique": false } }, @@ -631,10 +603,7 @@ "compositePrimaryKeys": { "user_workspace_id_id_pk": { "name": "user_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -691,9 +660,7 @@ "indexes": { "slug": { "name": "slug", - "columns": [ - "slug" - ], + "columns": ["slug"], "isUnique": true } }, @@ -701,9 +668,7 @@ "compositePrimaryKeys": { "workspace_id": { "name": "workspace_id", - "columns": [ - "id" - ] + "columns": ["id"] } }, "uniqueConstraints": {}, @@ -720,4 +685,4 @@ "tables": {}, "indexes": {} } -} \ No newline at end of file +} diff --git a/packages/console/core/migrations/meta/0027_snapshot.json b/packages/console/core/migrations/meta/0027_snapshot.json index 9b691022..408766f7 100644 --- a/packages/console/core/migrations/meta/0027_snapshot.json +++ b/packages/console/core/migrations/meta/0027_snapshot.json @@ -48,9 +48,7 @@ "indexes": { "email": { "name": "email", - "columns": [ - "email" - ], + "columns": ["email"], "isUnique": true } }, @@ -180,9 +178,7 @@ "indexes": { "global_customer_id": { "name": "global_customer_id", - "columns": [ - "customer_id" - ], + "columns": ["customer_id"], "isUnique": true } }, @@ -190,10 +186,7 @@ "compositePrimaryKeys": { "billing_workspace_id_id_pk": { "name": "billing_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -280,10 +273,7 @@ "compositePrimaryKeys": { "payment_workspace_id_id_pk": { "name": "payment_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -398,10 +388,7 @@ "compositePrimaryKeys": { "usage_workspace_id_id_pk": { "name": "usage_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -479,9 +466,7 @@ "indexes": { "global_key": { "name": "global_key", - "columns": [ - "key" - ], + "columns": ["key"], "isUnique": true } }, @@ -489,10 +474,7 @@ "compositePrimaryKeys": { "key_workspace_id_id_pk": { "name": "key_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -584,32 +566,22 @@ "indexes": { "user_account_id": { "name": "user_account_id", - "columns": [ - "workspace_id", - "account_id" - ], + "columns": ["workspace_id", "account_id"], "isUnique": true }, "user_email": { "name": "user_email", - "columns": [ - "workspace_id", - "email" - ], + "columns": ["workspace_id", "email"], "isUnique": true }, "global_account_id": { "name": "global_account_id", - "columns": [ - "account_id" - ], + "columns": ["account_id"], "isUnique": false }, "global_email": { "name": "global_email", - "columns": [ - "email" - ], + "columns": ["email"], "isUnique": false } }, @@ -617,10 +589,7 @@ "compositePrimaryKeys": { "user_workspace_id_id_pk": { "name": "user_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -677,9 +646,7 @@ "indexes": { "slug": { "name": "slug", - "columns": [ - "slug" - ], + "columns": ["slug"], "isUnique": true } }, @@ -687,9 +654,7 @@ "compositePrimaryKeys": { "workspace_id": { "name": "workspace_id", - "columns": [ - "id" - ] + "columns": ["id"] } }, "uniqueConstraints": {}, @@ -706,4 +671,4 @@ "tables": {}, "indexes": {} } -} \ No newline at end of file +} diff --git a/packages/console/core/migrations/meta/0028_snapshot.json b/packages/console/core/migrations/meta/0028_snapshot.json index 8242ae52..827cb53c 100644 --- a/packages/console/core/migrations/meta/0028_snapshot.json +++ b/packages/console/core/migrations/meta/0028_snapshot.json @@ -48,9 +48,7 @@ "indexes": { "email": { "name": "email", - "columns": [ - "email" - ], + "columns": ["email"], "isUnique": true } }, @@ -180,9 +178,7 @@ "indexes": { "global_customer_id": { "name": "global_customer_id", - "columns": [ - "customer_id" - ], + "columns": ["customer_id"], "isUnique": true } }, @@ -190,10 +186,7 @@ "compositePrimaryKeys": { "billing_workspace_id_id_pk": { "name": "billing_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -280,10 +273,7 @@ "compositePrimaryKeys": { "payment_workspace_id_id_pk": { "name": "payment_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -398,10 +388,7 @@ "compositePrimaryKeys": { "usage_workspace_id_id_pk": { "name": "usage_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -479,9 +466,7 @@ "indexes": { "global_key": { "name": "global_key", - "columns": [ - "key" - ], + "columns": ["key"], "isUnique": true } }, @@ -489,10 +474,7 @@ "compositePrimaryKeys": { "key_workspace_id_id_pk": { "name": "key_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -584,32 +566,22 @@ "indexes": { "user_account_id": { "name": "user_account_id", - "columns": [ - "workspace_id", - "account_id" - ], + "columns": ["workspace_id", "account_id"], "isUnique": true }, "user_email": { "name": "user_email", - "columns": [ - "workspace_id", - "email" - ], + "columns": ["workspace_id", "email"], "isUnique": true }, "global_account_id": { "name": "global_account_id", - "columns": [ - "account_id" - ], + "columns": ["account_id"], "isUnique": false }, "global_email": { "name": "global_email", - "columns": [ - "email" - ], + "columns": ["email"], "isUnique": false } }, @@ -617,10 +589,7 @@ "compositePrimaryKeys": { "user_workspace_id_id_pk": { "name": "user_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -677,9 +646,7 @@ "indexes": { "slug": { "name": "slug", - "columns": [ - "slug" - ], + "columns": ["slug"], "isUnique": true } }, @@ -687,9 +654,7 @@ "compositePrimaryKeys": { "workspace_id": { "name": "workspace_id", - "columns": [ - "id" - ] + "columns": ["id"] } }, "uniqueConstraints": {}, @@ -706,4 +671,4 @@ "tables": {}, "indexes": {} } -} \ No newline at end of file +} diff --git a/packages/console/core/migrations/meta/0029_snapshot.json b/packages/console/core/migrations/meta/0029_snapshot.json index 959004f3..d235697c 100644 --- a/packages/console/core/migrations/meta/0029_snapshot.json +++ b/packages/console/core/migrations/meta/0029_snapshot.json @@ -48,9 +48,7 @@ "indexes": { "email": { "name": "email", - "columns": [ - "email" - ], + "columns": ["email"], "isUnique": true } }, @@ -180,9 +178,7 @@ "indexes": { "global_customer_id": { "name": "global_customer_id", - "columns": [ - "customer_id" - ], + "columns": ["customer_id"], "isUnique": true } }, @@ -190,10 +186,7 @@ "compositePrimaryKeys": { "billing_workspace_id_id_pk": { "name": "billing_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -280,10 +273,7 @@ "compositePrimaryKeys": { "payment_workspace_id_id_pk": { "name": "payment_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -398,10 +388,7 @@ "compositePrimaryKeys": { "usage_workspace_id_id_pk": { "name": "usage_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -479,9 +466,7 @@ "indexes": { "global_key": { "name": "global_key", - "columns": [ - "key" - ], + "columns": ["key"], "isUnique": true } }, @@ -489,10 +474,7 @@ "compositePrimaryKeys": { "key_workspace_id_id_pk": { "name": "key_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -605,32 +587,22 @@ "indexes": { "user_account_id": { "name": "user_account_id", - "columns": [ - "workspace_id", - "account_id" - ], + "columns": ["workspace_id", "account_id"], "isUnique": true }, "user_email": { "name": "user_email", - "columns": [ - "workspace_id", - "email" - ], + "columns": ["workspace_id", "email"], "isUnique": true }, "global_account_id": { "name": "global_account_id", - "columns": [ - "account_id" - ], + "columns": ["account_id"], "isUnique": false }, "global_email": { "name": "global_email", - "columns": [ - "email" - ], + "columns": ["email"], "isUnique": false } }, @@ -638,10 +610,7 @@ "compositePrimaryKeys": { "user_workspace_id_id_pk": { "name": "user_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -698,9 +667,7 @@ "indexes": { "slug": { "name": "slug", - "columns": [ - "slug" - ], + "columns": ["slug"], "isUnique": true } }, @@ -708,9 +675,7 @@ "compositePrimaryKeys": { "workspace_id": { "name": "workspace_id", - "columns": [ - "id" - ] + "columns": ["id"] } }, "uniqueConstraints": {}, @@ -727,4 +692,4 @@ "tables": {}, "indexes": {} } -} \ No newline at end of file +} diff --git a/packages/console/core/migrations/meta/0030_snapshot.json b/packages/console/core/migrations/meta/0030_snapshot.json index 6a6eb38c..66978dfa 100644 --- a/packages/console/core/migrations/meta/0030_snapshot.json +++ b/packages/console/core/migrations/meta/0030_snapshot.json @@ -48,9 +48,7 @@ "indexes": { "email": { "name": "email", - "columns": [ - "email" - ], + "columns": ["email"], "isUnique": true } }, @@ -180,9 +178,7 @@ "indexes": { "global_customer_id": { "name": "global_customer_id", - "columns": [ - "customer_id" - ], + "columns": ["customer_id"], "isUnique": true } }, @@ -190,10 +186,7 @@ "compositePrimaryKeys": { "billing_workspace_id_id_pk": { "name": "billing_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -280,10 +273,7 @@ "compositePrimaryKeys": { "payment_workspace_id_id_pk": { "name": "payment_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -398,10 +388,7 @@ "compositePrimaryKeys": { "usage_workspace_id_id_pk": { "name": "usage_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -479,9 +466,7 @@ "indexes": { "global_key": { "name": "global_key", - "columns": [ - "key" - ], + "columns": ["key"], "isUnique": true } }, @@ -489,10 +474,7 @@ "compositePrimaryKeys": { "key_workspace_id_id_pk": { "name": "key_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -549,10 +531,7 @@ "indexes": { "model_workspace_model": { "name": "model_workspace_model", - "columns": [ - "workspace_id", - "model" - ], + "columns": ["workspace_id", "model"], "isUnique": true } }, @@ -560,10 +539,7 @@ "compositePrimaryKeys": { "model_workspace_id_id_pk": { "name": "model_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -676,32 +652,22 @@ "indexes": { "user_account_id": { "name": "user_account_id", - "columns": [ - "workspace_id", - "account_id" - ], + "columns": ["workspace_id", "account_id"], "isUnique": true }, "user_email": { "name": "user_email", - "columns": [ - "workspace_id", - "email" - ], + "columns": ["workspace_id", "email"], "isUnique": true }, "global_account_id": { "name": "global_account_id", - "columns": [ - "account_id" - ], + "columns": ["account_id"], "isUnique": false }, "global_email": { "name": "global_email", - "columns": [ - "email" - ], + "columns": ["email"], "isUnique": false } }, @@ -709,10 +675,7 @@ "compositePrimaryKeys": { "user_workspace_id_id_pk": { "name": "user_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -769,9 +732,7 @@ "indexes": { "slug": { "name": "slug", - "columns": [ - "slug" - ], + "columns": ["slug"], "isUnique": true } }, @@ -779,9 +740,7 @@ "compositePrimaryKeys": { "workspace_id": { "name": "workspace_id", - "columns": [ - "id" - ] + "columns": ["id"] } }, "uniqueConstraints": {}, @@ -798,4 +757,4 @@ "tables": {}, "indexes": {} } -} \ No newline at end of file +} diff --git a/packages/console/core/migrations/meta/0031_snapshot.json b/packages/console/core/migrations/meta/0031_snapshot.json index ba964881..c4716592 100644 --- a/packages/console/core/migrations/meta/0031_snapshot.json +++ b/packages/console/core/migrations/meta/0031_snapshot.json @@ -48,9 +48,7 @@ "indexes": { "email": { "name": "email", - "columns": [ - "email" - ], + "columns": ["email"], "isUnique": true } }, @@ -180,9 +178,7 @@ "indexes": { "global_customer_id": { "name": "global_customer_id", - "columns": [ - "customer_id" - ], + "columns": ["customer_id"], "isUnique": true } }, @@ -190,10 +186,7 @@ "compositePrimaryKeys": { "billing_workspace_id_id_pk": { "name": "billing_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -280,10 +273,7 @@ "compositePrimaryKeys": { "payment_workspace_id_id_pk": { "name": "payment_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -398,10 +388,7 @@ "compositePrimaryKeys": { "usage_workspace_id_id_pk": { "name": "usage_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -479,9 +466,7 @@ "indexes": { "global_key": { "name": "global_key", - "columns": [ - "key" - ], + "columns": ["key"], "isUnique": true } }, @@ -489,10 +474,7 @@ "compositePrimaryKeys": { "key_workspace_id_id_pk": { "name": "key_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -549,10 +531,7 @@ "indexes": { "model_workspace_model": { "name": "model_workspace_model", - "columns": [ - "workspace_id", - "model" - ], + "columns": ["workspace_id", "model"], "isUnique": true } }, @@ -560,10 +539,7 @@ "compositePrimaryKeys": { "model_workspace_id_id_pk": { "name": "model_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -627,10 +603,7 @@ "indexes": { "workspace_provider": { "name": "workspace_provider", - "columns": [ - "workspace_id", - "provider" - ], + "columns": ["workspace_id", "provider"], "isUnique": true } }, @@ -638,10 +611,7 @@ "compositePrimaryKeys": { "provider_workspace_id_id_pk": { "name": "provider_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -754,32 +724,22 @@ "indexes": { "user_account_id": { "name": "user_account_id", - "columns": [ - "workspace_id", - "account_id" - ], + "columns": ["workspace_id", "account_id"], "isUnique": true }, "user_email": { "name": "user_email", - "columns": [ - "workspace_id", - "email" - ], + "columns": ["workspace_id", "email"], "isUnique": true }, "global_account_id": { "name": "global_account_id", - "columns": [ - "account_id" - ], + "columns": ["account_id"], "isUnique": false }, "global_email": { "name": "global_email", - "columns": [ - "email" - ], + "columns": ["email"], "isUnique": false } }, @@ -787,10 +747,7 @@ "compositePrimaryKeys": { "user_workspace_id_id_pk": { "name": "user_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -847,9 +804,7 @@ "indexes": { "slug": { "name": "slug", - "columns": [ - "slug" - ], + "columns": ["slug"], "isUnique": true } }, @@ -857,9 +812,7 @@ "compositePrimaryKeys": { "workspace_id": { "name": "workspace_id", - "columns": [ - "id" - ] + "columns": ["id"] } }, "uniqueConstraints": {}, @@ -876,4 +829,4 @@ "tables": {}, "indexes": {} } -} \ No newline at end of file +} diff --git a/packages/console/core/migrations/meta/0032_snapshot.json b/packages/console/core/migrations/meta/0032_snapshot.json index 344fde6f..51e84a1d 100644 --- a/packages/console/core/migrations/meta/0032_snapshot.json +++ b/packages/console/core/migrations/meta/0032_snapshot.json @@ -48,9 +48,7 @@ "indexes": { "email": { "name": "email", - "columns": [ - "email" - ], + "columns": ["email"], "isUnique": true } }, @@ -180,9 +178,7 @@ "indexes": { "global_customer_id": { "name": "global_customer_id", - "columns": [ - "customer_id" - ], + "columns": ["customer_id"], "isUnique": true } }, @@ -190,10 +186,7 @@ "compositePrimaryKeys": { "billing_workspace_id_id_pk": { "name": "billing_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -280,10 +273,7 @@ "compositePrimaryKeys": { "payment_workspace_id_id_pk": { "name": "payment_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -405,10 +395,7 @@ "compositePrimaryKeys": { "usage_workspace_id_id_pk": { "name": "usage_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -486,9 +473,7 @@ "indexes": { "global_key": { "name": "global_key", - "columns": [ - "key" - ], + "columns": ["key"], "isUnique": true } }, @@ -496,10 +481,7 @@ "compositePrimaryKeys": { "key_workspace_id_id_pk": { "name": "key_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -556,10 +538,7 @@ "indexes": { "model_workspace_model": { "name": "model_workspace_model", - "columns": [ - "workspace_id", - "model" - ], + "columns": ["workspace_id", "model"], "isUnique": true } }, @@ -567,10 +546,7 @@ "compositePrimaryKeys": { "model_workspace_id_id_pk": { "name": "model_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -634,10 +610,7 @@ "indexes": { "workspace_provider": { "name": "workspace_provider", - "columns": [ - "workspace_id", - "provider" - ], + "columns": ["workspace_id", "provider"], "isUnique": true } }, @@ -645,10 +618,7 @@ "compositePrimaryKeys": { "provider_workspace_id_id_pk": { "name": "provider_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -761,32 +731,22 @@ "indexes": { "user_account_id": { "name": "user_account_id", - "columns": [ - "workspace_id", - "account_id" - ], + "columns": ["workspace_id", "account_id"], "isUnique": true }, "user_email": { "name": "user_email", - "columns": [ - "workspace_id", - "email" - ], + "columns": ["workspace_id", "email"], "isUnique": true }, "global_account_id": { "name": "global_account_id", - "columns": [ - "account_id" - ], + "columns": ["account_id"], "isUnique": false }, "global_email": { "name": "global_email", - "columns": [ - "email" - ], + "columns": ["email"], "isUnique": false } }, @@ -794,10 +754,7 @@ "compositePrimaryKeys": { "user_workspace_id_id_pk": { "name": "user_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -854,9 +811,7 @@ "indexes": { "slug": { "name": "slug", - "columns": [ - "slug" - ], + "columns": ["slug"], "isUnique": true } }, @@ -864,9 +819,7 @@ "compositePrimaryKeys": { "workspace_id": { "name": "workspace_id", - "columns": [ - "id" - ] + "columns": ["id"] } }, "uniqueConstraints": {}, @@ -883,4 +836,4 @@ "tables": {}, "indexes": {} } -} \ No newline at end of file +} diff --git a/packages/console/core/migrations/meta/0033_snapshot.json b/packages/console/core/migrations/meta/0033_snapshot.json index eb682adc..76d4720e 100644 --- a/packages/console/core/migrations/meta/0033_snapshot.json +++ b/packages/console/core/migrations/meta/0033_snapshot.json @@ -48,9 +48,7 @@ "indexes": { "email": { "name": "email", - "columns": [ - "email" - ], + "columns": ["email"], "isUnique": true } }, @@ -187,9 +185,7 @@ "indexes": { "global_customer_id": { "name": "global_customer_id", - "columns": [ - "customer_id" - ], + "columns": ["customer_id"], "isUnique": true } }, @@ -197,10 +193,7 @@ "compositePrimaryKeys": { "billing_workspace_id_id_pk": { "name": "billing_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -287,10 +280,7 @@ "compositePrimaryKeys": { "payment_workspace_id_id_pk": { "name": "payment_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -412,10 +402,7 @@ "compositePrimaryKeys": { "usage_workspace_id_id_pk": { "name": "usage_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -493,9 +480,7 @@ "indexes": { "global_key": { "name": "global_key", - "columns": [ - "key" - ], + "columns": ["key"], "isUnique": true } }, @@ -503,10 +488,7 @@ "compositePrimaryKeys": { "key_workspace_id_id_pk": { "name": "key_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -563,10 +545,7 @@ "indexes": { "model_workspace_model": { "name": "model_workspace_model", - "columns": [ - "workspace_id", - "model" - ], + "columns": ["workspace_id", "model"], "isUnique": true } }, @@ -574,10 +553,7 @@ "compositePrimaryKeys": { "model_workspace_id_id_pk": { "name": "model_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -641,10 +617,7 @@ "indexes": { "workspace_provider": { "name": "workspace_provider", - "columns": [ - "workspace_id", - "provider" - ], + "columns": ["workspace_id", "provider"], "isUnique": true } }, @@ -652,10 +625,7 @@ "compositePrimaryKeys": { "provider_workspace_id_id_pk": { "name": "provider_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -768,32 +738,22 @@ "indexes": { "user_account_id": { "name": "user_account_id", - "columns": [ - "workspace_id", - "account_id" - ], + "columns": ["workspace_id", "account_id"], "isUnique": true }, "user_email": { "name": "user_email", - "columns": [ - "workspace_id", - "email" - ], + "columns": ["workspace_id", "email"], "isUnique": true }, "global_account_id": { "name": "global_account_id", - "columns": [ - "account_id" - ], + "columns": ["account_id"], "isUnique": false }, "global_email": { "name": "global_email", - "columns": [ - "email" - ], + "columns": ["email"], "isUnique": false } }, @@ -801,10 +761,7 @@ "compositePrimaryKeys": { "user_workspace_id_id_pk": { "name": "user_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -861,9 +818,7 @@ "indexes": { "slug": { "name": "slug", - "columns": [ - "slug" - ], + "columns": ["slug"], "isUnique": true } }, @@ -871,9 +826,7 @@ "compositePrimaryKeys": { "workspace_id": { "name": "workspace_id", - "columns": [ - "id" - ] + "columns": ["id"] } }, "uniqueConstraints": {}, @@ -890,4 +843,4 @@ "tables": {}, "indexes": {} } -} \ No newline at end of file +} diff --git a/packages/console/core/migrations/meta/0034_snapshot.json b/packages/console/core/migrations/meta/0034_snapshot.json index 36acbdef..e9c999be 100644 --- a/packages/console/core/migrations/meta/0034_snapshot.json +++ b/packages/console/core/migrations/meta/0034_snapshot.json @@ -48,9 +48,7 @@ "indexes": { "email": { "name": "email", - "columns": [ - "email" - ], + "columns": ["email"], "isUnique": true } }, @@ -117,10 +115,7 @@ "indexes": { "provider": { "name": "provider", - "columns": [ - "provider", - "subject" - ], + "columns": ["provider", "subject"], "isUnique": true } }, @@ -257,9 +252,7 @@ "indexes": { "global_customer_id": { "name": "global_customer_id", - "columns": [ - "customer_id" - ], + "columns": ["customer_id"], "isUnique": true } }, @@ -267,10 +260,7 @@ "compositePrimaryKeys": { "billing_workspace_id_id_pk": { "name": "billing_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -357,10 +347,7 @@ "compositePrimaryKeys": { "payment_workspace_id_id_pk": { "name": "payment_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -482,10 +469,7 @@ "compositePrimaryKeys": { "usage_workspace_id_id_pk": { "name": "usage_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -563,9 +547,7 @@ "indexes": { "global_key": { "name": "global_key", - "columns": [ - "key" - ], + "columns": ["key"], "isUnique": true } }, @@ -573,10 +555,7 @@ "compositePrimaryKeys": { "key_workspace_id_id_pk": { "name": "key_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -633,10 +612,7 @@ "indexes": { "model_workspace_model": { "name": "model_workspace_model", - "columns": [ - "workspace_id", - "model" - ], + "columns": ["workspace_id", "model"], "isUnique": true } }, @@ -644,10 +620,7 @@ "compositePrimaryKeys": { "model_workspace_id_id_pk": { "name": "model_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -711,10 +684,7 @@ "indexes": { "workspace_provider": { "name": "workspace_provider", - "columns": [ - "workspace_id", - "provider" - ], + "columns": ["workspace_id", "provider"], "isUnique": true } }, @@ -722,10 +692,7 @@ "compositePrimaryKeys": { "provider_workspace_id_id_pk": { "name": "provider_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -838,32 +805,22 @@ "indexes": { "user_account_id": { "name": "user_account_id", - "columns": [ - "workspace_id", - "account_id" - ], + "columns": ["workspace_id", "account_id"], "isUnique": true }, "user_email": { "name": "user_email", - "columns": [ - "workspace_id", - "email" - ], + "columns": ["workspace_id", "email"], "isUnique": true }, "global_account_id": { "name": "global_account_id", - "columns": [ - "account_id" - ], + "columns": ["account_id"], "isUnique": false }, "global_email": { "name": "global_email", - "columns": [ - "email" - ], + "columns": ["email"], "isUnique": false } }, @@ -871,10 +828,7 @@ "compositePrimaryKeys": { "user_workspace_id_id_pk": { "name": "user_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -931,9 +885,7 @@ "indexes": { "slug": { "name": "slug", - "columns": [ - "slug" - ], + "columns": ["slug"], "isUnique": true } }, @@ -941,9 +893,7 @@ "compositePrimaryKeys": { "workspace_id": { "name": "workspace_id", - "columns": [ - "id" - ] + "columns": ["id"] } }, "uniqueConstraints": {}, @@ -960,4 +910,4 @@ "tables": {}, "indexes": {} } -} \ No newline at end of file +} diff --git a/packages/console/core/migrations/meta/0035_snapshot.json b/packages/console/core/migrations/meta/0035_snapshot.json index 7478337b..815d120e 100644 --- a/packages/console/core/migrations/meta/0035_snapshot.json +++ b/packages/console/core/migrations/meta/0035_snapshot.json @@ -102,17 +102,12 @@ "indexes": { "provider": { "name": "provider", - "columns": [ - "provider", - "subject" - ], + "columns": ["provider", "subject"], "isUnique": true }, "account_id": { "name": "account_id", - "columns": [ - "account_id" - ], + "columns": ["account_id"], "isUnique": false } }, @@ -249,9 +244,7 @@ "indexes": { "global_customer_id": { "name": "global_customer_id", - "columns": [ - "customer_id" - ], + "columns": ["customer_id"], "isUnique": true } }, @@ -259,10 +252,7 @@ "compositePrimaryKeys": { "billing_workspace_id_id_pk": { "name": "billing_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -349,10 +339,7 @@ "compositePrimaryKeys": { "payment_workspace_id_id_pk": { "name": "payment_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -474,10 +461,7 @@ "compositePrimaryKeys": { "usage_workspace_id_id_pk": { "name": "usage_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -555,9 +539,7 @@ "indexes": { "global_key": { "name": "global_key", - "columns": [ - "key" - ], + "columns": ["key"], "isUnique": true } }, @@ -565,10 +547,7 @@ "compositePrimaryKeys": { "key_workspace_id_id_pk": { "name": "key_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -625,10 +604,7 @@ "indexes": { "model_workspace_model": { "name": "model_workspace_model", - "columns": [ - "workspace_id", - "model" - ], + "columns": ["workspace_id", "model"], "isUnique": true } }, @@ -636,10 +612,7 @@ "compositePrimaryKeys": { "model_workspace_id_id_pk": { "name": "model_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -703,10 +676,7 @@ "indexes": { "workspace_provider": { "name": "workspace_provider", - "columns": [ - "workspace_id", - "provider" - ], + "columns": ["workspace_id", "provider"], "isUnique": true } }, @@ -714,10 +684,7 @@ "compositePrimaryKeys": { "provider_workspace_id_id_pk": { "name": "provider_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -830,32 +797,22 @@ "indexes": { "user_account_id": { "name": "user_account_id", - "columns": [ - "workspace_id", - "account_id" - ], + "columns": ["workspace_id", "account_id"], "isUnique": true }, "user_email": { "name": "user_email", - "columns": [ - "workspace_id", - "email" - ], + "columns": ["workspace_id", "email"], "isUnique": true }, "global_account_id": { "name": "global_account_id", - "columns": [ - "account_id" - ], + "columns": ["account_id"], "isUnique": false }, "global_email": { "name": "global_email", - "columns": [ - "email" - ], + "columns": ["email"], "isUnique": false } }, @@ -863,10 +820,7 @@ "compositePrimaryKeys": { "user_workspace_id_id_pk": { "name": "user_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -923,9 +877,7 @@ "indexes": { "slug": { "name": "slug", - "columns": [ - "slug" - ], + "columns": ["slug"], "isUnique": true } }, @@ -933,9 +885,7 @@ "compositePrimaryKeys": { "workspace_id": { "name": "workspace_id", - "columns": [ - "id" - ] + "columns": ["id"] } }, "uniqueConstraints": {}, @@ -952,4 +902,4 @@ "tables": {}, "indexes": {} } -} \ No newline at end of file +} diff --git a/packages/console/core/migrations/meta/0036_snapshot.json b/packages/console/core/migrations/meta/0036_snapshot.json index b030e30e..926b143e 100644 --- a/packages/console/core/migrations/meta/0036_snapshot.json +++ b/packages/console/core/migrations/meta/0036_snapshot.json @@ -43,9 +43,7 @@ "compositePrimaryKeys": { "account_id_pk": { "name": "account_id_pk", - "columns": [ - "id" - ] + "columns": ["id"] } }, "uniqueConstraints": {}, @@ -109,17 +107,12 @@ "indexes": { "provider": { "name": "provider", - "columns": [ - "provider", - "subject" - ], + "columns": ["provider", "subject"], "isUnique": true }, "account_id": { "name": "account_id", - "columns": [ - "account_id" - ], + "columns": ["account_id"], "isUnique": false } }, @@ -127,9 +120,7 @@ "compositePrimaryKeys": { "auth_id_pk": { "name": "auth_id_pk", - "columns": [ - "id" - ] + "columns": ["id"] } }, "uniqueConstraints": {}, @@ -263,9 +254,7 @@ "indexes": { "global_customer_id": { "name": "global_customer_id", - "columns": [ - "customer_id" - ], + "columns": ["customer_id"], "isUnique": true } }, @@ -273,10 +262,7 @@ "compositePrimaryKeys": { "billing_workspace_id_id_pk": { "name": "billing_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -363,10 +349,7 @@ "compositePrimaryKeys": { "payment_workspace_id_id_pk": { "name": "payment_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -488,10 +471,7 @@ "compositePrimaryKeys": { "usage_workspace_id_id_pk": { "name": "usage_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -569,9 +549,7 @@ "indexes": { "global_key": { "name": "global_key", - "columns": [ - "key" - ], + "columns": ["key"], "isUnique": true } }, @@ -579,10 +557,7 @@ "compositePrimaryKeys": { "key_workspace_id_id_pk": { "name": "key_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -639,10 +614,7 @@ "indexes": { "model_workspace_model": { "name": "model_workspace_model", - "columns": [ - "workspace_id", - "model" - ], + "columns": ["workspace_id", "model"], "isUnique": true } }, @@ -650,10 +622,7 @@ "compositePrimaryKeys": { "model_workspace_id_id_pk": { "name": "model_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -717,10 +686,7 @@ "indexes": { "workspace_provider": { "name": "workspace_provider", - "columns": [ - "workspace_id", - "provider" - ], + "columns": ["workspace_id", "provider"], "isUnique": true } }, @@ -728,10 +694,7 @@ "compositePrimaryKeys": { "provider_workspace_id_id_pk": { "name": "provider_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -844,32 +807,22 @@ "indexes": { "user_account_id": { "name": "user_account_id", - "columns": [ - "workspace_id", - "account_id" - ], + "columns": ["workspace_id", "account_id"], "isUnique": true }, "user_email": { "name": "user_email", - "columns": [ - "workspace_id", - "email" - ], + "columns": ["workspace_id", "email"], "isUnique": true }, "global_account_id": { "name": "global_account_id", - "columns": [ - "account_id" - ], + "columns": ["account_id"], "isUnique": false }, "global_email": { "name": "global_email", - "columns": [ - "email" - ], + "columns": ["email"], "isUnique": false } }, @@ -877,10 +830,7 @@ "compositePrimaryKeys": { "user_workspace_id_id_pk": { "name": "user_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -937,9 +887,7 @@ "indexes": { "slug": { "name": "slug", - "columns": [ - "slug" - ], + "columns": ["slug"], "isUnique": true } }, @@ -947,9 +895,7 @@ "compositePrimaryKeys": { "workspace_id": { "name": "workspace_id", - "columns": [ - "id" - ] + "columns": ["id"] } }, "uniqueConstraints": {}, @@ -966,4 +912,4 @@ "tables": {}, "indexes": {} } -} \ No newline at end of file +} diff --git a/packages/console/core/migrations/meta/0037_snapshot.json b/packages/console/core/migrations/meta/0037_snapshot.json index 690bae87..8a80ea52 100644 --- a/packages/console/core/migrations/meta/0037_snapshot.json +++ b/packages/console/core/migrations/meta/0037_snapshot.json @@ -43,9 +43,7 @@ "compositePrimaryKeys": { "account_id_pk": { "name": "account_id_pk", - "columns": [ - "id" - ] + "columns": ["id"] } }, "uniqueConstraints": {}, @@ -109,17 +107,12 @@ "indexes": { "provider": { "name": "provider", - "columns": [ - "provider", - "subject" - ], + "columns": ["provider", "subject"], "isUnique": true }, "account_id": { "name": "account_id", - "columns": [ - "account_id" - ], + "columns": ["account_id"], "isUnique": false } }, @@ -127,9 +120,7 @@ "compositePrimaryKeys": { "auth_id_pk": { "name": "auth_id_pk", - "columns": [ - "id" - ] + "columns": ["id"] } }, "uniqueConstraints": {}, @@ -277,9 +268,7 @@ "indexes": { "global_customer_id": { "name": "global_customer_id", - "columns": [ - "customer_id" - ], + "columns": ["customer_id"], "isUnique": true } }, @@ -287,10 +276,7 @@ "compositePrimaryKeys": { "billing_workspace_id_id_pk": { "name": "billing_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -377,10 +363,7 @@ "compositePrimaryKeys": { "payment_workspace_id_id_pk": { "name": "payment_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -502,10 +485,7 @@ "compositePrimaryKeys": { "usage_workspace_id_id_pk": { "name": "usage_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -583,9 +563,7 @@ "indexes": { "global_key": { "name": "global_key", - "columns": [ - "key" - ], + "columns": ["key"], "isUnique": true } }, @@ -593,10 +571,7 @@ "compositePrimaryKeys": { "key_workspace_id_id_pk": { "name": "key_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -653,10 +628,7 @@ "indexes": { "model_workspace_model": { "name": "model_workspace_model", - "columns": [ - "workspace_id", - "model" - ], + "columns": ["workspace_id", "model"], "isUnique": true } }, @@ -664,10 +636,7 @@ "compositePrimaryKeys": { "model_workspace_id_id_pk": { "name": "model_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -731,10 +700,7 @@ "indexes": { "workspace_provider": { "name": "workspace_provider", - "columns": [ - "workspace_id", - "provider" - ], + "columns": ["workspace_id", "provider"], "isUnique": true } }, @@ -742,10 +708,7 @@ "compositePrimaryKeys": { "provider_workspace_id_id_pk": { "name": "provider_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -858,32 +821,22 @@ "indexes": { "user_account_id": { "name": "user_account_id", - "columns": [ - "workspace_id", - "account_id" - ], + "columns": ["workspace_id", "account_id"], "isUnique": true }, "user_email": { "name": "user_email", - "columns": [ - "workspace_id", - "email" - ], + "columns": ["workspace_id", "email"], "isUnique": true }, "global_account_id": { "name": "global_account_id", - "columns": [ - "account_id" - ], + "columns": ["account_id"], "isUnique": false }, "global_email": { "name": "global_email", - "columns": [ - "email" - ], + "columns": ["email"], "isUnique": false } }, @@ -891,10 +844,7 @@ "compositePrimaryKeys": { "user_workspace_id_id_pk": { "name": "user_workspace_id_id_pk", - "columns": [ - "workspace_id", - "id" - ] + "columns": ["workspace_id", "id"] } }, "uniqueConstraints": {}, @@ -951,9 +901,7 @@ "indexes": { "slug": { "name": "slug", - "columns": [ - "slug" - ], + "columns": ["slug"], "isUnique": true } }, @@ -961,9 +909,7 @@ "compositePrimaryKeys": { "workspace_id": { "name": "workspace_id", - "columns": [ - "id" - ] + "columns": ["id"] } }, "uniqueConstraints": {}, @@ -980,4 +926,4 @@ "tables": {}, "indexes": {} } -} \ No newline at end of file +} diff --git a/packages/console/core/migrations/meta/_journal.json b/packages/console/core/migrations/meta/_journal.json index f2c6c6fc..250fe59b 100644 --- a/packages/console/core/migrations/meta/_journal.json +++ b/packages/console/core/migrations/meta/_journal.json @@ -269,4 +269,4 @@ "breakpoints": true } ] -} \ No newline at end of file +} diff --git a/packages/console/core/src/aws.ts b/packages/console/core/src/aws.ts index e87ada6e..ce4a20f4 100644 --- a/packages/console/core/src/aws.ts +++ b/packages/console/core/src/aws.ts @@ -24,37 +24,40 @@ export namespace AWS { body: z.string(), }), async (input) => { - const res = await createClient().fetch("https://email.us-east-1.amazonaws.com/v2/email/outbound-emails", { - method: "POST", - headers: { - "X-Amz-Target": "SES.SendEmail", - "Content-Type": "application/json", - }, - body: JSON.stringify({ - FromEmailAddress: `OpenCode Zen `, - Destination: { - ToAddresses: [input.to], + const res = await createClient().fetch( + "https://email.us-east-1.amazonaws.com/v2/email/outbound-emails", + { + method: "POST", + headers: { + "X-Amz-Target": "SES.SendEmail", + "Content-Type": "application/json", }, - Content: { - Simple: { - Subject: { - Charset: "UTF-8", - Data: input.subject, - }, - Body: { - Text: { + body: JSON.stringify({ + FromEmailAddress: `OpenCode Zen `, + Destination: { + ToAddresses: [input.to], + }, + Content: { + Simple: { + Subject: { Charset: "UTF-8", - Data: input.body, + Data: input.subject, }, - Html: { - Charset: "UTF-8", - Data: input.body, + Body: { + Text: { + Charset: "UTF-8", + Data: input.body, + }, + Html: { + Charset: "UTF-8", + Data: input.body, + }, }, }, }, - }, - }), - }) + }), + }, + ) if (!res.ok) { throw new Error(`Failed to send email: ${res.statusText}`) } diff --git a/packages/console/core/src/drizzle/index.ts b/packages/console/core/src/drizzle/index.ts index f0f065de..8b37b1f9 100644 --- a/packages/console/core/src/drizzle/index.ts +++ b/packages/console/core/src/drizzle/index.ts @@ -5,7 +5,10 @@ import { Client } from "@planetscale/database" import { MySqlTransaction, type MySqlTransactionConfig } from "drizzle-orm/mysql-core" import type { ExtractTablesWithRelations } from "drizzle-orm" -import type { PlanetScalePreparedQueryHKT, PlanetscaleQueryResultHKT } from "drizzle-orm/planetscale-serverless" +import type { + PlanetScalePreparedQueryHKT, + PlanetscaleQueryResultHKT, +} from "drizzle-orm/planetscale-serverless" import { Context } from "../context" import { memo } from "../util/memo" @@ -67,7 +70,10 @@ export namespace Database { } } - export async function transaction(callback: (tx: TxOrDb) => Promise, config?: MySqlTransactionConfig) { + export async function transaction( + callback: (tx: TxOrDb) => Promise, + config?: MySqlTransactionConfig, + ) { try { const { tx } = TransactionContext.use() return callback(tx) diff --git a/packages/console/core/src/key.ts b/packages/console/core/src/key.ts index 688f19b3..6396fd0b 100644 --- a/packages/console/core/src/key.ts +++ b/packages/console/core/src/key.ts @@ -20,8 +20,14 @@ export namespace Key { email: AuthTable.subject, }) .from(KeyTable) - .innerJoin(UserTable, and(eq(KeyTable.userID, UserTable.id), eq(KeyTable.workspaceID, UserTable.workspaceID))) - .innerJoin(AuthTable, and(eq(UserTable.accountID, AuthTable.accountID), eq(AuthTable.provider, "email"))) + .innerJoin( + UserTable, + and(eq(KeyTable.userID, UserTable.id), eq(KeyTable.workspaceID, UserTable.workspaceID)), + ) + .innerJoin( + AuthTable, + and(eq(UserTable.accountID, AuthTable.accountID), eq(AuthTable.provider, "email")), + ) .where( and( ...[ diff --git a/packages/console/core/src/provider.ts b/packages/console/core/src/provider.ts index cf2040b5..0af642f7 100644 --- a/packages/console/core/src/provider.ts +++ b/packages/console/core/src/provider.ts @@ -11,7 +11,9 @@ export namespace Provider { tx .select() .from(ProviderTable) - .where(and(eq(ProviderTable.workspaceID, Actor.workspace()), isNull(ProviderTable.timeDeleted))), + .where( + and(eq(ProviderTable.workspaceID, Actor.workspace()), isNull(ProviderTable.timeDeleted)), + ), ), ) @@ -50,7 +52,12 @@ export namespace Provider { return Database.transaction((tx) => tx .delete(ProviderTable) - .where(and(eq(ProviderTable.provider, provider), eq(ProviderTable.workspaceID, Actor.workspace()))), + .where( + and( + eq(ProviderTable.provider, provider), + eq(ProviderTable.workspaceID, Actor.workspace()), + ), + ), ) }, ) diff --git a/packages/console/core/src/schema/auth.sql.ts b/packages/console/core/src/schema/auth.sql.ts index 27c926d6..d55e605a 100644 --- a/packages/console/core/src/schema/auth.sql.ts +++ b/packages/console/core/src/schema/auth.sql.ts @@ -1,4 +1,11 @@ -import { index, mysqlEnum, mysqlTable, primaryKey, uniqueIndex, varchar } from "drizzle-orm/mysql-core" +import { + index, + mysqlEnum, + mysqlTable, + primaryKey, + uniqueIndex, + varchar, +} from "drizzle-orm/mysql-core" import { id, timestamps, ulid } from "../drizzle/types" export const AuthProvider = ["email", "github", "google"] as const diff --git a/packages/console/core/src/schema/model.sql.ts b/packages/console/core/src/schema/model.sql.ts index 1c032aad..343b0c4f 100644 --- a/packages/console/core/src/schema/model.sql.ts +++ b/packages/console/core/src/schema/model.sql.ts @@ -9,5 +9,8 @@ export const ModelTable = mysqlTable( ...timestamps, model: varchar("model", { length: 64 }).notNull(), }, - (table) => [...workspaceIndexes(table), uniqueIndex("model_workspace_model").on(table.workspaceID, table.model)], + (table) => [ + ...workspaceIndexes(table), + uniqueIndex("model_workspace_model").on(table.workspaceID, table.model), + ], ) diff --git a/packages/console/core/src/schema/provider.sql.ts b/packages/console/core/src/schema/provider.sql.ts index 11be5b4d..04d11e2e 100644 --- a/packages/console/core/src/schema/provider.sql.ts +++ b/packages/console/core/src/schema/provider.sql.ts @@ -10,5 +10,8 @@ export const ProviderTable = mysqlTable( provider: varchar("provider", { length: 64 }).notNull(), credentials: text("credentials").notNull(), }, - (table) => [...workspaceIndexes(table), uniqueIndex("workspace_provider").on(table.workspaceID, table.provider)], + (table) => [ + ...workspaceIndexes(table), + uniqueIndex("workspace_provider").on(table.workspaceID, table.provider), + ], ) diff --git a/packages/console/core/src/schema/user.sql.ts b/packages/console/core/src/schema/user.sql.ts index 7fd7f5e1..ce5b6c53 100644 --- a/packages/console/core/src/schema/user.sql.ts +++ b/packages/console/core/src/schema/user.sql.ts @@ -1,4 +1,12 @@ -import { mysqlTable, uniqueIndex, varchar, int, mysqlEnum, index, bigint } from "drizzle-orm/mysql-core" +import { + mysqlTable, + uniqueIndex, + varchar, + int, + mysqlEnum, + index, + bigint, +} from "drizzle-orm/mysql-core" import { timestamps, ulid, utc, workspaceColumns } from "../drizzle/types" import { workspaceIndexes } from "./workspace.sql" diff --git a/packages/console/core/src/user.ts b/packages/console/core/src/user.ts index 8b7a96f4..cbb1ac82 100644 --- a/packages/console/core/src/user.ts +++ b/packages/console/core/src/user.ts @@ -26,7 +26,10 @@ export namespace User { authEmail: AuthTable.subject, }) .from(UserTable) - .leftJoin(AuthTable, and(eq(UserTable.accountID, AuthTable.accountID), eq(AuthTable.provider, "email"))) + .leftJoin( + AuthTable, + and(eq(UserTable.accountID, AuthTable.accountID), eq(AuthTable.provider, "email")), + ) .where(and(eq(UserTable.workspaceID, Actor.workspace()), isNull(UserTable.timeDeleted))), ), ) @@ -36,7 +39,13 @@ export namespace User { tx .select() .from(UserTable) - .where(and(eq(UserTable.workspaceID, Actor.workspace()), eq(UserTable.id, id), isNull(UserTable.timeDeleted))) + .where( + and( + eq(UserTable.workspaceID, Actor.workspace()), + eq(UserTable.id, id), + isNull(UserTable.timeDeleted), + ), + ) .then((rows) => rows[0]), ), ) @@ -48,7 +57,10 @@ export namespace User { email: AuthTable.subject, }) .from(UserTable) - .leftJoin(AuthTable, and(eq(UserTable.accountID, AuthTable.accountID), eq(AuthTable.provider, "email"))) + .leftJoin( + AuthTable, + and(eq(UserTable.accountID, AuthTable.accountID), eq(AuthTable.provider, "email")), + ) .where(and(eq(UserTable.workspaceID, Actor.workspace()), eq(UserTable.id, id))) .then((rows) => rows[0]?.email), ), @@ -130,10 +142,16 @@ export namespace User { workspaceName: WorkspaceTable.name, }) .from(UserTable) - .innerJoin(AuthTable, and(eq(UserTable.accountID, AuthTable.accountID), eq(AuthTable.provider, "email"))) + .innerJoin( + AuthTable, + and(eq(UserTable.accountID, AuthTable.accountID), eq(AuthTable.provider, "email")), + ) .innerJoin(WorkspaceTable, eq(WorkspaceTable.id, workspaceID)) .where( - and(eq(UserTable.workspaceID, workspaceID), eq(UserTable.id, Actor.assert("user").properties.userID)), + and( + eq(UserTable.workspaceID, workspaceID), + eq(UserTable.id, Actor.assert("user").properties.userID), + ), ) .then((rows) => rows[0]), ) diff --git a/packages/console/core/sst-env.d.ts b/packages/console/core/sst-env.d.ts index 01407434..ba4c5a62 100644 --- a/packages/console/core/sst-env.d.ts +++ b/packages/console/core/sst-env.d.ts @@ -6,99 +6,99 @@ import "sst" declare module "sst" { export interface Resource { - "ADMIN_SECRET": { - "type": "sst.sst.Secret" - "value": string + ADMIN_SECRET: { + type: "sst.sst.Secret" + value: string } - "AUTH_API_URL": { - "type": "sst.sst.Linkable" - "value": string + AUTH_API_URL: { + type: "sst.sst.Linkable" + value: string } - "AWS_SES_ACCESS_KEY_ID": { - "type": "sst.sst.Secret" - "value": string + AWS_SES_ACCESS_KEY_ID: { + type: "sst.sst.Secret" + value: string } - "AWS_SES_SECRET_ACCESS_KEY": { - "type": "sst.sst.Secret" - "value": string + AWS_SES_SECRET_ACCESS_KEY: { + type: "sst.sst.Secret" + value: string } - "Console": { - "type": "sst.cloudflare.SolidStart" - "url": string + Console: { + type: "sst.cloudflare.SolidStart" + url: string } - "Database": { - "database": string - "host": string - "password": string - "port": number - "type": "sst.sst.Linkable" - "username": string + Database: { + database: string + host: string + password: string + port: number + type: "sst.sst.Linkable" + username: string } - "Desktop": { - "type": "sst.cloudflare.StaticSite" - "url": string + Desktop: { + type: "sst.cloudflare.StaticSite" + url: string } - "EMAILOCTOPUS_API_KEY": { - "type": "sst.sst.Secret" - "value": string + EMAILOCTOPUS_API_KEY: { + type: "sst.sst.Secret" + value: string } - "GITHUB_APP_ID": { - "type": "sst.sst.Secret" - "value": string + GITHUB_APP_ID: { + type: "sst.sst.Secret" + value: string } - "GITHUB_APP_PRIVATE_KEY": { - "type": "sst.sst.Secret" - "value": string + GITHUB_APP_PRIVATE_KEY: { + type: "sst.sst.Secret" + value: string } - "GITHUB_CLIENT_ID_CONSOLE": { - "type": "sst.sst.Secret" - "value": string + GITHUB_CLIENT_ID_CONSOLE: { + type: "sst.sst.Secret" + value: string } - "GITHUB_CLIENT_SECRET_CONSOLE": { - "type": "sst.sst.Secret" - "value": string + GITHUB_CLIENT_SECRET_CONSOLE: { + type: "sst.sst.Secret" + value: string } - "GOOGLE_CLIENT_ID": { - "type": "sst.sst.Secret" - "value": string + GOOGLE_CLIENT_ID: { + type: "sst.sst.Secret" + value: string } - "HONEYCOMB_API_KEY": { - "type": "sst.sst.Secret" - "value": string + HONEYCOMB_API_KEY: { + type: "sst.sst.Secret" + value: string } - "STRIPE_SECRET_KEY": { - "type": "sst.sst.Secret" - "value": string + STRIPE_SECRET_KEY: { + type: "sst.sst.Secret" + value: string } - "STRIPE_WEBHOOK_SECRET": { - "type": "sst.sst.Linkable" - "value": string + STRIPE_WEBHOOK_SECRET: { + type: "sst.sst.Linkable" + value: string } - "Web": { - "type": "sst.cloudflare.Astro" - "url": string + Web: { + type: "sst.cloudflare.Astro" + url: string } - "ZEN_MODELS1": { - "type": "sst.sst.Secret" - "value": string + ZEN_MODELS1: { + type: "sst.sst.Secret" + value: string } - "ZEN_MODELS2": { - "type": "sst.sst.Secret" - "value": string + ZEN_MODELS2: { + type: "sst.sst.Secret" + value: string } } } -// cloudflare -import * as cloudflare from "@cloudflare/workers-types"; +// cloudflare +import * as cloudflare from "@cloudflare/workers-types" declare module "sst" { export interface Resource { - "Api": cloudflare.Service - "AuthApi": cloudflare.Service - "AuthStorage": cloudflare.KVNamespace - "Bucket": cloudflare.R2Bucket - "LogProcessor": cloudflare.Service + Api: cloudflare.Service + AuthApi: cloudflare.Service + AuthStorage: cloudflare.KVNamespace + Bucket: cloudflare.R2Bucket + LogProcessor: cloudflare.Service } } import "sst" -export {} \ No newline at end of file +export {} diff --git a/packages/console/function/sst-env.d.ts b/packages/console/function/sst-env.d.ts index 01407434..ba4c5a62 100644 --- a/packages/console/function/sst-env.d.ts +++ b/packages/console/function/sst-env.d.ts @@ -6,99 +6,99 @@ import "sst" declare module "sst" { export interface Resource { - "ADMIN_SECRET": { - "type": "sst.sst.Secret" - "value": string + ADMIN_SECRET: { + type: "sst.sst.Secret" + value: string } - "AUTH_API_URL": { - "type": "sst.sst.Linkable" - "value": string + AUTH_API_URL: { + type: "sst.sst.Linkable" + value: string } - "AWS_SES_ACCESS_KEY_ID": { - "type": "sst.sst.Secret" - "value": string + AWS_SES_ACCESS_KEY_ID: { + type: "sst.sst.Secret" + value: string } - "AWS_SES_SECRET_ACCESS_KEY": { - "type": "sst.sst.Secret" - "value": string + AWS_SES_SECRET_ACCESS_KEY: { + type: "sst.sst.Secret" + value: string } - "Console": { - "type": "sst.cloudflare.SolidStart" - "url": string + Console: { + type: "sst.cloudflare.SolidStart" + url: string } - "Database": { - "database": string - "host": string - "password": string - "port": number - "type": "sst.sst.Linkable" - "username": string + Database: { + database: string + host: string + password: string + port: number + type: "sst.sst.Linkable" + username: string } - "Desktop": { - "type": "sst.cloudflare.StaticSite" - "url": string + Desktop: { + type: "sst.cloudflare.StaticSite" + url: string } - "EMAILOCTOPUS_API_KEY": { - "type": "sst.sst.Secret" - "value": string + EMAILOCTOPUS_API_KEY: { + type: "sst.sst.Secret" + value: string } - "GITHUB_APP_ID": { - "type": "sst.sst.Secret" - "value": string + GITHUB_APP_ID: { + type: "sst.sst.Secret" + value: string } - "GITHUB_APP_PRIVATE_KEY": { - "type": "sst.sst.Secret" - "value": string + GITHUB_APP_PRIVATE_KEY: { + type: "sst.sst.Secret" + value: string } - "GITHUB_CLIENT_ID_CONSOLE": { - "type": "sst.sst.Secret" - "value": string + GITHUB_CLIENT_ID_CONSOLE: { + type: "sst.sst.Secret" + value: string } - "GITHUB_CLIENT_SECRET_CONSOLE": { - "type": "sst.sst.Secret" - "value": string + GITHUB_CLIENT_SECRET_CONSOLE: { + type: "sst.sst.Secret" + value: string } - "GOOGLE_CLIENT_ID": { - "type": "sst.sst.Secret" - "value": string + GOOGLE_CLIENT_ID: { + type: "sst.sst.Secret" + value: string } - "HONEYCOMB_API_KEY": { - "type": "sst.sst.Secret" - "value": string + HONEYCOMB_API_KEY: { + type: "sst.sst.Secret" + value: string } - "STRIPE_SECRET_KEY": { - "type": "sst.sst.Secret" - "value": string + STRIPE_SECRET_KEY: { + type: "sst.sst.Secret" + value: string } - "STRIPE_WEBHOOK_SECRET": { - "type": "sst.sst.Linkable" - "value": string + STRIPE_WEBHOOK_SECRET: { + type: "sst.sst.Linkable" + value: string } - "Web": { - "type": "sst.cloudflare.Astro" - "url": string + Web: { + type: "sst.cloudflare.Astro" + url: string } - "ZEN_MODELS1": { - "type": "sst.sst.Secret" - "value": string + ZEN_MODELS1: { + type: "sst.sst.Secret" + value: string } - "ZEN_MODELS2": { - "type": "sst.sst.Secret" - "value": string + ZEN_MODELS2: { + type: "sst.sst.Secret" + value: string } } } -// cloudflare -import * as cloudflare from "@cloudflare/workers-types"; +// cloudflare +import * as cloudflare from "@cloudflare/workers-types" declare module "sst" { export interface Resource { - "Api": cloudflare.Service - "AuthApi": cloudflare.Service - "AuthStorage": cloudflare.KVNamespace - "Bucket": cloudflare.R2Bucket - "LogProcessor": cloudflare.Service + Api: cloudflare.Service + AuthApi: cloudflare.Service + AuthStorage: cloudflare.KVNamespace + Bucket: cloudflare.R2Bucket + LogProcessor: cloudflare.Service } } import "sst" -export {} \ No newline at end of file +export {} diff --git a/packages/console/mail/emails/templates/InviteEmail.tsx b/packages/console/mail/emails/templates/InviteEmail.tsx index baf0d383..e94eb564 100644 --- a/packages/console/mail/emails/templates/InviteEmail.tsx +++ b/packages/console/mail/emails/templates/InviteEmail.tsx @@ -1,6 +1,18 @@ // @ts-nocheck import React from "react" -import { Img, Row, Html, Link, Body, Head, Button, Column, Preview, Section, Container } from "@jsx-email/all" +import { + Img, + Row, + Html, + Link, + Body, + Head, + Button, + Column, + Preview, + Section, + Container, +} from "@jsx-email/all" import { Text, Fonts, Title, A, Span } from "../components" import { unit, @@ -52,8 +64,8 @@ export const InviteEmail = ({
    Join your team's OpenCode workspace - You have been invited by {inviter} to join the{" "} - {workspaceName} workspace on OpenCode. + You have been invited by {inviter} to join + the {workspaceName} workspace on OpenCode.
    @@ -61,7 +73,12 @@ export const InviteEmail = ({ diff --git a/packages/console/mail/sst-env.d.ts b/packages/console/mail/sst-env.d.ts index 9b9de732..bd558821 100644 --- a/packages/console/mail/sst-env.d.ts +++ b/packages/console/mail/sst-env.d.ts @@ -6,4 +6,4 @@ /// import "sst" -export {} \ No newline at end of file +export {} diff --git a/packages/console/resource/sst-env.d.ts b/packages/console/resource/sst-env.d.ts index 01407434..ba4c5a62 100644 --- a/packages/console/resource/sst-env.d.ts +++ b/packages/console/resource/sst-env.d.ts @@ -6,99 +6,99 @@ import "sst" declare module "sst" { export interface Resource { - "ADMIN_SECRET": { - "type": "sst.sst.Secret" - "value": string + ADMIN_SECRET: { + type: "sst.sst.Secret" + value: string } - "AUTH_API_URL": { - "type": "sst.sst.Linkable" - "value": string + AUTH_API_URL: { + type: "sst.sst.Linkable" + value: string } - "AWS_SES_ACCESS_KEY_ID": { - "type": "sst.sst.Secret" - "value": string + AWS_SES_ACCESS_KEY_ID: { + type: "sst.sst.Secret" + value: string } - "AWS_SES_SECRET_ACCESS_KEY": { - "type": "sst.sst.Secret" - "value": string + AWS_SES_SECRET_ACCESS_KEY: { + type: "sst.sst.Secret" + value: string } - "Console": { - "type": "sst.cloudflare.SolidStart" - "url": string + Console: { + type: "sst.cloudflare.SolidStart" + url: string } - "Database": { - "database": string - "host": string - "password": string - "port": number - "type": "sst.sst.Linkable" - "username": string + Database: { + database: string + host: string + password: string + port: number + type: "sst.sst.Linkable" + username: string } - "Desktop": { - "type": "sst.cloudflare.StaticSite" - "url": string + Desktop: { + type: "sst.cloudflare.StaticSite" + url: string } - "EMAILOCTOPUS_API_KEY": { - "type": "sst.sst.Secret" - "value": string + EMAILOCTOPUS_API_KEY: { + type: "sst.sst.Secret" + value: string } - "GITHUB_APP_ID": { - "type": "sst.sst.Secret" - "value": string + GITHUB_APP_ID: { + type: "sst.sst.Secret" + value: string } - "GITHUB_APP_PRIVATE_KEY": { - "type": "sst.sst.Secret" - "value": string + GITHUB_APP_PRIVATE_KEY: { + type: "sst.sst.Secret" + value: string } - "GITHUB_CLIENT_ID_CONSOLE": { - "type": "sst.sst.Secret" - "value": string + GITHUB_CLIENT_ID_CONSOLE: { + type: "sst.sst.Secret" + value: string } - "GITHUB_CLIENT_SECRET_CONSOLE": { - "type": "sst.sst.Secret" - "value": string + GITHUB_CLIENT_SECRET_CONSOLE: { + type: "sst.sst.Secret" + value: string } - "GOOGLE_CLIENT_ID": { - "type": "sst.sst.Secret" - "value": string + GOOGLE_CLIENT_ID: { + type: "sst.sst.Secret" + value: string } - "HONEYCOMB_API_KEY": { - "type": "sst.sst.Secret" - "value": string + HONEYCOMB_API_KEY: { + type: "sst.sst.Secret" + value: string } - "STRIPE_SECRET_KEY": { - "type": "sst.sst.Secret" - "value": string + STRIPE_SECRET_KEY: { + type: "sst.sst.Secret" + value: string } - "STRIPE_WEBHOOK_SECRET": { - "type": "sst.sst.Linkable" - "value": string + STRIPE_WEBHOOK_SECRET: { + type: "sst.sst.Linkable" + value: string } - "Web": { - "type": "sst.cloudflare.Astro" - "url": string + Web: { + type: "sst.cloudflare.Astro" + url: string } - "ZEN_MODELS1": { - "type": "sst.sst.Secret" - "value": string + ZEN_MODELS1: { + type: "sst.sst.Secret" + value: string } - "ZEN_MODELS2": { - "type": "sst.sst.Secret" - "value": string + ZEN_MODELS2: { + type: "sst.sst.Secret" + value: string } } } -// cloudflare -import * as cloudflare from "@cloudflare/workers-types"; +// cloudflare +import * as cloudflare from "@cloudflare/workers-types" declare module "sst" { export interface Resource { - "Api": cloudflare.Service - "AuthApi": cloudflare.Service - "AuthStorage": cloudflare.KVNamespace - "Bucket": cloudflare.R2Bucket - "LogProcessor": cloudflare.Service + Api: cloudflare.Service + AuthApi: cloudflare.Service + AuthStorage: cloudflare.KVNamespace + Bucket: cloudflare.R2Bucket + LogProcessor: cloudflare.Service } } import "sst" -export {} \ No newline at end of file +export {} diff --git a/packages/desktop/src/sst-env.d.ts b/packages/desktop/src/sst-env.d.ts index 47a8fbec..1b1683a1 100644 --- a/packages/desktop/src/sst-env.d.ts +++ b/packages/desktop/src/sst-env.d.ts @@ -2,9 +2,7 @@ /* tslint:disable */ /* eslint-disable */ /// -interface ImportMetaEnv { - -} +interface ImportMetaEnv {} interface ImportMeta { readonly env: ImportMetaEnv -} \ No newline at end of file +} diff --git a/packages/desktop/sst-env.d.ts b/packages/desktop/sst-env.d.ts index b6a7e906..0397645b 100644 --- a/packages/desktop/sst-env.d.ts +++ b/packages/desktop/sst-env.d.ts @@ -6,4 +6,4 @@ /// import "sst" -export {} \ No newline at end of file +export {} diff --git a/packages/function/src/api.ts b/packages/function/src/api.ts index 6f00dae9..3475f5d7 100644 --- a/packages/function/src/api.ts +++ b/packages/function/src/api.ts @@ -268,7 +268,11 @@ export default new Hono<{ Bindings: Env }>() // Verify permissions const userClient = new Octokit({ auth: token }) const { data: repoData } = await userClient.repos.get({ owner, repo }) - if (!repoData.permissions.admin && !repoData.permissions.push && !repoData.permissions.maintain) + if ( + !repoData.permissions.admin && + !repoData.permissions.push && + !repoData.permissions.maintain + ) throw new Error("User does not have write permissions") // Get installation token diff --git a/packages/function/sst-env.d.ts b/packages/function/sst-env.d.ts index 01407434..ba4c5a62 100644 --- a/packages/function/sst-env.d.ts +++ b/packages/function/sst-env.d.ts @@ -6,99 +6,99 @@ import "sst" declare module "sst" { export interface Resource { - "ADMIN_SECRET": { - "type": "sst.sst.Secret" - "value": string + ADMIN_SECRET: { + type: "sst.sst.Secret" + value: string } - "AUTH_API_URL": { - "type": "sst.sst.Linkable" - "value": string + AUTH_API_URL: { + type: "sst.sst.Linkable" + value: string } - "AWS_SES_ACCESS_KEY_ID": { - "type": "sst.sst.Secret" - "value": string + AWS_SES_ACCESS_KEY_ID: { + type: "sst.sst.Secret" + value: string } - "AWS_SES_SECRET_ACCESS_KEY": { - "type": "sst.sst.Secret" - "value": string + AWS_SES_SECRET_ACCESS_KEY: { + type: "sst.sst.Secret" + value: string } - "Console": { - "type": "sst.cloudflare.SolidStart" - "url": string + Console: { + type: "sst.cloudflare.SolidStart" + url: string } - "Database": { - "database": string - "host": string - "password": string - "port": number - "type": "sst.sst.Linkable" - "username": string + Database: { + database: string + host: string + password: string + port: number + type: "sst.sst.Linkable" + username: string } - "Desktop": { - "type": "sst.cloudflare.StaticSite" - "url": string + Desktop: { + type: "sst.cloudflare.StaticSite" + url: string } - "EMAILOCTOPUS_API_KEY": { - "type": "sst.sst.Secret" - "value": string + EMAILOCTOPUS_API_KEY: { + type: "sst.sst.Secret" + value: string } - "GITHUB_APP_ID": { - "type": "sst.sst.Secret" - "value": string + GITHUB_APP_ID: { + type: "sst.sst.Secret" + value: string } - "GITHUB_APP_PRIVATE_KEY": { - "type": "sst.sst.Secret" - "value": string + GITHUB_APP_PRIVATE_KEY: { + type: "sst.sst.Secret" + value: string } - "GITHUB_CLIENT_ID_CONSOLE": { - "type": "sst.sst.Secret" - "value": string + GITHUB_CLIENT_ID_CONSOLE: { + type: "sst.sst.Secret" + value: string } - "GITHUB_CLIENT_SECRET_CONSOLE": { - "type": "sst.sst.Secret" - "value": string + GITHUB_CLIENT_SECRET_CONSOLE: { + type: "sst.sst.Secret" + value: string } - "GOOGLE_CLIENT_ID": { - "type": "sst.sst.Secret" - "value": string + GOOGLE_CLIENT_ID: { + type: "sst.sst.Secret" + value: string } - "HONEYCOMB_API_KEY": { - "type": "sst.sst.Secret" - "value": string + HONEYCOMB_API_KEY: { + type: "sst.sst.Secret" + value: string } - "STRIPE_SECRET_KEY": { - "type": "sst.sst.Secret" - "value": string + STRIPE_SECRET_KEY: { + type: "sst.sst.Secret" + value: string } - "STRIPE_WEBHOOK_SECRET": { - "type": "sst.sst.Linkable" - "value": string + STRIPE_WEBHOOK_SECRET: { + type: "sst.sst.Linkable" + value: string } - "Web": { - "type": "sst.cloudflare.Astro" - "url": string + Web: { + type: "sst.cloudflare.Astro" + url: string } - "ZEN_MODELS1": { - "type": "sst.sst.Secret" - "value": string + ZEN_MODELS1: { + type: "sst.sst.Secret" + value: string } - "ZEN_MODELS2": { - "type": "sst.sst.Secret" - "value": string + ZEN_MODELS2: { + type: "sst.sst.Secret" + value: string } } } -// cloudflare -import * as cloudflare from "@cloudflare/workers-types"; +// cloudflare +import * as cloudflare from "@cloudflare/workers-types" declare module "sst" { export interface Resource { - "Api": cloudflare.Service - "AuthApi": cloudflare.Service - "AuthStorage": cloudflare.KVNamespace - "Bucket": cloudflare.R2Bucket - "LogProcessor": cloudflare.Service + Api: cloudflare.Service + AuthApi: cloudflare.Service + AuthStorage: cloudflare.KVNamespace + Bucket: cloudflare.R2Bucket + LogProcessor: cloudflare.Service } } import "sst" -export {} \ No newline at end of file +export {} diff --git a/packages/opencode/script/postinstall.mjs b/packages/opencode/script/postinstall.mjs index b875d158..41865273 100644 --- a/packages/opencode/script/postinstall.mjs +++ b/packages/opencode/script/postinstall.mjs @@ -77,7 +77,8 @@ async function regenerateWindowsCmdWrappers() { // npm_config_global is string | undefined // if it exists, the value is true - const isGlobal = process.env.npm_config_global === "true" || pkgPath.includes(path.join("npm", "node_modules")) + const isGlobal = + process.env.npm_config_global === "true" || pkgPath.includes(path.join("npm", "node_modules")) // The npm rebuild command does 2 things - Execute lifecycle scripts and rebuild bin links // We want to skip lifecycle scripts to avoid infinite loops, so we use --ignore-scripts @@ -93,7 +94,9 @@ async function regenerateWindowsCmdWrappers() { console.log("Successfully rebuilt npm bin links") } catch (error) { console.error("Error rebuilding npm links:", error.message) - console.error("npm rebuild failed. You may need to manually run: npm rebuild opencode-ai --ignore-scripts") + console.error( + "npm rebuild failed. You may need to manually run: npm rebuild opencode-ai --ignore-scripts", + ) } } diff --git a/packages/opencode/script/schema.ts b/packages/opencode/script/schema.ts index 585701c9..48bf6544 100755 --- a/packages/opencode/script/schema.ts +++ b/packages/opencode/script/schema.ts @@ -19,12 +19,23 @@ const result = z.toJSONSchema(Config.Info, { const schema = ctx.jsonSchema // Preserve strictness: set additionalProperties: false for objects - if (schema && typeof schema === "object" && schema.type === "object" && schema.additionalProperties === undefined) { + if ( + schema && + typeof schema === "object" && + schema.type === "object" && + schema.additionalProperties === undefined + ) { schema.additionalProperties = false } // Add examples and default descriptions for string fields with defaults - if (schema && typeof schema === "object" && "type" in schema && schema.type === "string" && schema?.default) { + if ( + schema && + typeof schema === "object" && + "type" in schema && + schema.type === "string" && + schema?.default + ) { if (!schema.examples) { schema.examples = [schema.default] } diff --git a/packages/opencode/src/agent/agent.ts b/packages/opencode/src/agent/agent.ts index a6933708..16f40162 100644 --- a/packages/opencode/src/agent/agent.ts +++ b/packages/opencode/src/agent/agent.ts @@ -143,7 +143,18 @@ export namespace Agent { tools: {}, builtIn: false, } - const { name, model, prompt, tools, description, temperature, top_p, mode, permission, ...extra } = value + const { + name, + model, + prompt, + tools, + description, + temperature, + top_p, + mode, + permission, + ...extra + } = value item.options = { ...item.options, ...extra, @@ -212,7 +223,10 @@ export namespace Agent { } } -function mergeAgentPermissions(basePermission: any, overridePermission: any): Agent.Info["permission"] { +function mergeAgentPermissions( + basePermission: any, + overridePermission: any, +): Agent.Info["permission"] { if (typeof basePermission.bash === "string") { basePermission.bash = { "*": basePermission.bash, diff --git a/packages/opencode/src/bus/index.ts b/packages/opencode/src/bus/index.ts index f4dd3ed2..c424eb87 100644 --- a/packages/opencode/src/bus/index.ts +++ b/packages/opencode/src/bus/index.ts @@ -19,7 +19,10 @@ export namespace Bus { const registry = new Map() - export function event(type: Type, properties: Properties) { + export function event( + type: Type, + properties: Properties, + ) { const result = { type, properties, @@ -70,7 +73,10 @@ export namespace Bus { export function subscribe( def: Definition, - callback: (event: { type: Definition["type"]; properties: z.infer }) => void, + callback: (event: { + type: Definition["type"] + properties: z.infer + }) => void, ) { return raw(def.type, callback) } diff --git a/packages/opencode/src/cli/cmd/auth.ts b/packages/opencode/src/cli/cmd/auth.ts index aa833e97..b4c47f0a 100644 --- a/packages/opencode/src/cli/cmd/auth.ts +++ b/packages/opencode/src/cli/cmd/auth.ts @@ -14,7 +14,11 @@ export const AuthCommand = cmd({ command: "auth", describe: "manage credentials", builder: (yargs) => - yargs.command(AuthLoginCommand).command(AuthLogoutCommand).command(AuthListCommand).demandCommand(), + yargs + .command(AuthLoginCommand) + .command(AuthLogoutCommand) + .command(AuthListCommand) + .demandCommand(), async handler() {}, }) @@ -60,7 +64,9 @@ export const AuthListCommand = cmd({ prompts.log.info(`${provider} ${UI.Style.TEXT_DIM}${envVar}`) } - prompts.outro(`${activeEnvVars.length} environment variable` + (activeEnvVars.length === 1 ? "" : "s")) + prompts.outro( + `${activeEnvVars.length} environment variable` + (activeEnvVars.length === 1 ? "" : "s"), + ) } }, }) @@ -80,7 +86,9 @@ export const AuthLoginCommand = cmd({ UI.empty() prompts.intro("Add credential") if (args.url) { - const wellknown = await fetch(`${args.url}/.well-known/opencode`).then((x) => x.json() as any) + const wellknown = await fetch(`${args.url}/.well-known/opencode`).then( + (x) => x.json() as any, + ) prompts.log.info(`Running \`${wellknown.auth.command.join(" ")}\``) const proc = Bun.spawn({ cmd: wellknown.auth.command, @@ -102,223 +110,224 @@ export const AuthLoginCommand = cmd({ prompts.outro("Done") return } - await ModelsDev.refresh().catch(() => {}) - const providers = await ModelsDev.get() - const priority: Record = { - opencode: 0, - anthropic: 1, - "github-copilot": 2, - openai: 3, - google: 4, - openrouter: 5, - vercel: 6, - } - let provider = await prompts.autocomplete({ - message: "Select provider", - maxItems: 8, - options: [ - ...pipe( - providers, - values(), - sortBy( - (x) => priority[x.id] ?? 99, - (x) => x.name ?? x.id, - ), - map((x) => ({ - label: x.name, - value: x.id, - hint: priority[x.id] <= 1 ? "recommended" : undefined, - })), - ), - { - value: "other", - label: "Other", - }, - ], - }) - - if (prompts.isCancel(provider)) throw new UI.CancelledError() - - const plugin = await Plugin.list().then((x) => x.find((x) => x.auth?.provider === provider)) - if (plugin && plugin.auth) { - let index = 0 - if (plugin.auth.methods.length > 1) { - const method = await prompts.select({ - message: "Login method", - options: [ - ...plugin.auth.methods.map((x, index) => ({ - label: x.label, - value: index.toString(), + await ModelsDev.refresh().catch(() => {}) + const providers = await ModelsDev.get() + const priority: Record = { + opencode: 0, + anthropic: 1, + "github-copilot": 2, + openai: 3, + google: 4, + openrouter: 5, + vercel: 6, + } + let provider = await prompts.autocomplete({ + message: "Select provider", + maxItems: 8, + options: [ + ...pipe( + providers, + values(), + sortBy( + (x) => priority[x.id] ?? 99, + (x) => x.name ?? x.id, + ), + map((x) => ({ + label: x.name, + value: x.id, + hint: priority[x.id] <= 1 ? "recommended" : undefined, })), - ], - }) - if (prompts.isCancel(method)) throw new UI.CancelledError() - index = parseInt(method) - } - const method = plugin.auth.methods[index] + ), + { + value: "other", + label: "Other", + }, + ], + }) - // Handle prompts for all auth types - await new Promise((resolve) => setTimeout(resolve, 10)) - const inputs: Record = {} - if (method.prompts) { - for (const prompt of method.prompts) { - if (prompt.condition && !prompt.condition(inputs)) { - continue - } - if (prompt.type === "select") { - const value = await prompts.select({ - message: prompt.message, - options: prompt.options, - }) - if (prompts.isCancel(value)) throw new UI.CancelledError() - inputs[prompt.key] = value - } else { - const value = await prompts.text({ - message: prompt.message, - placeholder: prompt.placeholder, - validate: prompt.validate ? (v) => prompt.validate!(v ?? "") : undefined, - }) - if (prompts.isCancel(value)) throw new UI.CancelledError() - inputs[prompt.key] = value - } - } - } + if (prompts.isCancel(provider)) throw new UI.CancelledError() - if (method.type === "oauth") { - const authorize = await method.authorize(inputs) - - if (authorize.url) { - prompts.log.info("Go to: " + authorize.url) - } - - if (authorize.method === "auto") { - if (authorize.instructions) { - prompts.log.info(authorize.instructions) - } - const spinner = prompts.spinner() - spinner.start("Waiting for authorization...") - const result = await authorize.callback() - if (result.type === "failed") { - spinner.stop("Failed to authorize", 1) - } - if (result.type === "success") { - const saveProvider = result.provider ?? provider - if ("refresh" in result) { - const { type: _, provider: __, refresh, access, expires, ...extraFields } = result - await Auth.set(saveProvider, { - type: "oauth", - refresh, - access, - expires, - ...extraFields, - }) - } - if ("key" in result) { - await Auth.set(saveProvider, { - type: "api", - key: result.key, - }) - } - spinner.stop("Login successful") - } - } - - if (authorize.method === "code") { - const code = await prompts.text({ - message: "Paste the authorization code here: ", - validate: (x) => (x && x.length > 0 ? undefined : "Required"), + const plugin = await Plugin.list().then((x) => x.find((x) => x.auth?.provider === provider)) + if (plugin && plugin.auth) { + let index = 0 + if (plugin.auth.methods.length > 1) { + const method = await prompts.select({ + message: "Login method", + options: [ + ...plugin.auth.methods.map((x, index) => ({ + label: x.label, + value: index.toString(), + })), + ], }) - if (prompts.isCancel(code)) throw new UI.CancelledError() - const result = await authorize.callback(code) - if (result.type === "failed") { - prompts.log.error("Failed to authorize") - } - if (result.type === "success") { - const saveProvider = result.provider ?? provider - if ("refresh" in result) { - const { type: _, provider: __, refresh, access, expires, ...extraFields } = result - await Auth.set(saveProvider, { - type: "oauth", - refresh, - access, - expires, - ...extraFields, - }) + if (prompts.isCancel(method)) throw new UI.CancelledError() + index = parseInt(method) + } + const method = plugin.auth.methods[index] + + // Handle prompts for all auth types + await new Promise((resolve) => setTimeout(resolve, 10)) + const inputs: Record = {} + if (method.prompts) { + for (const prompt of method.prompts) { + if (prompt.condition && !prompt.condition(inputs)) { + continue } - if ("key" in result) { + if (prompt.type === "select") { + const value = await prompts.select({ + message: prompt.message, + options: prompt.options, + }) + if (prompts.isCancel(value)) throw new UI.CancelledError() + inputs[prompt.key] = value + } else { + const value = await prompts.text({ + message: prompt.message, + placeholder: prompt.placeholder, + validate: prompt.validate ? (v) => prompt.validate!(v ?? "") : undefined, + }) + if (prompts.isCancel(value)) throw new UI.CancelledError() + inputs[prompt.key] = value + } + } + } + + if (method.type === "oauth") { + const authorize = await method.authorize(inputs) + + if (authorize.url) { + prompts.log.info("Go to: " + authorize.url) + } + + if (authorize.method === "auto") { + if (authorize.instructions) { + prompts.log.info(authorize.instructions) + } + const spinner = prompts.spinner() + spinner.start("Waiting for authorization...") + const result = await authorize.callback() + if (result.type === "failed") { + spinner.stop("Failed to authorize", 1) + } + if (result.type === "success") { + const saveProvider = result.provider ?? provider + if ("refresh" in result) { + const { type: _, provider: __, refresh, access, expires, ...extraFields } = result + await Auth.set(saveProvider, { + type: "oauth", + refresh, + access, + expires, + ...extraFields, + }) + } + if ("key" in result) { + await Auth.set(saveProvider, { + type: "api", + key: result.key, + }) + } + spinner.stop("Login successful") + } + } + + if (authorize.method === "code") { + const code = await prompts.text({ + message: "Paste the authorization code here: ", + validate: (x) => (x && x.length > 0 ? undefined : "Required"), + }) + if (prompts.isCancel(code)) throw new UI.CancelledError() + const result = await authorize.callback(code) + if (result.type === "failed") { + prompts.log.error("Failed to authorize") + } + if (result.type === "success") { + const saveProvider = result.provider ?? provider + if ("refresh" in result) { + const { type: _, provider: __, refresh, access, expires, ...extraFields } = result + await Auth.set(saveProvider, { + type: "oauth", + refresh, + access, + expires, + ...extraFields, + }) + } + if ("key" in result) { + await Auth.set(saveProvider, { + type: "api", + key: result.key, + }) + } + prompts.log.success("Login successful") + } + } + + prompts.outro("Done") + return + } + + if (method.type === "api") { + if (method.authorize) { + const result = await method.authorize(inputs) + if (result.type === "failed") { + prompts.log.error("Failed to authorize") + } + if (result.type === "success") { + const saveProvider = result.provider ?? provider await Auth.set(saveProvider, { type: "api", key: result.key, }) + prompts.log.success("Login successful") } - prompts.log.success("Login successful") + prompts.outro("Done") + return } } + } + if (provider === "other") { + provider = await prompts.text({ + message: "Enter provider id", + validate: (x) => + x && x.match(/^[0-9a-z-]+$/) ? undefined : "a-z, 0-9 and hyphens only", + }) + if (prompts.isCancel(provider)) throw new UI.CancelledError() + provider = provider.replace(/^@ai-sdk\//, "") + if (prompts.isCancel(provider)) throw new UI.CancelledError() + prompts.log.warn( + `This only stores a credential for ${provider} - you will need configure it in opencode.json, check the docs for examples.`, + ) + } + + if (provider === "amazon-bedrock") { + prompts.log.info( + "Amazon bedrock can be configured with standard AWS environment variables like AWS_BEARER_TOKEN_BEDROCK, AWS_PROFILE or AWS_ACCESS_KEY_ID", + ) prompts.outro("Done") return } - if (method.type === "api") { - if (method.authorize) { - const result = await method.authorize(inputs) - if (result.type === "failed") { - prompts.log.error("Failed to authorize") - } - if (result.type === "success") { - const saveProvider = result.provider ?? provider - await Auth.set(saveProvider, { - type: "api", - key: result.key, - }) - prompts.log.success("Login successful") - } - prompts.outro("Done") - return - } + if (provider === "opencode") { + prompts.log.info("Create an api key at https://opencode.ai/auth") } - } - if (provider === "other") { - provider = await prompts.text({ - message: "Enter provider id", - validate: (x) => (x && x.match(/^[0-9a-z-]+$/) ? undefined : "a-z, 0-9 and hyphens only"), + if (provider === "vercel") { + prompts.log.info("You can create an api key at https://vercel.link/ai-gateway-token") + } + + const key = await prompts.password({ + message: "Enter your API key", + validate: (x) => (x && x.length > 0 ? undefined : "Required"), + }) + if (prompts.isCancel(key)) throw new UI.CancelledError() + await Auth.set(provider, { + type: "api", + key, }) - if (prompts.isCancel(provider)) throw new UI.CancelledError() - provider = provider.replace(/^@ai-sdk\//, "") - if (prompts.isCancel(provider)) throw new UI.CancelledError() - prompts.log.warn( - `This only stores a credential for ${provider} - you will need configure it in opencode.json, check the docs for examples.`, - ) - } - if (provider === "amazon-bedrock") { - prompts.log.info( - "Amazon bedrock can be configured with standard AWS environment variables like AWS_BEARER_TOKEN_BEDROCK, AWS_PROFILE or AWS_ACCESS_KEY_ID", - ) prompts.outro("Done") - return - } - - if (provider === "opencode") { - prompts.log.info("Create an api key at https://opencode.ai/auth") - } - - if (provider === "vercel") { - prompts.log.info("You can create an api key at https://vercel.link/ai-gateway-token") - } - - const key = await prompts.password({ - message: "Enter your API key", - validate: (x) => (x && x.length > 0 ? undefined : "Required"), - }) - if (prompts.isCancel(key)) throw new UI.CancelledError() - await Auth.set(provider, { - type: "api", - key, - }) - - prompts.outro("Done") }, }) }, diff --git a/packages/opencode/src/cli/cmd/debug/lsp.ts b/packages/opencode/src/cli/cmd/debug/lsp.ts index 2f597719..8492395d 100644 --- a/packages/opencode/src/cli/cmd/debug/lsp.ts +++ b/packages/opencode/src/cli/cmd/debug/lsp.ts @@ -7,7 +7,11 @@ import { EOL } from "os" export const LSPCommand = cmd({ command: "lsp", builder: (yargs) => - yargs.command(DiagnosticsCommand).command(SymbolsCommand).command(DocumentSymbolsCommand).demandCommand(), + yargs + .command(DiagnosticsCommand) + .command(SymbolsCommand) + .command(DocumentSymbolsCommand) + .demandCommand(), async handler() {}, }) diff --git a/packages/opencode/src/cli/cmd/debug/ripgrep.ts b/packages/opencode/src/cli/cmd/debug/ripgrep.ts index 66cfba20..7c1d0d96 100644 --- a/packages/opencode/src/cli/cmd/debug/ripgrep.ts +++ b/packages/opencode/src/cli/cmd/debug/ripgrep.ts @@ -6,7 +6,8 @@ import { cmd } from "../cmd" export const RipgrepCommand = cmd({ command: "rg", - builder: (yargs) => yargs.command(TreeCommand).command(FilesCommand).command(SearchCommand).demandCommand(), + builder: (yargs) => + yargs.command(TreeCommand).command(FilesCommand).command(SearchCommand).demandCommand(), async handler() {}, }) @@ -18,7 +19,9 @@ const TreeCommand = cmd({ }), async handler(args) { await bootstrap(process.cwd(), async () => { - process.stdout.write(await Ripgrep.tree({ cwd: Instance.directory, limit: args.limit }) + EOL) + process.stdout.write( + (await Ripgrep.tree({ cwd: Instance.directory, limit: args.limit })) + EOL, + ) }) }, }) diff --git a/packages/opencode/src/cli/cmd/debug/snapshot.ts b/packages/opencode/src/cli/cmd/debug/snapshot.ts index 1849fe27..b114122b 100644 --- a/packages/opencode/src/cli/cmd/debug/snapshot.ts +++ b/packages/opencode/src/cli/cmd/debug/snapshot.ts @@ -4,7 +4,8 @@ import { cmd } from "../cmd" export const SnapshotCommand = cmd({ command: "snapshot", - builder: (yargs) => yargs.command(TrackCommand).command(PatchCommand).command(DiffCommand).demandCommand(), + builder: (yargs) => + yargs.command(TrackCommand).command(PatchCommand).command(DiffCommand).demandCommand(), async handler() {}, }) diff --git a/packages/opencode/src/cli/cmd/generate.ts b/packages/opencode/src/cli/cmd/generate.ts index 0cefb253..c29a22a8 100644 --- a/packages/opencode/src/cli/cmd/generate.ts +++ b/packages/opencode/src/cli/cmd/generate.ts @@ -6,7 +6,7 @@ export const GenerateCommand = { handler: async () => { const specs = await Server.openapi() const json = JSON.stringify(specs, null, 2) - + // Wait for stdout to finish writing before process.exit() is called await new Promise((resolve, reject) => { process.stdout.write(json, (err) => { diff --git a/packages/opencode/src/cli/cmd/github.ts b/packages/opencode/src/cli/cmd/github.ts index cd3ceb94..6fbeee2e 100644 --- a/packages/opencode/src/cli/cmd/github.ts +++ b/packages/opencode/src/cli/cmd/github.ts @@ -189,7 +189,9 @@ export const GithubInstallCommand = cmd({ async function getAppInfo() { const project = Instance.project if (project.vcs !== "git") { - prompts.log.error(`Could not find git repository. Please run this command from a git repository.`) + prompts.log.error( + `Could not find git repository. Please run this command from a git repository.`, + ) throw new UI.CancelledError() } @@ -202,9 +204,13 @@ export const GithubInstallCommand = cmd({ // ie. git@github.com:sst/opencode // ie. ssh://git@github.com/sst/opencode.git // ie. ssh://git@github.com/sst/opencode - const parsed = info.match(/^(?:(?:https?|ssh):\/\/)?(?:git@)?github\.com[:/]([^/]+)\/([^/.]+?)(?:\.git)?$/) + const parsed = info.match( + /^(?:(?:https?|ssh):\/\/)?(?:git@)?github\.com[:/]([^/]+)\/([^/.]+?)(?:\.git)?$/, + ) if (!parsed) { - prompts.log.error(`Could not find git repository. Please run this command from a git repository.`) + prompts.log.error( + `Could not find git repository. Please run this command from a git repository.`, + ) throw new UI.CancelledError() } const [, owner, repo] = parsed @@ -445,7 +451,9 @@ export const GithubRunCommand = cmd({ const summary = await summarize(response) await pushToLocalBranch(summary) } - const hasShared = prData.comments.nodes.some((c) => c.body.includes(`${shareBaseUrl}/s/${shareId}`)) + const hasShared = prData.comments.nodes.some((c) => + c.body.includes(`${shareBaseUrl}/s/${shareId}`), + ) await updateComment(`${response}${footer({ image: !hasShared })}`) } // Fork PR @@ -457,7 +465,9 @@ export const GithubRunCommand = cmd({ const summary = await summarize(response) await pushToForkBranch(summary, prData) } - const hasShared = prData.comments.nodes.some((c) => c.body.includes(`${shareBaseUrl}/s/${shareId}`)) + const hasShared = prData.comments.nodes.some((c) => + c.body.includes(`${shareBaseUrl}/s/${shareId}`), + ) await updateComment(`${response}${footer({ image: !hasShared })}`) } } @@ -547,8 +557,12 @@ export const GithubRunCommand = cmd({ // ie. Image // ie. [api.json](https://github.com/user-attachments/files/21433810/api.json) // ie. ![Image](https://github.com/user-attachments/assets/xxxx) - const mdMatches = prompt.matchAll(/!?\[.*?\]\((https:\/\/github\.com\/user-attachments\/[^)]+)\)/gi) - const tagMatches = prompt.matchAll(//gi) + const mdMatches = prompt.matchAll( + /!?\[.*?\]\((https:\/\/github\.com\/user-attachments\/[^)]+)\)/gi, + ) + const tagMatches = prompt.matchAll( + //gi, + ) const matches = [...mdMatches, ...tagMatches].sort((a, b) => a.index - b.index) console.log("Images", JSON.stringify(matches, null, 2)) @@ -573,7 +587,10 @@ export const GithubRunCommand = cmd({ // Replace img tag with file path, ie. @image.png const replacement = `@${filename}` - prompt = prompt.slice(0, start + offset) + replacement + prompt.slice(start + offset + tag.length) + prompt = + prompt.slice(0, start + offset) + + replacement + + prompt.slice(start + offset + tag.length) offset += replacement.length - tag.length const contentType = res.headers.get("content-type") @@ -856,7 +873,8 @@ Co-authored-by: ${actor} <${actor}@users.noreply.github.com>"` throw new Error(`Failed to check permissions for user ${actor}: ${error}`) } - if (!["admin", "write"].includes(permission)) throw new Error(`User ${actor} does not have write permissions`) + if (!["admin", "write"].includes(permission)) + throw new Error(`User ${actor} does not have write permissions`) } async function createComment() { @@ -904,7 +922,9 @@ Co-authored-by: ${actor} <${actor}@users.noreply.github.com>"` return `${titleAlt}\n` })() - const shareUrl = shareId ? `[opencode session](${shareBaseUrl}/s/${shareId})  |  ` : "" + const shareUrl = shareId + ? `[opencode session](${shareBaseUrl}/s/${shareId})  |  ` + : "" return `\n\n${image}${shareUrl}[github run](${runUrl})` } @@ -1080,9 +1100,13 @@ query($owner: String!, $repo: String!, $number: Int!) { }) .map((c) => `- ${c.author.login} at ${c.createdAt}: ${c.body}`) - const files = (pr.files.nodes || []).map((f) => `- ${f.path} (${f.changeType}) +${f.additions}/-${f.deletions}`) + const files = (pr.files.nodes || []).map( + (f) => `- ${f.path} (${f.changeType}) +${f.additions}/-${f.deletions}`, + ) const reviewData = (pr.reviews.nodes || []).map((r) => { - const comments = (r.comments.nodes || []).map((c) => ` - ${c.path}:${c.line ?? "?"}: ${c.body}`) + const comments = (r.comments.nodes || []).map( + (c) => ` - ${c.path}:${c.line ?? "?"}: ${c.body}`, + ) return [ `- ${r.author.login} at ${r.submittedAt}:`, ` - Review body: ${r.body}`, @@ -1104,9 +1128,15 @@ query($owner: String!, $repo: String!, $number: Int!) { `Deletions: ${pr.deletions}`, `Total Commits: ${pr.commits.totalCount}`, `Changed Files: ${pr.files.nodes.length} files`, - ...(comments.length > 0 ? ["", ...comments, ""] : []), - ...(files.length > 0 ? ["", ...files, ""] : []), - ...(reviewData.length > 0 ? ["", ...reviewData, ""] : []), + ...(comments.length > 0 + ? ["", ...comments, ""] + : []), + ...(files.length > 0 + ? ["", ...files, ""] + : []), + ...(reviewData.length > 0 + ? ["", ...reviewData, ""] + : []), "", ].join("\n") } diff --git a/packages/opencode/src/cli/cmd/run.ts b/packages/opencode/src/cli/cmd/run.ts index 39b0a55f..9add4bff 100644 --- a/packages/opencode/src/cli/cmd/run.ts +++ b/packages/opencode/src/cli/cmd/run.ts @@ -137,7 +137,9 @@ export const RunCommand = cmd({ const outputJsonEvent = (type: string, data: any) => { if (args.format === "json") { - process.stdout.write(JSON.stringify({ type, timestamp: Date.now(), sessionID, ...data }) + EOL) + process.stdout.write( + JSON.stringify({ type, timestamp: Date.now(), sessionID, ...data }) + EOL, + ) return true } return false @@ -157,7 +159,9 @@ export const RunCommand = cmd({ const [tool, color] = TOOL[part.tool] ?? [part.tool, UI.Style.TEXT_INFO_BOLD] const title = part.state.title || - (Object.keys(part.state.input).length > 0 ? JSON.stringify(part.state.input) : "Unknown") + (Object.keys(part.state.input).length > 0 + ? JSON.stringify(part.state.input) + : "Unknown") printEvent(color, tool, title) if (part.tool === "bash" && part.state.output?.trim()) { UI.println() @@ -280,7 +284,10 @@ export const RunCommand = cmd({ } const cfgResult = await sdk.config.get() - if (cfgResult.data && (cfgResult.data.share === "auto" || Flag.OPENCODE_AUTO_SHARE || args.share)) { + if ( + cfgResult.data && + (cfgResult.data.share === "auto" || Flag.OPENCODE_AUTO_SHARE || args.share) + ) { const shareResult = await sdk.session.share({ path: { id: sessionID } }).catch((error) => { if (error instanceof Error && error.message.includes("disabled")) { UI.println(UI.Style.TEXT_DANGER_BOLD + "! " + error.message) @@ -333,7 +340,10 @@ export const RunCommand = cmd({ } const cfgResult = await sdk.config.get() - if (cfgResult.data && (cfgResult.data.share === "auto" || Flag.OPENCODE_AUTO_SHARE || args.share)) { + if ( + cfgResult.data && + (cfgResult.data.share === "auto" || Flag.OPENCODE_AUTO_SHARE || args.share) + ) { const shareResult = await sdk.session.share({ path: { id: sessionID } }).catch((error) => { if (error instanceof Error && error.message.includes("disabled")) { UI.println(UI.Style.TEXT_DANGER_BOLD + "! " + error.message) diff --git a/packages/opencode/src/cli/cmd/tui/component/dialog-model.tsx b/packages/opencode/src/cli/cmd/tui/component/dialog-model.tsx index 04f2f652..15499599 100644 --- a/packages/opencode/src/cli/cmd/tui/component/dialog-model.tsx +++ b/packages/opencode/src/cli/cmd/tui/component/dialog-model.tsx @@ -52,7 +52,11 @@ export function DialogModel() { description: provider.name, category: provider.name, })), - filter((x) => Boolean(ref()?.filter) || !local.model.recent().find((y) => isDeepEqual(y, x.value))), + filter( + (x) => + Boolean(ref()?.filter) || + !local.model.recent().find((y) => isDeepEqual(y, x.value)), + ), ), ), ), diff --git a/packages/opencode/src/cli/cmd/tui/component/dialog-session-list.tsx b/packages/opencode/src/cli/cmd/tui/component/dialog-session-list.tsx index 95792ad8..dc770ce2 100644 --- a/packages/opencode/src/cli/cmd/tui/component/dialog-session-list.tsx +++ b/packages/opencode/src/cli/cmd/tui/component/dialog-session-list.tsx @@ -20,8 +20,8 @@ export function DialogSessionList() { const deleteKeybind = "ctrl+d" - const currentSessionID = createMemo(() => - route.data.type === "session" ? route.data.sessionID : undefined + const currentSessionID = createMemo(() => + route.data.type === "session" ? route.data.sessionID : undefined, ) const options = createMemo(() => { diff --git a/packages/opencode/src/cli/cmd/tui/component/logo.tsx b/packages/opencode/src/cli/cmd/tui/component/logo.tsx index 59db5fe7..7cac51ec 100644 --- a/packages/opencode/src/cli/cmd/tui/component/logo.tsx +++ b/packages/opencode/src/cli/cmd/tui/component/logo.tsx @@ -3,9 +3,19 @@ import { TextAttributes } from "@opentui/core" import { For } from "solid-js" import { useTheme } from "@tui/context/theme" -const LOGO_LEFT = [` `, `█▀▀█ █▀▀█ █▀▀█ █▀▀▄`, `█░░█ █░░█ █▀▀▀ █░░█`, `▀▀▀▀ █▀▀▀ ▀▀▀▀ ▀ ▀`] +const LOGO_LEFT = [ + ` `, + `█▀▀█ █▀▀█ █▀▀█ █▀▀▄`, + `█░░█ █░░█ █▀▀▀ █░░█`, + `▀▀▀▀ █▀▀▀ ▀▀▀▀ ▀ ▀`, +] -const LOGO_RIGHT = [` ▄ `, `█▀▀▀ █▀▀█ █▀▀█ █▀▀█`, `█░░░ █░░█ █░░█ █▀▀▀`, `▀▀▀▀ ▀▀▀▀ ▀▀▀▀ ▀▀▀▀`] +const LOGO_RIGHT = [ + ` ▄ `, + `█▀▀▀ █▀▀█ █▀▀█ █▀▀█`, + `█░░░ █░░█ █░░█ █▀▀▀`, + `▀▀▀▀ ▀▀▀▀ ▀▀▀▀ ▀▀▀▀`, +] export function Logo() { const { theme } = useTheme() diff --git a/packages/opencode/src/cli/cmd/tui/context/route.tsx b/packages/opencode/src/cli/cmd/tui/context/route.tsx index ef230dc9..dd8ede15 100644 --- a/packages/opencode/src/cli/cmd/tui/context/route.tsx +++ b/packages/opencode/src/cli/cmd/tui/context/route.tsx @@ -17,13 +17,11 @@ export const { use: useRoute, provider: RouteProvider } = createSimpleContext({ init: (props: { data?: Route }) => { const [store, setStore] = createStore( props.data ?? - ( - process.env["OPENCODE_ROUTE"] + (process.env["OPENCODE_ROUTE"] ? JSON.parse(process.env["OPENCODE_ROUTE"]) : { - type: "home", - } - ), + type: "home", + }), ) return { diff --git a/packages/opencode/src/cli/cmd/tui/context/sync.tsx b/packages/opencode/src/cli/cmd/tui/context/sync.tsx index 5d8f1dac..8ba73a4b 100644 --- a/packages/opencode/src/cli/cmd/tui/context/sync.tsx +++ b/packages/opencode/src/cli/cmd/tui/context/sync.tsx @@ -269,6 +269,7 @@ export const { use: useSync, provider: SyncProvider } = createSimpleContext({ }, async sync(sessionID: string) { const now = Date.now() + console.log("syncing", sessionID) const [session, messages, todo, diff] = await Promise.all([ sdk.client.session.get({ path: { id: sessionID }, throwOnError: true }), sdk.client.session.messages({ path: { id: sessionID } }), diff --git a/packages/opencode/src/cli/cmd/tui/context/theme/nightowl.json b/packages/opencode/src/cli/cmd/tui/context/theme/nightowl.json index 8eff42c5..24c74733 100644 --- a/packages/opencode/src/cli/cmd/tui/context/theme/nightowl.json +++ b/packages/opencode/src/cli/cmd/tui/context/theme/nightowl.json @@ -218,4 +218,4 @@ "light": "nightOwlFg" } } -} \ No newline at end of file +} diff --git a/packages/opencode/src/cli/cmd/tui/routes/session/dialog-message.tsx b/packages/opencode/src/cli/cmd/tui/routes/session/dialog-message.tsx index ee2b77af..cfdd4d69 100644 --- a/packages/opencode/src/cli/cmd/tui/routes/session/dialog-message.tsx +++ b/packages/opencode/src/cli/cmd/tui/routes/session/dialog-message.tsx @@ -7,7 +7,9 @@ import { useRoute } from "@tui/context/route" export function DialogMessage(props: { messageID: string; sessionID: string }) { const sync = useSync() const sdk = useSDK() - const message = createMemo(() => sync.data.message[props.sessionID]?.find((x) => x.id === props.messageID)) + const message = createMemo(() => + sync.data.message[props.sessionID]?.find((x) => x.id === props.messageID), + ) const route = useRoute() return ( diff --git a/packages/opencode/src/cli/cmd/tui/routes/session/dialog-timeline.tsx b/packages/opencode/src/cli/cmd/tui/routes/session/dialog-timeline.tsx index f5976cdf..b440ee1a 100644 --- a/packages/opencode/src/cli/cmd/tui/routes/session/dialog-timeline.tsx +++ b/packages/opencode/src/cli/cmd/tui/routes/session/dialog-timeline.tsx @@ -19,7 +19,9 @@ export function DialogTimeline(props: { sessionID: string; onMove: (messageID: s const result = [] as DialogSelectOption[] for (const message of messages) { if (message.role !== "user") continue - const part = (sync.data.part[message.id] ?? []).find((x) => x.type === "text" && !x.synthetic) as TextPart + const part = (sync.data.part[message.id] ?? []).find( + (x) => x.type === "text" && !x.synthetic, + ) as TextPart if (!part) continue result.push({ title: part.text.replace(/\n/g, " "), @@ -33,5 +35,11 @@ export function DialogTimeline(props: { sessionID: string; onMove: (messageID: s return result }) - return props.onMove(option.value)} title="Timeline" options={options()} /> + return ( + props.onMove(option.value)} + title="Timeline" + options={options()} + /> + ) } diff --git a/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx b/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx index 971ed817..7aa8ab2f 100644 --- a/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx +++ b/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx @@ -105,14 +105,15 @@ export function Session() { const sidebarVisible = createMemo(() => sidebar() === "show" || (sidebar() === "auto" && wide())) const contentWidth = createMemo(() => dimensions().width - (sidebarVisible() ? 42 : 0) - 4) - createEffect(() => { - sync.session.sync(route.sessionID).catch(() => { + createEffect(async () => { + await sync.session.sync(route.sessionID).catch(() => { toast.show({ message: `Session not found: ${route.sessionID}`, variant: "error", }) return navigate({ type: "home" }) }) + scroll.scrollBy(100_000) }) const toast = useToast() diff --git a/packages/opencode/src/cli/cmd/tui/spawn.ts b/packages/opencode/src/cli/cmd/tui/spawn.ts index 29c9a359..6a197513 100644 --- a/packages/opencode/src/cli/cmd/tui/spawn.ts +++ b/packages/opencode/src/cli/cmd/tui/spawn.ts @@ -41,7 +41,12 @@ export const TuiSpawnCommand = cmd({ ) cwd = new URL("../../../../", import.meta.url).pathname } else cmd.push(process.execPath) - cmd.push("attach", server.url.toString(), "--dir", args.project ? path.resolve(args.project) : process.cwd()) + cmd.push( + "attach", + server.url.toString(), + "--dir", + args.project ? path.resolve(args.project) : process.cwd(), + ) const proc = Bun.spawn({ cmd, cwd, diff --git a/packages/opencode/src/cli/cmd/tui/ui/dialog-confirm.tsx b/packages/opencode/src/cli/cmd/tui/ui/dialog-confirm.tsx index dd5b238b..f79ae055 100644 --- a/packages/opencode/src/cli/cmd/tui/ui/dialog-confirm.tsx +++ b/packages/opencode/src/cli/cmd/tui/ui/dialog-confirm.tsx @@ -53,7 +53,9 @@ export function DialogConfirm(props: DialogConfirmProps) { dialog.clear() }} > - {Locale.titlecase(key)} + + {Locale.titlecase(key)} + )} diff --git a/packages/opencode/src/cli/cmd/tui/util/editor.ts b/packages/opencode/src/cli/cmd/tui/util/editor.ts index 0aa69dcd..18a1400c 100644 --- a/packages/opencode/src/cli/cmd/tui/util/editor.ts +++ b/packages/opencode/src/cli/cmd/tui/util/editor.ts @@ -5,7 +5,10 @@ import { join } from "node:path" import { CliRenderer } from "@opentui/core" export namespace Editor { - export async function open(opts: { value: string; renderer: CliRenderer }): Promise { + export async function open(opts: { + value: string + renderer: CliRenderer + }): Promise { const editor = process.env["EDITOR"] if (!editor) return diff --git a/packages/opencode/src/cli/cmd/upgrade.ts b/packages/opencode/src/cli/cmd/upgrade.ts index 65f3bab4..f0ca4801 100644 --- a/packages/opencode/src/cli/cmd/upgrade.ts +++ b/packages/opencode/src/cli/cmd/upgrade.ts @@ -27,7 +27,9 @@ export const UpgradeCommand = { const detectedMethod = await Installation.method() const method = (args.method as Installation.Method) ?? detectedMethod if (method === "unknown") { - prompts.log.error(`opencode is installed to ${process.execPath} and may be managed by a package manager`) + prompts.log.error( + `opencode is installed to ${process.execPath} and may be managed by a package manager`, + ) const install = await prompts.select({ message: "Install anyways?", options: [ diff --git a/packages/opencode/src/config/config.ts b/packages/opencode/src/config/config.ts index efd31ccb..c2ee63c6 100644 --- a/packages/opencode/src/config/config.ts +++ b/packages/opencode/src/config/config.ts @@ -574,7 +574,10 @@ export namespace Config { .object({ apiKey: z.string().optional(), baseURL: z.string().optional(), - enterpriseUrl: z.string().optional().describe("GitHub Enterprise URL for copilot authentication"), + enterpriseUrl: z + .string() + .optional() + .describe("GitHub Enterprise URL for copilot authentication"), timeout: z .union([ z diff --git a/packages/opencode/src/file/fzf.ts b/packages/opencode/src/file/fzf.ts index cd0aa4fc..702688b1 100644 --- a/packages/opencode/src/file/fzf.ts +++ b/packages/opencode/src/file/fzf.ts @@ -81,7 +81,9 @@ export namespace Fzf { }) } if (config.extension === "zip") { - const zipFileReader = new ZipReader(new BlobReader(new Blob([await Bun.file(archivePath).arrayBuffer()]))) + const zipFileReader = new ZipReader( + new BlobReader(new Blob([await Bun.file(archivePath).arrayBuffer()])), + ) const entries = await zipFileReader.getEntries() let fzfEntry: any for (const entry of entries) { diff --git a/packages/opencode/src/file/ripgrep.ts b/packages/opencode/src/file/ripgrep.ts index 29014d19..84a45e38 100644 --- a/packages/opencode/src/file/ripgrep.ts +++ b/packages/opencode/src/file/ripgrep.ts @@ -161,7 +161,9 @@ export namespace Ripgrep { } if (config.extension === "zip") { if (config.extension === "zip") { - const zipFileReader = new ZipReader(new BlobReader(new Blob([await Bun.file(archivePath).arrayBuffer()]))) + const zipFileReader = new ZipReader( + new BlobReader(new Blob([await Bun.file(archivePath).arrayBuffer()])), + ) const entries = await zipFileReader.getEntries() let rgEntry: any for (const entry of entries) { @@ -354,7 +356,12 @@ export namespace Ripgrep { return lines.join("\n") } - export async function search(input: { cwd: string; pattern: string; glob?: string[]; limit?: number }) { + export async function search(input: { + cwd: string + pattern: string + glob?: string[] + limit?: number + }) { const args = [`${await filepath()}`, "--json", "--hidden", "--glob='!.git/*'"] if (input.glob) { diff --git a/packages/opencode/src/file/time.ts b/packages/opencode/src/file/time.ts index 5cba5e82..fe1dcff4 100644 --- a/packages/opencode/src/file/time.ts +++ b/packages/opencode/src/file/time.ts @@ -27,7 +27,10 @@ export namespace FileTime { export async function assert(sessionID: string, filepath: string) { const time = get(sessionID, filepath) - if (!time) throw new Error(`You must read the file ${filepath} before overwriting it. Use the Read tool first`) + if (!time) + throw new Error( + `You must read the file ${filepath} before overwriting it. Use the Read tool first`, + ) const stats = await Bun.file(filepath).stat() if (stats.mtime.getTime() > time.getTime()) { throw new Error( diff --git a/packages/opencode/src/file/watcher.ts b/packages/opencode/src/file/watcher.ts index d5985b58..e9304af7 100644 --- a/packages/opencode/src/file/watcher.ts +++ b/packages/opencode/src/file/watcher.ts @@ -51,8 +51,10 @@ export namespace FileWatcher { for (const evt of evts) { log.info("event", evt) if (evt.type === "create") Bus.publish(Event.Updated, { file: evt.path, event: "add" }) - if (evt.type === "update") Bus.publish(Event.Updated, { file: evt.path, event: "change" }) - if (evt.type === "delete") Bus.publish(Event.Updated, { file: evt.path, event: "unlink" }) + if (evt.type === "update") + Bus.publish(Event.Updated, { file: evt.path, event: "change" }) + if (evt.type === "delete") + Bus.publish(Event.Updated, { file: evt.path, event: "unlink" }) } }, { diff --git a/packages/opencode/src/id/id.ts b/packages/opencode/src/id/id.ts index 99eb6c9f..76b6a46b 100644 --- a/packages/opencode/src/id/id.ts +++ b/packages/opencode/src/id/id.ts @@ -49,7 +49,11 @@ export namespace Identifier { return result } - export function create(prefix: keyof typeof prefixes, descending: boolean, timestamp?: number): string { + export function create( + prefix: keyof typeof prefixes, + descending: boolean, + timestamp?: number, + ): string { const currentTimestamp = timestamp ?? Date.now() if (currentTimestamp !== lastTimestamp) { diff --git a/packages/opencode/src/lsp/client.ts b/packages/opencode/src/lsp/client.ts index 1a6e2cb7..920cecc6 100644 --- a/packages/opencode/src/lsp/client.ts +++ b/packages/opencode/src/lsp/client.ts @@ -1,5 +1,9 @@ import path from "path" -import { createMessageConnection, StreamMessageReader, StreamMessageWriter } from "vscode-jsonrpc/node" +import { + createMessageConnection, + StreamMessageReader, + StreamMessageWriter, +} from "vscode-jsonrpc/node" import type { Diagnostic as VSCodeDiagnostic } from "vscode-languageserver-types" import { Log } from "../util/log" import { LANGUAGE_EXTENSIONS } from "./language" @@ -34,7 +38,11 @@ export namespace LSPClient { ), } - export async function create(input: { serverID: string; server: LSPServer.Handle; root: string }) { + export async function create(input: { + serverID: string + server: LSPServer.Handle + root: string + }) { const l = log.clone().tag("serverID", input.serverID) l.info("starting client") @@ -129,7 +137,9 @@ export namespace LSPClient { }, notify: { async open(input: { path: string }) { - input.path = path.isAbsolute(input.path) ? input.path : path.resolve(Instance.directory, input.path) + input.path = path.isAbsolute(input.path) + ? input.path + : path.resolve(Instance.directory, input.path) const file = Bun.file(input.path) const text = await file.text() const extension = path.extname(input.path) @@ -171,13 +181,18 @@ export namespace LSPClient { return diagnostics }, async waitForDiagnostics(input: { path: string }) { - input.path = path.isAbsolute(input.path) ? input.path : path.resolve(Instance.directory, input.path) + input.path = path.isAbsolute(input.path) + ? input.path + : path.resolve(Instance.directory, input.path) log.info("waiting for diagnostics", input) let unsub: () => void return await withTimeout( new Promise((resolve) => { unsub = Bus.subscribe(Event.Diagnostics, (event) => { - if (event.properties.path === input.path && event.properties.serverID === result.serverID) { + if ( + event.properties.path === input.path && + event.properties.serverID === result.serverID + ) { log.info("got diagnostics", input) unsub?.() resolve() diff --git a/packages/opencode/src/patch/index.ts b/packages/opencode/src/patch/index.ts index c6e25c5c..46467e0b 100644 --- a/packages/opencode/src/patch/index.ts +++ b/packages/opencode/src/patch/index.ts @@ -20,7 +20,7 @@ export namespace Patch { workdir?: string } - export type Hunk = + export type Hunk = | { type: "add"; path: string; contents: string } | { type: "delete"; path: string } | { type: "update"; path: string; move_path?: string; chunks: UpdateFileChunk[] } @@ -71,60 +71,66 @@ export namespace Patch { } // Parser implementation - function parsePatchHeader(lines: string[], startIdx: number): { filePath: string; movePath?: string; nextIdx: number } | null { + function parsePatchHeader( + lines: string[], + startIdx: number, + ): { filePath: string; movePath?: string; nextIdx: number } | null { const line = lines[startIdx] - + if (line.startsWith("*** Add File:")) { const filePath = line.split(":", 2)[1]?.trim() return filePath ? { filePath, nextIdx: startIdx + 1 } : null } - + if (line.startsWith("*** Delete File:")) { const filePath = line.split(":", 2)[1]?.trim() return filePath ? { filePath, nextIdx: startIdx + 1 } : null } - + if (line.startsWith("*** Update File:")) { const filePath = line.split(":", 2)[1]?.trim() let movePath: string | undefined let nextIdx = startIdx + 1 - + // Check for move directive if (nextIdx < lines.length && lines[nextIdx].startsWith("*** Move to:")) { movePath = lines[nextIdx].split(":", 2)[1]?.trim() nextIdx++ } - + return filePath ? { filePath, movePath, nextIdx } : null } - + return null } - function parseUpdateFileChunks(lines: string[], startIdx: number): { chunks: UpdateFileChunk[]; nextIdx: number } { + function parseUpdateFileChunks( + lines: string[], + startIdx: number, + ): { chunks: UpdateFileChunk[]; nextIdx: number } { const chunks: UpdateFileChunk[] = [] let i = startIdx - + while (i < lines.length && !lines[i].startsWith("***")) { if (lines[i].startsWith("@@")) { // Parse context line const contextLine = lines[i].substring(2).trim() i++ - + const oldLines: string[] = [] const newLines: string[] = [] let isEndOfFile = false - + // Parse change lines while (i < lines.length && !lines[i].startsWith("@@") && !lines[i].startsWith("***")) { const changeLine = lines[i] - + if (changeLine === "*** End of File") { isEndOfFile = true i++ break } - + if (changeLine.startsWith(" ")) { // Keep line - appears in both old and new const content = changeLine.substring(1) @@ -137,10 +143,10 @@ export namespace Patch { // Add line - only in new newLines.push(changeLine.substring(1)) } - + i++ } - + chunks.push({ old_lines: oldLines, new_lines: newLines, @@ -151,26 +157,29 @@ export namespace Patch { i++ } } - + return { chunks, nextIdx: i } } - function parseAddFileContent(lines: string[], startIdx: number): { content: string; nextIdx: number } { + function parseAddFileContent( + lines: string[], + startIdx: number, + ): { content: string; nextIdx: number } { let content = "" let i = startIdx - + while (i < lines.length && !lines[i].startsWith("***")) { if (lines[i].startsWith("+")) { content += lines[i].substring(1) + "\n" } i++ } - + // Remove trailing newline if (content.endsWith("\n")) { content = content.slice(0, -1) } - + return { content, nextIdx: i } } @@ -178,28 +187,28 @@ export namespace Patch { const lines = patchText.split("\n") const hunks: Hunk[] = [] let i = 0 - + // Look for Begin/End patch markers const beginMarker = "*** Begin Patch" const endMarker = "*** End Patch" - - const beginIdx = lines.findIndex(line => line.trim() === beginMarker) - const endIdx = lines.findIndex(line => line.trim() === endMarker) - + + const beginIdx = lines.findIndex((line) => line.trim() === beginMarker) + const endIdx = lines.findIndex((line) => line.trim() === endMarker) + if (beginIdx === -1 || endIdx === -1 || beginIdx >= endIdx) { throw new Error("Invalid patch format: missing Begin/End markers") } - + // Parse content between markers i = beginIdx + 1 - + while (i < endIdx) { const header = parsePatchHeader(lines, i) if (!header) { i++ continue } - + if (lines[i].startsWith("*** Add File:")) { const { content, nextIdx } = parseAddFileContent(lines, header.nextIdx) hunks.push({ @@ -227,18 +236,19 @@ export namespace Patch { i++ } } - + return { hunks } } // Apply patch functionality - export function maybeParseApplyPatch(argv: string[]): + export function maybeParseApplyPatch( + argv: string[], + ): | { type: MaybeApplyPatch.Body; args: ApplyPatchArgs } | { type: MaybeApplyPatch.PatchParseError; error: Error } | { type: MaybeApplyPatch.NotApplyPatch } { - const APPLY_PATCH_COMMANDS = ["apply_patch", "applypatch"] - + // Direct invocation: apply_patch if (argv.length === 2 && APPLY_PATCH_COMMANDS.includes(argv[0])) { try { @@ -257,13 +267,13 @@ export namespace Patch { } } } - + // Bash heredoc form: bash -lc 'apply_patch <<"EOF" ...' if (argv.length === 3 && argv[0] === "bash" && argv[1] === "-lc") { // Simple extraction - in real implementation would need proper bash parsing const script = argv[2] const heredocMatch = script.match(/apply_patch\s*<<['"](\w+)['"]\s*\n([\s\S]*?)\n\1/) - + if (heredocMatch) { const patchContent = heredocMatch[2] try { @@ -283,7 +293,7 @@ export namespace Patch { } } } - + return { type: MaybeApplyPatch.NotApplyPatch } } @@ -293,7 +303,10 @@ export namespace Patch { content: string } - export function deriveNewContentsFromChunks(filePath: string, chunks: UpdateFileChunk[]): ApplyPatchFileUpdate { + export function deriveNewContentsFromChunks( + filePath: string, + chunks: UpdateFileChunk[], + ): ApplyPatchFileUpdate { // Read original file content let originalContent: string try { @@ -301,37 +314,41 @@ export namespace Patch { } catch (error) { throw new Error(`Failed to read file ${filePath}: ${error}`) } - + let originalLines = originalContent.split("\n") - + // Drop trailing empty element for consistent line counting if (originalLines.length > 0 && originalLines[originalLines.length - 1] === "") { originalLines.pop() } - + const replacements = computeReplacements(originalLines, filePath, chunks) let newLines = applyReplacements(originalLines, replacements) - + // Ensure trailing newline if (newLines.length === 0 || newLines[newLines.length - 1] !== "") { newLines.push("") } - + const newContent = newLines.join("\n") - + // Generate unified diff const unifiedDiff = generateUnifiedDiff(originalContent, newContent) - + return { unified_diff: unifiedDiff, content: newContent, } } - function computeReplacements(originalLines: string[], filePath: string, chunks: UpdateFileChunk[]): Array<[number, number, string[]]> { + function computeReplacements( + originalLines: string[], + filePath: string, + chunks: UpdateFileChunk[], + ): Array<[number, number, string[]]> { const replacements: Array<[number, number, string[]]> = [] let lineIndex = 0 - + for (const chunk of chunks) { // Handle context-based seeking if (chunk.change_context) { @@ -341,21 +358,22 @@ export namespace Patch { } lineIndex = contextIdx + 1 } - + // Handle pure addition (no old lines) if (chunk.old_lines.length === 0) { - const insertionIdx = originalLines.length > 0 && originalLines[originalLines.length - 1] === "" - ? originalLines.length - 1 - : originalLines.length + const insertionIdx = + originalLines.length > 0 && originalLines[originalLines.length - 1] === "" + ? originalLines.length - 1 + : originalLines.length replacements.push([insertionIdx, 0, chunk.new_lines]) continue } - + // Try to match old lines in the file let pattern = chunk.old_lines let newSlice = chunk.new_lines let found = seekSequence(originalLines, pattern, lineIndex) - + // Retry without trailing empty line if not found if (found === -1 && pattern.length > 0 && pattern[pattern.length - 1] === "") { pattern = pattern.slice(0, -1) @@ -364,79 +382,82 @@ export namespace Patch { } found = seekSequence(originalLines, pattern, lineIndex) } - + if (found !== -1) { replacements.push([found, pattern.length, newSlice]) lineIndex = found + pattern.length } else { throw new Error( - `Failed to find expected lines in ${filePath}:\n${chunk.old_lines.join("\n")}` + `Failed to find expected lines in ${filePath}:\n${chunk.old_lines.join("\n")}`, ) } } - + // Sort replacements by index to apply in order replacements.sort((a, b) => a[0] - b[0]) - + return replacements } - function applyReplacements(lines: string[], replacements: Array<[number, number, string[]]>): string[] { + function applyReplacements( + lines: string[], + replacements: Array<[number, number, string[]]>, + ): string[] { // Apply replacements in reverse order to avoid index shifting const result = [...lines] - + for (let i = replacements.length - 1; i >= 0; i--) { const [startIdx, oldLen, newSegment] = replacements[i] - + // Remove old lines result.splice(startIdx, oldLen) - + // Insert new lines for (let j = 0; j < newSegment.length; j++) { result.splice(startIdx + j, 0, newSegment[j]) } } - + return result } function seekSequence(lines: string[], pattern: string[], startIndex: number): number { if (pattern.length === 0) return -1 - + // Simple substring search implementation for (let i = startIndex; i <= lines.length - pattern.length; i++) { let matches = true - + for (let j = 0; j < pattern.length; j++) { if (lines[i + j] !== pattern[j]) { matches = false break } } - + if (matches) { return i } } - + return -1 } function generateUnifiedDiff(oldContent: string, newContent: string): string { const oldLines = oldContent.split("\n") const newLines = newContent.split("\n") - + // Simple diff generation - in a real implementation you'd use a proper diff algorithm let diff = "@@ -1 +1 @@\n" - + // Find changes (simplified approach) const maxLen = Math.max(oldLines.length, newLines.length) let hasChanges = false - + for (let i = 0; i < maxLen; i++) { const oldLine = oldLines[i] || "" const newLine = newLines[i] || "" - + if (oldLine !== newLine) { if (oldLine) diff += `-${oldLine}\n` if (newLine) diff += `+${newLine}\n` @@ -445,7 +466,7 @@ export namespace Patch { diff += ` ${oldLine}\n` } } - + return hasChanges ? diff : "" } @@ -454,11 +475,11 @@ export namespace Patch { if (hunks.length === 0) { throw new Error("No files were modified.") } - + const added: string[] = [] const modified: string[] = [] const deleted: string[] = [] - + for (const hunk of hunks) { switch (hunk.type) { case "add": @@ -467,28 +488,28 @@ export namespace Patch { if (addDir !== "." && addDir !== "/") { await fs.mkdir(addDir, { recursive: true }) } - + await fs.writeFile(hunk.path, hunk.contents, "utf-8") added.push(hunk.path) log.info(`Added file: ${hunk.path}`) break - + case "delete": await fs.unlink(hunk.path) deleted.push(hunk.path) log.info(`Deleted file: ${hunk.path}`) break - + case "update": const fileUpdate = deriveNewContentsFromChunks(hunk.path, hunk.chunks) - + if (hunk.move_path) { // Handle file move const moveDir = path.dirname(hunk.move_path) if (moveDir !== "." && moveDir !== "/") { await fs.mkdir(moveDir, { recursive: true }) } - + await fs.writeFile(hunk.move_path, fileUpdate.content, "utf-8") await fs.unlink(hunk.path) modified.push(hunk.move_path) @@ -502,7 +523,7 @@ export namespace Patch { break } } - + return { added, modified, deleted } } @@ -513,7 +534,10 @@ export namespace Patch { } // Async version of maybeParseApplyPatchVerified - export async function maybeParseApplyPatchVerified(argv: string[], cwd: string): Promise< + export async function maybeParseApplyPatchVerified( + argv: string[], + cwd: string, + ): Promise< | { type: MaybeApplyPatchVerified.Body; action: ApplyPatchAction } | { type: MaybeApplyPatchVerified.CorrectnessError; error: Error } | { type: MaybeApplyPatchVerified.NotApplyPatch } @@ -530,18 +554,21 @@ export namespace Patch { // Not a patch, continue } } - + const result = maybeParseApplyPatch(argv) - + switch (result.type) { case MaybeApplyPatch.Body: const { args } = result const effectiveCwd = args.workdir ? path.resolve(cwd, args.workdir) : cwd const changes = new Map() - + for (const hunk of args.hunks) { - const resolvedPath = path.resolve(effectiveCwd, hunk.type === "update" && hunk.move_path ? hunk.move_path : hunk.path) - + const resolvedPath = path.resolve( + effectiveCwd, + hunk.type === "update" && hunk.move_path ? hunk.move_path : hunk.path, + ) + switch (hunk.type) { case "add": changes.set(resolvedPath, { @@ -549,7 +576,7 @@ export namespace Patch { content: hunk.contents, }) break - + case "delete": // For delete, we need to read the current content const deletePath = path.resolve(effectiveCwd, hunk.path) @@ -566,7 +593,7 @@ export namespace Patch { } } break - + case "update": const updatePath = path.resolve(effectiveCwd, hunk.path) try { @@ -574,7 +601,9 @@ export namespace Patch { changes.set(resolvedPath, { type: "update", unified_diff: fileUpdate.unified_diff, - move_path: hunk.move_path ? path.resolve(effectiveCwd, hunk.move_path) : undefined, + move_path: hunk.move_path + ? path.resolve(effectiveCwd, hunk.move_path) + : undefined, new_content: fileUpdate.content, }) } catch (error) { @@ -586,7 +615,7 @@ export namespace Patch { break } } - + return { type: MaybeApplyPatchVerified.Body, action: { @@ -595,15 +624,15 @@ export namespace Patch { cwd: effectiveCwd, }, } - + case MaybeApplyPatch.PatchParseError: return { type: MaybeApplyPatchVerified.CorrectnessError, error: result.error, } - + case MaybeApplyPatch.NotApplyPatch: return { type: MaybeApplyPatchVerified.NotApplyPatch } } } -} \ No newline at end of file +} diff --git a/packages/opencode/src/provider/transform.ts b/packages/opencode/src/provider/transform.ts index 6212edff..9e095f5b 100644 --- a/packages/opencode/src/provider/transform.ts +++ b/packages/opencode/src/provider/transform.ts @@ -40,7 +40,8 @@ export namespace ProviderTransform { } for (const msg of unique([...system, ...final])) { - const shouldUseContentOptions = providerID !== "anthropic" && Array.isArray(msg.content) && msg.content.length > 0 + const shouldUseContentOptions = + providerID !== "anthropic" && Array.isArray(msg.content) && msg.content.length > 0 if (shouldUseContentOptions) { const lastContent = msg.content[msg.content.length - 1] @@ -84,7 +85,11 @@ export namespace ProviderTransform { return undefined } - export function options(providerID: string, modelID: string, sessionID: string): Record | undefined { + export function options( + providerID: string, + modelID: string, + sessionID: string, + ): Record | undefined { const result: Record = {} if (providerID === "openai") { @@ -109,7 +114,11 @@ export namespace ProviderTransform { return result } - export function providerOptions(npm: string | undefined, providerID: string, options: { [x: string]: any }) { + export function providerOptions( + npm: string | undefined, + providerID: string, + options: { [x: string]: any }, + ) { switch (npm) { case "@ai-sdk/openai": case "@ai-sdk/azure": @@ -142,7 +151,8 @@ export namespace ProviderTransform { if (providerID === "anthropic") { const thinking = options?.["thinking"] - const budgetTokens = typeof thinking?.["budgetTokens"] === "number" ? thinking["budgetTokens"] : 0 + const budgetTokens = + typeof thinking?.["budgetTokens"] === "number" ? thinking["budgetTokens"] : 0 const enabled = thinking?.["type"] === "enabled" if (enabled && budgetTokens > 0) { // Return text tokens so that text + thinking <= model cap, preferring 32k text when possible. diff --git a/packages/opencode/src/server/server.ts b/packages/opencode/src/server/server.ts index 59e066e1..308ed438 100644 --- a/packages/opencode/src/server/server.ts +++ b/packages/opencode/src/server/server.ts @@ -755,7 +755,7 @@ export namespace Server { ), async (c) => { const messages = await Session.messages(c.req.valid("param").id) - return c.json(messages) + return c.json(messages.slice(-100)) }, ) .get( diff --git a/packages/opencode/src/session/compaction.ts b/packages/opencode/src/session/compaction.ts index cc635167..021b544e 100644 --- a/packages/opencode/src/session/compaction.ts +++ b/packages/opencode/src/session/compaction.ts @@ -1,4 +1,4 @@ -import { streamText, type ModelMessage, LoadAPIKeyError, type StreamTextResult, type Tool as AITool } from "ai" +import { streamText, type ModelMessage, type StreamTextResult, type Tool as AITool } from "ai" import { Session } from "." import { Identifier } from "../id/id" import { Instance } from "../project/instance" @@ -30,12 +30,17 @@ export namespace SessionCompaction { ), } - export function isOverflow(input: { tokens: MessageV2.Assistant["tokens"]; model: ModelsDev.Model }) { + export function isOverflow(input: { + tokens: MessageV2.Assistant["tokens"] + model: ModelsDev.Model + }) { if (Flag.OPENCODE_DISABLE_AUTOCOMPACT) return false const context = input.model.limit.context if (context === 0) return false const count = input.tokens.input + input.tokens.cache.read + input.tokens.output - const output = Math.min(input.model.limit.output, SessionPrompt.OUTPUT_TOKEN_MAX) || SessionPrompt.OUTPUT_TOKEN_MAX + const output = + Math.min(input.model.limit.output, SessionPrompt.OUTPUT_TOKEN_MAX) || + SessionPrompt.OUTPUT_TOKEN_MAX const usable = context - output return count > usable } @@ -87,9 +92,15 @@ export namespace SessionCompaction { } } - export async function run(input: { sessionID: string; providerID: string; modelID: string; signal?: AbortSignal }) { + export async function run(input: { + sessionID: string + providerID: string + modelID: string + signal?: AbortSignal + }) { if (!input.signal) SessionLock.assertUnlocked(input.sessionID) - await using lock = input.signal === undefined ? SessionLock.acquire({ sessionID: input.sessionID }) : undefined + await using lock = + input.signal === undefined ? SessionLock.acquire({ sessionID: input.sessionID }) : undefined const signal = input.signal ?? lock!.signal await Session.update(input.sessionID, (draft) => { @@ -113,7 +124,6 @@ export namespace SessionCompaction { role: "assistant", parentID: toSummarize.findLast((m) => m.info.role === "user")?.info.id!, sessionID: input.sessionID, - system, mode: "build", path: { cwd: Instance.directory, @@ -150,7 +160,11 @@ export namespace SessionCompaction { // set to 0, we handle loop maxRetries: 0, model: model.language, - providerOptions: ProviderTransform.providerOptions(model.npm, model.providerID, model.info.options), + providerOptions: ProviderTransform.providerOptions( + model.npm, + model.providerID, + model.info.options, + ), headers: model.info.headers, abortSignal: signal, onError(error) { @@ -230,7 +244,11 @@ export namespace SessionCompaction { error: e, }) const error = MessageV2.fromError(e, { providerID: input.providerID }) - if (retries.count < retries.max && MessageV2.APIError.isInstance(error) && error.data.isRetryable) { + if ( + retries.count < retries.max && + MessageV2.APIError.isInstance(error) && + error.data.isRetryable + ) { shouldRetry = true await Session.updatePart({ id: Identifier.ascending("part"), diff --git a/packages/opencode/src/session/lock.ts b/packages/opencode/src/session/lock.ts index ed024eda..22eb8187 100644 --- a/packages/opencode/src/session/lock.ts +++ b/packages/opencode/src/session/lock.ts @@ -50,7 +50,10 @@ export namespace SessionLock { export function acquire(input: { sessionID: string }) { const lock = get(input.sessionID) if (lock) { - throw new LockedError({ sessionID: input.sessionID, message: `Session ${input.sessionID} is locked` }) + throw new LockedError({ + sessionID: input.sessionID, + message: `Session ${input.sessionID} is locked`, + }) } const controller = new AbortController() state().locks.set(input.sessionID, { diff --git a/packages/opencode/src/session/message-v2.ts b/packages/opencode/src/session/message-v2.ts index 3b28afe0..f35735b7 100644 --- a/packages/opencode/src/session/message-v2.ts +++ b/packages/opencode/src/session/message-v2.ts @@ -2,14 +2,23 @@ import z from "zod" import { Bus } from "../bus" import { NamedError } from "../util/error" import { Message } from "./message" -import { APICallError, convertToModelMessages, LoadAPIKeyError, type ModelMessage, type UIMessage } from "ai" +import { + APICallError, + convertToModelMessages, + LoadAPIKeyError, + type ModelMessage, + type UIMessage, +} from "ai" import { Identifier } from "../id/id" import { LSP } from "../lsp" import { Snapshot } from "@/snapshot" export namespace MessageV2 { export const OutputLengthError = NamedError.create("MessageOutputLengthError", z.object({})) - export const AbortedError = NamedError.create("MessageAbortedError", z.object({ message: z.string() })) + export const AbortedError = NamedError.create( + "MessageAbortedError", + z.object({ message: z.string() }), + ) export const AuthError = NamedError.create( "ProviderAuthError", z.object({ @@ -242,7 +251,12 @@ export namespace MessageV2 { export type ToolStateError = z.infer export const ToolState = z - .discriminatedUnion("status", [ToolStatePending, ToolStateRunning, ToolStateCompleted, ToolStateError]) + .discriminatedUnion("status", [ + ToolStatePending, + ToolStateRunning, + ToolStateCompleted, + ToolStateError, + ]) .meta({ ref: "ToolState", }) @@ -313,7 +327,6 @@ export namespace MessageV2 { APIError.Schema, ]) .optional(), - system: z.string().array(), parentID: z.string(), modelID: z.string(), providerID: z.string(), @@ -397,7 +410,6 @@ export namespace MessageV2 { tokens: v1.metadata.assistant!.tokens, modelID: v1.metadata.assistant!.modelID, providerID: v1.metadata.assistant!.providerID, - system: v1.metadata.assistant!.system, mode: "build", error: v1.metadata.error, } @@ -440,7 +452,8 @@ export namespace MessageV2 { } } - const { title, time, ...metadata } = v1.metadata.tool[part.toolInvocation.toolCallId] ?? {} + const { title, time, ...metadata } = + v1.metadata.tool[part.toolInvocation.toolCallId] ?? {} if (part.toolInvocation.state === "call") { return { status: "running", @@ -541,7 +554,11 @@ export namespace MessageV2 { }, ] // text/plain and directory files are converted into text parts, ignore them - if (part.type === "file" && part.mime !== "text/plain" && part.mime !== "application/x-directory") + if ( + part.type === "file" && + part.mime !== "text/plain" && + part.mime !== "application/x-directory" + ) return [ { type: "file", @@ -600,7 +617,9 @@ export namespace MessageV2 { state: "output-available", toolCallId: part.callID, input: part.state.input, - output: part.state.time.compacted ? "[Old tool result content cleared]" : part.state.output, + output: part.state.time.compacted + ? "[Old tool result content cleared]" + : part.state.output, callProviderMetadata: part.metadata, }, ] diff --git a/packages/opencode/src/session/message.ts b/packages/opencode/src/session/message.ts index 4471f923..baa8c00f 100644 --- a/packages/opencode/src/session/message.ts +++ b/packages/opencode/src/session/message.ts @@ -51,9 +51,11 @@ export namespace Message { }) export type ToolResult = z.infer - export const ToolInvocation = z.discriminatedUnion("state", [ToolCall, ToolPartialCall, ToolResult]).meta({ - ref: "ToolInvocation", - }) + export const ToolInvocation = z + .discriminatedUnion("state", [ToolCall, ToolPartialCall, ToolResult]) + .meta({ + ref: "ToolInvocation", + }) export type ToolInvocation = z.infer export const TextPart = z @@ -122,7 +124,14 @@ export namespace Message { export type StepStartPart = z.infer export const MessagePart = z - .discriminatedUnion("type", [TextPart, ReasoningPart, ToolInvocationPart, SourceUrlPart, FilePart, StepStartPart]) + .discriminatedUnion("type", [ + TextPart, + ReasoningPart, + ToolInvocationPart, + SourceUrlPart, + FilePart, + StepStartPart, + ]) .meta({ ref: "MessagePart", }) @@ -140,7 +149,11 @@ export namespace Message { completed: z.number().optional(), }), error: z - .discriminatedUnion("name", [AuthError.Schema, NamedError.Unknown.Schema, OutputLengthError.Schema]) + .discriminatedUnion("name", [ + AuthError.Schema, + NamedError.Unknown.Schema, + OutputLengthError.Schema, + ]) .optional(), sessionID: z.string(), tool: z.record( diff --git a/packages/opencode/src/session/prompt.ts b/packages/opencode/src/session/prompt.ts index a7004534..9072135f 100644 --- a/packages/opencode/src/session/prompt.ts +++ b/packages/opencode/src/session/prompt.ts @@ -961,7 +961,6 @@ export namespace SessionPrompt { id: Identifier.ascending("message"), parentID, role: "assistant", - system: input.system, mode: input.agent, path: { cwd: Instance.directory, @@ -1412,7 +1411,6 @@ export namespace SessionPrompt { id: Identifier.ascending("message"), sessionID: input.sessionID, parentID: userMsg.id, - system: [], mode: input.agent, cost: 0, path: { @@ -1709,7 +1707,6 @@ export namespace SessionPrompt { id: Identifier.ascending("message"), sessionID: input.sessionID, parentID: userMsg.id, - system: [], mode: agentName, cost: 0, path: { diff --git a/packages/opencode/src/session/revert.ts b/packages/opencode/src/session/revert.ts index a88b5f08..7439d59c 100644 --- a/packages/opencode/src/session/revert.ts +++ b/packages/opencode/src/session/revert.ts @@ -45,7 +45,9 @@ export namespace SessionRevert { if (!revert) { if ((msg.info.id === input.messageID && !input.partID) || part.id === input.partID) { // if no useful parts left in message, same as reverting whole message - const partID = remaining.some((item) => ["text", "tool"].includes(item.type)) ? input.partID : undefined + const partID = remaining.some((item) => ["text", "tool"].includes(item.type)) + ? input.partID + : undefined revert = { messageID: !partID && lastUser ? lastUser.id : msg.info.id, partID, diff --git a/packages/opencode/src/session/system.ts b/packages/opencode/src/session/system.ts index 3173dcac..3bff0772 100644 --- a/packages/opencode/src/session/system.ts +++ b/packages/opencode/src/session/system.ts @@ -24,7 +24,8 @@ export namespace SystemPrompt { export function provider(modelID: string) { if (modelID.includes("gpt-5")) return [PROMPT_CODEX] - if (modelID.includes("gpt-") || modelID.includes("o1") || modelID.includes("o3")) return [PROMPT_BEAST] + if (modelID.includes("gpt-") || modelID.includes("o1") || modelID.includes("o3")) + return [PROMPT_BEAST] if (modelID.includes("gemini-")) return [PROMPT_GEMINI] if (modelID.includes("claude")) return [PROMPT_ANTHROPIC] return [PROMPT_ANTHROPIC_WITHOUT_TODO] @@ -99,7 +100,11 @@ export namespace SystemPrompt { }), ).catch(() => []) } else { - matches = await Filesystem.globUp(instruction, Instance.directory, Instance.worktree).catch(() => []) + matches = await Filesystem.globUp( + instruction, + Instance.directory, + Instance.worktree, + ).catch(() => []) } matches.forEach((path) => paths.add(path)) } diff --git a/packages/opencode/src/session/todo.ts b/packages/opencode/src/session/todo.ts index d5208773..4d9a2650 100644 --- a/packages/opencode/src/session/todo.ts +++ b/packages/opencode/src/session/todo.ts @@ -6,7 +6,9 @@ export namespace Todo { export const Info = z .object({ content: z.string().describe("Brief description of the task"), - status: z.string().describe("Current status of the task: pending, in_progress, completed, cancelled"), + status: z + .string() + .describe("Current status of the task: pending, in_progress, completed, cancelled"), priority: z.string().describe("Priority level of the task: high, medium, low"), id: z.string().describe("Unique identifier for the todo item"), }) diff --git a/packages/opencode/src/share/share.ts b/packages/opencode/src/share/share.ts index 1006b23d..d48d76f8 100644 --- a/packages/opencode/src/share/share.ts +++ b/packages/opencode/src/share/share.ts @@ -50,7 +50,10 @@ export namespace Share { await sync("session/info/" + evt.properties.info.id, evt.properties.info) }) Bus.subscribe(MessageV2.Event.Updated, async (evt) => { - await sync("session/message/" + evt.properties.info.sessionID + "/" + evt.properties.info.id, evt.properties.info) + await sync( + "session/message/" + evt.properties.info.sessionID + "/" + evt.properties.info.id, + evt.properties.info, + ) }) Bus.subscribe(MessageV2.Event.PartUpdated, async (evt) => { await sync( @@ -67,7 +70,9 @@ export namespace Share { export const URL = process.env["OPENCODE_API"] ?? - (Installation.isPreview() || Installation.isLocal() ? "https://api.dev.opencode.ai" : "https://api.opencode.ai") + (Installation.isPreview() || Installation.isLocal() + ? "https://api.dev.opencode.ai" + : "https://api.opencode.ai") export async function create(sessionID: string) { return fetch(`${URL}/share_create`, { diff --git a/packages/opencode/src/snapshot/index.ts b/packages/opencode/src/snapshot/index.ts index 98b31680..b4deee97 100644 --- a/packages/opencode/src/snapshot/index.ts +++ b/packages/opencode/src/snapshot/index.ts @@ -27,7 +27,11 @@ export namespace Snapshot { log.info("initialized") } await $`git --git-dir ${git} add .`.quiet().cwd(Instance.directory).nothrow() - const hash = await $`git --git-dir ${git} write-tree`.quiet().cwd(Instance.directory).nothrow().text() + const hash = await $`git --git-dir ${git} write-tree` + .quiet() + .cwd(Instance.directory) + .nothrow() + .text() log.info("tracking", { hash, cwd: Instance.directory, git }) return hash.trim() } @@ -41,7 +45,10 @@ export namespace Snapshot { export async function patch(hash: string): Promise { const git = gitdir() await $`git --git-dir ${git} add .`.quiet().cwd(Instance.directory).nothrow() - const result = await $`git --git-dir ${git} diff --name-only ${hash} -- .`.quiet().cwd(Instance.directory).nothrow() + const result = await $`git --git-dir ${git} diff --name-only ${hash} -- .` + .quiet() + .cwd(Instance.directory) + .nothrow() // If git diff fails, return empty patch if (result.exitCode !== 0) { @@ -64,10 +71,11 @@ export namespace Snapshot { export async function restore(snapshot: string) { log.info("restore", { commit: snapshot }) const git = gitdir() - const result = await $`git --git-dir=${git} read-tree ${snapshot} && git --git-dir=${git} checkout-index -a -f` - .quiet() - .cwd(Instance.worktree) - .nothrow() + const result = + await $`git --git-dir=${git} read-tree ${snapshot} && git --git-dir=${git} checkout-index -a -f` + .quiet() + .cwd(Instance.worktree) + .nothrow() if (result.exitCode !== 0) { log.error("failed to restore snapshot", { @@ -113,7 +121,10 @@ export namespace Snapshot { export async function diff(hash: string) { const git = gitdir() await $`git --git-dir ${git} add .`.quiet().cwd(Instance.directory).nothrow() - const result = await $`git --git-dir=${git} diff ${hash} -- .`.quiet().cwd(Instance.worktree).nothrow() + const result = await $`git --git-dir=${git} diff ${hash} -- .` + .quiet() + .cwd(Instance.worktree) + .nothrow() if (result.exitCode !== 0) { log.warn("failed to get diff", { diff --git a/packages/opencode/src/tool/edit.ts b/packages/opencode/src/tool/edit.ts index ba3d2c0b..057fb9e8 100644 --- a/packages/opencode/src/tool/edit.ts +++ b/packages/opencode/src/tool/edit.ts @@ -23,8 +23,13 @@ export const EditTool = Tool.define("edit", { parameters: z.object({ filePath: z.string().describe("The absolute path to the file to modify"), oldString: z.string().describe("The text to replace"), - newString: z.string().describe("The text to replace it with (must be different from oldString)"), - replaceAll: z.boolean().optional().describe("Replace all occurrences of oldString (default false)"), + newString: z + .string() + .describe("The text to replace it with (must be different from oldString)"), + replaceAll: z + .boolean() + .optional() + .describe("Replace all occurrences of oldString (default false)"), }), async execute(params, ctx) { if (!params.filePath) { @@ -35,7 +40,9 @@ export const EditTool = Tool.define("edit", { throw new Error("oldString and newString must be different") } - const filePath = path.isAbsolute(params.filePath) ? params.filePath : path.join(Instance.directory, params.filePath) + const filePath = path.isAbsolute(params.filePath) + ? params.filePath + : path.join(Instance.directory, params.filePath) if (!Filesystem.contains(Instance.directory, filePath)) { const parentDir = path.dirname(filePath) await Permission.ask({ @@ -172,7 +179,11 @@ function levenshtein(a: string, b: string): number { for (let i = 1; i <= a.length; i++) { for (let j = 1; j <= b.length; j++) { const cost = a[i - 1] === b[j - 1] ? 0 : 1 - matrix[i][j] = Math.min(matrix[i - 1][j] + 1, matrix[i][j - 1] + 1, matrix[i - 1][j - 1] + cost) + matrix[i][j] = Math.min( + matrix[i - 1][j] + 1, + matrix[i][j - 1] + 1, + matrix[i - 1][j - 1] + cost, + ) } } return matrix[a.length][b.length] @@ -374,7 +385,9 @@ export const WhitespaceNormalizedReplacer: Replacer = function* (content, find) // Find the actual substring in the original line that matches const words = find.trim().split(/\s+/) if (words.length > 0) { - const pattern = words.map((word) => word.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("\\s+") + const pattern = words + .map((word) => word.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")) + .join("\\s+") try { const regex = new RegExp(pattern) const match = line.match(regex) @@ -612,7 +625,12 @@ export function trimDiff(diff: string): string { return trimmedLines.join("\n") } -export function replace(content: string, oldString: string, newString: string, replaceAll = false): string { +export function replace( + content: string, + oldString: string, + newString: string, + replaceAll = false, +): string { if (oldString === newString) { throw new Error("oldString and newString must be different") } diff --git a/packages/opencode/src/tool/grep.ts b/packages/opencode/src/tool/grep.ts index 5390be21..9f7d04ea 100644 --- a/packages/opencode/src/tool/grep.ts +++ b/packages/opencode/src/tool/grep.ts @@ -9,8 +9,14 @@ export const GrepTool = Tool.define("grep", { description: DESCRIPTION, parameters: z.object({ pattern: z.string().describe("The regex pattern to search for in file contents"), - path: z.string().optional().describe("The directory to search in. Defaults to the current working directory."), - include: z.string().optional().describe('File pattern to include in the search (e.g. "*.js", "*.{ts,tsx}")'), + path: z + .string() + .optional() + .describe("The directory to search in. Defaults to the current working directory."), + include: z + .string() + .optional() + .describe('File pattern to include in the search (e.g. "*.js", "*.{ts,tsx}")'), }), async execute(params) { if (!params.pattern) { diff --git a/packages/opencode/src/tool/ls.ts b/packages/opencode/src/tool/ls.ts index 95c36e74..4fcfcaa8 100644 --- a/packages/opencode/src/tool/ls.ts +++ b/packages/opencode/src/tool/ls.ts @@ -37,13 +37,18 @@ const LIMIT = 100 export const ListTool = Tool.define("list", { description: DESCRIPTION, parameters: z.object({ - path: z.string().describe("The absolute path to the directory to list (must be absolute, not relative)").optional(), + path: z + .string() + .describe("The absolute path to the directory to list (must be absolute, not relative)") + .optional(), ignore: z.array(z.string()).describe("List of glob patterns to ignore").optional(), }), async execute(params) { const searchPath = path.resolve(Instance.directory, params.path || ".") - const ignoreGlobs = IGNORE_PATTERNS.map((p) => `!${p}*`).concat(params.ignore?.map((p) => `!${p}`) || []) + const ignoreGlobs = IGNORE_PATTERNS.map((p) => `!${p}*`).concat( + params.ignore?.map((p) => `!${p}`) || [], + ) const files = [] for await (const file of Ripgrep.files({ cwd: searchPath, glob: ignoreGlobs })) { files.push(file) diff --git a/packages/opencode/src/tool/lsp-diagnostics.ts b/packages/opencode/src/tool/lsp-diagnostics.ts index 18a6868b..78c8c3ca 100644 --- a/packages/opencode/src/tool/lsp-diagnostics.ts +++ b/packages/opencode/src/tool/lsp-diagnostics.ts @@ -11,7 +11,9 @@ export const LspDiagnosticTool = Tool.define("lsp_diagnostics", { path: z.string().describe("The path to the file to get diagnostics."), }), execute: async (args) => { - const normalized = path.isAbsolute(args.path) ? args.path : path.join(Instance.directory, args.path) + const normalized = path.isAbsolute(args.path) + ? args.path + : path.join(Instance.directory, args.path) await LSP.touchFile(normalized, true) const diagnostics = await LSP.diagnostics() const file = diagnostics[normalized] diff --git a/packages/opencode/src/tool/multiedit.ts b/packages/opencode/src/tool/multiedit.ts index 7f562f47..f3a65735 100644 --- a/packages/opencode/src/tool/multiedit.ts +++ b/packages/opencode/src/tool/multiedit.ts @@ -14,8 +14,13 @@ export const MultiEditTool = Tool.define("multiedit", { z.object({ filePath: z.string().describe("The absolute path to the file to modify"), oldString: z.string().describe("The text to replace"), - newString: z.string().describe("The text to replace it with (must be different from oldString)"), - replaceAll: z.boolean().optional().describe("Replace all occurrences of oldString (default false)"), + newString: z + .string() + .describe("The text to replace it with (must be different from oldString)"), + replaceAll: z + .boolean() + .optional() + .describe("Replace all occurrences of oldString (default false)"), }), ) .describe("Array of edit operations to perform sequentially on the file"), diff --git a/packages/opencode/src/tool/read.ts b/packages/opencode/src/tool/read.ts index 963636fd..56a67bb0 100644 --- a/packages/opencode/src/tool/read.ts +++ b/packages/opencode/src/tool/read.ts @@ -18,7 +18,10 @@ export const ReadTool = Tool.define("read", { description: DESCRIPTION, parameters: z.object({ filePath: z.string().describe("The path to the file to read"), - offset: z.coerce.number().describe("The line number to start reading from (0-based)").optional(), + offset: z.coerce + .number() + .describe("The line number to start reading from (0-based)") + .optional(), limit: z.coerce.number().describe("The number of lines to read (defaults to 2000)").optional(), }), async execute(params, ctx) { @@ -53,13 +56,16 @@ export const ReadTool = Tool.define("read", { const suggestions = dirEntries .filter( (entry) => - entry.toLowerCase().includes(base.toLowerCase()) || base.toLowerCase().includes(entry.toLowerCase()), + entry.toLowerCase().includes(base.toLowerCase()) || + base.toLowerCase().includes(entry.toLowerCase()), ) .map((entry) => path.join(dir, entry)) .slice(0, 3) if (suggestions.length > 0) { - throw new Error(`File not found: ${filepath}\n\nDid you mean one of these?\n${suggestions.join("\n")}`) + throw new Error( + `File not found: ${filepath}\n\nDid you mean one of these?\n${suggestions.join("\n")}`, + ) } throw new Error(`File not found: ${filepath}`) diff --git a/packages/opencode/src/tool/registry.ts b/packages/opencode/src/tool/registry.ts index c4d54597..6234a4e6 100644 --- a/packages/opencode/src/tool/registry.ts +++ b/packages/opencode/src/tool/registry.ts @@ -24,7 +24,12 @@ export namespace ToolRegistry { const glob = new Bun.Glob("tool/*.{js,ts}") for (const dir of await Config.directories()) { - for await (const match of glob.scan({ cwd: dir, absolute: true, followSymlinks: true, dot: true })) { + for await (const match of glob.scan({ + cwd: dir, + absolute: true, + followSymlinks: true, + dot: true, + })) { const namespace = path.basename(match, path.extname(match)) const mod = await import(match) for (const [id, def] of Object.entries(mod)) { diff --git a/packages/opencode/src/tool/task.ts b/packages/opencode/src/tool/task.ts index 342645c3..ac0b204b 100644 --- a/packages/opencode/src/tool/task.ts +++ b/packages/opencode/src/tool/task.ts @@ -14,7 +14,10 @@ export const TaskTool = Tool.define("task", async () => { const description = DESCRIPTION.replace( "{agents}", agents - .map((a) => `- ${a.name}: ${a.description ?? "This subagent should only be called manually by the user."}`) + .map( + (a) => + `- ${a.name}: ${a.description ?? "This subagent should only be called manually by the user."}`, + ) .join("\n"), ) return { @@ -26,7 +29,8 @@ export const TaskTool = Tool.define("task", async () => { }), async execute(params, ctx) { const agent = await Agent.get(params.subagent_type) - if (!agent) throw new Error(`Unknown agent type: ${params.subagent_type} is not a valid agent type`) + if (!agent) + throw new Error(`Unknown agent type: ${params.subagent_type} is not a valid agent type`) const session = await Session.create({ parentID: ctx.sessionID, title: params.description + ` (@${agent.name} subagent)`, @@ -91,7 +95,9 @@ export const TaskTool = Tool.define("task", async () => { let all all = await Session.messages(session.id) all = all.filter((x) => x.info.role === "assistant") - all = all.flatMap((msg) => msg.parts.filter((x: any) => x.type === "tool") as MessageV2.ToolPart[]) + all = all.flatMap( + (msg) => msg.parts.filter((x: any) => x.type === "tool") as MessageV2.ToolPart[], + ) return { title: params.description, metadata: { diff --git a/packages/opencode/src/tool/webfetch.ts b/packages/opencode/src/tool/webfetch.ts index 0333bb01..d85351ff 100644 --- a/packages/opencode/src/tool/webfetch.ts +++ b/packages/opencode/src/tool/webfetch.ts @@ -48,13 +48,15 @@ export const WebFetchTool = Tool.define("webfetch", { let acceptHeader = "*/*" switch (params.format) { case "markdown": - acceptHeader = "text/markdown;q=1.0, text/x-markdown;q=0.9, text/plain;q=0.8, text/html;q=0.7, */*;q=0.1" + acceptHeader = + "text/markdown;q=1.0, text/x-markdown;q=0.9, text/plain;q=0.8, text/html;q=0.7, */*;q=0.1" break case "text": acceptHeader = "text/plain;q=1.0, text/markdown;q=0.9, text/html;q=0.8, */*;q=0.1" break case "html": - acceptHeader = "text/html;q=1.0, application/xhtml+xml;q=0.9, text/plain;q=0.8, text/markdown;q=0.7, */*;q=0.1" + acceptHeader = + "text/html;q=1.0, application/xhtml+xml;q=0.9, text/plain;q=0.8, text/markdown;q=0.7, */*;q=0.1" break default: acceptHeader = @@ -158,7 +160,9 @@ async function extractTextFromHTML(html: string) { .on("*", { element(element) { // Reset skip flag when entering other elements - if (!["script", "style", "noscript", "iframe", "object", "embed"].includes(element.tagName)) { + if ( + !["script", "style", "noscript", "iframe", "object", "embed"].includes(element.tagName) + ) { skipContent = false } }, diff --git a/packages/opencode/src/tool/write.ts b/packages/opencode/src/tool/write.ts index acaa1239..c7b99816 100644 --- a/packages/opencode/src/tool/write.ts +++ b/packages/opencode/src/tool/write.ts @@ -15,10 +15,14 @@ export const WriteTool = Tool.define("write", { description: DESCRIPTION, parameters: z.object({ content: z.string().describe("The content to write to the file"), - filePath: z.string().describe("The absolute path to the file to write (must be absolute, not relative)"), + filePath: z + .string() + .describe("The absolute path to the file to write (must be absolute, not relative)"), }), async execute(params, ctx) { - const filepath = path.isAbsolute(params.filePath) ? params.filePath : path.join(Instance.directory, params.filePath) + const filepath = path.isAbsolute(params.filePath) + ? params.filePath + : path.join(Instance.directory, params.filePath) if (!Filesystem.contains(Instance.directory, filepath)) { const parentDir = path.dirname(filepath) await Permission.ask({ diff --git a/packages/opencode/src/util/binary.ts b/packages/opencode/src/util/binary.ts index 3d8f6185..d72cc85d 100644 --- a/packages/opencode/src/util/binary.ts +++ b/packages/opencode/src/util/binary.ts @@ -1,5 +1,9 @@ export namespace Binary { - export function search(array: T[], id: string, compare: (item: T) => string): { found: boolean; index: number } { + export function search( + array: T[], + id: string, + compare: (item: T) => string, + ): { found: boolean; index: number } { let left = 0 let right = array.length - 1 diff --git a/packages/opencode/src/util/defer.ts b/packages/opencode/src/util/defer.ts index 8de21528..69b5c178 100644 --- a/packages/opencode/src/util/defer.ts +++ b/packages/opencode/src/util/defer.ts @@ -1,6 +1,8 @@ export function defer void | Promise>( fn: T, -): T extends () => Promise ? { [Symbol.asyncDispose]: () => Promise } : { [Symbol.dispose]: () => void } { +): T extends () => Promise + ? { [Symbol.asyncDispose]: () => Promise } + : { [Symbol.dispose]: () => void } { return { [Symbol.dispose]() { fn() diff --git a/packages/opencode/src/util/eventloop.ts b/packages/opencode/src/util/eventloop.ts index 87f6eef4..f7096d38 100644 --- a/packages/opencode/src/util/eventloop.ts +++ b/packages/opencode/src/util/eventloop.ts @@ -4,11 +4,17 @@ export namespace EventLoop { export async function wait() { return new Promise((resolve) => { const check = () => { - const active = [...(process as any)._getActiveHandles(), ...(process as any)._getActiveRequests()] + const active = [ + ...(process as any)._getActiveHandles(), + ...(process as any)._getActiveRequests(), + ] Log.Default.info("eventloop", { active, }) - if ((process as any)._getActiveHandles().length === 0 && (process as any)._getActiveRequests().length === 0) { + if ( + (process as any)._getActiveHandles().length === 0 && + (process as any)._getActiveRequests().length === 0 + ) { resolve() } else { setImmediate(check) diff --git a/packages/opencode/src/util/lock.ts b/packages/opencode/src/util/lock.ts index 3aea6439..c503ddd3 100644 --- a/packages/opencode/src/util/lock.ts +++ b/packages/opencode/src/util/lock.ts @@ -39,7 +39,12 @@ export namespace Lock { } // Clean up empty locks - if (lock.readers === 0 && !lock.writer && lock.waitingReaders.length === 0 && lock.waitingWriters.length === 0) { + if ( + lock.readers === 0 && + !lock.writer && + lock.waitingReaders.length === 0 && + lock.waitingWriters.length === 0 + ) { locks.delete(key) } } diff --git a/packages/opencode/src/util/rpc.ts b/packages/opencode/src/util/rpc.ts index 57c695c4..981cc071 100644 --- a/packages/opencode/src/util/rpc.ts +++ b/packages/opencode/src/util/rpc.ts @@ -30,7 +30,10 @@ export namespace Rpc { } } return { - call(method: Method, input: Parameters[0]): Promise> { + call( + method: Method, + input: Parameters[0], + ): Promise> { const requestId = id++ return new Promise((resolve) => { pending.set(requestId, resolve) diff --git a/packages/opencode/src/util/wildcard.ts b/packages/opencode/src/util/wildcard.ts index 9b595a0a..feda9696 100644 --- a/packages/opencode/src/util/wildcard.ts +++ b/packages/opencode/src/util/wildcard.ts @@ -15,7 +15,11 @@ export namespace Wildcard { } export function all(input: string, patterns: Record) { - const sorted = pipe(patterns, Object.entries, sortBy([([key]) => key.length, "asc"], [([key]) => key, "asc"])) + const sorted = pipe( + patterns, + Object.entries, + sortBy([([key]) => key.length, "asc"], [([key]) => key, "asc"]), + ) let result = undefined for (const [pattern, value] of sorted) { if (match(input, pattern)) { @@ -26,8 +30,15 @@ export namespace Wildcard { return result } - export function allStructured(input: { head: string; tail: string[] }, patterns: Record) { - const sorted = pipe(patterns, Object.entries, sortBy([([key]) => key.length, "asc"], [([key]) => key, "asc"])) + export function allStructured( + input: { head: string; tail: string[] }, + patterns: Record, + ) { + const sorted = pipe( + patterns, + Object.entries, + sortBy([([key]) => key.length, "asc"], [([key]) => key, "asc"]), + ) let result = undefined for (const [pattern, value] of sorted) { const parts = pattern.split(/\s+/) diff --git a/packages/opencode/sst-env.d.ts b/packages/opencode/sst-env.d.ts index b6a7e906..0397645b 100644 --- a/packages/opencode/sst-env.d.ts +++ b/packages/opencode/sst-env.d.ts @@ -6,4 +6,4 @@ /// import "sst" -export {} \ No newline at end of file +export {} diff --git a/packages/opencode/test/patch/patch.test.ts b/packages/opencode/test/patch/patch.test.ts index 51076c34..020253bf 100644 --- a/packages/opencode/test/patch/patch.test.ts +++ b/packages/opencode/test/patch/patch.test.ts @@ -6,23 +6,23 @@ import { tmpdir } from "os" describe("Patch namespace", () => { let tempDir: string - + beforeEach(async () => { tempDir = await fs.mkdtemp(path.join(tmpdir(), "patch-test-")) }) - + afterEach(async () => { // Clean up temp directory await fs.rm(tempDir, { recursive: true, force: true }) }) - + describe("parsePatch", () => { test("should parse simple add file patch", () => { const patchText = `*** Begin Patch *** Add File: test.txt +Hello World *** End Patch` - + const result = Patch.parsePatch(patchText) expect(result.hunks).toHaveLength(1) expect(result.hunks[0]).toEqual({ @@ -31,19 +31,19 @@ describe("Patch namespace", () => { contents: "Hello World", }) }) - + test("should parse delete file patch", () => { const patchText = `*** Begin Patch *** Delete File: old.txt *** End Patch` - + const result = Patch.parsePatch(patchText) expect(result.hunks).toHaveLength(1) const hunk = result.hunks[0] expect(hunk.type).toBe("delete") expect(hunk.path).toBe("old.txt") }) - + test("should parse patch with multiple hunks", () => { const patchText = `*** Begin Patch *** Add File: new.txt @@ -54,13 +54,13 @@ describe("Patch namespace", () => { -new line +updated line *** End Patch` - + const result = Patch.parsePatch(patchText) expect(result.hunks).toHaveLength(2) expect(result.hunks[0].type).toBe("add") expect(result.hunks[1].type).toBe("update") }) - + test("should parse file move operation", () => { const patchText = `*** Begin Patch *** Update File: old-name.txt @@ -69,7 +69,7 @@ describe("Patch namespace", () => { -Old content +New content *** End Patch` - + const result = Patch.parsePatch(patchText) expect(result.hunks).toHaveLength(1) const hunk = result.hunks[0] @@ -79,21 +79,21 @@ describe("Patch namespace", () => { expect(hunk.move_path).toBe("new-name.txt") } }) - + test("should throw error for invalid patch format", () => { const invalidPatch = `This is not a valid patch` - + expect(() => Patch.parsePatch(invalidPatch)).toThrow("Invalid patch format") }) }) - + describe("maybeParseApplyPatch", () => { test("should parse direct apply_patch command", () => { const patchText = `*** Begin Patch *** Add File: test.txt +Content *** End Patch` - + const result = Patch.maybeParseApplyPatch(["apply_patch", patchText]) expect(result.type).toBe(Patch.MaybeApplyPatch.Body) if (result.type === Patch.MaybeApplyPatch.Body) { @@ -101,17 +101,17 @@ describe("Patch namespace", () => { expect(result.args.hunks).toHaveLength(1) } }) - + test("should parse applypatch command", () => { const patchText = `*** Begin Patch *** Add File: test.txt +Content *** End Patch` - + const result = Patch.maybeParseApplyPatch(["applypatch", patchText]) expect(result.type).toBe(Patch.MaybeApplyPatch.Body) }) - + test("should handle bash heredoc format", () => { const script = `apply_patch <<'PATCH' *** Begin Patch @@ -119,20 +119,20 @@ describe("Patch namespace", () => { +Content *** End Patch PATCH` - + const result = Patch.maybeParseApplyPatch(["bash", "-lc", script]) expect(result.type).toBe(Patch.MaybeApplyPatch.Body) if (result.type === Patch.MaybeApplyPatch.Body) { expect(result.args.hunks).toHaveLength(1) } }) - + test("should return NotApplyPatch for non-patch commands", () => { const result = Patch.maybeParseApplyPatch(["echo", "hello"]) expect(result.type).toBe(Patch.MaybeApplyPatch.NotApplyPatch) }) }) - + describe("applyPatch", () => { test("should add a new file", async () => { const patchText = `*** Begin Patch @@ -140,36 +140,39 @@ PATCH` +Hello World +This is a new file *** End Patch` - + const result = await Patch.applyPatch(patchText) expect(result.added).toHaveLength(1) expect(result.modified).toHaveLength(0) expect(result.deleted).toHaveLength(0) - + const content = await fs.readFile(result.added[0], "utf-8") expect(content).toBe("Hello World\nThis is a new file") }) - + test("should delete an existing file", async () => { const filePath = path.join(tempDir, "to-delete.txt") await fs.writeFile(filePath, "This file will be deleted") - + const patchText = `*** Begin Patch *** Delete File: ${filePath} *** End Patch` - + const result = await Patch.applyPatch(patchText) expect(result.deleted).toHaveLength(1) expect(result.deleted[0]).toBe(filePath) - - const exists = await fs.access(filePath).then(() => true).catch(() => false) + + const exists = await fs + .access(filePath) + .then(() => true) + .catch(() => false) expect(exists).toBe(false) }) - + test("should update an existing file", async () => { const filePath = path.join(tempDir, "to-update.txt") await fs.writeFile(filePath, "line 1\nline 2\nline 3\n") - + const patchText = `*** Begin Patch *** Update File: ${filePath} @@ @@ -178,20 +181,20 @@ PATCH` +line 2 updated line 3 *** End Patch` - + const result = await Patch.applyPatch(patchText) expect(result.modified).toHaveLength(1) expect(result.modified[0]).toBe(filePath) - + const content = await fs.readFile(filePath, "utf-8") expect(content).toBe("line 1\nline 2 updated\nline 3\n") }) - + test("should move and update a file", async () => { const oldPath = path.join(tempDir, "old-name.txt") const newPath = path.join(tempDir, "new-name.txt") await fs.writeFile(oldPath, "old content\n") - + const patchText = `*** Begin Patch *** Update File: ${oldPath} *** Move to: ${newPath} @@ -199,26 +202,29 @@ PATCH` -old content +new content *** End Patch` - + const result = await Patch.applyPatch(patchText) expect(result.modified).toHaveLength(1) expect(result.modified[0]).toBe(newPath) - - const oldExists = await fs.access(oldPath).then(() => true).catch(() => false) + + const oldExists = await fs + .access(oldPath) + .then(() => true) + .catch(() => false) expect(oldExists).toBe(false) - + const newContent = await fs.readFile(newPath, "utf-8") expect(newContent).toBe("new content\n") }) - + test("should handle multiple operations in one patch", async () => { const file1 = path.join(tempDir, "file1.txt") const file2 = path.join(tempDir, "file2.txt") const file3 = path.join(tempDir, "file3.txt") - + await fs.writeFile(file1, "content 1") await fs.writeFile(file2, "content 2") - + const patchText = `*** Begin Patch *** Add File: ${file3} +new file content @@ -228,95 +234,98 @@ PATCH` +updated content 1 *** Delete File: ${file2} *** End Patch` - + const result = await Patch.applyPatch(patchText) expect(result.added).toHaveLength(1) expect(result.modified).toHaveLength(1) expect(result.deleted).toHaveLength(1) }) - + test("should create parent directories when adding files", async () => { const nestedPath = path.join(tempDir, "deep", "nested", "file.txt") - + const patchText = `*** Begin Patch *** Add File: ${nestedPath} +Deep nested content *** End Patch` - + const result = await Patch.applyPatch(patchText) expect(result.added).toHaveLength(1) expect(result.added[0]).toBe(nestedPath) - - const exists = await fs.access(nestedPath).then(() => true).catch(() => false) + + const exists = await fs + .access(nestedPath) + .then(() => true) + .catch(() => false) expect(exists).toBe(true) }) }) - + describe("error handling", () => { test("should throw error when updating non-existent file", async () => { const nonExistent = path.join(tempDir, "does-not-exist.txt") - + const patchText = `*** Begin Patch *** Update File: ${nonExistent} @@ -old line +new line *** End Patch` - + await expect(Patch.applyPatch(patchText)).rejects.toThrow() }) - + test("should throw error when deleting non-existent file", async () => { const nonExistent = path.join(tempDir, "does-not-exist.txt") - + const patchText = `*** Begin Patch *** Delete File: ${nonExistent} *** End Patch` - + await expect(Patch.applyPatch(patchText)).rejects.toThrow() }) }) - + describe("edge cases", () => { test("should handle empty files", async () => { const emptyFile = path.join(tempDir, "empty.txt") await fs.writeFile(emptyFile, "") - + const patchText = `*** Begin Patch *** Update File: ${emptyFile} @@ +First line *** End Patch` - + const result = await Patch.applyPatch(patchText) expect(result.modified).toHaveLength(1) - + const content = await fs.readFile(emptyFile, "utf-8") expect(content).toBe("First line\n") }) - + test("should handle files with no trailing newline", async () => { const filePath = path.join(tempDir, "no-newline.txt") await fs.writeFile(filePath, "no newline") - + const patchText = `*** Begin Patch *** Update File: ${filePath} @@ -no newline +has newline now *** End Patch` - + const result = await Patch.applyPatch(patchText) expect(result.modified).toHaveLength(1) - + const content = await fs.readFile(filePath, "utf-8") expect(content).toBe("has newline now\n") }) - + test("should handle multiple update chunks in single file", async () => { const filePath = path.join(tempDir, "multi-chunk.txt") await fs.writeFile(filePath, "line 1\nline 2\nline 3\nline 4\n") - + const patchText = `*** Begin Patch *** Update File: ${filePath} @@ @@ -328,12 +337,12 @@ PATCH` -line 4 +LINE 4 *** End Patch` - + const result = await Patch.applyPatch(patchText) expect(result.modified).toHaveLength(1) - + const content = await fs.readFile(filePath, "utf-8") expect(content).toBe("line 1\nLINE 2\nline 3\nLINE 4\n") }) }) -}) \ No newline at end of file +}) diff --git a/packages/opencode/test/session/retry.test.ts b/packages/opencode/test/session/retry.test.ts index edce412c..ebcee80d 100644 --- a/packages/opencode/test/session/retry.test.ts +++ b/packages/opencode/test/session/retry.test.ts @@ -13,7 +13,9 @@ function apiError(headers?: Record): MessageV2.APIError { describe("session.retry.getRetryDelayInMs", () => { test("doubles delay on each attempt when headers missing", () => { const error = apiError() - const delays = Array.from({ length: 7 }, (_, index) => SessionRetry.getRetryDelayInMs(error, index + 1)) + const delays = Array.from({ length: 7 }, (_, index) => + SessionRetry.getRetryDelayInMs(error, index + 1), + ) expect(delays).toStrictEqual([2000, 4000, 8000, 16000, 32000, 64000, 128000]) }) diff --git a/packages/opencode/test/util/wildcard.test.ts b/packages/opencode/test/util/wildcard.test.ts index f7f1e154..968b4f28 100644 --- a/packages/opencode/test/util/wildcard.test.ts +++ b/packages/opencode/test/util/wildcard.test.ts @@ -24,9 +24,12 @@ test("allStructured matches command sequences", () => { "git status*": "allow", } expect(Wildcard.allStructured({ head: "git", tail: ["status", "--short"] }, rules)).toBe("allow") - expect(Wildcard.allStructured({ head: "npm", tail: ["run", "build", "--watch"] }, { "npm run *": "allow" })).toBe( - "allow", - ) + expect( + Wildcard.allStructured( + { head: "npm", tail: ["run", "build", "--watch"] }, + { "npm run *": "allow" }, + ), + ).toBe("allow") expect(Wildcard.allStructured({ head: "ls", tail: ["-la"] }, rules)).toBeUndefined() }) @@ -51,5 +54,7 @@ test("allStructured handles sed flags", () => { expect(Wildcard.allStructured({ head: "sed", tail: ["-i", "file"] }, rules)).toBe("ask") expect(Wildcard.allStructured({ head: "sed", tail: ["-i.bak", "file"] }, rules)).toBe("ask") expect(Wildcard.allStructured({ head: "sed", tail: ["-n", "1p", "file"] }, rules)).toBe("allow") - expect(Wildcard.allStructured({ head: "sed", tail: ["-i", "-n", "/./p", "myfile.txt"] }, rules)).toBe("ask") + expect( + Wildcard.allStructured({ head: "sed", tail: ["-i", "-n", "/./p", "myfile.txt"] }, rules), + ).toBe("ask") }) diff --git a/packages/plugin/package.json b/packages/plugin/package.json index c510b519..9206efe1 100644 --- a/packages/plugin/package.json +++ b/packages/plugin/package.json @@ -24,4 +24,4 @@ "typescript": "catalog:", "@typescript/native-preview": "catalog:" } -} \ No newline at end of file +} diff --git a/packages/plugin/src/index.ts b/packages/plugin/src/index.ts index f103749b..1c8c6d2a 100644 --- a/packages/plugin/src/index.ts +++ b/packages/plugin/src/index.ts @@ -151,7 +151,10 @@ export interface Hooks { input: { model: Model; provider: Provider; message: UserMessage }, output: { temperature: number; topP: number; options: Record }, ) => Promise - "permission.ask"?: (input: Permission, output: { status: "ask" | "deny" | "allow" }) => Promise + "permission.ask"?: ( + input: Permission, + output: { status: "ask" | "deny" | "allow" }, + ) => Promise "tool.execute.before"?: ( input: { tool: string; sessionID: string; callID: string }, output: { args: any }, diff --git a/packages/plugin/sst-env.d.ts b/packages/plugin/sst-env.d.ts index b6a7e906..0397645b 100644 --- a/packages/plugin/sst-env.d.ts +++ b/packages/plugin/sst-env.d.ts @@ -6,4 +6,4 @@ /// import "sst" -export {} \ No newline at end of file +export {} diff --git a/packages/script/sst-env.d.ts b/packages/script/sst-env.d.ts index b6a7e906..0397645b 100644 --- a/packages/script/sst-env.d.ts +++ b/packages/script/sst-env.d.ts @@ -6,4 +6,4 @@ /// import "sst" -export {} \ No newline at end of file +export {} diff --git a/packages/sdk/go/.github/workflows/ci.yml b/packages/sdk/go/.github/workflows/ci.yml index 4bf1e907..0f5d45dc 100644 --- a/packages/sdk/go/.github/workflows/ci.yml +++ b/packages/sdk/go/.github/workflows/ci.yml @@ -2,15 +2,15 @@ name: CI on: push: branches-ignore: - - 'generated' - - 'codegen/**' - - 'integrated/**' - - 'stl-preview-head/**' - - 'stl-preview-base/**' + - "generated" + - "codegen/**" + - "integrated/**" + - "stl-preview-head/**" + - "stl-preview-base/**" pull_request: branches-ignore: - - 'stl-preview-head/**' - - 'stl-preview-base/**' + - "stl-preview-head/**" + - "stl-preview-base/**" jobs: lint: diff --git a/packages/sdk/go/.release-please-manifest.json b/packages/sdk/go/.release-please-manifest.json index 4ad3fef3..5e39b941 100644 --- a/packages/sdk/go/.release-please-manifest.json +++ b/packages/sdk/go/.release-please-manifest.json @@ -1,3 +1,3 @@ { ".": "0.18.0" -} \ No newline at end of file +} diff --git a/packages/sdk/go/CHANGELOG.md b/packages/sdk/go/CHANGELOG.md index 498a7802..937fbfdd 100644 --- a/packages/sdk/go/CHANGELOG.md +++ b/packages/sdk/go/CHANGELOG.md @@ -6,7 +6,7 @@ Full Changelog: [v0.17.0...v0.18.0](https://github.com/sst/opencode-sdk-go/compa ### Features -* **api:** api update ([0a7f5e7](https://github.com/sst/opencode-sdk-go/commit/0a7f5e710911506512a132ba39e0593c412beb77)) +- **api:** api update ([0a7f5e7](https://github.com/sst/opencode-sdk-go/commit/0a7f5e710911506512a132ba39e0593c412beb77)) ## 0.17.0 (2025-10-07) @@ -14,7 +14,7 @@ Full Changelog: [v0.16.2...v0.17.0](https://github.com/sst/opencode-sdk-go/compa ### Features -* **api:** api update ([84a3df5](https://github.com/sst/opencode-sdk-go/commit/84a3df50a7ff3d87e5593e4f29dfb5d561f71cc3)) +- **api:** api update ([84a3df5](https://github.com/sst/opencode-sdk-go/commit/84a3df50a7ff3d87e5593e4f29dfb5d561f71cc3)) ## 0.16.2 (2025-09-26) @@ -22,7 +22,7 @@ Full Changelog: [v0.16.1...v0.16.2](https://github.com/sst/opencode-sdk-go/compa ### Bug Fixes -* bugfix for setting JSON keys with special characters ([ac9a36f](https://github.com/sst/opencode-sdk-go/commit/ac9a36feb1c185ebf766d76909d0b86ac805e8a6)) +- bugfix for setting JSON keys with special characters ([ac9a36f](https://github.com/sst/opencode-sdk-go/commit/ac9a36feb1c185ebf766d76909d0b86ac805e8a6)) ## 0.16.1 (2025-09-20) @@ -30,14 +30,13 @@ Full Changelog: [v0.16.0...v0.16.1](https://github.com/sst/opencode-sdk-go/compa ### Bug Fixes -* use slices.Concat instead of sometimes modifying r.Options ([12e8b40](https://github.com/sst/opencode-sdk-go/commit/12e8b40809071095b0abb9b8031686353c8ac149)) - +- use slices.Concat instead of sometimes modifying r.Options ([12e8b40](https://github.com/sst/opencode-sdk-go/commit/12e8b40809071095b0abb9b8031686353c8ac149)) ### Chores -* bump minimum go version to 1.22 ([1a61c5c](https://github.com/sst/opencode-sdk-go/commit/1a61c5cc7e8f68cc1b0c219738cab530cb6aa3a2)) -* do not install brew dependencies in ./scripts/bootstrap by default ([f6d3eaf](https://github.com/sst/opencode-sdk-go/commit/f6d3eafffc20e124bbfae6ac5ddc1b1122ad3e27)) -* update more docs for 1.22 ([a3d0b0f](https://github.com/sst/opencode-sdk-go/commit/a3d0b0f26ed92ce1a6433f5bcf37a6436d268ba5)) +- bump minimum go version to 1.22 ([1a61c5c](https://github.com/sst/opencode-sdk-go/commit/1a61c5cc7e8f68cc1b0c219738cab530cb6aa3a2)) +- do not install brew dependencies in ./scripts/bootstrap by default ([f6d3eaf](https://github.com/sst/opencode-sdk-go/commit/f6d3eafffc20e124bbfae6ac5ddc1b1122ad3e27)) +- update more docs for 1.22 ([a3d0b0f](https://github.com/sst/opencode-sdk-go/commit/a3d0b0f26ed92ce1a6433f5bcf37a6436d268ba5)) ## 0.16.0 (2025-09-17) @@ -45,7 +44,7 @@ Full Changelog: [v0.15.0...v0.16.0](https://github.com/sst/opencode-sdk-go/compa ### Features -* **api:** api update ([46e978e](https://github.com/sst/opencode-sdk-go/commit/46e978e43aee733d5c1c09dc5be6d8ac2a752427)) +- **api:** api update ([46e978e](https://github.com/sst/opencode-sdk-go/commit/46e978e43aee733d5c1c09dc5be6d8ac2a752427)) ## 0.15.0 (2025-09-16) @@ -53,7 +52,7 @@ Full Changelog: [v0.14.0...v0.15.0](https://github.com/sst/opencode-sdk-go/compa ### Features -* **api:** api update ([397048f](https://github.com/sst/opencode-sdk-go/commit/397048faca7a1de7a028edd2254a0ad7797b151f)) +- **api:** api update ([397048f](https://github.com/sst/opencode-sdk-go/commit/397048faca7a1de7a028edd2254a0ad7797b151f)) ## 0.14.0 (2025-09-14) @@ -61,7 +60,7 @@ Full Changelog: [v0.13.0...v0.14.0](https://github.com/sst/opencode-sdk-go/compa ### Features -* **api:** api update ([dad0bc3](https://github.com/sst/opencode-sdk-go/commit/dad0bc3da99f20a0d002a6b94e049fb70f8e6a77)) +- **api:** api update ([dad0bc3](https://github.com/sst/opencode-sdk-go/commit/dad0bc3da99f20a0d002a6b94e049fb70f8e6a77)) ## 0.13.0 (2025-09-14) @@ -69,7 +68,7 @@ Full Changelog: [v0.12.0...v0.13.0](https://github.com/sst/opencode-sdk-go/compa ### Features -* **api:** api update ([80da4fb](https://github.com/sst/opencode-sdk-go/commit/80da4fb4ea9c6afb51a7e7135d9f5560ce6f2a6c)) +- **api:** api update ([80da4fb](https://github.com/sst/opencode-sdk-go/commit/80da4fb4ea9c6afb51a7e7135d9f5560ce6f2a6c)) ## 0.12.0 (2025-09-14) @@ -77,7 +76,7 @@ Full Changelog: [v0.11.0...v0.12.0](https://github.com/sst/opencode-sdk-go/compa ### Features -* **api:** api update ([7e3808b](https://github.com/sst/opencode-sdk-go/commit/7e3808ba349dc653174b32b48a1120c18d2975c2)) +- **api:** api update ([7e3808b](https://github.com/sst/opencode-sdk-go/commit/7e3808ba349dc653174b32b48a1120c18d2975c2)) ## 0.11.0 (2025-09-14) @@ -85,7 +84,7 @@ Full Changelog: [v0.10.0...v0.11.0](https://github.com/sst/opencode-sdk-go/compa ### Features -* **api:** api update ([a3d37f5](https://github.com/sst/opencode-sdk-go/commit/a3d37f5671545866547d351fc21b49809cc8b3c2)) +- **api:** api update ([a3d37f5](https://github.com/sst/opencode-sdk-go/commit/a3d37f5671545866547d351fc21b49809cc8b3c2)) ## 0.10.0 (2025-09-11) @@ -93,7 +92,7 @@ Full Changelog: [v0.9.0...v0.10.0](https://github.com/sst/opencode-sdk-go/compar ### Features -* **api:** api update ([0dc01f6](https://github.com/sst/opencode-sdk-go/commit/0dc01f6695c9b8400a4dc92166c5002bb120cf50)) +- **api:** api update ([0dc01f6](https://github.com/sst/opencode-sdk-go/commit/0dc01f6695c9b8400a4dc92166c5002bb120cf50)) ## 0.9.0 (2025-09-10) @@ -101,7 +100,7 @@ Full Changelog: [v0.8.0...v0.9.0](https://github.com/sst/opencode-sdk-go/compare ### Features -* **api:** api update ([2d3a28d](https://github.com/sst/opencode-sdk-go/commit/2d3a28df5657845aa4d73087e1737d1fc8c3ce1c)) +- **api:** api update ([2d3a28d](https://github.com/sst/opencode-sdk-go/commit/2d3a28df5657845aa4d73087e1737d1fc8c3ce1c)) ## 0.8.0 (2025-09-01) @@ -109,7 +108,7 @@ Full Changelog: [v0.7.0...v0.8.0](https://github.com/sst/opencode-sdk-go/compare ### Features -* **api:** api update ([ae87a71](https://github.com/sst/opencode-sdk-go/commit/ae87a71949994590ace8285a39f0991ef34b664d)) +- **api:** api update ([ae87a71](https://github.com/sst/opencode-sdk-go/commit/ae87a71949994590ace8285a39f0991ef34b664d)) ## 0.7.0 (2025-09-01) @@ -117,7 +116,7 @@ Full Changelog: [v0.6.0...v0.7.0](https://github.com/sst/opencode-sdk-go/compare ### Features -* **api:** api update ([64bb1b1](https://github.com/sst/opencode-sdk-go/commit/64bb1b1ee0cbe153abc6fb7bd9703b47911724d4)) +- **api:** api update ([64bb1b1](https://github.com/sst/opencode-sdk-go/commit/64bb1b1ee0cbe153abc6fb7bd9703b47911724d4)) ## 0.6.0 (2025-09-01) @@ -125,7 +124,7 @@ Full Changelog: [v0.5.0...v0.6.0](https://github.com/sst/opencode-sdk-go/compare ### Features -* **api:** api update ([928e384](https://github.com/sst/opencode-sdk-go/commit/928e3843355f96899f046f002b84372281dad0c8)) +- **api:** api update ([928e384](https://github.com/sst/opencode-sdk-go/commit/928e3843355f96899f046f002b84372281dad0c8)) ## 0.5.0 (2025-08-31) @@ -133,7 +132,7 @@ Full Changelog: [v0.4.0...v0.5.0](https://github.com/sst/opencode-sdk-go/compare ### Features -* **api:** api update ([44b281d](https://github.com/sst/opencode-sdk-go/commit/44b281d0bb39c5022a984ac9d0fca1529ccc0604)) +- **api:** api update ([44b281d](https://github.com/sst/opencode-sdk-go/commit/44b281d0bb39c5022a984ac9d0fca1529ccc0604)) ## 0.4.0 (2025-08-31) @@ -141,7 +140,7 @@ Full Changelog: [v0.3.0...v0.4.0](https://github.com/sst/opencode-sdk-go/compare ### Features -* **api:** api update ([fa9d6ec](https://github.com/sst/opencode-sdk-go/commit/fa9d6ec6472e62f4f6605d0a71a7aa8bf8a24559)) +- **api:** api update ([fa9d6ec](https://github.com/sst/opencode-sdk-go/commit/fa9d6ec6472e62f4f6605d0a71a7aa8bf8a24559)) ## 0.3.0 (2025-08-31) @@ -149,7 +148,7 @@ Full Changelog: [v0.2.0...v0.3.0](https://github.com/sst/opencode-sdk-go/compare ### Features -* **api:** api update ([aae1c06](https://github.com/sst/opencode-sdk-go/commit/aae1c06bb5a93a1cd9c589846a84b3f16246f5da)) +- **api:** api update ([aae1c06](https://github.com/sst/opencode-sdk-go/commit/aae1c06bb5a93a1cd9c589846a84b3f16246f5da)) ## 0.2.0 (2025-08-31) @@ -157,7 +156,7 @@ Full Changelog: [v0.1.0...v0.2.0](https://github.com/sst/opencode-sdk-go/compare ### Features -* **api:** api update ([1472790](https://github.com/sst/opencode-sdk-go/commit/1472790542515f47bd46e2a9e28d8afea024cf9c)) +- **api:** api update ([1472790](https://github.com/sst/opencode-sdk-go/commit/1472790542515f47bd46e2a9e28d8afea024cf9c)) ## 0.1.0 (2025-08-31) @@ -165,61 +164,59 @@ Full Changelog: [v0.0.1...v0.1.0](https://github.com/sst/opencode-sdk-go/compare ### Features -* **api:** api update ([3f03ddd](https://github.com/sst/opencode-sdk-go/commit/3f03dddd5ec0de98f99ce48679077dcae9ceffd6)) -* **api:** api update ([e9f79c4](https://github.com/sst/opencode-sdk-go/commit/e9f79c4792b21ef64ab0431ffd76f5a71e04d182)) -* **api:** api update ([139a686](https://github.com/sst/opencode-sdk-go/commit/139a6862d2f0ab0c8ea791663d736868be3e96e6)) -* **api:** api update ([2ed0800](https://github.com/sst/opencode-sdk-go/commit/2ed0800b2c5b99877e9f7fde669a6c005fad6b77)) -* **api:** api update ([88a87a4](https://github.com/sst/opencode-sdk-go/commit/88a87a458f56ce0c18b502c73da933f614f56e8b)) -* **api:** api update ([0e5d65b](https://github.com/sst/opencode-sdk-go/commit/0e5d65b571e7b30dc6347e6730098878ebba3a42)) -* **api:** api update ([ba381f1](https://github.com/sst/opencode-sdk-go/commit/ba381f1e07aad24e9824df7d53befae2a644f69f)) -* **api:** api update ([3f429f5](https://github.com/sst/opencode-sdk-go/commit/3f429f5b4be5607433ef5fdc0d5bf67fe590d039)) -* **api:** api update ([9f34787](https://github.com/sst/opencode-sdk-go/commit/9f347876b35b7f898060c1a5f71c322e95978e3e)) -* **api:** api update ([379c8e0](https://github.com/sst/opencode-sdk-go/commit/379c8e00197e13aebaf2f2d61277b125f1f90011)) -* **api:** api update ([550511c](https://github.com/sst/opencode-sdk-go/commit/550511c4c5b5055ac8ff22b7b11731331bd9d088)) -* **api:** api update ([547f0c2](https://github.com/sst/opencode-sdk-go/commit/547f0c262f2df1ce83eaa7267d68be64bb29b841)) -* **api:** api update ([b7b0720](https://github.com/sst/opencode-sdk-go/commit/b7b07204bff314da24b1819c128835a43ef64065)) -* **api:** api update ([7250ffc](https://github.com/sst/opencode-sdk-go/commit/7250ffcba262b916c958ddecc2a42927982db39f)) -* **api:** api update ([17fbab7](https://github.com/sst/opencode-sdk-go/commit/17fbab73111a3eae488737c69b12370bc69c65f7)) -* **api:** api update ([1270b5c](https://github.com/sst/opencode-sdk-go/commit/1270b5cd81e6ac769dcd92ade6d877891bf51bd5)) -* **api:** api update ([a238d4a](https://github.com/sst/opencode-sdk-go/commit/a238d4abd6ed7d15f3547d27a4b6ecf4aec8431e)) -* **api:** api update ([7475655](https://github.com/sst/opencode-sdk-go/commit/7475655aca577fe4f807c2f02f92171f6a358e9c)) -* **api:** api update ([429d258](https://github.com/sst/opencode-sdk-go/commit/429d258bb56e9cdeb1528be3944bf5537ac26a96)) -* **api:** api update ([f250915](https://github.com/sst/opencode-sdk-go/commit/f2509157eaf1b453e741ee9482127cad2e3ace25)) -* **api:** api update ([5efc987](https://github.com/sst/opencode-sdk-go/commit/5efc987353801d1e772c20edf162b1c75da32743)) -* **api:** api update ([98a8350](https://github.com/sst/opencode-sdk-go/commit/98a83504f7cfc361e83314c3e79a4e9ff53f0560)) -* **api:** api update ([6da8bf8](https://github.com/sst/opencode-sdk-go/commit/6da8bf8bfe91d45991fb580753d77c5534fc0b1b)) -* **api:** api update ([f8c7148](https://github.com/sst/opencode-sdk-go/commit/f8c7148ae56143823186e2675a78e82676154956)) -* **api:** manual updates ([7cf038f](https://github.com/sst/opencode-sdk-go/commit/7cf038ffae5da1b77e1cef11b5fa166a53b467f2)) -* **api:** update via SDK Studio ([068a0eb](https://github.com/sst/opencode-sdk-go/commit/068a0eb025010da0c8d86fa1bb496a39dbedcef9)) -* **api:** update via SDK Studio ([ca651ed](https://github.com/sst/opencode-sdk-go/commit/ca651edaf71d1f3678f929287474f5bc4f1aad10)) -* **api:** update via SDK Studio ([13550a5](https://github.com/sst/opencode-sdk-go/commit/13550a5c65d77325e945ed99fe0799cd1107b775)) -* **api:** update via SDK Studio ([7b73730](https://github.com/sst/opencode-sdk-go/commit/7b73730c7fa62ba966dda3541c3e97b49be8d2bf)) -* **api:** update via SDK Studio ([9e39a59](https://github.com/sst/opencode-sdk-go/commit/9e39a59b3d5d1bd5e64633732521fb28362cc70e)) -* **api:** update via SDK Studio ([9609d1b](https://github.com/sst/opencode-sdk-go/commit/9609d1b1db7806d00cb846c9914cb4935cdedf52)) -* **api:** update via SDK Studio ([51315fa](https://github.com/sst/opencode-sdk-go/commit/51315fa2eae424743ea79701e67d44447c44144d)) -* **api:** update via SDK Studio ([af07955](https://github.com/sst/opencode-sdk-go/commit/af0795543240aefaf04fc7663a348825541c79ed)) -* **api:** update via SDK Studio ([5e3468a](https://github.com/sst/opencode-sdk-go/commit/5e3468a0aaa5ed3b13e019c3a24e0ba9147d1675)) -* **api:** update via SDK Studio ([0a73e04](https://github.com/sst/opencode-sdk-go/commit/0a73e04c23c90b2061611edaa8fd6282dc0ce397)) -* **api:** update via SDK Studio ([9b7883a](https://github.com/sst/opencode-sdk-go/commit/9b7883a144eeac526d9d04538e0876a9d18bb844)) -* **client:** expand max streaming buffer size ([76303e5](https://github.com/sst/opencode-sdk-go/commit/76303e51067e78e732af26ced9d83b8bad7655c3)) -* **client:** support optional json html escaping ([449748f](https://github.com/sst/opencode-sdk-go/commit/449748f35a1d8cb6f91dc36d25bf9489f4f371bd)) - +- **api:** api update ([3f03ddd](https://github.com/sst/opencode-sdk-go/commit/3f03dddd5ec0de98f99ce48679077dcae9ceffd6)) +- **api:** api update ([e9f79c4](https://github.com/sst/opencode-sdk-go/commit/e9f79c4792b21ef64ab0431ffd76f5a71e04d182)) +- **api:** api update ([139a686](https://github.com/sst/opencode-sdk-go/commit/139a6862d2f0ab0c8ea791663d736868be3e96e6)) +- **api:** api update ([2ed0800](https://github.com/sst/opencode-sdk-go/commit/2ed0800b2c5b99877e9f7fde669a6c005fad6b77)) +- **api:** api update ([88a87a4](https://github.com/sst/opencode-sdk-go/commit/88a87a458f56ce0c18b502c73da933f614f56e8b)) +- **api:** api update ([0e5d65b](https://github.com/sst/opencode-sdk-go/commit/0e5d65b571e7b30dc6347e6730098878ebba3a42)) +- **api:** api update ([ba381f1](https://github.com/sst/opencode-sdk-go/commit/ba381f1e07aad24e9824df7d53befae2a644f69f)) +- **api:** api update ([3f429f5](https://github.com/sst/opencode-sdk-go/commit/3f429f5b4be5607433ef5fdc0d5bf67fe590d039)) +- **api:** api update ([9f34787](https://github.com/sst/opencode-sdk-go/commit/9f347876b35b7f898060c1a5f71c322e95978e3e)) +- **api:** api update ([379c8e0](https://github.com/sst/opencode-sdk-go/commit/379c8e00197e13aebaf2f2d61277b125f1f90011)) +- **api:** api update ([550511c](https://github.com/sst/opencode-sdk-go/commit/550511c4c5b5055ac8ff22b7b11731331bd9d088)) +- **api:** api update ([547f0c2](https://github.com/sst/opencode-sdk-go/commit/547f0c262f2df1ce83eaa7267d68be64bb29b841)) +- **api:** api update ([b7b0720](https://github.com/sst/opencode-sdk-go/commit/b7b07204bff314da24b1819c128835a43ef64065)) +- **api:** api update ([7250ffc](https://github.com/sst/opencode-sdk-go/commit/7250ffcba262b916c958ddecc2a42927982db39f)) +- **api:** api update ([17fbab7](https://github.com/sst/opencode-sdk-go/commit/17fbab73111a3eae488737c69b12370bc69c65f7)) +- **api:** api update ([1270b5c](https://github.com/sst/opencode-sdk-go/commit/1270b5cd81e6ac769dcd92ade6d877891bf51bd5)) +- **api:** api update ([a238d4a](https://github.com/sst/opencode-sdk-go/commit/a238d4abd6ed7d15f3547d27a4b6ecf4aec8431e)) +- **api:** api update ([7475655](https://github.com/sst/opencode-sdk-go/commit/7475655aca577fe4f807c2f02f92171f6a358e9c)) +- **api:** api update ([429d258](https://github.com/sst/opencode-sdk-go/commit/429d258bb56e9cdeb1528be3944bf5537ac26a96)) +- **api:** api update ([f250915](https://github.com/sst/opencode-sdk-go/commit/f2509157eaf1b453e741ee9482127cad2e3ace25)) +- **api:** api update ([5efc987](https://github.com/sst/opencode-sdk-go/commit/5efc987353801d1e772c20edf162b1c75da32743)) +- **api:** api update ([98a8350](https://github.com/sst/opencode-sdk-go/commit/98a83504f7cfc361e83314c3e79a4e9ff53f0560)) +- **api:** api update ([6da8bf8](https://github.com/sst/opencode-sdk-go/commit/6da8bf8bfe91d45991fb580753d77c5534fc0b1b)) +- **api:** api update ([f8c7148](https://github.com/sst/opencode-sdk-go/commit/f8c7148ae56143823186e2675a78e82676154956)) +- **api:** manual updates ([7cf038f](https://github.com/sst/opencode-sdk-go/commit/7cf038ffae5da1b77e1cef11b5fa166a53b467f2)) +- **api:** update via SDK Studio ([068a0eb](https://github.com/sst/opencode-sdk-go/commit/068a0eb025010da0c8d86fa1bb496a39dbedcef9)) +- **api:** update via SDK Studio ([ca651ed](https://github.com/sst/opencode-sdk-go/commit/ca651edaf71d1f3678f929287474f5bc4f1aad10)) +- **api:** update via SDK Studio ([13550a5](https://github.com/sst/opencode-sdk-go/commit/13550a5c65d77325e945ed99fe0799cd1107b775)) +- **api:** update via SDK Studio ([7b73730](https://github.com/sst/opencode-sdk-go/commit/7b73730c7fa62ba966dda3541c3e97b49be8d2bf)) +- **api:** update via SDK Studio ([9e39a59](https://github.com/sst/opencode-sdk-go/commit/9e39a59b3d5d1bd5e64633732521fb28362cc70e)) +- **api:** update via SDK Studio ([9609d1b](https://github.com/sst/opencode-sdk-go/commit/9609d1b1db7806d00cb846c9914cb4935cdedf52)) +- **api:** update via SDK Studio ([51315fa](https://github.com/sst/opencode-sdk-go/commit/51315fa2eae424743ea79701e67d44447c44144d)) +- **api:** update via SDK Studio ([af07955](https://github.com/sst/opencode-sdk-go/commit/af0795543240aefaf04fc7663a348825541c79ed)) +- **api:** update via SDK Studio ([5e3468a](https://github.com/sst/opencode-sdk-go/commit/5e3468a0aaa5ed3b13e019c3a24e0ba9147d1675)) +- **api:** update via SDK Studio ([0a73e04](https://github.com/sst/opencode-sdk-go/commit/0a73e04c23c90b2061611edaa8fd6282dc0ce397)) +- **api:** update via SDK Studio ([9b7883a](https://github.com/sst/opencode-sdk-go/commit/9b7883a144eeac526d9d04538e0876a9d18bb844)) +- **client:** expand max streaming buffer size ([76303e5](https://github.com/sst/opencode-sdk-go/commit/76303e51067e78e732af26ced9d83b8bad7655c3)) +- **client:** support optional json html escaping ([449748f](https://github.com/sst/opencode-sdk-go/commit/449748f35a1d8cb6f91dc36d25bf9489f4f371bd)) ### Bug Fixes -* **client:** process custom base url ahead of time ([9b360d6](https://github.com/sst/opencode-sdk-go/commit/9b360d642cf6f302104308af5622e17099899e5f)) -* **client:** resolve lint errors in streaming tests ([4d36cb0](https://github.com/sst/opencode-sdk-go/commit/4d36cb09fc9d436734d5dab1c499acaa88568ff7)) -* close body before retrying ([4da3f7f](https://github.com/sst/opencode-sdk-go/commit/4da3f7f372bad222a189ba3eabcfde3373166ae5)) -* don't try to deserialize as json when ResponseBodyInto is []byte ([595291f](https://github.com/sst/opencode-sdk-go/commit/595291f6dba6af472f160b9f8e3d145002f43a4a)) - +- **client:** process custom base url ahead of time ([9b360d6](https://github.com/sst/opencode-sdk-go/commit/9b360d642cf6f302104308af5622e17099899e5f)) +- **client:** resolve lint errors in streaming tests ([4d36cb0](https://github.com/sst/opencode-sdk-go/commit/4d36cb09fc9d436734d5dab1c499acaa88568ff7)) +- close body before retrying ([4da3f7f](https://github.com/sst/opencode-sdk-go/commit/4da3f7f372bad222a189ba3eabcfde3373166ae5)) +- don't try to deserialize as json when ResponseBodyInto is []byte ([595291f](https://github.com/sst/opencode-sdk-go/commit/595291f6dba6af472f160b9f8e3d145002f43a4a)) ### Chores -* **ci:** only run for pushes and fork pull requests ([bea59b8](https://github.com/sst/opencode-sdk-go/commit/bea59b886800ef555f89c47a9256d6392ed2e53d)) -* **internal:** codegen related update ([6a22ce6](https://github.com/sst/opencode-sdk-go/commit/6a22ce6df155f5003e80b8a75686a9e513a5568a)) -* **internal:** fix lint script for tests ([391c482](https://github.com/sst/opencode-sdk-go/commit/391c482148ed0a77c4ad52807abeb2d540b56797)) -* **internal:** update comment in script ([b7f1c3e](https://github.com/sst/opencode-sdk-go/commit/b7f1c3e16935c71e243004b8f321d661cd8e9474)) -* lint tests ([616796b](https://github.com/sst/opencode-sdk-go/commit/616796b761704bde6be5c6c2428f28c79c7f05ff)) -* lint tests in subpackages ([50c82ff](https://github.com/sst/opencode-sdk-go/commit/50c82ff0757c973834b68adc22566b70f767b611)) -* sync repo ([2f34d5d](https://github.com/sst/opencode-sdk-go/commit/2f34d5d53e56e9cdc3df99be7ee7efc83dd977a3)) -* update @stainless-api/prism-cli to v5.15.0 ([2f24852](https://github.com/sst/opencode-sdk-go/commit/2f2485216d4f4891d1fbfbc23ff8410c2f35152a)) +- **ci:** only run for pushes and fork pull requests ([bea59b8](https://github.com/sst/opencode-sdk-go/commit/bea59b886800ef555f89c47a9256d6392ed2e53d)) +- **internal:** codegen related update ([6a22ce6](https://github.com/sst/opencode-sdk-go/commit/6a22ce6df155f5003e80b8a75686a9e513a5568a)) +- **internal:** fix lint script for tests ([391c482](https://github.com/sst/opencode-sdk-go/commit/391c482148ed0a77c4ad52807abeb2d540b56797)) +- **internal:** update comment in script ([b7f1c3e](https://github.com/sst/opencode-sdk-go/commit/b7f1c3e16935c71e243004b8f321d661cd8e9474)) +- lint tests ([616796b](https://github.com/sst/opencode-sdk-go/commit/616796b761704bde6be5c6c2428f28c79c7f05ff)) +- lint tests in subpackages ([50c82ff](https://github.com/sst/opencode-sdk-go/commit/50c82ff0757c973834b68adc22566b70f767b611)) +- sync repo ([2f34d5d](https://github.com/sst/opencode-sdk-go/commit/2f34d5d53e56e9cdc3df99be7ee7efc83dd977a3)) +- update @stainless-api/prism-cli to v5.15.0 ([2f24852](https://github.com/sst/opencode-sdk-go/commit/2f2485216d4f4891d1fbfbc23ff8410c2f35152a)) diff --git a/packages/sdk/go/release-please-config.json b/packages/sdk/go/release-please-config.json index a38198ec..32960ce2 100644 --- a/packages/sdk/go/release-please-config.json +++ b/packages/sdk/go/release-please-config.json @@ -60,8 +60,5 @@ } ], "release-type": "go", - "extra-files": [ - "internal/version.go", - "README.md" - ] -} \ No newline at end of file + "extra-files": ["internal/version.go", "README.md"] +} diff --git a/packages/sdk/js/package.json b/packages/sdk/js/package.json index 97830ba1..bff4866a 100644 --- a/packages/sdk/js/package.json +++ b/packages/sdk/js/package.json @@ -26,4 +26,4 @@ "publishConfig": { "directory": "dist" } -} \ No newline at end of file +} diff --git a/packages/sdk/js/src/server.ts b/packages/sdk/js/src/server.ts index a09e14ab..15147745 100644 --- a/packages/sdk/js/src/server.ts +++ b/packages/sdk/js/src/server.ts @@ -28,13 +28,17 @@ export async function createOpencodeServer(options?: ServerOptions) { options ?? {}, ) - const proc = spawn(`opencode`, [`serve`, `--hostname=${options.hostname}`, `--port=${options.port}`], { - signal: options.signal, - env: { - ...process.env, - OPENCODE_CONFIG_CONTENT: JSON.stringify(options.config ?? {}), + const proc = spawn( + `opencode`, + [`serve`, `--hostname=${options.hostname}`, `--port=${options.port}`], + { + signal: options.signal, + env: { + ...process.env, + OPENCODE_CONFIG_CONTENT: JSON.stringify(options.config ?? {}), + }, }, - }) + ) const url = await new Promise((resolve, reject) => { const id = setTimeout(() => { diff --git a/packages/sdk/js/sst-env.d.ts b/packages/sdk/js/sst-env.d.ts index 9b9de732..bd558821 100644 --- a/packages/sdk/js/sst-env.d.ts +++ b/packages/sdk/js/sst-env.d.ts @@ -6,4 +6,4 @@ /// import "sst" -export {} \ No newline at end of file +export {} diff --git a/packages/sdk/python/README.md b/packages/sdk/python/README.md index a17c36ab..5d54434a 100644 --- a/packages/sdk/python/README.md +++ b/packages/sdk/python/README.md @@ -2,50 +2,59 @@ This package provides a Python SDK for the Opencode API. It is generated using openapi-python-client (not Stainless). - Documentation + - Full docs: see `mkdocs` site under `packages/sdk/python/docs/` - Preview locally: + ```bash uv run --project packages/sdk/python mkdocs serve -f packages/sdk/python/mkdocs.yml ``` Badges + - PyPI: https://img.shields.io/pypi/v/opencode-ai?style=flat-square Requirements + - Python 3.8+ - uv (recommended) -> https://docs.astral.sh/uv/ - openapi-python-client (invoked via `uvx`) Install uv + ```bash # macOS/Linux curl -LsSf https://astral.sh/uv/install.sh | sh ``` Set up the environment (from this directory) + ```bash uv sync --dev ``` Generate client code (from CLI-generated spec) + ```bash # From repository root OR from this directory uv run python packages/sdk/python/scripts/generate.py --source cli ``` Alternatively, fetch spec from a running server + ```bash uv run python packages/sdk/python/scripts/generate.py --source server --server-url http://localhost:4096/doc ``` This will: -1) Produce an OpenAPI spec from the local CLI or a running server -2) Run openapi-python-client (via `uvx`) to generate client code -3) Copy the generated Python package into src/opencode_ai + +1. Produce an OpenAPI spec from the local CLI or a running server +2. Run openapi-python-client (via `uvx`) to generate client code +3. Copy the generated Python package into src/opencode_ai Usage (after generation) + ```python from opencode_ai import OpenCodeClient @@ -77,6 +86,7 @@ client = OpenCodeClient(retries=2, backoff_factor=0.1) ``` Notes + - We intentionally do not use Stainless for the Python SDK. - The generator targets OpenAPI 3.1 emitted by the opencode server at /doc. - See scripts/generate.py for details and customization points. diff --git a/packages/sdk/python/docs/generation.md b/packages/sdk/python/docs/generation.md index f949760a..2151e370 100644 --- a/packages/sdk/python/docs/generation.md +++ b/packages/sdk/python/docs/generation.md @@ -3,10 +3,12 @@ The SDK is generated from the Opencode server's OpenAPI 3.1 spec. Two source modes are supported: + - CLI (default): runs `bun dev generate` to emit the OpenAPI JSON - Server: fetches `http://localhost:4096/doc` from a running server Generator command + ```bash # From repo root uv run --project packages/sdk/python python packages/sdk/python/scripts/generate.py --source cli @@ -15,5 +17,6 @@ uv run --project packages/sdk/python python packages/sdk/python/scripts/generate ``` Post-generation + - The generator injects `extras.py` (OpenCodeClient) and patches `__init__.py` to export it - Code is formatted with `ruff` (imports) and `black` diff --git a/packages/sdk/python/docs/index.md b/packages/sdk/python/docs/index.md index bc7b550f..e0cfe5d5 100644 --- a/packages/sdk/python/docs/index.md +++ b/packages/sdk/python/docs/index.md @@ -3,6 +3,7 @@ The official Python client for the Opencode API, generated from the OpenAPI spec and extended with ergonomic helpers. Highlights + - Provider-agnostic client generated from OpenAPI 3.1 - Thin convenience wrapper (OpenCodeClient) for common tasks - Sync and async SSE streaming for live event feeds diff --git a/packages/sdk/python/docs/installation.md b/packages/sdk/python/docs/installation.md index f66e217a..fe48f518 100644 --- a/packages/sdk/python/docs/installation.md +++ b/packages/sdk/python/docs/installation.md @@ -1,26 +1,31 @@ # Installation Requirements + - Python 3.8+ - uv (recommended) -> https://docs.astral.sh/uv/ Install uv + ```bash curl -LsSf https://astral.sh/uv/install.sh | sh ``` Project setup + ```bash # From repo root or this directory uv sync --dev --project packages/sdk/python ``` Using pip (alternative) + ```bash pip install opencode-ai ``` Preview docs locally + ```bash # From repo root uv run --project packages/sdk/python mkdocs serve -f packages/sdk/python/mkdocs.yml diff --git a/packages/sdk/python/docs/publishing.md b/packages/sdk/python/docs/publishing.md index c598baa8..c05a12a3 100644 --- a/packages/sdk/python/docs/publishing.md +++ b/packages/sdk/python/docs/publishing.md @@ -3,6 +3,7 @@ Automated publishing runs on GitHub Releases. Workflow + - Create a new Release (the tag value becomes the package version) - The `publish-python-sdk` workflow will: - Generate the SDK from OpenAPI (CLI path) @@ -10,9 +11,11 @@ Workflow - Build wheel/sdist and upload to PyPI Prerequisites + - Repository secret: `PYPI_API_TOKEN` Manual publish + ```bash # TestPyPI REPOSITORY=testpypi PYPI_TOKEN=$TEST_PYPI_API_TOKEN \ diff --git a/packages/sdk/python/docs/testing.md b/packages/sdk/python/docs/testing.md index 3119035d..e2c777e3 100644 --- a/packages/sdk/python/docs/testing.md +++ b/packages/sdk/python/docs/testing.md @@ -11,5 +11,6 @@ uv run --project packages/sdk/python pytest -q ``` Notes + - Integration test starts a headless opencode server via Bun in a subprocess - SSE behavior is validated using real streaming from the server diff --git a/packages/sdk/python/mkdocs.yml b/packages/sdk/python/mkdocs.yml index 25de28fb..565eb770 100644 --- a/packages/sdk/python/mkdocs.yml +++ b/packages/sdk/python/mkdocs.yml @@ -3,7 +3,7 @@ site_description: Official Python SDK for the Opencode API site_url: https://opencode.ai repo_url: https://github.com/sst/opencode repo_name: sst/opencode -edit_uri: '' +edit_uri: "" theme: name: material features: diff --git a/packages/slack/src/index.ts b/packages/slack/src/index.ts index 046f069e..2a952b63 100644 --- a/packages/slack/src/index.ts +++ b/packages/slack/src/index.ts @@ -19,7 +19,10 @@ const opencode = await createOpencode({ }) console.log("✅ Opencode server ready") -const sessions = new Map() +const sessions = new Map< + string, + { client: any; server: any; sessionId: string; channel: string; thread: string } +>() ;(async () => { const events = await opencode.client.event.subscribe() for await (const event of events.stream) { @@ -81,7 +84,10 @@ app.message(async ({ message, say }) => { if (createResult.error) { console.error("❌ Failed to create session:", createResult.error) - await say({ text: "Sorry, I had trouble creating a session. Please try again.", thread_ts: thread }) + await say({ + text: "Sorry, I had trouble creating a session. Please try again.", + thread_ts: thread, + }) return } @@ -108,7 +114,10 @@ app.message(async ({ message, say }) => { if (result.error) { console.error("❌ Failed to send message:", result.error) - await say({ text: "Sorry, I had trouble processing your message. Please try again.", thread_ts: thread }) + await say({ + text: "Sorry, I had trouble processing your message. Please try again.", + thread_ts: thread, + }) return } diff --git a/packages/slack/sst-env.d.ts b/packages/slack/sst-env.d.ts index b6a7e906..0397645b 100644 --- a/packages/slack/sst-env.d.ts +++ b/packages/slack/sst-env.d.ts @@ -6,4 +6,4 @@ /// import "sst" -export {} \ No newline at end of file +export {} diff --git a/packages/ui/src/assets/favicon/site.webmanifest b/packages/ui/src/assets/favicon/site.webmanifest index f7522f8f..41290e84 100644 --- a/packages/ui/src/assets/favicon/site.webmanifest +++ b/packages/ui/src/assets/favicon/site.webmanifest @@ -18,4 +18,4 @@ "theme_color": "#ffffff", "background_color": "#ffffff", "display": "standalone" -} \ No newline at end of file +} diff --git a/packages/ui/src/components/checkbox.tsx b/packages/ui/src/components/checkbox.tsx index 2009a430..ac9abfda 100644 --- a/packages/ui/src/components/checkbox.tsx +++ b/packages/ui/src/components/checkbox.tsx @@ -9,7 +9,14 @@ export interface CheckboxProps extends ParentProps local.children) return ( @@ -35,7 +42,9 @@ export function Checkbox(props: CheckboxProps) { - {local.description} + + {local.description} +
    diff --git a/packages/ui/src/components/dialog.tsx b/packages/ui/src/components/dialog.tsx index ce7a4b3a..fdbb9022 100644 --- a/packages/ui/src/components/dialog.tsx +++ b/packages/ui/src/components/dialog.tsx @@ -38,7 +38,11 @@ export function DialogRoot(props: DialogProps) { return ( - + {props.trigger} diff --git a/packages/ui/src/styles/base.css b/packages/ui/src/styles/base.css index b80398e1..02b47323 100644 --- a/packages/ui/src/styles/base.css +++ b/packages/ui/src/styles/base.css @@ -269,8 +269,8 @@ textarea, crash when using `color-mix(…)` with `currentcolor`. (https://github.com/tailwindlabs/tailwindcss/issues/17194) */ -@supports (not (-webkit-appearance: -apple-pay-button)) /* Not Safari */ or (contain-intrinsic-size: 1px) - /* Safari 17+ */ { +@supports (not (-webkit-appearance: -apple-pay-button)) /* Not Safari */ or + (contain-intrinsic-size: 1px) /* Safari 17+ */ { ::placeholder { color: color-mix(in oklab, currentcolor 50%, transparent); } diff --git a/packages/ui/src/styles/tailwind/colors.css b/packages/ui/src/styles/tailwind/colors.css index 527c4310..a5f982d6 100644 --- a/packages/ui/src/styles/tailwind/colors.css +++ b/packages/ui/src/styles/tailwind/colors.css @@ -232,4 +232,4 @@ --color-border-weaker-focus: var(--border-weaker-focus); --color-button-ghost-hover: var(--button-ghost-hover); --color-button-ghost-hover2: var(--button-ghost-hover2); -} \ No newline at end of file +} diff --git a/packages/ui/src/styles/theme.css b/packages/ui/src/styles/theme.css index 20c43b10..6187eef9 100644 --- a/packages/ui/src/styles/theme.css +++ b/packages/ui/src/styles/theme.css @@ -56,23 +56,18 @@ 0 6px 8px -4px rgba(19, 16, 16, 0.12), 0 4px 3px -2px rgba(19, 16, 16, 0.12), 0 1px 2px -1px rgba(19, 16, 16, 0.12); --shadow-xs-border: - 0 0 0 1px var(--border-base, rgba(11, 6, 0, 0.20)), - 0 1px 2px -1px rgba(19, 16, 16, 0.04), - 0 1px 2px 0 rgba(19, 16, 16, 0.06), - 0 1px 3px 0 rgba(19, 16, 16, 0.08); + 0 0 0 1px var(--border-base, rgba(11, 6, 0, 0.2)), 0 1px 2px -1px rgba(19, 16, 16, 0.04), + 0 1px 2px 0 rgba(19, 16, 16, 0.06), 0 1px 3px 0 rgba(19, 16, 16, 0.08); --shadow-xs-border-select: 0 0 0 3px var(--border-weak-selected, rgba(1, 103, 255, 0.29)), 0 0 0 1px var(--border-selected, rgba(0, 74, 255, 0.99)), 0 1px 2px -1px rgba(19, 16, 16, 0.25), 0 1px 2px 0 rgba(19, 16, 16, 0.08), 0 1px 3px 0 rgba(19, 16, 16, 0.12); --shadow-xs-border-focus: - 0 0 0 1px var(--border-base, rgba(11, 6, 0, 0.20)), - 0 1px 2px -1px rgba(19, 16, 16, 0.25), - 0 1px 2px 0 rgba(19, 16, 16, 0.08), - 0 1px 3px 0 rgba(19, 16, 16, 0.12), - 0 0 0 2px var(--background-weak, #F1F0F0), + 0 0 0 1px var(--border-base, rgba(11, 6, 0, 0.2)), 0 1px 2px -1px rgba(19, 16, 16, 0.25), + 0 1px 2px 0 rgba(19, 16, 16, 0.08), 0 1px 3px 0 rgba(19, 16, 16, 0.12), + 0 0 0 2px var(--background-weak, #f1f0f0), 0 0 0 3px var(--border-selected, rgba(0, 74, 255, 0.99)); - --text-mix-blend-mode: multiply; } @@ -413,7 +408,7 @@ --text-on-brand-weaker: var(--smoke-dark-alpha-8); --text-on-brand-strong: var(--smoke-dark-alpha-12); --button-secondary-base: var(--smoke-dark-4); - --button-secondary-hover: #2A2727; + --button-secondary-hover: #2a2727; --border-base: var(--smoke-dark-alpha-7); --border-hover: var(--smoke-dark-alpha-8); --border-active: var(--smoke-dark-alpha-9); diff --git a/packages/ui/sst-env.d.ts b/packages/ui/sst-env.d.ts index b6a7e906..0397645b 100644 --- a/packages/ui/sst-env.d.ts +++ b/packages/ui/sst-env.d.ts @@ -6,4 +6,4 @@ /// import "sst" -export {} \ No newline at end of file +export {} diff --git a/packages/ui/tsconfig.json b/packages/ui/tsconfig.json index 440aa8f9..c3531440 100644 --- a/packages/ui/tsconfig.json +++ b/packages/ui/tsconfig.json @@ -13,16 +13,9 @@ "module": "ESNext", "moduleResolution": "bundler", "noEmit": true, - "lib": [ - "es2022", - "dom", - "dom.iterable" - ], + "lib": ["es2022", "dom", "dom.iterable"], // Type Checking & Safety "strict": true, - "types": [ - "vite/client", - "bun" - ] + "types": ["vite/client", "bun"] } } diff --git a/packages/web/config.mjs b/packages/web/config.mjs index 5e2c8d3e..7adb147c 100644 --- a/packages/web/config.mjs +++ b/packages/web/config.mjs @@ -2,7 +2,8 @@ const stage = process.env.SST_STAGE || "dev" export default { url: stage === "production" ? "https://opencode.ai" : `https://${stage}.opencode.ai`, - console: stage === "production" ? "https://opencode.ai/auth" : `https://${stage}.opencode.ai/auth`, + console: + stage === "production" ? "https://opencode.ai/auth" : `https://${stage}.opencode.ai/auth`, email: "contact@anoma.ly", socialCard: "https://social-cards.sst.dev", github: "https://github.com/sst/opencode", diff --git a/packages/web/src/components/Share.tsx b/packages/web/src/components/Share.tsx index 06244971..486b6e44 100644 --- a/packages/web/src/components/Share.tsx +++ b/packages/web/src/components/Share.tsx @@ -1,4 +1,14 @@ -import { For, Show, onMount, Suspense, onCleanup, createMemo, createSignal, SuspenseList, createEffect } from "solid-js" +import { + For, + Show, + onMount, + Suspense, + onCleanup, + createMemo, + createSignal, + SuspenseList, + createEffect, +} from "solid-js" import { DateTime } from "luxon" import { createStore, reconcile, unwrap } from "solid-js/store" import { IconArrowDown } from "./icons" @@ -66,8 +76,13 @@ export default function Share(props: { id: string; api: string; info: Session.In }, messages: {}, }) - const messages = createMemo(() => Object.values(store.messages).toSorted((a, b) => a.id?.localeCompare(b.id))) - const [connectionStatus, setConnectionStatus] = createSignal<[Status, string?]>(["disconnected", "Disconnected"]) + const messages = createMemo(() => + Object.values(store.messages).toSorted((a, b) => a.id?.localeCompare(b.id)), + ) + const [connectionStatus, setConnectionStatus] = createSignal<[Status, string?]>([ + "disconnected", + "Disconnected", + ]) createEffect(() => { console.log(unwrap(store)) }) @@ -330,7 +345,9 @@ export default function Share(props: { id: string; api: string; info: Session.In
    {DateTime.fromMillis(data().created || 0).toLocaleString(DateTime.DATETIME_MED)}
    @@ -352,7 +369,10 @@ export default function Share(props: { id: string; api: string; info: Session.In if (x.type === "text" && x.synthetic === true) return false if (x.type === "tool" && x.tool === "todoread") return false if (x.type === "text" && !x.text) return false - if (x.type === "tool" && (x.state.status === "pending" || x.state.status === "running")) + if ( + x.type === "tool" && + (x.state.status === "pending" || x.state.status === "running") + ) return false return true }), @@ -364,7 +384,8 @@ export default function Share(props: { id: string; api: string; info: Session.In {(part, partIndex) => { const last = createMemo( () => - data().messages.length === msgIndex() + 1 && filteredParts().length === partIndex() + 1, + data().messages.length === msgIndex() + 1 && + filteredParts().length === partIndex() + 1, ) onMount(() => { @@ -381,7 +402,9 @@ export default function Share(props: { id: string; api: string; info: Session.In } }) - return + return ( + + ) }} @@ -406,7 +429,11 @@ export default function Share(props: { id: string; api: string; info: Session.In
  • Input Tokens - {data().tokens.input ? {data().tokens.input} : } + {data().tokens.input ? ( + {data().tokens.input} + ) : ( + + )}
  • Output Tokens @@ -560,7 +587,8 @@ export function fromV1(v1: Message.Info): MessageWithParts { } } - const { title, time, ...metadata } = v1.metadata.tool[part.toolInvocation.toolCallId] + const { title, time, ...metadata } = + v1.metadata.tool[part.toolInvocation.toolCallId] if (part.toolInvocation.state === "call") { return { status: "running", diff --git a/packages/web/src/components/icons/index.tsx b/packages/web/src/components/icons/index.tsx index 62445611..9aef7a92 100644 --- a/packages/web/src/components/icons/index.tsx +++ b/packages/web/src/components/icons/index.tsx @@ -4418,7 +4418,14 @@ export function IconMultiSelect(props: JSX.SvgSVGAttributes) { } export function IconSettings(props: JSX.SvgSVGAttributes) { return ( - + +
    { diff --git a/packages/web/src/components/share/content-code.tsx b/packages/web/src/components/share/content-code.tsx index 2f383b8b..0f9d28fa 100644 --- a/packages/web/src/components/share/content-code.tsx +++ b/packages/web/src/components/share/content-code.tsx @@ -26,7 +26,11 @@ export function ContentCode(props: Props) { ) return ( -
    +
    ) } diff --git a/packages/web/src/components/share/content-diff.tsx b/packages/web/src/components/share/content-diff.tsx index 9ccd554d..79c2723c 100644 --- a/packages/web/src/components/share/content-diff.tsx +++ b/packages/web/src/components/share/content-diff.tsx @@ -124,7 +124,9 @@ export function ContentDiff(props: Props) { // Collect consecutive modified/removed/added rows while ( i < currentRows.length && - (currentRows[i].type === "modified" || currentRows[i].type === "removed" || currentRows[i].type === "added") + (currentRows[i].type === "modified" || + currentRows[i].type === "removed" || + currentRows[i].type === "added") ) { const row = currentRows[i] if (row.left && (row.type === "removed" || row.type === "modified")) { @@ -162,10 +164,16 @@ export function ContentDiff(props: Props) {
    {rows().map((r) => (
    -
    +
    -
    +
    @@ -176,7 +184,11 @@ export function ContentDiff(props: Props) { {mobileRows().map((block) => (
    {block.lines.map((line) => ( -
    +
    ))} diff --git a/packages/web/src/components/share/copy-button.tsx b/packages/web/src/components/share/copy-button.tsx index 892d5553..6f51bb4d 100644 --- a/packages/web/src/components/share/copy-button.tsx +++ b/packages/web/src/components/share/copy-button.tsx @@ -21,7 +21,11 @@ export function CopyButton(props: CopyButtonProps) { return (
    ) diff --git a/packages/web/src/components/share/part.tsx b/packages/web/src/components/share/part.tsx index f7a6a930..6ad18273 100644 --- a/packages/web/src/components/share/part.tsx +++ b/packages/web/src/components/share/part.tsx @@ -1,6 +1,15 @@ import map from "lang-map" import { DateTime } from "luxon" -import { For, Show, Match, Switch, type JSX, createMemo, createSignal, type ParentProps } from "solid-js" +import { + For, + Show, + Match, + Switch, + type JSX, + createMemo, + createSignal, + type ParentProps, +} from "solid-js" import { IconHashtag, IconSparkles, @@ -19,7 +28,14 @@ import { IconMagnifyingGlass, IconDocumentMagnifyingGlass, } from "../icons" -import { IconMeta, IconRobot, IconOpenAI, IconGemini, IconAnthropic, IconBrain } from "../icons/custom" +import { + IconMeta, + IconRobot, + IconOpenAI, + IconGemini, + IconAnthropic, + IconBrain, +} from "../icons/custom" import { ContentCode } from "./content-code" import { ContentDiff } from "./content-diff" import { ContentText } from "./content-text" @@ -79,7 +95,11 @@ export function Part(props: PartProps) { {(model) => } @@ -147,7 +167,9 @@ export function Part(props: PartProps) { DateTime.DATETIME_FULL_WITH_SECONDS, )} > - {DateTime.fromMillis(props.message.time.completed).toLocaleString(DateTime.DATETIME_MED)} + {DateTime.fromMillis(props.message.time.completed).toLocaleString( + DateTime.DATETIME_MED, + )} )}
    @@ -343,7 +365,10 @@ function getShikiLang(filename: string) { return type ? (overrides[type] ?? type) : "plaintext" } -function getDiagnostics(diagnosticsByFile: Record, currentFile: string): JSX.Element[] { +function getDiagnostics( + diagnosticsByFile: Record, + currentFile: string, +): JSX.Element[] { const result: JSX.Element[] = [] if (diagnosticsByFile === undefined || diagnosticsByFile[currentFile] === undefined) return result @@ -397,7 +422,9 @@ export function TodoWriteTool(props: ToolProps) { completed: 2, } const todos = createMemo(() => - ((props.state.input?.todos ?? []) as Todo[]).slice().sort((a, b) => priority[a.status] - priority[b.status]), + ((props.state.input?.todos ?? []) as Todo[]) + .slice() + .sort((a, b) => priority[a.status] - priority[b.status]), ) const starting = () => todos().every((t: Todo) => t.status === "pending") const finished = () => todos().every((t: Todo) => t.status === "completed") @@ -439,13 +466,23 @@ export function GrepTool(props: ToolProps) { 0}> - +
    @@ -505,7 +542,9 @@ export function WebFetchTool(props: ToolProps) { } export function ReadTool(props: ToolProps) { - const filePath = createMemo(() => stripWorkingDirectory(props.state.input?.filePath, props.message.path.cwd)) + const filePath = createMemo(() => + stripWorkingDirectory(props.state.input?.filePath, props.message.path.cwd), + ) return ( <> @@ -522,7 +561,10 @@ export function ReadTool(props: ToolProps) { - + @@ -537,8 +579,12 @@ export function ReadTool(props: ToolProps) { } export function WriteTool(props: ToolProps) { - const filePath = createMemo(() => stripWorkingDirectory(props.state.input?.filePath, props.message.path.cwd)) - const diagnostics = createMemo(() => getDiagnostics(props.state.metadata?.diagnostics, props.state.input.filePath)) + const filePath = createMemo(() => + stripWorkingDirectory(props.state.input?.filePath, props.message.path.cwd), + ) + const diagnostics = createMemo(() => + getDiagnostics(props.state.metadata?.diagnostics, props.state.input.filePath), + ) return ( <> @@ -558,7 +604,10 @@ export function WriteTool(props: ToolProps) { - + @@ -568,8 +617,12 @@ export function WriteTool(props: ToolProps) { } export function EditTool(props: ToolProps) { - const filePath = createMemo(() => stripWorkingDirectory(props.state.input.filePath, props.message.path.cwd)) - const diagnostics = createMemo(() => getDiagnostics(props.state.metadata?.diagnostics, props.state.input.filePath)) + const filePath = createMemo(() => + stripWorkingDirectory(props.state.input.filePath, props.message.path.cwd), + ) + const diagnostics = createMemo(() => + getDiagnostics(props.state.metadata?.diagnostics, props.state.input.filePath), + ) return ( <> @@ -586,7 +639,10 @@ export function EditTool(props: ToolProps) {
    - +
    @@ -619,7 +675,11 @@ export function GlobTool(props: ToolProps) { 0}>
    @@ -642,7 +702,12 @@ function ResultsButton(props: ResultsButtonProps) { return ( <> -
    -
    - -
    New session
    -
    - -
    - {getDirectory(sync.data.path.directory)} - {getFilename(sync.data.path.directory)} -
    -
    -
    - -
    - Last modified  - - {DateTime.fromMillis(sync.data.project.time.created).toRelative()} - -
    + +
    New session
    +
    + +
    + {getDirectory(sync.data.path.directory)} + {getFilename(sync.data.path.directory)}
    - } - > - {(_) => { - return ( -
    -
    +
    + +
    + Last modified  + + {DateTime.fromMillis(sync.data.project.time.created).toRelative()} + +
    +
    +
    + } + > + {(_) => { + return ( +
    +
    +
    + + + +
    +
    1}>
    + } + > + +
    + ) + }} + - {/* */} + + +
    +
    +
    +
    +
    All changes
    +
    + + + {(diff) => ( + + + +
    +
    + +
    + + {getDirectory(diff.file)}‎ + + {getFilename(diff.file)} +
    +
    +
    + + +
    +
    +
    +
    + + + +
    + )} +
    +
    +
    +
    +
    +
    {(tab) => { const [file] = createResource( diff --git a/packages/ui/src/components/accordion.tsx b/packages/ui/src/components/accordion.tsx index 535d38e3..02f00b7b 100644 --- a/packages/ui/src/components/accordion.tsx +++ b/packages/ui/src/components/accordion.tsx @@ -1,9 +1,11 @@ import { Accordion as Kobalte } from "@kobalte/core/accordion" -import { splitProps } from "solid-js" +import { createSignal, splitProps } from "solid-js" import type { ComponentProps, ParentProps } from "solid-js" export interface AccordionProps extends ComponentProps {} -export interface AccordionItemProps extends ComponentProps {} +export interface AccordionItemProps extends ComponentProps { + defaultOpen?: boolean +} export interface AccordionHeaderProps extends ComponentProps {} export interface AccordionTriggerProps extends ComponentProps {} export interface AccordionContentProps extends ComponentProps {} @@ -23,11 +25,14 @@ function AccordionRoot(props: AccordionProps) { } function AccordionItem(props: AccordionItemProps) { - const [split, rest] = splitProps(props, ["class", "classList"]) + const [split, rest] = splitProps(props, ["class", "classList", "defaultOpen"]) + const [open, setOpen] = createSignal(split.defaultOpen ?? false) return ( 0 : true}> -
    +
    diff --git a/packages/ui/src/components/icon.tsx b/packages/ui/src/components/icon.tsx index 082bbea9..b61a54fe 100644 --- a/packages/ui/src/components/icon.tsx +++ b/packages/ui/src/components/icon.tsx @@ -153,7 +153,10 @@ const newIcons = { stop: ``, enter: ``, "layout-left": ``, + "layout-right": ``, "speech-bubble": ``, + "align-right": ``, + expand: ``, } export interface IconProps extends ComponentProps<"svg"> { diff --git a/packages/ui/src/components/tooltip.tsx b/packages/ui/src/components/tooltip.tsx index c3d1947d..e3784ed8 100644 --- a/packages/ui/src/components/tooltip.tsx +++ b/packages/ui/src/components/tooltip.tsx @@ -29,7 +29,7 @@ export function Tooltip(props: TooltipProps) { }) return ( - + {c()} From 957c43aa09a2ceea0a9544fde4d0e2d21d91863f Mon Sep 17 00:00:00 2001 From: Adam <2363879+adamdotdevin@users.noreply.github.com> Date: Thu, 6 Nov 2025 15:34:47 -0600 Subject: [PATCH 092/218] fix(desktop): review tab padding --- packages/desktop/src/pages/session.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/desktop/src/pages/session.tsx b/packages/desktop/src/pages/session.tsx index 9f72191b..22f9c47f 100644 --- a/packages/desktop/src/pages/session.tsx +++ b/packages/desktop/src/pages/session.tsx @@ -728,7 +728,7 @@ export default function Page() { "relative px-6 py-2 w-full flex flex-col gap-6 flex-1 min-h-0": true, }} > -
    +
    All changes
    From 61c4747fbe6b5368b0b752b973c0da3c4ee9f5f1 Mon Sep 17 00:00:00 2001 From: Adam <2363879+adamdotdevin@users.noreply.github.com> Date: Thu, 6 Nov 2025 15:58:45 -0600 Subject: [PATCH 093/218] fix(desktop): diff highlight rendering --- bun.lock | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bun.lock b/bun.lock index 68ac9692..cf47b5ef 100644 --- a/bun.lock +++ b/bun.lock @@ -365,7 +365,7 @@ "@hono/zod-validator": "0.4.2", "@kobalte/core": "0.13.11", "@openauthjs/openauth": "0.0.0-20250322224806", - "@pierre/precision-diffs": "0.4.2", + "@pierre/precision-diffs": "0.4.4", "@solidjs/meta": "0.29.4", "@tailwindcss/vite": "4.1.11", "@tsconfig/bun": "1.0.9", @@ -1034,7 +1034,7 @@ "@petamoriken/float16": ["@petamoriken/float16@3.9.3", "", {}, "sha512-8awtpHXCx/bNpFt4mt2xdkgtgVvKqty8VbjHI/WWWQuEw+KLzFot3f4+LkQY9YmOtq7A5GdOnqoIC8Pdygjk2g=="], - "@pierre/precision-diffs": ["@pierre/precision-diffs@0.4.2", "", { "dependencies": { "@shikijs/core": "3.14.0", "@shikijs/transformers": "3.14.0", "diff": "8.0.2", "fast-deep-equal": "3.1.3", "hast-util-to-html": "9.0.5", "shiki": "3.14.0" }, "peerDependencies": { "react": "^18.3.1 || ^19.0.0", "react-dom": "^18.3.1 || ^19.0.0" } }, "sha512-C6LbruH24BCp4awI47D5iMtVaZZD6GkzqBoDw+Sfu7DB3hC9y/rZr1C2BD7AUzAKwByTfFnh16Zp11ipfPqLKw=="], + "@pierre/precision-diffs": ["@pierre/precision-diffs@0.4.4", "", { "dependencies": { "@shikijs/core": "3.14.0", "@shikijs/transformers": "3.14.0", "diff": "8.0.2", "fast-deep-equal": "3.1.3", "hast-util-to-html": "9.0.5", "shiki": "3.14.0" }, "peerDependencies": { "react": "^18.3.1 || ^19.0.0", "react-dom": "^18.3.1 || ^19.0.0" } }, "sha512-9bhWs+hsz1i0/SMIrzce+fFrSec8aLIFrJYTGHATlynmQovngIWz1Gc+XwGigvY4+zSMksrGPzO5HiaNlvRqtQ=="], "@pkgjs/parseargs": ["@pkgjs/parseargs@0.11.0", "", {}, "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg=="], diff --git a/package.json b/package.json index e0bf476c..a5e1630f 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,7 @@ "@tsconfig/bun": "1.0.9", "@cloudflare/workers-types": "4.20251008.0", "@openauthjs/openauth": "0.0.0-20250322224806", - "@pierre/precision-diffs": "0.4.2", + "@pierre/precision-diffs": "0.4.4", "@solidjs/meta": "0.29.4", "@tailwindcss/vite": "4.1.11", "diff": "8.0.2", From 21957406ffb6f6bad3528b9d9b894e3e3b726a79 Mon Sep 17 00:00:00 2001 From: Jay V Date: Thu, 6 Nov 2025 17:08:48 -0500 Subject: [PATCH 094/218] docs: add Deep Infra provider documentation --- packages/web/src/content/docs/providers.mdx | 36 +++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/packages/web/src/content/docs/providers.mdx b/packages/web/src/content/docs/providers.mdx index 6409acee..6a7520e5 100644 --- a/packages/web/src/content/docs/providers.mdx +++ b/packages/web/src/content/docs/providers.mdx @@ -301,6 +301,42 @@ Or if you already have an API key, you can select **Manually enter API Key** and --- +### Deep Infra + +1. Head over to the [Deep Infra dashboard](https://deepinfra.com/dash), create an account, and generate an API key. + +2. Run `opencode auth login` and select **Deep Infra**. + + ```bash + $ opencode auth login + + ┌ Add credential + │ + ◆ Select provider + │ ● Deep Infra + │ ... + └ + ``` + +3. Enter your Deep Infra API key. + + ```bash + $ opencode auth login + + ┌ Add credential + │ + ◇ Select provider + │ Deep Infra + │ + ◇ Enter your API key + │ _ + └ + ``` + +4. Run the `/models` command to select a model. + +--- + ### Fireworks AI 1. Head over to the [Fireworks AI console](https://app.fireworks.ai/), create an account, and click **Create API Key**. From a2ab01931703aaac325a73e3948187c24c529207 Mon Sep 17 00:00:00 2001 From: Nicolai van der Smagt Date: Thu, 6 Nov 2025 23:53:02 +0100 Subject: [PATCH 095/218] fix: resolve Mistral API compatibility issues (#2440) Co-authored-by: Aiden Cline --- packages/opencode/src/provider/transform.ts | 86 +++++++++++++++++---- 1 file changed, 70 insertions(+), 16 deletions(-) diff --git a/packages/opencode/src/provider/transform.ts b/packages/opencode/src/provider/transform.ts index 9e095f5b..9a955f5c 100644 --- a/packages/opencode/src/provider/transform.ts +++ b/packages/opencode/src/provider/transform.ts @@ -3,21 +3,77 @@ import { unique } from "remeda" import type { JSONSchema } from "zod/v4/core" export namespace ProviderTransform { - function normalizeToolCallIds(msgs: ModelMessage[]): ModelMessage[] { - return msgs.map((msg) => { - if ((msg.role === "assistant" || msg.role === "tool") && Array.isArray(msg.content)) { - msg.content = msg.content.map((part) => { - if ((part.type === "tool-call" || part.type === "tool-result") && "toolCallId" in part) { - return { - ...part, - toolCallId: part.toolCallId.replace(/[^a-zA-Z0-9_-]/g, "_"), + function normalizeMessages( + msgs: ModelMessage[], + providerID: string, + modelID: string, + ): ModelMessage[] { + if (modelID.includes("claude")) { + return msgs.map((msg) => { + if ((msg.role === "assistant" || msg.role === "tool") && Array.isArray(msg.content)) { + msg.content = msg.content.map((part) => { + if ( + (part.type === "tool-call" || part.type === "tool-result") && + "toolCallId" in part + ) { + return { + ...part, + toolCallId: part.toolCallId.replace(/[^a-zA-Z0-9_-]/g, "_"), + } } - } - return part - }) + return part + }) + } + return msg + }) + } + if (providerID === "mistral" || modelID.toLowerCase().includes("mistral")) { + const result: ModelMessage[] = [] + for (let i = 0; i < msgs.length; i++) { + const msg = msgs[i] + const prevMsg = msgs[i - 1] + const nextMsg = msgs[i + 1] + + if ((msg.role === "assistant" || msg.role === "tool") && Array.isArray(msg.content)) { + msg.content = msg.content.map((part) => { + if ( + (part.type === "tool-call" || part.type === "tool-result") && + "toolCallId" in part + ) { + // Mistral requires alphanumeric tool call IDs with exactly 9 characters + const normalizedId = part.toolCallId + .replace(/[^a-zA-Z0-9]/g, "") // Remove non-alphanumeric characters + .substring(0, 9) // Take first 9 characters + .padEnd(9, "0") // Pad with zeros if less than 9 characters + + return { + ...part, + toolCallId: normalizedId, + } + } + return part + }) + } + + result.push(msg) + + // Fix message sequence: tool messages cannot be followed by user messages + if (msg.role === "tool" && nextMsg?.role === "user") { + result.push({ + role: "assistant", + content: [ + { + type: "text", + text: "Done.", + }, + ], + }) + } } - return msg - }) + return result + } + + return msgs } function applyCaching(msgs: ModelMessage[], providerID: string): ModelMessage[] { @@ -64,9 +120,7 @@ export namespace ProviderTransform { } export function message(msgs: ModelMessage[], providerID: string, modelID: string) { - if (modelID.includes("claude")) { - msgs = normalizeToolCallIds(msgs) - } + msgs = normalizeMessages(msgs, providerID, modelID) if (providerID === "anthropic" || modelID.includes("anthropic") || modelID.includes("claude")) { msgs = applyCaching(msgs, providerID) } From 3ba7e243d0771982b23d3d0d54fcbe3e02cb86de Mon Sep 17 00:00:00 2001 From: Dax Date: Thu, 6 Nov 2025 18:00:09 -0500 Subject: [PATCH 096/218] system theme (#4010) --- bun.lock | 20 +- packages/opencode/package.json | 4 +- .../cmd/tui/component/dialog-theme-list.tsx | 12 +- .../src/cli/cmd/tui/context/theme.tsx | 1223 ++++++++++------- .../src/cli/cmd/tui/routes/session/index.tsx | 1 + .../opencode/src/cli/cmd/tui/util/terminal.ts | 114 ++ 6 files changed, 843 insertions(+), 531 deletions(-) create mode 100644 packages/opencode/src/cli/cmd/tui/util/terminal.ts diff --git a/bun.lock b/bun.lock index cf47b5ef..226cf362 100644 --- a/bun.lock +++ b/bun.lock @@ -185,8 +185,8 @@ "@opencode-ai/plugin": "workspace:*", "@opencode-ai/script": "workspace:*", "@opencode-ai/sdk": "workspace:*", - "@opentui/core": "0.1.36", - "@opentui/solid": "0.1.36", + "@opentui/core": "0.0.0-20251106-788e97e4", + "@opentui/solid": "0.0.0-20251106-788e97e4", "@parcel/watcher": "2.5.1", "@pierre/precision-diffs": "catalog:", "@solid-primitives/event-bus": "1.1.2", @@ -962,21 +962,21 @@ "@opentelemetry/api": ["@opentelemetry/api@1.9.0", "", {}, "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg=="], - "@opentui/core": ["@opentui/core@0.1.36", "", { "dependencies": { "bun-ffi-structs": "^0.1.0", "jimp": "1.6.0", "yoga-layout": "3.2.1" }, "optionalDependencies": { "@dimforge/rapier2d-simd-compat": "^0.17.3", "@opentui/core-darwin-arm64": "0.1.36", "@opentui/core-darwin-x64": "0.1.36", "@opentui/core-linux-arm64": "0.1.36", "@opentui/core-linux-x64": "0.1.36", "@opentui/core-win32-arm64": "0.1.36", "@opentui/core-win32-x64": "0.1.36", "bun-webgpu": "0.1.3", "planck": "^1.4.2", "three": "0.177.0" }, "peerDependencies": { "web-tree-sitter": "0.25.10" } }, "sha512-urDrj33udJ0dJGkZv+T5U0mCFBOOvUt9Tvqkrj8aRvi6kN0Bc5d2COuWcpAKo0TO9/PvjSwHC+CMnw2Sr46/ug=="], + "@opentui/core": ["@opentui/core@0.0.0-20251106-788e97e4", "", { "dependencies": { "bun-ffi-structs": "^0.1.0", "jimp": "1.6.0", "yoga-layout": "3.2.1" }, "optionalDependencies": { "@dimforge/rapier2d-simd-compat": "^0.17.3", "@opentui/core-darwin-arm64": "0.0.0-20251106-788e97e4", "@opentui/core-darwin-x64": "0.0.0-20251106-788e97e4", "@opentui/core-linux-arm64": "0.0.0-20251106-788e97e4", "@opentui/core-linux-x64": "0.0.0-20251106-788e97e4", "@opentui/core-win32-arm64": "0.0.0-20251106-788e97e4", "@opentui/core-win32-x64": "0.0.0-20251106-788e97e4", "bun-webgpu": "0.1.3", "planck": "^1.4.2", "three": "0.177.0" }, "peerDependencies": { "web-tree-sitter": "0.25.10" } }, "sha512-Es2Oe7/J/yb58e0jjq/04pV9Mekx6hM4go4C5uTiZksX3asfIGWk553cuf5WlWj0PDlVnC+s7Nnayi/NbLJ5jQ=="], - "@opentui/core-darwin-arm64": ["@opentui/core-darwin-arm64@0.1.36", "", { "os": "darwin", "cpu": "arm64" }, "sha512-/fb0k1H0CeTroVt2UoEAcVrEx1cIYy4B2zfX0MrwUkIfXi36aoIBnisBeYvyCpsQfxFAkyLYCCA3NzaYEyC5hg=="], + "@opentui/core-darwin-arm64": ["@opentui/core-darwin-arm64@0.0.0-20251106-788e97e4", "", { "os": "darwin", "cpu": "arm64" }, "sha512-EOO8SSIYJBIh+Sd9bgVTiQmt+TEJmfg65/oym54J4zfDtCYlAqSaLcRnDe4TzB+4hejV9of8etrG3ZZACBJT+A=="], - "@opentui/core-darwin-x64": ["@opentui/core-darwin-x64@0.1.36", "", { "os": "darwin", "cpu": "x64" }, "sha512-PZMydJbSDUoEWqZsyEV8+FSwMT+r7mWFL0ABgdALI3AOrSr7Z8dMcRnFWl8LhriuHS589THvETJEN28L4q/E2Q=="], + "@opentui/core-darwin-x64": ["@opentui/core-darwin-x64@0.0.0-20251106-788e97e4", "", { "os": "darwin", "cpu": "x64" }, "sha512-MUTt7CDbzL2afNGK8gJ4jUZd+AHiOUJEO0eJGDSfWU8DUs0zv8XoLZfaI5PPbkUPEL/7CEBMARAAiwfRtoG/4A=="], - "@opentui/core-linux-arm64": ["@opentui/core-linux-arm64@0.1.36", "", { "os": "linux", "cpu": "arm64" }, "sha512-ATR+vdtraZEC/gHR1mQa/NYPlqFNBpsnnJAGepQmcxm85VceLYM701QaaIgNAwyYXiP6RQN1ZCv06MD1Ph1m4w=="], + "@opentui/core-linux-arm64": ["@opentui/core-linux-arm64@0.0.0-20251106-788e97e4", "", { "os": "linux", "cpu": "arm64" }, "sha512-Zi1EzLCzooRfYoQnN/Dz8OxzrpRXByny8SJqhdO9ZP2mYX72yJ3AhUUW1Sl6YSzVi0H+QIKj7g+RX2KfsXIGFg=="], - "@opentui/core-linux-x64": ["@opentui/core-linux-x64@0.1.36", "", { "os": "linux", "cpu": "x64" }, "sha512-INsnPtcZVx68C+0Vd0L9+akDwNbWblUDqLmY9CftfmeLFubzvJXNRYTBvr7lX68fcst6Ho+0beUxyUoClKc0rg=="], + "@opentui/core-linux-x64": ["@opentui/core-linux-x64@0.0.0-20251106-788e97e4", "", { "os": "linux", "cpu": "x64" }, "sha512-/E0XEBVzO4JEEhJGzfURF2tPxDE2oTODxlgNYYB1QbAuOsLcV69uSrwAjo1TxuIn4P78tBR+ZOlmONjroPqfbQ=="], - "@opentui/core-win32-arm64": ["@opentui/core-win32-arm64@0.1.36", "", { "os": "win32", "cpu": "arm64" }, "sha512-x9lDZTL+xE8jsG1hP4pdsqCsZBu77JNR/ze5F7ZQkYQEC6Zl/XJtL1YT08nUlWOu4NMSws2xXV0lS/sJkbEgPA=="], + "@opentui/core-win32-arm64": ["@opentui/core-win32-arm64@0.0.0-20251106-788e97e4", "", { "os": "win32", "cpu": "arm64" }, "sha512-En/29cgpYVvzlrQ7fAoP+EUdzmczgMzBIGGM0RuLi2hmCmCqyMtOJ0EJUh9UXa5jYIXNGOP49sIP6bUBbvXt7g=="], - "@opentui/core-win32-x64": ["@opentui/core-win32-x64@0.1.36", "", { "os": "win32", "cpu": "x64" }, "sha512-WVU+qtAfJe8ikPWbw8Hfli15GuQTMKiceTkF5lql5AQYy7PKYtGTzWszxOZKeUU1/eEd2X4REi8Bn0TprEMxYw=="], + "@opentui/core-win32-x64": ["@opentui/core-win32-x64@0.0.0-20251106-788e97e4", "", { "os": "win32", "cpu": "x64" }, "sha512-2lu0bgEi+k/1c9VHQFg3wjVxMgQnuZhs/6sDDpxk9eNS3fuHEJfZi0PFJQk2J4IFQL61nzukOvJKgYDWQvKB1g=="], - "@opentui/solid": ["@opentui/solid@0.1.36", "", { "dependencies": { "@babel/core": "7.28.0", "@babel/preset-typescript": "7.27.1", "@opentui/core": "0.1.36", "babel-plugin-module-resolver": "5.0.2", "babel-preset-solid": "1.9.9", "s-js": "^0.4.9" }, "peerDependencies": { "solid-js": "1.9.9" } }, "sha512-oHI01kZgyNecvXRFyQKJEDC5TCcsvfTPxHCa/XjbcZzH2qE2rfYMUF0mpwlLqoY9b3pm3w7Tpa8upzi1euBGJg=="], + "@opentui/solid": ["@opentui/solid@0.0.0-20251106-788e97e4", "", { "dependencies": { "@babel/core": "7.28.0", "@babel/preset-typescript": "7.27.1", "@opentui/core": "0.0.0-20251106-788e97e4", "babel-plugin-module-resolver": "5.0.2", "babel-preset-solid": "1.9.9", "s-js": "^0.4.9" }, "peerDependencies": { "solid-js": "1.9.9" } }, "sha512-82rFS6BB60rJZU5Ad8Wf58V6HaMSkpnjciizkv3vsjJc9hvIAwLRNYqPypQB+etypuELhYMzzaVqt+wUsPHSqQ=="], "@oslojs/asn1": ["@oslojs/asn1@1.0.0", "", { "dependencies": { "@oslojs/binary": "1.0.0" } }, "sha512-zw/wn0sj0j0QKbIXfIlnEcTviaCzYOY3V5rAyjR6YtOByFtJiT574+8p9Wlach0lZH9fddD4yb9laEAIl4vXQA=="], diff --git a/packages/opencode/package.json b/packages/opencode/package.json index 34c9081c..b9e2c307 100644 --- a/packages/opencode/package.json +++ b/packages/opencode/package.json @@ -54,8 +54,8 @@ "@opencode-ai/plugin": "workspace:*", "@opencode-ai/script": "workspace:*", "@opencode-ai/sdk": "workspace:*", - "@opentui/core": "0.1.36", - "@opentui/solid": "0.1.36", + "@opentui/core": "0.0.0-20251106-788e97e4", + "@opentui/solid": "0.0.0-20251106-788e97e4", "@parcel/watcher": "2.5.1", "@pierre/precision-diffs": "catalog:", "@solid-primitives/event-bus": "1.1.2", diff --git a/packages/opencode/src/cli/cmd/tui/component/dialog-theme-list.tsx b/packages/opencode/src/cli/cmd/tui/component/dialog-theme-list.tsx index 60411e56..5240603f 100644 --- a/packages/opencode/src/cli/cmd/tui/component/dialog-theme-list.tsx +++ b/packages/opencode/src/cli/cmd/tui/component/dialog-theme-list.tsx @@ -1,26 +1,24 @@ import { DialogSelect, type DialogSelectRef } from "../ui/dialog-select" -import { THEMES, useTheme } from "../context/theme" +import { useTheme } from "../context/theme" import { useDialog } from "../ui/dialog" import { onCleanup, onMount } from "solid-js" export function DialogThemeList() { const theme = useTheme() - const options = Object.keys(THEMES).map((value) => ({ + const options = Object.keys(theme.all()).map((value) => ({ title: value, - value: value as keyof typeof THEMES, + value: value, })) const dialog = useDialog() let confirmed = false - let ref: DialogSelectRef + let ref: DialogSelectRef const initial = theme.selected onMount(() => { - // highlight the first theme in the list when we open it for UX - theme.set(Object.keys(THEMES)[0] as keyof typeof THEMES) + theme.set(Object.keys(theme.all())[0]) }) onCleanup(() => { - // if we close the dialog without confirming, reset back to the initial theme if (!confirmed) theme.set(initial) }) diff --git a/packages/opencode/src/cli/cmd/tui/context/theme.tsx b/packages/opencode/src/cli/cmd/tui/context/theme.tsx index 93eae6c2..a609bcc9 100644 --- a/packages/opencode/src/cli/cmd/tui/context/theme.tsx +++ b/packages/opencode/src/cli/cmd/tui/context/theme.tsx @@ -1,5 +1,5 @@ -import { SyntaxStyle, RGBA } from "@opentui/core" -import { createMemo, createSignal } from "solid-js" +import { SyntaxStyle, RGBA, type TerminalColors } from "@opentui/core" +import { createMemo } from "solid-js" import { useSync } from "@tui/context/sync" import { createSimpleContext } from "./helper" import aura from "./theme/aura.json" with { type: "json" } @@ -26,6 +26,8 @@ import tokyonight from "./theme/tokyonight.json" with { type: "json" } import vesper from "./theme/vesper.json" with { type: "json" } import zenburn from "./theme/zenburn.json" with { type: "json" } import { useKV } from "./kv" +import { useRenderer } from "@opentui/solid" +import { createStore } from "solid-js/store" type Theme = { primary: RGBA @@ -86,14 +88,14 @@ type Variant = { dark: HexColor | RefName light: HexColor | RefName } -type ColorValue = HexColor | RefName | Variant +type ColorValue = HexColor | RefName | Variant | RGBA type ThemeJson = { $schema?: string defs?: Record theme: Record } -export const THEMES: Record = { +export const DEFAULT_THEMES: Record = { aura, ayu, catppuccin, @@ -122,6 +124,7 @@ export const THEMES: Record = { function resolveTheme(theme: ThemeJson, mode: "dark" | "light") { const defs = theme.defs ?? {} function resolveColor(c: ColorValue): RGBA { + if (c instanceof RGBA) return c if (typeof c === "string") return c.startsWith("#") ? RGBA.fromHex(c) : resolveColor(defs[c]) return resolveColor(c[mode]) } @@ -137,514 +140,27 @@ export const { use: useTheme, provider: ThemeProvider } = createSimpleContext({ init: (props: { mode: "dark" | "light" }) => { const sync = useSync() const kv = useKV() + const [store, setStore] = createStore({ + themes: DEFAULT_THEMES, + mode: props.mode, + active: (sync.data.config.theme ?? kv.get("theme", "opencode")) as string, + }) - const [theme, setTheme] = createSignal(sync.data.config.theme ?? kv.get("theme", "opencode")) - const [mode, setMode] = createSignal(props.mode) + const renderer = useRenderer() + renderer + .getPalette({ + size: 16, + }) + .then((colors) => { + if (!colors.palette[0]) return + setStore("themes", "system", generateSystem(colors, store.mode)) + }) const values = createMemo(() => { - return resolveTheme(THEMES[theme()] ?? THEMES.opencode, mode()) + return resolveTheme(store.themes[store.active] ?? store.themes.opencode, store.mode) }) - const syntax = createMemo(() => { - return SyntaxStyle.fromTheme([ - { - scope: ["prompt"], - style: { - foreground: values().accent, - }, - }, - { - scope: ["extmark.file"], - style: { - foreground: values().warning, - bold: true, - }, - }, - { - scope: ["extmark.agent"], - style: { - foreground: values().secondary, - bold: true, - }, - }, - { - scope: ["extmark.paste"], - style: { - foreground: values().background, - background: values().warning, - bold: true, - }, - }, - { - scope: ["comment"], - style: { - foreground: values().syntaxComment, - italic: true, - }, - }, - { - scope: ["comment.documentation"], - style: { - foreground: values().syntaxComment, - italic: true, - }, - }, - { - scope: ["string", "symbol"], - style: { - foreground: values().syntaxString, - }, - }, - { - scope: ["number", "boolean"], - style: { - foreground: values().syntaxNumber, - }, - }, - { - scope: ["character.special"], - style: { - foreground: values().syntaxString, - }, - }, - { - scope: ["keyword.return", "keyword.conditional", "keyword.repeat", "keyword.coroutine"], - style: { - foreground: values().syntaxKeyword, - italic: true, - }, - }, - { - scope: ["keyword.type"], - style: { - foreground: values().syntaxType, - bold: true, - italic: true, - }, - }, - { - scope: ["keyword.function", "function.method"], - style: { - foreground: values().syntaxFunction, - }, - }, - { - scope: ["keyword"], - style: { - foreground: values().syntaxKeyword, - italic: true, - }, - }, - { - scope: ["keyword.import"], - style: { - foreground: values().syntaxKeyword, - }, - }, - { - scope: ["operator", "keyword.operator", "punctuation.delimiter"], - style: { - foreground: values().syntaxOperator, - }, - }, - { - scope: ["keyword.conditional.ternary"], - style: { - foreground: values().syntaxOperator, - }, - }, - { - scope: ["variable", "variable.parameter", "function.method.call", "function.call"], - style: { - foreground: values().syntaxVariable, - }, - }, - { - scope: ["variable.member", "function", "constructor"], - style: { - foreground: values().syntaxFunction, - }, - }, - { - scope: ["type", "module"], - style: { - foreground: values().syntaxType, - }, - }, - { - scope: ["constant"], - style: { - foreground: values().syntaxNumber, - }, - }, - { - scope: ["property"], - style: { - foreground: values().syntaxVariable, - }, - }, - { - scope: ["class"], - style: { - foreground: values().syntaxType, - }, - }, - { - scope: ["parameter"], - style: { - foreground: values().syntaxVariable, - }, - }, - { - scope: ["punctuation", "punctuation.bracket"], - style: { - foreground: values().syntaxPunctuation, - }, - }, - { - scope: [ - "variable.builtin", - "type.builtin", - "function.builtin", - "module.builtin", - "constant.builtin", - ], - style: { - foreground: values().error, - }, - }, - { - scope: ["variable.super"], - style: { - foreground: values().error, - }, - }, - { - scope: ["string.escape", "string.regexp"], - style: { - foreground: values().syntaxKeyword, - }, - }, - { - scope: ["keyword.directive"], - style: { - foreground: values().syntaxKeyword, - italic: true, - }, - }, - { - scope: ["punctuation.special"], - style: { - foreground: values().syntaxOperator, - }, - }, - { - scope: ["keyword.modifier"], - style: { - foreground: values().syntaxKeyword, - italic: true, - }, - }, - { - scope: ["keyword.exception"], - style: { - foreground: values().syntaxKeyword, - italic: true, - }, - }, - // Markdown specific styles - { - scope: ["markup.heading"], - style: { - foreground: values().markdownHeading, - bold: true, - }, - }, - { - scope: ["markup.heading.1"], - style: { - foreground: values().markdownHeading, - bold: true, - }, - }, - { - scope: ["markup.heading.2"], - style: { - foreground: values().markdownHeading, - bold: true, - }, - }, - { - scope: ["markup.heading.3"], - style: { - foreground: values().markdownHeading, - bold: true, - }, - }, - { - scope: ["markup.heading.4"], - style: { - foreground: values().markdownHeading, - bold: true, - }, - }, - { - scope: ["markup.heading.5"], - style: { - foreground: values().markdownHeading, - bold: true, - }, - }, - { - scope: ["markup.heading.6"], - style: { - foreground: values().markdownHeading, - bold: true, - }, - }, - { - scope: ["markup.bold", "markup.strong"], - style: { - foreground: values().markdownStrong, - bold: true, - }, - }, - { - scope: ["markup.italic"], - style: { - foreground: values().markdownEmph, - italic: true, - }, - }, - { - scope: ["markup.list"], - style: { - foreground: values().markdownListItem, - }, - }, - { - scope: ["markup.quote"], - style: { - foreground: values().markdownBlockQuote, - italic: true, - }, - }, - { - scope: ["markup.raw", "markup.raw.block"], - style: { - foreground: values().markdownCode, - }, - }, - { - scope: ["markup.raw.inline"], - style: { - foreground: values().markdownCode, - background: values().background, - }, - }, - { - scope: ["markup.link"], - style: { - foreground: values().markdownLink, - underline: true, - }, - }, - { - scope: ["markup.link.label"], - style: { - foreground: values().markdownLinkText, - underline: true, - }, - }, - { - scope: ["markup.link.url"], - style: { - foreground: values().markdownLink, - underline: true, - }, - }, - { - scope: ["label"], - style: { - foreground: values().markdownLinkText, - }, - }, - { - scope: ["spell", "nospell"], - style: { - foreground: values().text, - }, - }, - { - scope: ["conceal"], - style: { - foreground: values().textMuted, - }, - }, - // Additional common highlight groups - { - scope: ["string.special", "string.special.url"], - style: { - foreground: values().markdownLink, - underline: true, - }, - }, - { - scope: ["character"], - style: { - foreground: values().syntaxString, - }, - }, - { - scope: ["float"], - style: { - foreground: values().syntaxNumber, - }, - }, - { - scope: ["comment.error"], - style: { - foreground: values().error, - italic: true, - bold: true, - }, - }, - { - scope: ["comment.warning"], - style: { - foreground: values().warning, - italic: true, - bold: true, - }, - }, - { - scope: ["comment.todo", "comment.note"], - style: { - foreground: values().info, - italic: true, - bold: true, - }, - }, - { - scope: ["namespace"], - style: { - foreground: values().syntaxType, - }, - }, - { - scope: ["field"], - style: { - foreground: values().syntaxVariable, - }, - }, - { - scope: ["type.definition"], - style: { - foreground: values().syntaxType, - bold: true, - }, - }, - { - scope: ["keyword.export"], - style: { - foreground: values().syntaxKeyword, - }, - }, - { - scope: ["attribute", "annotation"], - style: { - foreground: values().warning, - }, - }, - { - scope: ["tag"], - style: { - foreground: values().error, - }, - }, - { - scope: ["tag.attribute"], - style: { - foreground: values().syntaxKeyword, - }, - }, - { - scope: ["tag.delimiter"], - style: { - foreground: values().syntaxOperator, - }, - }, - { - scope: ["markup.strikethrough"], - style: { - foreground: values().textMuted, - }, - }, - { - scope: ["markup.underline"], - style: { - foreground: values().text, - underline: true, - }, - }, - { - scope: ["markup.list.checked"], - style: { - foreground: values().success, - }, - }, - { - scope: ["markup.list.unchecked"], - style: { - foreground: values().textMuted, - }, - }, - { - scope: ["diff.plus"], - style: { - foreground: values().diffAdded, - }, - }, - { - scope: ["diff.minus"], - style: { - foreground: values().diffRemoved, - }, - }, - { - scope: ["diff.delta"], - style: { - foreground: values().diffContext, - }, - }, - { - scope: ["error"], - style: { - foreground: values().error, - bold: true, - }, - }, - { - scope: ["warning"], - style: { - foreground: values().warning, - bold: true, - }, - }, - { - scope: ["info"], - style: { - foreground: values().info, - }, - }, - { - scope: ["debug"], - style: { - foreground: values().textMuted, - }, - }, - ]) - }) + const syntax = createMemo(() => generateSyntax(values())) return { theme: new Proxy(values(), { @@ -654,16 +170,20 @@ export const { use: useTheme, provider: ThemeProvider } = createSimpleContext({ }, }), get selected() { - return theme() + return store.active + }, + all() { + return store.themes }, syntax, - mode, + mode() { + return store.mode + }, setMode(mode: "dark" | "light") { - setMode(mode) + setStore("mode", mode) }, set(theme: string) { - if (!THEMES[theme]) return - setTheme(theme) + setStore("active", theme) kv.set("theme", theme) }, get ready() { @@ -672,3 +192,682 @@ export const { use: useTheme, provider: ThemeProvider } = createSimpleContext({ } }, }) + +function generateSystem(colors: TerminalColors, mode: "dark" | "light"): ThemeJson { + const bg = RGBA.fromHex(colors.defaultBackground ?? colors.palette[0]!) + const fg = RGBA.fromHex(colors.defaultForeground ?? colors.palette[7]!) + const palette = colors.palette.map((x) => RGBA.fromHex(x!)) + const isDark = mode == "dark" + + // Generate gray scale based on terminal background + const grays = generateGrayScale(bg, isDark) + const textMuted = generateMutedTextColor(bg, isDark) + + // ANSI color references + const ansiColors = { + black: palette[0], + red: palette[1], + green: palette[2], + yellow: palette[3], + blue: palette[4], + magenta: palette[5], + cyan: palette[6], + white: palette[7], + } + + return { + theme: { + // Primary colors using ANSI + primary: ansiColors.cyan, + secondary: ansiColors.magenta, + accent: ansiColors.cyan, + + // Status colors using ANSI + error: ansiColors.red, + warning: ansiColors.yellow, + success: ansiColors.green, + info: ansiColors.cyan, + + // Text colors + text: fg, + textMuted, + + // Background colors + background: bg, + backgroundPanel: grays[2], + backgroundElement: grays[3], + + // Border colors + borderSubtle: grays[6], + border: grays[7], + borderActive: grays[8], + + // Diff colors + diffAdded: ansiColors.green, + diffRemoved: ansiColors.red, + diffContext: grays[7], + diffHunkHeader: grays[7], + diffHighlightAdded: ansiColors.green, + diffHighlightRemoved: ansiColors.red, + diffAddedBg: grays[2], + diffRemovedBg: grays[2], + diffContextBg: grays[1], + diffLineNumber: grays[6], + diffAddedLineNumberBg: grays[3], + diffRemovedLineNumberBg: grays[3], + + // Markdown colors + markdownText: fg, + markdownHeading: fg, + markdownLink: ansiColors.blue, + markdownLinkText: ansiColors.cyan, + markdownCode: ansiColors.green, + markdownBlockQuote: ansiColors.yellow, + markdownEmph: ansiColors.yellow, + markdownStrong: fg, + markdownHorizontalRule: grays[7], + markdownListItem: ansiColors.blue, + markdownListEnumeration: ansiColors.cyan, + markdownImage: ansiColors.blue, + markdownImageText: ansiColors.cyan, + markdownCodeBlock: fg, + + // Syntax colors + syntaxComment: textMuted, + syntaxKeyword: ansiColors.magenta, + syntaxFunction: ansiColors.blue, + syntaxVariable: fg, + syntaxString: ansiColors.green, + syntaxNumber: ansiColors.yellow, + syntaxType: ansiColors.cyan, + syntaxOperator: ansiColors.cyan, + syntaxPunctuation: fg, + }, + } +} + +function generateGrayScale(bg: RGBA, isDark: boolean): Record { + const grays: Record = {} + + // RGBA stores floats in range 0-1, convert to 0-255 + const bgR = bg.r * 255 + const bgG = bg.g * 255 + const bgB = bg.b * 255 + + const luminance = 0.299 * bgR + 0.587 * bgG + 0.114 * bgB + + for (let i = 1; i <= 12; i++) { + const factor = i / 12.0 + + let grayValue: number + let newR: number + let newG: number + let newB: number + + if (isDark) { + if (luminance < 10) { + grayValue = Math.floor(factor * 0.4 * 255) + newR = grayValue + newG = grayValue + newB = grayValue + } else { + const newLum = luminance + (255 - luminance) * factor * 0.4 + + const ratio = newLum / luminance + newR = Math.min(bgR * ratio, 255) + newG = Math.min(bgG * ratio, 255) + newB = Math.min(bgB * ratio, 255) + } + } else { + if (luminance > 245) { + grayValue = Math.floor(255 - factor * 0.4 * 255) + newR = grayValue + newG = grayValue + newB = grayValue + } else { + const newLum = luminance * (1 - factor * 0.4) + + const ratio = newLum / luminance + newR = Math.max(bgR * ratio, 0) + newG = Math.max(bgG * ratio, 0) + newB = Math.max(bgB * ratio, 0) + } + } + + grays[i] = RGBA.fromInts(Math.floor(newR), Math.floor(newG), Math.floor(newB)) + } + + return grays +} + +function generateMutedTextColor(bg: RGBA, isDark: boolean): RGBA { + // RGBA stores floats in range 0-1, convert to 0-255 + const bgR = bg.r * 255 + const bgG = bg.g * 255 + const bgB = bg.b * 255 + + const bgLum = 0.299 * bgR + 0.587 * bgG + 0.114 * bgB + + let grayValue: number + + if (isDark) { + if (bgLum < 10) { + // Very dark/black background + grayValue = 180 // #b4b4b4 + } else { + // Scale up for lighter dark backgrounds + grayValue = Math.min(Math.floor(160 + bgLum * 0.3), 200) + } + } else { + if (bgLum > 245) { + // Very light/white background + grayValue = 75 // #4b4b4b + } else { + // Scale down for darker light backgrounds + grayValue = Math.max(Math.floor(100 - (255 - bgLum) * 0.2), 60) + } + } + + return RGBA.fromInts(grayValue, grayValue, grayValue) +} + +function generateSyntax(theme: Theme) { + return SyntaxStyle.fromTheme([ + { + scope: ["prompt"], + style: { + foreground: theme.accent, + }, + }, + { + scope: ["extmark.file"], + style: { + foreground: theme.warning, + bold: true, + }, + }, + { + scope: ["extmark.agent"], + style: { + foreground: theme.secondary, + bold: true, + }, + }, + { + scope: ["extmark.paste"], + style: { + foreground: theme.background, + background: theme.warning, + bold: true, + }, + }, + { + scope: ["comment"], + style: { + foreground: theme.syntaxComment, + italic: true, + }, + }, + { + scope: ["comment.documentation"], + style: { + foreground: theme.syntaxComment, + italic: true, + }, + }, + { + scope: ["string", "symbol"], + style: { + foreground: theme.syntaxString, + }, + }, + { + scope: ["number", "boolean"], + style: { + foreground: theme.syntaxNumber, + }, + }, + { + scope: ["character.special"], + style: { + foreground: theme.syntaxString, + }, + }, + { + scope: ["keyword.return", "keyword.conditional", "keyword.repeat", "keyword.coroutine"], + style: { + foreground: theme.syntaxKeyword, + italic: true, + }, + }, + { + scope: ["keyword.type"], + style: { + foreground: theme.syntaxType, + bold: true, + italic: true, + }, + }, + { + scope: ["keyword.function", "function.method"], + style: { + foreground: theme.syntaxFunction, + }, + }, + { + scope: ["keyword"], + style: { + foreground: theme.syntaxKeyword, + italic: true, + }, + }, + { + scope: ["keyword.import"], + style: { + foreground: theme.syntaxKeyword, + }, + }, + { + scope: ["operator", "keyword.operator", "punctuation.delimiter"], + style: { + foreground: theme.syntaxOperator, + }, + }, + { + scope: ["keyword.conditional.ternary"], + style: { + foreground: theme.syntaxOperator, + }, + }, + { + scope: ["variable", "variable.parameter", "function.method.call", "function.call"], + style: { + foreground: theme.syntaxVariable, + }, + }, + { + scope: ["variable.member", "function", "constructor"], + style: { + foreground: theme.syntaxFunction, + }, + }, + { + scope: ["type", "module"], + style: { + foreground: theme.syntaxType, + }, + }, + { + scope: ["constant"], + style: { + foreground: theme.syntaxNumber, + }, + }, + { + scope: ["property"], + style: { + foreground: theme.syntaxVariable, + }, + }, + { + scope: ["class"], + style: { + foreground: theme.syntaxType, + }, + }, + { + scope: ["parameter"], + style: { + foreground: theme.syntaxVariable, + }, + }, + { + scope: ["punctuation", "punctuation.bracket"], + style: { + foreground: theme.syntaxPunctuation, + }, + }, + { + scope: [ + "variable.builtin", + "type.builtin", + "function.builtin", + "module.builtin", + "constant.builtin", + ], + style: { + foreground: theme.error, + }, + }, + { + scope: ["variable.super"], + style: { + foreground: theme.error, + }, + }, + { + scope: ["string.escape", "string.regexp"], + style: { + foreground: theme.syntaxKeyword, + }, + }, + { + scope: ["keyword.directive"], + style: { + foreground: theme.syntaxKeyword, + italic: true, + }, + }, + { + scope: ["punctuation.special"], + style: { + foreground: theme.syntaxOperator, + }, + }, + { + scope: ["keyword.modifier"], + style: { + foreground: theme.syntaxKeyword, + italic: true, + }, + }, + { + scope: ["keyword.exception"], + style: { + foreground: theme.syntaxKeyword, + italic: true, + }, + }, + // Markdown specific styles + { + scope: ["markup.heading"], + style: { + foreground: theme.markdownHeading, + bold: true, + }, + }, + { + scope: ["markup.heading.1"], + style: { + foreground: theme.markdownHeading, + bold: true, + }, + }, + { + scope: ["markup.heading.2"], + style: { + foreground: theme.markdownHeading, + bold: true, + }, + }, + { + scope: ["markup.heading.3"], + style: { + foreground: theme.markdownHeading, + bold: true, + }, + }, + { + scope: ["markup.heading.4"], + style: { + foreground: theme.markdownHeading, + bold: true, + }, + }, + { + scope: ["markup.heading.5"], + style: { + foreground: theme.markdownHeading, + bold: true, + }, + }, + { + scope: ["markup.heading.6"], + style: { + foreground: theme.markdownHeading, + bold: true, + }, + }, + { + scope: ["markup.bold", "markup.strong"], + style: { + foreground: theme.markdownStrong, + bold: true, + }, + }, + { + scope: ["markup.italic"], + style: { + foreground: theme.markdownEmph, + italic: true, + }, + }, + { + scope: ["markup.list"], + style: { + foreground: theme.markdownListItem, + }, + }, + { + scope: ["markup.quote"], + style: { + foreground: theme.markdownBlockQuote, + italic: true, + }, + }, + { + scope: ["markup.raw", "markup.raw.block"], + style: { + foreground: theme.markdownCode, + }, + }, + { + scope: ["markup.raw.inline"], + style: { + foreground: theme.markdownCode, + background: theme.background, + }, + }, + { + scope: ["markup.link"], + style: { + foreground: theme.markdownLink, + underline: true, + }, + }, + { + scope: ["markup.link.label"], + style: { + foreground: theme.markdownLinkText, + underline: true, + }, + }, + { + scope: ["markup.link.url"], + style: { + foreground: theme.markdownLink, + underline: true, + }, + }, + { + scope: ["label"], + style: { + foreground: theme.markdownLinkText, + }, + }, + { + scope: ["spell", "nospell"], + style: { + foreground: theme.text, + }, + }, + { + scope: ["conceal"], + style: { + foreground: theme.textMuted, + }, + }, + // Additional common highlight groups + { + scope: ["string.special", "string.special.url"], + style: { + foreground: theme.markdownLink, + underline: true, + }, + }, + { + scope: ["character"], + style: { + foreground: theme.syntaxString, + }, + }, + { + scope: ["float"], + style: { + foreground: theme.syntaxNumber, + }, + }, + { + scope: ["comment.error"], + style: { + foreground: theme.error, + italic: true, + bold: true, + }, + }, + { + scope: ["comment.warning"], + style: { + foreground: theme.warning, + italic: true, + bold: true, + }, + }, + { + scope: ["comment.todo", "comment.note"], + style: { + foreground: theme.info, + italic: true, + bold: true, + }, + }, + { + scope: ["namespace"], + style: { + foreground: theme.syntaxType, + }, + }, + { + scope: ["field"], + style: { + foreground: theme.syntaxVariable, + }, + }, + { + scope: ["type.definition"], + style: { + foreground: theme.syntaxType, + bold: true, + }, + }, + { + scope: ["keyword.export"], + style: { + foreground: theme.syntaxKeyword, + }, + }, + { + scope: ["attribute", "annotation"], + style: { + foreground: theme.warning, + }, + }, + { + scope: ["tag"], + style: { + foreground: theme.error, + }, + }, + { + scope: ["tag.attribute"], + style: { + foreground: theme.syntaxKeyword, + }, + }, + { + scope: ["tag.delimiter"], + style: { + foreground: theme.syntaxOperator, + }, + }, + { + scope: ["markup.strikethrough"], + style: { + foreground: theme.textMuted, + }, + }, + { + scope: ["markup.underline"], + style: { + foreground: theme.text, + underline: true, + }, + }, + { + scope: ["markup.list.checked"], + style: { + foreground: theme.success, + }, + }, + { + scope: ["markup.list.unchecked"], + style: { + foreground: theme.textMuted, + }, + }, + { + scope: ["diff.plus"], + style: { + foreground: theme.diffAdded, + }, + }, + { + scope: ["diff.minus"], + style: { + foreground: theme.diffRemoved, + }, + }, + { + scope: ["diff.delta"], + style: { + foreground: theme.diffContext, + }, + }, + { + scope: ["error"], + style: { + foreground: theme.error, + bold: true, + }, + }, + { + scope: ["warning"], + style: { + foreground: theme.warning, + bold: true, + }, + }, + { + scope: ["info"], + style: { + foreground: theme.info, + }, + }, + { + scope: ["debug"], + style: { + foreground: theme.textMuted, + }, + }, + ]) +} diff --git a/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx b/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx index b0d98b08..7e0ccdae 100644 --- a/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx +++ b/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx @@ -683,6 +683,7 @@ export function Session() { (scroll = r)} scrollbarOptions={{ + paddingLeft: 2, trackOptions: { backgroundColor: theme.backgroundElement, foregroundColor: theme.border, diff --git a/packages/opencode/src/cli/cmd/tui/util/terminal.ts b/packages/opencode/src/cli/cmd/tui/util/terminal.ts new file mode 100644 index 00000000..2b81068b --- /dev/null +++ b/packages/opencode/src/cli/cmd/tui/util/terminal.ts @@ -0,0 +1,114 @@ +import { RGBA } from "@opentui/core" + +export namespace Terminal { + export type Colors = Awaited> + /** + * Query terminal colors including background, foreground, and palette (0-15). + * Uses OSC escape sequences to retrieve actual terminal color values. + * + * Note: OSC 4 (palette) queries may not work through tmux as responses are filtered. + * OSC 10/11 (foreground/background) typically work in most environments. + * + * Returns an object with background, foreground, and colors array. + * Any query that fails will be null/empty. + */ + export async function colors(): Promise<{ + background: RGBA | null + foreground: RGBA | null + colors: RGBA[] + }> { + if (!process.stdin.isTTY) return { background: null, foreground: null, colors: [] } + + return new Promise((resolve) => { + let background: RGBA | null = null + let foreground: RGBA | null = null + const paletteColors: RGBA[] = [] + let timeout: NodeJS.Timeout + + const cleanup = () => { + process.stdin.setRawMode(false) + process.stdin.removeListener("data", handler) + clearTimeout(timeout) + } + + const parseColor = (colorStr: string): RGBA | null => { + if (colorStr.startsWith("rgb:")) { + const parts = colorStr.substring(4).split("/") + return RGBA.fromInts( + parseInt(parts[0], 16) >> 8, // Convert 16-bit to 8-bit + parseInt(parts[1], 16) >> 8, + parseInt(parts[2], 16) >> 8, + 255, + ) + } + if (colorStr.startsWith("#")) { + return RGBA.fromHex(colorStr) + } + if (colorStr.startsWith("rgb(")) { + const parts = colorStr.substring(4, colorStr.length - 1).split(",") + return RGBA.fromInts(parseInt(parts[0]), parseInt(parts[1]), parseInt(parts[2]), 255) + } + return null + } + + const handler = (data: Buffer) => { + const str = data.toString() + + // Match OSC 11 (background color) + const bgMatch = str.match(/\x1b]11;([^\x07\x1b]+)/) + if (bgMatch) { + background = parseColor(bgMatch[1]) + } + + // Match OSC 10 (foreground color) + const fgMatch = str.match(/\x1b]10;([^\x07\x1b]+)/) + if (fgMatch) { + foreground = parseColor(fgMatch[1]) + } + + // Match OSC 4 (palette colors) + const paletteMatches = str.matchAll(/\x1b]4;(\d+);([^\x07\x1b]+)/g) + for (const match of paletteMatches) { + const index = parseInt(match[1]) + const color = parseColor(match[2]) + if (color) paletteColors[index] = color + } + + // Return immediately if we have all 16 palette colors + if (paletteColors.filter((c) => c !== undefined).length === 16) { + cleanup() + resolve({ background, foreground, colors: paletteColors }) + } + } + + process.stdin.setRawMode(true) + process.stdin.on("data", handler) + + // Query background (OSC 11) + process.stdout.write("\x1b]11;?\x07") + // Query foreground (OSC 10) + process.stdout.write("\x1b]10;?\x07") + // Query palette colors 0-15 (OSC 4) + for (let i = 0; i < 16; i++) { + process.stdout.write(`\x1b]4;${i};?\x07`) + } + + timeout = setTimeout(() => { + cleanup() + resolve({ background, foreground, colors: paletteColors }) + }, 1000) + }) + } + + export async function getTerminalBackgroundColor(): Promise<"dark" | "light"> { + const result = await colors() + if (!result.background) return "dark" + + const { r, g, b } = result.background + // Calculate luminance using relative luminance formula + const luminance = (0.299 * r + 0.587 * g + 0.114 * b) / 255 + + // Determine if dark or light based on luminance threshold + return luminance > 0.5 ? "light" : "dark" + } +} From 11a6f0886e0a436c02f4989da17cecaf93eec641 Mon Sep 17 00:00:00 2001 From: opencode Date: Thu, 6 Nov 2025 23:14:32 +0000 Subject: [PATCH 097/218] release: v1.0.37 --- bun.lock | 22 +++++++++++----------- packages/console/app/package.json | 2 +- packages/console/core/package.json | 2 +- packages/console/function/package.json | 2 +- packages/console/mail/package.json | 2 +- packages/desktop/package.json | 2 +- packages/function/package.json | 2 +- packages/opencode/package.json | 2 +- packages/plugin/package.json | 4 ++-- packages/sdk/js/package.json | 4 ++-- packages/slack/package.json | 2 +- packages/ui/package.json | 2 +- packages/web/package.json | 2 +- sdks/vscode/package.json | 2 +- 14 files changed, 26 insertions(+), 26 deletions(-) diff --git a/bun.lock b/bun.lock index 226cf362..338f7545 100644 --- a/bun.lock +++ b/bun.lock @@ -39,7 +39,7 @@ }, "packages/console/core": { "name": "@opencode-ai/console-core", - "version": "1.0.36", + "version": "1.0.37", "dependencies": { "@aws-sdk/client-sts": "3.782.0", "@jsx-email/render": "1.1.1", @@ -66,7 +66,7 @@ }, "packages/console/function": { "name": "@opencode-ai/console-function", - "version": "1.0.36", + "version": "1.0.37", "dependencies": { "@ai-sdk/anthropic": "2.0.0", "@ai-sdk/openai": "2.0.2", @@ -90,7 +90,7 @@ }, "packages/console/mail": { "name": "@opencode-ai/console-mail", - "version": "1.0.36", + "version": "1.0.37", "dependencies": { "@jsx-email/all": "2.2.3", "@jsx-email/cli": "1.4.3", @@ -111,7 +111,7 @@ }, "packages/desktop": { "name": "@opencode-ai/desktop", - "version": "1.0.36", + "version": "1.0.37", "dependencies": { "@kobalte/core": "catalog:", "@opencode-ai/sdk": "workspace:*", @@ -151,7 +151,7 @@ }, "packages/function": { "name": "@opencode-ai/function", - "version": "1.0.36", + "version": "1.0.37", "dependencies": { "@octokit/auth-app": "8.0.1", "@octokit/rest": "22.0.0", @@ -167,7 +167,7 @@ }, "packages/opencode": { "name": "opencode", - "version": "1.0.36", + "version": "1.0.37", "bin": { "opencode": "./bin/opencode", }, @@ -245,7 +245,7 @@ }, "packages/plugin": { "name": "@opencode-ai/plugin", - "version": "1.0.36", + "version": "1.0.37", "dependencies": { "@opencode-ai/sdk": "workspace:*", "zod": "catalog:", @@ -265,7 +265,7 @@ }, "packages/sdk/js": { "name": "@opencode-ai/sdk", - "version": "1.0.36", + "version": "1.0.37", "devDependencies": { "@hey-api/openapi-ts": "0.81.0", "@tsconfig/node22": "catalog:", @@ -276,7 +276,7 @@ }, "packages/slack": { "name": "@opencode-ai/slack", - "version": "1.0.36", + "version": "1.0.37", "dependencies": { "@opencode-ai/sdk": "workspace:*", "@slack/bolt": "^3.17.1", @@ -289,7 +289,7 @@ }, "packages/ui": { "name": "@opencode-ai/ui", - "version": "1.0.36", + "version": "1.0.37", "dependencies": { "@kobalte/core": "catalog:", "@opencode-ai/sdk": "workspace:*", @@ -319,7 +319,7 @@ }, "packages/web": { "name": "@opencode-ai/web", - "version": "1.0.36", + "version": "1.0.37", "dependencies": { "@astrojs/cloudflare": "12.6.3", "@astrojs/markdown-remark": "6.3.1", diff --git a/packages/console/app/package.json b/packages/console/app/package.json index 4dccc20d..c73dd2f3 100644 --- a/packages/console/app/package.json +++ b/packages/console/app/package.json @@ -7,7 +7,7 @@ "dev:remote": "VITE_AUTH_URL=https://auth.dev.opencode.ai bun sst shell --stage=dev bun dev", "build": "vinxi build && ../../opencode/script/schema.ts ./.output/public/config.json", "start": "vinxi start", - "version": "1.0.36" + "version": "1.0.37" }, "dependencies": { "@ibm/plex": "6.4.1", diff --git a/packages/console/core/package.json b/packages/console/core/package.json index ba4423e0..92a4e827 100644 --- a/packages/console/core/package.json +++ b/packages/console/core/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@opencode-ai/console-core", - "version": "1.0.36", + "version": "1.0.37", "private": true, "type": "module", "dependencies": { diff --git a/packages/console/function/package.json b/packages/console/function/package.json index eda2b012..dd18991d 100644 --- a/packages/console/function/package.json +++ b/packages/console/function/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/console-function", - "version": "1.0.36", + "version": "1.0.37", "$schema": "https://json.schemastore.org/package.json", "private": true, "type": "module", diff --git a/packages/console/mail/package.json b/packages/console/mail/package.json index 38f43ee3..b50c0c9e 100644 --- a/packages/console/mail/package.json +++ b/packages/console/mail/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/console-mail", - "version": "1.0.36", + "version": "1.0.37", "dependencies": { "@jsx-email/all": "2.2.3", "@jsx-email/cli": "1.4.3", diff --git a/packages/desktop/package.json b/packages/desktop/package.json index bc69118c..b5e0c4fd 100644 --- a/packages/desktop/package.json +++ b/packages/desktop/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/desktop", - "version": "1.0.36", + "version": "1.0.37", "description": "", "type": "module", "scripts": { diff --git a/packages/function/package.json b/packages/function/package.json index e4a6f733..ee9ba368 100644 --- a/packages/function/package.json +++ b/packages/function/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/function", - "version": "1.0.36", + "version": "1.0.37", "$schema": "https://json.schemastore.org/package.json", "private": true, "type": "module", diff --git a/packages/opencode/package.json b/packages/opencode/package.json index b9e2c307..bfd4b162 100644 --- a/packages/opencode/package.json +++ b/packages/opencode/package.json @@ -1,6 +1,6 @@ { "$schema": "https://json.schemastore.org/package.json", - "version": "1.0.36", + "version": "1.0.37", "name": "opencode", "type": "module", "private": true, diff --git a/packages/plugin/package.json b/packages/plugin/package.json index f4f7fbfb..4b256a60 100644 --- a/packages/plugin/package.json +++ b/packages/plugin/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@opencode-ai/plugin", - "version": "1.0.36", + "version": "1.0.37", "type": "module", "scripts": { "typecheck": "tsgo --noEmit", @@ -24,4 +24,4 @@ "typescript": "catalog:", "@typescript/native-preview": "catalog:" } -} +} \ No newline at end of file diff --git a/packages/sdk/js/package.json b/packages/sdk/js/package.json index c931dd44..0c33d18a 100644 --- a/packages/sdk/js/package.json +++ b/packages/sdk/js/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@opencode-ai/sdk", - "version": "1.0.36", + "version": "1.0.37", "type": "module", "scripts": { "typecheck": "tsgo --noEmit", @@ -26,4 +26,4 @@ "publishConfig": { "directory": "dist" } -} +} \ No newline at end of file diff --git a/packages/slack/package.json b/packages/slack/package.json index 7b01f5ef..df26d964 100644 --- a/packages/slack/package.json +++ b/packages/slack/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/slack", - "version": "1.0.36", + "version": "1.0.37", "type": "module", "scripts": { "dev": "bun run src/index.ts", diff --git a/packages/ui/package.json b/packages/ui/package.json index 797258a6..7f218885 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/ui", - "version": "1.0.36", + "version": "1.0.37", "type": "module", "exports": { ".": "./src/components/index.ts", diff --git a/packages/web/package.json b/packages/web/package.json index a5b5bae9..27e62353 100644 --- a/packages/web/package.json +++ b/packages/web/package.json @@ -1,7 +1,7 @@ { "name": "@opencode-ai/web", "type": "module", - "version": "1.0.36", + "version": "1.0.37", "scripts": { "dev": "astro dev", "dev:remote": "VITE_API_URL=https://api.opencode.ai astro dev", diff --git a/sdks/vscode/package.json b/sdks/vscode/package.json index a2d98db3..fa0d40db 100644 --- a/sdks/vscode/package.json +++ b/sdks/vscode/package.json @@ -2,7 +2,7 @@ "name": "opencode", "displayName": "opencode", "description": "opencode for VS Code", - "version": "1.0.36", + "version": "1.0.37", "publisher": "sst-dev", "repository": { "type": "git", From 25f31f30969c13d3f4dcea671f6f0a6f827a34a2 Mon Sep 17 00:00:00 2001 From: Dax Raad Date: Thu, 6 Nov 2025 19:14:01 -0500 Subject: [PATCH 098/218] codex tweaks --- packages/opencode/src/provider/transform.ts | 94 +++++---------------- 1 file changed, 20 insertions(+), 74 deletions(-) diff --git a/packages/opencode/src/provider/transform.ts b/packages/opencode/src/provider/transform.ts index 9a955f5c..94d2861c 100644 --- a/packages/opencode/src/provider/transform.ts +++ b/packages/opencode/src/provider/transform.ts @@ -3,77 +3,21 @@ import { unique } from "remeda" import type { JSONSchema } from "zod/v4/core" export namespace ProviderTransform { - function normalizeMessages( - msgs: ModelMessage[], - providerID: string, - modelID: string, - ): ModelMessage[] { - if (modelID.includes("claude")) { - return msgs.map((msg) => { - if ((msg.role === "assistant" || msg.role === "tool") && Array.isArray(msg.content)) { - msg.content = msg.content.map((part) => { - if ( - (part.type === "tool-call" || part.type === "tool-result") && - "toolCallId" in part - ) { - return { - ...part, - toolCallId: part.toolCallId.replace(/[^a-zA-Z0-9_-]/g, "_"), - } + function normalizeToolCallIds(msgs: ModelMessage[]): ModelMessage[] { + return msgs.map((msg) => { + if ((msg.role === "assistant" || msg.role === "tool") && Array.isArray(msg.content)) { + msg.content = msg.content.map((part) => { + if ((part.type === "tool-call" || part.type === "tool-result") && "toolCallId" in part) { + return { + ...part, + toolCallId: part.toolCallId.replace(/[^a-zA-Z0-9_-]/g, "_"), } - return part - }) - } - return msg - }) - } - if (providerID === "mistral" || modelID.toLowerCase().includes("mistral")) { - const result: ModelMessage[] = [] - for (let i = 0; i < msgs.length; i++) { - const msg = msgs[i] - const prevMsg = msgs[i - 1] - const nextMsg = msgs[i + 1] - - if ((msg.role === "assistant" || msg.role === "tool") && Array.isArray(msg.content)) { - msg.content = msg.content.map((part) => { - if ( - (part.type === "tool-call" || part.type === "tool-result") && - "toolCallId" in part - ) { - // Mistral requires alphanumeric tool call IDs with exactly 9 characters - const normalizedId = part.toolCallId - .replace(/[^a-zA-Z0-9]/g, "") // Remove non-alphanumeric characters - .substring(0, 9) // Take first 9 characters - .padEnd(9, "0") // Pad with zeros if less than 9 characters - - return { - ...part, - toolCallId: normalizedId, - } - } - return part - }) - } - - result.push(msg) - - // Fix message sequence: tool messages cannot be followed by user messages - if (msg.role === "tool" && nextMsg?.role === "user") { - result.push({ - role: "assistant", - content: [ - { - type: "text", - text: "Done.", - }, - ], - }) - } + } + return part + }) } - return result - } - - return msgs + return msg + }) } function applyCaching(msgs: ModelMessage[], providerID: string): ModelMessage[] { @@ -120,7 +64,9 @@ export namespace ProviderTransform { } export function message(msgs: ModelMessage[], providerID: string, modelID: string) { - msgs = normalizeMessages(msgs, providerID, modelID) + if (modelID.includes("claude")) { + msgs = normalizeToolCallIds(msgs) + } if (providerID === "anthropic" || modelID.includes("anthropic") || modelID.includes("claude")) { msgs = applyCaching(msgs, providerID) } @@ -151,12 +97,12 @@ export namespace ProviderTransform { } if (modelID.includes("gpt-5") && !modelID.includes("gpt-5-chat")) { - if (!modelID.includes("codex") && !modelID.includes("gpt-5-pro")) { - result["reasoningEffort"] = "medium" + if (modelID.includes("codex")) { + result["store"] = false } - if (providerID !== "azure") { - result["textVerbosity"] = modelID.includes("codex") ? "medium" : "low" + if (!modelID.includes("codex") && !modelID.includes("gpt-5-pro")) { + result["reasoningEffort"] = "medium" } if (providerID === "opencode") { From d1962ca5a7e65c50235e9c389772331e7cd7a0fe Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Fri, 7 Nov 2025 00:14:59 +0000 Subject: [PATCH 099/218] chore: format code --- packages/plugin/package.json | 2 +- packages/sdk/js/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/plugin/package.json b/packages/plugin/package.json index 4b256a60..45c2b6b1 100644 --- a/packages/plugin/package.json +++ b/packages/plugin/package.json @@ -24,4 +24,4 @@ "typescript": "catalog:", "@typescript/native-preview": "catalog:" } -} \ No newline at end of file +} diff --git a/packages/sdk/js/package.json b/packages/sdk/js/package.json index 0c33d18a..c2aa9a20 100644 --- a/packages/sdk/js/package.json +++ b/packages/sdk/js/package.json @@ -26,4 +26,4 @@ "publishConfig": { "directory": "dist" } -} \ No newline at end of file +} From b25d4f9dfb217442637d63167e31cf29617476bf Mon Sep 17 00:00:00 2001 From: Dax Raad Date: Thu, 6 Nov 2025 19:48:10 -0500 Subject: [PATCH 100/218] fix issue with input randomly breaking --- packages/opencode/src/cli/cmd/tui/thread.ts | 3 --- packages/opencode/src/cli/cmd/tui/worker.ts | 3 +++ 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/opencode/src/cli/cmd/tui/thread.ts b/packages/opencode/src/cli/cmd/tui/thread.ts index b05bb582..c530c888 100644 --- a/packages/opencode/src/cli/cmd/tui/thread.ts +++ b/packages/opencode/src/cli/cmd/tui/thread.ts @@ -2,7 +2,6 @@ import { cmd } from "@/cli/cmd/cmd" import { tui } from "./app" import { Rpc } from "@/util/rpc" import { type rpc } from "./worker" -import { upgrade } from "@/cli/upgrade" import { Session } from "@/session" import { bootstrap } from "@/cli/bootstrap" import path from "path" @@ -78,8 +77,6 @@ export const TuiThreadCommand = cmd({ } await bootstrap(cwd, async () => { - upgrade() - const sessionID = await (async () => { if (args.continue) { const it = Session.list() diff --git a/packages/opencode/src/cli/cmd/tui/worker.ts b/packages/opencode/src/cli/cmd/tui/worker.ts index d268449c..32cd5562 100644 --- a/packages/opencode/src/cli/cmd/tui/worker.ts +++ b/packages/opencode/src/cli/cmd/tui/worker.ts @@ -3,6 +3,7 @@ import { Server } from "@/server/server" import { Log } from "@/util/log" import { Instance } from "@/project/instance" import { Rpc } from "@/util/rpc" +import { upgrade } from "@/cli/upgrade" await Log.init({ print: process.argv.includes("--print-logs"), @@ -25,6 +26,8 @@ process.on("uncaughtException", (e) => { }) }) +upgrade() + let server: Bun.Server export const rpc = { async server(input: { port: number; hostname: string }) { From 6bfccace0cdd61545aee652eba28b21a4ff715c3 Mon Sep 17 00:00:00 2001 From: opencode Date: Fri, 7 Nov 2025 01:04:05 +0000 Subject: [PATCH 101/218] release: v1.0.39 --- bun.lock | 22 +++++++++++----------- packages/console/app/package.json | 2 +- packages/console/core/package.json | 2 +- packages/console/function/package.json | 2 +- packages/console/mail/package.json | 2 +- packages/desktop/package.json | 2 +- packages/function/package.json | 2 +- packages/opencode/package.json | 2 +- packages/plugin/package.json | 4 ++-- packages/sdk/js/package.json | 4 ++-- packages/slack/package.json | 2 +- packages/ui/package.json | 2 +- packages/web/package.json | 2 +- sdks/vscode/package.json | 2 +- 14 files changed, 26 insertions(+), 26 deletions(-) diff --git a/bun.lock b/bun.lock index 338f7545..e7542fb5 100644 --- a/bun.lock +++ b/bun.lock @@ -39,7 +39,7 @@ }, "packages/console/core": { "name": "@opencode-ai/console-core", - "version": "1.0.37", + "version": "1.0.39", "dependencies": { "@aws-sdk/client-sts": "3.782.0", "@jsx-email/render": "1.1.1", @@ -66,7 +66,7 @@ }, "packages/console/function": { "name": "@opencode-ai/console-function", - "version": "1.0.37", + "version": "1.0.39", "dependencies": { "@ai-sdk/anthropic": "2.0.0", "@ai-sdk/openai": "2.0.2", @@ -90,7 +90,7 @@ }, "packages/console/mail": { "name": "@opencode-ai/console-mail", - "version": "1.0.37", + "version": "1.0.39", "dependencies": { "@jsx-email/all": "2.2.3", "@jsx-email/cli": "1.4.3", @@ -111,7 +111,7 @@ }, "packages/desktop": { "name": "@opencode-ai/desktop", - "version": "1.0.37", + "version": "1.0.39", "dependencies": { "@kobalte/core": "catalog:", "@opencode-ai/sdk": "workspace:*", @@ -151,7 +151,7 @@ }, "packages/function": { "name": "@opencode-ai/function", - "version": "1.0.37", + "version": "1.0.39", "dependencies": { "@octokit/auth-app": "8.0.1", "@octokit/rest": "22.0.0", @@ -167,7 +167,7 @@ }, "packages/opencode": { "name": "opencode", - "version": "1.0.37", + "version": "1.0.39", "bin": { "opencode": "./bin/opencode", }, @@ -245,7 +245,7 @@ }, "packages/plugin": { "name": "@opencode-ai/plugin", - "version": "1.0.37", + "version": "1.0.39", "dependencies": { "@opencode-ai/sdk": "workspace:*", "zod": "catalog:", @@ -265,7 +265,7 @@ }, "packages/sdk/js": { "name": "@opencode-ai/sdk", - "version": "1.0.37", + "version": "1.0.39", "devDependencies": { "@hey-api/openapi-ts": "0.81.0", "@tsconfig/node22": "catalog:", @@ -276,7 +276,7 @@ }, "packages/slack": { "name": "@opencode-ai/slack", - "version": "1.0.37", + "version": "1.0.39", "dependencies": { "@opencode-ai/sdk": "workspace:*", "@slack/bolt": "^3.17.1", @@ -289,7 +289,7 @@ }, "packages/ui": { "name": "@opencode-ai/ui", - "version": "1.0.37", + "version": "1.0.39", "dependencies": { "@kobalte/core": "catalog:", "@opencode-ai/sdk": "workspace:*", @@ -319,7 +319,7 @@ }, "packages/web": { "name": "@opencode-ai/web", - "version": "1.0.37", + "version": "1.0.39", "dependencies": { "@astrojs/cloudflare": "12.6.3", "@astrojs/markdown-remark": "6.3.1", diff --git a/packages/console/app/package.json b/packages/console/app/package.json index c73dd2f3..431dc4d6 100644 --- a/packages/console/app/package.json +++ b/packages/console/app/package.json @@ -7,7 +7,7 @@ "dev:remote": "VITE_AUTH_URL=https://auth.dev.opencode.ai bun sst shell --stage=dev bun dev", "build": "vinxi build && ../../opencode/script/schema.ts ./.output/public/config.json", "start": "vinxi start", - "version": "1.0.37" + "version": "1.0.39" }, "dependencies": { "@ibm/plex": "6.4.1", diff --git a/packages/console/core/package.json b/packages/console/core/package.json index 92a4e827..5b0e05bd 100644 --- a/packages/console/core/package.json +++ b/packages/console/core/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@opencode-ai/console-core", - "version": "1.0.37", + "version": "1.0.39", "private": true, "type": "module", "dependencies": { diff --git a/packages/console/function/package.json b/packages/console/function/package.json index dd18991d..4912352c 100644 --- a/packages/console/function/package.json +++ b/packages/console/function/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/console-function", - "version": "1.0.37", + "version": "1.0.39", "$schema": "https://json.schemastore.org/package.json", "private": true, "type": "module", diff --git a/packages/console/mail/package.json b/packages/console/mail/package.json index b50c0c9e..98a62397 100644 --- a/packages/console/mail/package.json +++ b/packages/console/mail/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/console-mail", - "version": "1.0.37", + "version": "1.0.39", "dependencies": { "@jsx-email/all": "2.2.3", "@jsx-email/cli": "1.4.3", diff --git a/packages/desktop/package.json b/packages/desktop/package.json index b5e0c4fd..4f479e2e 100644 --- a/packages/desktop/package.json +++ b/packages/desktop/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/desktop", - "version": "1.0.37", + "version": "1.0.39", "description": "", "type": "module", "scripts": { diff --git a/packages/function/package.json b/packages/function/package.json index ee9ba368..b85a38d8 100644 --- a/packages/function/package.json +++ b/packages/function/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/function", - "version": "1.0.37", + "version": "1.0.39", "$schema": "https://json.schemastore.org/package.json", "private": true, "type": "module", diff --git a/packages/opencode/package.json b/packages/opencode/package.json index bfd4b162..d6ddb535 100644 --- a/packages/opencode/package.json +++ b/packages/opencode/package.json @@ -1,6 +1,6 @@ { "$schema": "https://json.schemastore.org/package.json", - "version": "1.0.37", + "version": "1.0.39", "name": "opencode", "type": "module", "private": true, diff --git a/packages/plugin/package.json b/packages/plugin/package.json index 45c2b6b1..e368732f 100644 --- a/packages/plugin/package.json +++ b/packages/plugin/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@opencode-ai/plugin", - "version": "1.0.37", + "version": "1.0.39", "type": "module", "scripts": { "typecheck": "tsgo --noEmit", @@ -24,4 +24,4 @@ "typescript": "catalog:", "@typescript/native-preview": "catalog:" } -} +} \ No newline at end of file diff --git a/packages/sdk/js/package.json b/packages/sdk/js/package.json index c2aa9a20..96036d29 100644 --- a/packages/sdk/js/package.json +++ b/packages/sdk/js/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@opencode-ai/sdk", - "version": "1.0.37", + "version": "1.0.39", "type": "module", "scripts": { "typecheck": "tsgo --noEmit", @@ -26,4 +26,4 @@ "publishConfig": { "directory": "dist" } -} +} \ No newline at end of file diff --git a/packages/slack/package.json b/packages/slack/package.json index df26d964..4ffe5442 100644 --- a/packages/slack/package.json +++ b/packages/slack/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/slack", - "version": "1.0.37", + "version": "1.0.39", "type": "module", "scripts": { "dev": "bun run src/index.ts", diff --git a/packages/ui/package.json b/packages/ui/package.json index 7f218885..16725c1c 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/ui", - "version": "1.0.37", + "version": "1.0.39", "type": "module", "exports": { ".": "./src/components/index.ts", diff --git a/packages/web/package.json b/packages/web/package.json index 27e62353..8a9d8ef7 100644 --- a/packages/web/package.json +++ b/packages/web/package.json @@ -1,7 +1,7 @@ { "name": "@opencode-ai/web", "type": "module", - "version": "1.0.37", + "version": "1.0.39", "scripts": { "dev": "astro dev", "dev:remote": "VITE_API_URL=https://api.opencode.ai astro dev", diff --git a/sdks/vscode/package.json b/sdks/vscode/package.json index fa0d40db..8ae59a2a 100644 --- a/sdks/vscode/package.json +++ b/sdks/vscode/package.json @@ -2,7 +2,7 @@ "name": "opencode", "displayName": "opencode", "description": "opencode for VS Code", - "version": "1.0.37", + "version": "1.0.39", "publisher": "sst-dev", "repository": { "type": "git", From 9e04ff013cc549f581ace9f9dbe0c5b318178a90 Mon Sep 17 00:00:00 2001 From: Nicolai van der Smagt Date: Thu, 6 Nov 2025 23:53:02 +0100 Subject: [PATCH 102/218] fix: resolve Mistral API compatibility issues (#2440) Co-authored-by: Aiden Cline --- packages/opencode/src/provider/transform.ts | 86 +++++++++++++++++---- 1 file changed, 70 insertions(+), 16 deletions(-) diff --git a/packages/opencode/src/provider/transform.ts b/packages/opencode/src/provider/transform.ts index 94d2861c..a81c4dd0 100644 --- a/packages/opencode/src/provider/transform.ts +++ b/packages/opencode/src/provider/transform.ts @@ -3,21 +3,77 @@ import { unique } from "remeda" import type { JSONSchema } from "zod/v4/core" export namespace ProviderTransform { - function normalizeToolCallIds(msgs: ModelMessage[]): ModelMessage[] { - return msgs.map((msg) => { - if ((msg.role === "assistant" || msg.role === "tool") && Array.isArray(msg.content)) { - msg.content = msg.content.map((part) => { - if ((part.type === "tool-call" || part.type === "tool-result") && "toolCallId" in part) { - return { - ...part, - toolCallId: part.toolCallId.replace(/[^a-zA-Z0-9_-]/g, "_"), + function normalizeMessages( + msgs: ModelMessage[], + providerID: string, + modelID: string, + ): ModelMessage[] { + if (modelID.includes("claude")) { + return msgs.map((msg) => { + if ((msg.role === "assistant" || msg.role === "tool") && Array.isArray(msg.content)) { + msg.content = msg.content.map((part) => { + if ( + (part.type === "tool-call" || part.type === "tool-result") && + "toolCallId" in part + ) { + return { + ...part, + toolCallId: part.toolCallId.replace(/[^a-zA-Z0-9_-]/g, "_"), + } } - } - return part - }) + return part + }) + } + return msg + }) + } + if (providerID === "mistral" || modelID.toLowerCase().includes("mistral")) { + const result: ModelMessage[] = [] + for (let i = 0; i < msgs.length; i++) { + const msg = msgs[i] + const prevMsg = msgs[i - 1] + const nextMsg = msgs[i + 1] + + if ((msg.role === "assistant" || msg.role === "tool") && Array.isArray(msg.content)) { + msg.content = msg.content.map((part) => { + if ( + (part.type === "tool-call" || part.type === "tool-result") && + "toolCallId" in part + ) { + // Mistral requires alphanumeric tool call IDs with exactly 9 characters + const normalizedId = part.toolCallId + .replace(/[^a-zA-Z0-9]/g, "") // Remove non-alphanumeric characters + .substring(0, 9) // Take first 9 characters + .padEnd(9, "0") // Pad with zeros if less than 9 characters + + return { + ...part, + toolCallId: normalizedId, + } + } + return part + }) + } + + result.push(msg) + + // Fix message sequence: tool messages cannot be followed by user messages + if (msg.role === "tool" && nextMsg?.role === "user") { + result.push({ + role: "assistant", + content: [ + { + type: "text", + text: "Done.", + }, + ], + }) + } } - return msg - }) + return result + } + + return msgs } function applyCaching(msgs: ModelMessage[], providerID: string): ModelMessage[] { @@ -64,9 +120,7 @@ export namespace ProviderTransform { } export function message(msgs: ModelMessage[], providerID: string, modelID: string) { - if (modelID.includes("claude")) { - msgs = normalizeToolCallIds(msgs) - } + msgs = normalizeMessages(msgs, providerID, modelID) if (providerID === "anthropic" || modelID.includes("anthropic") || modelID.includes("claude")) { msgs = applyCaching(msgs, providerID) } From da51c9dfac1f01907186b4e18c981ec45c870e23 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Fri, 7 Nov 2025 01:06:38 +0000 Subject: [PATCH 103/218] chore: format code --- packages/plugin/package.json | 2 +- packages/sdk/js/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/plugin/package.json b/packages/plugin/package.json index e368732f..a90fb4c8 100644 --- a/packages/plugin/package.json +++ b/packages/plugin/package.json @@ -24,4 +24,4 @@ "typescript": "catalog:", "@typescript/native-preview": "catalog:" } -} \ No newline at end of file +} diff --git a/packages/sdk/js/package.json b/packages/sdk/js/package.json index 96036d29..d0df17fc 100644 --- a/packages/sdk/js/package.json +++ b/packages/sdk/js/package.json @@ -26,4 +26,4 @@ "publishConfig": { "directory": "dist" } -} \ No newline at end of file +} From 9f603e39a6ed863a4edaddeeb5444804fc0b8998 Mon Sep 17 00:00:00 2001 From: "opencode-agent[bot]" <219766164+opencode-agent[bot]@users.noreply.github.com> Date: Thu, 6 Nov 2025 19:07:27 -0600 Subject: [PATCH 104/218] Fixed ACP to respect user's default model config. (#4006) Co-authored-by: opencode-agent[bot] Co-authored-by: rekram1-node Co-authored-by: GitHub Action Co-authored-by: Aiden Cline --- packages/opencode/src/acp/agent.ts | 38 +++++++++++++++++++++------- packages/opencode/src/cli/cmd/acp.ts | 3 ++- 2 files changed, 31 insertions(+), 10 deletions(-) diff --git a/packages/opencode/src/acp/agent.ts b/packages/opencode/src/acp/agent.ts index 4eaf76cf..046c8262 100644 --- a/packages/opencode/src/acp/agent.ts +++ b/packages/opencode/src/acp/agent.ts @@ -32,7 +32,7 @@ import { Command } from "@/command" import { Agent as Agents } from "@/agent/agent" import { Permission } from "@/permission" import { SessionCompaction } from "@/session/compaction" -import type { Config } from "@/config/config" +import { Config } from "@/config/config" import { MCP } from "@/mcp" import { Todo } from "@/session/todo" import { z } from "zod" @@ -41,6 +41,18 @@ import { LoadAPIKeyError } from "ai" export namespace ACP { const log = Log.create({ service: "acp-agent" }) + export async function init() { + const model = await defaultModel({}) + return { + create: (connection: AgentSideConnection, config: ACPConfig) => { + if (!config.defaultModel) { + config.defaultModel = model + } + return new Agent(connection, config) + }, + } + } + export class Agent implements ACPAgent { private sessionManager = new ACPSessionManager() private connection: AgentSideConnection @@ -48,13 +60,6 @@ export namespace ACP { constructor(connection: AgentSideConnection, config: ACPConfig = {}) { this.connection = connection - if (!config.defaultModel) { - // default to big pickle - config.defaultModel = { - providerID: "opencode", - modelID: "big-pickle", - } - } this.config = config this.setupEventSubscriptions() } @@ -685,7 +690,22 @@ export namespace ACP { async function defaultModel(config: ACPConfig) { const configured = config.defaultModel if (configured) return configured - return Provider.defaultModel() + + const model = await Config.get() + .then((cfg) => { + if (!cfg.model) return undefined + const parsed = Provider.parseModel(cfg.model) + return { + providerID: parsed.providerID, + modelID: parsed.modelID, + } + }) + .catch((error) => { + log.error("failed to load user config for default model", { error }) + return undefined + }) + + return model ?? { providerID: "opencode", modelID: "big-pickle" } } function parseUri( diff --git a/packages/opencode/src/cli/cmd/acp.ts b/packages/opencode/src/cli/cmd/acp.ts index de461e17..77ef0c60 100644 --- a/packages/opencode/src/cli/cmd/acp.ts +++ b/packages/opencode/src/cli/cmd/acp.ts @@ -50,9 +50,10 @@ export const AcpCommand = cmd({ }) const stream = ndJsonStream(input, output) + const agent = await ACP.init() new AgentSideConnection((conn) => { - return new ACP.Agent(conn) + return agent.create(conn, {}) }, stream) log.info("setup connection") From d0f5c825bd2bb83378545c996dc566de25df6f1c Mon Sep 17 00:00:00 2001 From: Charles David Mupende Date: Fri, 7 Nov 2025 02:37:23 +0100 Subject: [PATCH 105/218] feat: implement network IP retrieval for remote access in web command (#3945) --- packages/opencode/src/cli/cmd/web.ts | 59 +++++++++++++++++++++++++--- 1 file changed, 53 insertions(+), 6 deletions(-) diff --git a/packages/opencode/src/cli/cmd/web.ts b/packages/opencode/src/cli/cmd/web.ts index 8fc8a991..9d3a4253 100644 --- a/packages/opencode/src/cli/cmd/web.ts +++ b/packages/opencode/src/cli/cmd/web.ts @@ -2,6 +2,29 @@ import { Server } from "../../server/server" import { UI } from "../ui" import { cmd } from "./cmd" import open from "open" +import { networkInterfaces } from "os" + +function getNetworkIPs() { + const nets = networkInterfaces() + const results: string[] = [] + + for (const name of Object.keys(nets)) { + const net = nets[name] + if (!net) continue + + for (const netInfo of net) { + // Skip internal and non-IPv4 addresses + if (netInfo.internal || netInfo.family !== "IPv4") continue + + // Skip Docker bridge networks (typically 172.x.x.x) + if (netInfo.address.startsWith("172.")) continue + + results.push(netInfo.address) + } + } + + return results +} export const WebCommand = cmd({ command: "web", @@ -29,12 +52,36 @@ export const WebCommand = cmd({ UI.empty() UI.println(UI.logo(" ")) UI.empty() - UI.println( - UI.Style.TEXT_INFO_BOLD + " Web interface: ", - UI.Style.TEXT_NORMAL, - server.url.toString(), - ) - open(server.url.toString()).catch(() => {}) + + if (hostname === "0.0.0.0") { + // Show localhost for local access + const localhostUrl = `http://localhost:${server.port}` + UI.println( + UI.Style.TEXT_INFO_BOLD + " Local access: ", + UI.Style.TEXT_NORMAL, + localhostUrl, + ) + + // Show network IPs for remote access + const networkIPs = getNetworkIPs() + if (networkIPs.length > 0) { + for (const ip of networkIPs) { + UI.println( + UI.Style.TEXT_INFO_BOLD + " Network access: ", + UI.Style.TEXT_NORMAL, + `http://${ip}:${server.port}`, + ) + } + } + + // Open localhost in browser + open(localhostUrl.toString()).catch(() => {}) + } else { + const displayUrl = server.url.toString() + UI.println(UI.Style.TEXT_INFO_BOLD + " Web interface: ", UI.Style.TEXT_NORMAL, displayUrl) + open(displayUrl).catch(() => {}) + } + await new Promise(() => {}) await server.stop() }, From 9554abb56ef2998d13a31adc6ec85cd92cc71bf6 Mon Sep 17 00:00:00 2001 From: Dax Raad Date: Fri, 7 Nov 2025 01:11:47 -0500 Subject: [PATCH 106/218] message storage performance improvements --- .../cli/cmd/tui/component/prompt/index.tsx | 1 - .../opencode/src/cli/cmd/tui/context/sync.tsx | 1 + packages/opencode/src/server/server.ts | 2 +- packages/opencode/src/session/compaction.ts | 4 +--- packages/opencode/src/session/index.ts | 24 ++++++++++++------- packages/opencode/src/session/message-v2.ts | 12 ++++++---- packages/opencode/src/session/prompt.ts | 4 +--- packages/opencode/src/session/summary.ts | 12 +--------- 8 files changed, 28 insertions(+), 32 deletions(-) diff --git a/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx b/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx index c977f731..b9e40659 100644 --- a/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx +++ b/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx @@ -3,7 +3,6 @@ import { BoxRenderable, TextareaRenderable, MouseEvent, - KeyEvent, PasteEvent, t, dim, diff --git a/packages/opencode/src/cli/cmd/tui/context/sync.tsx b/packages/opencode/src/cli/cmd/tui/context/sync.tsx index 3fe1a4f5..5c8d3146 100644 --- a/packages/opencode/src/cli/cmd/tui/context/sync.tsx +++ b/packages/opencode/src/cli/cmd/tui/context/sync.tsx @@ -270,6 +270,7 @@ export const { use: useSync, provider: SyncProvider } = createSimpleContext({ }, async sync(sessionID: string) { const now = Date.now() + if (store.message[sessionID]) return console.log("syncing", sessionID) const [session, messages, todo, diff] = await Promise.all([ sdk.client.session.get({ path: { id: sessionID }, throwOnError: true }), diff --git a/packages/opencode/src/server/server.ts b/packages/opencode/src/server/server.ts index c7265006..bb9f065e 100644 --- a/packages/opencode/src/server/server.ts +++ b/packages/opencode/src/server/server.ts @@ -756,7 +756,7 @@ export namespace Server { validator( "query", z.object({ - limit: z.coerce.number().optional(), + limit: z.coerce.number(), }), ), async (c) => { diff --git a/packages/opencode/src/session/compaction.ts b/packages/opencode/src/session/compaction.ts index 115628cc..4924a35d 100644 --- a/packages/opencode/src/session/compaction.ts +++ b/packages/opencode/src/session/compaction.ts @@ -111,9 +111,7 @@ export namespace SessionCompaction { draft.time.compacting = undefined }) }) - const toSummarize = await Session.messages({ sessionID: input.sessionID }).then( - MessageV2.filterCompacted, - ) + const toSummarize = await MessageV2.filterCompacted(Session.messageStream(input.sessionID)) const model = await Provider.getModel(input.providerID, input.modelID) const system = [ ...SystemPrompt.summarize(model.providerID), diff --git a/packages/opencode/src/session/index.ts b/packages/opencode/src/session/index.ts index dc04f183..0971531f 100644 --- a/packages/opencode/src/session/index.ts +++ b/packages/opencode/src/session/index.ts @@ -273,6 +273,17 @@ export namespace Session { return diffs ?? [] }) + export const messageStream = fn(Identifier.schema("session"), async function* (sessionID) { + const list = await Array.fromAsync(await Storage.list(["message", sessionID])) + for (let i = list.length - 1; i >= 0; i--) { + const read = await Storage.read(list[i]) + yield { + info: read, + parts: await getParts(read.id), + } + } + }) + export const messages = fn( z.object({ sessionID: Identifier.schema("session"), @@ -280,16 +291,11 @@ export namespace Session { }), async (input) => { const result = [] as MessageV2.WithParts[] - const list = (await Array.fromAsync(await Storage.list(["message", input.sessionID]))) - .toSorted((a, b) => a.at(-1)!.localeCompare(b.at(-1)!)) - .slice(-1 * (input.limit ?? 1_000_000)) - for (const p of list) { - const read = await Storage.read(p) - result.push({ - info: read, - parts: await getParts(read.id), - }) + for await (const msg of messageStream(input.sessionID)) { + if (input.limit && result.length >= input.limit) break + result.push(msg) } + result.reverse() return result }, ) diff --git a/packages/opencode/src/session/message-v2.ts b/packages/opencode/src/session/message-v2.ts index f35735b7..66d29319 100644 --- a/packages/opencode/src/session/message-v2.ts +++ b/packages/opencode/src/session/message-v2.ts @@ -655,10 +655,14 @@ export namespace MessageV2 { return convertToModelMessages(result) } - export function filterCompacted(msgs: { info: MessageV2.Info; parts: MessageV2.Part[] }[]) { - const i = msgs.findLastIndex((m) => m.info.role === "assistant" && !!m.info.summary) - if (i === -1) return msgs.slice() - return msgs.slice(i) + export async function filterCompacted(stream: AsyncIterable) { + const result = [] as MessageV2.WithParts[] + for await (const msg of stream) { + result.push(msg) + if (msg.info.role === "assistant" && msg.info.summary === true) break + } + result.reverse() + return result } export function fromError(e: unknown, ctx: { providerID: string }) { diff --git a/packages/opencode/src/session/prompt.ts b/packages/opencode/src/session/prompt.ts index 06b06513..cf11b129 100644 --- a/packages/opencode/src/session/prompt.ts +++ b/packages/opencode/src/session/prompt.ts @@ -434,9 +434,7 @@ export namespace SessionPrompt { providerID: string signal: AbortSignal }) { - let msgs = await Session.messages({ sessionID: input.sessionID }).then( - MessageV2.filterCompacted, - ) + let msgs = await MessageV2.filterCompacted(Session.messageStream(input.sessionID)) const lastAssistant = msgs.findLast((msg) => msg.info.role === "assistant") if ( lastAssistant?.info.role === "assistant" && diff --git a/packages/opencode/src/session/summary.ts b/packages/opencode/src/session/summary.ts index 8783a36e..de3e22bd 100644 --- a/packages/opencode/src/session/summary.ts +++ b/packages/opencode/src/session/summary.ts @@ -151,17 +151,7 @@ export namespace SessionSummary { messageID: Identifier.schema("message").optional(), }), async (input) => { - let all = await Session.messages({ sessionID: input.sessionID }) - if (input.messageID) - all = all.filter( - (x) => - x.info.id === input.messageID || - (x.info.role === "assistant" && x.info.parentID === input.messageID), - ) - - return computeDiff({ - messages: all, - }) + return Storage.read(["session_diff", input.sessionID]) ?? [] }, ) From ce7b73170f0de6dcf6ea38ca2264caedbde78850 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Fri, 7 Nov 2025 12:04:25 +0000 Subject: [PATCH 107/218] ignore: update download stats 2025-11-07 --- STATS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/STATS.md b/STATS.md index 56d6d39f..424bf568 100644 --- a/STATS.md +++ b/STATS.md @@ -132,3 +132,4 @@ | 2025-11-04 | 663,912 (+10,782) | 608,056 (+10,917) | 1,271,968 (+21,699) | | 2025-11-05 | 675,074 (+11,162) | 619,690 (+11,634) | 1,294,764 (+22,796) | | 2025-11-06 | 686,252 (+11,178) | 630,885 (+11,195) | 1,317,137 (+22,373) | +| 2025-11-07 | 696,646 (+10,394) | 642,146 (+11,261) | 1,338,792 (+21,655) | From e5804f64f96a3b2fbcbb4dd9ad10c6ca40a6e083 Mon Sep 17 00:00:00 2001 From: Adam <2363879+adamdotdevin@users.noreply.github.com> Date: Fri, 7 Nov 2025 06:26:26 -0600 Subject: [PATCH 108/218] fix(desktop): layout quirks --- packages/desktop/src/pages/session.tsx | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/packages/desktop/src/pages/session.tsx b/packages/desktop/src/pages/session.tsx index 22f9c47f..30b8eab9 100644 --- a/packages/desktop/src/pages/session.tsx +++ b/packages/desktop/src/pages/session.tsx @@ -358,12 +358,12 @@ export default function Page() { return (
    -
    +
    @@ -382,7 +382,7 @@ export default function Page() { role="list" classList={{ "mr-8 shrink-0 flex flex-col items-start": true, - "absolute right-full w-60 @7xl:gap-2": local.layout.review.state() !== "open", + "absolute right-full w-60 @7xl:gap-2": true, // local.layout.review.state() !== "open", "": local.layout.review.state() === "open", }} > @@ -498,7 +498,7 @@ export default function Page() {
    {/* Title */}
    @@ -645,6 +645,14 @@ export default function Page() { }}
    + +
    + { + inputRef = el + }} + /> +
    @@ -826,13 +834,6 @@ export default function Page() { -
    - { - inputRef = el - }} - /> -
    From 14397651b5e2a673aa069fb82eedb690c17eba4c Mon Sep 17 00:00:00 2001 From: Adam <2363879+adamdotdevin@users.noreply.github.com> Date: Fri, 7 Nov 2025 09:05:09 -0600 Subject: [PATCH 109/218] ignore: test file --- theme-test.tsx | 285 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 285 insertions(+) create mode 100644 theme-test.tsx diff --git a/theme-test.tsx b/theme-test.tsx new file mode 100644 index 00000000..16559bf7 --- /dev/null +++ b/theme-test.tsx @@ -0,0 +1,285 @@ +import React, { useState, useEffect, useCallback, useMemo } from "react" +import { ComponentType, FC, ReactNode, JSX } from "react" + +// Interface definitions +interface User { + id: number + name: string + email?: string + readonly createdAt: Date + active: boolean +} + +type Theme = "light" | "dark" | "auto" +type Status = "pending" | "loading" | "success" | "error" + +// Generic function with constraints +function createRepository(items: T[]): Repository { + return new Repository(items) +} + +// Class definition +class Repository { + private items: T[] + protected cache: Map + + constructor(items: T[] = []) { + this.items = items + this.cache = new Map() + } + + public find(id: number): T | undefined { + return this.items.find((item) => item.id === id) + } + + public async findAll(): Promise { + return this.items + } + + get count(): number { + return this.items.length + } +} + +// Enum definition +enum LogLevel { + DEBUG = 0, + INFO = 1, + WARN = 2, + ERROR = 3, +} + +// Constants +const API_URL = "https://api.example.com" +const MAX_RETRIES = 3 +const DEFAULT_TIMEOUT = 5000 + +// Regular expressions +const EMAIL_REGEX = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/ +const PHONE_REGEX = /^\+?1?-?\.?\s?\(?(\d{3})\)?[-.\s]?(\d{3})[-.\s]?(\d{4})$/ + +// Template literals +const greeting = `Hello, ${user.name}!` +const sql = ` + SELECT * FROM users + WHERE active = true + AND created_at > '${new Date().toISOString()}' +` + +// Arrow functions +const debounce = any>( + func: T, + wait: number, +): ((...args: Parameters) => void) => { + let timeout: NodeJS.Timeout + return (...args: Parameters) => { + clearTimeout(timeout) + timeout = setTimeout(() => func(...args), wait) + } +} + +// Async function +async function fetchUserData(userId: number): Promise { + try { + const response = await fetch(`${API_URL}/users/${userId}`) + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`) + } + return await response.json() + } catch (error) { + console.error("Failed to fetch user data:", error) + throw error + } +} + +// React component with various patterns +const ThemeProvider: FC<{ children: ReactNode; theme?: Theme }> = ({ + children, + theme = "auto", +}) => { + const [currentTheme, setCurrentTheme] = useState(theme) + const [status, setStatus] = useState("pending") + + useEffect(() => { + const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)") + const handleChange = (e: MediaQueryListEvent) => { + setCurrentTheme(e.matches ? "dark" : "light") + } + + mediaQuery.addEventListener("change", handleChange) + return () => mediaQuery.removeEventListener("change", handleChange) + }, []) + + const contextValue = useMemo( + () => ({ + theme: currentTheme, + setTheme: setCurrentTheme, + toggleTheme: () => setCurrentTheme((prev) => (prev === "light" ? "dark" : "light")), + }), + [currentTheme], + ) + + return ( + +
    + {children} +
    +
    + ) +} + +// Higher-order component +function withLogging

    (Component: ComponentType

    ): ComponentType

    { + return function LoggedComponent(props: P) { + console.log("Rendering component:", Component.name) + return + } +} + +// Custom hook +function useLocalStorage(key: string, initialValue: T): [T, (value: T) => void] { + const [storedValue, setStoredValue] = useState(() => { + try { + const item = window.localStorage.getItem(key) + return item ? JSON.parse(item) : initialValue + } catch (error) { + console.warn(`Error reading localStorage key "${key}":`, error) + return initialValue + } + }) + + const setValue = useCallback( + (value: T) => { + try { + setStoredValue(value) + window.localStorage.setItem(key, JSON.stringify(value)) + } catch (error) { + console.warn(`Error setting localStorage key "${key}":`, error) + } + }, + [key], + ) + + return [storedValue, setValue] +} + +// JSX component with various elements +const UserProfile: FC<{ user: User; onUpdate?: (user: User) => void }> = ({ user, onUpdate }) => { + const [isEditing, setIsEditing] = useState(false) + const [formData, setFormData] = useState(user) + const [errors, setErrors] = useState>({}) + + const handleSubmit = async (e: React.FormEvent) => { + e.preventDefault() + + // Validation + if (!formData.name.trim()) { + setErrors({ name: "Name is required" }) + return + } + + if (formData.email && !EMAIL_REGEX.test(formData.email)) { + setErrors({ email: "Invalid email format" }) + return + } + + try { + setStatus("loading") + await onUpdate?.(formData) + setStatus("success") + setIsEditing(false) + } catch (error) { + setStatus("error") + setErrors({ submit: "Failed to update profile" }) + } + } + + return ( +

    +
    +

    {user.name}

    + + {user.active ? "Active" : "Inactive"} + +
    + + {isEditing ? ( + +
    + + setFormData({ ...formData, name: e.target.value })} + className={errors.name ? "error" : ""} + placeholder="Enter your name" + required + /> + {errors.name && {errors.name}} +
    + +
    + + setFormData({ ...formData, email: e.target.value })} + className={errors.email ? "error" : ""} + placeholder="user@example.com" + /> + {errors.email && {errors.email}} +
    + +
    + + +
    + + {errors.submit &&
    {errors.submit}
    } + + ) : ( +
    +

    + ID: {user.id} +

    +

    + Email: {user.email || "Not provided"} +

    +

    + Member since: {user.createdAt.toLocaleDateString()} +

    + + +
    + )} +
    + ) +} + +// Export statements +export { + User, + Theme, + Status, + LogLevel, + Repository, + ThemeProvider, + UserProfile, + fetchUserData, + useLocalStorage, + withLogging, + debounce, +} + +export default ThemeProvider + +// Type exports +export type { User as UserType, ComponentType as ReactComponentType } From afb831c93cdc20f25280630e3bd7e2387fe6e52d Mon Sep 17 00:00:00 2001 From: Jinhyeok Lee Date: Sat, 8 Nov 2025 01:31:16 +0900 Subject: [PATCH 110/218] vscode: Add VS Code Insiders support (#4019) --- packages/opencode/src/ide/index.ts | 6 +- packages/opencode/test/ide/ide.test.ts | 86 ++++++++++++++++++++++++++ 2 files changed, 91 insertions(+), 1 deletion(-) create mode 100644 packages/opencode/test/ide/ide.test.ts diff --git a/packages/opencode/src/ide/index.ts b/packages/opencode/src/ide/index.ts index ac80dac3..a6a997e1 100644 --- a/packages/opencode/src/ide/index.ts +++ b/packages/opencode/src/ide/index.ts @@ -6,6 +6,7 @@ import { Bus } from "../bus" const SUPPORTED_IDES = [ { name: "Windsurf" as const, cmd: "windsurf" }, + { name: "Visual Studio Code - Insiders" as const, cmd: "code-insiders" }, { name: "Visual Studio Code" as const, cmd: "code" }, { name: "Cursor" as const, cmd: "cursor" }, { name: "VSCodium" as const, cmd: "codium" }, @@ -43,7 +44,10 @@ export namespace Ide { } export function alreadyInstalled() { - return process.env["OPENCODE_CALLER"] === "vscode" + return ( + process.env["OPENCODE_CALLER"] === "vscode" || + process.env["OPENCODE_CALLER"] === "vscode-insiders" + ) } export async function install(ide: (typeof SUPPORTED_IDES)[number]["name"]) { diff --git a/packages/opencode/test/ide/ide.test.ts b/packages/opencode/test/ide/ide.test.ts new file mode 100644 index 00000000..9678aa90 --- /dev/null +++ b/packages/opencode/test/ide/ide.test.ts @@ -0,0 +1,86 @@ +import { describe, expect, test, afterEach } from "bun:test" +import { Ide } from "../../src/ide" + +describe("ide", () => { + const original = structuredClone(process.env) + + afterEach(() => { + Object.keys(process.env).forEach((key) => { + delete process.env[key] + }) + Object.assign(process.env, original) + }) + + test("should detect Visual Studio Code", () => { + process.env["TERM_PROGRAM"] = "vscode" + process.env["GIT_ASKPASS"] = + "/path/to/Visual Studio Code.app/Contents/Resources/app/extensions/git/dist/askpass.sh" + + expect(Ide.ide()).toBe("Visual Studio Code") + }) + + test("should detect Visual Studio Code Insiders", () => { + process.env["TERM_PROGRAM"] = "vscode" + process.env["GIT_ASKPASS"] = + "/Applications/Visual Studio Code - Insiders.app/Contents/Resources/app/extensions/git/dist/askpass.sh" + + expect(Ide.ide()).toBe("Visual Studio Code - Insiders") + }) + + test("should detect Cursor", () => { + process.env["TERM_PROGRAM"] = "vscode" + process.env["GIT_ASKPASS"] = + "/path/to/Cursor.app/Contents/Resources/app/extensions/git/dist/askpass.sh" + + expect(Ide.ide()).toBe("Cursor") + }) + + test("should detect VSCodium", () => { + process.env["TERM_PROGRAM"] = "vscode" + process.env["GIT_ASKPASS"] = + "/path/to/VSCodium.app/Contents/Resources/app/extensions/git/dist/askpass.sh" + + expect(Ide.ide()).toBe("VSCodium") + }) + + test("should detect Windsurf", () => { + process.env["TERM_PROGRAM"] = "vscode" + process.env["GIT_ASKPASS"] = + "/path/to/Windsurf.app/Contents/Resources/app/extensions/git/dist/askpass.sh" + + expect(Ide.ide()).toBe("Windsurf") + }) + + test("should return unknown when TERM_PROGRAM is not vscode", () => { + process.env["TERM_PROGRAM"] = "iTerm2" + process.env["GIT_ASKPASS"] = + "/Applications/Visual Studio Code - Insiders.app/Contents/Resources/app/extensions/git/dist/askpass.sh" + + expect(Ide.ide()).toBe("unknown") + }) + + test("should return unknown when GIT_ASKPASS does not contain IDE name", () => { + process.env["TERM_PROGRAM"] = "vscode" + process.env["GIT_ASKPASS"] = "/path/to/unknown/askpass.sh" + + expect(Ide.ide()).toBe("unknown") + }) + + test("should recognize vscode-insiders OPENCODE_CALLER", () => { + process.env["OPENCODE_CALLER"] = "vscode-insiders" + + expect(Ide.alreadyInstalled()).toBe(true) + }) + + test("should recognize vscode OPENCODE_CALLER", () => { + process.env["OPENCODE_CALLER"] = "vscode" + + expect(Ide.alreadyInstalled()).toBe(true) + }) + + test("should return false for unknown OPENCODE_CALLER", () => { + process.env["OPENCODE_CALLER"] = "unknown" + + expect(Ide.alreadyInstalled()).toBe(false) + }) +}) From b708d0ecec8cbfc3d60e4d209fcd218fd628ae7f Mon Sep 17 00:00:00 2001 From: Dax Raad Date: Fri, 7 Nov 2025 12:31:28 -0500 Subject: [PATCH 111/218] disable scrollbar temporarily because of text wrap issues --- packages/opencode/src/cli/cmd/tui/routes/session/index.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx b/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx index 7e0ccdae..4365b5ed 100644 --- a/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx +++ b/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx @@ -684,6 +684,7 @@ export function Session() { ref={(r) => (scroll = r)} scrollbarOptions={{ paddingLeft: 2, + visible: false, trackOptions: { backgroundColor: theme.backgroundElement, foregroundColor: theme.border, From d55f4f3322c857567d5327bfe928159a1b6a205f Mon Sep 17 00:00:00 2001 From: opencode Date: Fri, 7 Nov 2025 17:37:31 +0000 Subject: [PATCH 112/218] release: v1.0.40 --- bun.lock | 22 +++++++++++----------- packages/console/app/package.json | 2 +- packages/console/core/package.json | 2 +- packages/console/function/package.json | 2 +- packages/console/mail/package.json | 2 +- packages/desktop/package.json | 2 +- packages/function/package.json | 2 +- packages/opencode/package.json | 2 +- packages/plugin/package.json | 4 ++-- packages/sdk/js/package.json | 4 ++-- packages/sdk/js/src/gen/types.gen.ts | 4 ++-- packages/slack/package.json | 2 +- packages/ui/package.json | 2 +- packages/web/package.json | 2 +- sdks/vscode/package.json | 2 +- 15 files changed, 28 insertions(+), 28 deletions(-) diff --git a/bun.lock b/bun.lock index e7542fb5..0dd38f16 100644 --- a/bun.lock +++ b/bun.lock @@ -39,7 +39,7 @@ }, "packages/console/core": { "name": "@opencode-ai/console-core", - "version": "1.0.39", + "version": "1.0.40", "dependencies": { "@aws-sdk/client-sts": "3.782.0", "@jsx-email/render": "1.1.1", @@ -66,7 +66,7 @@ }, "packages/console/function": { "name": "@opencode-ai/console-function", - "version": "1.0.39", + "version": "1.0.40", "dependencies": { "@ai-sdk/anthropic": "2.0.0", "@ai-sdk/openai": "2.0.2", @@ -90,7 +90,7 @@ }, "packages/console/mail": { "name": "@opencode-ai/console-mail", - "version": "1.0.39", + "version": "1.0.40", "dependencies": { "@jsx-email/all": "2.2.3", "@jsx-email/cli": "1.4.3", @@ -111,7 +111,7 @@ }, "packages/desktop": { "name": "@opencode-ai/desktop", - "version": "1.0.39", + "version": "1.0.40", "dependencies": { "@kobalte/core": "catalog:", "@opencode-ai/sdk": "workspace:*", @@ -151,7 +151,7 @@ }, "packages/function": { "name": "@opencode-ai/function", - "version": "1.0.39", + "version": "1.0.40", "dependencies": { "@octokit/auth-app": "8.0.1", "@octokit/rest": "22.0.0", @@ -167,7 +167,7 @@ }, "packages/opencode": { "name": "opencode", - "version": "1.0.39", + "version": "1.0.40", "bin": { "opencode": "./bin/opencode", }, @@ -245,7 +245,7 @@ }, "packages/plugin": { "name": "@opencode-ai/plugin", - "version": "1.0.39", + "version": "1.0.40", "dependencies": { "@opencode-ai/sdk": "workspace:*", "zod": "catalog:", @@ -265,7 +265,7 @@ }, "packages/sdk/js": { "name": "@opencode-ai/sdk", - "version": "1.0.39", + "version": "1.0.40", "devDependencies": { "@hey-api/openapi-ts": "0.81.0", "@tsconfig/node22": "catalog:", @@ -276,7 +276,7 @@ }, "packages/slack": { "name": "@opencode-ai/slack", - "version": "1.0.39", + "version": "1.0.40", "dependencies": { "@opencode-ai/sdk": "workspace:*", "@slack/bolt": "^3.17.1", @@ -289,7 +289,7 @@ }, "packages/ui": { "name": "@opencode-ai/ui", - "version": "1.0.39", + "version": "1.0.40", "dependencies": { "@kobalte/core": "catalog:", "@opencode-ai/sdk": "workspace:*", @@ -319,7 +319,7 @@ }, "packages/web": { "name": "@opencode-ai/web", - "version": "1.0.39", + "version": "1.0.40", "dependencies": { "@astrojs/cloudflare": "12.6.3", "@astrojs/markdown-remark": "6.3.1", diff --git a/packages/console/app/package.json b/packages/console/app/package.json index 431dc4d6..9fa571eb 100644 --- a/packages/console/app/package.json +++ b/packages/console/app/package.json @@ -7,7 +7,7 @@ "dev:remote": "VITE_AUTH_URL=https://auth.dev.opencode.ai bun sst shell --stage=dev bun dev", "build": "vinxi build && ../../opencode/script/schema.ts ./.output/public/config.json", "start": "vinxi start", - "version": "1.0.39" + "version": "1.0.40" }, "dependencies": { "@ibm/plex": "6.4.1", diff --git a/packages/console/core/package.json b/packages/console/core/package.json index 5b0e05bd..e30a1497 100644 --- a/packages/console/core/package.json +++ b/packages/console/core/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@opencode-ai/console-core", - "version": "1.0.39", + "version": "1.0.40", "private": true, "type": "module", "dependencies": { diff --git a/packages/console/function/package.json b/packages/console/function/package.json index 4912352c..bd6fbd18 100644 --- a/packages/console/function/package.json +++ b/packages/console/function/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/console-function", - "version": "1.0.39", + "version": "1.0.40", "$schema": "https://json.schemastore.org/package.json", "private": true, "type": "module", diff --git a/packages/console/mail/package.json b/packages/console/mail/package.json index 98a62397..88b1c7bd 100644 --- a/packages/console/mail/package.json +++ b/packages/console/mail/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/console-mail", - "version": "1.0.39", + "version": "1.0.40", "dependencies": { "@jsx-email/all": "2.2.3", "@jsx-email/cli": "1.4.3", diff --git a/packages/desktop/package.json b/packages/desktop/package.json index 4f479e2e..a97f5305 100644 --- a/packages/desktop/package.json +++ b/packages/desktop/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/desktop", - "version": "1.0.39", + "version": "1.0.40", "description": "", "type": "module", "scripts": { diff --git a/packages/function/package.json b/packages/function/package.json index b85a38d8..e1fa8776 100644 --- a/packages/function/package.json +++ b/packages/function/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/function", - "version": "1.0.39", + "version": "1.0.40", "$schema": "https://json.schemastore.org/package.json", "private": true, "type": "module", diff --git a/packages/opencode/package.json b/packages/opencode/package.json index d6ddb535..c4134b7d 100644 --- a/packages/opencode/package.json +++ b/packages/opencode/package.json @@ -1,6 +1,6 @@ { "$schema": "https://json.schemastore.org/package.json", - "version": "1.0.39", + "version": "1.0.40", "name": "opencode", "type": "module", "private": true, diff --git a/packages/plugin/package.json b/packages/plugin/package.json index a90fb4c8..097b627a 100644 --- a/packages/plugin/package.json +++ b/packages/plugin/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@opencode-ai/plugin", - "version": "1.0.39", + "version": "1.0.40", "type": "module", "scripts": { "typecheck": "tsgo --noEmit", @@ -24,4 +24,4 @@ "typescript": "catalog:", "@typescript/native-preview": "catalog:" } -} +} \ No newline at end of file diff --git a/packages/sdk/js/package.json b/packages/sdk/js/package.json index d0df17fc..8583c058 100644 --- a/packages/sdk/js/package.json +++ b/packages/sdk/js/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@opencode-ai/sdk", - "version": "1.0.39", + "version": "1.0.40", "type": "module", "scripts": { "typecheck": "tsgo --noEmit", @@ -26,4 +26,4 @@ "publishConfig": { "directory": "dist" } -} +} \ No newline at end of file diff --git a/packages/sdk/js/src/gen/types.gen.ts b/packages/sdk/js/src/gen/types.gen.ts index 5f565df5..93958959 100644 --- a/packages/sdk/js/src/gen/types.gen.ts +++ b/packages/sdk/js/src/gen/types.gen.ts @@ -1979,9 +1979,9 @@ export type SessionMessagesData = { */ id: string } - query?: { + query: { directory?: string - limit?: number + limit: number } url: "/session/{id}/message" } diff --git a/packages/slack/package.json b/packages/slack/package.json index 4ffe5442..0894ccbd 100644 --- a/packages/slack/package.json +++ b/packages/slack/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/slack", - "version": "1.0.39", + "version": "1.0.40", "type": "module", "scripts": { "dev": "bun run src/index.ts", diff --git a/packages/ui/package.json b/packages/ui/package.json index 16725c1c..7ce20e3c 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/ui", - "version": "1.0.39", + "version": "1.0.40", "type": "module", "exports": { ".": "./src/components/index.ts", diff --git a/packages/web/package.json b/packages/web/package.json index 8a9d8ef7..b40e421a 100644 --- a/packages/web/package.json +++ b/packages/web/package.json @@ -1,7 +1,7 @@ { "name": "@opencode-ai/web", "type": "module", - "version": "1.0.39", + "version": "1.0.40", "scripts": { "dev": "astro dev", "dev:remote": "VITE_API_URL=https://api.opencode.ai astro dev", diff --git a/sdks/vscode/package.json b/sdks/vscode/package.json index 8ae59a2a..2bf8f1c1 100644 --- a/sdks/vscode/package.json +++ b/sdks/vscode/package.json @@ -2,7 +2,7 @@ "name": "opencode", "displayName": "opencode", "description": "opencode for VS Code", - "version": "1.0.39", + "version": "1.0.40", "publisher": "sst-dev", "repository": { "type": "git", From 287855336d23cab1e05e3088b42bfb70d883255b Mon Sep 17 00:00:00 2001 From: Dax Raad Date: Fri, 7 Nov 2025 13:03:54 -0500 Subject: [PATCH 113/218] allow not specifying a limit on messages endpoint --- packages/opencode/src/server/server.ts | 2 +- packages/sdk/js/src/gen/types.gen.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/opencode/src/server/server.ts b/packages/opencode/src/server/server.ts index bb9f065e..c7265006 100644 --- a/packages/opencode/src/server/server.ts +++ b/packages/opencode/src/server/server.ts @@ -756,7 +756,7 @@ export namespace Server { validator( "query", z.object({ - limit: z.coerce.number(), + limit: z.coerce.number().optional(), }), ), async (c) => { diff --git a/packages/sdk/js/src/gen/types.gen.ts b/packages/sdk/js/src/gen/types.gen.ts index 93958959..5f565df5 100644 --- a/packages/sdk/js/src/gen/types.gen.ts +++ b/packages/sdk/js/src/gen/types.gen.ts @@ -1979,9 +1979,9 @@ export type SessionMessagesData = { */ id: string } - query: { + query?: { directory?: string - limit: number + limit?: number } url: "/session/{id}/message" } From e317e7e481e60afbb8d9a1bd980650804aaf5d4d Mon Sep 17 00:00:00 2001 From: opencode Date: Fri, 7 Nov 2025 18:11:39 +0000 Subject: [PATCH 114/218] release: v1.0.41 --- bun.lock | 22 +++++++++++----------- packages/console/app/package.json | 2 +- packages/console/core/package.json | 2 +- packages/console/function/package.json | 2 +- packages/console/mail/package.json | 2 +- packages/desktop/package.json | 2 +- packages/function/package.json | 2 +- packages/opencode/package.json | 2 +- packages/plugin/package.json | 2 +- packages/sdk/js/package.json | 2 +- packages/slack/package.json | 2 +- packages/ui/package.json | 2 +- packages/web/package.json | 2 +- sdks/vscode/package.json | 2 +- 14 files changed, 24 insertions(+), 24 deletions(-) diff --git a/bun.lock b/bun.lock index 0dd38f16..c55d2821 100644 --- a/bun.lock +++ b/bun.lock @@ -39,7 +39,7 @@ }, "packages/console/core": { "name": "@opencode-ai/console-core", - "version": "1.0.40", + "version": "1.0.41", "dependencies": { "@aws-sdk/client-sts": "3.782.0", "@jsx-email/render": "1.1.1", @@ -66,7 +66,7 @@ }, "packages/console/function": { "name": "@opencode-ai/console-function", - "version": "1.0.40", + "version": "1.0.41", "dependencies": { "@ai-sdk/anthropic": "2.0.0", "@ai-sdk/openai": "2.0.2", @@ -90,7 +90,7 @@ }, "packages/console/mail": { "name": "@opencode-ai/console-mail", - "version": "1.0.40", + "version": "1.0.41", "dependencies": { "@jsx-email/all": "2.2.3", "@jsx-email/cli": "1.4.3", @@ -111,7 +111,7 @@ }, "packages/desktop": { "name": "@opencode-ai/desktop", - "version": "1.0.40", + "version": "1.0.41", "dependencies": { "@kobalte/core": "catalog:", "@opencode-ai/sdk": "workspace:*", @@ -151,7 +151,7 @@ }, "packages/function": { "name": "@opencode-ai/function", - "version": "1.0.40", + "version": "1.0.41", "dependencies": { "@octokit/auth-app": "8.0.1", "@octokit/rest": "22.0.0", @@ -167,7 +167,7 @@ }, "packages/opencode": { "name": "opencode", - "version": "1.0.40", + "version": "1.0.41", "bin": { "opencode": "./bin/opencode", }, @@ -245,7 +245,7 @@ }, "packages/plugin": { "name": "@opencode-ai/plugin", - "version": "1.0.40", + "version": "1.0.41", "dependencies": { "@opencode-ai/sdk": "workspace:*", "zod": "catalog:", @@ -265,7 +265,7 @@ }, "packages/sdk/js": { "name": "@opencode-ai/sdk", - "version": "1.0.40", + "version": "1.0.41", "devDependencies": { "@hey-api/openapi-ts": "0.81.0", "@tsconfig/node22": "catalog:", @@ -276,7 +276,7 @@ }, "packages/slack": { "name": "@opencode-ai/slack", - "version": "1.0.40", + "version": "1.0.41", "dependencies": { "@opencode-ai/sdk": "workspace:*", "@slack/bolt": "^3.17.1", @@ -289,7 +289,7 @@ }, "packages/ui": { "name": "@opencode-ai/ui", - "version": "1.0.40", + "version": "1.0.41", "dependencies": { "@kobalte/core": "catalog:", "@opencode-ai/sdk": "workspace:*", @@ -319,7 +319,7 @@ }, "packages/web": { "name": "@opencode-ai/web", - "version": "1.0.40", + "version": "1.0.41", "dependencies": { "@astrojs/cloudflare": "12.6.3", "@astrojs/markdown-remark": "6.3.1", diff --git a/packages/console/app/package.json b/packages/console/app/package.json index 9fa571eb..e830cdbc 100644 --- a/packages/console/app/package.json +++ b/packages/console/app/package.json @@ -7,7 +7,7 @@ "dev:remote": "VITE_AUTH_URL=https://auth.dev.opencode.ai bun sst shell --stage=dev bun dev", "build": "vinxi build && ../../opencode/script/schema.ts ./.output/public/config.json", "start": "vinxi start", - "version": "1.0.40" + "version": "1.0.41" }, "dependencies": { "@ibm/plex": "6.4.1", diff --git a/packages/console/core/package.json b/packages/console/core/package.json index e30a1497..25dc25f9 100644 --- a/packages/console/core/package.json +++ b/packages/console/core/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@opencode-ai/console-core", - "version": "1.0.40", + "version": "1.0.41", "private": true, "type": "module", "dependencies": { diff --git a/packages/console/function/package.json b/packages/console/function/package.json index bd6fbd18..cf3ea426 100644 --- a/packages/console/function/package.json +++ b/packages/console/function/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/console-function", - "version": "1.0.40", + "version": "1.0.41", "$schema": "https://json.schemastore.org/package.json", "private": true, "type": "module", diff --git a/packages/console/mail/package.json b/packages/console/mail/package.json index 88b1c7bd..19205a33 100644 --- a/packages/console/mail/package.json +++ b/packages/console/mail/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/console-mail", - "version": "1.0.40", + "version": "1.0.41", "dependencies": { "@jsx-email/all": "2.2.3", "@jsx-email/cli": "1.4.3", diff --git a/packages/desktop/package.json b/packages/desktop/package.json index a97f5305..cebbe893 100644 --- a/packages/desktop/package.json +++ b/packages/desktop/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/desktop", - "version": "1.0.40", + "version": "1.0.41", "description": "", "type": "module", "scripts": { diff --git a/packages/function/package.json b/packages/function/package.json index e1fa8776..57f0a876 100644 --- a/packages/function/package.json +++ b/packages/function/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/function", - "version": "1.0.40", + "version": "1.0.41", "$schema": "https://json.schemastore.org/package.json", "private": true, "type": "module", diff --git a/packages/opencode/package.json b/packages/opencode/package.json index c4134b7d..e5b2a138 100644 --- a/packages/opencode/package.json +++ b/packages/opencode/package.json @@ -1,6 +1,6 @@ { "$schema": "https://json.schemastore.org/package.json", - "version": "1.0.40", + "version": "1.0.41", "name": "opencode", "type": "module", "private": true, diff --git a/packages/plugin/package.json b/packages/plugin/package.json index 097b627a..97e3e77b 100644 --- a/packages/plugin/package.json +++ b/packages/plugin/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@opencode-ai/plugin", - "version": "1.0.40", + "version": "1.0.41", "type": "module", "scripts": { "typecheck": "tsgo --noEmit", diff --git a/packages/sdk/js/package.json b/packages/sdk/js/package.json index 8583c058..97725754 100644 --- a/packages/sdk/js/package.json +++ b/packages/sdk/js/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@opencode-ai/sdk", - "version": "1.0.40", + "version": "1.0.41", "type": "module", "scripts": { "typecheck": "tsgo --noEmit", diff --git a/packages/slack/package.json b/packages/slack/package.json index 0894ccbd..633050cd 100644 --- a/packages/slack/package.json +++ b/packages/slack/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/slack", - "version": "1.0.40", + "version": "1.0.41", "type": "module", "scripts": { "dev": "bun run src/index.ts", diff --git a/packages/ui/package.json b/packages/ui/package.json index 7ce20e3c..1bf2253c 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/ui", - "version": "1.0.40", + "version": "1.0.41", "type": "module", "exports": { ".": "./src/components/index.ts", diff --git a/packages/web/package.json b/packages/web/package.json index b40e421a..0381033a 100644 --- a/packages/web/package.json +++ b/packages/web/package.json @@ -1,7 +1,7 @@ { "name": "@opencode-ai/web", "type": "module", - "version": "1.0.40", + "version": "1.0.41", "scripts": { "dev": "astro dev", "dev:remote": "VITE_API_URL=https://api.opencode.ai astro dev", diff --git a/sdks/vscode/package.json b/sdks/vscode/package.json index 2bf8f1c1..baf51e57 100644 --- a/sdks/vscode/package.json +++ b/sdks/vscode/package.json @@ -2,7 +2,7 @@ "name": "opencode", "displayName": "opencode", "description": "opencode for VS Code", - "version": "1.0.40", + "version": "1.0.41", "publisher": "sst-dev", "repository": { "type": "git", From c6eea0343d2667a9f6850163665e2a0d90000925 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Fri, 7 Nov 2025 18:05:59 +0000 Subject: [PATCH 115/218] chore: format code --- packages/plugin/package.json | 2 +- packages/sdk/js/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/plugin/package.json b/packages/plugin/package.json index 97e3e77b..f9d15e49 100644 --- a/packages/plugin/package.json +++ b/packages/plugin/package.json @@ -24,4 +24,4 @@ "typescript": "catalog:", "@typescript/native-preview": "catalog:" } -} \ No newline at end of file +} diff --git a/packages/sdk/js/package.json b/packages/sdk/js/package.json index 97725754..d96c1a4c 100644 --- a/packages/sdk/js/package.json +++ b/packages/sdk/js/package.json @@ -26,4 +26,4 @@ "publishConfig": { "directory": "dist" } -} \ No newline at end of file +} From 4463d319c97ab167022b056aa199396bd97762e4 Mon Sep 17 00:00:00 2001 From: Dax Raad Date: Fri, 7 Nov 2025 13:22:03 -0500 Subject: [PATCH 116/218] fix scroll when no session exists --- .../cmd/tui/component/dialog-session-list.tsx | 6 +++++- .../src/cli/cmd/tui/routes/session/index.tsx | 18 +++++++++++------- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/packages/opencode/src/cli/cmd/tui/component/dialog-session-list.tsx b/packages/opencode/src/cli/cmd/tui/component/dialog-session-list.tsx index dc770ce2..e6f7efbe 100644 --- a/packages/opencode/src/cli/cmd/tui/component/dialog-session-list.tsx +++ b/packages/opencode/src/cli/cmd/tui/component/dialog-session-list.tsx @@ -2,7 +2,7 @@ import { useDialog } from "@tui/ui/dialog" import { DialogSelect } from "@tui/ui/dialog-select" import { useRoute } from "@tui/context/route" import { useSync } from "@tui/context/sync" -import { createMemo, createSignal, onMount } from "solid-js" +import { createEffect, createMemo, createSignal, onMount } from "solid-js" import { Locale } from "@/util/locale" import { Keybind } from "@/util/keybind" import { useTheme } from "../context/theme" @@ -45,6 +45,10 @@ export function DialogSessionList() { }) }) + createEffect(() => { + console.log("session count", sync.data.session.length) + }) + onMount(() => { dialog.setSize("large") }) diff --git a/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx b/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx index 4365b5ed..830d475f 100644 --- a/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx +++ b/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx @@ -107,14 +107,18 @@ export function Session() { const contentWidth = createMemo(() => dimensions().width - (sidebarVisible() ? 42 : 0) - 4) createEffect(async () => { - await sync.session.sync(route.sessionID).catch(() => { - toast.show({ - message: `Session not found: ${route.sessionID}`, - variant: "error", + await sync.session + .sync(route.sessionID) + .then(() => { + scroll.scrollBy(100_000) + }) + .catch(() => { + toast.show({ + message: `Session not found: ${route.sessionID}`, + variant: "error", + }) + return navigate({ type: "home" }) }) - return navigate({ type: "home" }) - }) - scroll.scrollBy(100_000) }) const toast = useToast() From 3a1d1a6284b66aaf385c3c97bb842a8e1d8985cb Mon Sep 17 00:00:00 2001 From: Adam <2363879+adamdotdevin@users.noreply.github.com> Date: Fri, 7 Nov 2025 12:48:12 -0600 Subject: [PATCH 117/218] feat(desktop): custom syntax colors --- packages/desktop/src/context/sync.tsx | 8 +- packages/desktop/src/pages/session.tsx | 3 +- packages/ui/src/components/code.tsx | 3 +- packages/ui/src/components/diff.tsx | 3937 ++------------------ packages/ui/src/styles/tailwind/colors.css | 5 + packages/ui/src/styles/theme.css | 59 +- theme-test.java | 461 +++ theme-test.md | 669 ++++ theme-test.tsx | 68 + 9 files changed, 1622 insertions(+), 3591 deletions(-) create mode 100644 theme-test.java create mode 100644 theme-test.md diff --git a/packages/desktop/src/context/sync.tsx b/packages/desktop/src/context/sync.tsx index c5b169a3..bc9491fd 100644 --- a/packages/desktop/src/context/sync.tsx +++ b/packages/desktop/src/context/sync.tsx @@ -188,7 +188,7 @@ export const { use: useSync, provider: SyncProvider } = createSimpleContext({ async sync(sessionID: string, _isRetry = false) { const [session, messages, todo, diff] = await Promise.all([ sdk.client.session.get({ path: { id: sessionID }, throwOnError: true }), - sdk.client.session.messages({ path: { id: sessionID } }), + sdk.client.session.messages({ path: { id: sessionID }, query: { limit: 100 } }), sdk.client.session.todo({ path: { id: sessionID } }), sdk.client.session.diff({ path: { id: sessionID } }), ]) @@ -211,12 +211,6 @@ export const { use: useSync, provider: SyncProvider } = createSimpleContext({ draft.session_diff[sessionID] = diff.data ?? [] }), ) - - // If no messages and this might be a new session, retry after a delay - // if (!isRetry && messages.data!.length === 0) { - // setTimeout(() => this.sync(sessionID, true), 500) - // return - // } }, fetch: async (count = 10) => { setStore("limit", (x) => x + count) diff --git a/packages/desktop/src/pages/session.tsx b/packages/desktop/src/pages/session.tsx index 30b8eab9..3dcc24e6 100644 --- a/packages/desktop/src/pages/session.tsx +++ b/packages/desktop/src/pages/session.tsx @@ -736,7 +736,7 @@ export default function Page() { "relative px-6 py-2 w-full flex flex-col gap-6 flex-1 min-h-0": true, }} > -
    +
    All changes
    @@ -766,6 +766,7 @@ export default function Page() { (props: CodeProps) { createEffect(() => { const instance = new File({ - theme: { dark: "oc-1-dark", light: "oc-1-light" }, // or any Shiki theme + theme: { dark: "oc-1-dark", light: "oc-1-light" }, + // theme: { dark: "pierre-dark", light: "pierre-light" }, overflow: "wrap", // or 'scroll' themeType: "system", // 'system', 'light', or 'dark' disableFileHeader: true, diff --git a/packages/ui/src/components/diff.tsx b/packages/ui/src/components/diff.tsx index 6297a642..09085b44 100644 --- a/packages/ui/src/components/diff.tsx +++ b/packages/ui/src/components/diff.tsx @@ -57,6 +57,7 @@ export function Diff(props: DiffProps) { const instance = new FileDiff({ // theme: "pierre-light", theme: { dark: "oc-1-dark", light: "oc-1-light" }, + // theme: { dark: "pierre-dark", light: "pierre-light" }, // When using the 'themes' prop, 'themeType' allows you to force 'dark' // or 'light' theme, or inherit from the OS ('system') theme. themeType: "system", @@ -180,1788 +181,385 @@ export function Diff(props: DiffProps) { ) } +const colors = { + "editor.background": "transparent", + "editor.foreground": "var(--text-base)", + "gitDecoration.addedResourceForeground": "var(--syntax-diff-add)", + "gitDecoration.deletedResourceForeground": "var(--syntax-diff-delete)", + // "gitDecoration.conflictingResourceForeground": "#ffca00", + // "gitDecoration.modifiedResourceForeground": "#1a76d4", + // "gitDecoration.untrackedResourceForeground": "#00cab1", + // "gitDecoration.ignoredResourceForeground": "#84848A", + // "terminal.titleForeground": "#adadb1", + // "terminal.titleInactiveForeground": "#84848A", + // "terminal.background": "#141415", + // "terminal.foreground": "#adadb1", + // "terminal.ansiBlack": "#141415", + // "terminal.ansiRed": "#ff2e3f", + // "terminal.ansiGreen": "#0dbe4e", + // "terminal.ansiYellow": "#ffca00", + // "terminal.ansiBlue": "#008cff", + // "terminal.ansiMagenta": "#c635e4", + // "terminal.ansiCyan": "#08c0ef", + // "terminal.ansiWhite": "#c6c6c8", + // "terminal.ansiBrightBlack": "#141415", + // "terminal.ansiBrightRed": "#ff2e3f", + // "terminal.ansiBrightGreen": "#0dbe4e", + // "terminal.ansiBrightYellow": "#ffca00", + // "terminal.ansiBrightBlue": "#008cff", + // "terminal.ansiBrightMagenta": "#c635e4", + // "terminal.ansiBrightCyan": "#08c0ef", + // "terminal.ansiBrightWhite": "#c6c6c8", +} + +const tokenColors = [ + { + scope: ["comment", "punctuation.definition.comment", "string.comment"], + settings: { + foreground: "var(--syntax-comment)", + }, + }, + { + scope: ["entity.other.attribute-name"], + settings: { + foreground: "var(--syntax-property)", // maybe attribute + }, + }, + { + scope: [ + "constant", + "entity.name.constant", + "variable.other.constant", + "variable.language", + "entity", + ], + settings: { + foreground: "var(--syntax-constant)", + }, + }, + { + scope: ["entity.name", "meta.export.default", "meta.definition.variable"], + settings: { + foreground: "var(--syntax-type)", + }, + }, + { + scope: [ + "variable.parameter.function", + "meta.jsx.children", + "meta.block", + "meta.tag.attributes", + "entity.name.constant", + "meta.object.member", + "meta.embedded.expression", + "meta.template.expression", + "string.other.begin.yaml", + "string.other.end.yaml", + ], + settings: { + foreground: "var(--syntax-punctuation)", + }, + }, + { + scope: ["entity.name.function", "support.type.primitive"], + settings: { + foreground: "var(--syntax-primitive)", + }, + }, + { + scope: ["support.class.component"], + settings: { + foreground: "var(--syntax-type)", + }, + }, + { + scope: "keyword", + settings: { + foreground: "var(--syntax-keyword)", + }, + }, + { + scope: [ + "keyword.operator", + "storage.type.function.arrow", + "punctuation.separator.key-value.css", + "entity.name.tag.yaml", + "punctuation.separator.key-value.mapping.yaml", + ], + settings: { + foreground: "var(--syntax-operator)", + }, + }, + { + scope: ["storage", "storage.type"], + settings: { + foreground: "var(--syntax-keyword)", + }, + }, + { + scope: ["storage.modifier.package", "storage.modifier.import", "storage.type.java"], + settings: { + foreground: "var(--syntax-primitive)", + }, + }, + { + scope: [ + "string", + "punctuation.definition.string", + "string punctuation.section.embedded source", + "entity.name.tag", + ], + settings: { + foreground: "var(--syntax-string)", + }, + }, + { + scope: "support", + settings: { + foreground: "var(--syntax-primitive)", + }, + }, + { + scope: [ + "support.type.object.module", + "variable.other.object", + "support.type.property-name.css", + ], + settings: { + foreground: "var(--syntax-object)", + }, + }, + { + scope: "meta.property-name", + settings: { + foreground: "var(--syntax-property)", + }, + }, + { + scope: "variable", + settings: { + foreground: "var(--syntax-variable)", + }, + }, + { + scope: "variable.other", + settings: { + foreground: "var(--syntax-variable)", + }, + }, + { + scope: [ + "invalid.broken", + "invalid.illegal", + "invalid.unimplemented", + "invalid.deprecated", + "message.error", + "markup.deleted", + "meta.diff.header.from-file", + "punctuation.definition.deleted", + "brackethighlighter.unmatched", + "token.error-token", + ], + settings: { + foreground: "var(--syntax-critical)", + }, + }, + { + scope: "carriage-return", + settings: { + foreground: "var(--syntax-keyword)", + }, + }, + { + scope: "string source", + settings: { + foreground: "var(--syntax-variable)", + }, + }, + { + scope: "string variable", + settings: { + foreground: "var(--syntax-constant)", + }, + }, + { + scope: [ + "source.regexp", + "string.regexp", + "string.regexp.character-class", + "string.regexp constant.character.escape", + "string.regexp source.ruby.embedded", + "string.regexp string.regexp.arbitrary-repitition", + "string.regexp constant.character.escape", + ], + settings: { + foreground: "var(--syntax-regexp)", + }, + }, + { + scope: "support.constant", + settings: { + foreground: "var(--syntax-primitive)", + }, + }, + { + scope: "support.variable", + settings: { + foreground: "var(--syntax-variable)", + }, + }, + { + scope: "meta.module-reference", + settings: { + foreground: "var(--syntax-info)", + }, + }, + { + scope: "punctuation.definition.list.begin.markdown", + settings: { + foreground: "var(--syntax-punctuation)", + }, + }, + { + scope: ["markup.heading", "markup.heading entity.name"], + settings: { + fontStyle: "bold", + foreground: "var(--syntax-info)", + }, + }, + { + scope: "markup.quote", + settings: { + foreground: "var(--syntax-info)", + }, + }, + { + scope: "markup.italic", + settings: { + fontStyle: "italic", + // foreground: "", + }, + }, + { + scope: "markup.bold", + settings: { + fontStyle: "bold", + foreground: "var(--text-strong)", + }, + }, + { + scope: [ + "markup.raw", + "markup.inserted", + "meta.diff.header.to-file", + "punctuation.definition.inserted", + "markup.changed", + "punctuation.definition.changed", + "markup.ignored", + "markup.untracked", + ], + settings: { + foreground: "var(--text-base)", + }, + }, + { + scope: "meta.diff.range", + settings: { + fontStyle: "bold", + foreground: "var(--syntax-unknown)", + }, + }, + { + scope: "meta.diff.header", + settings: { + foreground: "var(--syntax-unknown)", + }, + }, + { + scope: "meta.separator", + settings: { + fontStyle: "bold", + foreground: "var(--syntax-unknown)", + }, + }, + { + scope: "meta.output", + settings: { + foreground: "var(--syntax-unknown)", + }, + }, + { + scope: "meta.export.default", + settings: { + foreground: "var(--syntax-unknown)", + }, + }, + { + scope: [ + "brackethighlighter.tag", + "brackethighlighter.curly", + "brackethighlighter.round", + "brackethighlighter.square", + "brackethighlighter.angle", + "brackethighlighter.quote", + ], + settings: { + foreground: "var(--syntax-unknown)", + }, + }, + { + scope: ["constant.other.reference.link", "string.other.link"], + settings: { + fontStyle: "underline", + foreground: "var(--syntax-unknown)", + }, + }, + { + scope: "token.info-token", + settings: { + foreground: "var(--syntax-info)", + }, + }, + { + scope: "token.warn-token", + settings: { + foreground: "var(--syntax-warning)", + }, + }, + { + scope: "token.debug-token", + settings: { + foreground: "var(--syntax-info)", + }, + }, +] + +const semanticTokenColors = { + comment: "var(--syntax-comment)", + string: "var(--syntax-string)", + number: "var(--syntax-constant)", + regexp: "var(--syntax-regexp)", + keyword: "var(--syntax-keyword)", + variable: "var(--syntax-variable)", + parameter: "var(--syntax-variable)", + property: "var(--syntax-property)", + function: "var(--syntax-primitive)", + method: "var(--syntax-primitive)", + type: "var(--syntax-type)", + class: "var(--syntax-type)", + namespace: "var(--syntax-type)", + enumMember: "var(--syntax-primitive)", + "variable.constant": "var(--syntax-constant)", + "variable.defaultLibrary": "var(--syntax-unknown)", +} + registerCustomTheme("oc-1-light", () => { return Promise.resolve({ - name: "oc-1-light", type: "light", - colors: { - "editor.background": "transparent", - "editor.foreground": "#070707", - foreground: "#070707", - focusBorder: "#008cff", - "selection.background": "#dfe7ff", - "editor.selectionBackground": "#008cff2e", - "editor.lineHighlightBackground": "#dfe7ff8c", - "editorCursor.foreground": "#008cff", - "editorLineNumber.foreground": "#84848A", - "editorLineNumber.activeForeground": "#6C6C71", - "editorIndentGuide.background": "#eeeeef", - "editorIndentGuide.activeBackground": "#dbdbdd", - "diffEditor.insertedTextBackground": "#00cab133", - "diffEditor.deletedTextBackground": "#ff2e3f33", - "sideBar.background": "#f8f8f8", - "sideBar.foreground": "#6C6C71", - "sideBar.border": "#eeeeef", - "sideBarTitle.foreground": "#070707", - "sideBarSectionHeader.background": "#f8f8f8", - "sideBarSectionHeader.foreground": "#6C6C71", - "sideBarSectionHeader.border": "#eeeeef", - "activityBar.background": "#f8f8f8", - "activityBar.foreground": "#070707", - "activityBar.border": "#eeeeef", - "activityBar.activeBorder": "#008cff", - "activityBarBadge.background": "#008cff", - "activityBarBadge.foreground": "#ffffff", - "titleBar.activeBackground": "#f8f8f8", - "titleBar.activeForeground": "#070707", - "titleBar.inactiveBackground": "#f8f8f8", - "titleBar.inactiveForeground": "#84848A", - "titleBar.border": "#eeeeef", - "list.activeSelectionBackground": "#dfe7ffcc", - "list.activeSelectionForeground": "#070707", - "list.inactiveSelectionBackground": "#dfe7ff73", - "list.hoverBackground": "#dfe7ff59", - "list.focusOutline": "#008cff", - "tab.activeBackground": "#ffffff", - "tab.activeForeground": "#070707", - "tab.activeBorderTop": "#008cff", - "tab.inactiveBackground": "#f8f8f8", - "tab.inactiveForeground": "#84848A", - "tab.border": "#eeeeef", - "editorGroupHeader.tabsBackground": "#f8f8f8", - "editorGroupHeader.tabsBorder": "#eeeeef", - "panel.background": "#f8f8f8", - "panel.border": "#eeeeef", - "panelTitle.activeBorder": "#008cff", - "panelTitle.activeForeground": "#070707", - "panelTitle.inactiveForeground": "#84848A", - "statusBar.background": "#f8f8f8", - "statusBar.foreground": "#6C6C71", - "statusBar.border": "#eeeeef", - "statusBar.noFolderBackground": "#f8f8f8", - "statusBar.debuggingBackground": "#ffca00", - "statusBar.debuggingForeground": "#ffffff", - "statusBarItem.remoteBackground": "#f8f8f8", - "statusBarItem.remoteForeground": "#6C6C71", - "input.background": "#f2f2f3", - "input.border": "#dbdbdd", - "input.foreground": "#070707", - "input.placeholderForeground": "#8E8E95", - "dropdown.background": "#f2f2f3", - "dropdown.border": "#dbdbdd", - "dropdown.foreground": "#070707", - "button.background": "#008cff", - "button.foreground": "#ffffff", - "button.hoverBackground": "#1a98ff", - "textLink.foreground": "#008cff", - "textLink.activeForeground": "#008cff", - "gitDecoration.addedResourceForeground": "#00cab1", - "gitDecoration.conflictingResourceForeground": "#ffca00", - "gitDecoration.modifiedResourceForeground": "#008cff", - "gitDecoration.deletedResourceForeground": "#ff2e3f", - "gitDecoration.untrackedResourceForeground": "#00cab1", - "gitDecoration.ignoredResourceForeground": "#84848A", - "terminal.titleForeground": "#6C6C71", - "terminal.titleInactiveForeground": "#84848A", - "terminal.background": "#f8f8f8", - "terminal.foreground": "#6C6C71", - "terminal.ansiBlack": "#1F1F21", - "terminal.ansiRed": "#ff2e3f", - "terminal.ansiGreen": "#0dbe4e", - "terminal.ansiYellow": "#ffca00", - "terminal.ansiBlue": "#008cff", - "terminal.ansiMagenta": "#c635e4", - "terminal.ansiCyan": "#08c0ef", - "terminal.ansiWhite": "#c6c6c8", - "terminal.ansiBrightBlack": "#1F1F21", - "terminal.ansiBrightRed": "#ff2e3f", - "terminal.ansiBrightGreen": "#0dbe4e", - "terminal.ansiBrightYellow": "#ffca00", - "terminal.ansiBrightBlue": "#008cff", - "terminal.ansiBrightMagenta": "#c635e4", - "terminal.ansiBrightCyan": "#08c0ef", - "terminal.ansiBrightWhite": "#c6c6c8", - }, - tokenColors: [ - { - scope: ["comment", "punctuation.definition.comment"], - settings: { - foreground: "#84848A", - }, - }, - { - scope: "comment markup.link", - settings: { - foreground: "#84848A", - }, - }, - { - scope: ["string", "constant.other.symbol"], - settings: { - foreground: "#199f43", - }, - }, - { - scope: ["punctuation.definition.string.begin", "punctuation.definition.string.end"], - settings: { - foreground: "#199f43", - }, - }, - { - scope: ["constant.numeric", "constant.language.boolean"], - settings: { - foreground: "#1ca1c7", - }, - }, - { - scope: "constant", - settings: { - foreground: "#d5a910", - }, - }, - { - scope: "punctuation.definition.constant", - settings: { - foreground: "#d5a910", - }, - }, - { - scope: "constant.language", - settings: { - foreground: "#1ca1c7", - }, - }, - { - scope: "variable.other.constant", - settings: { - foreground: "#d5a910", - }, - }, - { - scope: "keyword", - settings: { - foreground: "#fc2b73", - }, - }, - { - scope: "keyword.control", - settings: { - foreground: "#fc2b73", - }, - }, - { - scope: ["storage", "storage.type", "storage.modifier"], - settings: { - foreground: "#fc2b73", - }, - }, - { - scope: "token.storage", - settings: { - foreground: "#fc2b73", - }, - }, - { - scope: [ - "keyword.operator.new", - "keyword.operator.expression.instanceof", - "keyword.operator.expression.typeof", - "keyword.operator.expression.void", - "keyword.operator.expression.delete", - "keyword.operator.expression.in", - "keyword.operator.expression.of", - "keyword.operator.expression.keyof", - ], - settings: { - foreground: "#fc2b73", - }, - }, - { - scope: "keyword.operator.delete", - settings: { - foreground: "#fc2b73", - }, - }, - { - scope: ["variable", "identifier", "meta.definition.variable"], - settings: { - foreground: "#d47628", - }, - }, - { - scope: [ - "variable.other.readwrite", - "meta.object-literal.key", - "support.variable.property", - "support.variable.object.process", - "support.variable.object.node", - ], - settings: { - foreground: "#d47628", - }, - }, - { - scope: "variable.language", - settings: { - foreground: "#d5a910", - }, - }, - { - scope: "variable.parameter.function", - settings: { - foreground: "#79797F", - }, - }, - { - scope: "function.parameter", - settings: { - foreground: "#79797F", - }, - }, - { - scope: "variable.parameter", - settings: { - foreground: "#79797F", - }, - }, - { - scope: "variable.parameter.function.language.python", - settings: { - foreground: "#d5a910", - }, - }, - { - scope: "variable.parameter.function.python", - settings: { - foreground: "#d5a910", - }, - }, - { - scope: [ - "support.function", - "entity.name.function", - "meta.function-call", - "meta.require", - "support.function.any-method", - "variable.function", - ], - settings: { - foreground: "#7b43f8", - }, - }, - { - scope: "keyword.other.special-method", - settings: { - foreground: "#7b43f8", - }, - }, - { - scope: "entity.name.function", - settings: { - foreground: "#7b43f8", - }, - }, - { - scope: "support.function.console", - settings: { - foreground: "#7b43f8", - }, - }, - { - scope: ["support.type", "entity.name.type", "entity.name.class", "storage.type"], - settings: { - foreground: "#c635e4", - }, - }, - { - scope: ["support.class", "entity.name.type.class"], - settings: { - foreground: "#c635e4", - }, - }, - { - scope: ["entity.name.class", "variable.other.class.js", "variable.other.class.ts"], - settings: { - foreground: "#c635e4", - }, - }, - { - scope: "entity.name.class.identifier.namespace.type", - settings: { - foreground: "#c635e4", - }, - }, - { - scope: "entity.name.type.namespace", - settings: { - foreground: "#d5a910", - }, - }, - { - scope: "entity.other.inherited-class", - settings: { - foreground: "#c635e4", - }, - }, - { - scope: "entity.name.namespace", - settings: { - foreground: "#d5a910", - }, - }, - { - scope: "keyword.operator", - settings: { - foreground: "#79797F", - }, - }, - { - scope: ["keyword.operator.logical", "keyword.operator.bitwise", "keyword.operator.channel"], - settings: { - foreground: "#08c0ef", - }, - }, - { - scope: [ - "keyword.operator.arithmetic", - "keyword.operator.comparison", - "keyword.operator.relational", - "keyword.operator.increment", - "keyword.operator.decrement", - ], - settings: { - foreground: "#08c0ef", - }, - }, - { - scope: "keyword.operator.assignment", - settings: { - foreground: "#08c0ef", - }, - }, - { - scope: "keyword.operator.assignment.compound", - settings: { - foreground: "#fc2b73", - }, - }, - { - scope: [ - "keyword.operator.assignment.compound.js", - "keyword.operator.assignment.compound.ts", - ], - settings: { - foreground: "#08c0ef", - }, - }, - { - scope: "keyword.operator.ternary", - settings: { - foreground: "#fc2b73", - }, - }, - { - scope: "keyword.operator.optional", - settings: { - foreground: "#fc2b73", - }, - }, - { - scope: "punctuation", - settings: { - foreground: "#79797F", - }, - }, - { - scope: "punctuation.separator.delimiter", - settings: { - foreground: "#79797F", - }, - }, - { - scope: "punctuation.separator.key-value", - settings: { - foreground: "#79797F", - }, - }, - { - scope: "punctuation.terminator", - settings: { - foreground: "#79797F", - }, - }, - { - scope: "meta.brace", - settings: { - foreground: "#79797F", - }, - }, - { - scope: "meta.brace.square", - settings: { - foreground: "#79797F", - }, - }, - { - scope: "meta.brace.round", - settings: { - foreground: "#79797F", - }, - }, - { - scope: "function.brace", - settings: { - foreground: "#79797F", - }, - }, - { - scope: ["punctuation.definition.parameters", "punctuation.definition.typeparameters"], - settings: { - foreground: "#79797F", - }, - }, - { - scope: ["punctuation.definition.block", "punctuation.definition.tag"], - settings: { - foreground: "#79797F", - }, - }, - { - scope: ["meta.tag.tsx", "meta.tag.jsx", "meta.tag.js", "meta.tag.ts"], - settings: { - foreground: "#79797F", - }, - }, - { - scope: "keyword.operator.expression.import", - settings: { - foreground: "#7b43f8", - }, - }, - { - scope: "keyword.operator.module", - settings: { - foreground: "#fc2b73", - }, - }, - { - scope: "support.type.object.console", - settings: { - foreground: "#d47628", - }, - }, - { - scope: ["support.module.node", "support.type.object.module", "entity.name.type.module"], - settings: { - foreground: "#d5a910", - }, - }, - { - scope: "support.constant.math", - settings: { - foreground: "#d5a910", - }, - }, - { - scope: "support.constant.property.math", - settings: { - foreground: "#d5a910", - }, - }, - { - scope: "support.constant.json", - settings: { - foreground: "#d5a910", - }, - }, - { - scope: "support.type.object.dom", - settings: { - foreground: "#08c0ef", - }, - }, - { - scope: ["support.variable.dom", "support.variable.property.dom"], - settings: { - foreground: "#d47628", - }, - }, - { - scope: "support.variable.property.process", - settings: { - foreground: "#d5a910", - }, - }, - { - scope: "meta.property.object", - settings: { - foreground: "#d47628", - }, - }, - { - scope: "variable.parameter.function.js", - settings: { - foreground: "#d47628", - }, - }, - { - scope: ["keyword.other.template.begin", "keyword.other.template.end"], - settings: { - foreground: "#199f43", - }, - }, - { - scope: ["keyword.other.substitution.begin", "keyword.other.substitution.end"], - settings: { - foreground: "#199f43", - }, - }, - { - scope: [ - "punctuation.definition.template-expression.begin", - "punctuation.definition.template-expression.end", - ], - settings: { - foreground: "#fc2b73", - }, - }, - { - scope: "meta.template.expression", - settings: { - foreground: "#79797F", - }, - }, - { - scope: "punctuation.section.embedded", - settings: { - foreground: "#d47628", - }, - }, - { - scope: "variable.interpolation", - settings: { - foreground: "#d47628", - }, - }, - { - scope: ["punctuation.section.embedded.begin", "punctuation.section.embedded.end"], - settings: { - foreground: "#fc2b73", - }, - }, - { - scope: "punctuation.quasi.element", - settings: { - foreground: "#fc2b73", - }, - }, - { - scope: [ - "support.type.primitive.ts", - "support.type.builtin.ts", - "support.type.primitive.tsx", - "support.type.builtin.tsx", - ], - settings: { - foreground: "#c635e4", - }, - }, - { - scope: "support.type.type.flowtype", - settings: { - foreground: "#7b43f8", - }, - }, - { - scope: "support.type.primitive", - settings: { - foreground: "#c635e4", - }, - }, - { - scope: "support.variable.magic.python", - settings: { - foreground: "#d52c36", - }, - }, - { - scope: "variable.parameter.function.language.special.self.python", - settings: { - foreground: "#d5a910", - }, - }, - { - scope: [ - "punctuation.separator.period.python", - "punctuation.separator.element.python", - "punctuation.parenthesis.begin.python", - "punctuation.parenthesis.end.python", - ], - settings: { - foreground: "#79797F", - }, - }, - { - scope: [ - "punctuation.definition.arguments.begin.python", - "punctuation.definition.arguments.end.python", - "punctuation.separator.arguments.python", - "punctuation.definition.list.begin.python", - "punctuation.definition.list.end.python", - ], - settings: { - foreground: "#79797F", - }, - }, - { - scope: "support.type.python", - settings: { - foreground: "#08c0ef", - }, - }, - { - scope: "keyword.operator.logical.python", - settings: { - foreground: "#fc2b73", - }, - }, - { - scope: "meta.function-call.generic.python", - settings: { - foreground: "#7b43f8", - }, - }, - { - scope: "constant.character.format.placeholder.other.python", - settings: { - foreground: "#d5a910", - }, - }, - { - scope: "meta.function.decorator.python", - settings: { - foreground: "#7b43f8", - }, - }, - { - scope: ["support.token.decorator.python", "meta.function.decorator.identifier.python"], - settings: { - foreground: "#08c0ef", - }, - }, - { - scope: "storage.modifier.lifetime.rust", - settings: { - foreground: "#79797F", - }, - }, - { - scope: "support.function.std.rust", - settings: { - foreground: "#7b43f8", - }, - }, - { - scope: "entity.name.lifetime.rust", - settings: { - foreground: "#d5a910", - }, - }, - { - scope: "variable.language.rust", - settings: { - foreground: "#d52c36", - }, - }, - { - scope: "keyword.operator.misc.rust", - settings: { - foreground: "#79797F", - }, - }, - { - scope: "keyword.operator.sigil.rust", - settings: { - foreground: "#fc2b73", - }, - }, - { - scope: "support.constant.core.rust", - settings: { - foreground: "#d5a910", - }, - }, - { - scope: ["meta.function.c", "meta.function.cpp"], - settings: { - foreground: "#d52c36", - }, - }, - { - scope: [ - "punctuation.section.block.begin.bracket.curly.cpp", - "punctuation.section.block.end.bracket.curly.cpp", - "punctuation.terminator.statement.c", - "punctuation.section.block.begin.bracket.curly.c", - "punctuation.section.block.end.bracket.curly.c", - "punctuation.section.parens.begin.bracket.round.c", - "punctuation.section.parens.end.bracket.round.c", - "punctuation.section.parameters.begin.bracket.round.c", - "punctuation.section.parameters.end.bracket.round.c", - ], - settings: { - foreground: "#79797F", - }, - }, - { - scope: [ - "keyword.operator.assignment.c", - "keyword.operator.comparison.c", - "keyword.operator.c", - "keyword.operator.increment.c", - "keyword.operator.decrement.c", - "keyword.operator.bitwise.shift.c", - ], - settings: { - foreground: "#fc2b73", - }, - }, - { - scope: [ - "keyword.operator.assignment.cpp", - "keyword.operator.comparison.cpp", - "keyword.operator.cpp", - "keyword.operator.increment.cpp", - "keyword.operator.decrement.cpp", - "keyword.operator.bitwise.shift.cpp", - ], - settings: { - foreground: "#fc2b73", - }, - }, - { - scope: ["punctuation.separator.c", "punctuation.separator.cpp"], - settings: { - foreground: "#fc2b73", - }, - }, - { - scope: ["support.type.posix-reserved.c", "support.type.posix-reserved.cpp"], - settings: { - foreground: "#08c0ef", - }, - }, - { - scope: ["keyword.operator.sizeof.c", "keyword.operator.sizeof.cpp"], - settings: { - foreground: "#fc2b73", - }, - }, - { - scope: "variable.c", - settings: { - foreground: "#79797F", - }, - }, - { - scope: ["storage.type.annotation.java", "storage.type.object.array.java"], - settings: { - foreground: "#d5a910", - }, - }, - { - scope: "source.java", - settings: { - foreground: "#d52c36", - }, - }, - { - scope: [ - "punctuation.section.block.begin.java", - "punctuation.section.block.end.java", - "punctuation.definition.method-parameters.begin.java", - "punctuation.definition.method-parameters.end.java", - "meta.method.identifier.java", - "punctuation.section.method.begin.java", - "punctuation.section.method.end.java", - "punctuation.terminator.java", - "punctuation.section.class.begin.java", - "punctuation.section.class.end.java", - "punctuation.section.inner-class.begin.java", - "punctuation.section.inner-class.end.java", - "meta.method-call.java", - "punctuation.section.class.begin.bracket.curly.java", - "punctuation.section.class.end.bracket.curly.java", - "punctuation.section.method.begin.bracket.curly.java", - "punctuation.section.method.end.bracket.curly.java", - "punctuation.separator.period.java", - "punctuation.bracket.angle.java", - "punctuation.definition.annotation.java", - "meta.method.body.java", - ], - settings: { - foreground: "#79797F", - }, - }, - { - scope: "meta.method.java", - settings: { - foreground: "#7b43f8", - }, - }, - { - scope: ["storage.modifier.import.java", "storage.type.java", "storage.type.generic.java"], - settings: { - foreground: "#d5a910", - }, - }, - { - scope: "keyword.operator.instanceof.java", - settings: { - foreground: "#fc2b73", - }, - }, - { - scope: "meta.definition.variable.name.java", - settings: { - foreground: "#d52c36", - }, - }, - { - scope: "token.variable.parameter.java", - settings: { - foreground: "#79797F", - }, - }, - { - scope: "import.storage.java", - settings: { - foreground: "#d5a910", - }, - }, - { - scope: "token.package.keyword", - settings: { - foreground: "#fc2b73", - }, - }, - { - scope: "token.package", - settings: { - foreground: "#79797F", - }, - }, - { - scope: "token.storage.type.java", - settings: { - foreground: "#d5a910", - }, - }, - { - scope: "keyword.operator.assignment.go", - settings: { - foreground: "#d5a910", - }, - }, - { - scope: ["keyword.operator.arithmetic.go", "keyword.operator.address.go"], - settings: { - foreground: "#fc2b73", - }, - }, - { - scope: "entity.name.package.go", - settings: { - foreground: "#d5a910", - }, - }, - { - scope: [ - "support.other.namespace.use.php", - "support.other.namespace.use-as.php", - "support.other.namespace.php", - "entity.other.alias.php", - "meta.interface.php", - ], - settings: { - foreground: "#d5a910", - }, - }, - { - scope: "keyword.operator.error-control.php", - settings: { - foreground: "#fc2b73", - }, - }, - { - scope: "keyword.operator.type.php", - settings: { - foreground: "#fc2b73", - }, - }, - { - scope: ["punctuation.section.array.begin.php", "punctuation.section.array.end.php"], - settings: { - foreground: "#79797F", - }, - }, - { - scope: [ - "storage.type.php", - "meta.other.type.phpdoc.php", - "keyword.other.type.php", - "keyword.other.array.phpdoc.php", - ], - settings: { - foreground: "#d5a910", - }, - }, - { - scope: [ - "meta.function-call.php", - "meta.function-call.object.php", - "meta.function-call.static.php", - ], - settings: { - foreground: "#7b43f8", - }, - }, - { - scope: [ - "punctuation.definition.parameters.begin.bracket.round.php", - "punctuation.definition.parameters.end.bracket.round.php", - "punctuation.separator.delimiter.php", - "punctuation.section.scope.begin.php", - "punctuation.section.scope.end.php", - "punctuation.terminator.expression.php", - "punctuation.definition.arguments.begin.bracket.round.php", - "punctuation.definition.arguments.end.bracket.round.php", - "punctuation.definition.storage-type.begin.bracket.round.php", - "punctuation.definition.storage-type.end.bracket.round.php", - "punctuation.definition.array.begin.bracket.round.php", - "punctuation.definition.array.end.bracket.round.php", - "punctuation.definition.begin.bracket.round.php", - "punctuation.definition.end.bracket.round.php", - "punctuation.definition.begin.bracket.curly.php", - "punctuation.definition.end.bracket.curly.php", - "punctuation.definition.section.switch-block.end.bracket.curly.php", - "punctuation.definition.section.switch-block.start.bracket.curly.php", - "punctuation.definition.section.switch-block.begin.bracket.curly.php", - "punctuation.definition.section.switch-block.end.bracket.curly.php", - ], - settings: { - foreground: "#79797F", - }, - }, - { - scope: [ - "support.constant.ext.php", - "support.constant.std.php", - "support.constant.core.php", - "support.constant.parser-token.php", - ], - settings: { - foreground: "#d5a910", - }, - }, - { - scope: ["entity.name.goto-label.php", "support.other.php"], - settings: { - foreground: "#7b43f8", - }, - }, - { - scope: [ - "keyword.operator.logical.php", - "keyword.operator.bitwise.php", - "keyword.operator.arithmetic.php", - ], - settings: { - foreground: "#08c0ef", - }, - }, - { - scope: "keyword.operator.regexp.php", - settings: { - foreground: "#fc2b73", - }, - }, - { - scope: "keyword.operator.comparison.php", - settings: { - foreground: "#08c0ef", - }, - }, - { - scope: ["keyword.operator.heredoc.php", "keyword.operator.nowdoc.php"], - settings: { - foreground: "#fc2b73", - }, - }, - { - scope: "variable.other.class.php", - settings: { - foreground: "#d52c36", - }, - }, - { - scope: "invalid.illegal.non-null-typehinted.php", - settings: { - foreground: "#f44747", - }, - }, - { - scope: "variable.other.generic-type.haskell", - settings: { - foreground: "#fc2b73", - }, - }, - { - scope: "storage.type.haskell", - settings: { - foreground: "#d5a910", - }, - }, - { - scope: "storage.type.cs", - settings: { - foreground: "#d5a910", - }, - }, - { - scope: "entity.name.variable.local.cs", - settings: { - foreground: "#d52c36", - }, - }, - { - scope: "entity.name.label.cs", - settings: { - foreground: "#d5a910", - }, - }, - { - scope: [ - "entity.name.scope-resolution.function.call", - "entity.name.scope-resolution.function.definition", - ], - settings: { - foreground: "#d5a910", - }, - }, - { - scope: [ - "punctuation.definition.delayed.unison", - "punctuation.definition.list.begin.unison", - "punctuation.definition.list.end.unison", - "punctuation.definition.ability.begin.unison", - "punctuation.definition.ability.end.unison", - "punctuation.operator.assignment.as.unison", - "punctuation.separator.pipe.unison", - "punctuation.separator.delimiter.unison", - "punctuation.definition.hash.unison", - ], - settings: { - foreground: "#d52c36", - }, - }, - { - scope: "support.constant.edge", - settings: { - foreground: "#fc2b73", - }, - }, - { - scope: "support.type.prelude.elm", - settings: { - foreground: "#08c0ef", - }, - }, - { - scope: "support.constant.elm", - settings: { - foreground: "#d5a910", - }, - }, - { - scope: "entity.global.clojure", - settings: { - foreground: "#d5a910", - }, - }, - { - scope: "meta.symbol.clojure", - settings: { - foreground: "#d52c36", - }, - }, - { - scope: "constant.keyword.clojure", - settings: { - foreground: "#08c0ef", - }, - }, - { - scope: ["meta.arguments.coffee", "variable.parameter.function.coffee"], - settings: { - foreground: "#d52c36", - }, - }, - { - scope: "storage.modifier.import.groovy", - settings: { - foreground: "#d5a910", - }, - }, - { - scope: "meta.method.groovy", - settings: { - foreground: "#7b43f8", - }, - }, - { - scope: "meta.definition.variable.name.groovy", - settings: { - foreground: "#d52c36", - }, - }, - { - scope: "meta.definition.class.inherited.classes.groovy", - settings: { - foreground: "#199f43", - }, - }, - { - scope: "support.variable.semantic.hlsl", - settings: { - foreground: "#d5a910", - }, - }, - { - scope: [ - "support.type.texture.hlsl", - "support.type.sampler.hlsl", - "support.type.object.hlsl", - "support.type.object.rw.hlsl", - "support.type.fx.hlsl", - "support.type.object.hlsl", - ], - settings: { - foreground: "#fc2b73", - }, - }, - { - scope: ["text.variable", "text.bracketed"], - settings: { - foreground: "#d52c36", - }, - }, - { - scope: ["support.type.swift", "support.type.vb.asp"], - settings: { - foreground: "#d5a910", - }, - }, - { - scope: "meta.scope.prerequisites.makefile", - settings: { - foreground: "#d52c36", - }, - }, - { - scope: "source.makefile", - settings: { - foreground: "#d5a910", - }, - }, - { - scope: "source.ini", - settings: { - foreground: "#199f43", - }, - }, - { - scope: "constant.language.symbol.ruby", - settings: { - foreground: "#08c0ef", - }, - }, - { - scope: ["function.parameter.ruby", "function.parameter.cs"], - settings: { - foreground: "#79797F", - }, - }, - { - scope: "constant.language.symbol.elixir", - settings: { - foreground: "#08c0ef", - }, - }, - { - scope: - "text.html.laravel-blade source.php.embedded.line.html entity.name.tag.laravel-blade", - settings: { - foreground: "#fc2b73", - }, - }, - { - scope: - "text.html.laravel-blade source.php.embedded.line.html support.constant.laravel-blade", - settings: { - foreground: "#fc2b73", - }, - }, - { - scope: "entity.name.function.xi", - settings: { - foreground: "#d5a910", - }, - }, - { - scope: "entity.name.class.xi", - settings: { - foreground: "#08c0ef", - }, - }, - { - scope: "constant.character.character-class.regexp.xi", - settings: { - foreground: "#d52c36", - }, - }, - { - scope: "constant.regexp.xi", - settings: { - foreground: "#fc2b73", - }, - }, - { - scope: "keyword.control.xi", - settings: { - foreground: "#08c0ef", - }, - }, - { - scope: "invalid.xi", - settings: { - foreground: "#79797F", - }, - }, - { - scope: "beginning.punctuation.definition.quote.markdown.xi", - settings: { - foreground: "#199f43", - }, - }, - { - scope: "beginning.punctuation.definition.list.markdown.xi", - settings: { - foreground: "#84848A", - }, - }, - { - scope: "constant.character.xi", - settings: { - foreground: "#7b43f8", - }, - }, - { - scope: "accent.xi", - settings: { - foreground: "#7b43f8", - }, - }, - { - scope: "wikiword.xi", - settings: { - foreground: "#d5a910", - }, - }, - { - scope: "constant.other.color.rgb-value.xi", - settings: { - foreground: "#ffffff", - }, - }, - { - scope: "punctuation.definition.tag.xi", - settings: { - foreground: "#84848A", - }, - }, - { - scope: ["support.constant.property-value.scss", "support.constant.property-value.css"], - settings: { - foreground: "#d5a910", - }, - }, - { - scope: ["keyword.operator.css", "keyword.operator.scss", "keyword.operator.less"], - settings: { - foreground: "#08c0ef", - }, - }, - { - scope: [ - "support.constant.color.w3c-standard-color-name.css", - "support.constant.color.w3c-standard-color-name.scss", - ], - settings: { - foreground: "#d5a910", - }, - }, - { - scope: "punctuation.separator.list.comma.css", - settings: { - foreground: "#79797F", - }, - }, - { - scope: "support.type.vendored.property-name.css", - settings: { - foreground: "#08c0ef", - }, - }, - { - scope: "support.type.property-name.css", - settings: { - foreground: "#08c0ef", - }, - }, - { - scope: "support.type.property-name", - settings: { - foreground: "#79797F", - }, - }, - { - scope: "support.constant.property-value", - settings: { - foreground: "#79797F", - }, - }, - { - scope: "support.constant.font-name", - settings: { - foreground: "#d5a910", - }, - }, - { - scope: "entity.other.attribute-name.class.css", - settings: { - foreground: "#16a994", - fontStyle: "normal", - }, - }, - { - scope: "entity.other.attribute-name.id", - settings: { - foreground: "#7b43f8", - fontStyle: "normal", - }, - }, - { - scope: [ - "entity.other.attribute-name.pseudo-element", - "entity.other.attribute-name.pseudo-class", - ], - settings: { - foreground: "#08c0ef", - }, - }, - { - scope: "meta.selector", - settings: { - foreground: "#fc2b73", - }, - }, - { - scope: "selector.sass", - settings: { - foreground: "#d52c36", - }, - }, - { - scope: "rgb-value", - settings: { - foreground: "#08c0ef", - }, - }, - { - scope: "inline-color-decoration rgb-value", - settings: { - foreground: "#d5a910", - }, - }, - { - scope: "less rgb-value", - settings: { - foreground: "#d5a910", - }, - }, - { - scope: "control.elements", - settings: { - foreground: "#d5a910", - }, - }, - { - scope: "keyword.operator.less", - settings: { - foreground: "#d5a910", - }, - }, - { - scope: "entity.name.tag", - settings: { - foreground: "#d52c36", - }, - }, - { - scope: "entity.other.attribute-name", - settings: { - foreground: "#16a994", - fontStyle: "normal", - }, - }, - { - scope: "constant.character.entity", - settings: { - foreground: "#d52c36", - }, - }, - { - scope: "meta.tag", - settings: { - foreground: "#79797F", - }, - }, - { - scope: "invalid.illegal.bad-ampersand.html", - settings: { - foreground: "#79797F", - }, - }, - { - scope: "markup.heading", - settings: { - foreground: "#d52c36", - }, - }, - { - scope: ["markup.heading punctuation.definition.heading", "entity.name.section"], - settings: { - foreground: "#7b43f8", - }, - }, - { - scope: "entity.name.section.markdown", - settings: { - foreground: "#d52c36", - }, - }, - { - scope: "punctuation.definition.heading.markdown", - settings: { - foreground: "#d52c36", - }, - }, - { - scope: "markup.heading.setext", - settings: { - foreground: "#79797F", - }, - }, - { - scope: ["markup.heading.setext.1.markdown", "markup.heading.setext.2.markdown"], - settings: { - foreground: "#d52c36", - }, - }, - { - scope: ["markup.bold", "todo.bold"], - settings: { - foreground: "#d5a910", - }, - }, - { - scope: "punctuation.definition.bold", - settings: { - foreground: "#d5a910", - }, - }, - { - scope: "punctuation.definition.bold.markdown", - settings: { - foreground: "#d5a910", - }, - }, - { - scope: ["markup.italic", "punctuation.definition.italic", "todo.emphasis"], - settings: { - foreground: "#fc2b73", - fontStyle: "italic", - }, - }, - { - scope: "emphasis md", - settings: { - foreground: "#fc2b73", - }, - }, - { - scope: "markup.italic.markdown", - settings: { - fontStyle: "italic", - }, - }, - { - scope: ["markup.underline.link.markdown", "markup.underline.link.image.markdown"], - settings: { - foreground: "#fc2b73", - }, - }, - { - scope: ["string.other.link.title.markdown", "string.other.link.description.markdown"], - settings: { - foreground: "#7b43f8", - }, - }, - { - scope: "punctuation.definition.metadata.markdown", - settings: { - foreground: "#d52c36", - }, - }, - { - scope: ["markup.inline.raw.markdown", "markup.inline.raw.string.markdown"], - settings: { - foreground: "#199f43", - }, - }, - { - scope: "punctuation.definition.list.begin.markdown", - settings: { - foreground: "#d52c36", - }, - }, - { - scope: "punctuation.definition.list.markdown", - settings: { - foreground: "#d52c36", - }, - }, - { - scope: "beginning.punctuation.definition.list.markdown", - settings: { - foreground: "#d52c36", - }, - }, - { - scope: [ - "punctuation.definition.string.begin.markdown", - "punctuation.definition.string.end.markdown", - ], - settings: { - foreground: "#d52c36", - }, - }, - { - scope: "markup.quote.markdown", - settings: { - foreground: "#84848A", - }, - }, - { - scope: "keyword.other.unit", - settings: { - foreground: "#d52c36", - }, - }, - { - scope: "markup.changed.diff", - settings: { - foreground: "#d5a910", - }, - }, - { - scope: [ - "meta.diff.header.from-file", - "meta.diff.header.to-file", - "punctuation.definition.from-file.diff", - "punctuation.definition.to-file.diff", - ], - settings: { - foreground: "#7b43f8", - }, - }, - { - scope: "markup.inserted.diff", - settings: { - foreground: "#199f43", - }, - }, - { - scope: "markup.deleted.diff", - settings: { - foreground: "#d52c36", - }, - }, - { - scope: "string.regexp", - settings: { - foreground: "#17a5af", - }, - }, - { - scope: "constant.other.character-class.regexp", - settings: { - foreground: "#d52c36", - }, - }, - { - scope: "keyword.operator.quantifier.regexp", - settings: { - foreground: "#d5a910", - }, - }, - { - scope: "constant.character.escape", - settings: { - foreground: "#1ca1c7", - }, - }, - { - scope: "source.json meta.structure.dictionary.json > string.quoted.json", - settings: { - foreground: "#d52c36", - }, - }, - { - scope: - "source.json meta.structure.dictionary.json > string.quoted.json > punctuation.string", - settings: { - foreground: "#d52c36", - }, - }, - { - scope: [ - "source.json meta.structure.dictionary.json > value.json > string.quoted.json", - "source.json meta.structure.array.json > value.json > string.quoted.json", - "source.json meta.structure.dictionary.json > value.json > string.quoted.json > punctuation", - "source.json meta.structure.array.json > value.json > string.quoted.json > punctuation", - ], - settings: { - foreground: "#199f43", - }, - }, - { - scope: [ - "source.json meta.structure.dictionary.json > constant.language.json", - "source.json meta.structure.array.json > constant.language.json", - ], - settings: { - foreground: "#08c0ef", - }, - }, - { - scope: "support.type.property-name.json", - settings: { - foreground: "#d52c36", - }, - }, - { - scope: "support.type.property-name.json punctuation", - settings: { - foreground: "#d52c36", - }, - }, - { - scope: "punctuation.definition.block.sequence.item.yaml", - settings: { - foreground: "#79797F", - }, - }, - { - scope: "block.scope.end", - settings: { - foreground: "#79797F", - }, - }, - { - scope: "block.scope.begin", - settings: { - foreground: "#79797F", - }, - }, - { - scope: "token.info-token", - settings: { - foreground: "#7b43f8", - }, - }, - { - scope: "token.warn-token", - settings: { - foreground: "#d5a910", - }, - }, - { - scope: "token.error-token", - settings: { - foreground: "#f44747", - }, - }, - { - scope: "token.debug-token", - settings: { - foreground: "#fc2b73", - }, - }, - { - scope: "invalid.illegal", - settings: { - foreground: "#ffffff", - }, - }, - { - scope: "invalid.broken", - settings: { - foreground: "#ffffff", - }, - }, - { - scope: "invalid.deprecated", - settings: { - foreground: "#ffffff", - }, - }, - { - scope: "invalid.unimplemented", - settings: { - foreground: "#ffffff", - }, - }, - ], - semanticTokenColors: { - comment: "#84848A", - string: "#199f43", - number: "#1ca1c7", - regexp: "#17a5af", - keyword: "#fc2b73", - variable: "#d47628", - parameter: "#79797F", - property: "#d47628", - function: "#7b43f8", - method: "#7b43f8", - type: "#c635e4", - class: "#c635e4", - namespace: "#d5a910", - enumMember: "#08c0ef", - "variable.constant": "#d5a910", - "variable.defaultLibrary": "#d5a910", - }, + name: "oc-1-light", + colors, + tokenColors, + semanticTokenColors, } as unknown as ThemeRegistrationResolved) }) @@ -1969,1783 +567,8 @@ registerCustomTheme("oc-1-dark", () => { return Promise.resolve({ name: "oc-1-dark", type: "dark", - colors: { - "editor.background": "transparent", - "editor.foreground": "#fbfbfb", - foreground: "#fbfbfb", - focusBorder: "#1a76d4", - "selection.background": "#19253c", - "editor.selectionBackground": "#1a76d44d", - "editor.lineHighlightBackground": "#19253c8c", - "editorCursor.foreground": "#1a76d4", - "editorLineNumber.foreground": "#84848A", - "editorLineNumber.activeForeground": "#adadb1", - "editorIndentGuide.background": "#39393c", - "editorIndentGuide.activeBackground": "#2e2e30", - "diffEditor.insertedTextBackground": "#00cab11a", - "diffEditor.deletedTextBackground": "#ff2e3f1a", - "sideBar.background": "#141415", - "sideBar.foreground": "#adadb1", - "sideBar.border": "#070707", - "sideBarTitle.foreground": "#fbfbfb", - "sideBarSectionHeader.background": "#141415", - "sideBarSectionHeader.foreground": "#adadb1", - "sideBarSectionHeader.border": "#070707", - "activityBar.background": "#141415", - "activityBar.foreground": "#fbfbfb", - "activityBar.border": "#070707", - "activityBar.activeBorder": "#1a76d4", - "activityBarBadge.background": "#1a76d4", - "activityBarBadge.foreground": "#070707", - "titleBar.activeBackground": "#141415", - "titleBar.activeForeground": "#fbfbfb", - "titleBar.inactiveBackground": "#141415", - "titleBar.inactiveForeground": "#84848A", - "titleBar.border": "#070707", - "list.activeSelectionBackground": "#19253c99", - "list.activeSelectionForeground": "#fbfbfb", - "list.inactiveSelectionBackground": "#19253c73", - "list.hoverBackground": "#19253c59", - "list.focusOutline": "#1a76d4", - "tab.activeBackground": "#070707", - "tab.activeForeground": "#fbfbfb", - "tab.activeBorderTop": "#1a76d4", - "tab.inactiveBackground": "#141415", - "tab.inactiveForeground": "#84848A", - "tab.border": "#070707", - "editorGroupHeader.tabsBackground": "#141415", - "editorGroupHeader.tabsBorder": "#070707", - "panel.background": "#141415", - "panel.border": "#070707", - "panelTitle.activeBorder": "#1a76d4", - "panelTitle.activeForeground": "#fbfbfb", - "panelTitle.inactiveForeground": "#84848A", - "statusBar.background": "#141415", - "statusBar.foreground": "#adadb1", - "statusBar.border": "#070707", - "statusBar.noFolderBackground": "#141415", - "statusBar.debuggingBackground": "#ffca00", - "statusBar.debuggingForeground": "#070707", - "statusBarItem.remoteBackground": "#141415", - "statusBarItem.remoteForeground": "#adadb1", - "input.background": "#1F1F21", - "input.border": "#424245", - "input.foreground": "#fbfbfb", - "input.placeholderForeground": "#79797F", - "dropdown.background": "#1F1F21", - "dropdown.border": "#424245", - "dropdown.foreground": "#fbfbfb", - "button.background": "#1a76d4", - "button.foreground": "#070707", - "button.hoverBackground": "#186bc0", - "textLink.foreground": "#1a76d4", - "textLink.activeForeground": "#1a76d4", - "gitDecoration.addedResourceForeground": "#00cab1", - "gitDecoration.conflictingResourceForeground": "#ffca00", - "gitDecoration.modifiedResourceForeground": "#1a76d4", - "gitDecoration.deletedResourceForeground": "#ff2e3f", - "gitDecoration.untrackedResourceForeground": "#00cab1", - "gitDecoration.ignoredResourceForeground": "#84848A", - "terminal.titleForeground": "#adadb1", - "terminal.titleInactiveForeground": "#84848A", - "terminal.background": "#141415", - "terminal.foreground": "#adadb1", - "terminal.ansiBlack": "#141415", - "terminal.ansiRed": "#ff2e3f", - "terminal.ansiGreen": "#0dbe4e", - "terminal.ansiYellow": "#ffca00", - "terminal.ansiBlue": "#008cff", - "terminal.ansiMagenta": "#c635e4", - "terminal.ansiCyan": "#08c0ef", - "terminal.ansiWhite": "#c6c6c8", - "terminal.ansiBrightBlack": "#141415", - "terminal.ansiBrightRed": "#ff2e3f", - "terminal.ansiBrightGreen": "#0dbe4e", - "terminal.ansiBrightYellow": "#ffca00", - "terminal.ansiBrightBlue": "#008cff", - "terminal.ansiBrightMagenta": "#c635e4", - "terminal.ansiBrightCyan": "#08c0ef", - "terminal.ansiBrightWhite": "#c6c6c8", - }, - tokenColors: [ - { - scope: ["comment", "punctuation.definition.comment"], - settings: { - foreground: "#84848A", - }, - }, - { - scope: "comment markup.link", - settings: { - foreground: "#84848A", - }, - }, - { - scope: ["string", "constant.other.symbol"], - settings: { - foreground: "#5ecc71", - }, - }, - { - scope: ["punctuation.definition.string.begin", "punctuation.definition.string.end"], - settings: { - foreground: "#5ecc71", - }, - }, - { - scope: ["constant.numeric", "constant.language.boolean"], - settings: { - foreground: "#68cdf2", - }, - }, - { - scope: "constant", - settings: { - foreground: "#ffd452", - }, - }, - { - scope: "punctuation.definition.constant", - settings: { - foreground: "#ffd452", - }, - }, - { - scope: "constant.language", - settings: { - foreground: "#68cdf2", - }, - }, - { - scope: "variable.other.constant", - settings: { - foreground: "#ffca00", - }, - }, - { - scope: "keyword", - settings: { - foreground: "#ff678d", - }, - }, - { - scope: "keyword.control", - settings: { - foreground: "#ff678d", - }, - }, - { - scope: ["storage", "storage.type", "storage.modifier"], - settings: { - foreground: "#ff678d", - }, - }, - { - scope: "token.storage", - settings: { - foreground: "#ff678d", - }, - }, - { - scope: [ - "keyword.operator.new", - "keyword.operator.expression.instanceof", - "keyword.operator.expression.typeof", - "keyword.operator.expression.void", - "keyword.operator.expression.delete", - "keyword.operator.expression.in", - "keyword.operator.expression.of", - "keyword.operator.expression.keyof", - ], - settings: { - foreground: "#ff678d", - }, - }, - { - scope: "keyword.operator.delete", - settings: { - foreground: "#ff678d", - }, - }, - { - scope: ["variable", "identifier", "meta.definition.variable"], - settings: { - foreground: "#ffa359", - }, - }, - { - scope: [ - "variable.other.readwrite", - "meta.object-literal.key", - "support.variable.property", - "support.variable.object.process", - "support.variable.object.node", - ], - settings: { - foreground: "#ffa359", - }, - }, - { - scope: "variable.language", - settings: { - foreground: "#ffca00", - }, - }, - { - scope: "variable.parameter.function", - settings: { - foreground: "#adadb1", - }, - }, - { - scope: "function.parameter", - settings: { - foreground: "#adadb1", - }, - }, - { - scope: "variable.parameter", - settings: { - foreground: "#adadb1", - }, - }, - { - scope: "variable.parameter.function.language.python", - settings: { - foreground: "#ffd452", - }, - }, - { - scope: "variable.parameter.function.python", - settings: { - foreground: "#ffd452", - }, - }, - { - scope: [ - "support.function", - "entity.name.function", - "meta.function-call", - "meta.require", - "support.function.any-method", - "variable.function", - ], - settings: { - foreground: "#9d6afb", - }, - }, - { - scope: "keyword.other.special-method", - settings: { - foreground: "#9d6afb", - }, - }, - { - scope: "entity.name.function", - settings: { - foreground: "#9d6afb", - }, - }, - { - scope: "support.function.console", - settings: { - foreground: "#9d6afb", - }, - }, - { - scope: ["support.type", "entity.name.type", "entity.name.class", "storage.type"], - settings: { - foreground: "#d568ea", - }, - }, - { - scope: ["support.class", "entity.name.type.class"], - settings: { - foreground: "#d568ea", - }, - }, - { - scope: ["entity.name.class", "variable.other.class.js", "variable.other.class.ts"], - settings: { - foreground: "#d568ea", - }, - }, - { - scope: "entity.name.class.identifier.namespace.type", - settings: { - foreground: "#d568ea", - }, - }, - { - scope: "entity.name.type.namespace", - settings: { - foreground: "#ffca00", - }, - }, - { - scope: "entity.other.inherited-class", - settings: { - foreground: "#d568ea", - }, - }, - { - scope: "entity.name.namespace", - settings: { - foreground: "#ffca00", - }, - }, - { - scope: "keyword.operator", - settings: { - foreground: "#79797F", - }, - }, - { - scope: ["keyword.operator.logical", "keyword.operator.bitwise", "keyword.operator.channel"], - settings: { - foreground: "#08c0ef", - }, - }, - { - scope: [ - "keyword.operator.arithmetic", - "keyword.operator.comparison", - "keyword.operator.relational", - "keyword.operator.increment", - "keyword.operator.decrement", - ], - settings: { - foreground: "#08c0ef", - }, - }, - { - scope: "keyword.operator.assignment", - settings: { - foreground: "#08c0ef", - }, - }, - { - scope: "keyword.operator.assignment.compound", - settings: { - foreground: "#ff678d", - }, - }, - { - scope: [ - "keyword.operator.assignment.compound.js", - "keyword.operator.assignment.compound.ts", - ], - settings: { - foreground: "#08c0ef", - }, - }, - { - scope: "keyword.operator.ternary", - settings: { - foreground: "#ff678d", - }, - }, - { - scope: "keyword.operator.optional", - settings: { - foreground: "#ff678d", - }, - }, - { - scope: "punctuation", - settings: { - foreground: "#79797F", - }, - }, - { - scope: "punctuation.separator.delimiter", - settings: { - foreground: "#79797F", - }, - }, - { - scope: "punctuation.separator.key-value", - settings: { - foreground: "#79797F", - }, - }, - { - scope: "punctuation.terminator", - settings: { - foreground: "#79797F", - }, - }, - { - scope: "meta.brace", - settings: { - foreground: "#79797F", - }, - }, - { - scope: "meta.brace.square", - settings: { - foreground: "#79797F", - }, - }, - { - scope: "meta.brace.round", - settings: { - foreground: "#79797F", - }, - }, - { - scope: "function.brace", - settings: { - foreground: "#79797F", - }, - }, - { - scope: ["punctuation.definition.parameters", "punctuation.definition.typeparameters"], - settings: { - foreground: "#79797F", - }, - }, - { - scope: ["punctuation.definition.block", "punctuation.definition.tag"], - settings: { - foreground: "#79797F", - }, - }, - { - scope: ["meta.tag.tsx", "meta.tag.jsx", "meta.tag.js", "meta.tag.ts"], - settings: { - foreground: "#79797F", - }, - }, - { - scope: "keyword.operator.expression.import", - settings: { - foreground: "#9d6afb", - }, - }, - { - scope: "keyword.operator.module", - settings: { - foreground: "#ff678d", - }, - }, - { - scope: "support.type.object.console", - settings: { - foreground: "#ffa359", - }, - }, - { - scope: ["support.module.node", "support.type.object.module", "entity.name.type.module"], - settings: { - foreground: "#ffca00", - }, - }, - { - scope: "support.constant.math", - settings: { - foreground: "#ffca00", - }, - }, - { - scope: "support.constant.property.math", - settings: { - foreground: "#ffd452", - }, - }, - { - scope: "support.constant.json", - settings: { - foreground: "#ffd452", - }, - }, - { - scope: "support.type.object.dom", - settings: { - foreground: "#08c0ef", - }, - }, - { - scope: ["support.variable.dom", "support.variable.property.dom"], - settings: { - foreground: "#ffa359", - }, - }, - { - scope: "support.variable.property.process", - settings: { - foreground: "#ffd452", - }, - }, - { - scope: "meta.property.object", - settings: { - foreground: "#ffa359", - }, - }, - { - scope: "variable.parameter.function.js", - settings: { - foreground: "#ffa359", - }, - }, - { - scope: ["keyword.other.template.begin", "keyword.other.template.end"], - settings: { - foreground: "#5ecc71", - }, - }, - { - scope: ["keyword.other.substitution.begin", "keyword.other.substitution.end"], - settings: { - foreground: "#5ecc71", - }, - }, - { - scope: [ - "punctuation.definition.template-expression.begin", - "punctuation.definition.template-expression.end", - ], - settings: { - foreground: "#ff678d", - }, - }, - { - scope: "meta.template.expression", - settings: { - foreground: "#79797F", - }, - }, - { - scope: "punctuation.section.embedded", - settings: { - foreground: "#ffa359", - }, - }, - { - scope: "variable.interpolation", - settings: { - foreground: "#ffa359", - }, - }, - { - scope: ["punctuation.section.embedded.begin", "punctuation.section.embedded.end"], - settings: { - foreground: "#ff678d", - }, - }, - { - scope: "punctuation.quasi.element", - settings: { - foreground: "#ff678d", - }, - }, - { - scope: [ - "support.type.primitive.ts", - "support.type.builtin.ts", - "support.type.primitive.tsx", - "support.type.builtin.tsx", - ], - settings: { - foreground: "#d568ea", - }, - }, - { - scope: "support.type.type.flowtype", - settings: { - foreground: "#9d6afb", - }, - }, - { - scope: "support.type.primitive", - settings: { - foreground: "#d568ea", - }, - }, - { - scope: "support.variable.magic.python", - settings: { - foreground: "#ff6762", - }, - }, - { - scope: "variable.parameter.function.language.special.self.python", - settings: { - foreground: "#ffca00", - }, - }, - { - scope: [ - "punctuation.separator.period.python", - "punctuation.separator.element.python", - "punctuation.parenthesis.begin.python", - "punctuation.parenthesis.end.python", - ], - settings: { - foreground: "#79797F", - }, - }, - { - scope: [ - "punctuation.definition.arguments.begin.python", - "punctuation.definition.arguments.end.python", - "punctuation.separator.arguments.python", - "punctuation.definition.list.begin.python", - "punctuation.definition.list.end.python", - ], - settings: { - foreground: "#79797F", - }, - }, - { - scope: "support.type.python", - settings: { - foreground: "#08c0ef", - }, - }, - { - scope: "keyword.operator.logical.python", - settings: { - foreground: "#ff678d", - }, - }, - { - scope: "meta.function-call.generic.python", - settings: { - foreground: "#9d6afb", - }, - }, - { - scope: "constant.character.format.placeholder.other.python", - settings: { - foreground: "#ffd452", - }, - }, - { - scope: "meta.function.decorator.python", - settings: { - foreground: "#9d6afb", - }, - }, - { - scope: ["support.token.decorator.python", "meta.function.decorator.identifier.python"], - settings: { - foreground: "#08c0ef", - }, - }, - { - scope: "storage.modifier.lifetime.rust", - settings: { - foreground: "#79797F", - }, - }, - { - scope: "support.function.std.rust", - settings: { - foreground: "#9d6afb", - }, - }, - { - scope: "entity.name.lifetime.rust", - settings: { - foreground: "#ffca00", - }, - }, - { - scope: "variable.language.rust", - settings: { - foreground: "#ff6762", - }, - }, - { - scope: "keyword.operator.misc.rust", - settings: { - foreground: "#79797F", - }, - }, - { - scope: "keyword.operator.sigil.rust", - settings: { - foreground: "#ff678d", - }, - }, - { - scope: "support.constant.core.rust", - settings: { - foreground: "#ffd452", - }, - }, - { - scope: ["meta.function.c", "meta.function.cpp"], - settings: { - foreground: "#ff6762", - }, - }, - { - scope: [ - "punctuation.section.block.begin.bracket.curly.cpp", - "punctuation.section.block.end.bracket.curly.cpp", - "punctuation.terminator.statement.c", - "punctuation.section.block.begin.bracket.curly.c", - "punctuation.section.block.end.bracket.curly.c", - "punctuation.section.parens.begin.bracket.round.c", - "punctuation.section.parens.end.bracket.round.c", - "punctuation.section.parameters.begin.bracket.round.c", - "punctuation.section.parameters.end.bracket.round.c", - ], - settings: { - foreground: "#79797F", - }, - }, - { - scope: [ - "keyword.operator.assignment.c", - "keyword.operator.comparison.c", - "keyword.operator.c", - "keyword.operator.increment.c", - "keyword.operator.decrement.c", - "keyword.operator.bitwise.shift.c", - ], - settings: { - foreground: "#ff678d", - }, - }, - { - scope: [ - "keyword.operator.assignment.cpp", - "keyword.operator.comparison.cpp", - "keyword.operator.cpp", - "keyword.operator.increment.cpp", - "keyword.operator.decrement.cpp", - "keyword.operator.bitwise.shift.cpp", - ], - settings: { - foreground: "#ff678d", - }, - }, - { - scope: ["punctuation.separator.c", "punctuation.separator.cpp"], - settings: { - foreground: "#ff678d", - }, - }, - { - scope: ["support.type.posix-reserved.c", "support.type.posix-reserved.cpp"], - settings: { - foreground: "#08c0ef", - }, - }, - { - scope: ["keyword.operator.sizeof.c", "keyword.operator.sizeof.cpp"], - settings: { - foreground: "#ff678d", - }, - }, - { - scope: "variable.c", - settings: { - foreground: "#79797F", - }, - }, - { - scope: ["storage.type.annotation.java", "storage.type.object.array.java"], - settings: { - foreground: "#ffca00", - }, - }, - { - scope: "source.java", - settings: { - foreground: "#ff6762", - }, - }, - { - scope: [ - "punctuation.section.block.begin.java", - "punctuation.section.block.end.java", - "punctuation.definition.method-parameters.begin.java", - "punctuation.definition.method-parameters.end.java", - "meta.method.identifier.java", - "punctuation.section.method.begin.java", - "punctuation.section.method.end.java", - "punctuation.terminator.java", - "punctuation.section.class.begin.java", - "punctuation.section.class.end.java", - "punctuation.section.inner-class.begin.java", - "punctuation.section.inner-class.end.java", - "meta.method-call.java", - "punctuation.section.class.begin.bracket.curly.java", - "punctuation.section.class.end.bracket.curly.java", - "punctuation.section.method.begin.bracket.curly.java", - "punctuation.section.method.end.bracket.curly.java", - "punctuation.separator.period.java", - "punctuation.bracket.angle.java", - "punctuation.definition.annotation.java", - "meta.method.body.java", - ], - settings: { - foreground: "#79797F", - }, - }, - { - scope: "meta.method.java", - settings: { - foreground: "#9d6afb", - }, - }, - { - scope: ["storage.modifier.import.java", "storage.type.java", "storage.type.generic.java"], - settings: { - foreground: "#ffca00", - }, - }, - { - scope: "keyword.operator.instanceof.java", - settings: { - foreground: "#ff678d", - }, - }, - { - scope: "meta.definition.variable.name.java", - settings: { - foreground: "#ff6762", - }, - }, - { - scope: "token.variable.parameter.java", - settings: { - foreground: "#79797F", - }, - }, - { - scope: "import.storage.java", - settings: { - foreground: "#ffca00", - }, - }, - { - scope: "token.package.keyword", - settings: { - foreground: "#ff678d", - }, - }, - { - scope: "token.package", - settings: { - foreground: "#79797F", - }, - }, - { - scope: "token.storage.type.java", - settings: { - foreground: "#ffca00", - }, - }, - { - scope: "keyword.operator.assignment.go", - settings: { - foreground: "#ffca00", - }, - }, - { - scope: ["keyword.operator.arithmetic.go", "keyword.operator.address.go"], - settings: { - foreground: "#ff678d", - }, - }, - { - scope: "entity.name.package.go", - settings: { - foreground: "#ffca00", - }, - }, - { - scope: [ - "support.other.namespace.use.php", - "support.other.namespace.use-as.php", - "support.other.namespace.php", - "entity.other.alias.php", - "meta.interface.php", - ], - settings: { - foreground: "#ffca00", - }, - }, - { - scope: "keyword.operator.error-control.php", - settings: { - foreground: "#ff678d", - }, - }, - { - scope: "keyword.operator.type.php", - settings: { - foreground: "#ff678d", - }, - }, - { - scope: ["punctuation.section.array.begin.php", "punctuation.section.array.end.php"], - settings: { - foreground: "#79797F", - }, - }, - { - scope: [ - "storage.type.php", - "meta.other.type.phpdoc.php", - "keyword.other.type.php", - "keyword.other.array.phpdoc.php", - ], - settings: { - foreground: "#ffca00", - }, - }, - { - scope: [ - "meta.function-call.php", - "meta.function-call.object.php", - "meta.function-call.static.php", - ], - settings: { - foreground: "#9d6afb", - }, - }, - { - scope: [ - "punctuation.definition.parameters.begin.bracket.round.php", - "punctuation.definition.parameters.end.bracket.round.php", - "punctuation.separator.delimiter.php", - "punctuation.section.scope.begin.php", - "punctuation.section.scope.end.php", - "punctuation.terminator.expression.php", - "punctuation.definition.arguments.begin.bracket.round.php", - "punctuation.definition.arguments.end.bracket.round.php", - "punctuation.definition.storage-type.begin.bracket.round.php", - "punctuation.definition.storage-type.end.bracket.round.php", - "punctuation.definition.array.begin.bracket.round.php", - "punctuation.definition.array.end.bracket.round.php", - "punctuation.definition.begin.bracket.round.php", - "punctuation.definition.end.bracket.round.php", - "punctuation.definition.begin.bracket.curly.php", - "punctuation.definition.end.bracket.curly.php", - "punctuation.definition.section.switch-block.end.bracket.curly.php", - "punctuation.definition.section.switch-block.start.bracket.curly.php", - "punctuation.definition.section.switch-block.begin.bracket.curly.php", - "punctuation.definition.section.switch-block.end.bracket.curly.php", - ], - settings: { - foreground: "#79797F", - }, - }, - { - scope: [ - "support.constant.ext.php", - "support.constant.std.php", - "support.constant.core.php", - "support.constant.parser-token.php", - ], - settings: { - foreground: "#ffd452", - }, - }, - { - scope: ["entity.name.goto-label.php", "support.other.php"], - settings: { - foreground: "#9d6afb", - }, - }, - { - scope: [ - "keyword.operator.logical.php", - "keyword.operator.bitwise.php", - "keyword.operator.arithmetic.php", - ], - settings: { - foreground: "#08c0ef", - }, - }, - { - scope: "keyword.operator.regexp.php", - settings: { - foreground: "#ff678d", - }, - }, - { - scope: "keyword.operator.comparison.php", - settings: { - foreground: "#08c0ef", - }, - }, - { - scope: ["keyword.operator.heredoc.php", "keyword.operator.nowdoc.php"], - settings: { - foreground: "#ff678d", - }, - }, - { - scope: "variable.other.class.php", - settings: { - foreground: "#ff6762", - }, - }, - { - scope: "invalid.illegal.non-null-typehinted.php", - settings: { - foreground: "#f44747", - }, - }, - { - scope: "variable.other.generic-type.haskell", - settings: { - foreground: "#ff678d", - }, - }, - { - scope: "storage.type.haskell", - settings: { - foreground: "#ffd452", - }, - }, - { - scope: "storage.type.cs", - settings: { - foreground: "#ffca00", - }, - }, - { - scope: "entity.name.variable.local.cs", - settings: { - foreground: "#ff6762", - }, - }, - { - scope: "entity.name.label.cs", - settings: { - foreground: "#ffca00", - }, - }, - { - scope: [ - "entity.name.scope-resolution.function.call", - "entity.name.scope-resolution.function.definition", - ], - settings: { - foreground: "#ffca00", - }, - }, - { - scope: [ - "punctuation.definition.delayed.unison", - "punctuation.definition.list.begin.unison", - "punctuation.definition.list.end.unison", - "punctuation.definition.ability.begin.unison", - "punctuation.definition.ability.end.unison", - "punctuation.operator.assignment.as.unison", - "punctuation.separator.pipe.unison", - "punctuation.separator.delimiter.unison", - "punctuation.definition.hash.unison", - ], - settings: { - foreground: "#ff6762", - }, - }, - { - scope: "support.constant.edge", - settings: { - foreground: "#ff678d", - }, - }, - { - scope: "support.type.prelude.elm", - settings: { - foreground: "#08c0ef", - }, - }, - { - scope: "support.constant.elm", - settings: { - foreground: "#ffd452", - }, - }, - { - scope: "entity.global.clojure", - settings: { - foreground: "#ffca00", - }, - }, - { - scope: "meta.symbol.clojure", - settings: { - foreground: "#ff6762", - }, - }, - { - scope: "constant.keyword.clojure", - settings: { - foreground: "#08c0ef", - }, - }, - { - scope: ["meta.arguments.coffee", "variable.parameter.function.coffee"], - settings: { - foreground: "#ff6762", - }, - }, - { - scope: "storage.modifier.import.groovy", - settings: { - foreground: "#ffca00", - }, - }, - { - scope: "meta.method.groovy", - settings: { - foreground: "#9d6afb", - }, - }, - { - scope: "meta.definition.variable.name.groovy", - settings: { - foreground: "#ff6762", - }, - }, - { - scope: "meta.definition.class.inherited.classes.groovy", - settings: { - foreground: "#5ecc71", - }, - }, - { - scope: "support.variable.semantic.hlsl", - settings: { - foreground: "#ffca00", - }, - }, - { - scope: [ - "support.type.texture.hlsl", - "support.type.sampler.hlsl", - "support.type.object.hlsl", - "support.type.object.rw.hlsl", - "support.type.fx.hlsl", - "support.type.object.hlsl", - ], - settings: { - foreground: "#ff678d", - }, - }, - { - scope: ["text.variable", "text.bracketed"], - settings: { - foreground: "#ff6762", - }, - }, - { - scope: ["support.type.swift", "support.type.vb.asp"], - settings: { - foreground: "#ffca00", - }, - }, - { - scope: "meta.scope.prerequisites.makefile", - settings: { - foreground: "#ff6762", - }, - }, - { - scope: "source.makefile", - settings: { - foreground: "#ffca00", - }, - }, - { - scope: "source.ini", - settings: { - foreground: "#5ecc71", - }, - }, - { - scope: "constant.language.symbol.ruby", - settings: { - foreground: "#08c0ef", - }, - }, - { - scope: ["function.parameter.ruby", "function.parameter.cs"], - settings: { - foreground: "#79797F", - }, - }, - { - scope: "constant.language.symbol.elixir", - settings: { - foreground: "#08c0ef", - }, - }, - { - scope: - "text.html.laravel-blade source.php.embedded.line.html entity.name.tag.laravel-blade", - settings: { - foreground: "#ff678d", - }, - }, - { - scope: - "text.html.laravel-blade source.php.embedded.line.html support.constant.laravel-blade", - settings: { - foreground: "#ff678d", - }, - }, - { - scope: "entity.name.function.xi", - settings: { - foreground: "#ffca00", - }, - }, - { - scope: "entity.name.class.xi", - settings: { - foreground: "#08c0ef", - }, - }, - { - scope: "constant.character.character-class.regexp.xi", - settings: { - foreground: "#ff6762", - }, - }, - { - scope: "constant.regexp.xi", - settings: { - foreground: "#ff678d", - }, - }, - { - scope: "keyword.control.xi", - settings: { - foreground: "#08c0ef", - }, - }, - { - scope: "invalid.xi", - settings: { - foreground: "#79797F", - }, - }, - { - scope: "beginning.punctuation.definition.quote.markdown.xi", - settings: { - foreground: "#5ecc71", - }, - }, - { - scope: "beginning.punctuation.definition.list.markdown.xi", - settings: { - foreground: "#84848A", - }, - }, - { - scope: "constant.character.xi", - settings: { - foreground: "#9d6afb", - }, - }, - { - scope: "accent.xi", - settings: { - foreground: "#9d6afb", - }, - }, - { - scope: "wikiword.xi", - settings: { - foreground: "#ffd452", - }, - }, - { - scope: "constant.other.color.rgb-value.xi", - settings: { - foreground: "#ffffff", - }, - }, - { - scope: "punctuation.definition.tag.xi", - settings: { - foreground: "#84848A", - }, - }, - { - scope: ["support.constant.property-value.scss", "support.constant.property-value.css"], - settings: { - foreground: "#ffd452", - }, - }, - { - scope: ["keyword.operator.css", "keyword.operator.scss", "keyword.operator.less"], - settings: { - foreground: "#08c0ef", - }, - }, - { - scope: [ - "support.constant.color.w3c-standard-color-name.css", - "support.constant.color.w3c-standard-color-name.scss", - ], - settings: { - foreground: "#ffd452", - }, - }, - { - scope: "punctuation.separator.list.comma.css", - settings: { - foreground: "#79797F", - }, - }, - { - scope: "support.type.vendored.property-name.css", - settings: { - foreground: "#08c0ef", - }, - }, - { - scope: "support.type.property-name.css", - settings: { - foreground: "#08c0ef", - }, - }, - { - scope: "support.type.property-name", - settings: { - foreground: "#79797F", - }, - }, - { - scope: "support.constant.property-value", - settings: { - foreground: "#79797F", - }, - }, - { - scope: "support.constant.font-name", - settings: { - foreground: "#ffd452", - }, - }, - { - scope: "entity.other.attribute-name.class.css", - settings: { - foreground: "#61d5c0", - fontStyle: "normal", - }, - }, - { - scope: "entity.other.attribute-name.id", - settings: { - foreground: "#9d6afb", - fontStyle: "normal", - }, - }, - { - scope: [ - "entity.other.attribute-name.pseudo-element", - "entity.other.attribute-name.pseudo-class", - ], - settings: { - foreground: "#08c0ef", - }, - }, - { - scope: "meta.selector", - settings: { - foreground: "#ff678d", - }, - }, - { - scope: "selector.sass", - settings: { - foreground: "#ff6762", - }, - }, - { - scope: "rgb-value", - settings: { - foreground: "#08c0ef", - }, - }, - { - scope: "inline-color-decoration rgb-value", - settings: { - foreground: "#ffd452", - }, - }, - { - scope: "less rgb-value", - settings: { - foreground: "#ffd452", - }, - }, - { - scope: "control.elements", - settings: { - foreground: "#ffd452", - }, - }, - { - scope: "keyword.operator.less", - settings: { - foreground: "#ffd452", - }, - }, - { - scope: "entity.name.tag", - settings: { - foreground: "#ff6762", - }, - }, - { - scope: "entity.other.attribute-name", - settings: { - foreground: "#61d5c0", - fontStyle: "normal", - }, - }, - { - scope: "constant.character.entity", - settings: { - foreground: "#ff6762", - }, - }, - { - scope: "meta.tag", - settings: { - foreground: "#79797F", - }, - }, - { - scope: "invalid.illegal.bad-ampersand.html", - settings: { - foreground: "#79797F", - }, - }, - { - scope: "markup.heading", - settings: { - foreground: "#ff6762", - }, - }, - { - scope: ["markup.heading punctuation.definition.heading", "entity.name.section"], - settings: { - foreground: "#9d6afb", - }, - }, - { - scope: "entity.name.section.markdown", - settings: { - foreground: "#ff6762", - }, - }, - { - scope: "punctuation.definition.heading.markdown", - settings: { - foreground: "#ff6762", - }, - }, - { - scope: "markup.heading.setext", - settings: { - foreground: "#79797F", - }, - }, - { - scope: ["markup.heading.setext.1.markdown", "markup.heading.setext.2.markdown"], - settings: { - foreground: "#ff6762", - }, - }, - { - scope: ["markup.bold", "todo.bold"], - settings: { - foreground: "#ffd452", - }, - }, - { - scope: "punctuation.definition.bold", - settings: { - foreground: "#ffca00", - }, - }, - { - scope: "punctuation.definition.bold.markdown", - settings: { - foreground: "#ffd452", - }, - }, - { - scope: ["markup.italic", "punctuation.definition.italic", "todo.emphasis"], - settings: { - foreground: "#ff678d", - fontStyle: "italic", - }, - }, - { - scope: "emphasis md", - settings: { - foreground: "#ff678d", - }, - }, - { - scope: "markup.italic.markdown", - settings: { - fontStyle: "italic", - }, - }, - { - scope: ["markup.underline.link.markdown", "markup.underline.link.image.markdown"], - settings: { - foreground: "#ff678d", - }, - }, - { - scope: ["string.other.link.title.markdown", "string.other.link.description.markdown"], - settings: { - foreground: "#9d6afb", - }, - }, - { - scope: "punctuation.definition.metadata.markdown", - settings: { - foreground: "#ff6762", - }, - }, - { - scope: ["markup.inline.raw.markdown", "markup.inline.raw.string.markdown"], - settings: { - foreground: "#5ecc71", - }, - }, - { - scope: "punctuation.definition.list.begin.markdown", - settings: { - foreground: "#ff6762", - }, - }, - { - scope: "punctuation.definition.list.markdown", - settings: { - foreground: "#ff6762", - }, - }, - { - scope: "beginning.punctuation.definition.list.markdown", - settings: { - foreground: "#ff6762", - }, - }, - { - scope: [ - "punctuation.definition.string.begin.markdown", - "punctuation.definition.string.end.markdown", - ], - settings: { - foreground: "#ff6762", - }, - }, - { - scope: "markup.quote.markdown", - settings: { - foreground: "#84848A", - }, - }, - { - scope: "keyword.other.unit", - settings: { - foreground: "#ff6762", - }, - }, - { - scope: "markup.changed.diff", - settings: { - foreground: "#ffca00", - }, - }, - { - scope: [ - "meta.diff.header.from-file", - "meta.diff.header.to-file", - "punctuation.definition.from-file.diff", - "punctuation.definition.to-file.diff", - ], - settings: { - foreground: "#9d6afb", - }, - }, - { - scope: "markup.inserted.diff", - settings: { - foreground: "#5ecc71", - }, - }, - { - scope: "markup.deleted.diff", - settings: { - foreground: "#ff6762", - }, - }, - { - scope: "string.regexp", - settings: { - foreground: "#64d1db", - }, - }, - { - scope: "constant.other.character-class.regexp", - settings: { - foreground: "#ff6762", - }, - }, - { - scope: "keyword.operator.quantifier.regexp", - settings: { - foreground: "#ffd452", - }, - }, - { - scope: "constant.character.escape", - settings: { - foreground: "#68cdf2", - }, - }, - { - scope: "source.json meta.structure.dictionary.json > string.quoted.json", - settings: { - foreground: "#ff6762", - }, - }, - { - scope: - "source.json meta.structure.dictionary.json > string.quoted.json > punctuation.string", - settings: { - foreground: "#ff6762", - }, - }, - { - scope: [ - "source.json meta.structure.dictionary.json > value.json > string.quoted.json", - "source.json meta.structure.array.json > value.json > string.quoted.json", - "source.json meta.structure.dictionary.json > value.json > string.quoted.json > punctuation", - "source.json meta.structure.array.json > value.json > string.quoted.json > punctuation", - ], - settings: { - foreground: "#5ecc71", - }, - }, - { - scope: [ - "source.json meta.structure.dictionary.json > constant.language.json", - "source.json meta.structure.array.json > constant.language.json", - ], - settings: { - foreground: "#08c0ef", - }, - }, - { - scope: "support.type.property-name.json", - settings: { - foreground: "#ff6762", - }, - }, - { - scope: "support.type.property-name.json punctuation", - settings: { - foreground: "#ff6762", - }, - }, - { - scope: "punctuation.definition.block.sequence.item.yaml", - settings: { - foreground: "#79797F", - }, - }, - { - scope: "block.scope.end", - settings: { - foreground: "#79797F", - }, - }, - { - scope: "block.scope.begin", - settings: { - foreground: "#79797F", - }, - }, - { - scope: "token.info-token", - settings: { - foreground: "#9d6afb", - }, - }, - { - scope: "token.warn-token", - settings: { - foreground: "#ffd452", - }, - }, - { - scope: "token.error-token", - settings: { - foreground: "#f44747", - }, - }, - { - scope: "token.debug-token", - settings: { - foreground: "#ff678d", - }, - }, - { - scope: "invalid.illegal", - settings: { - foreground: "#ffffff", - }, - }, - { - scope: "invalid.broken", - settings: { - foreground: "#ffffff", - }, - }, - { - scope: "invalid.deprecated", - settings: { - foreground: "#ffffff", - }, - }, - { - scope: "invalid.unimplemented", - settings: { - foreground: "#ffffff", - }, - }, - ], - semanticTokenColors: { - comment: "#84848A", - string: "#5ecc71", - number: "#68cdf2", - regexp: "#64d1db", - keyword: "#ff678d", - variable: "#ffa359", - parameter: "#adadb1", - property: "#ffa359", - function: "#9d6afb", - method: "#9d6afb", - type: "#d568ea", - class: "#d568ea", - namespace: "#ffca00", - enumMember: "#08c0ef", - "variable.constant": "#ffd452", - "variable.defaultLibrary": "#ffca00", - }, + colors, + tokenColors, + semanticTokenColors, } as unknown as ThemeRegistrationResolved) }) diff --git a/packages/ui/src/styles/tailwind/colors.css b/packages/ui/src/styles/tailwind/colors.css index a5f982d6..95a497ba 100644 --- a/packages/ui/src/styles/tailwind/colors.css +++ b/packages/ui/src/styles/tailwind/colors.css @@ -196,15 +196,20 @@ --color-icon-diff-delete-base: var(--icon-diff-delete-base); --color-icon-diff-delete-hover: var(--icon-diff-delete-hover); --color-syntax-comment: var(--syntax-comment); + --color-syntax-regexp: var(--syntax-regexp); --color-syntax-string: var(--syntax-string); --color-syntax-keyword: var(--syntax-keyword); --color-syntax-function: var(--syntax-function); --color-syntax-number: var(--syntax-number); --color-syntax-operator: var(--syntax-operator); --color-syntax-variable: var(--syntax-variable); + --color-syntax-property: var(--syntax-property); + --color-syntax-parameter: var(--syntax-parameter); --color-syntax-type: var(--syntax-type); --color-syntax-constant: var(--syntax-constant); --color-syntax-punctuation: var(--syntax-punctuation); + --color-syntax-namespace: var(--syntax-namespace); + --color-syntax-enum: var(--syntax-enum); --color-syntax-success: var(--syntax-success); --color-syntax-warning: var(--syntax-warning); --color-syntax-critical: var(--syntax-critical); diff --git a/packages/ui/src/styles/theme.css b/packages/ui/src/styles/theme.css index 6187eef9..431d811d 100644 --- a/packages/ui/src/styles/theme.css +++ b/packages/ui/src/styles/theme.css @@ -268,20 +268,25 @@ --icon-diff-add-active: var(--mint-light-12); --icon-diff-delete-base: var(--ember-light-10); --icon-diff-delete-hover: var(--ember-light-11); - --syntax-comment: #8a8a8a; - --syntax-string: #d68c27; - --syntax-keyword: #3b7dd8; - --syntax-function: #d1383d; - --syntax-number: #3d9a57; - --syntax-operator: #d68c27; - --syntax-variable: #b0851f; - --syntax-type: #318795; - --syntax-constant: #953170; - --syntax-punctuation: #1a1a1a; - --syntax-success: var(--apple-dark-10); + --syntax-comment: var(--text-weaker); + --syntax-regexp: var(--text-base); + --syntax-string: var(--mint-light-11); + --syntax-keyword: var(--text-weak); + --syntax-primitive: var(--ember-light-11); + --syntax-operator: var(--text-weak); + --syntax-variable: var(--text-strong); + --syntax-property: var(--lilac-light-11); + --syntax-type: var(--cobalt-light-11); + --syntax-constant: var(--lilac-light-11); + --syntax-punctuation: var(--text-weak); + --syntax-object: var(--blue-light-11); + --syntax-success: var(--apple-light-10); --syntax-warning: var(--amber-light-10); - --syntax-critical: var(--ember-dark-9); - --syntax-info: var(--lilac-dark-11); + --syntax-critical: var(--ember-light-9); + --syntax-info: var(--lilac-light-11); + --syntax-diff-add: var(--mint-light-11); + --syntax-diff-delete: var(--ember-light-11); + --syntax-unknown: red; --markdown-heading: #d68c27; --markdown-text: #1a1a1a; --markdown-link: #3b7dd8; @@ -503,20 +508,24 @@ --icon-diff-add-active: var(--mint-dark-11); --icon-diff-delete-base: var(--ember-dark-9); --icon-diff-delete-hover: var(--ember-dark-10); - --syntax-comment: #808080; - --syntax-string: #9d7cd8; - --syntax-keyword: #fab283; - --syntax-function: #e06c75; - --syntax-number: #7fd88f; - --syntax-operator: #f5a742; - --syntax-variable: #e5c07b; - --syntax-type: #56b6c2; - --syntax-constant: #c2569a; - --syntax-punctuation: #eeeeee; + --syntax-comment: var(--text-weaker); + --syntax-regexp: var(--text-base); + --syntax-string: var(--mint-dark-11); + --syntax-keyword: var(--text-weak); + --syntax-primitive: var(--ember-dark-11); + --syntax-operator: var(--text-weak); + --syntax-variable: var(--text-strong); + --syntax-property: var(--lilac-dark-11); + --syntax-type: var(--cobalt-dark-11); + --syntax-constant: var(--lilac-dark-11); + --syntax-punctuation: var(--text-weak); + --syntax-object: var(--blue-dark-11); --syntax-success: var(--apple-dark-10); --syntax-warning: var(--amber-dark-10); - --syntax-critical: var(--ember-dark-10); - --syntax-info: var(--lilac-dark-10); + --syntax-critical: var(--ember-dark-9); + --syntax-info: var(--lilac-dark-11); + --syntax-diff-add: var(--mint-dark-11); + --syntax-diff-delete: var(--ember-dark-11); --markdown-heading: #9d7cd8; --markdown-text: #eeeeee; --markdown-link: #fab283; diff --git a/theme-test.java b/theme-test.java new file mode 100644 index 00000000..7c1b582a --- /dev/null +++ b/theme-test.java @@ -0,0 +1,461 @@ +package com.example.theme; + +import java.util.*; +import java.util.concurrent.*; +import java.util.function.*; +import java.util.stream.*; +import java.time.*; +import java.time.format.*; +import java.net.*; +import java.io.*; +import java.nio.file.*; +import java.sql.*; +import java.lang.annotation.*; +import java.math.BigDecimal; +import java.math.BigInteger; + +// Enum definition +public enum LogLevel { + DEBUG(0, "Debug"), + INFO(1, "Info"), + WARN(2, "Warning"), + ERROR(3, "Error"); + + private final int level; + private final String description; + + LogLevel(int level, String description) { + this.level = level; + this.description = description; + } + + public int getLevel() { return level; } + public String getDescription() { return description; } +} + +// Interface with generics +public interface Repository { + Optional findById(Long id); + List findAll(); + T save(T entity); + void delete(Long id); + Stream stream(); + + @FunctionalInterface + interface Predicate { + boolean test(T t); + } +} + +// Abstract class +public abstract class AbstractService implements Repository { + protected final Map cache = new ConcurrentHashMap<>(); + protected volatile boolean initialized = false; + + @Override + public Optional findById(Long id) { + return Optional.ofNullable(cache.get(id)); + } + + @Override + public List findAll() { + return new ArrayList<>(cache.values()); + } + + @Override + public Stream stream() { + return cache.values().stream(); + } + + protected abstract void validate(T entity) throws ValidationException; +} + +// Annotation definition +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.TYPE, ElementType.METHOD}) +public @interface Service { + String value() default ""; + boolean transactional() default true; + Class[] exceptions() = {}; +} + +// Record class (Java 14+) +public record User( + Long id, + String username, + String email, + @Deprecated String fullName, + LocalDateTime createdAt, + boolean active +) implements Entity { + + public User { + Objects.requireNonNull(username, "Username cannot be null"); + Objects.requireNonNull(email, "Email cannot be null"); + Objects.requireNonNull(createdAt, "Created date cannot be null"); + } + + public static User of(String username, String email) { + return new User(null, username, email, null, LocalDateTime.now(), true); + } + + public User withId(Long id) { + return new User(id, username, email, fullName, createdAt, active); + } +} + +// Exception classes +public class ValidationException extends RuntimeException { + private final List errors; + + public ValidationException(String message) { + super(message); + this.errors = List.of(message); + } + + public ValidationException(List errors) { + super(String.join(", ", errors)); + this.errors = Collections.unmodifiableList(errors); + } + + public List getErrors() { return errors; } +} + +public class ResourceNotFoundException extends RuntimeException { + public ResourceNotFoundException(String resource, Long id) { + super(String.format("%s with id %d not found", resource, id)); + } +} + +// Service implementation +@Service(value = "userService", transactional = true) +public class UserService extends AbstractService { + + private static final Logger logger = LoggerFactory.getLogger(UserService.class); + private static final int MAX_RETRY_ATTEMPTS = 3; + private static final Duration TIMEOUT = Duration.ofSeconds(30); + + private final EmailService emailService; + private final UserRepository userRepository; + private final PasswordEncoder passwordEncoder; + + @Inject + public UserService(EmailService emailService, + UserRepository userRepository, + PasswordEncoder passwordEncoder) { + this.emailService = emailService; + this.userRepository = userRepository; + this.passwordEncoder = passwordEncoder; + } + + @Override + protected void validate(User user) throws ValidationException { + List errors = new ArrayList<>(); + + if (user.username() == null || user.username().trim().isEmpty()) { + errors.add("Username is required"); + } else if (!user.username().matches("^[a-zA-Z0-9_]{3,20}$")) { + errors.add("Username must be 3-20 characters, alphanumeric and underscore only"); + } + + if (user.email() == null || !user.email().matches("^[A-Za-z0-9+_.-]+@(.+)$")) { + errors.add("Valid email is required"); + } + + if (!errors.isEmpty()) { + throw new ValidationException(errors); + } + } + + @Transactional + public User createUser(CreateUserRequest request) throws ValidationException { + logger.info("Creating new user: {}", request.username()); + + // Check if user already exists + if (userRepository.findByUsername(request.username()).isPresent()) { + throw new ValidationException("Username already exists"); + } + + if (userRepository.findByEmail(request.email()).isPresent()) { + throw new ValidationException("Email already exists"); + } + + // Create new user + User user = User.of(request.username(), request.email()) + .withId(generateId()); + + validate(user); + + try { + User savedUser = userRepository.save(user); + cache.put(savedUser.id(), savedUser); + + // Send welcome email asynchronously + CompletableFuture.runAsync(() -> + emailService.sendWelcomeEmail(savedUser) + ).exceptionally(throwable -> { + logger.error("Failed to send welcome email to user {}", savedUser.id(), throwable); + return null; + }); + + logger.info("Successfully created user with ID: {}", savedUser.id()); + return savedUser; + + } catch (DataAccessException e) { + logger.error("Database error while creating user", e); + throw new ServiceException("Failed to create user", e); + } + } + + public Optional findByUsername(String username) { + return cache.values().stream() + .filter(user -> user.username().equals(username)) + .findFirst(); + } + + public List findActiveUsers() { + return cache.values().stream() + .filter(User::active) + .sorted(Comparator.comparing(User::createdAt).reversed()) + .collect(Collectors.toList()); + } + + @Retry(maxAttempts = MAX_RETRY_ATTEMPTS, backoff = @Backoff(delay = 1000)) + public User updateUser(Long id, UpdateUserRequest request) { + User existingUser = findById(id) + .orElseThrow(() -> new ResourceNotFoundException("User", id)); + + User updatedUser = new User( + id, + request.username() != null ? request.username() : existingUser.username(), + request.email() != null ? request.email() : existingUser.email(), + existingUser.fullName(), + existingUser.createdAt(), + request.active() != null ? request.active() : existingUser.active() + ); + + validate(updatedUser); + + try { + User savedUser = userRepository.save(updatedUser); + cache.put(id, savedUser); + return savedUser; + } catch (DataAccessException e) { + logger.error("Failed to update user with ID: {}", id, e); + throw new ServiceException("Failed to update user", e); + } + } + + @Async + public CompletableFuture deleteUser(Long id) { + return CompletableFuture.runAsync(() -> { + try { + userRepository.deleteById(id); + cache.remove(id); + logger.info("Successfully deleted user with ID: {}", id); + } catch (DataAccessException e) { + logger.error("Failed to delete user with ID: {}", id, e); + throw new ServiceException("Failed to delete user", e); + } + }); + } + + private Long generateId() { + return System.currentTimeMillis() + (long)(Math.random() * 1000); + } +} + +// Utility class +public final class DateUtils { + + private DateUtils() { + // Utility class - prevent instantiation + } + + private static final DateTimeFormatter ISO_FORMATTER = + DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSXXX"); + + public static String formatIsoDateTime(LocalDateTime dateTime) { + return dateTime.atZone(ZoneId.systemDefault()).format(ISO_FORMATTER); + } + + public static LocalDateTime parseIsoDateTime(String isoString) { + return LocalDateTime.parse(isoString, ISO_FORMATTER); + } + + public static boolean isWithinLastDays(LocalDateTime dateTime, int days) { + return dateTime.isAfter(LocalDateTime.now().minusDays(days)); + } +} + +// Builder pattern +public class UserQueryBuilder { + private String username; + private String email; + private Boolean active; + private LocalDateTime createdAfter; + private LocalDateTime createdBefore; + private SortOrder sortOrder = SortOrder.ASC; + private String sortBy = "createdAt"; + private int limit = 100; + private int offset = 0; + + public UserQueryBuilder withUsername(String username) { + this.username = username; + return this; + } + + public UserQueryBuilder withEmail(String email) { + this.email = email; + return this; + } + + public UserQueryBuilder activeOnly(boolean active) { + this.active = active; + return this; + } + + public UserQueryBuilder createdAfter(LocalDateTime date) { + this.createdAfter = date; + return this; + } + + public UserQueryBuilder createdBefore(LocalDateTime date) { + this.createdBefore = date; + return this; + } + + public UserQueryBuilder sortBy(String field, SortOrder order) { + this.sortBy = field; + this.sortOrder = order; + return this; + } + + public UserQueryBuilder limit(int limit) { + this.limit = Math.max(1, Math.min(limit, 1000)); + return this; + } + + public UserQueryBuilder offset(int offset) { + this.offset = Math.max(0, offset); + return this; + } + + public UserQuery build() { + return new UserQuery(username, email, active, createdAfter, createdBefore, + sortBy, sortOrder, limit, offset); + } +} + +// Lambda expressions and streams +public class StreamProcessor { + + private static final Map> TYPE_CONVERTERS = Map.of( + "string", s -> s, + "int", Integer::parseInt, + "double", Double::parseDouble, + "boolean", Boolean::parseBoolean, + "bigdecimal", BigDecimal::new, + "bigint", BigInteger::new + ); + + public Map processConfig(Properties properties) { + return properties.entrySet().stream() + .filter(entry -> entry.getKey() instanceof String) + .filter(entry -> entry.getValue() != null) + .collect(Collectors.toMap( + entry -> (String) entry.getKey(), + entry -> convertValue((String) entry.getKey(), (String) entry.getValue()) + )); + } + + private Object convertValue(String key, String value) { + String type = determineType(key, value); + return TYPE_CONVERTERS.getOrDefault(type, Function.identity()).apply(value); + } + + private String determineType(String key, String value) { + if (value.equalsIgnoreCase("true") || value.equalsIgnoreCase("false")) { + return "boolean"; + } else if (value.matches("-?\\d+")) { + return "int"; + } else if (value.matches("-?\\d*\\.\\d+")) { + return "double"; + } else if (key.toLowerCase().contains("amount") || key.toLowerCase().contains("price")) { + return "bigdecimal"; + } + return "string"; + } + + public List validateEmails(List emails) { + return emails.stream() + .filter(Objects::nonNull) + .map(String::trim) + .filter(email -> !email.isEmpty()) + .filter(email -> email.matches("^[A-Za-z0-9+_.-]+@(.+)$")) + .distinct() + .collect(Collectors.toList()); + } + + public CompletableFuture> processUsersAsync(List users) { + return CompletableFuture.supplyAsync(() -> + users.parallelStream() + .filter(User::active) + .filter(user -> user.createdAt().isAfter(LocalDateTime.now().minusYears(1))) + .sorted(Comparator.comparing(User::username)) + .collect(Collectors.toList()) + ); + } +} + +// Main class for testing +public class Main { + private static final Logger logger = LoggerFactory.getLogger(Main.class); + + public static void main(String[] args) { + try { + // Initialize application context + ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class); + + // Get service bean + UserService userService = context.getBean(UserService.class); + + // Create test users + List users = Arrays.asList( + User.of("john_doe", "john@example.com"), + User.of("jane_smith", "jane@example.com"), + User.of("bob_wilson", "bob@example.com") + ); + + // Process users + List> futures = users.stream() + .map(user -> { + try { + return CompletableFuture.completedFuture(userService.createUser( + new CreateUserRequest(user.username(), user.email()) + )); + } catch (ValidationException e) { + logger.error("Failed to create user: {}", user.username(), e); + return CompletableFuture.failedFuture(e); + } + }) + .collect(Collectors.toList()); + + // Wait for all to complete + CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])) + .thenRun(() -> { + logger.info("All users created successfully"); + System.out.println("Application started successfully!"); + }) + .exceptionally(throwable -> { + logger.error("Failed to initialize users", throwable); + System.err.println("Application startup failed!"); + return null; + }); + + } catch (Exception e) { + logger.error("Application startup failed", e); + System.exit(1); + } + } +} \ No newline at end of file diff --git a/theme-test.md b/theme-test.md new file mode 100644 index 00000000..3863cc32 --- /dev/null +++ b/theme-test.md @@ -0,0 +1,669 @@ +# TextMate Grammar Token Examples + +This file contains examples of every major TextMate token style for theme testing. + +## Comments + + + +// Single line comment +/_ Multi-line comment _/ + +# Shell comment + +/_ JSDoc comment with @param and @return _/ + +## Strings + +"Double quoted string" +'Single quoted string' +`Backtick string` +"String with \"escaped\" quotes" +'String with \'escaped\' quotes' +`String with \`escaped\` backticks` + +## Template Literals + +`Simple template literal` +`Template with ${variable} interpolation` +`Template with ${function.call()} expression` +Multi-line template with ${nested.interpolation} + +## Numbers + +42 +-17 +3.14159 +-0.001 +1e10 +-2.5e-8 +0xFF +0o755 +0b1010 + +## Keywords + +if else elif for while do switch case default +function class extends implements import export +return break continue throw try catch finally +var let const static async await yield +new this super null undefined true false + +## Storage Types + +int float double string boolean char void +static final abstract private public protected +readonly volatile transient synchronized + +## Constants + +MAX_VALUE +DEFAULT_TIMEOUT +API_ENDPOINT +PI +E + +## Variables + +variableName +\_privateVariable +$specialVariable +camelCase +snake_case +PascalCase +kebab-case + +## Functions + +functionName() +method.call() +object.property() +array[index] +arrowFunction => expression + +## Operators + +- - - / % ++ -- + == === != !== > < >= <= + && || ! & | ^ ~ << >> >>> + = += -= \*= /= %= &= |= ^= <<= >>= >>>= + +## Punctuation + +, ; : . ... ( ) [ ] { } < > / \\ + +# @ $ % ^ & \* - \_ + = | ~ ` ? + +## Entities + +ClassName +InterfaceName +EnumName +TypeName +MethodName +PropertyName + +## Tags + +
    + +

    + +description + +## Attributes + +class="container" +id="main" +data-value="123" +disabled +required +readonly + +## CSS Selectors & Properties + +.container +#header +.button:hover +input[type="text"] +::before +::after + +color: #ffffff; +background: linear-gradient(45deg, #ff0000, #00ff00); +font-size: 16px; +margin: 0 auto; +padding: 10px 20px; + +## Regular Expressions + +/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/ +/\d{3}-\d{3}-\d{4}/g +/(https?:\/\/)?([\da-z\.-]+)\.([a-z\.]{2,6})/ + +## URLs & Paths + +https://example.com/path/to/resource +file:///Users/username/project +./relative/path +../parent/directory +/home/user/documents + +## JSON + +{ +"name": "example", +"version": "1.0.0", +"dependencies": { +"react": "^18.0.0", +"typescript": "^4.9.0" +}, +"scripts": { +"start": "node index.js", +"test": "jest" +} +} + +## XML/HTML + + + + + + + Document + + +

    + + + +## SQL + +SELECT u.id, u.name, u.email, COUNT(o.id) as order_count +FROM users u +LEFT JOIN orders o ON u.id = o.user_id +WHERE u.active = true +AND o.created_at >= '2023-01-01' +GROUP BY u.id, u.name, u.email +HAVING COUNT(o.id) > 5 +ORDER BY order_count DESC +LIMIT 10; + +## GraphQL + +query GetUserProfile($userId: ID!, $includePosts: Boolean!) { +user(id: $userId) { +id +name +email +avatar +createdAt +posts @include(if: $includePosts) { +id +title +content +publishedAt +comments(first: 10) { +edges { +node { +id +author +content +createdAt +} +} +} +} +} +} + +## Shell/Bash + +#!/bin/bash + +# Variables + +PROJECT*DIR="/home/user/projects" +BACKUP_DIR="$PROJECT_DIR/backups" +TIMESTAMP=$(date +"%Y%m%d*%H%M%S") + +# Functions + +create*backup() { +local source_dir=$1 + local backup_file="$BACKUP_DIR/backup*$TIMESTAMP.tar.gz" + + echo "Creating backup of $source_dir..." + tar -czf "$backup_file" "$source_dir" + echo "Backup created: $backup_file" + +} + +# Conditional logic + +if [ -d "$PROJECT_DIR" ]; then +create_backup "$PROJECT_DIR" +else +echo "Project directory not found: $PROJECT_DIR" +exit 1 +fi + +## Python + +import os +import sys +from typing import List, Dict, Optional +import requests +from dataclasses import dataclass + +@dataclass +class User: +id: int +name: str +email: Optional[str] = None +active: bool = True + + def __post_init__(self): + if not self.name.strip(): + raise ValueError("Name cannot be empty") + +class UserService: +def **init**(self, api_url: str): +self.api_url = api_url +self.session = requests.Session() + + async def get_user(self, user_id: int) -> Optional[User]: + """Fetch user data from API.""" + try: + response = await self.session.get(f"{self.api_url}/users/{user_id}") + response.raise_for_status() + data = response.json() + return User(**data) + except requests.RequestException as e: + print(f"Error fetching user {user_id}: {e}") + return None + +## Rust + +use std::collections::HashMap; +use std::fs::File; +use std::io::{self, Read}; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct User { +pub id: u64, +pub name: String, +pub email: Option, #[serde(default)] +pub active: bool, +pub created_at: chrono::DateTime, +} + +impl User { +pub fn new(id: u64, name: String, email: Option) -> Self { +Self { +id, +name, +email, +active: true, +created_at: chrono::Utc::now(), +} +} + + pub fn display_name(&self) -> String { + match &self.email { + Some(email) => format!("{} <{}>", self.name, email), + None => self.name.clone(), + } + } + +} + +pub struct UserService { +api_url: String, +client: reqwest::Client, +} + +impl UserService { +pub fn new(api_url: String) -> Self { +Self { +api_url, +client: reqwest::Client::new(), +} +} + + pub async fn get_user(&self, user_id: u64) -> Result> { + let url = format!("{}/users/{}", self.api_url, user_id); + let response = self.client.get(&url).send().await?; + let user: User = response.json().await?; + Ok(user) + } + +} + +## Go + +package main + +import ( +"context" +"encoding/json" +"fmt" +"log" +"net/http" +"time" +"github.com/gorilla/mux" +) + +type User struct { +ID int64 `json:"id"` +Name string `json:"name"` +Email \*string `json:"email,omitempty"` +Active bool `json:"active"` +CreatedAt time.Time `json:"created_at"` +} + +type UserService struct { +re UserRepository +} + +func NewUserService(repo UserRepository) \*UserService { +return &UserService{repo: repo} +} + +func (s *UserService) GetUser(ctx context.Context, id int64) (*User, error) { +user, err := s.repo.FindByID(ctx, id) +if err != nil { +return nil, fmt.Errorf("failed to get user %d: %w", id, err) +} +return user, nil +} + +func (s *UserService) CreateUser(ctx context.Context, req *CreateUserRequest) (\*User, error) { +user := &User{ +Name: req.Name, +Email: req.Email, +Active: true, +CreatedAt: time.Now(), +} +if err := s.repo.Create(ctx, user); err != nil { +return nil, fmt.Errorf("failed to create user: %w", err) +} +return user, nil +} + +## YAML + +apiVersion: apps/v1 +kind: Deployment +metadata: +name: web-app +namespace: production +labels: +app: web-app +version: v1.2.3 +spec: +replicas: 3 +selector: +matchLabels: +app: web-app +template: +metadata: +labels: +app: web-app +tier: frontend +spec: +containers: - name: web-app +image: nginx:1.21-alpine +ports: - containerPort: 80 +protocol: TCP +env: - name: NODE_ENV +value: "production" - name: API_URL +valueFrom: +secretKeyRef: +name: app-secrets +key: api-url +resources: +requests: +memory: "64Mi" +cpu: "250m" +limits: +memory: "128Mi" +cpu: "500m" +livenessProbe: +httpGet: +path: /health +port: 80 +initialDelaySeconds: 30 +periodSeconds: 10 +readinessProbe: +httpGet: +path: /ready +port: 80 +initialDelaySeconds: 5 +periodSeconds: 5 + +## TOML + +[project] +name = "example-app" +version = "1.0.0" +description = "An example application" +authors = ["John Doe "] +license = "MIT" +readme = "README.md" +homepage = "https://example.com" +repository = "https://github.com/johndoe/example-app" +keywords = ["web", "api", "rust"] +categories = ["web-programming"] +edition = "2021" + +[dependencies] +tokio = { version = "1.0", features = ["full"] } +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" +reqwest = { version = "0.11", features = ["json"] } +chrono = { version = "0.4", features = ["serde"] } +log = "0.4" +env_logger = "0.10" + +[dev-dependencies] +tokio-test = "0.4" +mockito = "1.0" + +[[bin]] +name = "server" +path = "src/main.rs" + +[[bin]] +name = "client" +path = "src/client.rs" + +## Dockerfile + +FROM node:18-alpine AS base + +# Install dependencies only when needed + +FROM base AS deps + +# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed. + +RUN apk add --no-cache libc6-compat +WORKDIR /app + +# Install dependencies based on the preferred package manager + +COPY package.json yarn.lock* package-lock.json* pnpm-lock.yaml\* ./ +RUN \ + if [ -f yarn.lock ]; then yarn --frozen-lockfile; \ + elif [ -f package-lock.json ]; then npm ci; \ + elif [ -f pnpm-lock.yaml ]; then yarn global add pnpm && pnpm i --frozen-lockfile; \ + else echo "Lockfile not found." && exit 1; \ + fi + +# Rebuild the source code only when needed + +FROM base AS builder +WORKDIR /app +COPY --from=deps /app/node_modules ./node_modules +COPY . . + +# Next.js collects completely anonymous telemetry data about general usage. + +# Learn more here: https://nextjs.org/telemetry + +# Uncomment the following line in case you want to disable telemetry during the build. + +# ENV NEXT_TELEMETRY_DISABLED 1 + +RUN \ + if [ -f yarn.lock ]; then yarn run build; \ + elif [ -f package-lock.json ]; then npm run build; \ + elif [ -f pnpm-lock.yaml ]; then pnpm run build; \ + else echo "Lockfile not found." && exit 1; \ + fi + +# Production image, copy all the files and run next + +FROM base AS runner +WORKDIR /app + +ENV NODE_ENV production + +# Uncomment the following line in case you want to disable telemetry during runtime. + +# ENV NEXT_TELEMETRY_DISABLED 1 + +RUN addgroup --system --gid 1001 nodejs +RUN adduser --system --uid 1001 nextjs + +COPY --from=builder /app/public ./public + +# Set the correct permission for prerender cache + +RUN mkdir .next +RUN chown nextjs:nodejs .next + +# Automatically leverage output traces to reduce image size + +# https://nextjs.org/docs/advanced-features/output-file-tracing + +COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./ +COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static + +USER nextjs + +EXPOSE 3000 + +ENV PORT 3000 + +# set hostname to localhost + +ENV HOSTNAME "0.0.0.0" + +# server.js is created by next build from the standalone output + +# https://nextjs.org/docs/pages/api-reference/next-config-js/output + +CMD ["node", "server.js"] + +## Makefile + +.PHONY: help build test clean install dev lint format + +# Default target + +.DEFAULT_GOAL := help + +# Variables + +APP_NAME := myapp +VERSION := $(shell git describe --tags --always --dirty) +BUILD_DIR := ./build +DIST_DIR := ./dist +GO_FILES := $(shell find . -name '\*.go' -type f) + +help: ## Show this help message +@echo "Available targets:" +@grep -E '^[a-zA-Z_-]+:._?## ._$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.\*?## "}; {printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}' + +install: ## Install dependencies +go mod download +npm install + +build: ## Build the application +@echo "Building $(APP_NAME) version $(VERSION)..." + mkdir -p $(BUILD_DIR) + go build -ldflags "-X main.version=$(VERSION)" -o $(BUILD_DIR)/$(APP_NAME) ./cmd/main.go + +test: ## Run tests +go test -v ./... +npm test + +lint: ## Run linters +golangci-lint run +npx eslint . + +format: ## Format code +go fmt ./... +npx prettier --write . + +dev: ## Run in development mode +go run ./cmd/main.go --dev + +clean: ## Clean build artifacts +rm -rf $(BUILD_DIR) +rm -rf $(DIST_DIR) +go clean -cache + +docker-build: ## Build Docker image +docker build -t $(APP_NAME):$(VERSION) . +docker tag $(APP_NAME):$(VERSION) $(APP_NAME):latest + +docker-run: ## Run Docker container +docker run -p 8080:8080 $(APP_NAME):latest + +release: ## Create a new release +@echo "Creating release $(VERSION)" +git tag -a $(VERSION) -m "Release $(VERSION)" +git push origin $(VERSION) +goreleaser release --rm-dist + +## Git Diff + +diff --git a/src/components/UserProfile.tsx b/src/components/UserProfile.tsx +index 1234567..abcdefg 100644 +--- a/src/components/UserProfile.tsx ++++ b/src/components/UserProfile.tsx +@@ -10,7 +10,7 @@ interface User { +id: number +name: string +email?: string + +- createdAt: Date + +* readonly createdAt: Date + active: boolean + } + +@@ -25,8 +25,12 @@ const UserProfile: FC<{ user: User }> = ({ user }) => { +const [isEditing, setIsEditing] = useState(false) +const [formData, setFormData] = useState(user) + +- const handleSubmit = async (e: React.FormEvent) => { +- e.preventDefault() +- // Handle form submission +- } +- return ( + +*
    + +-
    +

    {user.name}

    +

    {user.email}

    +
    diff --git a/theme-test.tsx b/theme-test.tsx index 16559bf7..61837473 100644 --- a/theme-test.tsx +++ b/theme-test.tsx @@ -29,6 +29,8 @@ class Repository { } public find(id: number): T | undefined { + const x = undefined + type x = { foo: undefined } return this.items.find((item) => item.id === id) } @@ -66,6 +68,72 @@ const sql = ` AND created_at > '${new Date().toISOString()}' ` +// String source examples (CSS-in-JS, GraphQL, etc.) +const styledComponent = css` + .container { + display: flex; + justify-content: center; + align-items: center; + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + padding: 2rem; + border-radius: 8px; + box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); + + &:hover { + transform: translateY(-2px); + box-shadow: 0 8px 12px rgba(0, 0, 0, 0.15); + } + + .title { + font-size: 1.5rem; + font-weight: bold; + color: white; + margin-bottom: 1rem; + } + } +` + +const graphqlQuery = ` + query GetUserProfile($userId: ID!) { + user(id: $userId) { + id + name + email + avatar + createdAt + posts { + id + title + content + publishedAt + comments { + id + author + content + createdAt + } + } + } + } +` + +const htmlTemplate = ` +
    + ${user.name} + +
    + + +
    +
    +` + // Arrow functions const debounce = any>( func: T, From 89922a8598bf344ed24fb1b472307f383ef2b18a Mon Sep 17 00:00:00 2001 From: Adam <2363879+adamdotdevin@users.noreply.github.com> Date: Fri, 7 Nov 2025 12:56:07 -0600 Subject: [PATCH 118/218] fix(desktop): prompt input missing on new session --- packages/desktop/src/pages/session.tsx | 738 ++++++++++++------------- 1 file changed, 366 insertions(+), 372 deletions(-) diff --git a/packages/desktop/src/pages/session.tsx b/packages/desktop/src/pages/session.tsx index 3dcc24e6..b872c143 100644 --- a/packages/desktop/src/pages/session.tsx +++ b/packages/desktop/src/pages/session.tsx @@ -330,142 +330,39 @@ export default function Page() {
    - -
    New session
    -
    - -
    - {getDirectory(sync.data.path.directory)} - {getFilename(sync.data.path.directory)} -
    -
    -
    - -
    - Last modified  - - {DateTime.fromMillis(sync.data.project.time.created).toRelative()} - -
    -
    -
    - } +
    - {(_) => { - return ( -
    -
    -
    - - - -
    -
    - 1}> -
      - - {(message) => { - const assistantMessages = createMemo(() => { - if (!session.id) return [] - return sync.data.message[session.id]?.filter( - (m) => m.role === "assistant" && m.parentID == message.id, - ) as AssistantMessageType[] - }) - const error = createMemo(() => assistantMessages().find((m) => m?.error)?.error) - const working = createMemo(() => !message.summary?.body && !error()) - - const handleClick = () => session.messages.setActive(message.id) - - return ( -
    • - - - {message.summary?.title} -
    - } - > - - - -
  • - ) - }} - - - -
    +
    + + +
    + + + +
    +
    + 1}> +
      {(message) => { - const isActive = createMemo(() => session.messages.active()?.id === message.id) - const [titled, setTitled] = createSignal(!!message.summary?.title) const assistantMessages = createMemo(() => { if (!session.id) return [] return sync.data.message[session.id]?.filter( @@ -473,261 +370,358 @@ export default function Page() { ) as AssistantMessageType[] }) const error = createMemo(() => assistantMessages().find((m) => m?.error)?.error) - const [completed, setCompleted] = createSignal(!!message.summary?.body || !!error()) - const [detailsExpanded, setDetailsExpanded] = createSignal(false) - const parts = createMemo(() => sync.data.part[message.id]) - const hasToolPart = createMemo(() => - assistantMessages() - ?.flatMap((m) => sync.data.part[m.id]) - .some((p) => p?.type === "tool"), - ) const working = createMemo(() => !message.summary?.body && !error()) - // allowing time for the animations to finish - createEffect(() => { - const title = message.summary?.title - setTimeout(() => setTitled(!!title), 10_000) - }) - createEffect(() => { - const summary = message.summary?.body - const complete = !!summary || !!error() - setTimeout(() => setCompleted(complete), 1200) - }) + const handleClick = () => session.messages.setActive(message.id) return ( - -
      + + + {message.summary?.title} +
      + } > - {/* Title */} -
      -
      - - } - > -

      - {message.summary?.title} -

      -
      -
      + + +
      -
      + + ) }}
      -
    + + +
    + + {(message) => { + const isActive = createMemo(() => session.messages.active()?.id === message.id) + const [titled, setTitled] = createSignal(!!message.summary?.title) + const assistantMessages = createMemo(() => { + if (!session.id) return [] + return sync.data.message[session.id]?.filter( + (m) => m.role === "assistant" && m.parentID == message.id, + ) as AssistantMessageType[] + }) + const error = createMemo(() => assistantMessages().find((m) => m?.error)?.error) + const [completed, setCompleted] = createSignal(!!message.summary?.body || !!error()) + const [detailsExpanded, setDetailsExpanded] = createSignal(false) + const parts = createMemo(() => sync.data.part[message.id]) + const hasToolPart = createMemo(() => + assistantMessages() + ?.flatMap((m) => sync.data.part[m.id]) + .some((p) => p?.type === "tool"), + ) + const working = createMemo(() => !message.summary?.body && !error()) -
    - { - inputRef = el - }} - /> + // allowing time for the animations to finish + createEffect(() => { + const title = message.summary?.title + setTimeout(() => setTitled(!!title), 10_000) + }) + createEffect(() => { + const summary = message.summary?.body + const complete = !!summary || !!error() + setTimeout(() => setCompleted(complete), 1200) + }) + + return ( + +
    + {/* Title */} +
    +
    + + } + > +

    + {message.summary?.title} +

    +
    +
    +
    +
    + +
    + {/* Summary */} + +
    +
    +

    + + Summary + Response + +

    + + {(summary) => ( + *]:fade-up-text": !message.summary?.diffs?.length, + }} + text={summary()} + /> + )} + +
    + + + {(diff) => ( + + + +
    +
    + +
    + + + {getDirectory(diff.file)}‎ + + + + {getFilename(diff.file)} + +
    +
    +
    + + +
    +
    +
    +
    + + + +
    + )} +
    +
    +
    +
    + + + {error()?.data?.message as string} + + + {/* Response */} +
    + + + + + + + +
    +
    + + Hide details + Show details + +
    + +
    +
    + +
    + + {(assistantMessage) => { + const parts = createMemo(() => sync.data.part[assistantMessage.id]) + return + }} + + + + {error()?.data?.message as string} + + +
    +
    +
    +
    +
    +
    +
    +
    + ) + }} + +
    +
    +
    + +
    +
    New session
    +
    + +
    + {getDirectory(sync.data.path.directory)} + {getFilename(sync.data.path.directory)} +
    +
    +
    + +
    + Last modified  + + {DateTime.fromMillis(sync.data.project.time.created).toRelative()} +
    - -
    -
    -
    - - - - - { - local.layout.review.tab() - session.layout.setActiveTab("review") + + +
    + { + inputRef = el + }} + /> +
    +
    + +
    +
    +
    + + + + + { + local.layout.review.tab() + session.layout.setActiveTab("review") + }} + /> + +
    +
    +
    All changes
    +
    + + + {(diff) => ( + + + +
    +
    + +
    + + + {getDirectory(diff.file)}‎ + + + {getFilename(diff.file)} +
    +
    +
    + + +
    +
    +
    +
    + + - -
    -
    -
    All changes
    -
    - - - {(diff) => ( - - - -
    -
    - -
    - - - {getDirectory(diff.file)}‎ - - - {getFilename(diff.file)} -
    -
    -
    - - -
    -
    -
    -
    - - - -
    - )} -
    -
    -
    -
    - + + + )} + +
    - ) - }} -
    +
    + +
    From 7adbc3ad443af942b400923b66119436589c676c Mon Sep 17 00:00:00 2001 From: Adam <2363879+adamdotdevin@users.noreply.github.com> Date: Fri, 7 Nov 2025 13:14:57 -0600 Subject: [PATCH 119/218] fix(desktop): code tab padding --- packages/desktop/src/pages/session.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/desktop/src/pages/session.tsx b/packages/desktop/src/pages/session.tsx index b872c143..1c92941d 100644 --- a/packages/desktop/src/pages/session.tsx +++ b/packages/desktop/src/pages/session.tsx @@ -791,14 +791,14 @@ export default function Page() { }, ) return ( - + {(f) => ( )} From 7f51b181d4b77326c5e7f6961552036ae2d56234 Mon Sep 17 00:00:00 2001 From: Adam <2363879+adamdotdevin@users.noreply.github.com> Date: Fri, 7 Nov 2025 13:30:07 -0600 Subject: [PATCH 120/218] chore(desktop): cleanup shiki theme stuff --- packages/desktop/src/components/theme.json | 558 --------------- packages/desktop/src/index.tsx | 36 +- packages/ui/src/components/code.tsx | 3 +- packages/ui/src/components/diff.tsx | 763 ++++++++++----------- packages/ui/src/components/index.ts | 1 - packages/ui/src/context/marked.tsx | 8 +- packages/ui/src/context/shiki.tsx | 577 ---------------- 7 files changed, 394 insertions(+), 1552 deletions(-) delete mode 100644 packages/desktop/src/components/theme.json delete mode 100644 packages/ui/src/context/shiki.tsx diff --git a/packages/desktop/src/components/theme.json b/packages/desktop/src/components/theme.json deleted file mode 100644 index 36a4d020..00000000 --- a/packages/desktop/src/components/theme.json +++ /dev/null @@ -1,558 +0,0 @@ -{ - "colors": { - "actionBar.toggledBackground": "var(--surface-raised-base)", - "activityBarBadge.background": "var(--surface-brand-base)", - "checkbox.border": "var(--border-base)", - "editor.background": "transparent", - "editor.foreground": "var(--text-base)", - "editor.inactiveSelectionBackground": "var(--surface-raised-base)", - "editor.selectionHighlightBackground": "var(--border-active)", - "editorIndentGuide.activeBackground1": "var(--border-weak-base)", - "editorIndentGuide.background1": "var(--border-weak-base)", - "input.placeholderForeground": "var(--text-weak)", - "list.activeSelectionIconForeground": "var(--text-base)", - "list.dropBackground": "var(--surface-raised-base)", - "menu.background": "var(--surface-base)", - "menu.border": "var(--border-base)", - "menu.foreground": "var(--text-base)", - "menu.selectionBackground": "var(--surface-interactive-base)", - "menu.separatorBackground": "var(--border-base)", - "ports.iconRunningProcessForeground": "var(--icon-success-base)", - "sideBarSectionHeader.background": "transparent", - "sideBarSectionHeader.border": "var(--border-weak-base)", - "sideBarTitle.foreground": "var(--text-weak)", - "statusBarItem.remoteBackground": "var(--surface-success-base)", - "statusBarItem.remoteForeground": "var(--text-base)", - "tab.lastPinnedBorder": "var(--border-weak-base)", - "tab.selectedBackground": "var(--surface-raised-base)", - "tab.selectedForeground": "var(--text-weak)", - "terminal.inactiveSelectionBackground": "var(--surface-raised-base)", - "widget.border": "var(--border-base)" - }, - "displayName": "opencode", - "name": "opencode", - "semanticHighlighting": true, - "semanticTokenColors": { - "customLiteral": "var(--syntax-function)", - "newOperator": "var(--syntax-operator)", - "numberLiteral": "var(--syntax-number)", - "stringLiteral": "var(--syntax-string)" - }, - "tokenColors": [ - { - "scope": [ - "meta.embedded", - "source.groovy.embedded", - "string meta.image.inline.markdown", - "variable.legacy.builtin.python" - ], - "settings": { - "foreground": "var(--text-base)" - } - }, - { - "scope": "emphasis", - "settings": { - "fontStyle": "italic" - } - }, - { - "scope": "strong", - "settings": { - "fontStyle": "bold" - } - }, - { - "scope": "header", - "settings": { - "foreground": "var(--markdown-heading)" - } - }, - { - "scope": "comment", - "settings": { - "foreground": "var(--syntax-comment)" - } - }, - { - "scope": "constant.language", - "settings": { - "foreground": "var(--syntax-keyword)" - } - }, - { - "scope": [ - "constant.numeric", - "variable.other.enummember", - "keyword.operator.plus.exponent", - "keyword.operator.minus.exponent" - ], - "settings": { - "foreground": "var(--syntax-number)" - } - }, - { - "scope": "constant.regexp", - "settings": { - "foreground": "var(--syntax-operator)" - } - }, - { - "scope": "entity.name.tag", - "settings": { - "foreground": "var(--syntax-keyword)" - } - }, - { - "scope": ["entity.name.tag.css", "entity.name.tag.less"], - "settings": { - "foreground": "var(--syntax-operator)" - } - }, - { - "scope": "entity.other.attribute-name", - "settings": { - "foreground": "var(--syntax-variable)" - } - }, - { - "scope": [ - "entity.other.attribute-name.class.css", - "source.css entity.other.attribute-name.class", - "entity.other.attribute-name.id.css", - "entity.other.attribute-name.parent-selector.css", - "entity.other.attribute-name.parent.less", - "source.css entity.other.attribute-name.pseudo-class", - "entity.other.attribute-name.pseudo-element.css", - "source.css.less entity.other.attribute-name.id", - "entity.other.attribute-name.scss" - ], - "settings": { - "foreground": "var(--syntax-operator)" - } - }, - { - "scope": "invalid", - "settings": { - "foreground": "var(--syntax-critical)" - } - }, - { - "scope": "markup.underline", - "settings": { - "fontStyle": "underline" - } - }, - { - "scope": "markup.bold", - "settings": { - "fontStyle": "bold", - "foreground": "var(--markdown-strong)" - } - }, - { - "scope": "markup.heading", - "settings": { - "fontStyle": "bold", - "foreground": "var(--theme-markdown-heading)" - } - }, - { - "scope": "markup.italic", - "settings": { - "fontStyle": "italic" - } - }, - { - "scope": "markup.strikethrough", - "settings": { - "fontStyle": "strikethrough" - } - }, - { - "scope": "markup.inserted", - "settings": { - "foreground": "var(--text-diff-add-base)" - } - }, - { - "scope": "markup.deleted", - "settings": { - "foreground": "var(--text-diff-delete-base)" - } - }, - { - "scope": "markup.changed", - "settings": { - "foreground": "var(--text-base)" - } - }, - { - "scope": "punctuation.definition.quote.begin.markdown", - "settings": { - "foreground": "var(--markdown-block-quote)" - } - }, - { - "scope": "punctuation.definition.list.begin.markdown", - "settings": { - "foreground": "var(--markdown-list-enumeration)" - } - }, - { - "scope": "markup.inline.raw", - "settings": { - "foreground": "var(--markdown-code)" - } - }, - { - "scope": "punctuation.definition.tag", - "settings": { - "foreground": "var(--syntax-punctuation)" - } - }, - { - "scope": ["meta.preprocessor", "entity.name.function.preprocessor"], - "settings": { - "foreground": "var(--syntax-keyword)" - } - }, - { - "scope": "meta.preprocessor.string", - "settings": { - "foreground": "var(--syntax-string)" - } - }, - { - "scope": "meta.preprocessor.numeric", - "settings": { - "foreground": "var(--syntax-number)" - } - }, - { - "scope": "meta.structure.dictionary.key.python", - "settings": { - "foreground": "var(--syntax-variable)" - } - }, - { - "scope": "meta.diff.header", - "settings": { - "foreground": "var(--text-weak)" - } - }, - { - "scope": "storage", - "settings": { - "foreground": "var(--syntax-keyword)" - } - }, - { - "scope": "storage.type", - "settings": { - "foreground": "var(--syntax-keyword)" - } - }, - { - "scope": ["storage.modifier", "keyword.operator.noexcept"], - "settings": { - "foreground": "var(--syntax-keyword)" - } - }, - { - "scope": ["string", "meta.embedded.assembly"], - "settings": { - "foreground": "var(--syntax-string)" - } - }, - { - "scope": "string.tag", - "settings": { - "foreground": "var(--syntax-string)" - } - }, - { - "scope": "string.value", - "settings": { - "foreground": "var(--syntax-string)" - } - }, - { - "scope": "string.regexp", - "settings": { - "foreground": "var(--syntax-operator)" - } - }, - { - "scope": [ - "punctuation.definition.template-expression.begin", - "punctuation.definition.template-expression.end", - "punctuation.section.embedded" - ], - "settings": { - "foreground": "var(--syntax-keyword)" - } - }, - { - "scope": ["meta.template.expression"], - "settings": { - "foreground": "var(--text-base)" - } - }, - { - "scope": [ - "support.type.vendored.property-name", - "support.type.property-name", - "source.css variable", - "source.coffee.embedded" - ], - "settings": { - "foreground": "var(--syntax-variable)" - } - }, - { - "scope": "keyword", - "settings": { - "foreground": "var(--syntax-keyword)" - } - }, - { - "scope": "keyword.control", - "settings": { - "foreground": "var(--syntax-keyword)" - } - }, - { - "scope": "keyword.operator", - "settings": { - "foreground": "var(--syntax-operator)" - } - }, - { - "scope": [ - "keyword.operator.new", - "keyword.operator.expression", - "keyword.operator.cast", - "keyword.operator.sizeof", - "keyword.operator.alignof", - "keyword.operator.typeid", - "keyword.operator.alignas", - "keyword.operator.instanceof", - "keyword.operator.logical.python", - "keyword.operator.wordlike" - ], - "settings": { - "foreground": "var(--syntax-keyword)" - } - }, - { - "scope": "keyword.other.unit", - "settings": { - "foreground": "var(--syntax-number)" - } - }, - { - "scope": ["punctuation.section.embedded.begin.php", "punctuation.section.embedded.end.php"], - "settings": { - "foreground": "var(--syntax-keyword)" - } - }, - { - "scope": "support.function.git-rebase", - "settings": { - "foreground": "var(--syntax-variable)" - } - }, - { - "scope": "constant.sha.git-rebase", - "settings": { - "foreground": "var(--syntax-number)" - } - }, - { - "scope": ["storage.modifier.import.java", "variable.language.wildcard.java", "storage.modifier.package.java"], - "settings": { - "foreground": "var(--text-base)" - } - }, - { - "scope": "variable.language", - "settings": { - "foreground": "var(--syntax-keyword)" - } - }, - { - "scope": [ - "entity.name.function", - "support.function", - "support.constant.handlebars", - "source.powershell variable.other.member", - "entity.name.operator.custom-literal" - ], - "settings": { - "foreground": "var(--syntax-function)" - } - }, - { - "scope": [ - "support.class", - "support.type", - "entity.name.type", - "entity.name.namespace", - "entity.other.attribute", - "entity.name.scope-resolution", - "entity.name.class", - "storage.type.numeric.go", - "storage.type.byte.go", - "storage.type.boolean.go", - "storage.type.string.go", - "storage.type.uintptr.go", - "storage.type.error.go", - "storage.type.rune.go", - "storage.type.cs", - "storage.type.generic.cs", - "storage.type.modifier.cs", - "storage.type.variable.cs", - "storage.type.annotation.java", - "storage.type.generic.java", - "storage.type.java", - "storage.type.object.array.java", - "storage.type.primitive.array.java", - "storage.type.primitive.java", - "storage.type.token.java", - "storage.type.groovy", - "storage.type.annotation.groovy", - "storage.type.parameters.groovy", - "storage.type.generic.groovy", - "storage.type.object.array.groovy", - "storage.type.primitive.array.groovy", - "storage.type.primitive.groovy" - ], - "settings": { - "foreground": "var(--syntax-type)" - } - }, - { - "scope": [ - "meta.type.cast.expr", - "meta.type.new.expr", - "support.constant.math", - "support.constant.dom", - "support.constant.json", - "entity.other.inherited-class", - "punctuation.separator.namespace.ruby" - ], - "settings": { - "foreground": "var(--syntax-type)" - } - }, - { - "scope": [ - "keyword.control", - "source.cpp keyword.operator.new", - "keyword.operator.delete", - "keyword.other.using", - "keyword.other.directive.using", - "keyword.other.operator", - "entity.name.operator" - ], - "settings": { - "foreground": "var(--syntax-operator)" - } - }, - { - "scope": [ - "variable", - "meta.definition.variable.name", - "support.variable", - "entity.name.variable", - "constant.other.placeholder" - ], - "settings": { - "foreground": "var(--syntax-variable)" - } - }, - { - "scope": ["variable.other.constant", "variable.other.enummember"], - "settings": { - "foreground": "var(--syntax-variable)" - } - }, - { - "scope": ["meta.object-literal.key"], - "settings": { - "foreground": "var(--syntax-variable)" - } - }, - { - "scope": [ - "support.constant.property-value", - "support.constant.font-name", - "support.constant.media-type", - "support.constant.media", - "constant.other.color.rgb-value", - "constant.other.rgb-value", - "support.constant.color" - ], - "settings": { - "foreground": "var(--syntax-string)" - } - }, - { - "scope": [ - "punctuation.definition.group.regexp", - "punctuation.definition.group.assertion.regexp", - "punctuation.definition.character-class.regexp", - "punctuation.character.set.begin.regexp", - "punctuation.character.set.end.regexp", - "keyword.operator.negation.regexp", - "support.other.parenthesis.regexp" - ], - "settings": { - "foreground": "var(--syntax-string)" - } - }, - { - "scope": [ - "constant.character.character-class.regexp", - "constant.other.character-class.set.regexp", - "constant.other.character-class.regexp", - "constant.character.set.regexp" - ], - "settings": { - "foreground": "var(--syntax-operator)" - } - }, - { - "scope": ["keyword.operator.or.regexp", "keyword.control.anchor.regexp"], - "settings": { - "foreground": "var(--syntax-operator)" - } - }, - { - "scope": "keyword.operator.quantifier.regexp", - "settings": { - "foreground": "var(--syntax-operator)" - } - }, - { - "scope": ["constant.character", "constant.other.option"], - "settings": { - "foreground": "var(--syntax-keyword)" - } - }, - { - "scope": "constant.character.escape", - "settings": { - "foreground": "var(--syntax-operator)" - } - }, - { - "scope": "entity.name.label", - "settings": { - "foreground": "var(--text-weak)" - } - } - ], - "type": "dark" -} diff --git a/packages/desktop/src/index.tsx b/packages/desktop/src/index.tsx index 9d402138..63d96ae8 100644 --- a/packages/desktop/src/index.tsx +++ b/packages/desktop/src/index.tsx @@ -3,7 +3,7 @@ import "@/index.css" import { render } from "solid-js/web" import { Router, Route } from "@solidjs/router" import { MetaProvider } from "@solidjs/meta" -import { Fonts, ShikiProvider, MarkedProvider } from "@opencode-ai/ui" +import { Fonts, MarkedProvider } from "@opencode-ai/ui" import { SDKProvider } from "./context/sdk" import { SyncProvider } from "./context/sync" import { LocalProvider } from "./context/local" @@ -29,24 +29,22 @@ if (import.meta.env.DEV && !(root instanceof HTMLElement)) { render( () => ( - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + ), root!, ) diff --git a/packages/ui/src/components/code.tsx b/packages/ui/src/components/code.tsx index 6b95e665..06541fe4 100644 --- a/packages/ui/src/components/code.tsx +++ b/packages/ui/src/components/code.tsx @@ -14,8 +14,7 @@ export function Code(props: CodeProps) { createEffect(() => { const instance = new File({ - theme: { dark: "oc-1-dark", light: "oc-1-light" }, - // theme: { dark: "pierre-dark", light: "pierre-light" }, + theme: "OpenCode", overflow: "wrap", // or 'scroll' themeType: "system", // 'system', 'light', or 'dark' disableFileHeader: true, diff --git a/packages/ui/src/components/diff.tsx b/packages/ui/src/components/diff.tsx index 09085b44..21ff980c 100644 --- a/packages/ui/src/components/diff.tsx +++ b/packages/ui/src/components/diff.tsx @@ -55,9 +55,7 @@ export function Diff(props: DiffProps) { // annotations and a container element to hold the diff createEffect(() => { const instance = new FileDiff({ - // theme: "pierre-light", - theme: { dark: "oc-1-dark", light: "oc-1-light" }, - // theme: { dark: "pierre-dark", light: "pierre-light" }, + theme: "OpenCode", // When using the 'themes' prop, 'themeType' allows you to force 'dark' // or 'light' theme, or inherit from the OS ('system') theme. themeType: "system", @@ -181,394 +179,377 @@ export function Diff(props: DiffProps) { ) } -const colors = { - "editor.background": "transparent", - "editor.foreground": "var(--text-base)", - "gitDecoration.addedResourceForeground": "var(--syntax-diff-add)", - "gitDecoration.deletedResourceForeground": "var(--syntax-diff-delete)", - // "gitDecoration.conflictingResourceForeground": "#ffca00", - // "gitDecoration.modifiedResourceForeground": "#1a76d4", - // "gitDecoration.untrackedResourceForeground": "#00cab1", - // "gitDecoration.ignoredResourceForeground": "#84848A", - // "terminal.titleForeground": "#adadb1", - // "terminal.titleInactiveForeground": "#84848A", - // "terminal.background": "#141415", - // "terminal.foreground": "#adadb1", - // "terminal.ansiBlack": "#141415", - // "terminal.ansiRed": "#ff2e3f", - // "terminal.ansiGreen": "#0dbe4e", - // "terminal.ansiYellow": "#ffca00", - // "terminal.ansiBlue": "#008cff", - // "terminal.ansiMagenta": "#c635e4", - // "terminal.ansiCyan": "#08c0ef", - // "terminal.ansiWhite": "#c6c6c8", - // "terminal.ansiBrightBlack": "#141415", - // "terminal.ansiBrightRed": "#ff2e3f", - // "terminal.ansiBrightGreen": "#0dbe4e", - // "terminal.ansiBrightYellow": "#ffca00", - // "terminal.ansiBrightBlue": "#008cff", - // "terminal.ansiBrightMagenta": "#c635e4", - // "terminal.ansiBrightCyan": "#08c0ef", - // "terminal.ansiBrightWhite": "#c6c6c8", -} - -const tokenColors = [ - { - scope: ["comment", "punctuation.definition.comment", "string.comment"], - settings: { - foreground: "var(--syntax-comment)", - }, - }, - { - scope: ["entity.other.attribute-name"], - settings: { - foreground: "var(--syntax-property)", // maybe attribute - }, - }, - { - scope: [ - "constant", - "entity.name.constant", - "variable.other.constant", - "variable.language", - "entity", - ], - settings: { - foreground: "var(--syntax-constant)", - }, - }, - { - scope: ["entity.name", "meta.export.default", "meta.definition.variable"], - settings: { - foreground: "var(--syntax-type)", - }, - }, - { - scope: [ - "variable.parameter.function", - "meta.jsx.children", - "meta.block", - "meta.tag.attributes", - "entity.name.constant", - "meta.object.member", - "meta.embedded.expression", - "meta.template.expression", - "string.other.begin.yaml", - "string.other.end.yaml", - ], - settings: { - foreground: "var(--syntax-punctuation)", - }, - }, - { - scope: ["entity.name.function", "support.type.primitive"], - settings: { - foreground: "var(--syntax-primitive)", - }, - }, - { - scope: ["support.class.component"], - settings: { - foreground: "var(--syntax-type)", - }, - }, - { - scope: "keyword", - settings: { - foreground: "var(--syntax-keyword)", - }, - }, - { - scope: [ - "keyword.operator", - "storage.type.function.arrow", - "punctuation.separator.key-value.css", - "entity.name.tag.yaml", - "punctuation.separator.key-value.mapping.yaml", - ], - settings: { - foreground: "var(--syntax-operator)", - }, - }, - { - scope: ["storage", "storage.type"], - settings: { - foreground: "var(--syntax-keyword)", - }, - }, - { - scope: ["storage.modifier.package", "storage.modifier.import", "storage.type.java"], - settings: { - foreground: "var(--syntax-primitive)", - }, - }, - { - scope: [ - "string", - "punctuation.definition.string", - "string punctuation.section.embedded source", - "entity.name.tag", - ], - settings: { - foreground: "var(--syntax-string)", - }, - }, - { - scope: "support", - settings: { - foreground: "var(--syntax-primitive)", - }, - }, - { - scope: [ - "support.type.object.module", - "variable.other.object", - "support.type.property-name.css", - ], - settings: { - foreground: "var(--syntax-object)", - }, - }, - { - scope: "meta.property-name", - settings: { - foreground: "var(--syntax-property)", - }, - }, - { - scope: "variable", - settings: { - foreground: "var(--syntax-variable)", - }, - }, - { - scope: "variable.other", - settings: { - foreground: "var(--syntax-variable)", - }, - }, - { - scope: [ - "invalid.broken", - "invalid.illegal", - "invalid.unimplemented", - "invalid.deprecated", - "message.error", - "markup.deleted", - "meta.diff.header.from-file", - "punctuation.definition.deleted", - "brackethighlighter.unmatched", - "token.error-token", - ], - settings: { - foreground: "var(--syntax-critical)", - }, - }, - { - scope: "carriage-return", - settings: { - foreground: "var(--syntax-keyword)", - }, - }, - { - scope: "string source", - settings: { - foreground: "var(--syntax-variable)", - }, - }, - { - scope: "string variable", - settings: { - foreground: "var(--syntax-constant)", - }, - }, - { - scope: [ - "source.regexp", - "string.regexp", - "string.regexp.character-class", - "string.regexp constant.character.escape", - "string.regexp source.ruby.embedded", - "string.regexp string.regexp.arbitrary-repitition", - "string.regexp constant.character.escape", - ], - settings: { - foreground: "var(--syntax-regexp)", - }, - }, - { - scope: "support.constant", - settings: { - foreground: "var(--syntax-primitive)", - }, - }, - { - scope: "support.variable", - settings: { - foreground: "var(--syntax-variable)", - }, - }, - { - scope: "meta.module-reference", - settings: { - foreground: "var(--syntax-info)", - }, - }, - { - scope: "punctuation.definition.list.begin.markdown", - settings: { - foreground: "var(--syntax-punctuation)", - }, - }, - { - scope: ["markup.heading", "markup.heading entity.name"], - settings: { - fontStyle: "bold", - foreground: "var(--syntax-info)", - }, - }, - { - scope: "markup.quote", - settings: { - foreground: "var(--syntax-info)", - }, - }, - { - scope: "markup.italic", - settings: { - fontStyle: "italic", - // foreground: "", - }, - }, - { - scope: "markup.bold", - settings: { - fontStyle: "bold", - foreground: "var(--text-strong)", - }, - }, - { - scope: [ - "markup.raw", - "markup.inserted", - "meta.diff.header.to-file", - "punctuation.definition.inserted", - "markup.changed", - "punctuation.definition.changed", - "markup.ignored", - "markup.untracked", - ], - settings: { - foreground: "var(--text-base)", - }, - }, - { - scope: "meta.diff.range", - settings: { - fontStyle: "bold", - foreground: "var(--syntax-unknown)", - }, - }, - { - scope: "meta.diff.header", - settings: { - foreground: "var(--syntax-unknown)", - }, - }, - { - scope: "meta.separator", - settings: { - fontStyle: "bold", - foreground: "var(--syntax-unknown)", - }, - }, - { - scope: "meta.output", - settings: { - foreground: "var(--syntax-unknown)", - }, - }, - { - scope: "meta.export.default", - settings: { - foreground: "var(--syntax-unknown)", - }, - }, - { - scope: [ - "brackethighlighter.tag", - "brackethighlighter.curly", - "brackethighlighter.round", - "brackethighlighter.square", - "brackethighlighter.angle", - "brackethighlighter.quote", - ], - settings: { - foreground: "var(--syntax-unknown)", - }, - }, - { - scope: ["constant.other.reference.link", "string.other.link"], - settings: { - fontStyle: "underline", - foreground: "var(--syntax-unknown)", - }, - }, - { - scope: "token.info-token", - settings: { - foreground: "var(--syntax-info)", - }, - }, - { - scope: "token.warn-token", - settings: { - foreground: "var(--syntax-warning)", - }, - }, - { - scope: "token.debug-token", - settings: { - foreground: "var(--syntax-info)", - }, - }, -] - -const semanticTokenColors = { - comment: "var(--syntax-comment)", - string: "var(--syntax-string)", - number: "var(--syntax-constant)", - regexp: "var(--syntax-regexp)", - keyword: "var(--syntax-keyword)", - variable: "var(--syntax-variable)", - parameter: "var(--syntax-variable)", - property: "var(--syntax-property)", - function: "var(--syntax-primitive)", - method: "var(--syntax-primitive)", - type: "var(--syntax-type)", - class: "var(--syntax-type)", - namespace: "var(--syntax-type)", - enumMember: "var(--syntax-primitive)", - "variable.constant": "var(--syntax-constant)", - "variable.defaultLibrary": "var(--syntax-unknown)", -} - -registerCustomTheme("oc-1-light", () => { +registerCustomTheme("OpenCode", () => { return Promise.resolve({ - type: "light", - name: "oc-1-light", - colors, - tokenColors, - semanticTokenColors, - } as unknown as ThemeRegistrationResolved) -}) - -registerCustomTheme("oc-1-dark", () => { - return Promise.resolve({ - name: "oc-1-dark", - type: "dark", - colors, - tokenColors, - semanticTokenColors, + name: "OpenCode", + colors: { + "editor.background": "transparent", + "editor.foreground": "var(--text-base)", + "gitDecoration.addedResourceForeground": "var(--syntax-diff-add)", + "gitDecoration.deletedResourceForeground": "var(--syntax-diff-delete)", + // "gitDecoration.conflictingResourceForeground": "#ffca00", + // "gitDecoration.modifiedResourceForeground": "#1a76d4", + // "gitDecoration.untrackedResourceForeground": "#00cab1", + // "gitDecoration.ignoredResourceForeground": "#84848A", + // "terminal.titleForeground": "#adadb1", + // "terminal.titleInactiveForeground": "#84848A", + // "terminal.background": "#141415", + // "terminal.foreground": "#adadb1", + // "terminal.ansiBlack": "#141415", + // "terminal.ansiRed": "#ff2e3f", + // "terminal.ansiGreen": "#0dbe4e", + // "terminal.ansiYellow": "#ffca00", + // "terminal.ansiBlue": "#008cff", + // "terminal.ansiMagenta": "#c635e4", + // "terminal.ansiCyan": "#08c0ef", + // "terminal.ansiWhite": "#c6c6c8", + // "terminal.ansiBrightBlack": "#141415", + // "terminal.ansiBrightRed": "#ff2e3f", + // "terminal.ansiBrightGreen": "#0dbe4e", + // "terminal.ansiBrightYellow": "#ffca00", + // "terminal.ansiBrightBlue": "#008cff", + // "terminal.ansiBrightMagenta": "#c635e4", + // "terminal.ansiBrightCyan": "#08c0ef", + // "terminal.ansiBrightWhite": "#c6c6c8", + }, + tokenColors: [ + { + scope: ["comment", "punctuation.definition.comment", "string.comment"], + settings: { + foreground: "var(--syntax-comment)", + }, + }, + { + scope: ["entity.other.attribute-name"], + settings: { + foreground: "var(--syntax-property)", // maybe attribute + }, + }, + { + scope: [ + "constant", + "entity.name.constant", + "variable.other.constant", + "variable.language", + "entity", + ], + settings: { + foreground: "var(--syntax-constant)", + }, + }, + { + scope: ["entity.name", "meta.export.default", "meta.definition.variable"], + settings: { + foreground: "var(--syntax-type)", + }, + }, + { + scope: [ + "variable.parameter.function", + "meta.jsx.children", + "meta.block", + "meta.tag.attributes", + "entity.name.constant", + "meta.object.member", + "meta.embedded.expression", + "meta.template.expression", + "string.other.begin.yaml", + "string.other.end.yaml", + ], + settings: { + foreground: "var(--syntax-punctuation)", + }, + }, + { + scope: ["entity.name.function", "support.type.primitive"], + settings: { + foreground: "var(--syntax-primitive)", + }, + }, + { + scope: ["support.class.component"], + settings: { + foreground: "var(--syntax-type)", + }, + }, + { + scope: "keyword", + settings: { + foreground: "var(--syntax-keyword)", + }, + }, + { + scope: [ + "keyword.operator", + "storage.type.function.arrow", + "punctuation.separator.key-value.css", + "entity.name.tag.yaml", + "punctuation.separator.key-value.mapping.yaml", + ], + settings: { + foreground: "var(--syntax-operator)", + }, + }, + { + scope: ["storage", "storage.type"], + settings: { + foreground: "var(--syntax-keyword)", + }, + }, + { + scope: ["storage.modifier.package", "storage.modifier.import", "storage.type.java"], + settings: { + foreground: "var(--syntax-primitive)", + }, + }, + { + scope: [ + "string", + "punctuation.definition.string", + "string punctuation.section.embedded source", + "entity.name.tag", + ], + settings: { + foreground: "var(--syntax-string)", + }, + }, + { + scope: "support", + settings: { + foreground: "var(--syntax-primitive)", + }, + }, + { + scope: [ + "support.type.object.module", + "variable.other.object", + "support.type.property-name.css", + ], + settings: { + foreground: "var(--syntax-object)", + }, + }, + { + scope: "meta.property-name", + settings: { + foreground: "var(--syntax-property)", + }, + }, + { + scope: "variable", + settings: { + foreground: "var(--syntax-variable)", + }, + }, + { + scope: "variable.other", + settings: { + foreground: "var(--syntax-variable)", + }, + }, + { + scope: [ + "invalid.broken", + "invalid.illegal", + "invalid.unimplemented", + "invalid.deprecated", + "message.error", + "markup.deleted", + "meta.diff.header.from-file", + "punctuation.definition.deleted", + "brackethighlighter.unmatched", + "token.error-token", + ], + settings: { + foreground: "var(--syntax-critical)", + }, + }, + { + scope: "carriage-return", + settings: { + foreground: "var(--syntax-keyword)", + }, + }, + { + scope: "string source", + settings: { + foreground: "var(--syntax-variable)", + }, + }, + { + scope: "string variable", + settings: { + foreground: "var(--syntax-constant)", + }, + }, + { + scope: [ + "source.regexp", + "string.regexp", + "string.regexp.character-class", + "string.regexp constant.character.escape", + "string.regexp source.ruby.embedded", + "string.regexp string.regexp.arbitrary-repitition", + "string.regexp constant.character.escape", + ], + settings: { + foreground: "var(--syntax-regexp)", + }, + }, + { + scope: "support.constant", + settings: { + foreground: "var(--syntax-primitive)", + }, + }, + { + scope: "support.variable", + settings: { + foreground: "var(--syntax-variable)", + }, + }, + { + scope: "meta.module-reference", + settings: { + foreground: "var(--syntax-info)", + }, + }, + { + scope: "punctuation.definition.list.begin.markdown", + settings: { + foreground: "var(--syntax-punctuation)", + }, + }, + { + scope: ["markup.heading", "markup.heading entity.name"], + settings: { + fontStyle: "bold", + foreground: "var(--syntax-info)", + }, + }, + { + scope: "markup.quote", + settings: { + foreground: "var(--syntax-info)", + }, + }, + { + scope: "markup.italic", + settings: { + fontStyle: "italic", + // foreground: "", + }, + }, + { + scope: "markup.bold", + settings: { + fontStyle: "bold", + foreground: "var(--text-strong)", + }, + }, + { + scope: [ + "markup.raw", + "markup.inserted", + "meta.diff.header.to-file", + "punctuation.definition.inserted", + "markup.changed", + "punctuation.definition.changed", + "markup.ignored", + "markup.untracked", + ], + settings: { + foreground: "var(--text-base)", + }, + }, + { + scope: "meta.diff.range", + settings: { + fontStyle: "bold", + foreground: "var(--syntax-unknown)", + }, + }, + { + scope: "meta.diff.header", + settings: { + foreground: "var(--syntax-unknown)", + }, + }, + { + scope: "meta.separator", + settings: { + fontStyle: "bold", + foreground: "var(--syntax-unknown)", + }, + }, + { + scope: "meta.output", + settings: { + foreground: "var(--syntax-unknown)", + }, + }, + { + scope: "meta.export.default", + settings: { + foreground: "var(--syntax-unknown)", + }, + }, + { + scope: [ + "brackethighlighter.tag", + "brackethighlighter.curly", + "brackethighlighter.round", + "brackethighlighter.square", + "brackethighlighter.angle", + "brackethighlighter.quote", + ], + settings: { + foreground: "var(--syntax-unknown)", + }, + }, + { + scope: ["constant.other.reference.link", "string.other.link"], + settings: { + fontStyle: "underline", + foreground: "var(--syntax-unknown)", + }, + }, + { + scope: "token.info-token", + settings: { + foreground: "var(--syntax-info)", + }, + }, + { + scope: "token.warn-token", + settings: { + foreground: "var(--syntax-warning)", + }, + }, + { + scope: "token.debug-token", + settings: { + foreground: "var(--syntax-info)", + }, + }, + ], + semanticTokenColors: { + comment: "var(--syntax-comment)", + string: "var(--syntax-string)", + number: "var(--syntax-constant)", + regexp: "var(--syntax-regexp)", + keyword: "var(--syntax-keyword)", + variable: "var(--syntax-variable)", + parameter: "var(--syntax-variable)", + property: "var(--syntax-property)", + function: "var(--syntax-primitive)", + method: "var(--syntax-primitive)", + type: "var(--syntax-type)", + class: "var(--syntax-type)", + namespace: "var(--syntax-type)", + enumMember: "var(--syntax-primitive)", + "variable.constant": "var(--syntax-constant)", + "variable.defaultLibrary": "var(--syntax-unknown)", + }, } as unknown as ThemeRegistrationResolved) }) diff --git a/packages/ui/src/components/index.ts b/packages/ui/src/components/index.ts index cd2d4caa..ebc897a1 100644 --- a/packages/ui/src/components/index.ts +++ b/packages/ui/src/components/index.ts @@ -24,5 +24,4 @@ export * from "./tooltip" export * from "./typewriter" export * from "../context/helper" -export * from "../context/shiki" export * from "../context/marked" diff --git a/packages/ui/src/context/marked.tsx b/packages/ui/src/context/marked.tsx index 18ce4280..804d449c 100644 --- a/packages/ui/src/context/marked.tsx +++ b/packages/ui/src/context/marked.tsx @@ -1,14 +1,14 @@ import { marked } from "marked" import markedShiki from "marked-shiki" import { bundledLanguages, type BundledLanguage } from "shiki" - import { createSimpleContext } from "./helper" -import { useShiki } from "./shiki" +import { getSharedHighlighter } from "@pierre/precision-diffs" + +const highlighter = await getSharedHighlighter({ themes: ["OpenCode"], langs: [] }) export const { use: useMarked, provider: MarkedProvider } = createSimpleContext({ name: "Marked", init: () => { - const highlighter = useShiki() return marked.use( markedShiki({ async highlight(code, lang) { @@ -20,7 +20,7 @@ export const { use: useMarked, provider: MarkedProvider } = createSimpleContext( } return highlighter.codeToHtml(code, { lang: lang || "text", - theme: "opencode", + theme: "OpenCode", tabindex: false, }) }, diff --git a/packages/ui/src/context/shiki.tsx b/packages/ui/src/context/shiki.tsx deleted file mode 100644 index d33b98ab..00000000 --- a/packages/ui/src/context/shiki.tsx +++ /dev/null @@ -1,577 +0,0 @@ -import { createSimpleContext } from "./helper" -import { createHighlighter, type ThemeInput } from "shiki" - -const theme: ThemeInput = { - colors: { - "actionBar.toggledBackground": "var(--surface-raised-base)", - "activityBarBadge.background": "var(--surface-brand-base)", - "checkbox.border": "var(--border-base)", - "editor.background": "transparent", - "editor.foreground": "var(--text-base)", - "editor.inactiveSelectionBackground": "var(--surface-raised-base)", - "editor.selectionHighlightBackground": "var(--border-active)", - "editorIndentGuide.activeBackground1": "var(--border-weak-base)", - "editorIndentGuide.background1": "var(--border-weak-base)", - "input.placeholderForeground": "var(--text-weak)", - "list.activeSelectionIconForeground": "var(--text-base)", - "list.dropBackground": "var(--surface-raised-base)", - "menu.background": "var(--surface-base)", - "menu.border": "var(--border-base)", - "menu.foreground": "var(--text-base)", - "menu.selectionBackground": "var(--surface-interactive-base)", - "menu.separatorBackground": "var(--border-base)", - "ports.iconRunningProcessForeground": "var(--icon-success-base)", - "sideBarSectionHeader.background": "transparent", - "sideBarSectionHeader.border": "var(--border-weak-base)", - "sideBarTitle.foreground": "var(--text-weak)", - "statusBarItem.remoteBackground": "var(--surface-success-base)", - "statusBarItem.remoteForeground": "var(--text-base)", - "tab.lastPinnedBorder": "var(--border-weak-base)", - "tab.selectedBackground": "var(--surface-raised-base)", - "tab.selectedForeground": "var(--text-weak)", - "terminal.inactiveSelectionBackground": "var(--surface-raised-base)", - "widget.border": "var(--border-base)", - }, - displayName: "opencode", - name: "opencode", - semanticHighlighting: true, - semanticTokenColors: { - customLiteral: "var(--syntax-function)", - newOperator: "var(--syntax-operator)", - numberLiteral: "var(--syntax-number)", - stringLiteral: "var(--syntax-string)", - }, - tokenColors: [ - { - scope: [ - "meta.embedded", - "source.groovy.embedded", - "string meta.image.inline.markdown", - "variable.legacy.builtin.python", - ], - settings: { - foreground: "var(--text-base)", - }, - }, - { - scope: "emphasis", - settings: { - fontStyle: "italic", - }, - }, - { - scope: "strong", - settings: { - fontStyle: "bold", - }, - }, - { - scope: "header", - settings: { - foreground: "var(--markdown-heading)", - }, - }, - { - scope: "comment", - settings: { - foreground: "var(--syntax-comment)", - }, - }, - { - scope: "constant.language", - settings: { - foreground: "var(--syntax-keyword)", - }, - }, - { - scope: [ - "constant.numeric", - "variable.other.enummember", - "keyword.operator.plus.exponent", - "keyword.operator.minus.exponent", - ], - settings: { - foreground: "var(--syntax-number)", - }, - }, - { - scope: "constant.regexp", - settings: { - foreground: "var(--syntax-operator)", - }, - }, - { - scope: "entity.name.tag", - settings: { - foreground: "var(--syntax-keyword)", - }, - }, - { - scope: ["entity.name.tag.css", "entity.name.tag.less"], - settings: { - foreground: "var(--syntax-operator)", - }, - }, - { - scope: "entity.other.attribute-name", - settings: { - foreground: "var(--syntax-variable)", - }, - }, - { - scope: [ - "entity.other.attribute-name.class.css", - "source.css entity.other.attribute-name.class", - "entity.other.attribute-name.id.css", - "entity.other.attribute-name.parent-selector.css", - "entity.other.attribute-name.parent.less", - "source.css entity.other.attribute-name.pseudo-class", - "entity.other.attribute-name.pseudo-element.css", - "source.css.less entity.other.attribute-name.id", - "entity.other.attribute-name.scss", - ], - settings: { - foreground: "var(--syntax-operator)", - }, - }, - { - scope: "invalid", - settings: { - foreground: "var(--syntax-critical)", - }, - }, - { - scope: "markup.underline", - settings: { - fontStyle: "underline", - }, - }, - { - scope: "markup.bold", - settings: { - fontStyle: "bold", - foreground: "var(--markdown-strong)", - }, - }, - { - scope: "markup.heading", - settings: { - fontStyle: "bold", - foreground: "var(--theme-markdown-heading)", - }, - }, - { - scope: "markup.italic", - settings: { - fontStyle: "italic", - }, - }, - { - scope: "markup.strikethrough", - settings: { - fontStyle: "strikethrough", - }, - }, - { - scope: "markup.inserted", - settings: { - foreground: "var(--text-diff-add-base)", - }, - }, - { - scope: "markup.deleted", - settings: { - foreground: "var(--text-diff-delete-base)", - }, - }, - { - scope: "markup.changed", - settings: { - foreground: "var(--text-base)", - }, - }, - { - scope: "punctuation.definition.quote.begin.markdown", - settings: { - foreground: "var(--markdown-block-quote)", - }, - }, - { - scope: "punctuation.definition.list.begin.markdown", - settings: { - foreground: "var(--markdown-list-enumeration)", - }, - }, - { - scope: "markup.inline.raw", - settings: { - foreground: "var(--markdown-code)", - }, - }, - { - scope: "punctuation.definition.tag", - settings: { - foreground: "var(--syntax-punctuation)", - }, - }, - { - scope: ["meta.preprocessor", "entity.name.function.preprocessor"], - settings: { - foreground: "var(--syntax-keyword)", - }, - }, - { - scope: "meta.preprocessor.string", - settings: { - foreground: "var(--syntax-string)", - }, - }, - { - scope: "meta.preprocessor.numeric", - settings: { - foreground: "var(--syntax-number)", - }, - }, - { - scope: "meta.structure.dictionary.key.python", - settings: { - foreground: "var(--syntax-variable)", - }, - }, - { - scope: "meta.diff.header", - settings: { - foreground: "var(--text-weak)", - }, - }, - { - scope: "storage", - settings: { - foreground: "var(--syntax-keyword)", - }, - }, - { - scope: "storage.type", - settings: { - foreground: "var(--syntax-keyword)", - }, - }, - { - scope: ["storage.modifier", "keyword.operator.noexcept"], - settings: { - foreground: "var(--syntax-keyword)", - }, - }, - { - scope: ["string", "meta.embedded.assembly"], - settings: { - foreground: "var(--syntax-string)", - }, - }, - { - scope: "string.tag", - settings: { - foreground: "var(--syntax-string)", - }, - }, - { - scope: "string.value", - settings: { - foreground: "var(--syntax-string)", - }, - }, - { - scope: "string.regexp", - settings: { - foreground: "var(--syntax-operator)", - }, - }, - { - scope: [ - "punctuation.definition.template-expression.begin", - "punctuation.definition.template-expression.end", - "punctuation.section.embedded", - ], - settings: { - foreground: "var(--syntax-keyword)", - }, - }, - { - scope: ["meta.template.expression"], - settings: { - foreground: "var(--text-base)", - }, - }, - { - scope: [ - "support.type.vendored.property-name", - "support.type.property-name", - "source.css variable", - "source.coffee.embedded", - ], - settings: { - foreground: "var(--syntax-variable)", - }, - }, - { - scope: "keyword", - settings: { - foreground: "var(--syntax-keyword)", - }, - }, - { - scope: "keyword.control", - settings: { - foreground: "var(--syntax-keyword)", - }, - }, - { - scope: "keyword.operator", - settings: { - foreground: "var(--syntax-operator)", - }, - }, - { - scope: [ - "keyword.operator.new", - "keyword.operator.expression", - "keyword.operator.cast", - "keyword.operator.sizeof", - "keyword.operator.alignof", - "keyword.operator.typeid", - "keyword.operator.alignas", - "keyword.operator.instanceof", - "keyword.operator.logical.python", - "keyword.operator.wordlike", - ], - settings: { - foreground: "var(--syntax-keyword)", - }, - }, - { - scope: "keyword.other.unit", - settings: { - foreground: "var(--syntax-number)", - }, - }, - { - scope: ["punctuation.section.embedded.begin.php", "punctuation.section.embedded.end.php"], - settings: { - foreground: "var(--syntax-keyword)", - }, - }, - { - scope: "support.function.git-rebase", - settings: { - foreground: "var(--syntax-variable)", - }, - }, - { - scope: "constant.sha.git-rebase", - settings: { - foreground: "var(--syntax-number)", - }, - }, - { - scope: [ - "storage.modifier.import.java", - "variable.language.wildcard.java", - "storage.modifier.package.java", - ], - settings: { - foreground: "var(--text-base)", - }, - }, - { - scope: "variable.language", - settings: { - foreground: "var(--syntax-keyword)", - }, - }, - { - scope: [ - "entity.name.function", - "support.function", - "support.constant.handlebars", - "source.powershell variable.other.member", - "entity.name.operator.custom-literal", - ], - settings: { - foreground: "var(--syntax-function)", - }, - }, - { - scope: [ - "support.class", - "support.type", - "entity.name.type", - "entity.name.namespace", - "entity.other.attribute", - "entity.name.scope-resolution", - "entity.name.class", - "storage.type.numeric.go", - "storage.type.byte.go", - "storage.type.boolean.go", - "storage.type.string.go", - "storage.type.uintptr.go", - "storage.type.error.go", - "storage.type.rune.go", - "storage.type.cs", - "storage.type.generic.cs", - "storage.type.modifier.cs", - "storage.type.variable.cs", - "storage.type.annotation.java", - "storage.type.generic.java", - "storage.type.java", - "storage.type.object.array.java", - "storage.type.primitive.array.java", - "storage.type.primitive.java", - "storage.type.token.java", - "storage.type.groovy", - "storage.type.annotation.groovy", - "storage.type.parameters.groovy", - "storage.type.generic.groovy", - "storage.type.object.array.groovy", - "storage.type.primitive.array.groovy", - "storage.type.primitive.groovy", - ], - settings: { - foreground: "var(--syntax-type)", - }, - }, - { - scope: [ - "meta.type.cast.expr", - "meta.type.new.expr", - "support.constant.math", - "support.constant.dom", - "support.constant.json", - "entity.other.inherited-class", - "punctuation.separator.namespace.ruby", - ], - settings: { - foreground: "var(--syntax-type)", - }, - }, - { - scope: [ - "keyword.control", - "source.cpp keyword.operator.new", - "keyword.operator.delete", - "keyword.other.using", - "keyword.other.directive.using", - "keyword.other.operator", - "entity.name.operator", - ], - settings: { - foreground: "var(--syntax-operator)", - }, - }, - { - scope: [ - "variable", - "meta.definition.variable.name", - "support.variable", - "entity.name.variable", - "constant.other.placeholder", - ], - settings: { - foreground: "var(--syntax-variable)", - }, - }, - { - scope: ["variable.other.constant", "variable.other.enummember"], - settings: { - foreground: "var(--syntax-variable)", - }, - }, - { - scope: ["meta.object-literal.key"], - settings: { - foreground: "var(--syntax-variable)", - }, - }, - { - scope: [ - "support.constant.property-value", - "support.constant.font-name", - "support.constant.media-type", - "support.constant.media", - "constant.other.color.rgb-value", - "constant.other.rgb-value", - "support.constant.color", - ], - settings: { - foreground: "var(--syntax-string)", - }, - }, - { - scope: [ - "punctuation.definition.group.regexp", - "punctuation.definition.group.assertion.regexp", - "punctuation.definition.character-class.regexp", - "punctuation.character.set.begin.regexp", - "punctuation.character.set.end.regexp", - "keyword.operator.negation.regexp", - "support.other.parenthesis.regexp", - ], - settings: { - foreground: "var(--syntax-string)", - }, - }, - { - scope: [ - "constant.character.character-class.regexp", - "constant.other.character-class.set.regexp", - "constant.other.character-class.regexp", - "constant.character.set.regexp", - ], - settings: { - foreground: "var(--syntax-operator)", - }, - }, - { - scope: ["keyword.operator.or.regexp", "keyword.control.anchor.regexp"], - settings: { - foreground: "var(--syntax-operator)", - }, - }, - { - scope: "keyword.operator.quantifier.regexp", - settings: { - foreground: "var(--syntax-operator)", - }, - }, - { - scope: ["constant.character", "constant.other.option"], - settings: { - foreground: "var(--syntax-keyword)", - }, - }, - { - scope: "constant.character.escape", - settings: { - foreground: "var(--syntax-operator)", - }, - }, - { - scope: "entity.name.label", - settings: { - foreground: "var(--text-weak)", - }, - }, - ], - type: "dark", -} - -const highlighter = await createHighlighter({ - themes: [theme], - langs: [], -}) - -export const { use: useShiki, provider: ShikiProvider } = createSimpleContext({ - name: "Shiki", - init: () => { - return highlighter - }, -}) From c5a558f3dad12fd41d65d68eac9d774d4c4bd8d4 Mon Sep 17 00:00:00 2001 From: Adam <2363879+adamdotdevin@users.noreply.github.com> Date: Fri, 7 Nov 2025 13:34:41 -0600 Subject: [PATCH 121/218] chore(desktop): remove dead code --- packages/desktop/src/components/code.tsx | 846 ----------------------- 1 file changed, 846 deletions(-) delete mode 100644 packages/desktop/src/components/code.tsx diff --git a/packages/desktop/src/components/code.tsx b/packages/desktop/src/components/code.tsx deleted file mode 100644 index bbf7e28a..00000000 --- a/packages/desktop/src/components/code.tsx +++ /dev/null @@ -1,846 +0,0 @@ -import { bundledLanguages, type BundledLanguage, type ShikiTransformer } from "shiki" -import { splitProps, type ComponentProps, createEffect, onMount, onCleanup, createMemo, createResource } from "solid-js" -import { useLocal, type TextSelection } from "@/context/local" -import { getFileExtension, getNodeOffsetInLine, getSelectionInContainer } from "@/utils" -import { useShiki } from "@opencode-ai/ui" - -type DefinedSelection = Exclude - -interface Props extends ComponentProps<"div"> { - code: string - path: string -} - -export function Code(props: Props) { - const ctx = useLocal() - const highlighter = useShiki() - const [local, others] = splitProps(props, ["class", "classList", "code", "path"]) - const lang = createMemo(() => { - const ext = getFileExtension(local.path) - if (ext in bundledLanguages) return ext - return "text" - }) - - let container: HTMLDivElement | undefined - let isProgrammaticSelection = false - - const ranges = createMemo(() => { - const items = ctx.context.all() as Array<{ type: "file"; path: string; selection?: DefinedSelection }> - const result: DefinedSelection[] = [] - for (const item of items) { - if (item.path !== local.path) continue - const selection = item.selection - if (!selection) continue - result.push(selection) - } - return result - }) - - const createLineNumberTransformer = (selections: DefinedSelection[]): ShikiTransformer => { - const highlighted = new Set() - for (const selection of selections) { - const startLine = selection.startLine - const endLine = selection.endLine - const start = Math.max(1, Math.min(startLine, endLine)) - const end = Math.max(start, Math.max(startLine, endLine)) - const count = end - start + 1 - if (count <= 0) continue - const values = Array.from({ length: count }, (_, index) => start + index) - for (const value of values) highlighted.add(value) - } - return { - name: "line-number-highlight", - line(node, index) { - if (!highlighted.has(index)) return - this.addClassToHast(node, "line-number-highlight") - const children = node.children - if (!Array.isArray(children)) return - for (const child of children) { - if (!child || typeof child !== "object") continue - const element = child as { type?: string; properties?: { className?: string[] } } - if (element.type !== "element") continue - const className = element.properties?.className - if (!Array.isArray(className)) continue - const matches = className.includes("diff-oldln") || className.includes("diff-newln") - if (!matches) continue - if (className.includes("line-number-highlight")) continue - className.push("line-number-highlight") - } - }, - } - } - - const [html] = createResource( - () => ranges(), - async (activeRanges) => { - if (!highlighter.getLoadedLanguages().includes(lang())) { - await highlighter.loadLanguage(lang() as BundledLanguage) - } - return highlighter.codeToHtml(local.code || "", { - lang: lang() && lang() in bundledLanguages ? lang() : "text", - theme: "opencode", - transformers: [transformerUnifiedDiff(), transformerDiffGroups(), createLineNumberTransformer(activeRanges)], - }) as string - }, - ) - - onMount(() => { - if (!container) return - - let ticking = false - const onScroll = () => { - if (!container) return - // if (ctx.file.active()?.path !== local.path) return - if (ticking) return - ticking = true - requestAnimationFrame(() => { - ticking = false - ctx.file.scroll(local.path, container!.scrollTop) - }) - } - - const onSelectionChange = async () => { - if (!container) return - if (isProgrammaticSelection) return - // if (ctx.file.active()?.path !== local.path) return - const d = getSelectionInContainer(container) - if (!d) return - const p = (await ctx.file.node(local.path))?.selection - if (p && p.startLine === d.sl && p.endLine === d.el && p.startChar === d.sch && p.endChar === d.ech) return - ctx.file.select(local.path, { startLine: d.sl, startChar: d.sch, endLine: d.el, endChar: d.ech }) - } - - const MOD = typeof navigator === "object" && /(Mac|iPod|iPhone|iPad)/.test(navigator.platform) ? "Meta" : "Control" - const onKeyDown = (e: KeyboardEvent) => { - // if (ctx.file.active()?.path !== local.path) return - const ae = document.activeElement as HTMLElement | undefined - const tag = (ae?.tagName || "").toLowerCase() - const inputFocused = !!ae && (tag === "input" || tag === "textarea" || ae.isContentEditable) - if (inputFocused) return - if (e.getModifierState(MOD) && e.key.toLowerCase() === "a") { - e.preventDefault() - if (!container) return - const element = container.querySelector("code") as HTMLElement | undefined - if (!element) return - const lines = Array.from(element.querySelectorAll(".line")) - if (!lines.length) return - const r = document.createRange() - const last = lines[lines.length - 1] - r.selectNodeContents(last) - const lastLen = r.toString().length - ctx.file.select(local.path, { startLine: 1, startChar: 0, endLine: lines.length, endChar: lastLen }) - } - } - - container.addEventListener("scroll", onScroll) - document.addEventListener("selectionchange", onSelectionChange) - document.addEventListener("keydown", onKeyDown) - - onCleanup(() => { - container?.removeEventListener("scroll", onScroll) - document.removeEventListener("selectionchange", onSelectionChange) - document.removeEventListener("keydown", onKeyDown) - }) - }) - - // Restore scroll position from store when content is ready - createEffect(async () => { - const content = html() - if (!container || !content) return - const top = (await ctx.file.node(local.path))?.scrollTop - if (top !== undefined && container.scrollTop !== top) container.scrollTop = top - }) - - // Sync selection from store -> DOM - createEffect(async () => { - const content = html() - if (!container || !content) return - // if (ctx.file.active()?.path !== local.path) return - const codeEl = container.querySelector("code") as HTMLElement | undefined - if (!codeEl) return - const target = (await ctx.file.node(local.path))?.selection - const current = getSelectionInContainer(container) - const sel = window.getSelection() - if (!sel) return - if (!target) { - if (current) { - isProgrammaticSelection = true - sel.removeAllRanges() - queueMicrotask(() => { - isProgrammaticSelection = false - }) - } - return - } - const matches = !!( - current && - current.sl === target.startLine && - current.sch === target.startChar && - current.el === target.endLine && - current.ech === target.endChar - ) - if (matches) return - const lines = Array.from(codeEl.querySelectorAll(".line")) - if (lines.length === 0) return - let sIdx = Math.max(0, target.startLine - 1) - let eIdx = Math.max(0, target.endLine - 1) - let sChar = Math.max(0, target.startChar || 0) - let eChar = Math.max(0, target.endChar || 0) - if (sIdx > eIdx || (sIdx === eIdx && sChar > eChar)) { - const ti = sIdx - sIdx = eIdx - eIdx = ti - const tc = sChar - sChar = eChar - eChar = tc - } - if (eChar === 0 && eIdx > sIdx) { - eIdx = eIdx - 1 - eChar = Number.POSITIVE_INFINITY - } - if (sIdx >= lines.length) return - if (eIdx >= lines.length) eIdx = lines.length - 1 - const s = getNodeOffsetInLine(lines[sIdx], sChar) ?? { node: lines[sIdx], offset: 0 } - const e = getNodeOffsetInLine(lines[eIdx], eChar) ?? { node: lines[eIdx], offset: lines[eIdx].childNodes.length } - const range = document.createRange() - range.setStart(s.node, s.offset) - range.setEnd(e.node, e.offset) - isProgrammaticSelection = true - sel.removeAllRanges() - sel.addRange(range) - queueMicrotask(() => { - isProgrammaticSelection = false - }) - }) - - // Build/toggle split layout and apply folding (both unified and split) - createEffect(() => { - const content = html() - if (!container || !content) return - const view = ctx.file.view(local.path) - - const pres = Array.from(container.querySelectorAll("pre")) - if (pres.length === 0) return - const originalPre = pres[0] - - const split = container.querySelector(".diff-split") - if (view === "diff-split") { - applySplitDiff(container) - const next = container.querySelector(".diff-split") - if (next) next.style.display = "" - originalPre.style.display = "none" - } else { - if (split) split.style.display = "none" - originalPre.style.display = "" - } - - const expanded = ctx.file.folded(local.path) - if (view === "diff-split") { - const left = container.querySelector(".diff-split pre:nth-child(1) code") - const right = container.querySelector(".diff-split pre:nth-child(2) code") - if (left) - applyDiffFolding(left, 3, { expanded, onExpand: (key) => ctx.file.unfold(local.path, key), side: "left" }) - if (right) - applyDiffFolding(right, 3, { expanded, onExpand: (key) => ctx.file.unfold(local.path, key), side: "right" }) - } else { - const code = container.querySelector("pre code") - if (code) - applyDiffFolding(code, 3, { - expanded, - onExpand: (key) => ctx.file.unfold(local.path, key), - }) - } - }) - - // Highlight groups + scroll coupling - const clearHighlights = () => { - if (!container) return - container.querySelectorAll(".diff-selected").forEach((el) => el.classList.remove("diff-selected")) - } - - const applyHighlight = (idx: number, scroll?: boolean) => { - if (!container) return - const view = ctx.file.view(local.path) - if (view === "raw") return - - clearHighlights() - - const nodes: HTMLElement[] = [] - if (view === "diff-split") { - const left = container.querySelector(".diff-split pre:nth-child(1) code") - const right = container.querySelector(".diff-split pre:nth-child(2) code") - if (left) - nodes.push(...Array.from(left.querySelectorAll(`[data-chgrp="${idx}"][data-diff="remove"]`))) - if (right) - nodes.push(...Array.from(right.querySelectorAll(`[data-chgrp="${idx}"][data-diff="add"]`))) - } else { - const code = container.querySelector("pre code") - if (code) nodes.push(...Array.from(code.querySelectorAll(`[data-chgrp="${idx}"]`))) - } - - for (const n of nodes) n.classList.add("diff-selected") - if (scroll && nodes.length) nodes[0].scrollIntoView({ block: "center", behavior: "smooth" }) - } - - const countGroups = () => { - if (!container) return 0 - const code = container.querySelector("pre code") - if (!code) return 0 - const set = new Set() - for (const el of Array.from(code.querySelectorAll(".diff-line[data-chgrp]"))) { - const v = el.getAttribute("data-chgrp") - if (v != undefined) set.add(v) - } - return set.size - } - - let lastIdx: number | undefined = undefined - let lastView: string | undefined - let lastContent: string | undefined - let lastRawIdx: number | undefined = undefined - createEffect(() => { - const content = html() - if (!container || !content) return - const view = ctx.file.view(local.path) - const raw = ctx.file.changeIndex(local.path) - if (raw === undefined) return - const total = countGroups() - if (total <= 0) return - const next = ((raw % total) + total) % total - - const navigated = lastRawIdx !== undefined && lastRawIdx !== raw - - if (next !== raw) { - ctx.file.setChangeIndex(local.path, next) - applyHighlight(next, true) - } else { - if (lastView !== view || lastContent !== content) applyHighlight(next) - if ((lastIdx !== undefined && lastIdx !== next) || navigated) applyHighlight(next, true) - } - - lastRawIdx = raw - lastIdx = next - lastView = view - lastContent = content - }) - - return ( -
    { - container = el - }} - innerHTML={html()} - class=" - font-mono text-xs tracking-wide overflow-y-auto h-full - [&]:[counter-reset:line] - [&_pre]:focus-visible:outline-none - [&_pre]:overflow-x-auto [&_pre]:no-scrollbar - [&_code]:min-w-full [&_code]:inline-block - [&_.tab]:relative - [&_.tab::before]:content['⇥'] - [&_.tab::before]:absolute - [&_.tab::before]:opacity-0 - [&_.space]:relative - [&_.space::before]:content-['·'] - [&_.space::before]:absolute - [&_.space::before]:opacity-0 - [&_.line]:inline-block [&_.line]:w-full - [&_.line]:hover:bg-background-element - [&_.line::before]:sticky [&_.line::before]:left-0 - [&_.line::before]:w-12 [&_.line::before]:pr-4 - [&_.line::before]:z-10 - [&_.line::before]:bg-background-panel - [&_.line::before]:text-text-muted/60 - [&_.line::before]:text-right [&_.line::before]:inline-block - [&_.line::before]:select-none - [&_.line::before]:[counter-increment:line] - [&_.line::before]:content-[counter(line)] - [&_.line-number-highlight]:bg-accent/20 - [&_.line-number-highlight::before]:bg-accent/40! - [&_.line-number-highlight::before]:text-background-panel! - [&_code.code-diff_.line::before]:content-[''] - [&_code.code-diff_.line::before]:w-0 - [&_code.code-diff_.line::before]:pr-0 - [&_.diff-split_code.code-diff::before]:w-10 - [&_.diff-split_.diff-newln]:left-0 - [&_.diff-oldln]:sticky [&_.diff-oldln]:left-0 - [&_.diff-oldln]:w-10 [&_.diff-oldln]:pr-2 - [&_.diff-oldln]:z-40 - [&_.diff-oldln]:text-text-muted/60 - [&_.diff-oldln]:text-right [&_.diff-oldln]:inline-block - [&_.diff-oldln]:select-none - [&_.diff-oldln]:bg-background-panel - [&_.diff-newln]:sticky [&_.diff-newln]:left-10 - [&_.diff-newln]:w-10 [&_.diff-newln]:pr-2 - [&_.diff-newln]:z-40 - [&_.diff-newln]:text-text-muted/60 - [&_.diff-newln]:text-right [&_.diff-newln]:inline-block - [&_.diff-newln]:select-none - [&_.diff-newln]:bg-background-panel - [&_.diff-add]:bg-success/20! - [&_.diff-add.diff-selected]:bg-success/50! - [&_.diff-add_.diff-oldln]:bg-success! - [&_.diff-add_.diff-oldln]:text-background-panel! - [&_.diff-add_.diff-newln]:bg-success! - [&_.diff-add_.diff-newln]:text-background-panel! - [&_.diff-remove]:bg-error/20! - [&_.diff-remove.diff-selected]:bg-error/50! - [&_.diff-remove_.diff-newln]:bg-error! - [&_.diff-remove_.diff-newln]:text-background-panel! - [&_.diff-remove_.diff-oldln]:bg-error! - [&_.diff-remove_.diff-oldln]:text-background-panel! - [&_.diff-sign]:inline-block [&_.diff-sign]:px-2 [&_.diff-sign]:select-none - [&_.diff-blank]:bg-background-element - [&_.diff-blank_.diff-oldln]:bg-background-element - [&_.diff-blank_.diff-newln]:bg-background-element - [&_.diff-collapsed]:block! [&_.diff-collapsed]:w-full [&_.diff-collapsed]:relative - [&_.diff-collapsed]:select-none - [&_.diff-collapsed]:bg-info/20 [&_.diff-collapsed]:hover:bg-info/40! - [&_.diff-collapsed]:text-info/80 [&_.diff-collapsed]:hover:text-info - [&_.diff-collapsed]:text-xs - [&_.diff-collapsed_.diff-oldln]:bg-info! - [&_.diff-collapsed_.diff-newln]:bg-info! - " - classList={{ - ...(local.classList || {}), - [local.class ?? ""]: !!local.class, - }} - {...others} - >
    - ) -} - -function transformerUnifiedDiff(): ShikiTransformer { - const kinds = new Map() - const meta = new Map() - let isDiff = false - - return { - name: "unified-diff", - preprocess(input) { - kinds.clear() - meta.clear() - isDiff = false - - const ls = input.split(/\r?\n/) - const out: Array = [] - let oldNo = 0 - let newNo = 0 - let inHunk = false - - for (let i = 0; i < ls.length; i++) { - const s = ls[i] - - const m = s.match(/^@@\s*-(\d+)(?:,(\d+))?\s+\+(\d+)(?:,(\d+))?\s*@@/) - if (m) { - isDiff = true - inHunk = true - oldNo = parseInt(m[1], 10) - newNo = parseInt(m[3], 10) - continue - } - - if ( - /^diff --git /.test(s) || - /^Index: /.test(s) || - /^--- /.test(s) || - /^\+\+\+ /.test(s) || - /^[=]{3,}$/.test(s) || - /^\*{3,}$/.test(s) || - /^\\ No newline at end of file$/.test(s) - ) { - isDiff = true - continue - } - - if (!inHunk) { - out.push(s) - continue - } - - if (/^\+/.test(s)) { - out.push(s) - const ln = out.length - kinds.set(ln, "add") - meta.set(ln, { new: newNo, sign: "+" }) - newNo++ - continue - } - - if (/^-/.test(s)) { - out.push(s) - const ln = out.length - kinds.set(ln, "remove") - meta.set(ln, { old: oldNo, sign: "-" }) - oldNo++ - continue - } - - if (/^ /.test(s)) { - out.push(s) - const ln = out.length - kinds.set(ln, "context") - meta.set(ln, { old: oldNo, new: newNo }) - oldNo++ - newNo++ - continue - } - - // fallback in hunks - out.push(s) - } - - return out.join("\n").trimEnd() - }, - code(node) { - if (isDiff) this.addClassToHast(node, "code-diff") - }, - pre(node) { - if (isDiff) this.addClassToHast(node, "code-diff") - }, - line(node, line) { - if (!isDiff) return - const kind = kinds.get(line) - if (!kind) return - - const m = meta.get(line) || {} - - this.addClassToHast(node, "diff-line") - this.addClassToHast(node, `diff-${kind}`) - node.properties = node.properties || {} - ;(node.properties as any)["data-diff"] = kind - if (m.old != undefined) (node.properties as any)["data-old"] = String(m.old) - if (m.new != undefined) (node.properties as any)["data-new"] = String(m.new) - - const oldSpan = { - type: "element", - tagName: "span", - properties: { className: ["diff-oldln"] }, - children: [{ type: "text", value: m.old != undefined ? String(m.old) : " " }], - } - const newSpan = { - type: "element", - tagName: "span", - properties: { className: ["diff-newln"] }, - children: [{ type: "text", value: m.new != undefined ? String(m.new) : " " }], - } - - if (kind === "add" || kind === "remove" || kind === "context") { - const first = (node.children && (node.children as any[])[0]) as any - if (first && first.type === "element" && first.children && first.children.length > 0) { - const t = first.children[0] - if (t && t.type === "text" && typeof t.value === "string" && t.value.length > 0) { - const ch = t.value[0] - if (ch === "+" || ch === "-" || ch === " ") t.value = t.value.slice(1) - } - } - } - - const signSpan = { - type: "element", - tagName: "span", - properties: { className: ["diff-sign"] }, - children: [{ type: "text", value: (m as any).sign || " " }], - } - - // @ts-expect-error hast typing across versions - node.children = [oldSpan, newSpan, signSpan, ...(node.children || [])] - }, - } -} - -function transformerDiffGroups(): ShikiTransformer { - let group = -1 - let inGroup = false - return { - name: "diff-groups", - pre() { - group = -1 - inGroup = false - }, - line(node) { - const props = (node.properties || {}) as any - const kind = props["data-diff"] as string | undefined - if (kind === "add" || kind === "remove") { - if (!inGroup) { - group += 1 - inGroup = true - } - ;(node.properties as any)["data-chgrp"] = String(group) - } else { - inGroup = false - } - }, - } -} - -function applyDiffFolding( - root: HTMLElement, - context = 3, - options?: { expanded?: string[]; onExpand?: (key: string) => void; side?: "left" | "right" }, -) { - if (!root.classList.contains("code-diff")) return - - // Cleanup: unwrap previous collapsed blocks and remove toggles - const blocks = Array.from(root.querySelectorAll(".diff-collapsed-block")) - for (const block of blocks) { - const p = block.parentNode - if (!p) { - block.remove() - continue - } - while (block.firstChild) p.insertBefore(block.firstChild, block) - block.remove() - } - const toggles = Array.from(root.querySelectorAll(".diff-collapsed")) - for (const t of toggles) t.remove() - - const lines = Array.from(root.querySelectorAll(".diff-line")) - if (lines.length === 0) return - - const n = lines.length - const isChange = lines.map((l) => l.dataset["diff"] === "add" || l.dataset["diff"] === "remove") - const isContext = lines.map((l) => l.dataset["diff"] === "context") - if (!isChange.some(Boolean)) return - - const visible = new Array(n).fill(false) as boolean[] - for (let i = 0; i < n; i++) if (isChange[i]) visible[i] = true - for (let i = 0; i < n; i++) { - if (isChange[i]) { - const s = Math.max(0, i - context) - const e = Math.min(n - 1, i + context) - for (let j = s; j <= e; j++) if (isContext[j]) visible[j] = true - } - } - - type Range = { start: number; end: number } - const ranges: Range[] = [] - let i = 0 - while (i < n) { - if (!visible[i] && isContext[i]) { - let j = i - while (j + 1 < n && !visible[j + 1] && isContext[j + 1]) j++ - ranges.push({ start: i, end: j }) - i = j + 1 - } else { - i++ - } - } - - for (const r of ranges) { - const start = lines[r.start] - const end = lines[r.end] - const count = r.end - r.start + 1 - const minCollapse = 20 - if (count < minCollapse) { - continue - } - - // Wrap the entire collapsed chunk (including trailing newline) so it takes no space - const block = document.createElement("span") - block.className = "diff-collapsed-block" - start.parentElement?.insertBefore(block, start) - - let cur: Node | undefined = start - while (cur) { - const next: Node | undefined = cur.nextSibling || undefined - block.appendChild(cur) - if (cur === end) { - // Also move the newline after the last line into the block - if (next && next.nodeType === Node.TEXT_NODE && (next.textContent || "").startsWith("\n")) { - block.appendChild(next) - } - break - } - cur = next - } - - block.style.display = "none" - const row = document.createElement("span") - row.className = "line diff-collapsed" - row.setAttribute("data-kind", "collapsed") - row.setAttribute("data-count", String(count)) - row.setAttribute("tabindex", "0") - row.setAttribute("role", "button") - - const oldln = document.createElement("span") - oldln.className = "diff-oldln" - oldln.textContent = " " - - const newln = document.createElement("span") - newln.className = "diff-newln" - newln.textContent = " " - - const sign = document.createElement("span") - sign.className = "diff-sign" - sign.textContent = "…" - - const label = document.createElement("span") - label.textContent = `show ${count} unchanged line${count > 1 ? "s" : ""}` - - const key = `o${start.dataset["old"] || ""}-${end.dataset["old"] || ""}:n${start.dataset["new"] || ""}-${end.dataset["new"] || ""}` - - const show = (record = true) => { - if (record) options?.onExpand?.(key) - const p = block.parentNode - if (p) { - while (block.firstChild) p.insertBefore(block.firstChild, block) - block.remove() - } - row.remove() - } - - row.addEventListener("click", () => show(true)) - row.addEventListener("keydown", (ev) => { - if (ev.key === "Enter" || ev.key === " ") { - ev.preventDefault() - show(true) - } - }) - - block.parentElement?.insertBefore(row, block) - if (!options?.side || options.side === "left") row.appendChild(oldln) - if (!options?.side || options.side === "right") row.appendChild(newln) - row.appendChild(sign) - row.appendChild(label) - - if (options?.expanded && options.expanded.includes(key)) { - show(false) - } - } -} - -function applySplitDiff(container: HTMLElement) { - const pres = Array.from(container.querySelectorAll("pre")) - if (pres.length === 0) return - const originalPre = pres[0] - const originalCode = originalPre.querySelector("code") as HTMLElement | undefined - if (!originalCode || !originalCode.classList.contains("code-diff")) return - - // Rebuild split each time to match current content - const existing = container.querySelector(".diff-split") - if (existing) existing.remove() - - const grid = document.createElement("div") - grid.className = "diff-split grid grid-cols-2 gap-x-6" - - const makeColumn = () => { - const pre = document.createElement("pre") - pre.className = originalPre.className - const code = document.createElement("code") - code.className = originalCode.className - pre.appendChild(code) - return { pre, code } - } - - const left = makeColumn() - const right = makeColumn() - - // Helpers - const cloneSide = (line: HTMLElement, side: "old" | "new"): HTMLElement => { - const clone = line.cloneNode(true) as HTMLElement - const oldln = clone.querySelector(".diff-oldln") - const newln = clone.querySelector(".diff-newln") - if (side === "old") { - if (newln) newln.remove() - } else { - if (oldln) oldln.remove() - } - return clone - } - - const blankLine = (side: "old" | "new", kind: "add" | "remove"): HTMLElement => { - const span = document.createElement("span") - span.className = "line diff-line diff-blank" - span.setAttribute("data-diff", kind) - const ln = document.createElement("span") - ln.className = side === "old" ? "diff-oldln" : "diff-newln" - ln.textContent = " " - span.appendChild(ln) - return span - } - - const lines = Array.from(originalCode.querySelectorAll(".diff-line")) - let i = 0 - while (i < lines.length) { - const cur = lines[i] - const kind = cur.dataset["diff"] - - if (kind === "context") { - left.code.appendChild(cloneSide(cur, "old")) - left.code.appendChild(document.createTextNode("\n")) - right.code.appendChild(cloneSide(cur, "new")) - right.code.appendChild(document.createTextNode("\n")) - i++ - continue - } - - if (kind === "remove") { - // Batch consecutive removes and following adds, then pair - const removes: HTMLElement[] = [] - const adds: HTMLElement[] = [] - let j = i - while (j < lines.length && lines[j].dataset["diff"] === "remove") { - removes.push(lines[j]) - j++ - } - let k = j - while (k < lines.length && lines[k].dataset["diff"] === "add") { - adds.push(lines[k]) - k++ - } - - const pairs = Math.min(removes.length, adds.length) - for (let p = 0; p < pairs; p++) { - left.code.appendChild(cloneSide(removes[p], "old")) - left.code.appendChild(document.createTextNode("\n")) - right.code.appendChild(cloneSide(adds[p], "new")) - right.code.appendChild(document.createTextNode("\n")) - } - for (let p = pairs; p < removes.length; p++) { - left.code.appendChild(cloneSide(removes[p], "old")) - left.code.appendChild(document.createTextNode("\n")) - right.code.appendChild(blankLine("new", "remove")) - right.code.appendChild(document.createTextNode("\n")) - } - for (let p = pairs; p < adds.length; p++) { - left.code.appendChild(blankLine("old", "add")) - left.code.appendChild(document.createTextNode("\n")) - right.code.appendChild(cloneSide(adds[p], "new")) - right.code.appendChild(document.createTextNode("\n")) - } - - i = k - continue - } - - if (kind === "add") { - // Run of adds not preceded by removes - const adds: HTMLElement[] = [] - let j = i - while (j < lines.length && lines[j].dataset["diff"] === "add") { - adds.push(lines[j]) - j++ - } - for (let p = 0; p < adds.length; p++) { - left.code.appendChild(blankLine("old", "add")) - left.code.appendChild(document.createTextNode("\n")) - right.code.appendChild(cloneSide(adds[p], "new")) - right.code.appendChild(document.createTextNode("\n")) - } - i = j - continue - } - - // Any other kind: mirror as context - left.code.appendChild(cloneSide(cur, "old")) - left.code.appendChild(document.createTextNode("\n")) - right.code.appendChild(cloneSide(cur, "new")) - right.code.appendChild(document.createTextNode("\n")) - i++ - } - - grid.appendChild(left.pre) - grid.appendChild(right.pre) - container.appendChild(grid) -} From d462e380f4b444c7817ed2c4fbef27fec1eeeed1 Mon Sep 17 00:00:00 2001 From: Dax Raad Date: Fri, 7 Nov 2025 14:46:58 -0500 Subject: [PATCH 122/218] fix: update references after moving message functions to MessageV2 namespace --- packages/opencode/src/server/server.ts | 2 +- packages/opencode/src/session/compaction.ts | 8 ++--- packages/opencode/src/session/index.ts | 36 +-------------------- packages/opencode/src/session/message-v2.ts | 35 ++++++++++++++++++++ packages/opencode/src/session/prompt.ts | 8 ++--- packages/opencode/src/tool/task.ts | 2 +- 6 files changed, 46 insertions(+), 45 deletions(-) diff --git a/packages/opencode/src/server/server.ts b/packages/opencode/src/server/server.ts index c7265006..53d8b4dd 100644 --- a/packages/opencode/src/server/server.ts +++ b/packages/opencode/src/server/server.ts @@ -827,7 +827,7 @@ export namespace Server { ), async (c) => { const params = c.req.valid("param") - const message = await Session.getMessage({ + const message = await MessageV2.get({ sessionID: params.id, messageID: params.messageID, }) diff --git a/packages/opencode/src/session/compaction.ts b/packages/opencode/src/session/compaction.ts index 4924a35d..d54b07ca 100644 --- a/packages/opencode/src/session/compaction.ts +++ b/packages/opencode/src/session/compaction.ts @@ -111,7 +111,7 @@ export namespace SessionCompaction { draft.time.compacting = undefined }) }) - const toSummarize = await MessageV2.filterCompacted(Session.messageStream(input.sessionID)) + const toSummarize = await MessageV2.filterCompacted(MessageV2.stream(input.sessionID)) const model = await Provider.getModel(input.providerID, input.modelID) const system = [ ...SystemPrompt.summarize(model.providerID), @@ -270,7 +270,7 @@ export namespace SessionCompaction { } } - const parts = await Session.getParts(msg.id) + const parts = await MessageV2.parts(msg.id) return { info: msg, parts, @@ -287,7 +287,7 @@ export namespace SessionCompaction { }) if (result.shouldRetry) { for (let retry = 1; retry < maxRetries; retry++) { - const lastRetryPart = result.parts.findLast((p) => p.type === "retry") + const lastRetryPart = result.parts.findLast((p): p is MessageV2.RetryPart => p.type === "retry") if (lastRetryPart) { const delayMs = SessionRetry.getRetryDelayInMs(lastRetryPart.error, retry) @@ -336,7 +336,7 @@ export namespace SessionCompaction { if ( !msg.error || (MessageV2.AbortedError.isInstance(msg.error) && - result.parts.some((part) => part.type === "text" && part.text.length > 0)) + result.parts.some((part): part is MessageV2.TextPart => part.type === "text" && part.text.length > 0)) ) { msg.summary = true Bus.publish(Event.Compacted, { diff --git a/packages/opencode/src/session/index.ts b/packages/opencode/src/session/index.ts index 0971531f..831c2ddd 100644 --- a/packages/opencode/src/session/index.ts +++ b/packages/opencode/src/session/index.ts @@ -273,17 +273,6 @@ export namespace Session { return diffs ?? [] }) - export const messageStream = fn(Identifier.schema("session"), async function* (sessionID) { - const list = await Array.fromAsync(await Storage.list(["message", sessionID])) - for (let i = list.length - 1; i >= 0; i--) { - const read = await Storage.read(list[i]) - yield { - info: read, - parts: await getParts(read.id), - } - } - }) - export const messages = fn( z.object({ sessionID: Identifier.schema("session"), @@ -291,7 +280,7 @@ export namespace Session { }), async (input) => { const result = [] as MessageV2.WithParts[] - for await (const msg of messageStream(input.sessionID)) { + for await (const msg of MessageV2.stream(input.sessionID)) { if (input.limit && result.length >= input.limit) break result.push(msg) } @@ -300,29 +289,6 @@ export namespace Session { }, ) - export const getMessage = fn( - z.object({ - sessionID: Identifier.schema("session"), - messageID: Identifier.schema("message"), - }), - async (input) => { - return { - info: await Storage.read(["message", input.sessionID, input.messageID]), - parts: await getParts(input.messageID), - } - }, - ) - - export const getParts = fn(Identifier.schema("message"), async (messageID) => { - const result = [] as MessageV2.Part[] - for (const item of await Storage.list(["part", messageID])) { - const read = await Storage.read(item) - result.push(read) - } - result.sort((a, b) => (a.id > b.id ? 1 : -1)) - return result - }) - export async function* list() { const project = Instance.project for (const item of await Storage.list(["session", project.id])) { diff --git a/packages/opencode/src/session/message-v2.ts b/packages/opencode/src/session/message-v2.ts index 66d29319..bf15d734 100644 --- a/packages/opencode/src/session/message-v2.ts +++ b/packages/opencode/src/session/message-v2.ts @@ -12,6 +12,8 @@ import { import { Identifier } from "../id/id" import { LSP } from "../lsp" import { Snapshot } from "@/snapshot" +import { fn } from "@/util/fn" +import { Storage } from "@/storage/storage" export namespace MessageV2 { export const OutputLengthError = NamedError.create("MessageOutputLengthError", z.object({})) @@ -655,6 +657,39 @@ export namespace MessageV2 { return convertToModelMessages(result) } + export const stream = fn(Identifier.schema("session"), async function* (sessionID) { + const list = await Array.fromAsync(await Storage.list(["message", sessionID])) + for (let i = list.length - 1; i >= 0; i--) { + yield await get({ + sessionID, + messageID: list[i][2], + }) + } + }) + + export const parts = fn(Identifier.schema("message"), async (messageID) => { + const result = [] as MessageV2.Part[] + for (const item of await Storage.list(["part", messageID])) { + const read = await Storage.read(item) + result.push(read) + } + result.sort((a, b) => (a.id > b.id ? 1 : -1)) + return result + }) + + export const get = fn( + z.object({ + sessionID: Identifier.schema("session"), + messageID: Identifier.schema("message"), + }), + async (input) => { + return { + info: await Storage.read(["message", input.sessionID, input.messageID]), + parts: await parts(input.messageID), + } + }, + ) + export async function filterCompacted(stream: AsyncIterable) { const result = [] as MessageV2.WithParts[] for await (const msg of stream) { diff --git a/packages/opencode/src/session/prompt.ts b/packages/opencode/src/session/prompt.ts index cf11b129..f9480cd6 100644 --- a/packages/opencode/src/session/prompt.ts +++ b/packages/opencode/src/session/prompt.ts @@ -362,7 +362,7 @@ export namespace SessionPrompt { }) if (result.shouldRetry) { for (let retry = 1; retry < maxRetries; retry++) { - const lastRetryPart = result.parts.findLast((p) => p.type === "retry") + const lastRetryPart = result.parts.findLast((p): p is MessageV2.RetryPart => p.type === "retry") if (lastRetryPart) { const delayMs = SessionRetry.getRetryDelayInMs(lastRetryPart.error, retry) @@ -434,7 +434,7 @@ export namespace SessionPrompt { providerID: string signal: AbortSignal }) { - let msgs = await MessageV2.filterCompacted(Session.messageStream(input.sessionID)) + let msgs = await MessageV2.filterCompacted(MessageV2.stream(input.sessionID)) const lastAssistant = msgs.findLast((msg) => msg.info.role === "assistant") if ( lastAssistant?.info.role === "assistant" && @@ -1106,7 +1106,7 @@ export namespace SessionPrompt { }) toolcalls[value.toolCallId] = part as MessageV2.ToolPart - const parts = await Session.getParts(assistantMsg.id) + const parts = await MessageV2.parts(assistantMsg.id) const lastThree = parts.slice(-DOOM_LOOP_THRESHOLD) if ( lastThree.length === DOOM_LOOP_THRESHOLD && @@ -1319,7 +1319,7 @@ export namespace SessionPrompt { }) } } - const p = await Session.getParts(assistantMsg.id) + const p = await MessageV2.parts(assistantMsg.id) for (const part of p) { if ( part.type === "tool" && diff --git a/packages/opencode/src/tool/task.ts b/packages/opencode/src/tool/task.ts index 642611f8..312c3bba 100644 --- a/packages/opencode/src/tool/task.ts +++ b/packages/opencode/src/tool/task.ts @@ -35,7 +35,7 @@ export const TaskTool = Tool.define("task", async () => { parentID: ctx.sessionID, title: params.description + ` (@${agent.name} subagent)`, }) - const msg = await Session.getMessage({ sessionID: ctx.sessionID, messageID: ctx.messageID }) + const msg = await MessageV2.get({ sessionID: ctx.sessionID, messageID: ctx.messageID }) if (msg.info.role !== "assistant") throw new Error("Not an assistant message") ctx.metadata({ From 5f7e1e099b2b5786dd94a172c33d6997d54c215f Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Fri, 7 Nov 2025 19:47:53 +0000 Subject: [PATCH 123/218] chore: format code --- packages/opencode/src/session/compaction.ts | 8 ++++++-- packages/opencode/src/session/prompt.ts | 4 +++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/packages/opencode/src/session/compaction.ts b/packages/opencode/src/session/compaction.ts index d54b07ca..67831101 100644 --- a/packages/opencode/src/session/compaction.ts +++ b/packages/opencode/src/session/compaction.ts @@ -287,7 +287,9 @@ export namespace SessionCompaction { }) if (result.shouldRetry) { for (let retry = 1; retry < maxRetries; retry++) { - const lastRetryPart = result.parts.findLast((p): p is MessageV2.RetryPart => p.type === "retry") + const lastRetryPart = result.parts.findLast( + (p): p is MessageV2.RetryPart => p.type === "retry", + ) if (lastRetryPart) { const delayMs = SessionRetry.getRetryDelayInMs(lastRetryPart.error, retry) @@ -336,7 +338,9 @@ export namespace SessionCompaction { if ( !msg.error || (MessageV2.AbortedError.isInstance(msg.error) && - result.parts.some((part): part is MessageV2.TextPart => part.type === "text" && part.text.length > 0)) + result.parts.some( + (part): part is MessageV2.TextPart => part.type === "text" && part.text.length > 0, + )) ) { msg.summary = true Bus.publish(Event.Compacted, { diff --git a/packages/opencode/src/session/prompt.ts b/packages/opencode/src/session/prompt.ts index f9480cd6..3210a08f 100644 --- a/packages/opencode/src/session/prompt.ts +++ b/packages/opencode/src/session/prompt.ts @@ -362,7 +362,9 @@ export namespace SessionPrompt { }) if (result.shouldRetry) { for (let retry = 1; retry < maxRetries; retry++) { - const lastRetryPart = result.parts.findLast((p): p is MessageV2.RetryPart => p.type === "retry") + const lastRetryPart = result.parts.findLast( + (p): p is MessageV2.RetryPart => p.type === "retry", + ) if (lastRetryPart) { const delayMs = SessionRetry.getRetryDelayInMs(lastRetryPart.error, retry) From a96365fd81555a2967524930aeb949009008f9a2 Mon Sep 17 00:00:00 2001 From: Dax Raad Date: Fri, 7 Nov 2025 14:51:37 -0500 Subject: [PATCH 124/218] Add command bar action to rename sessions --- .../opencode/src/cli/cmd/tui/routes/session/index.tsx | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx b/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx index 830d475f..cd3a8f72 100644 --- a/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx +++ b/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx @@ -60,6 +60,7 @@ import type { PromptInfo } from "../../component/prompt/history" import { iife } from "@/util/iife" import { DialogConfirm } from "@tui/ui/dialog-confirm" import { DialogTimeline } from "./dialog-timeline" +import { DialogSessionRename } from "../../component/dialog-session-rename" import { Sidebar } from "./sidebar" import { LANGUAGE_EXTENSIONS } from "@/lsp/language" import parsers from "../../../../../../parsers-config.ts" @@ -191,6 +192,15 @@ export function Session() { const command = useCommandDialog() command.register(() => [ + { + title: "Rename session", + value: "session.rename", + keybind: "session_rename", + category: "Session", + onSelect: (dialog) => { + dialog.replace(() => ) + }, + }, { title: "Jump to message", value: "session.timeline", From 45fabec0919ba3268b6bd0b9566ec98cac0ed3d7 Mon Sep 17 00:00:00 2001 From: Adam <2363879+adamdotdevin@users.noreply.github.com> Date: Fri, 7 Nov 2025 13:54:18 -0600 Subject: [PATCH 125/218] fix(desktop): prompt input on non-chat tabs --- packages/desktop/src/pages/session.tsx | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/packages/desktop/src/pages/session.tsx b/packages/desktop/src/pages/session.tsx index 1c92941d..23d44cfc 100644 --- a/packages/desktop/src/pages/session.tsx +++ b/packages/desktop/src/pages/session.tsx @@ -829,6 +829,15 @@ export default function Page() {
    + +
    + { + inputRef = el + }} + /> +
    +
    From b46c3f2a26b06b2fe7459b082def635654756094 Mon Sep 17 00:00:00 2001 From: Adam <2363879+adamdotdevin@users.noreply.github.com> Date: Fri, 7 Nov 2025 13:54:49 -0600 Subject: [PATCH 126/218] fix(desktop): prompt input issues (wip) --- .../desktop/src/components/prompt-input.tsx | 36 +++++++++---------- 1 file changed, 16 insertions(+), 20 deletions(-) diff --git a/packages/desktop/src/components/prompt-input.tsx b/packages/desktop/src/components/prompt-input.tsx index 15bc54c4..5ae56f82 100644 --- a/packages/desktop/src/components/prompt-input.tsx +++ b/packages/desktop/src/components/prompt-input.tsx @@ -174,10 +174,8 @@ export const PromptInput: Component = (props) => { const addPart = (part: ContentPart) => { const cursorPosition = getCursorPosition(editorRef) - const rawText = session.prompt - .current() - .map((p) => p.content) - .join("") + const prompt = session.prompt.current() + const rawText = prompt.map((p) => p.content).join("") const textBeforeCursor = rawText.substring(0, cursorPosition) const atMatch = textBeforeCursor.match(/@(\S*)$/) @@ -203,7 +201,7 @@ export const PromptInput: Component = (props) => { parts: nextParts, inserted, cursorPositionAfter, - } = session.prompt.current().reduce( + } = prompt.reduce( (acc, item) => { if (acc.inserted) { acc.parts.push({ ...item, start: acc.runningIndex, end: acc.runningIndex + item.content.length }) @@ -262,7 +260,7 @@ export const PromptInput: Component = (props) => { ) if (!inserted) { - const baseParts = session.prompt.current().filter((item) => !(item.type === "text" && item.content === "")) + const baseParts = prompt.filter((item) => !(item.type === "text" && item.content === "")) const runningIndex = baseParts.reduce((sum, p) => sum + p.content.length, 0) const appendedAcc = { parts: [...baseParts] as ContentPart[], runningIndex } if (part.type === "text") { @@ -316,10 +314,8 @@ export const PromptInput: Component = (props) => { const handleSubmit = async (event: Event) => { event.preventDefault() - const text = session.prompt - .current() - .map((part) => part.content) - .join("") + const prompt = session.prompt.current() + const text = prompt.map((part) => part.content).join("") if (text.trim().length === 0) { if (session.working()) abort() return @@ -329,19 +325,17 @@ export const PromptInput: Component = (props) => { if (!existing) { const created = await sdk.client.session.create() existing = created.data ?? undefined + if (existing) navigate(`/session/${existing.id}`) } if (!existing) return - navigate(`/session/${existing.id}`) - if (!session.id) { - // session.layout.setOpenedTabs( - // session.layout.copyTabs("", session.id) - } - session.layout.setActiveTab(undefined) - session.messages.setActive(undefined) - const toAbsolutePath = (path: string) => (path.startsWith("/") ? path : sync.absolute(path)) + // if (!session.id) { + // session.layout.setOpenedTabs( + // session.layout.copyTabs("", session.id) + // } - const attachments = session.prompt.current().filter((part) => part.type === "file") + const toAbsolutePath = (path: string) => (path.startsWith("/") ? path : sync.absolute(path)) + const attachments = prompt.filter((part) => part.type === "file") // const activeFile = local.context.active() // if (activeFile) { @@ -382,9 +376,11 @@ export const PromptInput: Component = (props) => { } }) + session.layout.setActiveTab(undefined) + session.messages.setActive(undefined) session.prompt.set(DEFAULT_PROMPT, 0) - await sdk.client.session.prompt({ + sdk.client.session.prompt({ path: { id: existing.id }, body: { agent: local.agent.current()!.name, From 73cd8a334c146237f177c6a78e6ed37b50ada8b6 Mon Sep 17 00:00:00 2001 From: Aiden Cline <63023139+rekram1-node@users.noreply.github.com> Date: Fri, 7 Nov 2025 11:57:12 -0800 Subject: [PATCH 127/218] rework acp to compensate for changes in Zed IDE (#4050) --- packages/extensions/zed/extension.toml | 36 ++ packages/extensions/zed/icons/opencode.svg | 3 + packages/opencode/src/acp/agent.ts | 718 ++++++++++++--------- packages/opencode/src/acp/session.ts | 60 +- packages/opencode/src/acp/types.ts | 5 +- packages/opencode/src/cli/cmd/acp.ts | 39 +- packages/opencode/src/mcp/index.ts | 38 +- packages/opencode/src/server/server.ts | 30 + packages/sdk/js/src/gen/sdk.gen.ts | 17 + packages/sdk/js/src/gen/types.gen.ts | 36 +- 10 files changed, 621 insertions(+), 361 deletions(-) create mode 100644 packages/extensions/zed/extension.toml create mode 100644 packages/extensions/zed/icons/opencode.svg diff --git a/packages/extensions/zed/extension.toml b/packages/extensions/zed/extension.toml new file mode 100644 index 00000000..34af9621 --- /dev/null +++ b/packages/extensions/zed/extension.toml @@ -0,0 +1,36 @@ +id = "opencode" +name = "OpenCode" +description = "The AI coding agent built for the terminal" +version = "0.1.1" +schema_version = 1 +authors = ["Anomaly"] +repository = "https://github.com/sst/opencode" + +[agent_servers.opencode] +name = "OpenCode" +icon = "./icons/opencode.svg" + +[agent_servers.opencode.targets.darwin-aarch64] +archive = "https://github.com/sst/opencode/releases/latest/download/opencode-darwin-arm64.zip" +cmd = "./opencode" +args = ["acp"] + +[agent_servers.opencode.targets.darwin-x86_64] +archive = "https://github.com/sst/opencode/releases/latest/download/opencode-darwin-x64.zip" +cmd = "./opencode" +args = ["acp"] + +[agent_servers.opencode.targets.linux-aarch64] +archive = "https://github.com/sst/opencode/releases/latest/download/opencode-linux-arm64.zip" +cmd = "./opencode" +args = ["acp"] + +[agent_servers.opencode.targets.linux-x86_64] +archive = "https://github.com/sst/opencode/releases/latest/download/opencode-linux-x64.zip" +cmd = "./opencode" +args = ["acp"] + +[agent_servers.opencode.targets.windows-x86_64] +archive = "https://github.com/sst/opencode/releases/latest/download/opencode-windows-x64.zip" +cmd = "./opencode.exe" +args = ["acp"] diff --git a/packages/extensions/zed/icons/opencode.svg b/packages/extensions/zed/icons/opencode.svg new file mode 100644 index 00000000..fc001e49 --- /dev/null +++ b/packages/extensions/zed/icons/opencode.svg @@ -0,0 +1,3 @@ + + + diff --git a/packages/opencode/src/acp/agent.ts b/packages/opencode/src/acp/agent.ts index 046c8262..b25b6688 100644 --- a/packages/opencode/src/acp/agent.ts +++ b/packages/opencode/src/acp/agent.ts @@ -20,299 +20,321 @@ import { } from "@agentclientprotocol/sdk" import { Log } from "../util/log" import { ACPSessionManager } from "./session" -import type { ACPConfig } from "./types" +import type { ACPConfig, ACPSessionState } from "./types" import { Provider } from "../provider/provider" -import { SessionPrompt } from "../session/prompt" import { Installation } from "@/installation" -import { SessionLock } from "@/session/lock" -import { Bus } from "@/bus" import { MessageV2 } from "@/session/message-v2" -import { Storage } from "@/storage/storage" -import { Command } from "@/command" -import { Agent as Agents } from "@/agent/agent" -import { Permission } from "@/permission" -import { SessionCompaction } from "@/session/compaction" import { Config } from "@/config/config" import { MCP } from "@/mcp" import { Todo } from "@/session/todo" import { z } from "zod" import { LoadAPIKeyError } from "ai" +import type { OpencodeClient } from "@opencode-ai/sdk" export namespace ACP { const log = Log.create({ service: "acp-agent" }) - export async function init() { - const model = await defaultModel({}) + export async function init({ sdk }: { sdk: OpencodeClient }) { + const model = await defaultModel({ sdk }) return { - create: (connection: AgentSideConnection, config: ACPConfig) => { - if (!config.defaultModel) { - config.defaultModel = model + create: (connection: AgentSideConnection, fullConfig: ACPConfig) => { + if (!fullConfig.defaultModel) { + fullConfig.defaultModel = model } - return new Agent(connection, config) + return new Agent(connection, fullConfig) }, } } export class Agent implements ACPAgent { - private sessionManager = new ACPSessionManager() private connection: AgentSideConnection private config: ACPConfig + private sdk: OpencodeClient + private sessionManager - constructor(connection: AgentSideConnection, config: ACPConfig = {}) { + constructor(connection: AgentSideConnection, config: ACPConfig) { this.connection = connection this.config = config - this.setupEventSubscriptions() + this.sdk = config.sdk + this.sessionManager = new ACPSessionManager(this.sdk) } - private setupEventSubscriptions() { + private setupEventSubscriptions(session: ACPSessionState) { + const sessionId = session.id + const directory = session.cwd + const options: PermissionOption[] = [ { optionId: "once", kind: "allow_once", name: "Allow once" }, { optionId: "always", kind: "allow_always", name: "Always allow" }, { optionId: "reject", kind: "reject_once", name: "Reject" }, ] - Bus.subscribe(Permission.Event.Updated, async (event) => { - const acpSession = this.sessionManager.get(event.properties.sessionID) - if (!acpSession) return - try { - const permission = event.properties - const res = await this.connection - .requestPermission({ - sessionId: acpSession.id, - toolCall: { - toolCallId: permission.callID ?? permission.id, - status: "pending", - title: permission.title, - rawInput: permission.metadata, - kind: toToolKind(permission.type), - locations: toLocations(permission.type, permission.metadata), - }, - options, - }) - .catch((error) => { - log.error("failed to request permission from ACP", { - error, - permissionID: permission.id, - sessionID: permission.sessionID, - }) - Permission.respond({ - sessionID: permission.sessionID, - permissionID: permission.id, - response: "reject", - }) - return - }) - if (!res) return - if (res.outcome.outcome !== "selected") { - Permission.respond({ - sessionID: permission.sessionID, - permissionID: permission.id, - response: "reject", - }) - return - } - Permission.respond({ - sessionID: permission.sessionID, - permissionID: permission.id, - response: res.outcome.optionId as "once" | "always" | "reject", - }) - } catch (err) { - if (!(err instanceof Permission.RejectedError)) { - log.error("unexpected error when handling permission", { error: err }) - throw err - } - } - }) - - Bus.subscribe(MessageV2.Event.PartUpdated, async (event) => { - const props = event.properties - const { part } = props - const acpSession = this.sessionManager.get(part.sessionID) - if (!acpSession) return - - const message = await Storage.read([ - "message", - part.sessionID, - part.messageID, - ]).catch(() => undefined) - if (!message || message.role !== "assistant") return - - if (part.type === "tool") { - switch (part.state.status) { - case "pending": - await this.connection - .sessionUpdate({ - sessionId: acpSession.id, - update: { - sessionUpdate: "tool_call", - toolCallId: part.callID, - title: part.tool, - kind: toToolKind(part.tool), - status: "pending", - locations: [], - rawInput: {}, - }, - }) - .catch((err) => { - log.error("failed to send tool pending to ACP", { error: err }) - }) - break - case "running": - await this.connection - .sessionUpdate({ - sessionId: acpSession.id, - update: { - sessionUpdate: "tool_call_update", - toolCallId: part.callID, - status: "in_progress", - locations: toLocations(part.tool, part.state.input), - rawInput: part.state.input, - }, - }) - .catch((err) => { - log.error("failed to send tool in_progress to ACP", { error: err }) - }) - break - case "completed": - const kind = toToolKind(part.tool) - const content: ToolCallContent[] = [ - { - type: "content", - content: { - type: "text", - text: part.state.output, - }, - }, - ] - - if (kind === "edit") { - const input = part.state.input - const filePath = typeof input["filePath"] === "string" ? input["filePath"] : "" - const oldText = typeof input["oldString"] === "string" ? input["oldString"] : "" - const newText = - typeof input["newString"] === "string" - ? input["newString"] - : typeof input["content"] === "string" - ? input["content"] - : "" - content.push({ - type: "diff", - path: filePath, - oldText, - newText, - }) - } - - if (part.tool === "todowrite") { - const parsedTodos = z.array(Todo.Info).safeParse(JSON.parse(part.state.output)) - if (parsedTodos.success) { - await this.connection - .sessionUpdate({ - sessionId: acpSession.id, - update: { - sessionUpdate: "plan", - entries: parsedTodos.data.map((todo) => { - const status: PlanEntry["status"] = - todo.status === "cancelled" - ? "completed" - : (todo.status as PlanEntry["status"]) - return { - priority: "medium", - status, - content: todo.content, - } - }), + this.config.sdk.event.subscribe({ query: { directory } }).then(async (events) => { + for await (const event of events.stream) { + switch (event.type) { + case "permission.updated": + try { + const permission = event.properties + const res = await this.connection + .requestPermission({ + sessionId, + toolCall: { + toolCallId: permission.callID ?? permission.id, + status: "pending", + title: permission.title, + rawInput: permission.metadata, + kind: toToolKind(permission.type), + locations: toLocations(permission.type, permission.metadata), + }, + options, + }) + .catch(async (error) => { + log.error("failed to request permission from ACP", { + error, + permissionID: permission.id, + sessionID: permission.sessionID, + }) + await this.config.sdk.postSessionIdPermissionsPermissionId({ + path: { id: permission.sessionID, permissionID: permission.id }, + body: { + response: "reject", }, + query: { directory }, }) - .catch((err) => { - log.error("failed to send session update for todo", { error: err }) - }) - } else { - log.error("failed to parse todo output", { error: parsedTodos.error }) + return + }) + if (!res) return + if (res.outcome.outcome !== "selected") { + await this.config.sdk.postSessionIdPermissionsPermissionId({ + path: { id: permission.sessionID, permissionID: permission.id }, + body: { + response: "reject", + }, + query: { directory }, + }) + return } + await this.config.sdk.postSessionIdPermissionsPermissionId({ + path: { id: permission.sessionID, permissionID: permission.id }, + body: { + response: res.outcome.optionId as "once" | "always" | "reject", + }, + query: { directory }, + }) + } catch (err) { + log.error("unexpected error when handling permission", { error: err }) + } finally { + break } - await this.connection - .sessionUpdate({ - sessionId: acpSession.id, - update: { - sessionUpdate: "tool_call_update", - toolCallId: part.callID, - status: "completed", - kind, - content, - title: part.state.title, - rawOutput: { - output: part.state.output, - metadata: part.state.metadata, + case "message.part.updated": + log.info("message part updated", { event: event.properties }) + try { + const props = event.properties + const { part } = props + + const message = await this.config.sdk.session + .message({ + throwOnError: true, + path: { + id: part.sessionID, + messageID: part.messageID, }, - }, - }) - .catch((err) => { - log.error("failed to send tool completed to ACP", { error: err }) - }) - break - case "error": - await this.connection - .sessionUpdate({ - sessionId: acpSession.id, - update: { - sessionUpdate: "tool_call_update", - toolCallId: part.callID, - status: "failed", - content: [ - { - type: "content", - content: { - type: "text", - text: part.state.error, + query: { directory }, + }) + .then((x) => x.data) + .catch((err) => { + log.error("unexpected error when fetching message", { error: err }) + return undefined + }) + + if (!message || message.info.role !== "assistant") return + + if (part.type === "tool") { + switch (part.state.status) { + case "pending": + await this.connection + .sessionUpdate({ + sessionId, + update: { + sessionUpdate: "tool_call", + toolCallId: part.callID, + title: part.tool, + kind: toToolKind(part.tool), + status: "pending", + locations: [], + rawInput: {}, + }, + }) + .catch((err) => { + log.error("failed to send tool pending to ACP", { error: err }) + }) + break + case "running": + await this.connection + .sessionUpdate({ + sessionId, + update: { + sessionUpdate: "tool_call_update", + toolCallId: part.callID, + status: "in_progress", + locations: toLocations(part.tool, part.state.input), + rawInput: part.state.input, + }, + }) + .catch((err) => { + log.error("failed to send tool in_progress to ACP", { error: err }) + }) + break + case "completed": + const kind = toToolKind(part.tool) + const content: ToolCallContent[] = [ + { + type: "content", + content: { + type: "text", + text: part.state.output, + }, }, - }, - ], - rawOutput: { - error: part.state.error, - }, - }, - }) - .catch((err) => { - log.error("failed to send tool error to ACP", { error: err }) - }) - break - } - } else if (part.type === "text") { - const delta = props.delta - if (delta && part.synthetic !== true) { - await this.connection - .sessionUpdate({ - sessionId: acpSession.id, - update: { - sessionUpdate: "agent_message_chunk", - content: { - type: "text", - text: delta, - }, - }, - }) - .catch((err) => { - log.error("failed to send text to ACP", { error: err }) - }) - } - } else if (part.type === "reasoning") { - const delta = props.delta - if (delta) { - await this.connection - .sessionUpdate({ - sessionId: acpSession.id, - update: { - sessionUpdate: "agent_thought_chunk", - content: { - type: "text", - text: delta, - }, - }, - }) - .catch((err) => { - log.error("failed to send reasoning to ACP", { error: err }) - }) + ] + + if (kind === "edit") { + const input = part.state.input + const filePath = + typeof input["filePath"] === "string" ? input["filePath"] : "" + const oldText = + typeof input["oldString"] === "string" ? input["oldString"] : "" + const newText = + typeof input["newString"] === "string" + ? input["newString"] + : typeof input["content"] === "string" + ? input["content"] + : "" + content.push({ + type: "diff", + path: filePath, + oldText, + newText, + }) + } + + if (part.tool === "todowrite") { + const parsedTodos = z + .array(Todo.Info) + .safeParse(JSON.parse(part.state.output)) + if (parsedTodos.success) { + await this.connection + .sessionUpdate({ + sessionId, + update: { + sessionUpdate: "plan", + entries: parsedTodos.data.map((todo) => { + const status: PlanEntry["status"] = + todo.status === "cancelled" + ? "completed" + : (todo.status as PlanEntry["status"]) + return { + priority: "medium", + status, + content: todo.content, + } + }), + }, + }) + .catch((err) => { + log.error("failed to send session update for todo", { error: err }) + }) + } else { + log.error("failed to parse todo output", { error: parsedTodos.error }) + } + } + + await this.connection + .sessionUpdate({ + sessionId, + update: { + sessionUpdate: "tool_call_update", + toolCallId: part.callID, + status: "completed", + kind, + content, + title: part.state.title, + rawOutput: { + output: part.state.output, + metadata: part.state.metadata, + }, + }, + }) + .catch((err) => { + log.error("failed to send tool completed to ACP", { error: err }) + }) + break + case "error": + await this.connection + .sessionUpdate({ + sessionId, + update: { + sessionUpdate: "tool_call_update", + toolCallId: part.callID, + status: "failed", + content: [ + { + type: "content", + content: { + type: "text", + text: part.state.error, + }, + }, + ], + rawOutput: { + error: part.state.error, + }, + }, + }) + .catch((err) => { + log.error("failed to send tool error to ACP", { error: err }) + }) + break + } + } else if (part.type === "text") { + const delta = props.delta + if (delta && part.synthetic !== true) { + await this.connection + .sessionUpdate({ + sessionId, + update: { + sessionUpdate: "agent_message_chunk", + content: { + type: "text", + text: delta, + }, + }, + }) + .catch((err) => { + log.error("failed to send text to ACP", { error: err }) + }) + } + } else if (part.type === "reasoning") { + const delta = props.delta + if (delta) { + await this.connection + .sessionUpdate({ + sessionId, + update: { + sessionUpdate: "agent_thought_chunk", + content: { + type: "text", + text: delta, + }, + }, + }) + .catch((err) => { + log.error("failed to send reasoning to ACP", { error: err }) + }) + } + } + } finally { + break + } } } }) @@ -364,19 +386,26 @@ export namespace ACP { } async newSession(params: NewSessionRequest) { + const directory = params.cwd try { - const model = await defaultModel(this.config) - const session = await this.sessionManager.create(params.cwd, params.mcpServers, model) + const model = await defaultModel(this.config, directory) + + // Store ACP session state + const state = await this.sessionManager.create(params.cwd, params.mcpServers, model) + const sessionId = state.id + + log.info("creating_session", { sessionId, mcpServers: params.mcpServers.length }) - log.info("creating_session", { mcpServers: params.mcpServers.length }) const load = await this.loadSession({ - cwd: params.cwd, + cwd: directory, mcpServers: params.mcpServers, - sessionId: session.id, + sessionId, }) + this.setupEventSubscriptions(state) + return { - sessionId: session.id, + sessionId, models: load.models, modes: load.modes, _meta: {}, @@ -393,26 +422,47 @@ export namespace ACP { } async loadSession(params: LoadSessionRequest) { - const model = await defaultModel(this.config) + const directory = params.cwd + const model = await defaultModel(this.config, directory) const sessionId = params.sessionId - const providers = await Provider.list() - const entries = Object.entries(providers).sort((a, b) => { - const nameA = a[1].info.name.toLowerCase() - const nameB = b[1].info.name.toLowerCase() + const providers = await this.sdk.config + .providers({ throwOnError: true, query: { directory } }) + .then((x) => x.data.providers) + const entries = providers.sort((a, b) => { + const nameA = a.name.toLowerCase() + const nameB = b.name.toLowerCase() if (nameA < nameB) return -1 if (nameA > nameB) return 1 return 0 }) - const availableModels = entries.flatMap(([providerID, provider]) => { - const models = Provider.sort(Object.values(provider.info.models)) + const availableModels = entries.flatMap((provider) => { + const models = Provider.sort(Object.values(provider.models)) return models.map((model) => ({ - modelId: `${providerID}/${model.id}`, - name: `${provider.info.name}/${model.name}`, + modelId: `${provider.id}/${model.id}`, + name: `${provider.name}/${model.name}`, })) }) - const availableCommands = (await Command.list()).map((command) => ({ + const agents = await this.config.sdk.app + .agents({ + throwOnError: true, + query: { + directory, + }, + }) + .then((resp) => resp.data) + + const commands = await this.config.sdk.command + .list({ + throwOnError: true, + query: { + directory, + }, + }) + .then((resp) => resp.data) + + const availableCommands = commands.map((command) => ({ name: command.name, description: command.description ?? "", })) @@ -423,7 +473,7 @@ export namespace ACP { description: "compact the session", }) - const availableModes = (await Agents.list()) + const availableModes = agents .filter((agent) => agent.mode !== "subagent") .map((agent) => ({ id: agent.name, @@ -459,7 +509,18 @@ export namespace ACP { await Promise.all( Object.entries(mcpServers).map(async ([key, mcp]) => { - await MCP.add(key, mcp) + await this.sdk.mcp + .add({ + throwOnError: true, + query: { directory }, + body: { + name: key, + config: mcp, + }, + }) + .catch((error) => { + log.error("failed to add mcp server", { name: key, error }) + }) }), ) @@ -489,12 +550,8 @@ export namespace ACP { async setSessionModel(params: SetSessionModelRequest) { const session = this.sessionManager.get(params.sessionId) - if (!session) { - throw new Error(`Session not found: ${params.sessionId}`) - } - const parsed = Provider.parseModel(params.modelId) - const model = await Provider.getModel(parsed.providerID, parsed.modelID) + const model = Provider.parseModel(params.modelId) this.sessionManager.setModel(session.id, { providerID: model.providerID, @@ -507,31 +564,32 @@ export namespace ACP { } async setSessionMode(params: SetSessionModeRequest): Promise { - const session = this.sessionManager.get(params.sessionId) - if (!session) { - throw new Error(`Session not found: ${params.sessionId}`) - } - await Agents.get(params.modeId).then((agent) => { - if (!agent) throw new Error(`Agent not found: ${params.modeId}`) - }) + this.sessionManager.get(params.sessionId) + await this.config.sdk.app + .agents({ throwOnError: true }) + .then((x) => x.data) + .then((agent) => { + if (!agent) throw new Error(`Agent not found: ${params.modeId}`) + }) this.sessionManager.setMode(params.sessionId, params.modeId) } async prompt(params: PromptRequest) { const sessionID = params.sessionId - const acpSession = this.sessionManager.get(sessionID) - if (!acpSession) { - throw new Error(`Session not found: ${sessionID}`) - } + const session = this.sessionManager.get(sessionID) + const directory = session.cwd - const current = acpSession.model - const model = current ?? (await defaultModel(this.config)) + const current = session.model + const model = current ?? (await defaultModel(this.config, directory)) if (!current) { - this.sessionManager.setModel(acpSession.id, model) + this.sessionManager.setModel(session.id, model) } - const agent = acpSession.modeId ?? "build" + const agent = session.modeId ?? "build" - const parts: SessionPrompt.PromptInput["parts"] = [] + const parts: Array< + | { type: "text"; text: string } + | { type: "file"; url: string; filename: string; mime: string } + > = [] for (const part of params.prompt) { switch (part.type) { case "text": @@ -545,12 +603,14 @@ export namespace ACP { parts.push({ type: "file", url: `data:${part.mimeType};base64,${part.data}`, + filename: "image", mime: part.mimeType, }) } else if (part.uri && part.uri.startsWith("http:")) { parts.push({ type: "file", url: part.uri, + filename: "image", mime: part.mimeType, }) } @@ -581,7 +641,7 @@ export namespace ACP { const cmd = (() => { const text = parts - .filter((p) => p.type === "text") + .filter((p): p is { type: "text"; text: string } => p.type === "text") .map((p) => p.text) .join("") .trim() @@ -598,36 +658,50 @@ export namespace ACP { } if (!cmd) { - await SessionPrompt.prompt({ - sessionID, - model: { - providerID: model.providerID, - modelID: model.modelID, + await this.sdk.session.prompt({ + path: { id: sessionID }, + body: { + model: { + providerID: model.providerID, + modelID: model.modelID, + }, + parts, + agent, + }, + query: { + directory, }, - parts, - agent, }) return done } - const command = await Command.get(cmd.name) + const command = await this.config.sdk.command + .list({ throwOnError: true, query: { directory } }) + .then((x) => x.data.find((c) => c.name === cmd.name)) if (command) { - await SessionPrompt.command({ - sessionID, - command: command.name, - arguments: cmd.args, - model: model.providerID + "/" + model.modelID, - agent, + await this.sdk.session.command({ + path: { id: sessionID }, + body: { + command: command.name, + arguments: cmd.args, + model: model.providerID + "/" + model.modelID, + agent, + }, + query: { + directory, + }, }) return done } switch (cmd.name) { case "compact": - await SessionCompaction.run({ - sessionID, - providerID: model.providerID, - modelID: model.modelID, + await this.config.sdk.session.summarize({ + path: { id: sessionID }, + throwOnError: true, + query: { + directory, + }, }) break } @@ -636,7 +710,14 @@ export namespace ACP { } async cancel(params: CancelNotification) { - SessionLock.abort(params.sessionId) + const session = this.sessionManager.get(params.sessionId) + await this.config.sdk.session.abort({ + path: { id: params.sessionId }, + throwOnError: true, + query: { + directory: session.cwd, + }, + }) } } @@ -687,12 +768,15 @@ export namespace ACP { } } - async function defaultModel(config: ACPConfig) { + async function defaultModel(config: ACPConfig, cwd?: string) { + const sdk = config.sdk const configured = config.defaultModel if (configured) return configured - const model = await Config.get() - .then((cfg) => { + const model = await sdk.config + .get({ throwOnError: true, query: { directory: cwd } }) + .then((resp) => { + const cfg = resp.data if (!cfg.model) return undefined const parsed = Provider.parseModel(cfg.model) return { diff --git a/packages/opencode/src/acp/session.ts b/packages/opencode/src/acp/session.ts index d3ab73d2..eb9dd522 100644 --- a/packages/opencode/src/acp/session.ts +++ b/packages/opencode/src/acp/session.ts @@ -1,66 +1,74 @@ -import type { McpServer } from "@agentclientprotocol/sdk" -import { Session } from "../session" -import { Provider } from "../provider/provider" +import { RequestError, type McpServer } from "@agentclientprotocol/sdk" import type { ACPSessionState } from "./types" +import { Log } from "@/util/log" +import type { OpencodeClient } from "@opencode-ai/sdk" + +const log = Log.create({ service: "acp-session-manager" }) export class ACPSessionManager { private sessions = new Map() + private sdk: OpencodeClient + + constructor(sdk: OpencodeClient) { + this.sdk = sdk + } async create( cwd: string, mcpServers: McpServer[], model?: ACPSessionState["model"], ): Promise { - const session = await Session.create({ title: `ACP Session ${crypto.randomUUID()}` }) + const session = await this.sdk.session + .create({ + body: { + title: `ACP Session ${crypto.randomUUID()}`, + }, + query: { + directory: cwd, + }, + throwOnError: true, + }) + .then((x) => x.data) + const sessionId = session.id - const resolvedModel = model ?? (await Provider.defaultModel()) + const resolvedModel = model const state: ACPSessionState = { id: sessionId, - parentId: session.parentID, cwd, mcpServers, createdAt: new Date(), model: resolvedModel, } + log.info("creating_session", { state }) this.sessions.set(sessionId, state) return state } - get(sessionId: string) { - return this.sessions.get(sessionId) - } - - async remove(sessionId: string) { - const state = this.sessions.get(sessionId) - if (!state) return - - await Session.remove(sessionId).catch(() => {}) - this.sessions.delete(sessionId) - } - - has(sessionId: string) { - return this.sessions.has(sessionId) + get(sessionId: string): ACPSessionState { + const session = this.sessions.get(sessionId) + if (!session) { + log.error("session not found", { sessionId }) + throw RequestError.invalidParams(JSON.stringify({ error: `Session not found: ${sessionId}` })) + } + return session } getModel(sessionId: string) { - const session = this.sessions.get(sessionId) - if (!session) return + const session = this.get(sessionId) return session.model } setModel(sessionId: string, model: ACPSessionState["model"]) { - const session = this.sessions.get(sessionId) - if (!session) return + const session = this.get(sessionId) session.model = model this.sessions.set(sessionId, session) return session } setMode(sessionId: string, modeId: string) { - const session = this.sessions.get(sessionId) - if (!session) return + const session = this.get(sessionId) session.modeId = modeId this.sessions.set(sessionId, session) return session diff --git a/packages/opencode/src/acp/types.ts b/packages/opencode/src/acp/types.ts index 119b335c..8507228e 100644 --- a/packages/opencode/src/acp/types.ts +++ b/packages/opencode/src/acp/types.ts @@ -1,12 +1,12 @@ import type { McpServer } from "@agentclientprotocol/sdk" +import type { OpencodeClient } from "@opencode-ai/sdk" export interface ACPSessionState { id: string - parentId?: string cwd: string mcpServers: McpServer[] createdAt: Date - model: { + model?: { providerID: string modelID: string } @@ -14,6 +14,7 @@ export interface ACPSessionState { } export interface ACPConfig { + sdk: OpencodeClient defaultModel?: { providerID: string modelID: string diff --git a/packages/opencode/src/cli/cmd/acp.ts b/packages/opencode/src/cli/cmd/acp.ts index 77ef0c60..7d27f941 100644 --- a/packages/opencode/src/cli/cmd/acp.ts +++ b/packages/opencode/src/cli/cmd/acp.ts @@ -3,6 +3,8 @@ import { bootstrap } from "../bootstrap" import { cmd } from "./cmd" import { AgentSideConnection, ndJsonStream } from "@agentclientprotocol/sdk" import { ACP } from "@/acp/agent" +import { Server } from "@/server/server" +import { createOpencodeClient } from "@opencode-ai/sdk" const log = Log.create({ service: "acp-command" }) @@ -17,15 +19,34 @@ export const AcpCommand = cmd({ command: "acp", describe: "Start ACP (Agent Client Protocol) server", builder: (yargs) => { - return yargs.option("cwd", { - describe: "working directory", - type: "string", - default: process.cwd(), - }) + return yargs + .option("cwd", { + describe: "working directory", + type: "string", + default: process.cwd(), + }) + .option("port", { + type: "number", + describe: "port to listen on", + default: 0, + }) + .option("hostname", { + type: "string", + describe: "hostname to listen on", + default: "127.0.0.1", + }) }, - handler: async (opts) => { - if (opts.cwd) process.chdir(opts["cwd"]) + handler: async (args) => { await bootstrap(process.cwd(), async () => { + const server = Server.listen({ + port: args.port, + hostname: args.hostname, + }) + + const sdk = createOpencodeClient({ + baseUrl: `http://${server.hostname}:${server.port}`, + }) + const input = new WritableStream({ write(chunk) { return new Promise((resolve, reject) => { @@ -50,10 +71,10 @@ export const AcpCommand = cmd({ }) const stream = ndJsonStream(input, output) - const agent = await ACP.init() + const agent = await ACP.init({ sdk }) new AgentSideConnection((conn) => { - return agent.create(conn, {}) + return agent.create(conn, { sdk }) }, stream) log.info("setup connection") diff --git a/packages/opencode/src/mcp/index.ts b/packages/opencode/src/mcp/index.ts index fbc88703..eddd1924 100644 --- a/packages/opencode/src/mcp/index.ts +++ b/packages/opencode/src/mcp/index.ts @@ -92,13 +92,28 @@ export namespace MCP { export async function add(name: string, mcp: Config.Mcp) { const s = await state() const result = await create(name, mcp) - if (!result) return + if (!result) { + const status = { + status: "failed" as const, + error: "unknown error", + } + s.status[name] = status + return { + status, + } + } if (!result.mcpClient) { s.status[name] = result.status - return + return { + status: s.status, + } } s.clients[name] = result.mcpClient s.status[name] = result.status + + return { + status: s.status, + } } async function create(key: string, mcp: Config.Mcp) { @@ -207,8 +222,12 @@ export namespace MCP { } } - const result = await withTimeout(mcpClient.tools(), mcp.timeout ?? 5000).catch(() => {}) + const result = await withTimeout(mcpClient.tools(), mcp.timeout ?? 5000).catch((err) => { + log.error("create() failed to get tools from client", { key, error: err }) + return undefined + }) if (!result) { + log.info("create() tools() returned nothing, closing client", { key }) await mcpClient.close().catch((error) => { log.error("Failed to close MCP client", { error, @@ -227,6 +246,7 @@ export namespace MCP { } } + log.info("create() successfully created client", { key, toolCount: Object.keys(result).length }) return { mcpClient, status, @@ -238,13 +258,18 @@ export namespace MCP { } export async function clients() { - return state().then((state) => state.clients) + const s = await state() + log.info("clients() called", { clientCount: Object.keys(s.clients).length }) + return s.clients } export async function tools() { const result: Record = {} const s = await state() - for (const [clientName, client] of Object.entries(await clients())) { + log.info("tools() called", { clientCount: Object.keys(s.clients).length }) + const clientsSnapshot = await clients() + for (const [clientName, client] of Object.entries(clientsSnapshot)) { + log.info("tools() fetching tools for client", { clientName }) const tools = await client.tools().catch((e) => { log.error("failed to get tools", { clientName, error: e.message }) const failedStatus = { @@ -255,14 +280,17 @@ export namespace MCP { delete s.clients[clientName] }) if (!tools) { + log.info("tools() no tools returned for client", { clientName }) continue } + log.info("tools() got tools for client", { clientName, toolCount: Object.keys(tools).length }) for (const [toolName, tool] of Object.entries(tools)) { const sanitizedClientName = clientName.replace(/[^a-zA-Z0-9_-]/g, "_") const sanitizedToolName = toolName.replace(/[^a-zA-Z0-9_-]/g, "_") result[sanitizedClientName + "_" + sanitizedToolName] = tool } } + log.info("tools() final result", { toolCount: Object.keys(result).length }) return result } } diff --git a/packages/opencode/src/server/server.ts b/packages/opencode/src/server/server.ts index 53d8b4dd..bfe804ae 100644 --- a/packages/opencode/src/server/server.ts +++ b/packages/opencode/src/server/server.ts @@ -1359,6 +1359,36 @@ export namespace Server { return c.json(await MCP.status()) }, ) + .post( + "/mcp", + describeRoute({ + description: "Add MCP server dynamically", + operationId: "mcp.add", + responses: { + 200: { + description: "MCP server added successfully", + content: { + "application/json": { + schema: resolver(z.record(z.string(), MCP.Status)), + }, + }, + }, + ...errors(400), + }, + }), + validator( + "json", + z.object({ + name: z.string(), + config: Config.Mcp, + }), + ), + async (c) => { + const { name, config } = c.req.valid("json") + const result = await MCP.add(name, config) + return c.json(result.status) + }, + ) .get( "/lsp", describeRoute({ diff --git a/packages/sdk/js/src/gen/sdk.gen.ts b/packages/sdk/js/src/gen/sdk.gen.ts index 1a54da8f..f902d91a 100644 --- a/packages/sdk/js/src/gen/sdk.gen.ts +++ b/packages/sdk/js/src/gen/sdk.gen.ts @@ -106,6 +106,9 @@ import type { AppAgentsResponses, McpStatusData, McpStatusResponses, + McpAddData, + McpAddResponses, + McpAddErrors, LspStatusData, LspStatusResponses, FormatterStatusData, @@ -764,6 +767,20 @@ class Mcp extends _HeyApiClient { ...options, }) } + + /** + * Add MCP server dynamically + */ + public add(options?: Options) { + return (options?.client ?? this._client).post({ + url: "/mcp", + ...options, + headers: { + "Content-Type": "application/json", + ...options?.headers, + }, + }) + } } class Lsp extends _HeyApiClient { diff --git a/packages/sdk/js/src/gen/types.gen.ts b/packages/sdk/js/src/gen/types.gen.ts index 5f565df5..2a0df302 100644 --- a/packages/sdk/js/src/gen/types.gen.ts +++ b/packages/sdk/js/src/gen/types.gen.ts @@ -1979,9 +1979,9 @@ export type SessionMessagesData = { */ id: string } - query?: { + query: { directory?: string - limit?: number + limit: number } url: "/session/{id}/message" } @@ -2552,6 +2552,38 @@ export type McpStatusResponses = { export type McpStatusResponse = McpStatusResponses[keyof McpStatusResponses] +export type McpAddData = { + body?: { + name: string + config: McpLocalConfig | McpRemoteConfig + } + path?: never + query?: { + directory?: string + } + url: "/mcp" +} + +export type McpAddErrors = { + /** + * Bad request + */ + 400: BadRequestError +} + +export type McpAddError = McpAddErrors[keyof McpAddErrors] + +export type McpAddResponses = { + /** + * MCP server added successfully + */ + 200: { + [key: string]: McpStatus + } +} + +export type McpAddResponse = McpAddResponses[keyof McpAddResponses] + export type LspStatusData = { body?: never path?: never From b374a6cac950759eaf14e668e8517bb7abfc32d5 Mon Sep 17 00:00:00 2001 From: Adam <2363879+adamdotdevin@users.noreply.github.com> Date: Fri, 7 Nov 2025 13:58:47 -0600 Subject: [PATCH 128/218] fix(desktop): stop icon size --- packages/ui/src/components/icon.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ui/src/components/icon.tsx b/packages/ui/src/components/icon.tsx index b61a54fe..27a43e51 100644 --- a/packages/ui/src/components/icon.tsx +++ b/packages/ui/src/components/icon.tsx @@ -150,7 +150,7 @@ const newIcons = { "code-lines": ``, "square-arrow-top-right": ``, "circle-ban-sign": ``, - stop: ``, + stop: ``, enter: ``, "layout-left": ``, "layout-right": ``, From 090d27df11a718cff3453a38da22d8a5eb405631 Mon Sep 17 00:00:00 2001 From: Aiden Cline Date: Fri, 7 Nov 2025 13:59:18 -0600 Subject: [PATCH 129/218] chore: rm debug logs --- packages/opencode/src/mcp/index.ts | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/packages/opencode/src/mcp/index.ts b/packages/opencode/src/mcp/index.ts index eddd1924..149cd76f 100644 --- a/packages/opencode/src/mcp/index.ts +++ b/packages/opencode/src/mcp/index.ts @@ -223,11 +223,10 @@ export namespace MCP { } const result = await withTimeout(mcpClient.tools(), mcp.timeout ?? 5000).catch((err) => { - log.error("create() failed to get tools from client", { key, error: err }) + log.error("failed to get tools from client", { key, error: err }) return undefined }) if (!result) { - log.info("create() tools() returned nothing, closing client", { key }) await mcpClient.close().catch((error) => { log.error("Failed to close MCP client", { error, @@ -258,18 +257,14 @@ export namespace MCP { } export async function clients() { - const s = await state() - log.info("clients() called", { clientCount: Object.keys(s.clients).length }) - return s.clients + return state().then((state) => state.clients) } export async function tools() { const result: Record = {} const s = await state() - log.info("tools() called", { clientCount: Object.keys(s.clients).length }) const clientsSnapshot = await clients() for (const [clientName, client] of Object.entries(clientsSnapshot)) { - log.info("tools() fetching tools for client", { clientName }) const tools = await client.tools().catch((e) => { log.error("failed to get tools", { clientName, error: e.message }) const failedStatus = { @@ -280,17 +275,14 @@ export namespace MCP { delete s.clients[clientName] }) if (!tools) { - log.info("tools() no tools returned for client", { clientName }) continue } - log.info("tools() got tools for client", { clientName, toolCount: Object.keys(tools).length }) for (const [toolName, tool] of Object.entries(tools)) { const sanitizedClientName = clientName.replace(/[^a-zA-Z0-9_-]/g, "_") const sanitizedToolName = toolName.replace(/[^a-zA-Z0-9_-]/g, "_") result[sanitizedClientName + "_" + sanitizedToolName] = tool } } - log.info("tools() final result", { toolCount: Object.keys(result).length }) return result } } From b3c6d0b08a571796e4a9ecce798408b15a525df1 Mon Sep 17 00:00:00 2001 From: Aiden Cline Date: Fri, 7 Nov 2025 14:10:20 -0600 Subject: [PATCH 130/218] fix formatters --- packages/opencode/src/format/index.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/opencode/src/format/index.ts b/packages/opencode/src/format/index.ts index ebcc7909..e307496c 100644 --- a/packages/opencode/src/format/index.ts +++ b/packages/opencode/src/format/index.ts @@ -91,7 +91,6 @@ export namespace Format { export function init() { log.info("init") - return Bus.subscribe(File.Event.Edited, async (payload) => { const file = payload.properties.file log.info("formatting", { file }) From b5a035ceab79ce55f565823910d7c561f6ab7920 Mon Sep 17 00:00:00 2001 From: Sebastian Herrlinger Date: Fri, 7 Nov 2025 21:38:30 +0100 Subject: [PATCH 131/218] upgrade to opentui to fix disappearing content (again) and sticky scroll --- bun.lock | 20 ++++++++++---------- packages/opencode/package.json | 4 ++-- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/bun.lock b/bun.lock index c55d2821..35071c6e 100644 --- a/bun.lock +++ b/bun.lock @@ -185,8 +185,8 @@ "@opencode-ai/plugin": "workspace:*", "@opencode-ai/script": "workspace:*", "@opencode-ai/sdk": "workspace:*", - "@opentui/core": "0.0.0-20251106-788e97e4", - "@opentui/solid": "0.0.0-20251106-788e97e4", + "@opentui/core": "0.1.38", + "@opentui/solid": "0.1.38", "@parcel/watcher": "2.5.1", "@pierre/precision-diffs": "catalog:", "@solid-primitives/event-bus": "1.1.2", @@ -962,21 +962,21 @@ "@opentelemetry/api": ["@opentelemetry/api@1.9.0", "", {}, "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg=="], - "@opentui/core": ["@opentui/core@0.0.0-20251106-788e97e4", "", { "dependencies": { "bun-ffi-structs": "^0.1.0", "jimp": "1.6.0", "yoga-layout": "3.2.1" }, "optionalDependencies": { "@dimforge/rapier2d-simd-compat": "^0.17.3", "@opentui/core-darwin-arm64": "0.0.0-20251106-788e97e4", "@opentui/core-darwin-x64": "0.0.0-20251106-788e97e4", "@opentui/core-linux-arm64": "0.0.0-20251106-788e97e4", "@opentui/core-linux-x64": "0.0.0-20251106-788e97e4", "@opentui/core-win32-arm64": "0.0.0-20251106-788e97e4", "@opentui/core-win32-x64": "0.0.0-20251106-788e97e4", "bun-webgpu": "0.1.3", "planck": "^1.4.2", "three": "0.177.0" }, "peerDependencies": { "web-tree-sitter": "0.25.10" } }, "sha512-Es2Oe7/J/yb58e0jjq/04pV9Mekx6hM4go4C5uTiZksX3asfIGWk553cuf5WlWj0PDlVnC+s7Nnayi/NbLJ5jQ=="], + "@opentui/core": ["@opentui/core@0.1.38", "", { "dependencies": { "bun-ffi-structs": "^0.1.0", "jimp": "1.6.0", "yoga-layout": "3.2.1" }, "optionalDependencies": { "@dimforge/rapier2d-simd-compat": "^0.17.3", "@opentui/core-darwin-arm64": "0.1.38", "@opentui/core-darwin-x64": "0.1.38", "@opentui/core-linux-arm64": "0.1.38", "@opentui/core-linux-x64": "0.1.38", "@opentui/core-win32-arm64": "0.1.38", "@opentui/core-win32-x64": "0.1.38", "bun-webgpu": "0.1.3", "planck": "^1.4.2", "three": "0.177.0" }, "peerDependencies": { "web-tree-sitter": "0.25.10" } }, "sha512-GwSsOfGos0CTJhVaCT9DSGM/VcM38Kj8Ds06+sfloxB4sxPgrkItfXxwIm2uCLGUAtuGgGGUN8nMfUmrTibKZw=="], - "@opentui/core-darwin-arm64": ["@opentui/core-darwin-arm64@0.0.0-20251106-788e97e4", "", { "os": "darwin", "cpu": "arm64" }, "sha512-EOO8SSIYJBIh+Sd9bgVTiQmt+TEJmfg65/oym54J4zfDtCYlAqSaLcRnDe4TzB+4hejV9of8etrG3ZZACBJT+A=="], + "@opentui/core-darwin-arm64": ["@opentui/core-darwin-arm64@0.1.38", "", { "os": "darwin", "cpu": "arm64" }, "sha512-iC71iR1N1ZiHjTC84PbncD7+NC1a+hWdF+wK7DVpW0NsKFRhNImIKGFxoq9aAG+/mH1dcvyNmk29gBwQnbPSpg=="], - "@opentui/core-darwin-x64": ["@opentui/core-darwin-x64@0.0.0-20251106-788e97e4", "", { "os": "darwin", "cpu": "x64" }, "sha512-MUTt7CDbzL2afNGK8gJ4jUZd+AHiOUJEO0eJGDSfWU8DUs0zv8XoLZfaI5PPbkUPEL/7CEBMARAAiwfRtoG/4A=="], + "@opentui/core-darwin-x64": ["@opentui/core-darwin-x64@0.1.38", "", { "os": "darwin", "cpu": "x64" }, "sha512-5f68CY8VC6/W78FjaeP/B/K6L5R28M+ypyZMzZphssimUAXY2uXzJyXN4AMSRWnI9ztDb1XS54m1GWkB2MBLGw=="], - "@opentui/core-linux-arm64": ["@opentui/core-linux-arm64@0.0.0-20251106-788e97e4", "", { "os": "linux", "cpu": "arm64" }, "sha512-Zi1EzLCzooRfYoQnN/Dz8OxzrpRXByny8SJqhdO9ZP2mYX72yJ3AhUUW1Sl6YSzVi0H+QIKj7g+RX2KfsXIGFg=="], + "@opentui/core-linux-arm64": ["@opentui/core-linux-arm64@0.1.38", "", { "os": "linux", "cpu": "arm64" }, "sha512-WNiI7jx6o7UYCPNtp05ajODPSzQLZN2+DADKBWT3pOwGpWvLYeMQpUGYQ0Z1nmwsqO5R/27SJdaoPnbKU6DIPw=="], - "@opentui/core-linux-x64": ["@opentui/core-linux-x64@0.0.0-20251106-788e97e4", "", { "os": "linux", "cpu": "x64" }, "sha512-/E0XEBVzO4JEEhJGzfURF2tPxDE2oTODxlgNYYB1QbAuOsLcV69uSrwAjo1TxuIn4P78tBR+ZOlmONjroPqfbQ=="], + "@opentui/core-linux-x64": ["@opentui/core-linux-x64@0.1.38", "", { "os": "linux", "cpu": "x64" }, "sha512-sjQlgbmY0QNIyaCUO/Qp8J7wLLrTjhFzrQQE50Q4ReTNC6puUgsNBlT4PxoS3bYxVtvHYr+y95OCRqZPrbkyrQ=="], - "@opentui/core-win32-arm64": ["@opentui/core-win32-arm64@0.0.0-20251106-788e97e4", "", { "os": "win32", "cpu": "arm64" }, "sha512-En/29cgpYVvzlrQ7fAoP+EUdzmczgMzBIGGM0RuLi2hmCmCqyMtOJ0EJUh9UXa5jYIXNGOP49sIP6bUBbvXt7g=="], + "@opentui/core-win32-arm64": ["@opentui/core-win32-arm64@0.1.38", "", { "os": "win32", "cpu": "arm64" }, "sha512-mFylg8AItMvWaf4YhUfrO72NIrArjY3zhmHXObnV2pssvWZQWmskvtLPaXoaOEAyRBbev5hx7h58DgVzq6ECqw=="], - "@opentui/core-win32-x64": ["@opentui/core-win32-x64@0.0.0-20251106-788e97e4", "", { "os": "win32", "cpu": "x64" }, "sha512-2lu0bgEi+k/1c9VHQFg3wjVxMgQnuZhs/6sDDpxk9eNS3fuHEJfZi0PFJQk2J4IFQL61nzukOvJKgYDWQvKB1g=="], + "@opentui/core-win32-x64": ["@opentui/core-win32-x64@0.1.38", "", { "os": "win32", "cpu": "x64" }, "sha512-5JmYrlmT1OlLI8eAdSW7r4m1J903c15VtkfLOkjEpqasvS75J0ulvq6kuofdqXuYqBarIh8cb8lcsTFQJniM2Q=="], - "@opentui/solid": ["@opentui/solid@0.0.0-20251106-788e97e4", "", { "dependencies": { "@babel/core": "7.28.0", "@babel/preset-typescript": "7.27.1", "@opentui/core": "0.0.0-20251106-788e97e4", "babel-plugin-module-resolver": "5.0.2", "babel-preset-solid": "1.9.9", "s-js": "^0.4.9" }, "peerDependencies": { "solid-js": "1.9.9" } }, "sha512-82rFS6BB60rJZU5Ad8Wf58V6HaMSkpnjciizkv3vsjJc9hvIAwLRNYqPypQB+etypuELhYMzzaVqt+wUsPHSqQ=="], + "@opentui/solid": ["@opentui/solid@0.1.38", "", { "dependencies": { "@babel/core": "7.28.0", "@babel/preset-typescript": "7.27.1", "@opentui/core": "0.1.38", "babel-plugin-module-resolver": "5.0.2", "babel-preset-solid": "1.9.9", "s-js": "^0.4.9" }, "peerDependencies": { "solid-js": "1.9.9" } }, "sha512-xkBmuVEvpSddryzgGS7Y7KoP3UKiRbKcW7T9vlMrYQwq+JhqGuKsG0RI0wpG2kv6gTYeU1/OkwYzPm1DjXBaoA=="], "@oslojs/asn1": ["@oslojs/asn1@1.0.0", "", { "dependencies": { "@oslojs/binary": "1.0.0" } }, "sha512-zw/wn0sj0j0QKbIXfIlnEcTviaCzYOY3V5rAyjR6YtOByFtJiT574+8p9Wlach0lZH9fddD4yb9laEAIl4vXQA=="], diff --git a/packages/opencode/package.json b/packages/opencode/package.json index e5b2a138..d48cac81 100644 --- a/packages/opencode/package.json +++ b/packages/opencode/package.json @@ -54,8 +54,8 @@ "@opencode-ai/plugin": "workspace:*", "@opencode-ai/script": "workspace:*", "@opencode-ai/sdk": "workspace:*", - "@opentui/core": "0.0.0-20251106-788e97e4", - "@opentui/solid": "0.0.0-20251106-788e97e4", + "@opentui/core": "0.1.38", + "@opentui/solid": "0.1.38", "@parcel/watcher": "2.5.1", "@pierre/precision-diffs": "catalog:", "@solid-primitives/event-bus": "1.1.2", From 58bbe9e689d4ae99e18cea4e0bdd40599643c427 Mon Sep 17 00:00:00 2001 From: Dax Raad Date: Fri, 7 Nov 2025 15:58:51 -0500 Subject: [PATCH 132/218] ci: add optional version parameter to publish workflow Allows overriding the version when publishing releases instead of only using semantic bumping. This gives maintainers more control over release versioning for special cases or hotfixes. --- .github/workflows/publish.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index df1a36f7..a339c7da 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -12,6 +12,10 @@ on: - major - minor - patch + version: + description: "Override version (optional)" + required: false + type: string concurrency: ${{ github.workflow }}-${{ github.ref }} @@ -62,6 +66,7 @@ jobs: ./script/publish.ts env: OPENCODE_BUMP: ${{ inputs.bump }} + OPENCODE_VERSION: ${{ inputs.version }} OPENCODE_CHANNEL: latest NPM_CONFIG_TOKEN: ${{ secrets.NPM_TOKEN }} GITHUB_TOKEN: ${{ secrets.SST_GITHUB_TOKEN }} From 5d6bdca6d06d4fbeccc94200b6ca4f552ad2da43 Mon Sep 17 00:00:00 2001 From: opencode Date: Fri, 7 Nov 2025 21:04:26 +0000 Subject: [PATCH 133/218] release: v1.0.43 --- bun.lock | 22 +++++++++++----------- packages/console/app/package.json | 2 +- packages/console/core/package.json | 2 +- packages/console/function/package.json | 2 +- packages/console/mail/package.json | 2 +- packages/desktop/package.json | 2 +- packages/function/package.json | 2 +- packages/opencode/package.json | 2 +- packages/plugin/package.json | 4 ++-- packages/sdk/js/package.json | 4 ++-- packages/sdk/js/src/gen/types.gen.ts | 4 ++-- packages/slack/package.json | 2 +- packages/ui/package.json | 2 +- packages/web/package.json | 2 +- sdks/vscode/package.json | 2 +- 15 files changed, 28 insertions(+), 28 deletions(-) diff --git a/bun.lock b/bun.lock index 35071c6e..8abcb293 100644 --- a/bun.lock +++ b/bun.lock @@ -39,7 +39,7 @@ }, "packages/console/core": { "name": "@opencode-ai/console-core", - "version": "1.0.41", + "version": "1.0.43", "dependencies": { "@aws-sdk/client-sts": "3.782.0", "@jsx-email/render": "1.1.1", @@ -66,7 +66,7 @@ }, "packages/console/function": { "name": "@opencode-ai/console-function", - "version": "1.0.41", + "version": "1.0.43", "dependencies": { "@ai-sdk/anthropic": "2.0.0", "@ai-sdk/openai": "2.0.2", @@ -90,7 +90,7 @@ }, "packages/console/mail": { "name": "@opencode-ai/console-mail", - "version": "1.0.41", + "version": "1.0.43", "dependencies": { "@jsx-email/all": "2.2.3", "@jsx-email/cli": "1.4.3", @@ -111,7 +111,7 @@ }, "packages/desktop": { "name": "@opencode-ai/desktop", - "version": "1.0.41", + "version": "1.0.43", "dependencies": { "@kobalte/core": "catalog:", "@opencode-ai/sdk": "workspace:*", @@ -151,7 +151,7 @@ }, "packages/function": { "name": "@opencode-ai/function", - "version": "1.0.41", + "version": "1.0.43", "dependencies": { "@octokit/auth-app": "8.0.1", "@octokit/rest": "22.0.0", @@ -167,7 +167,7 @@ }, "packages/opencode": { "name": "opencode", - "version": "1.0.41", + "version": "1.0.43", "bin": { "opencode": "./bin/opencode", }, @@ -245,7 +245,7 @@ }, "packages/plugin": { "name": "@opencode-ai/plugin", - "version": "1.0.41", + "version": "1.0.43", "dependencies": { "@opencode-ai/sdk": "workspace:*", "zod": "catalog:", @@ -265,7 +265,7 @@ }, "packages/sdk/js": { "name": "@opencode-ai/sdk", - "version": "1.0.41", + "version": "1.0.43", "devDependencies": { "@hey-api/openapi-ts": "0.81.0", "@tsconfig/node22": "catalog:", @@ -276,7 +276,7 @@ }, "packages/slack": { "name": "@opencode-ai/slack", - "version": "1.0.41", + "version": "1.0.43", "dependencies": { "@opencode-ai/sdk": "workspace:*", "@slack/bolt": "^3.17.1", @@ -289,7 +289,7 @@ }, "packages/ui": { "name": "@opencode-ai/ui", - "version": "1.0.41", + "version": "1.0.43", "dependencies": { "@kobalte/core": "catalog:", "@opencode-ai/sdk": "workspace:*", @@ -319,7 +319,7 @@ }, "packages/web": { "name": "@opencode-ai/web", - "version": "1.0.41", + "version": "1.0.43", "dependencies": { "@astrojs/cloudflare": "12.6.3", "@astrojs/markdown-remark": "6.3.1", diff --git a/packages/console/app/package.json b/packages/console/app/package.json index e830cdbc..18206295 100644 --- a/packages/console/app/package.json +++ b/packages/console/app/package.json @@ -7,7 +7,7 @@ "dev:remote": "VITE_AUTH_URL=https://auth.dev.opencode.ai bun sst shell --stage=dev bun dev", "build": "vinxi build && ../../opencode/script/schema.ts ./.output/public/config.json", "start": "vinxi start", - "version": "1.0.41" + "version": "1.0.43" }, "dependencies": { "@ibm/plex": "6.4.1", diff --git a/packages/console/core/package.json b/packages/console/core/package.json index 25dc25f9..fa4b9350 100644 --- a/packages/console/core/package.json +++ b/packages/console/core/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@opencode-ai/console-core", - "version": "1.0.41", + "version": "1.0.43", "private": true, "type": "module", "dependencies": { diff --git a/packages/console/function/package.json b/packages/console/function/package.json index cf3ea426..0182a472 100644 --- a/packages/console/function/package.json +++ b/packages/console/function/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/console-function", - "version": "1.0.41", + "version": "1.0.43", "$schema": "https://json.schemastore.org/package.json", "private": true, "type": "module", diff --git a/packages/console/mail/package.json b/packages/console/mail/package.json index 19205a33..d5e280f2 100644 --- a/packages/console/mail/package.json +++ b/packages/console/mail/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/console-mail", - "version": "1.0.41", + "version": "1.0.43", "dependencies": { "@jsx-email/all": "2.2.3", "@jsx-email/cli": "1.4.3", diff --git a/packages/desktop/package.json b/packages/desktop/package.json index cebbe893..a2c1e3cb 100644 --- a/packages/desktop/package.json +++ b/packages/desktop/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/desktop", - "version": "1.0.41", + "version": "1.0.43", "description": "", "type": "module", "scripts": { diff --git a/packages/function/package.json b/packages/function/package.json index 57f0a876..23c669cc 100644 --- a/packages/function/package.json +++ b/packages/function/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/function", - "version": "1.0.41", + "version": "1.0.43", "$schema": "https://json.schemastore.org/package.json", "private": true, "type": "module", diff --git a/packages/opencode/package.json b/packages/opencode/package.json index d48cac81..713e4651 100644 --- a/packages/opencode/package.json +++ b/packages/opencode/package.json @@ -1,6 +1,6 @@ { "$schema": "https://json.schemastore.org/package.json", - "version": "1.0.41", + "version": "1.0.43", "name": "opencode", "type": "module", "private": true, diff --git a/packages/plugin/package.json b/packages/plugin/package.json index f9d15e49..9317ac3e 100644 --- a/packages/plugin/package.json +++ b/packages/plugin/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@opencode-ai/plugin", - "version": "1.0.41", + "version": "1.0.43", "type": "module", "scripts": { "typecheck": "tsgo --noEmit", @@ -24,4 +24,4 @@ "typescript": "catalog:", "@typescript/native-preview": "catalog:" } -} +} \ No newline at end of file diff --git a/packages/sdk/js/package.json b/packages/sdk/js/package.json index d96c1a4c..ead1c964 100644 --- a/packages/sdk/js/package.json +++ b/packages/sdk/js/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@opencode-ai/sdk", - "version": "1.0.41", + "version": "1.0.43", "type": "module", "scripts": { "typecheck": "tsgo --noEmit", @@ -26,4 +26,4 @@ "publishConfig": { "directory": "dist" } -} +} \ No newline at end of file diff --git a/packages/sdk/js/src/gen/types.gen.ts b/packages/sdk/js/src/gen/types.gen.ts index 2a0df302..08ce17b4 100644 --- a/packages/sdk/js/src/gen/types.gen.ts +++ b/packages/sdk/js/src/gen/types.gen.ts @@ -1979,9 +1979,9 @@ export type SessionMessagesData = { */ id: string } - query: { + query?: { directory?: string - limit: number + limit?: number } url: "/session/{id}/message" } diff --git a/packages/slack/package.json b/packages/slack/package.json index 633050cd..1ee34d21 100644 --- a/packages/slack/package.json +++ b/packages/slack/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/slack", - "version": "1.0.41", + "version": "1.0.43", "type": "module", "scripts": { "dev": "bun run src/index.ts", diff --git a/packages/ui/package.json b/packages/ui/package.json index 1bf2253c..f0caecce 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/ui", - "version": "1.0.41", + "version": "1.0.43", "type": "module", "exports": { ".": "./src/components/index.ts", diff --git a/packages/web/package.json b/packages/web/package.json index 0381033a..e6d032a4 100644 --- a/packages/web/package.json +++ b/packages/web/package.json @@ -1,7 +1,7 @@ { "name": "@opencode-ai/web", "type": "module", - "version": "1.0.41", + "version": "1.0.43", "scripts": { "dev": "astro dev", "dev:remote": "VITE_API_URL=https://api.opencode.ai astro dev", diff --git a/sdks/vscode/package.json b/sdks/vscode/package.json index baf51e57..55a7aa99 100644 --- a/sdks/vscode/package.json +++ b/sdks/vscode/package.json @@ -2,7 +2,7 @@ "name": "opencode", "displayName": "opencode", "description": "opencode for VS Code", - "version": "1.0.41", + "version": "1.0.43", "publisher": "sst-dev", "repository": { "type": "git", From aa07be09e18f7d2a3f2bfc36f9980e2bd88175d2 Mon Sep 17 00:00:00 2001 From: Aiden Cline Date: Fri, 7 Nov 2025 15:08:50 -0600 Subject: [PATCH 134/218] ignore: update zed extension --- packages/extensions/zed/extension.toml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/extensions/zed/extension.toml b/packages/extensions/zed/extension.toml index 34af9621..6ab238b2 100644 --- a/packages/extensions/zed/extension.toml +++ b/packages/extensions/zed/extension.toml @@ -1,7 +1,7 @@ id = "opencode" name = "OpenCode" description = "The AI coding agent built for the terminal" -version = "0.1.1" +version = "0.1.2" schema_version = 1 authors = ["Anomaly"] repository = "https://github.com/sst/opencode" @@ -11,26 +11,26 @@ name = "OpenCode" icon = "./icons/opencode.svg" [agent_servers.opencode.targets.darwin-aarch64] -archive = "https://github.com/sst/opencode/releases/latest/download/opencode-darwin-arm64.zip" +archive = "https://github.com/sst/opencode/releases/v1.0.43/download/opencode-darwin-arm64.zip" cmd = "./opencode" args = ["acp"] [agent_servers.opencode.targets.darwin-x86_64] -archive = "https://github.com/sst/opencode/releases/latest/download/opencode-darwin-x64.zip" +archive = "https://github.com/sst/opencode/releases/v1.0.43/download/opencode-darwin-x64.zip" cmd = "./opencode" args = ["acp"] [agent_servers.opencode.targets.linux-aarch64] -archive = "https://github.com/sst/opencode/releases/latest/download/opencode-linux-arm64.zip" +archive = "https://github.com/sst/opencode/releases/v1.0.43/download/opencode-linux-arm64.zip" cmd = "./opencode" args = ["acp"] [agent_servers.opencode.targets.linux-x86_64] -archive = "https://github.com/sst/opencode/releases/latest/download/opencode-linux-x64.zip" +archive = "https://github.com/sst/opencode/releases/v1.0.43/download/opencode-linux-x64.zip" cmd = "./opencode" args = ["acp"] [agent_servers.opencode.targets.windows-x86_64] -archive = "https://github.com/sst/opencode/releases/latest/download/opencode-windows-x64.zip" +archive = "https://github.com/sst/opencode/releases/v1.0.43/download/opencode-windows-x64.zip" cmd = "./opencode.exe" args = ["acp"] From 4271df96d27965428a547ecf38db75baf169e0a8 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Fri, 7 Nov 2025 21:09:47 +0000 Subject: [PATCH 135/218] chore: format code --- packages/plugin/package.json | 2 +- packages/sdk/js/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/plugin/package.json b/packages/plugin/package.json index 9317ac3e..13e95bd9 100644 --- a/packages/plugin/package.json +++ b/packages/plugin/package.json @@ -24,4 +24,4 @@ "typescript": "catalog:", "@typescript/native-preview": "catalog:" } -} \ No newline at end of file +} diff --git a/packages/sdk/js/package.json b/packages/sdk/js/package.json index ead1c964..91d6eab7 100644 --- a/packages/sdk/js/package.json +++ b/packages/sdk/js/package.json @@ -26,4 +26,4 @@ "publishConfig": { "directory": "dist" } -} \ No newline at end of file +} From 79bb22a5735610e7d7691741865c22808436343c Mon Sep 17 00:00:00 2001 From: Aiden Cline Date: Fri, 7 Nov 2025 15:17:19 -0600 Subject: [PATCH 136/218] ci: auto update zed extension --- script/publish.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/script/publish.ts b/script/publish.ts index 307755a1..7cd81d41 100755 --- a/script/publish.ts +++ b/script/publish.ts @@ -83,6 +83,14 @@ for (const file of pkgjsons) { console.log("updated:", file) await Bun.file(file).write(pkg) } + +const extensionToml = new URL("../packages/extensions/zed/extension.toml", import.meta.url).pathname +let toml = await Bun.file(extensionToml).text() +toml = toml.replace(/^version = "[^"]+"/m, `version = "${Script.version}"`) +toml = toml.replaceAll(/releases\/v[^/]+\//g, `releases/v${Script.version}/`) +console.log("updated:", extensionToml) +await Bun.file(extensionToml).write(toml) + await $`bun install` console.log("\n=== opencode ===\n") From 0a395d87839e4d4700d5f51f5085785ec30b5fb6 Mon Sep 17 00:00:00 2001 From: Aiden Cline Date: Fri, 7 Nov 2025 15:18:44 -0600 Subject: [PATCH 137/218] ignore: update version --- packages/extensions/zed/extension.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/extensions/zed/extension.toml b/packages/extensions/zed/extension.toml index 6ab238b2..bdde4781 100644 --- a/packages/extensions/zed/extension.toml +++ b/packages/extensions/zed/extension.toml @@ -1,7 +1,7 @@ id = "opencode" name = "OpenCode" description = "The AI coding agent built for the terminal" -version = "0.1.2" +version = "v1.0.43" schema_version = 1 authors = ["Anomaly"] repository = "https://github.com/sst/opencode" From 1a2b3701f2a4f6ea12de4c51c6d4ba5d3d8d083a Mon Sep 17 00:00:00 2001 From: Dax Raad Date: Fri, 7 Nov 2025 16:19:38 -0500 Subject: [PATCH 138/218] tui: show more sessions in list and fix sync timing to prevent race conditions --- .../opencode/src/cli/cmd/tui/component/dialog-session-list.tsx | 2 +- packages/opencode/src/cli/cmd/tui/context/sync.tsx | 2 +- packages/opencode/src/cli/cmd/tui/ui/dialog-select.tsx | 2 -- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/opencode/src/cli/cmd/tui/component/dialog-session-list.tsx b/packages/opencode/src/cli/cmd/tui/component/dialog-session-list.tsx index e6f7efbe..c4f31845 100644 --- a/packages/opencode/src/cli/cmd/tui/component/dialog-session-list.tsx +++ b/packages/opencode/src/cli/cmd/tui/component/dialog-session-list.tsx @@ -43,6 +43,7 @@ export function DialogSessionList() { footer: Locale.time(x.time.updated), } }) + .slice(0, 150) }) createEffect(() => { @@ -57,7 +58,6 @@ export function DialogSessionList() { { setToDelete(undefined) diff --git a/packages/opencode/src/cli/cmd/tui/context/sync.tsx b/packages/opencode/src/cli/cmd/tui/context/sync.tsx index 5c8d3146..60758aeb 100644 --- a/packages/opencode/src/cli/cmd/tui/context/sync.tsx +++ b/packages/opencode/src/cli/cmd/tui/context/sync.tsx @@ -269,8 +269,8 @@ export const { use: useSync, provider: SyncProvider } = createSimpleContext({ return last.time.completed ? "idle" : "working" }, async sync(sessionID: string) { - const now = Date.now() if (store.message[sessionID]) return + const now = Date.now() console.log("syncing", sessionID) const [session, messages, todo, diff] = await Promise.all([ sdk.client.session.get({ path: { id: sessionID }, throwOnError: true }), diff --git a/packages/opencode/src/cli/cmd/tui/ui/dialog-select.tsx b/packages/opencode/src/cli/cmd/tui/ui/dialog-select.tsx index 6dd0b5cd..b442f7b3 100644 --- a/packages/opencode/src/cli/cmd/tui/ui/dialog-select.tsx +++ b/packages/opencode/src/cli/cmd/tui/ui/dialog-select.tsx @@ -23,7 +23,6 @@ export interface DialogSelectProps { title: string onTrigger: (option: DialogSelectOption) => void }[] - limit?: number current?: T } @@ -58,7 +57,6 @@ export function DialogSelect(props: DialogSelectProps) { const result = pipe( props.options, filter((x) => x.disabled !== true), - take(props.limit ?? Infinity), (x) => !needle ? x : fuzzysort.go(needle, x, { keys: ["title", "category"] }).map((x) => x.obj), ) From 39461fbbce6a54d254a182a982607f5571120551 Mon Sep 17 00:00:00 2001 From: opencode Date: Fri, 7 Nov 2025 21:24:15 +0000 Subject: [PATCH 139/218] release: v1.0.44 --- bun.lock | 22 +++++++++++----------- packages/console/app/package.json | 2 +- packages/console/core/package.json | 2 +- packages/console/function/package.json | 2 +- packages/console/mail/package.json | 2 +- packages/desktop/package.json | 2 +- packages/extensions/zed/extension.toml | 12 ++++++------ packages/function/package.json | 2 +- packages/opencode/package.json | 2 +- packages/plugin/package.json | 4 ++-- packages/sdk/js/package.json | 4 ++-- packages/slack/package.json | 2 +- packages/ui/package.json | 2 +- packages/web/package.json | 2 +- sdks/vscode/package.json | 2 +- 15 files changed, 32 insertions(+), 32 deletions(-) diff --git a/bun.lock b/bun.lock index 8abcb293..27cc0f33 100644 --- a/bun.lock +++ b/bun.lock @@ -39,7 +39,7 @@ }, "packages/console/core": { "name": "@opencode-ai/console-core", - "version": "1.0.43", + "version": "1.0.44", "dependencies": { "@aws-sdk/client-sts": "3.782.0", "@jsx-email/render": "1.1.1", @@ -66,7 +66,7 @@ }, "packages/console/function": { "name": "@opencode-ai/console-function", - "version": "1.0.43", + "version": "1.0.44", "dependencies": { "@ai-sdk/anthropic": "2.0.0", "@ai-sdk/openai": "2.0.2", @@ -90,7 +90,7 @@ }, "packages/console/mail": { "name": "@opencode-ai/console-mail", - "version": "1.0.43", + "version": "1.0.44", "dependencies": { "@jsx-email/all": "2.2.3", "@jsx-email/cli": "1.4.3", @@ -111,7 +111,7 @@ }, "packages/desktop": { "name": "@opencode-ai/desktop", - "version": "1.0.43", + "version": "1.0.44", "dependencies": { "@kobalte/core": "catalog:", "@opencode-ai/sdk": "workspace:*", @@ -151,7 +151,7 @@ }, "packages/function": { "name": "@opencode-ai/function", - "version": "1.0.43", + "version": "1.0.44", "dependencies": { "@octokit/auth-app": "8.0.1", "@octokit/rest": "22.0.0", @@ -167,7 +167,7 @@ }, "packages/opencode": { "name": "opencode", - "version": "1.0.43", + "version": "1.0.44", "bin": { "opencode": "./bin/opencode", }, @@ -245,7 +245,7 @@ }, "packages/plugin": { "name": "@opencode-ai/plugin", - "version": "1.0.43", + "version": "1.0.44", "dependencies": { "@opencode-ai/sdk": "workspace:*", "zod": "catalog:", @@ -265,7 +265,7 @@ }, "packages/sdk/js": { "name": "@opencode-ai/sdk", - "version": "1.0.43", + "version": "1.0.44", "devDependencies": { "@hey-api/openapi-ts": "0.81.0", "@tsconfig/node22": "catalog:", @@ -276,7 +276,7 @@ }, "packages/slack": { "name": "@opencode-ai/slack", - "version": "1.0.43", + "version": "1.0.44", "dependencies": { "@opencode-ai/sdk": "workspace:*", "@slack/bolt": "^3.17.1", @@ -289,7 +289,7 @@ }, "packages/ui": { "name": "@opencode-ai/ui", - "version": "1.0.43", + "version": "1.0.44", "dependencies": { "@kobalte/core": "catalog:", "@opencode-ai/sdk": "workspace:*", @@ -319,7 +319,7 @@ }, "packages/web": { "name": "@opencode-ai/web", - "version": "1.0.43", + "version": "1.0.44", "dependencies": { "@astrojs/cloudflare": "12.6.3", "@astrojs/markdown-remark": "6.3.1", diff --git a/packages/console/app/package.json b/packages/console/app/package.json index 18206295..5e37e214 100644 --- a/packages/console/app/package.json +++ b/packages/console/app/package.json @@ -7,7 +7,7 @@ "dev:remote": "VITE_AUTH_URL=https://auth.dev.opencode.ai bun sst shell --stage=dev bun dev", "build": "vinxi build && ../../opencode/script/schema.ts ./.output/public/config.json", "start": "vinxi start", - "version": "1.0.43" + "version": "1.0.44" }, "dependencies": { "@ibm/plex": "6.4.1", diff --git a/packages/console/core/package.json b/packages/console/core/package.json index fa4b9350..a06f5929 100644 --- a/packages/console/core/package.json +++ b/packages/console/core/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@opencode-ai/console-core", - "version": "1.0.43", + "version": "1.0.44", "private": true, "type": "module", "dependencies": { diff --git a/packages/console/function/package.json b/packages/console/function/package.json index 0182a472..2c3b5da2 100644 --- a/packages/console/function/package.json +++ b/packages/console/function/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/console-function", - "version": "1.0.43", + "version": "1.0.44", "$schema": "https://json.schemastore.org/package.json", "private": true, "type": "module", diff --git a/packages/console/mail/package.json b/packages/console/mail/package.json index d5e280f2..9019c716 100644 --- a/packages/console/mail/package.json +++ b/packages/console/mail/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/console-mail", - "version": "1.0.43", + "version": "1.0.44", "dependencies": { "@jsx-email/all": "2.2.3", "@jsx-email/cli": "1.4.3", diff --git a/packages/desktop/package.json b/packages/desktop/package.json index a2c1e3cb..eecac67e 100644 --- a/packages/desktop/package.json +++ b/packages/desktop/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/desktop", - "version": "1.0.43", + "version": "1.0.44", "description": "", "type": "module", "scripts": { diff --git a/packages/extensions/zed/extension.toml b/packages/extensions/zed/extension.toml index bdde4781..a6e6aa6f 100644 --- a/packages/extensions/zed/extension.toml +++ b/packages/extensions/zed/extension.toml @@ -1,7 +1,7 @@ id = "opencode" name = "OpenCode" description = "The AI coding agent built for the terminal" -version = "v1.0.43" +version = "1.0.44" schema_version = 1 authors = ["Anomaly"] repository = "https://github.com/sst/opencode" @@ -11,26 +11,26 @@ name = "OpenCode" icon = "./icons/opencode.svg" [agent_servers.opencode.targets.darwin-aarch64] -archive = "https://github.com/sst/opencode/releases/v1.0.43/download/opencode-darwin-arm64.zip" +archive = "https://github.com/sst/opencode/releases/v1.0.44/download/opencode-darwin-arm64.zip" cmd = "./opencode" args = ["acp"] [agent_servers.opencode.targets.darwin-x86_64] -archive = "https://github.com/sst/opencode/releases/v1.0.43/download/opencode-darwin-x64.zip" +archive = "https://github.com/sst/opencode/releases/v1.0.44/download/opencode-darwin-x64.zip" cmd = "./opencode" args = ["acp"] [agent_servers.opencode.targets.linux-aarch64] -archive = "https://github.com/sst/opencode/releases/v1.0.43/download/opencode-linux-arm64.zip" +archive = "https://github.com/sst/opencode/releases/v1.0.44/download/opencode-linux-arm64.zip" cmd = "./opencode" args = ["acp"] [agent_servers.opencode.targets.linux-x86_64] -archive = "https://github.com/sst/opencode/releases/v1.0.43/download/opencode-linux-x64.zip" +archive = "https://github.com/sst/opencode/releases/v1.0.44/download/opencode-linux-x64.zip" cmd = "./opencode" args = ["acp"] [agent_servers.opencode.targets.windows-x86_64] -archive = "https://github.com/sst/opencode/releases/v1.0.43/download/opencode-windows-x64.zip" +archive = "https://github.com/sst/opencode/releases/v1.0.44/download/opencode-windows-x64.zip" cmd = "./opencode.exe" args = ["acp"] diff --git a/packages/function/package.json b/packages/function/package.json index 23c669cc..9eb02d59 100644 --- a/packages/function/package.json +++ b/packages/function/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/function", - "version": "1.0.43", + "version": "1.0.44", "$schema": "https://json.schemastore.org/package.json", "private": true, "type": "module", diff --git a/packages/opencode/package.json b/packages/opencode/package.json index 713e4651..ae0d0b08 100644 --- a/packages/opencode/package.json +++ b/packages/opencode/package.json @@ -1,6 +1,6 @@ { "$schema": "https://json.schemastore.org/package.json", - "version": "1.0.43", + "version": "1.0.44", "name": "opencode", "type": "module", "private": true, diff --git a/packages/plugin/package.json b/packages/plugin/package.json index 13e95bd9..96f2c814 100644 --- a/packages/plugin/package.json +++ b/packages/plugin/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@opencode-ai/plugin", - "version": "1.0.43", + "version": "1.0.44", "type": "module", "scripts": { "typecheck": "tsgo --noEmit", @@ -24,4 +24,4 @@ "typescript": "catalog:", "@typescript/native-preview": "catalog:" } -} +} \ No newline at end of file diff --git a/packages/sdk/js/package.json b/packages/sdk/js/package.json index 91d6eab7..1bf28cee 100644 --- a/packages/sdk/js/package.json +++ b/packages/sdk/js/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@opencode-ai/sdk", - "version": "1.0.43", + "version": "1.0.44", "type": "module", "scripts": { "typecheck": "tsgo --noEmit", @@ -26,4 +26,4 @@ "publishConfig": { "directory": "dist" } -} +} \ No newline at end of file diff --git a/packages/slack/package.json b/packages/slack/package.json index 1ee34d21..1e3f0c6b 100644 --- a/packages/slack/package.json +++ b/packages/slack/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/slack", - "version": "1.0.43", + "version": "1.0.44", "type": "module", "scripts": { "dev": "bun run src/index.ts", diff --git a/packages/ui/package.json b/packages/ui/package.json index f0caecce..b2505a9d 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/ui", - "version": "1.0.43", + "version": "1.0.44", "type": "module", "exports": { ".": "./src/components/index.ts", diff --git a/packages/web/package.json b/packages/web/package.json index e6d032a4..9755c0f9 100644 --- a/packages/web/package.json +++ b/packages/web/package.json @@ -1,7 +1,7 @@ { "name": "@opencode-ai/web", "type": "module", - "version": "1.0.43", + "version": "1.0.44", "scripts": { "dev": "astro dev", "dev:remote": "VITE_API_URL=https://api.opencode.ai astro dev", diff --git a/sdks/vscode/package.json b/sdks/vscode/package.json index 55a7aa99..17afb3e4 100644 --- a/sdks/vscode/package.json +++ b/sdks/vscode/package.json @@ -2,7 +2,7 @@ "name": "opencode", "displayName": "opencode", "description": "opencode for VS Code", - "version": "1.0.43", + "version": "1.0.44", "publisher": "sst-dev", "repository": { "type": "git", From 9885c716f387d35024eaed5c0aab0528189c1191 Mon Sep 17 00:00:00 2001 From: Jay V Date: Fri, 7 Nov 2025 14:40:48 -0500 Subject: [PATCH 140/218] ignore: lander use h1 tags for main headings on landing and zen pages --- packages/console/app/src/routes/index.css | 2 +- packages/console/app/src/routes/index.tsx | 2 +- packages/console/app/src/routes/zen/index.css | 2 +- packages/console/app/src/routes/zen/index.tsx | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/console/app/src/routes/index.css b/packages/console/app/src/routes/index.css index 49690133..e5101442 100644 --- a/packages/console/app/src/routes/index.css +++ b/packages/console/app/src/routes/index.css @@ -479,7 +479,7 @@ body { border-bottom: 1px solid var(--color-border-weak); } - strong { + h1 { font-size: 28px; color: var(--color-text-strong); font-weight: 500; diff --git a/packages/console/app/src/routes/index.tsx b/packages/console/app/src/routes/index.tsx index bcfb22bc..71b535f7 100644 --- a/packages/console/app/src/routes/index.tsx +++ b/packages/console/app/src/routes/index.tsx @@ -63,7 +63,7 @@ export default function Home() { > What’s new in {release()?.name ?? "the latest release"}
    - The AI coding agent built for the terminal +

    The AI coding agent built for the terminal

    OpenCode is fully open source, giving you control and freedom to use any provider, any model, and any editor. diff --git a/packages/console/app/src/routes/zen/index.css b/packages/console/app/src/routes/zen/index.css index 661517c4..fbdd1530 100644 --- a/packages/console/app/src/routes/zen/index.css +++ b/packages/console/app/src/routes/zen/index.css @@ -277,7 +277,7 @@ body { margin-bottom: 24px; } - strong { + h1 { font-size: 28px; color: var(--color-text-strong); font-weight: 500; diff --git a/packages/console/app/src/routes/zen/index.tsx b/packages/console/app/src/routes/zen/index.tsx index 92cc0a50..220f7a11 100644 --- a/packages/console/app/src/routes/zen/index.tsx +++ b/packages/console/app/src/routes/zen/index.tsx @@ -45,7 +45,7 @@ export default function Home() {

    zen logo light zen logo dark - Reliable optimized models for coding agents +

    Reliable optimized models for coding agents

    Zen gives you access to a curated set of AI models that OpenCode has tested and benchmarked specifically for coding agents. No need to worry about inconsistent From 536d10e5abcf43a439ccb48fc8e1447d2cbe131e Mon Sep 17 00:00:00 2001 From: Jay V Date: Fri, 7 Nov 2025 14:59:11 -0500 Subject: [PATCH 141/218] ignore: lander add canonical urls and h1 tags to all landing pages --- packages/console/app/src/config.ts | 3 +++ packages/console/app/src/routes/brand/index.css | 2 +- packages/console/app/src/routes/brand/index.tsx | 6 ++++-- packages/console/app/src/routes/enterprise/index.css | 2 +- packages/console/app/src/routes/enterprise/index.tsx | 6 ++++-- packages/console/app/src/routes/index.tsx | 1 + packages/console/app/src/routes/zen/index.tsx | 2 ++ 7 files changed, 16 insertions(+), 6 deletions(-) diff --git a/packages/console/app/src/config.ts b/packages/console/app/src/config.ts index 097764b8..40108e96 100644 --- a/packages/console/app/src/config.ts +++ b/packages/console/app/src/config.ts @@ -2,6 +2,9 @@ * Application-wide constants and configuration */ export const config = { + // Base URL + baseUrl: "https://opencode.ai", + // GitHub github: { repoUrl: "https://github.com/sst/opencode", diff --git a/packages/console/app/src/routes/brand/index.css b/packages/console/app/src/routes/brand/index.css index 058d150b..d3c0d052 100644 --- a/packages/console/app/src/routes/brand/index.css +++ b/packages/console/app/src/routes/brand/index.css @@ -264,7 +264,7 @@ [data-component="brand-content"] { padding: 4rem 5rem; - h2 { + h1 { font-size: 1.5rem; font-weight: 500; color: var(--color-text-strong); diff --git a/packages/console/app/src/routes/brand/index.tsx b/packages/console/app/src/routes/brand/index.tsx index 4570c73c..72ea0f15 100644 --- a/packages/console/app/src/routes/brand/index.tsx +++ b/packages/console/app/src/routes/brand/index.tsx @@ -1,6 +1,7 @@ import "./index.css" -import { Title, Meta } from "@solidjs/meta" +import { Title, Meta, Link } from "@solidjs/meta" import { Header } from "~/component/header" +import { config } from "~/config" import { Footer } from "~/component/footer" import { Legal } from "~/component/legal" import previewLogoLight from "../../asset/brand/preview-opencode-logo-light.png" @@ -53,13 +54,14 @@ export default function Brand() { return (

    OpenCode | Brand +
    -

    Brand guidelines

    +

    Brand guidelines

    Resources and assets to help you work with the OpenCode brand.

    - - - -
    @@ -232,31 +215,29 @@ export default function Enterprise() {
    • - OpenCode Enterprise is for organizations that want to ensure that their code and - data never leaves their infrastructure. It can do this by using a centralized - config that integrates with your SSO and internal AI gateway. + OpenCode Enterprise is for organizations that want to ensure that their code and data never leaves + their infrastructure. It can do this by using a centralized config that integrates with your SSO and + internal AI gateway.
    • - Simply start with an internal trial with your team. OpenCode by default does not - store your code or context data, making it easy to get started. Then contact us to - discuss pricing and implementation options. + Simply start with an internal trial with your team. OpenCode by default does not store your code or + context data, making it easy to get started. Then contact us to discuss pricing and implementation + options.
    • - We offer per-seat enterprise pricing. If you have your own LLM gateway, we do not - charge for tokens used. For further details, contact us for a custom quote based - on your organization's needs. + We offer per-seat enterprise pricing. If you have your own LLM gateway, we do not charge for tokens + used. For further details, contact us for a custom quote based on your organization's needs.
    • - Yes. OpenCode does not store your code or context data. All processing happens - locally or through direct API calls to your AI provider. With central config and - SSO integration, your data remains secure within your organization's - infrastructure. + Yes. OpenCode does not store your code or context data. All processing happens locally or through + direct API calls to your AI provider. With central config and SSO integration, your data remains + secure within your organization's infrastructure.
    diff --git a/packages/console/app/src/routes/index.tsx b/packages/console/app/src/routes/index.tsx index ee138e14..8b8f4499 100644 --- a/packages/console/app/src/routes/index.tsx +++ b/packages/console/app/src/routes/index.tsx @@ -42,10 +42,7 @@ export default function Home() { return (
    - + OpenCode | The AI coding agent built for the terminal @@ -57,27 +54,17 @@ export default function Home() {
    - + What’s new in {release()?.name ?? "the latest release"}

    The AI coding agent built for the terminal

    - OpenCode is fully open source, giving you control and freedom to use any provider, - any model, and any editor. + OpenCode is fully open source, giving you control and freedom to use any provider, any model, and any + editor.

    Read docs - +

    What is OpenCode?

    -

    - OpenCode is an open source agent that helps you write and run code directly from the - terminal. -

    +

    OpenCode is an open source agent that helps you write and run code directly from the terminal.

    • @@ -197,8 +181,7 @@ export default function Home() {
    • [*]
      - Multi-session Start multiple agents in parallel on the same - project + Multi-session Start multiple agents in parallel on the same project
    • @@ -210,15 +193,13 @@ export default function Home() {
    • [*]
      - Claude Pro Log in with Anthropic to use your Claude Pro or Max - account + Claude Pro Log in with Anthropic to use your Claude Pro or Max account
    • [*]
      - Any model 75+ LLM providers through Models.dev, including local - models + Any model 75+ LLM providers through Models.dev, including local models
    • @@ -238,21 +219,15 @@ export default function Home() {

      With over {config.github.starsFormatted.full} GitHub stars,{" "} {config.stats.contributors} contributors, and almost{" "} - {config.stats.commits} commits, OpenCode is used and trusted by - over {config.stats.monthlyUsers} developers every month. + {config.stats.commits} commits, OpenCode is used and trusted by over{" "} + {config.stats.monthlyUsers} developers every month.

    - +
    -
    Fig 1.
    {config.github.starsFormatted.compact}{" "} - GitHub Stars +
    Fig 1.
    {config.github.starsFormatted.compact} GitHub Stars
    - + @@ -440,54 +408,12 @@ export default function Home() { - - - - - - + + + + + + @@ -496,55 +422,13 @@ export default function Home() { - - - + + + - - - + + + @@ -553,55 +437,13 @@ export default function Home() { - - - - + + + + - - + + @@ -610,47 +452,12 @@ export default function Home() { - - - + + + - - + + @@ -659,55 +466,13 @@ export default function Home() { - - - + + + - - - + + + @@ -716,55 +481,13 @@ export default function Home() { - - - - + + + + - - + + @@ -773,62 +496,13 @@ export default function Home() { - - - - - - - + + + + + + + @@ -837,55 +511,13 @@ export default function Home() { - + - - - - - + + + + + @@ -895,54 +527,12 @@ export default function Home() { - - - - - - + + + + + + @@ -951,62 +541,13 @@ export default function Home() { - - - - - - - + + + + + + + @@ -1015,54 +556,12 @@ export default function Home() { - - - - - - + + + + + + @@ -1071,31 +570,19 @@ export default function Home() { - +
    -
    Fig 2.
    {config.stats.contributors}{" "} - Contributors +
    Fig 2.
    {config.stats.contributors} Contributors
    - + @@ -1131,8 +618,7 @@ export default function Home() {
    -
    Fig 3.
    {config.stats.monthlyUsers} Monthly - Devs +
    Fig 3.
    {config.stats.monthlyUsers} Monthly Devs
    @@ -1146,9 +632,8 @@ export default function Home() { [*]

    - OpenCode does not store any of your code or context data, so that it can operate - in privacy sensitive environments. Learn more about{" "} - privacy. + OpenCode does not store any of your code or context data, so that it can operate in privacy sensitive + environments. Learn more about privacy.

    @@ -1161,9 +646,9 @@ export default function Home() {
    • - OpenCode is an open source agent that helps you write and run code directly from - the terminal. You can pair OpenCode with any AI model, and because it’s - terminal-based you can pair it with your preferred code editor. + OpenCode is an open source agent that helps you write and run code directly from the terminal. You can + pair OpenCode with any AI model, and because it’s terminal-based you can pair it with your preferred + code editor.
    • @@ -1173,32 +658,30 @@ export default function Home() {
    • - Not necessarily, but probably. You’ll need an AI subscription if you want to - connect OpenCode to a paid provider, although you can work with{" "} + Not necessarily, but probably. You’ll need an AI subscription if you want to connect OpenCode to a + paid provider, although you can work with{" "} local models {" "} - for free. While we encourage users to use Zen, OpenCode works - with all popular providers such as OpenAI, Anthropic, xAI etc. + for free. While we encourage users to use Zen, OpenCode works with all popular + providers such as OpenAI, Anthropic, xAI etc.
    • - Yes, for now. We are actively working on a desktop app. Join the waitlist for - early access. + Yes, for now. We are actively working on a desktop app. Join the waitlist for early access.
    • - OpenCode is 100% free to use. Any additional costs will come from your - subscription to a model provider. While OpenCode works with any model provider, we - recommend using Zen. + OpenCode is 100% free to use. Any additional costs will come from your subscription to a model + provider. While OpenCode works with any model provider, we recommend using Zen.
    • - Your data and information is only stored when you create sharable links in - OpenCode. Learn more about share pages. + Your data and information is only stored when you create sharable links in OpenCode. Learn more about{" "} + share pages.
    • @@ -1211,8 +694,8 @@ export default function Home() { MIT License - , meaning anyone can use, modify, or contribute to its development. Anyone from - the community can file issues, submit pull requests, and extend functionality. + , meaning anyone can use, modify, or contribute to its development. Anyone from the community can file + issues, submit pull requests, and extend functionality.
    @@ -1222,19 +705,13 @@ export default function Home() {
    Access reliable optimized models for coding agents

    - Zen gives you access to a handpicked set of AI models that OpenCode has tested and - benchmarked specifically for coding agents. No need to worry about inconsistent - performance and quality across providers, use validated models that work. + Zen gives you access to a handpicked set of AI models that OpenCode has tested and benchmarked + specifically for coding agents. No need to worry about inconsistent performance and quality across + providers, use validated models that work.

    - +
    - - + +
    - +
    - +
    - + Learn about Zen - + { const customer = await Billing.get() - if (customer?.customerID && customer.customerID !== customerID) - throw new Error("Customer ID mismatch") + if (customer?.customerID && customer.customerID !== customerID) throw new Error("Customer ID mismatch") // set customer metadata if (!customer?.customerID) { @@ -72,8 +70,7 @@ export async function POST(input: APIEvent) { expand: ["payment_method"], }) const paymentMethod = paymentIntent.payment_method - if (!paymentMethod || typeof paymentMethod === "string") - throw new Error("Payment method not expanded") + if (!paymentMethod || typeof paymentMethod === "string") throw new Error("Payment method not expanded") await Database.transaction(async (tx) => { await tx @@ -128,12 +125,7 @@ export async function POST(input: APIEvent) { amount: PaymentTable.amount, }) .from(PaymentTable) - .where( - and( - eq(PaymentTable.paymentID, paymentIntentID), - eq(PaymentTable.workspaceID, workspaceID), - ), - ) + .where(and(eq(PaymentTable.paymentID, paymentIntentID), eq(PaymentTable.workspaceID, workspaceID))) .then((rows) => rows[0]?.amount), ) if (!amount) throw new Error("Payment not found") @@ -144,12 +136,7 @@ export async function POST(input: APIEvent) { .set({ timeRefunded: new Date(body.created * 1000), }) - .where( - and( - eq(PaymentTable.paymentID, paymentIntentID), - eq(PaymentTable.workspaceID, workspaceID), - ), - ) + .where(and(eq(PaymentTable.paymentID, paymentIntentID), eq(PaymentTable.workspaceID, workspaceID))) await tx .update(BillingTable) diff --git a/packages/console/app/src/routes/temp.tsx b/packages/console/app/src/routes/temp.tsx index 59987e4d..b0aef00e 100644 --- a/packages/console/app/src/routes/temp.tsx +++ b/packages/console/app/src/routes/temp.tsx @@ -79,19 +79,17 @@ export default function Home() { LSP enabled Automatically loads the right LSPs for the LLM
  • - opencode zen A curated list of models{" "} - provided by opencode + opencode zen A curated list of models provided by opencode{" "} +
  • Multi-session Start multiple agents in parallel on the same project
  • - Shareable links Share a link to any sessions for reference or to - debug + Shareable links Share a link to any sessions for reference or to debug
  • - Claude Pro Log in with Anthropic to use your Claude Pro or Max - account + Claude Pro Log in with Anthropic to use your Claude Pro or Max account
  • Use any model Supports 75+ LLM providers through{" "} diff --git a/packages/console/app/src/routes/workspace-picker.tsx b/packages/console/app/src/routes/workspace-picker.tsx index 4e218227..fa8cf1d2 100644 --- a/packages/console/app/src/routes/workspace-picker.tsx +++ b/packages/console/app/src/routes/workspace-picker.tsx @@ -85,10 +85,7 @@ export function WorkspacePicker() { {(workspace) => ( - handleSelectWorkspace(workspace.id)} - > + handleSelectWorkspace(workspace.id)}> {workspace.name || workspace.slug} )} @@ -98,11 +95,7 @@ export function WorkspacePicker() { - setStore("showForm", false)} - title="Create New Workspace" - > + setStore("showForm", false)} title="Create New Workspace">

    Billing

    - Manage payments methods. Contact us if you have any - questions. + Manage payments methods. Contact us if you have any questions.

    @@ -164,32 +163,20 @@ export function BillingSection() { placeholder="Enter amount" />
    -
    - + {(err: any) =>
    {err()}
    }
  • @@ -210,10 +197,7 @@ export function BillingSection() {
    - ----} - > + ----}> •••• {billingInfo()?.paymentMethodLast4} @@ -241,9 +225,7 @@ export function BillingSection() { disabled={checkoutSubmission.pending || store.checkoutRedirecting} onClick={onClickCheckout} > - {checkoutSubmission.pending || store.checkoutRedirecting - ? "Loading..." - : "Enable Billing"} + {checkoutSubmission.pending || store.checkoutRedirecting ? "Loading..." : "Enable Billing"}
    diff --git a/packages/console/app/src/routes/workspace/[id]/billing/monthly-limit-section.tsx b/packages/console/app/src/routes/workspace/[id]/billing/monthly-limit-section.tsx index e6461ac8..77c01796 100644 --- a/packages/console/app/src/routes/workspace/[id]/billing/monthly-limit-section.tsx +++ b/packages/console/app/src/routes/workspace/[id]/billing/monthly-limit-section.tsx @@ -104,13 +104,9 @@ export function MonthlyLimitSection() {
    - No usage limit set.

    } - > + No usage limit set.

    }>

    - Current usage for{" "} - {new Date().toLocaleDateString("en-US", { month: "long", timeZone: "UTC" })} is $ + Current usage for {new Date().toLocaleDateString("en-US", { month: "long", timeZone: "UTC" })} is $ {(() => { const dateLastUsed = billingInfo()?.timeMonthlyUsageUpdated if (!dateLastUsed) return "0" diff --git a/packages/console/app/src/routes/workspace/[id]/billing/payment-section.tsx b/packages/console/app/src/routes/workspace/[id]/billing/payment-section.tsx index a7218546..0fb2a0df 100644 --- a/packages/console/app/src/routes/workspace/[id]/billing/payment-section.tsx +++ b/packages/console/app/src/routes/workspace/[id]/billing/payment-section.tsx @@ -89,10 +89,7 @@ export function PaymentSection() { } > diff --git a/packages/console/app/src/routes/workspace/[id]/keys/key-section.tsx b/packages/console/app/src/routes/workspace/[id]/keys/key-section.tsx index e1c2c00c..565981c7 100644 --- a/packages/console/app/src/routes/workspace/[id]/keys/key-section.tsx +++ b/packages/console/app/src/routes/workspace/[id]/keys/key-section.tsx @@ -146,20 +146,14 @@ export function KeySection() { title="Copy API key" > {key.keyDisplay} - } - > + }> {key.email} - + {key.timeUsed ? formatDateForTable(key.timeUsed) : "-"} diff --git a/packages/console/app/src/routes/workspace/[id]/members/member-section.tsx b/packages/console/app/src/routes/workspace/[id]/members/member-section.tsx index 4b2a12fd..5aa1b969 100644 --- a/packages/console/app/src/routes/workspace/[id]/members/member-section.tsx +++ b/packages/console/app/src/routes/workspace/[id]/members/member-section.tsx @@ -85,12 +85,7 @@ const updateMember = action(async (form: FormData) => { ) }, "member.update") -function MemberRow(props: { - member: any - workspaceID: string - actorID: string - actorRole: string -}) { +function MemberRow(props: { member: any; workspaceID: string; actorID: string; actorRole: string }) { const submission = useSubmission(updateMember) const isCurrentUser = () => props.actorID === props.member.id const isAdmin = () => props.actorRole === "admin" diff --git a/packages/console/app/src/routes/workspace/[id]/model-section.tsx b/packages/console/app/src/routes/workspace/[id]/model-section.tsx index 223d69fc..7a1980eb 100644 --- a/packages/console/app/src/routes/workspace/[id]/model-section.tsx +++ b/packages/console/app/src/routes/workspace/[id]/model-section.tsx @@ -5,15 +5,7 @@ import { withActor } from "~/context/auth.withActor" import { ZenData } from "@opencode-ai/console-core/model.js" import styles from "./model-section.module.css" import { querySessionInfo } from "../common" -import { - IconAlibaba, - IconAnthropic, - IconMoonshotAI, - IconOpenAI, - IconStealth, - IconXai, - IconZai, -} from "~/component/icon" +import { IconAlibaba, IconAnthropic, IconMoonshotAI, IconOpenAI, IconStealth, IconXai, IconZai } from "~/component/icon" const getModelLab = (modelId: string) => { if (modelId.startsWith("claude")) return "Anthropic" @@ -76,8 +68,7 @@ export function ModelSection() {

    Models

    - Manage which models workspace members can access.{" "} - Learn more. + Manage which models workspace members can access. Learn more.

    diff --git a/packages/console/app/src/routes/workspace/[id]/new-user-section.tsx b/packages/console/app/src/routes/workspace/[id]/new-user-section.tsx index 7b949c66..65edc684 100644 --- a/packages/console/app/src/routes/workspace/[id]/new-user-section.tsx +++ b/packages/console/app/src/routes/workspace/[id]/new-user-section.tsx @@ -43,24 +43,15 @@ export function NewUserSection() {

    Tested & Verified Models

    -

    - We've benchmarked and tested models specifically for coding agents to ensure the best - performance. -

    +

    We've benchmarked and tested models specifically for coding agents to ensure the best performance.

    Highest Quality

    -

    - Access models configured for optimal performance - no downgrades or routing to cheaper - providers. -

    +

    Access models configured for optimal performance - no downgrades or routing to cheaper providers.

    No Lock-in

    -

    - Use Zen with any coding agent, and continue using other providers with opencode - whenever you want. -

    +

    Use Zen with any coding agent, and continue using other providers with opencode whenever you want.

    diff --git a/packages/console/app/src/routes/workspace/[id]/provider-section.tsx b/packages/console/app/src/routes/workspace/[id]/provider-section.tsx index 67314fbd..5419ed7f 100644 --- a/packages/console/app/src/routes/workspace/[id]/provider-section.tsx +++ b/packages/console/app/src/routes/workspace/[id]/provider-section.tsx @@ -55,10 +55,7 @@ const listProviders = query(async (workspaceID: string) => { function ProviderRow(props: { provider: Provider }) { const params = useParams() const providers = createAsync(() => listProviders(params.id)) - const saveSubmission = useSubmission( - saveProvider, - ([fd]) => fd.get("provider")?.toString() === props.provider.key, - ) + const saveSubmission = useSubmission(saveProvider, ([fd]) => fd.get("provider")?.toString() === props.provider.key) const removeSubmission = useSubmission( removeProvider, ([fd]) => fd.get("provider")?.toString() === props.provider.key, @@ -94,16 +91,9 @@ function ProviderRow(props: { provider: Provider }) { {providerData() ? maskCredentials(providerData()!.credentials) : "-"} - } + fallback={{providerData() ? maskCredentials(providerData()!.credentials) : "-"}} > - +
    (input = r)} diff --git a/packages/console/app/src/routes/workspace/common.tsx b/packages/console/app/src/routes/workspace/common.tsx index 5b638192..a6eaaeb1 100644 --- a/packages/console/app/src/routes/workspace/common.tsx +++ b/packages/console/app/src/routes/workspace/common.tsx @@ -67,10 +67,7 @@ export const querySessionInfo = query(async (workspaceID: string) => { return withActor(() => { return { isAdmin: Actor.userRole() === "admin", - isBeta: - Resource.App.stage === "production" - ? workspaceID === "wrk_01K46JDFR0E75SG2Q8K172KF3Y" - : true, + isBeta: Resource.App.stage === "production" ? workspaceID === "wrk_01K46JDFR0E75SG2Q8K172KF3Y" : true, } }, workspaceID) }, "session.get") diff --git a/packages/console/app/src/routes/zen/index.tsx b/packages/console/app/src/routes/zen/index.tsx index a096b52d..4eab4dcb 100644 --- a/packages/console/app/src/routes/zen/index.tsx +++ b/packages/console/app/src/routes/zen/index.tsx @@ -29,10 +29,7 @@ export default function Home() { createAsync(() => checkLoggedIn()) return (
    - + OpenCode Zen | A curated set of reliable optimized models for coding agents @@ -49,19 +46,13 @@ export default function Home() { zen logo dark

    Reliable optimized models for coding agents

    - Zen gives you access to a curated set of AI models that OpenCode has tested and - benchmarked specifically for coding agents. No need to worry about inconsistent - performance and quality, use validated models that work. + Zen gives you access to a curated set of AI models that OpenCode has tested and benchmarked specifically + for coding agents. No need to worry about inconsistent performance and quality, use validated models + that work.

    - +
    - - + +
    - +
    - +
    - + Get started with Zen - +

    - Add $20 Pay as you go balance{" "} - (+$1.23 card processing fee) + Add $20 Pay as you go balance (+$1.23 card processing fee)

    Use with any agent. Set monthly spend limits. Cancel any time.

    -
    @@ -193,8 +142,8 @@ export default function Home() {

    What problem is Zen solving?

    - There are so many models available, but only a few work well with coding agents. - Most providers configure them differently with varying results. + There are so many models available, but only a few work well with coding agents. Most providers + configure them differently with varying results.

    We're fixing this for everyone, not just OpenCode users.

    @@ -229,15 +178,14 @@ export default function Home() {
  • [2]
    - Use Zen with transparent pricing -{" "} - pay per request with zero markups + Use Zen with transparent pricing - pay per request{" "} + with zero markups
  • [3]
    - Auto-top up - when your balance reaches $5 we’ll automatically - add $20 + Auto-top up - when your balance reaches $5 we’ll automatically add $20
  • @@ -249,9 +197,8 @@ export default function Home() {
    [*]

    - All Zen models are hosted in the US. Providers follow a zero-retention policy and - do not use your data for model training, with the{" "} - following exceptions. + All Zen models are hosted in the US. Providers follow a zero-retention policy and do not use your data + for model training, with the following exceptions.

    @@ -306,8 +253,7 @@ export default function Home() { ex-Head of Design, Laravel
    - With @OpenCode Zen I know all the models are tested and perfect for - coding agents. + With @OpenCode Zen I know all the models are tested and perfect for coding agents.
    @@ -331,44 +277,38 @@ export default function Home() {
    • - Zen is a curated set of AI models tested and benchmarked for coding agents created - by the team behind OpenCode. + Zen is a curated set of AI models tested and benchmarked for coding agents created by the team behind + OpenCode.
    • - Zen only provides models that have been specifically tested and benchmarked for - coding agents. You wouldn’t use a butter knife to cut steak, don’t use poor models - for coding. + Zen only provides models that have been specifically tested and benchmarked for coding agents. You + wouldn’t use a butter knife to cut steak, don’t use poor models for coding.
    • - Zen is not for profit. Zen passes through the costs from the model providers to - you. The higher Zen’s usage the more OpenCode can negotiate better rates and pass - those to you. + Zen is not for profit. Zen passes through the costs from the model providers to you. The higher Zen’s + usage the more OpenCode can negotiate better rates and pass those to you.
    • - Zen charges per request with zero markups, so you - pay exactly what the model provider charges. Your total cost depends on usage, and - you can set monthly spend limits in your account. To cover - costs, OpenCode adds only a small payment processing fee of $1.23 per $20 balance - top-up. + Zen charges per request with zero markups, so you pay exactly what + the model provider charges. Your total cost depends on usage, and you can set monthly spend limits in + your account. To cover costs, OpenCode adds only a small payment processing fee of + $1.23 per $20 balance top-up.
    • - All Zen models are hosted in the US. Providers follow a zero-retention policy and - do not use your data for model training, with the{" "} - following exceptions. + All Zen models are hosted in the US. Providers follow a zero-retention policy and do not use your data + for model training, with the following exceptions.
    • - - Yes, you can set monthly spending limits in your account. - + Yes, you can set monthly spending limits in your account.
    • @@ -377,8 +317,8 @@ export default function Home() {
    • - While Zen works great with OpenCode, you can use Zen with any agent. Follow the - setup instructions in your preferred coding agent. + While Zen works great with OpenCode, you can use Zen with any agent. Follow the setup instructions in + your preferred coding agent.
    diff --git a/packages/console/app/src/routes/zen/util/handler.ts b/packages/console/app/src/routes/zen/util/handler.ts index deab7ded..194a7c71 100644 --- a/packages/console/app/src/routes/zen/util/handler.ts +++ b/packages/console/app/src/routes/zen/util/handler.ts @@ -13,11 +13,7 @@ import { ModelTable } from "@opencode-ai/console-core/schema/model.sql.js" import { ProviderTable } from "@opencode-ai/console-core/schema/provider.sql.js" import { logger } from "./logger" import { AuthError, CreditsError, MonthlyLimitError, UserLimitError, ModelError } from "./error" -import { - createBodyConverter, - createStreamPartConverter, - createResponseConverter, -} from "./provider/provider" +import { createBodyConverter, createStreamPartConverter, createResponseConverter } from "./provider/provider" import { anthropicHelper } from "./provider/anthropic" import { openaiHelper } from "./provider/openai" import { oaCompatHelper } from "./provider/openai-compatible" @@ -46,11 +42,7 @@ export async function handler( }) const zenData = ZenData.list() const modelInfo = validateModel(zenData, body.model) - const providerInfo = selectProvider( - zenData, - modelInfo, - input.request.headers.get("x-real-ip") ?? "", - ) + const providerInfo = selectProvider(zenData, modelInfo, input.request.headers.get("x-real-ip") ?? "") const authInfo = await authenticate(modelInfo, providerInfo) validateBilling(modelInfo, authInfo) validateModelSettings(authInfo) @@ -229,11 +221,7 @@ export async function handler( return { id: modelId, ...modelData } } - function selectProvider( - zenData: ZenData, - model: Awaited>, - ip: string, - ) { + function selectProvider(zenData: ZenData, model: Awaited>, ip: string) { const providers = model.providers .filter((provider) => !provider.disabled) .flatMap((provider) => Array(provider.weight ?? 1).fill(provider)) @@ -252,11 +240,7 @@ export async function handler( return { ...provider, ...zenData.providers[provider.id], - ...(format === "anthropic" - ? anthropicHelper - : format === "openai" - ? openaiHelper - : oaCompatHelper), + ...(format === "anthropic" ? anthropicHelper : format === "openai" ? openaiHelper : oaCompatHelper), } } @@ -297,20 +281,11 @@ export async function handler( .from(KeyTable) .innerJoin(WorkspaceTable, eq(WorkspaceTable.id, KeyTable.workspaceID)) .innerJoin(BillingTable, eq(BillingTable.workspaceID, KeyTable.workspaceID)) - .innerJoin( - UserTable, - and(eq(UserTable.workspaceID, KeyTable.workspaceID), eq(UserTable.id, KeyTable.userID)), - ) - .leftJoin( - ModelTable, - and(eq(ModelTable.workspaceID, KeyTable.workspaceID), eq(ModelTable.model, model.id)), - ) + .innerJoin(UserTable, and(eq(UserTable.workspaceID, KeyTable.workspaceID), eq(UserTable.id, KeyTable.userID))) + .leftJoin(ModelTable, and(eq(ModelTable.workspaceID, KeyTable.workspaceID), eq(ModelTable.model, model.id))) .leftJoin( ProviderTable, - and( - eq(ProviderTable.workspaceID, KeyTable.workspaceID), - eq(ProviderTable.provider, providerInfo.id), - ), + and(eq(ProviderTable.workspaceID, KeyTable.workspaceID), eq(ProviderTable.provider, providerInfo.id)), ) .where(and(eq(KeyTable.key, apiKey), isNull(KeyTable.timeDeleted))) .then((rows) => rows[0]), @@ -401,19 +376,12 @@ export async function handler( providerInfo: Awaited>, usage: any, ) { - const { - inputTokens, - outputTokens, - reasoningTokens, - cacheReadTokens, - cacheWrite5mTokens, - cacheWrite1hTokens, - } = providerInfo.normalizeUsage(usage) + const { inputTokens, outputTokens, reasoningTokens, cacheReadTokens, cacheWrite5mTokens, cacheWrite1hTokens } = + providerInfo.normalizeUsage(usage) const modelCost = modelInfo.cost200K && - inputTokens + (cacheReadTokens ?? 0) + (cacheWrite5mTokens ?? 0) + (cacheWrite1hTokens ?? 0) > - 200_000 + inputTokens + (cacheReadTokens ?? 0) + (cacheWrite5mTokens ?? 0) + (cacheWrite1hTokens ?? 0) > 200_000 ? modelInfo.cost200K : modelInfo.cost @@ -464,8 +432,7 @@ export async function handler( if (!authInfo) return - const cost = - authInfo.isFree || authInfo.provider?.credentials ? 0 : centsToMicroCents(totalCostInCent) + const cost = authInfo.isFree || authInfo.provider?.credentials ? 0 : centsToMicroCents(totalCostInCent) await Database.transaction(async (tx) => { await tx.insert(UsageTable).values({ workspaceID: authInfo.workspaceID, @@ -505,9 +472,7 @@ export async function handler( `, timeMonthlyUsageUpdated: sql`now()`, }) - .where( - and(eq(UserTable.workspaceID, authInfo.workspaceID), eq(UserTable.id, authInfo.user.id)), - ) + .where(and(eq(UserTable.workspaceID, authInfo.workspaceID), eq(UserTable.id, authInfo.user.id))) }) await Database.use((tx) => @@ -537,10 +502,7 @@ export async function handler( BillingTable.balance, centsToMicroCents((authInfo.billing.reloadTrigger ?? Billing.RELOAD_TRIGGER) * 100), ), - or( - isNull(BillingTable.timeReloadLockedTill), - lt(BillingTable.timeReloadLockedTill, sql`now()`), - ), + or(isNull(BillingTable.timeReloadLockedTill), lt(BillingTable.timeReloadLockedTill, sql`now()`)), ), ), ) diff --git a/packages/console/app/src/routes/zen/util/provider/anthropic.ts b/packages/console/app/src/routes/zen/util/provider/anthropic.ts index f4e8dc44..d8d1cd74 100644 --- a/packages/console/app/src/routes/zen/util/provider/anthropic.ts +++ b/packages/console/app/src/routes/zen/util/provider/anthropic.ts @@ -123,15 +123,12 @@ export function fromAnthropicRequest(body: any): CommonRequest { if ((p as any).type === "tool_result") { const id = (p as any).tool_use_id const content = - typeof (p as any).content === "string" - ? (p as any).content - : JSON.stringify((p as any).content) + typeof (p as any).content === "string" ? (p as any).content : JSON.stringify((p as any).content) msgs.push({ role: "tool", tool_call_id: id, content }) } } if (partsOut.length > 0) { - if (partsOut.length === 1 && partsOut[0].type === "text") - msgs.push({ role: "user", content: partsOut[0].text }) + if (partsOut.length === 1 && partsOut[0].type === "text") msgs.push({ role: "user", content: partsOut[0].text }) else msgs.push({ role: "user", content: partsOut }) } continue @@ -143,8 +140,7 @@ export function fromAnthropicRequest(body: any): CommonRequest { const tcs: any[] = [] for (const p of partsIn) { if (!p || !(p as any).type) continue - if ((p as any).type === "text" && typeof (p as any).text === "string") - texts.push((p as any).text) + if ((p as any).type === "text" && typeof (p as any).text === "string") texts.push((p as any).text) if ((p as any).type === "tool_use") { const name = (p as any).name const id = (p as any).id @@ -214,9 +210,7 @@ export function fromAnthropicRequest(body: any): CommonRequest { export function toAnthropicRequest(body: CommonRequest) { if (!body || typeof body !== "object") return body - const sysIn = Array.isArray(body.messages) - ? body.messages.filter((m: any) => m && m.role === "system") - : [] + const sysIn = Array.isArray(body.messages) ? body.messages.filter((m: any) => m && m.role === "system") : [] let ccCount = 0 const cc = () => { ccCount++ @@ -367,9 +361,7 @@ export function fromAnthropicResponse(resp: any): CommonResponse { const idIn = (resp as any).id const id = - typeof idIn === "string" - ? idIn.replace(/^msg_/, "chatcmpl_") - : `chatcmpl_${Math.random().toString(36).slice(2)}` + typeof idIn === "string" ? idIn.replace(/^msg_/, "chatcmpl_") : `chatcmpl_${Math.random().toString(36).slice(2)}` const model = (resp as any).model const blocks: any[] = Array.isArray((resp as any).content) ? (resp as any).content : [] @@ -412,9 +404,7 @@ export function fromAnthropicResponse(resp: any): CommonResponse { const ct = typeof (u as any).output_tokens === "number" ? (u as any).output_tokens : undefined const total = pt != null && ct != null ? pt + ct : undefined const cached = - typeof (u as any).cache_read_input_tokens === "number" - ? (u as any).cache_read_input_tokens - : undefined + typeof (u as any).cache_read_input_tokens === "number" ? (u as any).cache_read_input_tokens : undefined const details = cached != null ? { cached_tokens: cached } : undefined return { prompt_tokens: pt, @@ -591,9 +581,7 @@ export function fromAnthropicChunk(chunk: string): CommonChunk | string { prompt_tokens: u.input_tokens, completion_tokens: u.output_tokens, total_tokens: (u.input_tokens || 0) + (u.output_tokens || 0), - ...(u.cache_read_input_tokens - ? { prompt_tokens_details: { cached_tokens: u.cache_read_input_tokens } } - : {}), + ...(u.cache_read_input_tokens ? { prompt_tokens_details: { cached_tokens: u.cache_read_input_tokens } } : {}), } } diff --git a/packages/console/app/src/routes/zen/util/provider/openai-compatible.ts b/packages/console/app/src/routes/zen/util/provider/openai-compatible.ts index d6998572..8a9170ef 100644 --- a/packages/console/app/src/routes/zen/util/provider/openai-compatible.ts +++ b/packages/console/app/src/routes/zen/util/provider/openai-compatible.ts @@ -57,8 +57,7 @@ export const oaCompatHelper = { const inputTokens = usage.prompt_tokens ?? 0 const outputTokens = usage.completion_tokens ?? 0 const reasoningTokens = usage.completion_tokens_details?.reasoning_tokens ?? undefined - const cacheReadTokens = - usage.cached_tokens ?? usage.prompt_tokens_details?.cached_tokens ?? undefined + const cacheReadTokens = usage.cached_tokens ?? usage.prompt_tokens_details?.cached_tokens ?? undefined return { inputTokens: inputTokens - (cacheReadTokens ?? 0), outputTokens, @@ -80,8 +79,7 @@ export function fromOaCompatibleRequest(body: any): CommonRequest { if (!m || !m.role) continue if (m.role === "system") { - if (typeof m.content === "string" && m.content.length > 0) - msgsOut.push({ role: "system", content: m.content }) + if (typeof m.content === "string" && m.content.length > 0) msgsOut.push({ role: "system", content: m.content }) continue } @@ -92,12 +90,10 @@ export function fromOaCompatibleRequest(body: any): CommonRequest { const parts: any[] = [] for (const p of m.content) { if (!p || !p.type) continue - if (p.type === "text" && typeof p.text === "string") - parts.push({ type: "text", text: p.text }) + if (p.type === "text" && typeof p.text === "string") parts.push({ type: "text", text: p.text }) if (p.type === "image_url") parts.push({ type: "image_url", image_url: p.image_url }) } - if (parts.length === 1 && parts[0].type === "text") - msgsOut.push({ role: "user", content: parts[0].text }) + if (parts.length === 1 && parts[0].type === "text") msgsOut.push({ role: "user", content: parts[0].text }) else if (parts.length > 0) msgsOut.push({ role: "user", content: parts }) } continue @@ -141,8 +137,7 @@ export function toOaCompatibleRequest(body: CommonRequest) { if (p.type === "image_url" && p.image_url) return { type: "image_url", image_url: p.image_url } const s = (p as any).source if (!s || typeof s !== "object") return undefined - if (s.type === "url" && typeof s.url === "string") - return { type: "image_url", image_url: { url: s.url } } + if (s.type === "url" && typeof s.url === "string") return { type: "image_url", image_url: { url: s.url } } if (s.type === "base64" && typeof s.media_type === "string" && typeof s.data === "string") return { type: "image_url", image_url: { url: `data:${s.media_type};base64,${s.data}` } } return undefined @@ -152,8 +147,7 @@ export function toOaCompatibleRequest(body: CommonRequest) { if (!m || !m.role) continue if (m.role === "system") { - if (typeof m.content === "string" && m.content.length > 0) - msgsOut.push({ role: "system", content: m.content }) + if (typeof m.content === "string" && m.content.length > 0) msgsOut.push({ role: "system", content: m.content }) continue } @@ -166,13 +160,11 @@ export function toOaCompatibleRequest(body: CommonRequest) { const parts: any[] = [] for (const p of m.content) { if (!p || !p.type) continue - if (p.type === "text" && typeof p.text === "string") - parts.push({ type: "text", text: p.text }) + if (p.type === "text" && typeof p.text === "string") parts.push({ type: "text", text: p.text }) const ip = toImg(p) if (ip) parts.push(ip) } - if (parts.length === 1 && parts[0].type === "text") - msgsOut.push({ role: "user", content: parts[0].text }) + if (parts.length === 1 && parts[0].type === "text") msgsOut.push({ role: "user", content: parts[0].text }) else if (parts.length > 0) msgsOut.push({ role: "user", content: parts }) } continue @@ -325,9 +317,7 @@ export function toOaCompatibleResponse(resp: CommonResponse) { const idIn = (resp as any).id const id = - typeof idIn === "string" - ? idIn.replace(/^msg_/, "chatcmpl_") - : `chatcmpl_${Math.random().toString(36).slice(2)}` + typeof idIn === "string" ? idIn.replace(/^msg_/, "chatcmpl_") : `chatcmpl_${Math.random().toString(36).slice(2)}` const model = (resp as any).model const blocks: any[] = Array.isArray((resp as any).content) ? (resp as any).content : [] @@ -369,8 +359,7 @@ export function toOaCompatibleResponse(resp: CommonResponse) { const pt = typeof u.input_tokens === "number" ? u.input_tokens : undefined const ct = typeof u.output_tokens === "number" ? u.output_tokens : undefined const total = pt != null && ct != null ? pt + ct : undefined - const cached = - typeof u.cache_read_input_tokens === "number" ? u.cache_read_input_tokens : undefined + const cached = typeof u.cache_read_input_tokens === "number" ? u.cache_read_input_tokens : undefined const details = cached != null ? { cached_tokens: cached } : undefined return { prompt_tokens: pt, diff --git a/packages/console/app/src/routes/zen/util/provider/openai.ts b/packages/console/app/src/routes/zen/util/provider/openai.ts index fa0776b7..e79e8357 100644 --- a/packages/console/app/src/routes/zen/util/provider/openai.ts +++ b/packages/console/app/src/routes/zen/util/provider/openai.ts @@ -86,11 +86,7 @@ export function fromOpenaiRequest(body: any): CommonRequest { const msgs: any[] = [] - const inMsgs = Array.isArray(body.input) - ? body.input - : Array.isArray(body.messages) - ? body.messages - : [] + const inMsgs = Array.isArray(body.input) ? body.input : Array.isArray(body.messages) ? body.messages : [] for (const m of inMsgs) { if (!m) continue @@ -103,9 +99,7 @@ export function fromOpenaiRequest(body: any): CommonRequest { const args = typeof a === "string" ? a : JSON.stringify(a ?? {}) msgs.push({ role: "assistant", - tool_calls: [ - { id: (m as any).id, type: "function", function: { name, arguments: args } }, - ], + tool_calls: [{ id: (m as any).id, type: "function", function: { name, arguments: args } }], }) } if ((m as any).type === "function_call_output") { @@ -122,8 +116,7 @@ export function fromOpenaiRequest(body: any): CommonRequest { if (typeof c === "string" && c.length > 0) msgs.push({ role: "system", content: c }) if (Array.isArray(c)) { const t = c.find((p: any) => p && typeof p.text === "string") - if (t && typeof t.text === "string" && t.text.length > 0) - msgs.push({ role: "system", content: t.text }) + if (t && typeof t.text === "string" && t.text.length > 0) msgs.push({ role: "system", content: t.text }) } continue } @@ -136,24 +129,18 @@ export function fromOpenaiRequest(body: any): CommonRequest { const parts: any[] = [] for (const p of c) { if (!p || !(p as any).type) continue - if ( - ((p as any).type === "text" || (p as any).type === "input_text") && - typeof (p as any).text === "string" - ) + if (((p as any).type === "text" || (p as any).type === "input_text") && typeof (p as any).text === "string") parts.push({ type: "text", text: (p as any).text }) const ip = toImg(p) if (ip) parts.push(ip) if ((p as any).type === "tool_result") { const id = (p as any).tool_call_id const content = - typeof (p as any).content === "string" - ? (p as any).content - : JSON.stringify((p as any).content) + typeof (p as any).content === "string" ? (p as any).content : JSON.stringify((p as any).content) msgs.push({ role: "tool", tool_call_id: id, content }) } } - if (parts.length === 1 && parts[0].type === "text") - msgs.push({ role: "user", content: parts[0].text }) + if (parts.length === 1 && parts[0].type === "text") msgs.push({ role: "user", content: parts[0].text }) else if (parts.length > 0) msgs.push({ role: "user", content: parts }) } continue @@ -280,10 +267,7 @@ export function toOpenaiRequest(body: CommonRequest) { } if ((m as any).role === "tool") { - const out = - typeof (m as any).content === "string" - ? (m as any).content - : JSON.stringify((m as any).content) + const out = typeof (m as any).content === "string" ? (m as any).content : JSON.stringify((m as any).content) input.push({ type: "function_call_output", call_id: (m as any).tool_call_id, output: out }) continue } @@ -351,9 +335,7 @@ export function fromOpenaiResponse(resp: any): CommonResponse { const idIn = (r as any).id const id = - typeof idIn === "string" - ? idIn.replace(/^resp_/, "chatcmpl_") - : `chatcmpl_${Math.random().toString(36).slice(2)}` + typeof idIn === "string" ? idIn.replace(/^resp_/, "chatcmpl_") : `chatcmpl_${Math.random().toString(36).slice(2)}` const model = (r as any).model ?? (resp as any).model const out = Array.isArray((r as any).output) ? (r as any).output : [] @@ -480,9 +462,7 @@ export function toOpenaiResponse(resp: CommonResponse) { })() return { - id: - (resp as any).id?.replace(/^chatcmpl_/, "resp_") ?? - `resp_${Math.random().toString(36).slice(2)}`, + id: (resp as any).id?.replace(/^chatcmpl_/, "resp_") ?? `resp_${Math.random().toString(36).slice(2)}`, object: "response", model: (resp as any).model, output: outputItems, diff --git a/packages/console/app/src/routes/zen/v1/models.ts b/packages/console/app/src/routes/zen/v1/models.ts index 3d0c3147..ee2b3ab5 100644 --- a/packages/console/app/src/routes/zen/v1/models.ts +++ b/packages/console/app/src/routes/zen/v1/models.ts @@ -50,10 +50,7 @@ export async function GET(input: APIEvent) { }) .from(KeyTable) .innerJoin(WorkspaceTable, eq(WorkspaceTable.id, KeyTable.workspaceID)) - .leftJoin( - ModelTable, - and(eq(ModelTable.workspaceID, KeyTable.workspaceID), isNull(ModelTable.timeDeleted)), - ) + .leftJoin(ModelTable, and(eq(ModelTable.workspaceID, KeyTable.workspaceID), isNull(ModelTable.timeDeleted))) .where(and(eq(KeyTable.key, apiKey), isNull(KeyTable.timeDeleted))) .then((rows) => rows.map((row) => row.model)), ) diff --git a/packages/console/app/src/style/token/font.css b/packages/console/app/src/style/token/font.css index dc0d298f..67143e66 100644 --- a/packages/console/app/src/style/token/font.css +++ b/packages/console/app/src/style/token/font.css @@ -15,7 +15,6 @@ body { --font-size-9xl: 8rem; --font-mono: - "IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", - "Courier New", monospace; + "IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; --font-sans: var(--font-mono); } diff --git a/packages/console/core/script/lookup-user.ts b/packages/console/core/script/lookup-user.ts index af9bcc3a..1ae18c4d 100644 --- a/packages/console/core/script/lookup-user.ts +++ b/packages/console/core/script/lookup-user.ts @@ -8,22 +8,15 @@ if (!email) { process.exit(1) } -const authData = await printTable("Auth", (tx) => - tx.select().from(AuthTable).where(eq(AuthTable.subject, email)), -) +const authData = await printTable("Auth", (tx) => tx.select().from(AuthTable).where(eq(AuthTable.subject, email))) if (authData.length === 0) { console.error("User not found") process.exit(1) } -await printTable("Auth", (tx) => - tx.select().from(AuthTable).where(eq(AuthTable.accountID, authData[0].accountID)), -) +await printTable("Auth", (tx) => tx.select().from(AuthTable).where(eq(AuthTable.accountID, authData[0].accountID))) -function printTable( - title: string, - callback: (tx: Database.TxOrDb) => Promise, -): Promise { +function printTable(title: string, callback: (tx: Database.TxOrDb) => Promise): Promise { return Database.use(async (tx) => { const data = await callback(tx) console.log(`== ${title} ==`) diff --git a/packages/console/core/script/reset-db.ts b/packages/console/core/script/reset-db.ts index bd00e196..02d49890 100644 --- a/packages/console/core/script/reset-db.ts +++ b/packages/console/core/script/reset-db.ts @@ -8,14 +8,6 @@ import { KeyTable } from "../src/schema/key.sql.js" if (Resource.App.stage !== "frank") throw new Error("This script is only for frank") -for (const table of [ - AccountTable, - BillingTable, - KeyTable, - PaymentTable, - UsageTable, - UserTable, - WorkspaceTable, -]) { +for (const table of [AccountTable, BillingTable, KeyTable, PaymentTable, UsageTable, UserTable, WorkspaceTable]) { await Database.use((tx) => tx.delete(table)) } diff --git a/packages/console/core/src/aws.ts b/packages/console/core/src/aws.ts index ce4a20f4..e87ada6e 100644 --- a/packages/console/core/src/aws.ts +++ b/packages/console/core/src/aws.ts @@ -24,40 +24,37 @@ export namespace AWS { body: z.string(), }), async (input) => { - const res = await createClient().fetch( - "https://email.us-east-1.amazonaws.com/v2/email/outbound-emails", - { - method: "POST", - headers: { - "X-Amz-Target": "SES.SendEmail", - "Content-Type": "application/json", + const res = await createClient().fetch("https://email.us-east-1.amazonaws.com/v2/email/outbound-emails", { + method: "POST", + headers: { + "X-Amz-Target": "SES.SendEmail", + "Content-Type": "application/json", + }, + body: JSON.stringify({ + FromEmailAddress: `OpenCode Zen `, + Destination: { + ToAddresses: [input.to], }, - body: JSON.stringify({ - FromEmailAddress: `OpenCode Zen `, - Destination: { - ToAddresses: [input.to], - }, - Content: { - Simple: { - Subject: { + Content: { + Simple: { + Subject: { + Charset: "UTF-8", + Data: input.subject, + }, + Body: { + Text: { Charset: "UTF-8", - Data: input.subject, + Data: input.body, }, - Body: { - Text: { - Charset: "UTF-8", - Data: input.body, - }, - Html: { - Charset: "UTF-8", - Data: input.body, - }, + Html: { + Charset: "UTF-8", + Data: input.body, }, }, }, - }), - }, - ) + }, + }), + }) if (!res.ok) { throw new Error(`Failed to send email: ${res.statusText}`) } diff --git a/packages/console/core/src/drizzle/index.ts b/packages/console/core/src/drizzle/index.ts index 8b37b1f9..f0f065de 100644 --- a/packages/console/core/src/drizzle/index.ts +++ b/packages/console/core/src/drizzle/index.ts @@ -5,10 +5,7 @@ import { Client } from "@planetscale/database" import { MySqlTransaction, type MySqlTransactionConfig } from "drizzle-orm/mysql-core" import type { ExtractTablesWithRelations } from "drizzle-orm" -import type { - PlanetScalePreparedQueryHKT, - PlanetscaleQueryResultHKT, -} from "drizzle-orm/planetscale-serverless" +import type { PlanetScalePreparedQueryHKT, PlanetscaleQueryResultHKT } from "drizzle-orm/planetscale-serverless" import { Context } from "../context" import { memo } from "../util/memo" @@ -70,10 +67,7 @@ export namespace Database { } } - export async function transaction( - callback: (tx: TxOrDb) => Promise, - config?: MySqlTransactionConfig, - ) { + export async function transaction(callback: (tx: TxOrDb) => Promise, config?: MySqlTransactionConfig) { try { const { tx } = TransactionContext.use() return callback(tx) diff --git a/packages/console/core/src/key.ts b/packages/console/core/src/key.ts index 6396fd0b..688f19b3 100644 --- a/packages/console/core/src/key.ts +++ b/packages/console/core/src/key.ts @@ -20,14 +20,8 @@ export namespace Key { email: AuthTable.subject, }) .from(KeyTable) - .innerJoin( - UserTable, - and(eq(KeyTable.userID, UserTable.id), eq(KeyTable.workspaceID, UserTable.workspaceID)), - ) - .innerJoin( - AuthTable, - and(eq(UserTable.accountID, AuthTable.accountID), eq(AuthTable.provider, "email")), - ) + .innerJoin(UserTable, and(eq(KeyTable.userID, UserTable.id), eq(KeyTable.workspaceID, UserTable.workspaceID))) + .innerJoin(AuthTable, and(eq(UserTable.accountID, AuthTable.accountID), eq(AuthTable.provider, "email"))) .where( and( ...[ diff --git a/packages/console/core/src/model.ts b/packages/console/core/src/model.ts index 30cc15e4..ea719534 100644 --- a/packages/console/core/src/model.ts +++ b/packages/console/core/src/model.ts @@ -60,9 +60,7 @@ export namespace Model { export const enable = fn(z.object({ model: z.string() }), ({ model }) => { Actor.assertAdmin() return Database.use((db) => - db - .delete(ModelTable) - .where(and(eq(ModelTable.workspaceID, Actor.workspace()), eq(ModelTable.model, model))), + db.delete(ModelTable).where(and(eq(ModelTable.workspaceID, Actor.workspace()), eq(ModelTable.model, model))), ) }) diff --git a/packages/console/core/src/provider.ts b/packages/console/core/src/provider.ts index 0af642f7..cf2040b5 100644 --- a/packages/console/core/src/provider.ts +++ b/packages/console/core/src/provider.ts @@ -11,9 +11,7 @@ export namespace Provider { tx .select() .from(ProviderTable) - .where( - and(eq(ProviderTable.workspaceID, Actor.workspace()), isNull(ProviderTable.timeDeleted)), - ), + .where(and(eq(ProviderTable.workspaceID, Actor.workspace()), isNull(ProviderTable.timeDeleted))), ), ) @@ -52,12 +50,7 @@ export namespace Provider { return Database.transaction((tx) => tx .delete(ProviderTable) - .where( - and( - eq(ProviderTable.provider, provider), - eq(ProviderTable.workspaceID, Actor.workspace()), - ), - ), + .where(and(eq(ProviderTable.provider, provider), eq(ProviderTable.workspaceID, Actor.workspace()))), ) }, ) diff --git a/packages/console/core/src/schema/auth.sql.ts b/packages/console/core/src/schema/auth.sql.ts index d55e605a..27c926d6 100644 --- a/packages/console/core/src/schema/auth.sql.ts +++ b/packages/console/core/src/schema/auth.sql.ts @@ -1,11 +1,4 @@ -import { - index, - mysqlEnum, - mysqlTable, - primaryKey, - uniqueIndex, - varchar, -} from "drizzle-orm/mysql-core" +import { index, mysqlEnum, mysqlTable, primaryKey, uniqueIndex, varchar } from "drizzle-orm/mysql-core" import { id, timestamps, ulid } from "../drizzle/types" export const AuthProvider = ["email", "github", "google"] as const diff --git a/packages/console/core/src/schema/model.sql.ts b/packages/console/core/src/schema/model.sql.ts index 343b0c4f..1c032aad 100644 --- a/packages/console/core/src/schema/model.sql.ts +++ b/packages/console/core/src/schema/model.sql.ts @@ -9,8 +9,5 @@ export const ModelTable = mysqlTable( ...timestamps, model: varchar("model", { length: 64 }).notNull(), }, - (table) => [ - ...workspaceIndexes(table), - uniqueIndex("model_workspace_model").on(table.workspaceID, table.model), - ], + (table) => [...workspaceIndexes(table), uniqueIndex("model_workspace_model").on(table.workspaceID, table.model)], ) diff --git a/packages/console/core/src/schema/provider.sql.ts b/packages/console/core/src/schema/provider.sql.ts index 04d11e2e..11be5b4d 100644 --- a/packages/console/core/src/schema/provider.sql.ts +++ b/packages/console/core/src/schema/provider.sql.ts @@ -10,8 +10,5 @@ export const ProviderTable = mysqlTable( provider: varchar("provider", { length: 64 }).notNull(), credentials: text("credentials").notNull(), }, - (table) => [ - ...workspaceIndexes(table), - uniqueIndex("workspace_provider").on(table.workspaceID, table.provider), - ], + (table) => [...workspaceIndexes(table), uniqueIndex("workspace_provider").on(table.workspaceID, table.provider)], ) diff --git a/packages/console/core/src/schema/user.sql.ts b/packages/console/core/src/schema/user.sql.ts index ce5b6c53..7fd7f5e1 100644 --- a/packages/console/core/src/schema/user.sql.ts +++ b/packages/console/core/src/schema/user.sql.ts @@ -1,12 +1,4 @@ -import { - mysqlTable, - uniqueIndex, - varchar, - int, - mysqlEnum, - index, - bigint, -} from "drizzle-orm/mysql-core" +import { mysqlTable, uniqueIndex, varchar, int, mysqlEnum, index, bigint } from "drizzle-orm/mysql-core" import { timestamps, ulid, utc, workspaceColumns } from "../drizzle/types" import { workspaceIndexes } from "./workspace.sql" diff --git a/packages/console/core/src/user.ts b/packages/console/core/src/user.ts index cbb1ac82..8b7a96f4 100644 --- a/packages/console/core/src/user.ts +++ b/packages/console/core/src/user.ts @@ -26,10 +26,7 @@ export namespace User { authEmail: AuthTable.subject, }) .from(UserTable) - .leftJoin( - AuthTable, - and(eq(UserTable.accountID, AuthTable.accountID), eq(AuthTable.provider, "email")), - ) + .leftJoin(AuthTable, and(eq(UserTable.accountID, AuthTable.accountID), eq(AuthTable.provider, "email"))) .where(and(eq(UserTable.workspaceID, Actor.workspace()), isNull(UserTable.timeDeleted))), ), ) @@ -39,13 +36,7 @@ export namespace User { tx .select() .from(UserTable) - .where( - and( - eq(UserTable.workspaceID, Actor.workspace()), - eq(UserTable.id, id), - isNull(UserTable.timeDeleted), - ), - ) + .where(and(eq(UserTable.workspaceID, Actor.workspace()), eq(UserTable.id, id), isNull(UserTable.timeDeleted))) .then((rows) => rows[0]), ), ) @@ -57,10 +48,7 @@ export namespace User { email: AuthTable.subject, }) .from(UserTable) - .leftJoin( - AuthTable, - and(eq(UserTable.accountID, AuthTable.accountID), eq(AuthTable.provider, "email")), - ) + .leftJoin(AuthTable, and(eq(UserTable.accountID, AuthTable.accountID), eq(AuthTable.provider, "email"))) .where(and(eq(UserTable.workspaceID, Actor.workspace()), eq(UserTable.id, id))) .then((rows) => rows[0]?.email), ), @@ -142,16 +130,10 @@ export namespace User { workspaceName: WorkspaceTable.name, }) .from(UserTable) - .innerJoin( - AuthTable, - and(eq(UserTable.accountID, AuthTable.accountID), eq(AuthTable.provider, "email")), - ) + .innerJoin(AuthTable, and(eq(UserTable.accountID, AuthTable.accountID), eq(AuthTable.provider, "email"))) .innerJoin(WorkspaceTable, eq(WorkspaceTable.id, workspaceID)) .where( - and( - eq(UserTable.workspaceID, workspaceID), - eq(UserTable.id, Actor.assert("user").properties.userID), - ), + and(eq(UserTable.workspaceID, workspaceID), eq(UserTable.id, Actor.assert("user").properties.userID)), ) .then((rows) => rows[0]), ) diff --git a/packages/console/mail/emails/templates/InviteEmail.tsx b/packages/console/mail/emails/templates/InviteEmail.tsx index e94eb564..baf0d383 100644 --- a/packages/console/mail/emails/templates/InviteEmail.tsx +++ b/packages/console/mail/emails/templates/InviteEmail.tsx @@ -1,18 +1,6 @@ // @ts-nocheck import React from "react" -import { - Img, - Row, - Html, - Link, - Body, - Head, - Button, - Column, - Preview, - Section, - Container, -} from "@jsx-email/all" +import { Img, Row, Html, Link, Body, Head, Button, Column, Preview, Section, Container } from "@jsx-email/all" import { Text, Fonts, Title, A, Span } from "../components" import { unit, @@ -64,8 +52,8 @@ export const InviteEmail = ({
    Join your team's OpenCode workspace - You have been invited by {inviter} to join - the {workspaceName} workspace on OpenCode. + You have been invited by {inviter} to join the{" "} + {workspaceName} workspace on OpenCode.
    @@ -73,12 +61,7 @@ export const InviteEmail = ({ diff --git a/packages/function/src/api.ts b/packages/function/src/api.ts index 3475f5d7..6f00dae9 100644 --- a/packages/function/src/api.ts +++ b/packages/function/src/api.ts @@ -268,11 +268,7 @@ export default new Hono<{ Bindings: Env }>() // Verify permissions const userClient = new Octokit({ auth: token }) const { data: repoData } = await userClient.repos.get({ owner, repo }) - if ( - !repoData.permissions.admin && - !repoData.permissions.push && - !repoData.permissions.maintain - ) + if (!repoData.permissions.admin && !repoData.permissions.push && !repoData.permissions.maintain) throw new Error("User does not have write permissions") // Get installation token diff --git a/packages/opencode/script/build.ts b/packages/opencode/script/build.ts index 4ce8bfba..29706c09 100755 --- a/packages/opencode/script/build.ts +++ b/packages/opencode/script/build.ts @@ -41,9 +41,7 @@ for (const [os, arch] of targets) { const opentui = `@opentui/core-${os === "windows" ? "win32" : os}-${arch.replace("-baseline", "")}` await $`mkdir -p ../../node_modules/${opentui}` - await $`npm pack ${opentui}@${pkg.dependencies["@opentui/core"]}`.cwd( - path.join(dir, "../../node_modules"), - ) + await $`npm pack ${opentui}@${pkg.dependencies["@opentui/core"]}`.cwd(path.join(dir, "../../node_modules")) await $`tar -xf ../../node_modules/${opentui.replace("@opentui/", "opentui-")}-*.tgz -C ../../node_modules/${opentui} --strip-components=1` const watcher = `@parcel/watcher-${os === "windows" ? "win32" : os}-${arch.replace("-baseline", "")}${os === "linux" ? "-glibc" : ""}` @@ -51,9 +49,7 @@ for (const [os, arch] of targets) { await $`npm pack ${watcher}`.cwd(path.join(dir, "../../node_modules")).quiet() await $`tar -xf ../../node_modules/${watcher.replace("@parcel/", "parcel-")}-*.tgz -C ../../node_modules/${watcher} --strip-components=1` - const parserWorker = fs.realpathSync( - path.resolve(dir, "./node_modules/@opentui/core/parser.worker.js"), - ) + const parserWorker = fs.realpathSync(path.resolve(dir, "./node_modules/@opentui/core/parser.worker.js")) const workerPath = "./src/cli/cmd/tui/worker.ts" await Bun.build({ diff --git a/packages/opencode/script/postinstall.mjs b/packages/opencode/script/postinstall.mjs index 41865273..b875d158 100644 --- a/packages/opencode/script/postinstall.mjs +++ b/packages/opencode/script/postinstall.mjs @@ -77,8 +77,7 @@ async function regenerateWindowsCmdWrappers() { // npm_config_global is string | undefined // if it exists, the value is true - const isGlobal = - process.env.npm_config_global === "true" || pkgPath.includes(path.join("npm", "node_modules")) + const isGlobal = process.env.npm_config_global === "true" || pkgPath.includes(path.join("npm", "node_modules")) // The npm rebuild command does 2 things - Execute lifecycle scripts and rebuild bin links // We want to skip lifecycle scripts to avoid infinite loops, so we use --ignore-scripts @@ -94,9 +93,7 @@ async function regenerateWindowsCmdWrappers() { console.log("Successfully rebuilt npm bin links") } catch (error) { console.error("Error rebuilding npm links:", error.message) - console.error( - "npm rebuild failed. You may need to manually run: npm rebuild opencode-ai --ignore-scripts", - ) + console.error("npm rebuild failed. You may need to manually run: npm rebuild opencode-ai --ignore-scripts") } } diff --git a/packages/opencode/script/publish.ts b/packages/opencode/script/publish.ts index 3ae4ccf9..3e989cc6 100755 --- a/packages/opencode/script/publish.ts +++ b/packages/opencode/script/publish.ts @@ -55,18 +55,10 @@ if (!Script.preview) { } // Calculate SHA values - const arm64Sha = await $`sha256sum ./dist/opencode-linux-arm64.zip | cut -d' ' -f1` - .text() - .then((x) => x.trim()) - const x64Sha = await $`sha256sum ./dist/opencode-linux-x64.zip | cut -d' ' -f1` - .text() - .then((x) => x.trim()) - const macX64Sha = await $`sha256sum ./dist/opencode-darwin-x64.zip | cut -d' ' -f1` - .text() - .then((x) => x.trim()) - const macArm64Sha = await $`sha256sum ./dist/opencode-darwin-arm64.zip | cut -d' ' -f1` - .text() - .then((x) => x.trim()) + const arm64Sha = await $`sha256sum ./dist/opencode-linux-arm64.zip | cut -d' ' -f1`.text().then((x) => x.trim()) + const x64Sha = await $`sha256sum ./dist/opencode-linux-x64.zip | cut -d' ' -f1`.text().then((x) => x.trim()) + const macX64Sha = await $`sha256sum ./dist/opencode-darwin-x64.zip | cut -d' ' -f1`.text().then((x) => x.trim()) + const macArm64Sha = await $`sha256sum ./dist/opencode-darwin-arm64.zip | cut -d' ' -f1`.text().then((x) => x.trim()) const [pkgver, _subver = ""] = Script.version.split(/(-.*)/, 2) diff --git a/packages/opencode/script/schema.ts b/packages/opencode/script/schema.ts index 48bf6544..585701c9 100755 --- a/packages/opencode/script/schema.ts +++ b/packages/opencode/script/schema.ts @@ -19,23 +19,12 @@ const result = z.toJSONSchema(Config.Info, { const schema = ctx.jsonSchema // Preserve strictness: set additionalProperties: false for objects - if ( - schema && - typeof schema === "object" && - schema.type === "object" && - schema.additionalProperties === undefined - ) { + if (schema && typeof schema === "object" && schema.type === "object" && schema.additionalProperties === undefined) { schema.additionalProperties = false } // Add examples and default descriptions for string fields with defaults - if ( - schema && - typeof schema === "object" && - "type" in schema && - schema.type === "string" && - schema?.default - ) { + if (schema && typeof schema === "object" && "type" in schema && schema.type === "string" && schema?.default) { if (!schema.examples) { schema.examples = [schema.default] } diff --git a/packages/opencode/src/acp/agent.ts b/packages/opencode/src/acp/agent.ts index b25b6688..ff71b045 100644 --- a/packages/opencode/src/acp/agent.ts +++ b/packages/opencode/src/acp/agent.ts @@ -199,10 +199,8 @@ export namespace ACP { if (kind === "edit") { const input = part.state.input - const filePath = - typeof input["filePath"] === "string" ? input["filePath"] : "" - const oldText = - typeof input["oldString"] === "string" ? input["oldString"] : "" + const filePath = typeof input["filePath"] === "string" ? input["filePath"] : "" + const oldText = typeof input["oldString"] === "string" ? input["oldString"] : "" const newText = typeof input["newString"] === "string" ? input["newString"] @@ -218,9 +216,7 @@ export namespace ACP { } if (part.tool === "todowrite") { - const parsedTodos = z - .array(Todo.Info) - .safeParse(JSON.parse(part.state.output)) + const parsedTodos = z.array(Todo.Info).safeParse(JSON.parse(part.state.output)) if (parsedTodos.success) { await this.connection .sessionUpdate({ @@ -229,9 +225,7 @@ export namespace ACP { sessionUpdate: "plan", entries: parsedTodos.data.map((todo) => { const status: PlanEntry["status"] = - todo.status === "cancelled" - ? "completed" - : (todo.status as PlanEntry["status"]) + todo.status === "cancelled" ? "completed" : (todo.status as PlanEntry["status"]) return { priority: "medium", status, @@ -481,8 +475,7 @@ export namespace ACP { description: agent.description, })) - const currentModeId = - availableModes.find((m) => m.name === "build")?.id ?? availableModes[0].id + const currentModeId = availableModes.find((m) => m.name === "build")?.id ?? availableModes[0].id const mcpServers: Record = {} for (const server of params.mcpServers) { @@ -587,8 +580,7 @@ export namespace ACP { const agent = session.modeId ?? "build" const parts: Array< - | { type: "text"; text: string } - | { type: "file"; url: string; filename: string; mime: string } + { type: "text"; text: string } | { type: "file"; url: string; filename: string; mime: string } > = [] for (const part of params.prompt) { switch (part.type) { @@ -794,9 +786,7 @@ export namespace ACP { function parseUri( uri: string, - ): - | { type: "file"; url: string; filename: string; mime: string } - | { type: "text"; text: string } { + ): { type: "file"; url: string; filename: string; mime: string } | { type: "text"; text: string } { try { if (uri.startsWith("file://")) { const path = uri.slice(7) diff --git a/packages/opencode/src/acp/session.ts b/packages/opencode/src/acp/session.ts index eb9dd522..63948a8c 100644 --- a/packages/opencode/src/acp/session.ts +++ b/packages/opencode/src/acp/session.ts @@ -13,11 +13,7 @@ export class ACPSessionManager { this.sdk = sdk } - async create( - cwd: string, - mcpServers: McpServer[], - model?: ACPSessionState["model"], - ): Promise { + async create(cwd: string, mcpServers: McpServer[], model?: ACPSessionState["model"]): Promise { const session = await this.sdk.session .create({ body: { diff --git a/packages/opencode/src/agent/agent.ts b/packages/opencode/src/agent/agent.ts index 16f40162..a6933708 100644 --- a/packages/opencode/src/agent/agent.ts +++ b/packages/opencode/src/agent/agent.ts @@ -143,18 +143,7 @@ export namespace Agent { tools: {}, builtIn: false, } - const { - name, - model, - prompt, - tools, - description, - temperature, - top_p, - mode, - permission, - ...extra - } = value + const { name, model, prompt, tools, description, temperature, top_p, mode, permission, ...extra } = value item.options = { ...item.options, ...extra, @@ -223,10 +212,7 @@ export namespace Agent { } } -function mergeAgentPermissions( - basePermission: any, - overridePermission: any, -): Agent.Info["permission"] { +function mergeAgentPermissions(basePermission: any, overridePermission: any): Agent.Info["permission"] { if (typeof basePermission.bash === "string") { basePermission.bash = { "*": basePermission.bash, diff --git a/packages/opencode/src/bun/index.ts b/packages/opencode/src/bun/index.ts index 2a8b48ef..5f184727 100644 --- a/packages/opencode/src/bun/index.ts +++ b/packages/opencode/src/bun/index.ts @@ -8,10 +8,7 @@ import { readableStreamToText } from "bun" export namespace BunProc { const log = Log.create({ service: "bun" }) - export async function run( - cmd: string[], - options?: Bun.SpawnOptions.OptionsObject, - ) { + export async function run(cmd: string[], options?: Bun.SpawnOptions.OptionsObject) { log.info("running", { cmd: [which(), ...cmd], ...options, diff --git a/packages/opencode/src/bus/index.ts b/packages/opencode/src/bus/index.ts index c424eb87..f4dd3ed2 100644 --- a/packages/opencode/src/bus/index.ts +++ b/packages/opencode/src/bus/index.ts @@ -19,10 +19,7 @@ export namespace Bus { const registry = new Map() - export function event( - type: Type, - properties: Properties, - ) { + export function event(type: Type, properties: Properties) { const result = { type, properties, @@ -73,10 +70,7 @@ export namespace Bus { export function subscribe( def: Definition, - callback: (event: { - type: Definition["type"] - properties: z.infer - }) => void, + callback: (event: { type: Definition["type"]; properties: z.infer }) => void, ) { return raw(def.type, callback) } diff --git a/packages/opencode/src/cli/cmd/auth.ts b/packages/opencode/src/cli/cmd/auth.ts index b4c47f0a..ae24fbef 100644 --- a/packages/opencode/src/cli/cmd/auth.ts +++ b/packages/opencode/src/cli/cmd/auth.ts @@ -14,11 +14,7 @@ export const AuthCommand = cmd({ command: "auth", describe: "manage credentials", builder: (yargs) => - yargs - .command(AuthLoginCommand) - .command(AuthLogoutCommand) - .command(AuthListCommand) - .demandCommand(), + yargs.command(AuthLoginCommand).command(AuthLogoutCommand).command(AuthListCommand).demandCommand(), async handler() {}, }) @@ -64,9 +60,7 @@ export const AuthListCommand = cmd({ prompts.log.info(`${provider} ${UI.Style.TEXT_DIM}${envVar}`) } - prompts.outro( - `${activeEnvVars.length} environment variable` + (activeEnvVars.length === 1 ? "" : "s"), - ) + prompts.outro(`${activeEnvVars.length} environment variable` + (activeEnvVars.length === 1 ? "" : "s")) } }, }) @@ -86,9 +80,7 @@ export const AuthLoginCommand = cmd({ UI.empty() prompts.intro("Add credential") if (args.url) { - const wellknown = await fetch(`${args.url}/.well-known/opencode`).then( - (x) => x.json() as any, - ) + const wellknown = await fetch(`${args.url}/.well-known/opencode`).then((x) => x.json() as any) prompts.log.info(`Running \`${wellknown.auth.command.join(" ")}\``) const proc = Bun.spawn({ cmd: wellknown.auth.command, @@ -290,8 +282,7 @@ export const AuthLoginCommand = cmd({ if (provider === "other") { provider = await prompts.text({ message: "Enter provider id", - validate: (x) => - x && x.match(/^[0-9a-z-]+$/) ? undefined : "a-z, 0-9 and hyphens only", + validate: (x) => (x && x.match(/^[0-9a-z-]+$/) ? undefined : "a-z, 0-9 and hyphens only"), }) if (prompts.isCancel(provider)) throw new UI.CancelledError() provider = provider.replace(/^@ai-sdk\//, "") diff --git a/packages/opencode/src/cli/cmd/debug/lsp.ts b/packages/opencode/src/cli/cmd/debug/lsp.ts index 8492395d..2f597719 100644 --- a/packages/opencode/src/cli/cmd/debug/lsp.ts +++ b/packages/opencode/src/cli/cmd/debug/lsp.ts @@ -7,11 +7,7 @@ import { EOL } from "os" export const LSPCommand = cmd({ command: "lsp", builder: (yargs) => - yargs - .command(DiagnosticsCommand) - .command(SymbolsCommand) - .command(DocumentSymbolsCommand) - .demandCommand(), + yargs.command(DiagnosticsCommand).command(SymbolsCommand).command(DocumentSymbolsCommand).demandCommand(), async handler() {}, }) diff --git a/packages/opencode/src/cli/cmd/debug/ripgrep.ts b/packages/opencode/src/cli/cmd/debug/ripgrep.ts index 7c1d0d96..4c18bce9 100644 --- a/packages/opencode/src/cli/cmd/debug/ripgrep.ts +++ b/packages/opencode/src/cli/cmd/debug/ripgrep.ts @@ -6,8 +6,7 @@ import { cmd } from "../cmd" export const RipgrepCommand = cmd({ command: "rg", - builder: (yargs) => - yargs.command(TreeCommand).command(FilesCommand).command(SearchCommand).demandCommand(), + builder: (yargs) => yargs.command(TreeCommand).command(FilesCommand).command(SearchCommand).demandCommand(), async handler() {}, }) @@ -19,9 +18,7 @@ const TreeCommand = cmd({ }), async handler(args) { await bootstrap(process.cwd(), async () => { - process.stdout.write( - (await Ripgrep.tree({ cwd: Instance.directory, limit: args.limit })) + EOL, - ) + process.stdout.write((await Ripgrep.tree({ cwd: Instance.directory, limit: args.limit })) + EOL) }) }, }) diff --git a/packages/opencode/src/cli/cmd/debug/snapshot.ts b/packages/opencode/src/cli/cmd/debug/snapshot.ts index b114122b..1849fe27 100644 --- a/packages/opencode/src/cli/cmd/debug/snapshot.ts +++ b/packages/opencode/src/cli/cmd/debug/snapshot.ts @@ -4,8 +4,7 @@ import { cmd } from "../cmd" export const SnapshotCommand = cmd({ command: "snapshot", - builder: (yargs) => - yargs.command(TrackCommand).command(PatchCommand).command(DiffCommand).demandCommand(), + builder: (yargs) => yargs.command(TrackCommand).command(PatchCommand).command(DiffCommand).demandCommand(), async handler() {}, }) diff --git a/packages/opencode/src/cli/cmd/github.ts b/packages/opencode/src/cli/cmd/github.ts index 6fbeee2e..cd3ceb94 100644 --- a/packages/opencode/src/cli/cmd/github.ts +++ b/packages/opencode/src/cli/cmd/github.ts @@ -189,9 +189,7 @@ export const GithubInstallCommand = cmd({ async function getAppInfo() { const project = Instance.project if (project.vcs !== "git") { - prompts.log.error( - `Could not find git repository. Please run this command from a git repository.`, - ) + prompts.log.error(`Could not find git repository. Please run this command from a git repository.`) throw new UI.CancelledError() } @@ -204,13 +202,9 @@ export const GithubInstallCommand = cmd({ // ie. git@github.com:sst/opencode // ie. ssh://git@github.com/sst/opencode.git // ie. ssh://git@github.com/sst/opencode - const parsed = info.match( - /^(?:(?:https?|ssh):\/\/)?(?:git@)?github\.com[:/]([^/]+)\/([^/.]+?)(?:\.git)?$/, - ) + const parsed = info.match(/^(?:(?:https?|ssh):\/\/)?(?:git@)?github\.com[:/]([^/]+)\/([^/.]+?)(?:\.git)?$/) if (!parsed) { - prompts.log.error( - `Could not find git repository. Please run this command from a git repository.`, - ) + prompts.log.error(`Could not find git repository. Please run this command from a git repository.`) throw new UI.CancelledError() } const [, owner, repo] = parsed @@ -451,9 +445,7 @@ export const GithubRunCommand = cmd({ const summary = await summarize(response) await pushToLocalBranch(summary) } - const hasShared = prData.comments.nodes.some((c) => - c.body.includes(`${shareBaseUrl}/s/${shareId}`), - ) + const hasShared = prData.comments.nodes.some((c) => c.body.includes(`${shareBaseUrl}/s/${shareId}`)) await updateComment(`${response}${footer({ image: !hasShared })}`) } // Fork PR @@ -465,9 +457,7 @@ export const GithubRunCommand = cmd({ const summary = await summarize(response) await pushToForkBranch(summary, prData) } - const hasShared = prData.comments.nodes.some((c) => - c.body.includes(`${shareBaseUrl}/s/${shareId}`), - ) + const hasShared = prData.comments.nodes.some((c) => c.body.includes(`${shareBaseUrl}/s/${shareId}`)) await updateComment(`${response}${footer({ image: !hasShared })}`) } } @@ -557,12 +547,8 @@ export const GithubRunCommand = cmd({ // ie. Image // ie. [api.json](https://github.com/user-attachments/files/21433810/api.json) // ie. ![Image](https://github.com/user-attachments/assets/xxxx) - const mdMatches = prompt.matchAll( - /!?\[.*?\]\((https:\/\/github\.com\/user-attachments\/[^)]+)\)/gi, - ) - const tagMatches = prompt.matchAll( - //gi, - ) + const mdMatches = prompt.matchAll(/!?\[.*?\]\((https:\/\/github\.com\/user-attachments\/[^)]+)\)/gi) + const tagMatches = prompt.matchAll(//gi) const matches = [...mdMatches, ...tagMatches].sort((a, b) => a.index - b.index) console.log("Images", JSON.stringify(matches, null, 2)) @@ -587,10 +573,7 @@ export const GithubRunCommand = cmd({ // Replace img tag with file path, ie. @image.png const replacement = `@${filename}` - prompt = - prompt.slice(0, start + offset) + - replacement + - prompt.slice(start + offset + tag.length) + prompt = prompt.slice(0, start + offset) + replacement + prompt.slice(start + offset + tag.length) offset += replacement.length - tag.length const contentType = res.headers.get("content-type") @@ -873,8 +856,7 @@ Co-authored-by: ${actor} <${actor}@users.noreply.github.com>"` throw new Error(`Failed to check permissions for user ${actor}: ${error}`) } - if (!["admin", "write"].includes(permission)) - throw new Error(`User ${actor} does not have write permissions`) + if (!["admin", "write"].includes(permission)) throw new Error(`User ${actor} does not have write permissions`) } async function createComment() { @@ -922,9 +904,7 @@ Co-authored-by: ${actor} <${actor}@users.noreply.github.com>"` return `${titleAlt}\n` })() - const shareUrl = shareId - ? `[opencode session](${shareBaseUrl}/s/${shareId})  |  ` - : "" + const shareUrl = shareId ? `[opencode session](${shareBaseUrl}/s/${shareId})  |  ` : "" return `\n\n${image}${shareUrl}[github run](${runUrl})` } @@ -1100,13 +1080,9 @@ query($owner: String!, $repo: String!, $number: Int!) { }) .map((c) => `- ${c.author.login} at ${c.createdAt}: ${c.body}`) - const files = (pr.files.nodes || []).map( - (f) => `- ${f.path} (${f.changeType}) +${f.additions}/-${f.deletions}`, - ) + const files = (pr.files.nodes || []).map((f) => `- ${f.path} (${f.changeType}) +${f.additions}/-${f.deletions}`) const reviewData = (pr.reviews.nodes || []).map((r) => { - const comments = (r.comments.nodes || []).map( - (c) => ` - ${c.path}:${c.line ?? "?"}: ${c.body}`, - ) + const comments = (r.comments.nodes || []).map((c) => ` - ${c.path}:${c.line ?? "?"}: ${c.body}`) return [ `- ${r.author.login} at ${r.submittedAt}:`, ` - Review body: ${r.body}`, @@ -1128,15 +1104,9 @@ query($owner: String!, $repo: String!, $number: Int!) { `Deletions: ${pr.deletions}`, `Total Commits: ${pr.commits.totalCount}`, `Changed Files: ${pr.files.nodes.length} files`, - ...(comments.length > 0 - ? ["", ...comments, ""] - : []), - ...(files.length > 0 - ? ["", ...files, ""] - : []), - ...(reviewData.length > 0 - ? ["", ...reviewData, ""] - : []), + ...(comments.length > 0 ? ["", ...comments, ""] : []), + ...(files.length > 0 ? ["", ...files, ""] : []), + ...(reviewData.length > 0 ? ["", ...reviewData, ""] : []), "", ].join("\n") } diff --git a/packages/opencode/src/cli/cmd/run.ts b/packages/opencode/src/cli/cmd/run.ts index 756776d0..b646f0b1 100644 --- a/packages/opencode/src/cli/cmd/run.ts +++ b/packages/opencode/src/cli/cmd/run.ts @@ -138,9 +138,7 @@ export const RunCommand = cmd({ const outputJsonEvent = (type: string, data: any) => { if (args.format === "json") { - process.stdout.write( - JSON.stringify({ type, timestamp: Date.now(), sessionID, ...data }) + EOL, - ) + process.stdout.write(JSON.stringify({ type, timestamp: Date.now(), sessionID, ...data }) + EOL) return true } return false @@ -160,9 +158,7 @@ export const RunCommand = cmd({ const [tool, color] = TOOL[part.tool] ?? [part.tool, UI.Style.TEXT_INFO_BOLD] const title = part.state.title || - (Object.keys(part.state.input).length > 0 - ? JSON.stringify(part.state.input) - : "Unknown") + (Object.keys(part.state.input).length > 0 ? JSON.stringify(part.state.input) : "Unknown") printEvent(color, tool, title) if (part.tool === "bash" && part.state.output?.trim()) { UI.println() @@ -215,10 +211,7 @@ export const RunCommand = cmd({ ], initialValue: "once", }).catch(() => "reject") - const response = (result.toString().includes("cancel") ? "reject" : result) as - | "once" - | "always" - | "reject" + const response = (result.toString().includes("cancel") ? "reject" : result) as "once" | "always" | "reject" await sdk.postSessionIdPermissionsPermissionId({ path: { id: sessionID, permissionID: permission.id }, body: { response }, @@ -280,10 +273,7 @@ export const RunCommand = cmd({ } const cfgResult = await sdk.config.get() - if ( - cfgResult.data && - (cfgResult.data.share === "auto" || Flag.OPENCODE_AUTO_SHARE || args.share) - ) { + if (cfgResult.data && (cfgResult.data.share === "auto" || Flag.OPENCODE_AUTO_SHARE || args.share)) { const shareResult = await sdk.session.share({ path: { id: sessionID } }).catch((error) => { if (error instanceof Error && error.message.includes("disabled")) { UI.println(UI.Style.TEXT_DANGER_BOLD + "! " + error.message) @@ -336,10 +326,7 @@ export const RunCommand = cmd({ } const cfgResult = await sdk.config.get() - if ( - cfgResult.data && - (cfgResult.data.share === "auto" || Flag.OPENCODE_AUTO_SHARE || args.share) - ) { + if (cfgResult.data && (cfgResult.data.share === "auto" || Flag.OPENCODE_AUTO_SHARE || args.share)) { const shareResult = await sdk.session.share({ path: { id: sessionID } }).catch((error) => { if (error instanceof Error && error.message.includes("disabled")) { UI.println(UI.Style.TEXT_DANGER_BOLD + "! " + error.message) diff --git a/packages/opencode/src/cli/cmd/stats.ts b/packages/opencode/src/cli/cmd/stats.ts index d7afbe33..58e8397d 100644 --- a/packages/opencode/src/cli/cmd/stats.ts +++ b/packages/opencode/src/cli/cmd/stats.ts @@ -68,9 +68,7 @@ async function getAllSessions(): Promise { if (!project) continue const sessionKeys = await Storage.list(["session", project.id]) - const projectSessions = await Promise.all( - sessionKeys.map((key) => Storage.read(key)), - ) + const projectSessions = await Promise.all(sessionKeys.map((key) => Storage.read(key))) for (const session of projectSessions) { if (session) { @@ -87,16 +85,12 @@ async function aggregateSessionStats(days?: number, projectFilter?: string): Pro const DAYS_IN_SECOND = 24 * 60 * 60 * 1000 const cutoffTime = days ? Date.now() - days * DAYS_IN_SECOND : 0 - let filteredSessions = days - ? sessions.filter((session) => session.time.updated >= cutoffTime) - : sessions + let filteredSessions = days ? sessions.filter((session) => session.time.updated >= cutoffTime) : sessions if (projectFilter !== undefined) { if (projectFilter === "") { const currentProject = await getCurrentProject() - filteredSessions = filteredSessions.filter( - (session) => session.projectID === currentProject.id, - ) + filteredSessions = filteredSessions.filter((session) => session.projectID === currentProject.id) } else { filteredSessions = filteredSessions.filter((session) => session.projectID === projectFilter) } @@ -125,9 +119,7 @@ async function aggregateSessionStats(days?: number, projectFilter?: string): Pro } if (filteredSessions.length > 1000) { - console.log( - `Large dataset detected (${filteredSessions.length} sessions). This may take a while...`, - ) + console.log(`Large dataset detected (${filteredSessions.length} sessions). This may take a while...`) } if (filteredSessions.length === 0) { @@ -262,8 +254,7 @@ export function displayStats(stats: SessionStats, toolLimit?: number) { const percentage = ((count / totalToolUsage) * 100).toFixed(1) const maxToolLength = 18 - const truncatedTool = - tool.length > maxToolLength ? tool.substring(0, maxToolLength - 2) + ".." : tool + const truncatedTool = tool.length > maxToolLength ? tool.substring(0, maxToolLength - 2) + ".." : tool const toolName = truncatedTool.padEnd(maxToolLength) const content = ` ${toolName} ${bar.padEnd(20)} ${count.toString().padStart(3)} (${percentage.padStart(4)}%)` diff --git a/packages/opencode/src/cli/cmd/tui/app.tsx b/packages/opencode/src/cli/cmd/tui/app.tsx index 9d30ed6d..fad23398 100644 --- a/packages/opencode/src/cli/cmd/tui/app.tsx +++ b/packages/opencode/src/cli/cmd/tui/app.tsx @@ -115,11 +115,7 @@ export function tui(input: { render( () => { return ( - ( - - )} - > + }> @@ -413,12 +409,7 @@ function App() { flexShrink={0} > - + open code{" "} @@ -434,11 +425,7 @@ function App() { tab {""} - + {local.agent.current().name.toUpperCase()} AGENT diff --git a/packages/opencode/src/cli/cmd/tui/component/dialog-model.tsx b/packages/opencode/src/cli/cmd/tui/component/dialog-model.tsx index 15499599..04f2f652 100644 --- a/packages/opencode/src/cli/cmd/tui/component/dialog-model.tsx +++ b/packages/opencode/src/cli/cmd/tui/component/dialog-model.tsx @@ -52,11 +52,7 @@ export function DialogModel() { description: provider.name, category: provider.name, })), - filter( - (x) => - Boolean(ref()?.filter) || - !local.model.recent().find((y) => isDeepEqual(y, x.value)), - ), + filter((x) => Boolean(ref()?.filter) || !local.model.recent().find((y) => isDeepEqual(y, x.value))), ), ), ), diff --git a/packages/opencode/src/cli/cmd/tui/component/dialog-session-list.tsx b/packages/opencode/src/cli/cmd/tui/component/dialog-session-list.tsx index c4f31845..5e0095a8 100644 --- a/packages/opencode/src/cli/cmd/tui/component/dialog-session-list.tsx +++ b/packages/opencode/src/cli/cmd/tui/component/dialog-session-list.tsx @@ -20,9 +20,7 @@ export function DialogSessionList() { const deleteKeybind = "ctrl+d" - const currentSessionID = createMemo(() => - route.data.type === "session" ? route.data.sessionID : undefined, - ) + const currentSessionID = createMemo(() => (route.data.type === "session" ? route.data.sessionID : undefined)) const options = createMemo(() => { const today = new Date().toDateString() diff --git a/packages/opencode/src/cli/cmd/tui/component/dialog-status.tsx b/packages/opencode/src/cli/cmd/tui/component/dialog-status.tsx index d1ef5ca5..e427e24e 100644 --- a/packages/opencode/src/cli/cmd/tui/component/dialog-status.tsx +++ b/packages/opencode/src/cli/cmd/tui/component/dialog-status.tsx @@ -77,10 +77,7 @@ export function DialogStatus() { )} - 0} - fallback={No Formatters} - > + 0} fallback={No Formatters}> {enabledFormatters().length} Formatters diff --git a/packages/opencode/src/cli/cmd/tui/component/logo.tsx b/packages/opencode/src/cli/cmd/tui/component/logo.tsx index 7cac51ec..59db5fe7 100644 --- a/packages/opencode/src/cli/cmd/tui/component/logo.tsx +++ b/packages/opencode/src/cli/cmd/tui/component/logo.tsx @@ -3,19 +3,9 @@ import { TextAttributes } from "@opentui/core" import { For } from "solid-js" import { useTheme } from "@tui/context/theme" -const LOGO_LEFT = [ - ` `, - `█▀▀█ █▀▀█ █▀▀█ █▀▀▄`, - `█░░█ █░░█ █▀▀▀ █░░█`, - `▀▀▀▀ █▀▀▀ ▀▀▀▀ ▀ ▀`, -] +const LOGO_LEFT = [` `, `█▀▀█ █▀▀█ █▀▀█ █▀▀▄`, `█░░█ █░░█ █▀▀▀ █░░█`, `▀▀▀▀ █▀▀▀ ▀▀▀▀ ▀ ▀`] -const LOGO_RIGHT = [ - ` ▄ `, - `█▀▀▀ █▀▀█ █▀▀█ █▀▀█`, - `█░░░ █░░█ █░░█ █▀▀▀`, - `▀▀▀▀ ▀▀▀▀ ▀▀▀▀ ▀▀▀▀`, -] +const LOGO_RIGHT = [` ▄ `, `█▀▀▀ █▀▀█ █▀▀█ █▀▀█`, `█░░░ █░░█ █░░█ █▀▀▀`, `▀▀▀▀ ▀▀▀▀ ▀▀▀▀ ▀▀▀▀`] export function Logo() { const { theme } = useTheme() diff --git a/packages/opencode/src/cli/cmd/tui/component/prompt/autocomplete.tsx b/packages/opencode/src/cli/cmd/tui/component/prompt/autocomplete.tsx index 88ca3242..68578e70 100644 --- a/packages/opencode/src/cli/cmd/tui/component/prompt/autocomplete.tsx +++ b/packages/opencode/src/cli/cmd/tui/component/prompt/autocomplete.tsx @@ -83,12 +83,7 @@ export function Autocomplete(props: { const extmarkStart = store.index const extmarkEnd = extmarkStart + Bun.stringWidth(virtualText) - const styleId = - part.type === "file" - ? props.fileStyleId - : part.type === "agent" - ? props.agentStyleId - : undefined + const styleId = part.type === "file" ? props.fileStyleId : part.type === "agent" ? props.agentStyleId : undefined const extmarkId = input.extmarks.create({ start: extmarkStart, @@ -185,9 +180,7 @@ export function Autocomplete(props: { ) }) - const session = createMemo(() => - props.sessionID ? sync.session.get(props.sessionID) : undefined, - ) + const session = createMemo(() => (props.sessionID ? sync.session.get(props.sessionID) : undefined)) const commands = createMemo((): AutocompleteOption[] => { const results: AutocompleteOption[] = [] const s = session() @@ -324,9 +317,7 @@ export function Autocomplete(props: { const options = createMemo(() => { const mixed: AutocompleteOption[] = ( - store.visible === "@" - ? [...agents(), ...(files.loading ? files.latest || [] : files())] - : [...commands()] + store.visible === "@" ? [...agents(), ...(files.loading ? files.latest || [] : files())] : [...commands()] ).filter((x) => x.disabled !== true) const currentFilter = filter() if (!currentFilter) return mixed.slice(0, 10) @@ -393,9 +384,7 @@ export function Autocomplete(props: { return } // Check if a space was typed after the trigger character - const currentText = props - .input() - .getTextRange(store.index + 1, props.input().cursorOffset + 1) + const currentText = props.input().getTextRange(store.index + 1, props.input().cursorOffset + 1) if (currentText.includes(" ")) { hide() } @@ -433,13 +422,8 @@ export function Autocomplete(props: { if (e.name === "@") { const cursorOffset = props.input().cursorOffset const charBeforeCursor = - cursorOffset === 0 - ? undefined - : props.input().getTextRange(cursorOffset - 1, cursorOffset) - const canTrigger = - charBeforeCursor === undefined || - charBeforeCursor === "" || - /\s/.test(charBeforeCursor) + cursorOffset === 0 ? undefined : props.input().getTextRange(cursorOffset - 1, cursorOffset) + const canTrigger = charBeforeCursor === undefined || charBeforeCursor === "" || /\s/.test(charBeforeCursor) if (canTrigger) show("@") } @@ -487,10 +471,7 @@ export function Autocomplete(props: { {option.display} - + {option.description} diff --git a/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx b/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx index b9e40659..eac00d9e 100644 --- a/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx +++ b/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx @@ -334,9 +334,7 @@ export function Prompt(props: PromptProps) { // Expand pasted text inline before submitting const allExtmarks = input.extmarks.getAllForTypeId(promptPartTypeId) - const sortedExtmarks = allExtmarks.sort( - (a: { start: number }, b: { start: number }) => b.start - a.start, - ) + const sortedExtmarks = allExtmarks.sort((a: { start: number }, b: { start: number }) => b.start - a.start) for (const extmark of sortedExtmarks) { const partIndex = store.extmarkToPartIndex.get(extmark.id) @@ -499,28 +497,15 @@ export function Prompt(props: PromptProps) { - + {store.mode === "normal" ? ">" : "!"} - +