Skip to content

Commit fde8b48

Browse files
Foundry UI polish: terminal empty state, history minimap redesign, styling tweaks (#242)
- Hide terminal pane body when no terminal tabs exist - Redesign history minimap from orange bar to single icon with popover dropdown - Simplify popover items to single-line user messages with ellipsis - Adjust min-used badge hover padding - Add right padding to message list for history icon clearance Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent f09b909 commit fde8b48

20 files changed

Lines changed: 4161 additions & 1015 deletions

foundry/packages/backend/src/actors/task/workbench.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -475,6 +475,7 @@ export async function getWorkbenchTask(c: any): Promise<any> {
475475
fileChanges: gitState.fileChanges,
476476
diffs: gitState.diffs,
477477
fileTree: gitState.fileTree,
478+
minutesUsed: 0,
478479
};
479480
}
480481

foundry/packages/client/src/mock/workbench-client.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ class MockWorkbenchStore implements TaskWorkbenchClient {
9999
fileChanges: [],
100100
diffs: {},
101101
fileTree: [],
102+
minutesUsed: 0,
102103
};
103104

104105
this.updateState((current) => ({

foundry/packages/client/src/workbench-model.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -434,6 +434,7 @@ export function buildInitialTasks(): Task[] {
434434
],
435435
},
436436
],
437+
minutesUsed: 42,
437438
},
438439
{
439440
id: "h2",
@@ -533,6 +534,7 @@ export function buildInitialTasks(): Task[] {
533534
],
534535
},
535536
],
537+
minutesUsed: 187,
536538
},
537539
{
538540
id: "h3",
@@ -606,6 +608,7 @@ export function buildInitialTasks(): Task[] {
606608
],
607609
},
608610
],
611+
minutesUsed: 23,
609612
},
610613
// ── rivet-dev/rivet ──
611614
{
@@ -740,6 +743,7 @@ export function buildInitialTasks(): Task[] {
740743
],
741744
},
742745
],
746+
minutesUsed: 5,
743747
},
744748
{
745749
id: "h5",
@@ -795,6 +799,7 @@ export function buildInitialTasks(): Task[] {
795799
],
796800
diffs: {},
797801
fileTree: [],
802+
minutesUsed: 312,
798803
},
799804
// ── rivet-dev/cloud ──
800805
{
@@ -903,6 +908,7 @@ export function buildInitialTasks(): Task[] {
903908
],
904909
},
905910
],
911+
minutesUsed: 0,
906912
},
907913
// ── rivet-dev/engine-ee ──
908914
{
@@ -1016,6 +1022,7 @@ export function buildInitialTasks(): Task[] {
10161022
],
10171023
},
10181024
],
1025+
minutesUsed: 78,
10191026
},
10201027
// ── rivet-dev/engine-ee (archived) ──
10211028
{
@@ -1057,6 +1064,7 @@ export function buildInitialTasks(): Task[] {
10571064
],
10581065
diffs: {},
10591066
fileTree: [],
1067+
minutesUsed: 15,
10601068
},
10611069
// ── rivet-dev/secure-exec ──
10621070
{
@@ -1109,6 +1117,7 @@ export function buildInitialTasks(): Task[] {
11091117
],
11101118
diffs: {},
11111119
fileTree: [],
1120+
minutesUsed: 3,
11121121
},
11131122
];
11141123
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
const e = {};
2+
export { e as default };

foundry/packages/desktop/frontend-dist/assets/ghostty-web-CC99DH20.js

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

foundry/packages/desktop/frontend-dist/assets/index-5GPxonOP.css

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

foundry/packages/desktop/frontend-dist/assets/index-D0-B2Qgl.js

Lines changed: 98 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 198 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
1+
import { _ as u } from "./index-D0-B2Qgl.js";
2+
var P = {};
3+
function S() {
4+
return typeof process?.versions?.bun == "string" ? !0 : (P?.npm_config_user_agent || "").includes("bun/");
5+
}
6+
var I = new Set(["EACCES", "EPERM", "ENOEXEC"]);
7+
function A(n) {
8+
if (!n || typeof n != "object") return !1;
9+
const e = n.code;
10+
return typeof e == "string" && I.has(e);
11+
}
12+
function R(n, e) {
13+
if (process.platform === "win32") return !0;
14+
try {
15+
return e.accessSync(n, e.constants.X_OK), !0;
16+
} catch {}
17+
try {
18+
return e.chmodSync(n, 493), !0;
19+
} catch (o) {
20+
if (A(o)) return !1;
21+
throw o;
22+
}
23+
}
24+
function T(n) {
25+
const { binPath: e, trustPackages: o, bunInstallBlocks: s, genericInstallCommands: r, binaryName: a } = n,
26+
t = [`${a ?? "sandbox-agent"} binary is not executable: ${e}`];
27+
if (S()) {
28+
t.push("Allow Bun to run postinstall scripts for native binaries and reinstall:");
29+
for (const c of s) {
30+
t.push(`${c.label}:`);
31+
for (const d of c.commands) t.push(` ${d}`);
32+
}
33+
return (
34+
t.push(`Or run: chmod +x "${e}"`),
35+
t.join(`
36+
`)
37+
);
38+
}
39+
if ((t.push("Postinstall scripts for native packages did not run, so the binary was left non-executable."), r && r.length > 0)) {
40+
t.push("Reinstall with scripts enabled:");
41+
for (const c of r) t.push(` ${c}`);
42+
} else t.push("Reinstall with scripts enabled for:"), t.push(` ${o}`);
43+
return (
44+
t.push(`Or run: chmod +x "${e}"`),
45+
t.join(`
46+
`)
47+
);
48+
}
49+
var x = {},
50+
$ = {
51+
"darwin-arm64": "@sandbox-agent/cli-darwin-arm64",
52+
"darwin-x64": "@sandbox-agent/cli-darwin-x64",
53+
"linux-x64": "@sandbox-agent/cli-linux-x64",
54+
"linux-arm64": "@sandbox-agent/cli-linux-arm64",
55+
"win32-x64": "@sandbox-agent/cli-win32-x64",
56+
},
57+
b = "@sandbox-agent/cli-linux-x64 @sandbox-agent/cli-linux-arm64 @sandbox-agent/cli-darwin-arm64 @sandbox-agent/cli-darwin-x64 @sandbox-agent/cli-win32-x64";
58+
function k() {
59+
return typeof process < "u" && !!process.versions?.node;
60+
}
61+
async function V(n, e) {
62+
if (!k()) throw new Error("Autospawn requires a Node.js runtime.");
63+
const { spawn: o } = await u(async () => {
64+
const { spawn: p } = await import("./__vite-browser-external-BIHI7g3E.js");
65+
return { spawn: p };
66+
}, []),
67+
s = await u(() => import("./__vite-browser-external-BIHI7g3E.js"), []),
68+
r = await u(() => import("./__vite-browser-external-BIHI7g3E.js"), []),
69+
a = await u(() => import("./__vite-browser-external-BIHI7g3E.js"), []),
70+
i = await u(() => import("./__vite-browser-external-BIHI7g3E.js"), []),
71+
{ createRequire: t } = await u(async () => {
72+
const { createRequire: p } = await import("./__vite-browser-external-BIHI7g3E.js");
73+
return { createRequire: p };
74+
}, []),
75+
c = n.host ?? "127.0.0.1",
76+
d = n.port ?? (await C(i, c)),
77+
_ = c === "0.0.0.0" || c === "::" ? "127.0.0.1" : c,
78+
m = n.token ?? s.randomBytes(24).toString("hex"),
79+
E = n.timeoutMs ?? 15e3,
80+
w = n.log ?? "inherit",
81+
f = n.binaryPath ?? B(r, a) ?? O(t(import.meta.url), a, r) ?? N(r, a);
82+
if (!f) throw new Error("sandbox-agent binary not found. Install @sandbox-agent/cli or set SANDBOX_AGENT_BIN.");
83+
if (!R(f, r))
84+
throw new Error(
85+
T({
86+
binPath: f,
87+
trustPackages: b,
88+
bunInstallBlocks: [
89+
{ label: "Project install", commands: [`bun pm trust ${b}`, "bun add sandbox-agent"] },
90+
{ label: "Global install", commands: [`bun pm -g trust ${b}`, "bun add -g sandbox-agent"] },
91+
],
92+
}),
93+
);
94+
const v = w === "inherit" ? "inherit" : w === "silent" ? "ignore" : "pipe",
95+
y = ["server", "--host", c, "--port", String(d), "--token", m],
96+
l = o(f, y, { stdio: v, env: { ...x, ...(n.env ?? {}) } }),
97+
h = D(l),
98+
g = `http://${_}:${d}`;
99+
return (
100+
await G(g, e ?? globalThis.fetch, E, l, m),
101+
{
102+
baseUrl: g,
103+
token: m,
104+
child: l,
105+
dispose: async () => {
106+
if (l.exitCode !== null) {
107+
h.dispose();
108+
return;
109+
}
110+
l.kill("SIGTERM"), (await M(l, 5e3)) || l.kill("SIGKILL"), h.dispose();
111+
},
112+
}
113+
);
114+
}
115+
function B(n, e) {
116+
const o = x.SANDBOX_AGENT_BIN;
117+
if (!o) return null;
118+
const s = e.resolve(o);
119+
return n.existsSync(s) ? s : null;
120+
}
121+
function O(n, e, o) {
122+
const s = `${process.platform}-${process.arch}`,
123+
r = $[s];
124+
if (!r) return null;
125+
try {
126+
const a = n.resolve(`${r}/package.json`),
127+
i = process.platform === "win32" ? "sandbox-agent.exe" : "sandbox-agent",
128+
t = e.join(e.dirname(a), "bin", i);
129+
return o.existsSync(t) ? t : null;
130+
} catch {
131+
return null;
132+
}
133+
}
134+
function N(n, e) {
135+
const o = x.PATH ?? "",
136+
s = process.platform === "win32" ? ";" : ":",
137+
r = o.split(s).filter(Boolean),
138+
a = process.platform === "win32" ? "sandbox-agent.exe" : "sandbox-agent";
139+
for (const i of r) {
140+
const t = e.join(i, a);
141+
if (n.existsSync(t)) return t;
142+
}
143+
return null;
144+
}
145+
async function C(n, e) {
146+
return new Promise((o, s) => {
147+
const r = n.createServer();
148+
r.unref(),
149+
r.on("error", s),
150+
r.listen(0, e, () => {
151+
const a = r.address();
152+
r.close(() => o(a.port));
153+
});
154+
});
155+
}
156+
async function G(n, e, o, s, r) {
157+
if (!e) throw new Error("Fetch API is not available; provide a fetch implementation.");
158+
const a = Date.now();
159+
let i;
160+
for (; Date.now() - a < o; ) {
161+
if (s.exitCode !== null) throw new Error("sandbox-agent exited before becoming healthy.");
162+
try {
163+
const t = await e(`${n}/v1/health`, { headers: { Authorization: `Bearer ${r}` } });
164+
if (t.ok) return;
165+
i = `status ${t.status}`;
166+
} catch (t) {
167+
i = t instanceof Error ? t.message : String(t);
168+
}
169+
await new Promise((t) => setTimeout(t, 200));
170+
}
171+
throw new Error(`Timed out waiting for sandbox-agent health (${i ?? "unknown error"}).`);
172+
}
173+
async function M(n, e) {
174+
return n.exitCode !== null
175+
? !0
176+
: new Promise((o) => {
177+
const s = setTimeout(() => o(!1), e);
178+
n.once("exit", () => {
179+
clearTimeout(s), o(!0);
180+
});
181+
});
182+
}
183+
function D(n) {
184+
const e = () => {
185+
n.exitCode === null && n.kill("SIGTERM");
186+
};
187+
return (
188+
process.once("exit", e),
189+
process.once("SIGINT", e),
190+
process.once("SIGTERM", e),
191+
{
192+
dispose: () => {
193+
process.off("exit", e), process.off("SIGINT", e), process.off("SIGTERM", e);
194+
},
195+
}
196+
);
197+
}
198+
export { k as isNodeRuntime, V as spawnSandboxAgent };
Lines changed: 5 additions & 0 deletions
Loading
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<!doctype html>
2+
<html lang="en">
3+
<head>
4+
<!--
5+
<script type="module">
6+
if (import.meta.env.DEV) {
7+
import("react-grab");
8+
import("@react-grab/mcp/client");
9+
}
10+
</script>
11+
-->
12+
<script>if(window.__TAURI_INTERNALS__)document.documentElement.dataset.tauri="1"</script>
13+
<meta charset="UTF-8" />
14+
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
15+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
16+
<title>Foundry</title>
17+
<script type="module" crossorigin src="/assets/index-D0-B2Qgl.js"></script>
18+
<link rel="stylesheet" crossorigin href="/assets/index-5GPxonOP.css">
19+
</head>
20+
<body>
21+
<div id="root"></div>
22+
</body>
23+
</html>

0 commit comments

Comments
 (0)