summaryrefslogtreecommitdiffhomepage
path: root/packages
diff options
context:
space:
mode:
authorAdam <[email protected]>2026-02-10 05:52:34 -0600
committerAdam <[email protected]>2026-02-10 05:52:34 -0600
commit4a73d51acd6cc2610fa962a424a6d7049520f560 (patch)
tree35e5513d53bbf700c01ce0082eef5cc4c516d431 /packages
parent63cd763418a562245b22bb3c2906c9ec6063786a (diff)
downloadopencode-4a73d51acd6cc2610fa962a424a6d7049520f560.tar.gz
opencode-4a73d51acd6cc2610fa962a424a6d7049520f560.zip
fix(app): workspace reset issues
Diffstat (limited to 'packages')
-rw-r--r--packages/opencode/src/worktree/index.ts40
-rw-r--r--packages/ui/src/components/toast.css10
2 files changed, 48 insertions, 2 deletions
diff --git a/packages/opencode/src/worktree/index.ts b/packages/opencode/src/worktree/index.ts
index 2e095136e..88c778cbb 100644
--- a/packages/opencode/src/worktree/index.ts
+++ b/packages/opencode/src/worktree/index.ts
@@ -219,6 +219,44 @@ export namespace Worktree {
return [outputText(result.stderr), outputText(result.stdout)].filter(Boolean).join("\n")
}
+ function failed(result: { stdout?: Uint8Array; stderr?: Uint8Array }) {
+ return [outputText(result.stderr), outputText(result.stdout)].filter(Boolean).flatMap((chunk) =>
+ chunk
+ .split("\n")
+ .map((line) => line.trim())
+ .flatMap((line) => {
+ const match = line.match(/^warning:\s+failed to remove\s+(.+):\s+/i)
+ if (!match) return []
+ const value = match[1]?.trim().replace(/^['"]|['"]$/g, "")
+ if (!value) return []
+ return [value]
+ }),
+ )
+ }
+
+ async function prune(root: string, entries: string[]) {
+ const base = await canonical(root)
+ await Promise.all(
+ entries.map(async (entry) => {
+ const target = await canonical(path.resolve(root, entry))
+ if (target === base) return
+ if (!target.startsWith(`${base}${path.sep}`)) return
+ await fs.rm(target, { recursive: true, force: true }).catch(() => undefined)
+ }),
+ )
+ }
+
+ async function sweep(root: string) {
+ const first = await $`git clean -ffdx`.quiet().nothrow().cwd(root)
+ if (first.exitCode === 0) return first
+
+ const entries = failed(first)
+ if (!entries.length) return first
+
+ await prune(root, entries)
+ return $`git clean -ffdx`.quiet().nothrow().cwd(root)
+ }
+
async function canonical(input: string) {
const abs = path.resolve(input)
const real = await fs.realpath(abs).catch(() => abs)
@@ -536,7 +574,7 @@ export namespace Worktree {
throw new ResetFailedError({ message: errorText(resetToTarget) || "Failed to reset worktree to target" })
}
- const clean = await $`git clean -fdx`.quiet().nothrow().cwd(worktreePath)
+ const clean = await sweep(worktreePath)
if (clean.exitCode !== 0) {
throw new ResetFailedError({ message: errorText(clean) || "Failed to clean worktree" })
}
diff --git a/packages/ui/src/components/toast.css b/packages/ui/src/components/toast.css
index ed7ba4a20..de547f9c7 100644
--- a/packages/ui/src/components/toast.css
+++ b/packages/ui/src/components/toast.css
@@ -7,7 +7,9 @@
flex-direction: column;
gap: 8px;
max-width: min(400px, calc(100vw - 64px));
+ max-height: calc(100dvh - 96px);
width: 100%;
+ overflow: hidden;
pointer-events: none;
[data-slot="toast-list"] {
@@ -17,6 +19,8 @@
list-style: none;
margin: 0;
padding: 0;
+ max-height: 100%;
+ overflow-y: auto;
}
}
@@ -26,6 +30,8 @@
align-items: flex-start;
gap: 20px;
padding: 16px 20px;
+ max-height: min(420px, calc(100dvh - 96px));
+ overflow: hidden;
pointer-events: auto;
transition: all 150ms ease-out;
@@ -91,8 +97,10 @@
display: flex;
flex-direction: column;
gap: 2px;
+ min-height: 0;
min-width: 0;
- overflow: hidden;
+ overflow-x: hidden;
+ overflow-y: auto;
}
[data-slot="toast-title"] {