Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions foundry/packages/backend/src/actors/workspace/app-shell.ts
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,7 @@ async function buildAppSnapshot(c: any, sessionId: string): Promise<FoundryAppSn
name: session.currentUserName ?? session.currentUserGithubLogin ?? "GitHub user",
email: session.currentUserEmail ?? "",
githubLogin: session.currentUserGithubLogin ?? "",
avatarUrl: session.currentUserGithubLogin ? `https://github.com/${session.currentUserGithubLogin}.png` : null,
roleLabel: session.currentUserRoleLabel ?? "GitHub user",
eligibleOrganizationIds: organizations.map((organization) => organization.id),
}
Expand Down
92 changes: 83 additions & 9 deletions foundry/packages/client/src/mock-app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export interface MockFoundryUser {
name: string;
email: string;
githubLogin: string;
avatarUrl: string | null;
roleLabel: string;
eligibleOrganizationIds: string[];
}
Expand All @@ -22,6 +23,8 @@ export interface MockFoundryOrganizationMember {
email: string;
role: "owner" | "admin" | "member";
state: "active" | "invited";
avatarUrl: string | null;
githubLogin: string | null;
}

export interface MockFoundryInvoice {
Expand Down Expand Up @@ -162,6 +165,7 @@ function buildDefaultSnapshot(): MockFoundryAppSnapshot {
name: "Nathan",
email: "nathan@acme.dev",
githubLogin: "nathan",
avatarUrl: "https://github.com/NathanFlurry.png",
roleLabel: "Founder",
eligibleOrganizationIds: ["personal-nathan", "acme", "rivet"],
},
Expand All @@ -170,6 +174,7 @@ function buildDefaultSnapshot(): MockFoundryAppSnapshot {
name: "Maya",
email: "maya@acme.dev",
githubLogin: "maya",
avatarUrl: "https://github.com/octocat.png",
roleLabel: "Staff Engineer",
eligibleOrganizationIds: ["acme"],
},
Expand All @@ -178,6 +183,7 @@ function buildDefaultSnapshot(): MockFoundryAppSnapshot {
name: "Jamie",
email: "jamie@rivet.dev",
githubLogin: "jamie",
avatarUrl: "https://github.com/defunkt.png",
roleLabel: "Platform Lead",
eligibleOrganizationIds: ["personal-jamie", "rivet"],
},
Expand Down Expand Up @@ -213,7 +219,17 @@ function buildDefaultSnapshot(): MockFoundryAppSnapshot {
paymentMethodLabel: "No card required",
invoices: [],
},
members: [{ id: "member-nathan", name: "Nathan", email: "nathan@acme.dev", role: "owner", state: "active" }],
members: [
{
id: "member-nathan",
name: "Nathan",
email: "nathan@acme.dev",
role: "owner",
state: "active",
avatarUrl: "https://github.com/NathanFlurry.png",
githubLogin: "NathanFlurry",
},
],
seatAssignments: ["nathan@acme.dev"],
repoCatalog: ["nathan/personal-site"],
},
Expand Down Expand Up @@ -251,10 +267,34 @@ function buildDefaultSnapshot(): MockFoundryAppSnapshot {
],
},
members: [
{ id: "member-acme-nathan", name: "Nathan", email: "nathan@acme.dev", role: "owner", state: "active" },
{ id: "member-acme-maya", name: "Maya", email: "maya@acme.dev", role: "admin", state: "active" },
{ id: "member-acme-priya", name: "Priya", email: "priya@acme.dev", role: "member", state: "active" },
{ id: "member-acme-devon", name: "Devon", email: "devon@acme.dev", role: "member", state: "invited" },
{
id: "member-acme-nathan",
name: "Nathan",
email: "nathan@acme.dev",
role: "owner",
state: "active",
avatarUrl: "https://github.com/NathanFlurry.png",
githubLogin: "NathanFlurry",
},
{
id: "member-acme-maya",
name: "Maya",
email: "maya@acme.dev",
role: "admin",
state: "active",
avatarUrl: "https://github.com/octocat.png",
githubLogin: "octocat",
},
{
id: "member-acme-priya",
name: "Priya",
email: "priya@acme.dev",
role: "member",
state: "active",
avatarUrl: "https://github.com/mona.png",
githubLogin: "mona",
},
{ id: "member-acme-devon", name: "Devon", email: "devon@acme.dev", role: "member", state: "invited", avatarUrl: null, githubLogin: null },
],
seatAssignments: ["nathan@acme.dev", "maya@acme.dev"],
repoCatalog: ["acme/backend", "acme/frontend", "acme/infra"],
Expand Down Expand Up @@ -290,9 +330,33 @@ function buildDefaultSnapshot(): MockFoundryAppSnapshot {
invoices: [{ id: "inv-rivet-001", label: "Team pilot", issuedAt: "2026-03-04", amountUsd: 0, status: "paid" }],
},
members: [
{ id: "member-rivet-jamie", name: "Jamie", email: "jamie@rivet.dev", role: "owner", state: "active" },
{ id: "member-rivet-nathan", name: "Nathan", email: "nathan@acme.dev", role: "member", state: "active" },
{ id: "member-rivet-lena", name: "Lena", email: "lena@rivet.dev", role: "admin", state: "active" },
{
id: "member-rivet-jamie",
name: "Jamie",
email: "jamie@rivet.dev",
role: "owner",
state: "active",
avatarUrl: "https://github.com/defunkt.png",
githubLogin: "defunkt",
},
{
id: "member-rivet-nathan",
name: "Nathan",
email: "nathan@acme.dev",
role: "member",
state: "active",
avatarUrl: "https://github.com/NathanFlurry.png",
githubLogin: "NathanFlurry",
},
{
id: "member-rivet-lena",
name: "Lena",
email: "lena@rivet.dev",
role: "admin",
state: "active",
avatarUrl: "https://github.com/mojombo.png",
githubLogin: "mojombo",
},
],
seatAssignments: ["jamie@rivet.dev"],
repoCatalog: ["rivet/dashboard", "rivet/agents", "rivet/billing", "rivet/infrastructure"],
Expand Down Expand Up @@ -327,7 +391,17 @@ function buildDefaultSnapshot(): MockFoundryAppSnapshot {
paymentMethodLabel: "No card required",
invoices: [],
},
members: [{ id: "member-jamie", name: "Jamie", email: "jamie@rivet.dev", role: "owner", state: "active" }],
members: [
{
id: "member-jamie",
name: "Jamie",
email: "jamie@rivet.dev",
role: "owner",
state: "active",
avatarUrl: "https://github.com/defunkt.png",
githubLogin: "defunkt",
},
],
seatAssignments: ["jamie@rivet.dev"],
repoCatalog: ["jamie/demo-app"],
},
Expand Down
1 change: 1 addition & 0 deletions foundry/packages/client/src/mock/workbench-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ class MockWorkbenchStore implements TaskWorkbenchClient {
diffs: {},
fileTree: [],
minutesUsed: 0,
presence: [],
};

this.updateState((current) => ({
Expand Down
16 changes: 16 additions & 0 deletions foundry/packages/client/src/workbench-model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -435,6 +435,10 @@ export function buildInitialTasks(): Task[] {
},
],
minutesUsed: 42,
presence: [
{ memberId: "member-acme-nathan", name: "Nathan", avatarUrl: "https://github.com/NathanFlurry.png", lastSeenAtMs: minutesAgo(1) },
{ memberId: "member-acme-maya", name: "Maya", avatarUrl: "https://github.com/octocat.png", lastSeenAtMs: minutesAgo(0), typing: true },
],
},
{
id: "h2",
Expand Down Expand Up @@ -535,6 +539,7 @@ export function buildInitialTasks(): Task[] {
},
],
minutesUsed: 187,
presence: [{ memberId: "member-acme-priya", name: "Priya", avatarUrl: "https://github.com/mona.png", lastSeenAtMs: minutesAgo(0) }],
},
{
id: "h3",
Expand Down Expand Up @@ -609,6 +614,7 @@ export function buildInitialTasks(): Task[] {
},
],
minutesUsed: 23,
presence: [],
},
// ── rivet-dev/rivet ──
{
Expand Down Expand Up @@ -744,6 +750,11 @@ export function buildInitialTasks(): Task[] {
},
],
minutesUsed: 5,
presence: [
{ memberId: "member-acme-nathan", name: "Nathan", avatarUrl: "https://github.com/NathanFlurry.png", lastSeenAtMs: minutesAgo(0) },
{ memberId: "member-acme-maya", name: "Maya", avatarUrl: "https://github.com/octocat.png", lastSeenAtMs: minutesAgo(2) },
{ memberId: "member-acme-priya", name: "Priya", avatarUrl: "https://github.com/mona.png", lastSeenAtMs: minutesAgo(5) },
],
},
{
id: "h5",
Expand Down Expand Up @@ -800,6 +811,7 @@ export function buildInitialTasks(): Task[] {
diffs: {},
fileTree: [],
minutesUsed: 312,
presence: [{ memberId: "member-acme-maya", name: "Maya", avatarUrl: "https://github.com/octocat.png", lastSeenAtMs: minutesAgo(45) }],
},
// ── rivet-dev/cloud ──
{
Expand Down Expand Up @@ -909,6 +921,7 @@ export function buildInitialTasks(): Task[] {
},
],
minutesUsed: 0,
presence: [],
},
// ── rivet-dev/engine-ee ──
{
Expand Down Expand Up @@ -1023,6 +1036,7 @@ export function buildInitialTasks(): Task[] {
},
],
minutesUsed: 78,
presence: [],
},
// ── rivet-dev/engine-ee (archived) ──
{
Expand Down Expand Up @@ -1065,6 +1079,7 @@ export function buildInitialTasks(): Task[] {
diffs: {},
fileTree: [],
minutesUsed: 15,
presence: [],
},
// ── rivet-dev/secure-exec ──
{
Expand Down Expand Up @@ -1118,6 +1133,7 @@ export function buildInitialTasks(): Task[] {
diffs: {},
fileTree: [],
minutesUsed: 3,
presence: [],
},
];
}
Expand Down
6 changes: 6 additions & 0 deletions foundry/packages/desktop/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,16 @@
"type": "module",
"scripts": {
"dev": "tauri dev",
"dev:ios": "VITE_MOBILE=1 tauri ios dev",
"dev:android": "VITE_MOBILE=1 tauri android dev",
"build": "tauri build",
"build:ios": "tauri ios build",
"build:android": "tauri android build",
"build:sidecar": "tsx scripts/build-sidecar.ts",
"build:frontend": "tsx scripts/build-frontend.ts",
"build:frontend:mobile": "tsx scripts/build-frontend-mobile.ts",
"build:all": "pnpm build:sidecar && pnpm build:frontend && pnpm build",
"build:all:ios": "pnpm build:frontend:mobile && pnpm build:ios",
"tauri": "tauri"
},
"devDependencies": {
Expand Down
42 changes: 42 additions & 0 deletions foundry/packages/desktop/scripts/build-frontend-mobile.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { execSync } from "node:child_process";
import { cpSync, readFileSync, writeFileSync, rmSync, existsSync } from "node:fs";
import { resolve, dirname } from "node:path";
import { fileURLToPath } from "node:url";

const __dirname = dirname(fileURLToPath(import.meta.url));
const desktopRoot = resolve(__dirname, "..");
const repoRoot = resolve(desktopRoot, "../../..");
const frontendDist = resolve(desktopRoot, "../frontend/dist");
const destDir = resolve(desktopRoot, "frontend-dist");

function run(cmd: string, opts?: { cwd?: string; env?: NodeJS.ProcessEnv }) {
console.log(`> ${cmd}`);
execSync(cmd, {
stdio: "inherit",
cwd: opts?.cwd ?? repoRoot,
env: { ...process.env, ...opts?.env },
});
}

// Step 1: Build the frontend for mobile (no hardcoded backend endpoint)
console.log("\n=== Building frontend for mobile ===\n");
run("pnpm --filter @sandbox-agent/foundry-frontend build", {
env: {
VITE_MOBILE: "1",
},
});

// Step 2: Copy dist to frontend-dist/
console.log("\n=== Copying frontend build output ===\n");
if (existsSync(destDir)) {
rmSync(destDir, { recursive: true });
}
cpSync(frontendDist, destDir, { recursive: true });

// Step 3: Strip react-scan script from index.html (it loads unconditionally)
const indexPath = resolve(destDir, "index.html");
let html = readFileSync(indexPath, "utf-8");
html = html.replace(/<script\s+src="https:\/\/unpkg\.com\/react-scan\/dist\/auto\.global\.js"[^>]*><\/script>\s*/g, "");
writeFileSync(indexPath, html);

console.log("\n=== Mobile frontend build complete ===\n");
9 changes: 8 additions & 1 deletion foundry/packages/desktop/src-tauri/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,20 @@ name = "foundry"
version = "0.1.0"
edition = "2021"

[lib]
crate-type = ["staticlib", "cdylib", "lib"]

[build-dependencies]
tauri-build = { version = "2", features = [] }

[dependencies]
tauri = { version = "2", features = [] }
tauri-plugin-shell = "2"
serde = { version = "1", features = ["derive"] }
serde_json = "1"
reqwest = { version = "0.12", features = ["json"] }
tokio = { version = "1", features = ["time"] }

# Shell plugin is desktop-only (used for sidecar spawning).
# Exclude iOS and Android targets.
[target.'cfg(not(any(target_os = "ios", target_os = "android")))'.dependencies]
tauri-plugin-shell = "2"
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"identifier": "default",
"description": "Default capability for Foundry desktop",
"windows": ["main"],
"platforms": ["macOS", "windows", "linux"],
"permissions": [
"core:default",
"core:window:allow-start-dragging",
Expand Down
7 changes: 7 additions & 0 deletions foundry/packages/desktop/src-tauri/capabilities/mobile.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"identifier": "mobile",
"description": "Capability for Foundry mobile (iOS/Android)",
"windows": ["main"],
"platforms": ["iOS", "android"],
"permissions": ["core:default"]
}
3 changes: 3 additions & 0 deletions foundry/packages/desktop/src-tauri/gen/apple/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
xcuserdata/
build/
Externals/
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading