Skip to content

Commit 0e1eb95

Browse files
authored
Merge branch 'anomalyco:dev' into dev
2 parents 97b6f8e + 6e01786 commit 0e1eb95

21 files changed

Lines changed: 916 additions & 196 deletions

File tree

bun.lock

Lines changed: 14 additions & 14 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-i9TxYwWkJAR+kW6pbvhgQbRW9UYPtdrPQAGic4zPoa4=",
4-
"aarch64-linux": "sha256-RYc/OYlETXUwkWBRDas+/P4cBW6zde4FqxxnMARu5vs=",
5-
"aarch64-darwin": "sha256-jIhUOIRIQEa2WT62TVIedmRIhl/edhK8sbiAFvU3yCM=",
6-
"x86_64-darwin": "sha256-xLGzaX7OofFlZzVgpORJR5QXD2u+54hp+t3cCfUtO84="
3+
"x86_64-linux": "sha256-YcVW8AGN3TP34CoBoCw+Fx30RL1aveNvxr5eoeOgYeg=",
4+
"aarch64-linux": "sha256-G/J3YFfrpEwXSHa25kNyUhYpwPhzNIZf/4v+RCfuslk=",
5+
"aarch64-darwin": "sha256-dNPYrGWKoafk4rHqc34U34TtiJGk87yUv5tKnliQcWs=",
6+
"x86_64-darwin": "sha256-1LStvefCajGkbdXobMpk0IQyw9SQcQgGKE+U3Fc0Osw="
77
}
88
}

packages/opencode/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -122,8 +122,8 @@
122122
"@opentelemetry/exporter-trace-otlp-http": "0.214.0",
123123
"@opentelemetry/sdk-trace-base": "2.6.1",
124124
"@opentelemetry/sdk-trace-node": "2.6.1",
125-
"@opentui/core": "catalog:",
126-
"@opentui/solid": "catalog:",
125+
"@opentui/core": "0.1.101",
126+
"@opentui/solid": "0.1.101",
127127
"@parcel/watcher": "2.5.1",
128128
"@pierre/diffs": "catalog:",
129129
"@solid-primitives/event-bus": "1.1.2",

packages/opencode/script/publish.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,10 +65,10 @@ const image = "ghcr.io/anomalyco/opencode"
6565
const platforms = "linux/amd64,linux/arm64"
6666
const tags = [`${image}:${version}`, `${image}:${Script.channel}`]
6767
const tagFlags = tags.flatMap((t) => ["-t", t])
68-
await $`docker buildx build --platform ${platforms} ${tagFlags} --push .`
6968

7069
// registries
7170
if (!Script.preview) {
71+
await $`docker buildx build --platform ${platforms} ${tagFlags} --push .`
7272
// Calculate SHA values
7373
const arm64Sha = await $`sha256sum ./dist/opencode-linux-arm64.tar.gz | cut -d' ' -f1`.text().then((x) => x.trim())
7474
const x64Sha = await $`sha256sum ./dist/opencode-linux-x64.tar.gz | cut -d' ' -f1`.text().then((x) => x.trim())

packages/opencode/src/agent/prompt/compaction.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
You are a helpful AI assistant tasked with summarizing conversations.
22

3-
When asked to summarize, provide a detailed but concise summary of the conversation.
3+
When asked to summarize, provide a detailed but concise summary of the older conversation history.
4+
The most recent turns may be preserved verbatim outside your summary, so focus on information that would still be needed to continue the work with that recent context available.
45
Focus on information that would be helpful for continuing the conversation, including:
56
- What was done
67
- What is currently being worked on

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

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import { render, TimeToFirstDraw, useKeyboard, useRenderer, useTerminalDimensions } from "@opentui/solid"
22
import * as Clipboard from "@tui/util/clipboard"
33
import * as Selection from "@tui/util/selection"
4-
import * as Terminal from "@tui/util/terminal"
54
import { createCliRenderer, MouseButton, type CliRendererConfig } from "@opentui/core"
65
import { RouteProvider, useRoute } from "@tui/context/route"
76
import {
@@ -120,12 +119,6 @@ export function tui(input: {
120119
const unguard = win32InstallCtrlCGuard()
121120
win32DisableProcessedInput()
122121

123-
const mode = await Terminal.getTerminalBackgroundColor()
124-
125-
// Re-clear after getTerminalBackgroundColor() — setRawMode(false) restores
126-
// the original console mode which re-enables ENABLE_PROCESSED_INPUT.
127-
win32DisableProcessedInput()
128-
129122
const onExit = async () => {
130123
unguard?.()
131124
resolve()
@@ -136,6 +129,7 @@ export function tui(input: {
136129
}
137130

138131
const renderer = await createCliRenderer(rendererConfig(input.config))
132+
const mode = (await renderer.waitForThemeMode(1000)) ?? "dark"
139133

140134
await render(() => {
141135
return (

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

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
import { Global } from "@/global"
22
import { Filesystem } from "@/util"
3+
import { Flock } from "@opencode-ai/shared/util/flock"
4+
import { rename, rm } from "fs/promises"
35
import { createSignal, type Setter } from "solid-js"
4-
import { createStore } from "solid-js/store"
6+
import { createStore, unwrap } from "solid-js/store"
57
import { createSimpleContext } from "./helper"
68
import path from "path"
79

@@ -11,12 +13,29 @@ export const { use: useKV, provider: KVProvider } = createSimpleContext({
1113
const [ready, setReady] = createSignal(false)
1214
const [store, setStore] = createStore<Record<string, any>>()
1315
const filePath = path.join(Global.Path.state, "kv.json")
16+
const lock = `tui-kv:${filePath}`
17+
// Queue same-process writes so rapid updates persist in order.
18+
let write = Promise.resolve()
1419

15-
Filesystem.readJson<Record<string, any>>(filePath)
20+
// Write to a temp file first so kv.json is only replaced once the JSON is complete, avoiding partial writes if shutdown interrupts persistence.
21+
function writeSnapshot(snapshot: Record<string, any>) {
22+
const tempPath = `${filePath}.${process.pid}.${Date.now()}.tmp`
23+
return Filesystem.writeJson(tempPath, snapshot)
24+
.then(() => rename(tempPath, filePath))
25+
.catch(async (error) => {
26+
await rm(tempPath, { force: true }).catch(() => undefined)
27+
throw error
28+
})
29+
}
30+
31+
// Read under the same lock used for writes because kv.json is shared across processes.
32+
Flock.withLock(lock, () => Filesystem.readJson<Record<string, any>>(filePath))
1633
.then((x) => {
1734
setStore(x)
1835
})
19-
.catch(() => {})
36+
.catch((error) => {
37+
console.error("Failed to read KV state", { filePath, error })
38+
})
2039
.finally(() => {
2140
setReady(true)
2241
})
@@ -44,7 +63,12 @@ export const { use: useKV, provider: KVProvider } = createSimpleContext({
4463
},
4564
set(key: string, value: any) {
4665
setStore(key, value)
47-
void Filesystem.writeJson(filePath, store)
66+
const snapshot = structuredClone(unwrap(store))
67+
write = write
68+
.then(() => Flock.withLock(lock, () => writeSnapshot(snapshot)))
69+
.catch((error) => {
70+
console.error("Failed to write KV state", { filePath, error })
71+
})
4872
},
4973
}
5074
return result

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

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -314,8 +314,11 @@ export const { use: useTheme, provider: ThemeProvider } = createSimpleContext({
314314
setStore(
315315
produce((draft) => {
316316
const lock = pick(kv.get("theme_mode_lock"))
317-
const mode = pick(kv.get("theme_mode", props.mode))
318-
draft.mode = lock ?? mode ?? props.mode
317+
const mode = lock ?? props.mode
318+
if (!lock && pick(kv.get("theme_mode")) !== undefined) {
319+
kv.set("theme_mode", undefined)
320+
}
321+
draft.mode = mode
319322
draft.lock = lock
320323
const active = config.theme ?? kv.get("theme", "opencode")
321324
draft.active = typeof active === "string" ? active : "opencode"
@@ -373,7 +376,7 @@ export const { use: useTheme, provider: ThemeProvider } = createSimpleContext({
373376
}
374377

375378
function apply(mode: "dark" | "light") {
376-
kv.set("theme_mode", mode)
379+
if (store.lock !== undefined) kv.set("theme_mode", mode)
377380
if (store.mode === mode) return
378381
setStore("mode", mode)
379382
renderer.clearPaletteCache()
@@ -389,6 +392,7 @@ export const { use: useTheme, provider: ThemeProvider } = createSimpleContext({
389392
function free() {
390393
setStore("lock", undefined)
391394
kv.set("theme_mode_lock", undefined)
395+
kv.set("theme_mode", undefined)
392396
const mode = renderer.themeMode
393397
if (mode) apply(mode)
394398
}
@@ -397,7 +401,7 @@ export const { use: useTheme, provider: ThemeProvider } = createSimpleContext({
397401
if (store.lock) return
398402
apply(mode)
399403
}
400-
// renderer.on(CliRenderEvents.THEME_MODE, handle)
404+
renderer.on(CliRenderEvents.THEME_MODE, handle)
401405

402406
const refresh = () => {
403407
renderer.clearPaletteCache()

packages/opencode/src/cli/cmd/tui/util/terminal.ts

Lines changed: 0 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,6 @@ function parse(color: string): RGBA | null {
1717
return null
1818
}
1919

20-
function mode(bg: RGBA | null): "dark" | "light" {
21-
if (!bg) return "dark"
22-
const luminance = (0.299 * bg.r + 0.587 * bg.g + 0.114 * bg.b) / 255
23-
return luminance > 0.5 ? "light" : "dark"
24-
}
25-
2620
/**
2721
* Query terminal colors including background, foreground, and palette (0-15).
2822
* Uses OSC escape sequences to retrieve actual terminal color values.
@@ -100,36 +94,3 @@ export async function colors(): Promise<{
10094
}, 1000)
10195
})
10296
}
103-
104-
// Keep startup mode detection separate from `colors()`: the TUI boot path only
105-
// needs OSC 11 and should resolve on the first background response instead of
106-
// waiting on the full palette query used by system theme generation.
107-
export async function getTerminalBackgroundColor(): Promise<"dark" | "light"> {
108-
if (!process.stdin.isTTY) return "dark"
109-
110-
return new Promise((resolve) => {
111-
let timeout: NodeJS.Timeout
112-
113-
const cleanup = () => {
114-
process.stdin.setRawMode(false)
115-
process.stdin.removeListener("data", handler)
116-
clearTimeout(timeout)
117-
}
118-
119-
const handler = (data: Buffer) => {
120-
const match = data.toString().match(/\x1b]11;([^\x07\x1b]+)/)
121-
if (!match) return
122-
cleanup()
123-
resolve(mode(parse(match[1])))
124-
}
125-
126-
process.stdin.setRawMode(true)
127-
process.stdin.on("data", handler)
128-
process.stdout.write("\x1b]11;?\x07")
129-
130-
timeout = setTimeout(() => {
131-
cleanup()
132-
resolve("dark")
133-
}, 1000)
134-
})
135-
}

packages/opencode/src/config/config.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,13 @@ const InfoSchema = Schema.Struct({
204204
prune: Schema.optional(Schema.Boolean).annotate({
205205
description: "Enable pruning of old tool outputs (default: true)",
206206
}),
207+
tail_turns: Schema.optional(NonNegativeInt).annotate({
208+
description:
209+
"Number of recent user turns, including their following assistant/tool responses, to keep verbatim during compaction (default: 2)",
210+
}),
211+
tail_tokens: Schema.optional(NonNegativeInt).annotate({
212+
description: "Token budget for retained recent turn spans during compaction",
213+
}),
207214
reserved: Schema.optional(NonNegativeInt).annotate({
208215
description: "Token buffer for compaction. Leaves enough window to avoid overflow during compaction.",
209216
}),

0 commit comments

Comments
 (0)