Skip to content

Commit 532b64c

Browse files
authored
Merge branch 'dev' into feat/canceled-prompts-in-history
2 parents eec4c77 + fde201c commit 532b64c

10 files changed

Lines changed: 126 additions & 30 deletions

File tree

bun.lock

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

nix/hashes.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
{
22
"nodeModules": {
3-
"x86_64-linux": "sha256-E5neEbBiwQDhIQ5QVhijpHCCP9hcxm319S9WrDKngSw=",
4-
"aarch64-linux": "sha256-lnwaGSEirl9izskDooB/xQ0ZdirW0t3/S+OoOnfYaoQ=",
5-
"aarch64-darwin": "sha256-RDxxW9NMlGMIdIxTsbOYVqxunflkILv2dA7JqjnJgm4=",
6-
"x86_64-darwin": "sha256-1tvvktu2NRg6N6ASuKzqzcEmMrzH3/LFey0Vxr4E8zg="
3+
"x86_64-linux": "sha256-nMERinypUtIZGfLlAS5meYrvH5tTl2SkdG3GUguhOos=",
4+
"aarch64-linux": "sha256-aQ42YVcjXSxpweA3e0SfJ8mnMWEqGeIOKg1cIhn8szA=",
5+
"aarch64-darwin": "sha256-OGtUfhKWTRqi8bYcqkvfb1RZa3iS0DVy5bbRry47Og4=",
6+
"x86_64-darwin": "sha256-kdzsr67cGduvGl+4UVdngiKNCaVw88WeMgx1ckVbG30="
77
}
88
}

packages/app/src/pages/session.tsx

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,13 @@ import { useSync } from "@/context/sync"
4141
import { useTerminal } from "@/context/terminal"
4242
import { type FollowupDraft, sendFollowupDraft } from "@/components/prompt-input/submit"
4343
import { createSessionComposerState, SessionComposerRegion } from "@/pages/session/composer"
44-
import { createOpenReviewFile, createSessionTabs, createSizing, focusTerminalById } from "@/pages/session/helpers"
44+
import {
45+
createOpenReviewFile,
46+
createSessionTabs,
47+
createSizing,
48+
focusTerminalById,
49+
shouldFocusTerminalOnKeyDown,
50+
} from "@/pages/session/helpers"
4551
import { MessageTimeline } from "@/pages/session/message-timeline"
4652
import { type DiffStyle, SessionReviewTab, type SessionReviewTabProps } from "@/pages/session/review-tab"
4753
import { useSessionLayout } from "@/pages/session/session-layout"
@@ -850,7 +856,7 @@ export default function Page() {
850856
// Prefer the open terminal over the composer when it can take focus
851857
if (view().terminal.opened()) {
852858
const id = terminal.active()
853-
if (id && focusTerminalById(id)) return
859+
if (id && shouldFocusTerminalOnKeyDown(event) && focusTerminalById(id)) return
854860
}
855861

856862
// Only treat explicit scroll keys as potential "user scroll" gestures.

packages/app/src/pages/session/helpers.test.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
createSessionTabs,
88
focusTerminalById,
99
getTabReorderIndex,
10+
shouldFocusTerminalOnKeyDown,
1011
} from "./helpers"
1112

1213
describe("createOpenReviewFile", () => {
@@ -86,6 +87,26 @@ describe("focusTerminalById", () => {
8687
})
8788
})
8889

90+
describe("shouldFocusTerminalOnKeyDown", () => {
91+
test("skips pure modifier keys", () => {
92+
expect(shouldFocusTerminalOnKeyDown(new KeyboardEvent("keydown", { key: "Meta", metaKey: true }))).toBe(false)
93+
expect(shouldFocusTerminalOnKeyDown(new KeyboardEvent("keydown", { key: "Control", ctrlKey: true }))).toBe(false)
94+
expect(shouldFocusTerminalOnKeyDown(new KeyboardEvent("keydown", { key: "Alt", altKey: true }))).toBe(false)
95+
expect(shouldFocusTerminalOnKeyDown(new KeyboardEvent("keydown", { key: "Shift", shiftKey: true }))).toBe(false)
96+
})
97+
98+
test("skips shortcut key combos", () => {
99+
expect(shouldFocusTerminalOnKeyDown(new KeyboardEvent("keydown", { key: "c", metaKey: true }))).toBe(false)
100+
expect(shouldFocusTerminalOnKeyDown(new KeyboardEvent("keydown", { key: "c", ctrlKey: true }))).toBe(false)
101+
expect(shouldFocusTerminalOnKeyDown(new KeyboardEvent("keydown", { key: "ArrowLeft", altKey: true }))).toBe(false)
102+
})
103+
104+
test("keeps plain typing focused on terminal", () => {
105+
expect(shouldFocusTerminalOnKeyDown(new KeyboardEvent("keydown", { key: "a" }))).toBe(true)
106+
expect(shouldFocusTerminalOnKeyDown(new KeyboardEvent("keydown", { key: "A", shiftKey: true }))).toBe(true)
107+
})
108+
})
109+
89110
describe("getTabReorderIndex", () => {
90111
test("returns target index for valid drag reorder", () => {
91112
expect(getTabReorderIndex(["a", "b", "c"], "a", "c")).toBe(2)

packages/app/src/pages/session/helpers.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,13 @@ export const focusTerminalById = (id: string) => {
9393
return true
9494
}
9595

96+
const skip = new Set(["Alt", "Control", "Meta", "Shift"])
97+
98+
export const shouldFocusTerminalOnKeyDown = (event: Pick<KeyboardEvent, "key" | "ctrlKey" | "metaKey" | "altKey">) => {
99+
if (skip.has(event.key)) return false
100+
return !(event.ctrlKey || event.metaKey || event.altKey)
101+
}
102+
96103
export const createOpenReviewFile = (input: {
97104
showAllFiles: () => void
98105
tabForPath: (path: string) => string

packages/console/app/src/routes/zen/util/handler.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,13 @@ export async function handler(
340340
"error.message": error.message,
341341
"error.cause": error.cause?.toString(),
342342
})
343+
if (error.message.startsWith("Failed query")) {
344+
try {
345+
logger.metric({
346+
"error.cause2": JSON.stringify(error.cause),
347+
})
348+
} catch (e) {}
349+
}
343350

344351
// Note: both top level "type" and "error.type" fields are used by the @ai-sdk/anthropic client to render the error message.
345352
if (

packages/console/core/script/lookup-user.ts

Lines changed: 30 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,14 @@
11
import { Database, and, eq, sql } from "../src/drizzle/index.js"
22
import { AuthTable } from "../src/schema/auth.sql.js"
33
import { UserTable } from "../src/schema/user.sql.js"
4-
import { BillingTable, PaymentTable, SubscriptionTable, BlackPlans, UsageTable } from "../src/schema/billing.sql.js"
4+
import {
5+
BillingTable,
6+
PaymentTable,
7+
SubscriptionTable,
8+
BlackPlans,
9+
UsageTable,
10+
LiteTable,
11+
} from "../src/schema/billing.sql.js"
512
import { WorkspaceTable } from "../src/schema/workspace.sql.js"
613
import { KeyTable } from "../src/schema/key.sql.js"
714
import { BlackData } from "../src/black.js"
@@ -72,19 +79,22 @@ else {
7279
workspaceID: UserTable.workspaceID,
7380
workspaceName: WorkspaceTable.name,
7481
role: UserTable.role,
75-
subscribed: SubscriptionTable.timeCreated,
82+
black: SubscriptionTable.timeCreated,
83+
lite: LiteTable.timeCreated,
7684
})
7785
.from(UserTable)
7886
.rightJoin(WorkspaceTable, eq(WorkspaceTable.id, UserTable.workspaceID))
7987
.leftJoin(SubscriptionTable, eq(SubscriptionTable.userID, UserTable.id))
88+
.leftJoin(LiteTable, eq(LiteTable.userID, UserTable.id))
8089
.where(eq(UserTable.accountID, accountID))
8190
.then((rows) =>
8291
rows.map((row) => ({
8392
userID: row.userID,
8493
workspaceID: row.workspaceID,
8594
workspaceName: row.workspaceName,
8695
role: row.role,
87-
subscribed: formatDate(row.subscribed),
96+
black: formatDate(row.black),
97+
lite: formatDate(row.lite),
8898
})),
8999
),
90100
)
@@ -151,13 +161,14 @@ async function printWorkspace(workspaceID: string) {
151161
balance: BillingTable.balance,
152162
customerID: BillingTable.customerID,
153163
reload: BillingTable.reload,
154-
subscriptionID: BillingTable.subscriptionID,
155-
subscription: {
164+
blackSubscriptionID: BillingTable.subscriptionID,
165+
blackSubscription: {
156166
plan: BillingTable.subscriptionPlan,
157167
booked: BillingTable.timeSubscriptionBooked,
158168
enrichment: BillingTable.subscription,
159169
},
160-
timeSubscriptionSelected: BillingTable.timeSubscriptionSelected,
170+
timeBlackSubscriptionSelected: BillingTable.timeSubscriptionSelected,
171+
liteSubscriptionID: BillingTable.liteSubscriptionID,
161172
})
162173
.from(BillingTable)
163174
.where(eq(BillingTable.workspaceID, workspace.id))
@@ -167,16 +178,21 @@ async function printWorkspace(workspaceID: string) {
167178
balance: `$${(row.balance / 100000000).toFixed(2)}`,
168179
reload: row.reload ? "yes" : "no",
169180
customerID: row.customerID,
170-
subscriptionID: row.subscriptionID,
171-
subscription: row.subscriptionID
181+
liteSubscriptionID: row.liteSubscriptionID,
182+
blackSubscriptionID: row.blackSubscriptionID,
183+
blackSubscription: row.blackSubscriptionID
172184
? [
173-
`Black ${row.subscription.enrichment!.plan}`,
174-
row.subscription.enrichment!.seats > 1 ? `X ${row.subscription.enrichment!.seats} seats` : "",
175-
row.subscription.enrichment!.coupon ? `(coupon: ${row.subscription.enrichment!.coupon})` : "",
176-
`(ref: ${row.subscriptionID})`,
185+
`Black ${row.blackSubscription.enrichment!.plan}`,
186+
row.blackSubscription.enrichment!.seats > 1
187+
? `X ${row.blackSubscription.enrichment!.seats} seats`
188+
: "",
189+
row.blackSubscription.enrichment!.coupon
190+
? `(coupon: ${row.blackSubscription.enrichment!.coupon})`
191+
: "",
192+
`(ref: ${row.blackSubscriptionID})`,
177193
].join(" ")
178-
: row.subscription.booked
179-
? `Waitlist ${row.subscription.plan} plan${row.timeSubscriptionSelected ? " (selected)" : ""}`
194+
: row.blackSubscription.booked
195+
? `Waitlist ${row.blackSubscription.plan} plan${row.timeBlackSubscriptionSelected ? " (selected)" : ""}`
180196
: undefined,
181197
}))[0],
182198
),

packages/opencode/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@
121121
"drizzle-orm": "catalog:",
122122
"effect": "catalog:",
123123
"fuzzysort": "3.1.0",
124-
"gitlab-ai-provider": "5.2.2",
124+
"gitlab-ai-provider": "5.3.1",
125125
"glob": "13.0.5",
126126
"google-auth-library": "10.5.0",
127127
"gray-matter": "4.0.3",

packages/opencode/src/cli/cmd/tui/app.tsx

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@ function App() {
212212
const command = useCommandDialog()
213213
const sdk = useSDK()
214214
const toast = useToast()
215-
const { theme, mode, setMode } = useTheme()
215+
const { theme, mode, setMode, locked, lock, unlock } = useTheme()
216216
const sync = useSync()
217217
const exit = useExit()
218218
const promptRef = usePromptRef()
@@ -557,14 +557,24 @@ function App() {
557557
category: "System",
558558
},
559559
{
560-
title: "Toggle appearance",
560+
title: "Toggle Theme Mode",
561561
value: "theme.switch_mode",
562562
onSelect: (dialog) => {
563563
setMode(mode() === "dark" ? "light" : "dark")
564564
dialog.clear()
565565
},
566566
category: "System",
567567
},
568+
{
569+
title: locked() ? "Unlock Theme Mode" : "Lock Theme Mode",
570+
value: "theme.mode.lock",
571+
onSelect: (dialog) => {
572+
if (locked()) unlock()
573+
else lock()
574+
dialog.clear()
575+
},
576+
category: "System",
577+
},
568578
{
569579
title: "Help",
570580
value: "help.show",

packages/opencode/src/cli/cmd/tui/context/theme.tsx

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -283,9 +283,15 @@ export const { use: useTheme, provider: ThemeProvider } = createSimpleContext({
283283
const renderer = useRenderer()
284284
const config = useTuiConfig()
285285
const kv = useKV()
286+
const pick = (value: unknown) => {
287+
if (value === "dark" || value === "light") return value
288+
return
289+
}
290+
const lock = pick(kv.get("theme_mode_lock"))
286291
const [store, setStore] = createStore({
287292
themes: DEFAULT_THEMES,
288-
mode: kv.get("theme_mode", props.mode),
293+
mode: lock ?? pick(kv.get("theme_mode", props.mode)) ?? props.mode,
294+
lock,
289295
active: (config.theme ?? kv.get("theme", "opencode")) as string,
290296
ready: false,
291297
})
@@ -345,16 +351,30 @@ export const { use: useTheme, provider: ThemeProvider } = createSimpleContext({
345351
})
346352
}
347353

348-
function update(mode: "dark" | "light") {
354+
function apply(mode: "dark" | "light") {
355+
kv.set("theme_mode", mode)
349356
if (store.mode === mode) return
350357
setStore("mode", mode)
351-
kv.set("theme_mode", mode)
352358
renderer.clearPaletteCache()
353359
resolveSystemTheme(mode)
354360
}
355361

362+
function pin(mode: "dark" | "light" = store.mode) {
363+
setStore("lock", mode)
364+
kv.set("theme_mode_lock", mode)
365+
apply(mode)
366+
}
367+
368+
function free() {
369+
setStore("lock", undefined)
370+
kv.set("theme_mode_lock", undefined)
371+
const mode = renderer.themeMode
372+
if (mode) apply(mode)
373+
}
374+
356375
const handle = (mode: "dark" | "light") => {
357-
update(mode)
376+
if (store.lock) return
377+
apply(mode)
358378
}
359379
renderer.on(CliRenderEvents.THEME_MODE, handle)
360380
onCleanup(() => {
@@ -390,8 +410,17 @@ export const { use: useTheme, provider: ThemeProvider } = createSimpleContext({
390410
mode() {
391411
return store.mode
392412
},
413+
locked() {
414+
return store.lock !== undefined
415+
},
416+
lock() {
417+
pin(store.mode)
418+
},
419+
unlock() {
420+
free()
421+
},
393422
setMode(mode: "dark" | "light") {
394-
update(mode)
423+
pin(mode)
395424
},
396425
set(theme: string) {
397426
setStore("active", theme)

0 commit comments

Comments
 (0)