From f464fa96ad52ed34eda5f1c86b6cf96ad1725f07 Mon Sep 17 00:00:00 2001 From: Nicholas Kissel Date: Thu, 12 Mar 2026 22:35:54 -0700 Subject: [PATCH] Add Foundry mobile layout with Tauri iOS/Android support - Add responsive mobile layout with bottom pill tab bar, swipe navigation, and task list as home screen - Add platform detection (useIsMobile hook) with viewport breakpoint and VITE_MOBILE build flag - Mobile-optimize settings/billing/account pages (single-column layout with horizontal tabs) - Add iOS safe area inset handling with 47px minimum padding - Scaffold Tauri v2 mobile targets (iOS/Android) with platform-gated sidecar and capabilities - Add notification sound support and mobile build script Co-Authored-By: Claude Opus 4.6 --- .../backend/src/actors/workspace/app-shell.ts | 1 + foundry/packages/client/src/mock-app.ts | 92 +- .../client/src/mock/workbench-client.ts | 1 + .../packages/client/src/workbench-model.ts | 16 + foundry/packages/desktop/package.json | 6 + .../desktop/scripts/build-frontend-mobile.ts | 42 + foundry/packages/desktop/src-tauri/Cargo.toml | 9 +- .../src-tauri/capabilities/default.json | 1 + .../src-tauri/capabilities/mobile.json | 7 + .../desktop/src-tauri/gen/apple/.gitignore | 3 + .../AppIcon.appiconset/AppIcon-20x20@1x.png | Bin 0 -> 1036 bytes .../AppIcon.appiconset/AppIcon-20x20@2x-1.png | Bin 0 -> 2216 bytes .../AppIcon.appiconset/AppIcon-20x20@2x.png | Bin 0 -> 2216 bytes .../AppIcon.appiconset/AppIcon-20x20@3x.png | Bin 0 -> 3512 bytes .../AppIcon.appiconset/AppIcon-29x29@1x.png | Bin 0 -> 1568 bytes .../AppIcon.appiconset/AppIcon-29x29@2x-1.png | Bin 0 -> 3394 bytes .../AppIcon.appiconset/AppIcon-29x29@2x.png | Bin 0 -> 3394 bytes .../AppIcon.appiconset/AppIcon-29x29@3x.png | Bin 0 -> 5228 bytes .../AppIcon.appiconset/AppIcon-40x40@1x.png | Bin 0 -> 2216 bytes .../AppIcon.appiconset/AppIcon-40x40@2x-1.png | Bin 0 -> 4794 bytes .../AppIcon.appiconset/AppIcon-40x40@2x.png | Bin 0 -> 4794 bytes .../AppIcon.appiconset/AppIcon-40x40@3x.png | Bin 0 -> 7288 bytes .../AppIcon.appiconset/AppIcon-512@2x.png | Bin 0 -> 121323 bytes .../AppIcon.appiconset/AppIcon-60x60@2x.png | Bin 0 -> 7288 bytes .../AppIcon.appiconset/AppIcon-60x60@3x.png | Bin 0 -> 11091 bytes .../AppIcon.appiconset/AppIcon-76x76@1x.png | Bin 0 -> 4515 bytes .../AppIcon.appiconset/AppIcon-76x76@2x.png | Bin 0 -> 9257 bytes .../AppIcon-83.5x83.5@2x.png | Bin 0 -> 10219 bytes .../AppIcon.appiconset/Contents.json | 116 + .../gen/apple/Assets.xcassets/Contents.json | 6 + .../src-tauri/gen/apple/ExportOptions.plist | 8 + .../gen/apple/LaunchScreen.storyboard | 30 + .../desktop/src-tauri/gen/apple/Podfile | 21 + .../apple/Sources/foundry/bindings/bindings.h | 8 + .../gen/apple/Sources/foundry/main.mm | 6 + .../apple/foundry.xcodeproj/project.pbxproj | 460 ++++ .../contents.xcworkspacedata | 7 + .../xcshareddata/WorkspaceSettings.xcsettings | 10 + .../xcschemes/foundry_iOS.xcscheme | 123 + .../gen/apple/foundry_iOS/Info.plist | 49 + .../foundry_iOS/foundry_iOS.entitlements | 5 + .../desktop/src-tauri/gen/apple/project.yml | 88 + .../src-tauri/gen/schemas/capabilities.json | 25 +- .../src-tauri/gen/schemas/iOS-schema.json | 2216 +++++++++++++++++ .../src-tauri/gen/schemas/mobile-schema.json | 2216 +++++++++++++++++ foundry/packages/desktop/src-tauri/src/lib.rs | 151 +- .../desktop/src-tauri/tauri.android.conf.json | 10 + .../desktop/src-tauri/tauri.ios.conf.json | 11 + foundry/packages/frontend/index.html | 2 +- .../frontend/public/sounds/notification-1.mp3 | Bin 0 -> 25389 bytes .../frontend/public/sounds/notification-2.mp3 | Bin 0 -> 12717 bytes .../frontend/src/components/mock-layout.tsx | 506 +++- .../mock-layout/history-minimap.tsx | 49 +- .../components/mock-layout/message-list.tsx | 61 +- .../components/mock-layout/mobile-layout.tsx | 338 +++ .../components/mock-layout/right-sidebar.tsx | 268 +- .../src/components/mock-layout/sidebar.tsx | 411 ++- .../src/components/mock-layout/tab-strip.tsx | 90 +- .../components/mock-layout/terminal-pane.tsx | 207 +- .../mock-layout/transcript-header.tsx | 78 +- .../src/components/mock-layout/ui.tsx | 112 +- .../src/components/mock-layout/view-model.ts | 9 + .../src/components/mock-onboarding.tsx | 579 ++++- .../frontend/src/lib/notification-sound.ts | 77 + foundry/packages/frontend/src/lib/platform.ts | 55 + foundry/packages/frontend/src/styles.css | 39 + foundry/packages/shared/src/app-shell.ts | 3 + foundry/packages/shared/src/workbench.ts | 9 + 68 files changed, 8006 insertions(+), 631 deletions(-) create mode 100644 foundry/packages/desktop/scripts/build-frontend-mobile.ts create mode 100644 foundry/packages/desktop/src-tauri/capabilities/mobile.json create mode 100644 foundry/packages/desktop/src-tauri/gen/apple/.gitignore create mode 100644 foundry/packages/desktop/src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-20x20@1x.png create mode 100644 foundry/packages/desktop/src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-20x20@2x-1.png create mode 100644 foundry/packages/desktop/src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-20x20@2x.png create mode 100644 foundry/packages/desktop/src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-20x20@3x.png create mode 100644 foundry/packages/desktop/src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-29x29@1x.png create mode 100644 foundry/packages/desktop/src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-29x29@2x-1.png create mode 100644 foundry/packages/desktop/src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-29x29@2x.png create mode 100644 foundry/packages/desktop/src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-29x29@3x.png create mode 100644 foundry/packages/desktop/src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-40x40@1x.png create mode 100644 foundry/packages/desktop/src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-40x40@2x-1.png create mode 100644 foundry/packages/desktop/src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-40x40@2x.png create mode 100644 foundry/packages/desktop/src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-40x40@3x.png create mode 100644 foundry/packages/desktop/src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-512@2x.png create mode 100644 foundry/packages/desktop/src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-60x60@2x.png create mode 100644 foundry/packages/desktop/src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-60x60@3x.png create mode 100644 foundry/packages/desktop/src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-76x76@1x.png create mode 100644 foundry/packages/desktop/src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-76x76@2x.png create mode 100644 foundry/packages/desktop/src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-83.5x83.5@2x.png create mode 100644 foundry/packages/desktop/src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/Contents.json create mode 100644 foundry/packages/desktop/src-tauri/gen/apple/Assets.xcassets/Contents.json create mode 100644 foundry/packages/desktop/src-tauri/gen/apple/ExportOptions.plist create mode 100644 foundry/packages/desktop/src-tauri/gen/apple/LaunchScreen.storyboard create mode 100644 foundry/packages/desktop/src-tauri/gen/apple/Podfile create mode 100644 foundry/packages/desktop/src-tauri/gen/apple/Sources/foundry/bindings/bindings.h create mode 100644 foundry/packages/desktop/src-tauri/gen/apple/Sources/foundry/main.mm create mode 100644 foundry/packages/desktop/src-tauri/gen/apple/foundry.xcodeproj/project.pbxproj create mode 100644 foundry/packages/desktop/src-tauri/gen/apple/foundry.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100644 foundry/packages/desktop/src-tauri/gen/apple/foundry.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings create mode 100644 foundry/packages/desktop/src-tauri/gen/apple/foundry.xcodeproj/xcshareddata/xcschemes/foundry_iOS.xcscheme create mode 100644 foundry/packages/desktop/src-tauri/gen/apple/foundry_iOS/Info.plist create mode 100644 foundry/packages/desktop/src-tauri/gen/apple/foundry_iOS/foundry_iOS.entitlements create mode 100644 foundry/packages/desktop/src-tauri/gen/apple/project.yml create mode 100644 foundry/packages/desktop/src-tauri/gen/schemas/iOS-schema.json create mode 100644 foundry/packages/desktop/src-tauri/gen/schemas/mobile-schema.json create mode 100644 foundry/packages/desktop/src-tauri/tauri.android.conf.json create mode 100644 foundry/packages/desktop/src-tauri/tauri.ios.conf.json create mode 100644 foundry/packages/frontend/public/sounds/notification-1.mp3 create mode 100644 foundry/packages/frontend/public/sounds/notification-2.mp3 create mode 100644 foundry/packages/frontend/src/components/mock-layout/mobile-layout.tsx create mode 100644 foundry/packages/frontend/src/lib/notification-sound.ts create mode 100644 foundry/packages/frontend/src/lib/platform.ts diff --git a/foundry/packages/backend/src/actors/workspace/app-shell.ts b/foundry/packages/backend/src/actors/workspace/app-shell.ts index aff0fe1..8ac6b40 100644 --- a/foundry/packages/backend/src/actors/workspace/app-shell.ts +++ b/foundry/packages/backend/src/actors/workspace/app-shell.ts @@ -245,6 +245,7 @@ async function buildAppSnapshot(c: any, sessionId: string): Promise organization.id), } diff --git a/foundry/packages/client/src/mock-app.ts b/foundry/packages/client/src/mock-app.ts index 61dadd2..bcc5ea8 100644 --- a/foundry/packages/client/src/mock-app.ts +++ b/foundry/packages/client/src/mock-app.ts @@ -12,6 +12,7 @@ export interface MockFoundryUser { name: string; email: string; githubLogin: string; + avatarUrl: string | null; roleLabel: string; eligibleOrganizationIds: string[]; } @@ -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 { @@ -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"], }, @@ -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"], }, @@ -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"], }, @@ -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"], }, @@ -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"], @@ -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"], @@ -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"], }, diff --git a/foundry/packages/client/src/mock/workbench-client.ts b/foundry/packages/client/src/mock/workbench-client.ts index f27c436..fc2ce66 100644 --- a/foundry/packages/client/src/mock/workbench-client.ts +++ b/foundry/packages/client/src/mock/workbench-client.ts @@ -100,6 +100,7 @@ class MockWorkbenchStore implements TaskWorkbenchClient { diffs: {}, fileTree: [], minutesUsed: 0, + presence: [], }; this.updateState((current) => ({ diff --git a/foundry/packages/client/src/workbench-model.ts b/foundry/packages/client/src/workbench-model.ts index 42cff08..01a75fb 100644 --- a/foundry/packages/client/src/workbench-model.ts +++ b/foundry/packages/client/src/workbench-model.ts @@ -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", @@ -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", @@ -609,6 +614,7 @@ export function buildInitialTasks(): Task[] { }, ], minutesUsed: 23, + presence: [], }, // ── rivet-dev/rivet ── { @@ -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", @@ -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 ── { @@ -909,6 +921,7 @@ export function buildInitialTasks(): Task[] { }, ], minutesUsed: 0, + presence: [], }, // ── rivet-dev/engine-ee ── { @@ -1023,6 +1036,7 @@ export function buildInitialTasks(): Task[] { }, ], minutesUsed: 78, + presence: [], }, // ── rivet-dev/engine-ee (archived) ── { @@ -1065,6 +1079,7 @@ export function buildInitialTasks(): Task[] { diffs: {}, fileTree: [], minutesUsed: 15, + presence: [], }, // ── rivet-dev/secure-exec ── { @@ -1118,6 +1133,7 @@ export function buildInitialTasks(): Task[] { diffs: {}, fileTree: [], minutesUsed: 3, + presence: [], }, ]; } diff --git a/foundry/packages/desktop/package.json b/foundry/packages/desktop/package.json index 825d62d..e3b8c96 100644 --- a/foundry/packages/desktop/package.json +++ b/foundry/packages/desktop/package.json @@ -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": { diff --git a/foundry/packages/desktop/scripts/build-frontend-mobile.ts b/foundry/packages/desktop/scripts/build-frontend-mobile.ts new file mode 100644 index 0000000..38d02a4 --- /dev/null +++ b/foundry/packages/desktop/scripts/build-frontend-mobile.ts @@ -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*/g, ""); +writeFileSync(indexPath, html); + +console.log("\n=== Mobile frontend build complete ===\n"); diff --git a/foundry/packages/desktop/src-tauri/Cargo.toml b/foundry/packages/desktop/src-tauri/Cargo.toml index bf86188..2dab87f 100644 --- a/foundry/packages/desktop/src-tauri/Cargo.toml +++ b/foundry/packages/desktop/src-tauri/Cargo.toml @@ -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" diff --git a/foundry/packages/desktop/src-tauri/capabilities/default.json b/foundry/packages/desktop/src-tauri/capabilities/default.json index 1275b58..c13d51d 100644 --- a/foundry/packages/desktop/src-tauri/capabilities/default.json +++ b/foundry/packages/desktop/src-tauri/capabilities/default.json @@ -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", diff --git a/foundry/packages/desktop/src-tauri/capabilities/mobile.json b/foundry/packages/desktop/src-tauri/capabilities/mobile.json new file mode 100644 index 0000000..fc0e328 --- /dev/null +++ b/foundry/packages/desktop/src-tauri/capabilities/mobile.json @@ -0,0 +1,7 @@ +{ + "identifier": "mobile", + "description": "Capability for Foundry mobile (iOS/Android)", + "windows": ["main"], + "platforms": ["iOS", "android"], + "permissions": ["core:default"] +} diff --git a/foundry/packages/desktop/src-tauri/gen/apple/.gitignore b/foundry/packages/desktop/src-tauri/gen/apple/.gitignore new file mode 100644 index 0000000..6726e2f --- /dev/null +++ b/foundry/packages/desktop/src-tauri/gen/apple/.gitignore @@ -0,0 +1,3 @@ +xcuserdata/ +build/ +Externals/ diff --git a/foundry/packages/desktop/src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-20x20@1x.png b/foundry/packages/desktop/src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-20x20@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..a6ac2a8ccf0aff8558f948fbc2c9befd5aa34361 GIT binary patch literal 1036 zcmeAS@N?(olHy`uVBq!ia0y~yU=RUe4rT@hhF#%r?HL#t6p}rHd>I(3)EF2VS{N99 zF)%PRykKA`HDF+PmB7GYHG_dcykO3*KpO@I#zO%JYq|Ni~||7YX-f9Jma|95}-zcUg4-k}E^zop$(`qi-hc7D_@MXEoBv-f{(rsY z_y7Nn=kF^VzxCkz&+YGi6yE=G{p*j-uRn1eyzYGA!R>E9fBgMhdG{s5zRNLJANDh4GoY%m=Q8UU~fU@4uaIKYLw#D0bwgz~Sr0r|mw=1=vb3=9m6N#5=*3>~bp9t;c&>?NMQuIw+^BzTz^6OUKiU|?WW_H=O! zk+|$SAvB!XP^2Y&VZaN$D4mSmFOpgxU3>KI-Me?KO1kg({!dR?`+36Wxt8X|>Wm_V zb^C%R+b3{vn4Eg>xv9x_kARRAo8M;(i9^atX9F)9ZY=zzP)=$i< zV@xT`tYlrC{o1YaJDb_|ZH;s9+G^jlw+LA!JYjM2^iLZm2b;TW{dM!_QB~Id@2_U* zPF8*N?AyD44?n*A`83pAbI;y-3;X^1>R+(Mip1{E9nO2Eg12>0?7Xt%>2Hb{{%-q!ClEmBsxE>>u5JO`t10yQ~Lx?4rkKcY~U|?YI MboFyt=akR{0N?04Pyhe` literal 0 HcmV?d00001 diff --git a/foundry/packages/desktop/src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-20x20@2x-1.png b/foundry/packages/desktop/src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-20x20@2x-1.png new file mode 100644 index 0000000000000000000000000000000000000000..2869541f735d2f3f890a5b400fcced58698cbac4 GIT binary patch literal 2216 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 k;ChTqLJWI(3)EF2VS{N99 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 A00000 literal 0 HcmV?d00001 diff --git a/foundry/packages/desktop/src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-29x29@1x.png b/foundry/packages/desktop/src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-29x29@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..29c9746c053996568d0fcf678fcf98ba0ce0f700 GIT binary patch literal 1568 zcmeAS@N?(olHy`uVBq!ia0y~yV2}l24rT@hhD6`#whRmm3dtTpz6=aiY77hwEes65 z7#J8DUNA6}8Za=tN?>5Hn!&&zUNC1@pbY~9)7b!@5ZC`8@bCY>zyJUJ`Ty_tzrVl# ze!TSe`KG^5R{njt{om)C|3C`<{`>d)?}OR@PI~`4p#Oib>i@mU|M#i=J81atbm-q_ z>;8Rx@b8rW|9z_e59t0oX!L)-_W!*qe=nr|`~CUfx5xjE*#6(I`R}Cf--q-6emM8{ z^UZ(nPW-($>EBVu|NFK6oeui<=lj1iq5t>D{k_%t@87?FzdruGnECf=+203qe(zEG zb1Lxfy($0y{`_}7;oti+fBygf_j23+?|1+G`tbknuYX_e{5xp;_gdwjfB#p#`8ngs zn}7fQ{`>y)@4482hb{kJDg5{6+y6ZZ|4#b+`}^zfzyF8ce{nm1kK@4A%DXRq|NHy* zQuhDdGXD=5|KBC~_wIzh_a^^4V*T&?^M%jfOCG%`fBY8rq3cr~zxng;-``UK{}1T= zKVtpwO5xv!bN=s9{CC)V+nZ0~M{X*exUF*HcK@R{AAkS(_wUc&M~nXNmixC)?eCkz ze{VMb`}N-V%w4(Tx71JEKK%a6?|=XPzS{HePVc`DXaDb2`gbmN>XWx(M{i0WyZQ6q zKTu3OS^j^Y#@~l?11>)lIdaqG{QdKvzV$tNec=6xYbw~KfjY*H+v^;pFaq1ejR1=DxDm5_KNDI?Q5XTqPSXAZo5bn5Z32k#!fe0ui4p@b)oU$bw&IbTu1 zKx2kti=v5+jnbrpO^T<~t=QCFpAnE2pFiQmgd=n3OwyXkHpTb+iI9dmLssl)MIn%B(>oVSD-o0yp%H`-#s zd~@xBhK&gs+0)-P?3y`y;pWx18D4Cfch8P3fyc<;i~od~7My7xo@fRyH}pxLVOV_a zjirP8iStwEsawmhDrG!;$hCXAflg|~wi?%?UJDld)LMBpJ0WpnL*m_s~y zCH&^Ncv+p}G4`8lcldz8-dP9ht(XtrEPk%faF>mpTSCt)c2^DSp`BH^pGzl{dTjb> zzAkoGEzgpaHj`Br`X)xFj*R0ItW#B*f6z%D~9Vzz||d=Hs`Y85kHCJYD@<);T3K F0RT^sbH4xp literal 0 HcmV?d00001 diff --git a/foundry/packages/desktop/src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-29x29@2x-1.png b/foundry/packages/desktop/src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-29x29@2x-1.png new file mode 100644 index 0000000000000000000000000000000000000000..a4e68c8d6d5c4a564be190fdd200d7214eda2db2 GIT binary patch literal 3394 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 literal 0 HcmV?d00001 diff --git a/foundry/packages/desktop/src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-40x40@1x.png b/foundry/packages/desktop/src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-40x40@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..2869541f735d2f3f890a5b400fcced58698cbac4 GIT binary patch literal 2216 zcmeAS@N?(olHy`uVBq!ia0y~yV9)?z4kiW$2Ie{XRtyXb3dtTpz6=aiY77hwEes65 z7#J8DUNA6}8Za=tN?>5Hn!&&zUNC1@pbY~916z`}y9>jA5L~c#`D6wL_Sv2;jv*0; zk49wY$b^gjJGZkut$c5Gb+&cg8e!|s&pJD_bU!c$uy|>8DTFdEWm?)06)LFpC~&1h zhUN<0AZ@ONP7|hut#T3mF)?UC;KBe-r6pln{;Eq97gkm#AK$q5_1EM*ukX&>`Taw3 z+1sOKIm>k){hPD1cz^M}&v)O?i4_w3V?V8q`#zUT!>%2jjKAWUx*0i+EI4Ywv~hK3 z!@9n#jS37r2Yv}_%yX@b@R@kSbqzDGwB|+M;)4^bW*dny2Qi)av3kcJ8Q;Imb@Nm@ zZirpF;5+G-n(X#~>uX)AD&K^r>#!|(^Tyzu&5@sr6&k%7=l(PjcINRBJhr{}deUX{ z9Zzc;STj6tg|o{n^xNaMzJ6vC(;cx6g*idY5I#ka6PT_uaooRPI&M<_x|p z?qwN^aX&Kn-NX9wTz}D;z5jj+t?HcD&AM@h(7#Qy|JW!9#dm+-~KpW`h)o0HGwn{TTvRKG6&=nL=Gj>f0F zM>;efZQ9!I&SfwA*-G~B=JGYGkNPm3I9dJkQ(}S4quZy?KaM>=={B3k)~2=ADG!dT zI9(HeuX4%!iuCVGrhTuLb;Rja?Cwk5Zx--lb@)sFql+_?B0b;r+kCQl6k9M$@O9Gr zB|LwYxLGhRs4%}1=D{Iw>M*xLh36HIHTQSV_OWHj~cQmT$Q5FpJ6U&xY95YkBn;Rz)hP{#H=z zU}U{ypz8VM!=5h=*V=WPIRsW5;X2^vBKX(H{OjL^PRm!XJuzkD{I?mq)-Tt6o58KY zw16Stcl+B}vn$`Yu3)>-<(uR1-i|?`iKAnQk&h#z3^U8ebx#`>@9JZJ*v$M>Z7G9~ z^zR41w$;v@*3ntHNs-0rfB%~czaRb;-l!L~dwSB_ttHM4hX1%`O0L*3q4~1sMmUgD>g95)D^K+>gla3fi{I(B3RHA>hfmIM$zo&r}!7>zZ2;#ohj1Tc;VEv zwurq;Lr%v?Zp_>L*8V{4_X~S?^smt zW_TUDw{6+SXV=_9bX!>k-cRw2%{H2UX{PO($${4UFE!Zm%Us=IFIwI)!yxs|e6{Y` z(n;Hvz4AFzxpDvVn-foZ*A*mdZQQx#D3OU*IipppL4nPC|nX}T*$#Jnk{c(|Ldgi&AG=n#oL(gTdCN0D>lON@lKwi zx*eY@%8qrMHj$n6J||=M=GCkY8cqs}Ua@x9ZOT+~cxPk#r+d!zR~hGT*ygTO-|Z~gQ4x%=J=8LM7de#&)S(&=|@O8I<=Ke-EUNSAZG zD7w1++WMVM6V}f$T(yfqSWZgf_rVJ;%U3h@urE_zmY?hW)bTfa1y>frTf##G`yOLe_AmY8$)F zxUgm_(=q4CVSlb%TPOQ6<;mNKOkLa5bFshgKUpq+?%DZi&1}z>Jn}fqlqkU5*pa@5 zK|agRX4l5W<`35iiJtD+9`rg~HJQKH@1NECy@8+7*W9>O=X>SV3hCgDdu7j>Z#8jy z6|JfjW*B}x{I$=@Pi`xX9<}dNSeg-g=H|Sf(j9&xOV_A8Ud`OcXBzHzlxY)}=3dDM ztP(TAPn k;ChTqLJW45bDP46hOx7_4S6Fo+k-*%fHRz`($k|H*YfkAMsr;B4q#jUq< zDkt1IT6%o{`rY-#Z_m7Yvv+l}c&wlxha-=LYvKVmW%frqm<*Sl3fQ5e-ewWdHsvu3 z&yq(8NgEzFNicDSs1^y%k;pOd*ue4OU&y>o zOY0}CsH!>Ha__pvS+Rr(Yn<2_PA8-(o_M@^(Uyd`s88R$59c^AsW3!j=cJi0zvr07 z|FnOC^k%i=XH=$y3jX+IVc|0|SaXjfOOfK77`(W;IsdV|1$Q_5Q?$+}wIJ^LGoA@r|Y>tZzPw7gntH z+2?4+|FHc-xTM*1o!u->PuWd<_;PykC;Zl1JoWm?2S!siJgu2t^r-P>mDmd5{N(%F zQ~ro5FdHQ3(zBe8$0Yijx7mn^R%?`tx)ojokVaC(9Qr$9m{ zZ-OIV3d55I$qmN$Pq&pG;<>MJttRr!{7TP8?=9{hpP3rfORTC@)AiiY=x3-Y9dmSI zuZ*2&F*gY{w(dbH{%&Gm6EFY6_33F zSI%6PX?$#dkGb8FL)qd%iksLp*}m-CU+DI({c_;s+a3pdU;fj6lKDNr^0WE$r5XHt z|7`egeJIVV%#}$+QD(-RkGvmd-Vc7bH9=hEc`W~Arf8yYNC<+X57oyItX$I zyncUWrL5LxzLXUyw{sRADtZ+vTzwDuSLQ(g~ZFdk8VuQDL7FU*D$X?@VMH` z*GpzyH|d`r7aJ~X7f`={vZLB1~(lX@51KUr72GIZ*`9Se?%sdTx|UwTMz zTcF$-H`VC?B;FF(K!OrYMEtquCmpuv;qYqqD7w;&zrVST=6@B+f5%z0}E!Zs9JS#_m?YXKd+^G{#bpPaW`l2ujWKp72bq+8k3+rN7nYtJL?{OEsItxz9ADPE%o&IVC!8rq5o9^M7=v z{&z`#@#x*RUrQOH*FSld8z1m;Zh+tfCd(tP6DxYR?@wyWpOl@K^`bY2)${gOL6x{x z9)JB78L$6Mj8=t?rwzQ7Jhy1it*$Wnmt$kSFxO*J+O9R)Ob3jns~3kxyBvx-YrSuY z(fdR9`Cl`|6xoO>I=ubA?Hm6J(Qs1(Kci{tRB}lyx!_P}W9l-UB_BRqQRLJ=9wdLi?!&^3OH^Kk zI5D){OzqQ<`mplTt+W;H1`2BPnt4n#dURU)xfYjws`ru(@joG+x_t3BVV0XVGgCev zJs*8obo-w74}O^QAFpkyl36*kce)qjVGd5N&Rx+b86?eH|3vKEzh0k3>}D8ct`&-|Zq{>I|tlWhA~oUgBo7LZZ8xJGc6?Y_({+k0DAth>1F z&z;H{B}ZrG-L(DoVq?nu#WS+SR2dwnn3Wwe-L>xji}E(5to#~TxR!Hmo9DSKEtVFi!b@v@%;EVm?bq{}Yj_$yw|lB9 zsA#EjNv|mTRLYbgvgkQij$~Ix{k9KVCw6vB+BR)kqh@Yh{er(ceGgAB*&cnsL_3@_ zXQ}YR%kRuralczKeWv$XBk>9LtER^;4vXbq(8y`Ppt5b^S^xF(Io7PrZf$#}x%Z?jidy^Atl&~o7n(}XKq_9!!&t*T|V`_l66x2!kcYm+-F zv-f;lU*P{&d*?&x5XRNt%eWQ3-B(ziwjj5gWBq(NMbin_0&i(A|5vK?@p8qs%Yj#K zDLZ-He!u4B?p^j-5={#-@|2S%B`7yH*Zhi~eMiHn`sA~l*R_?TWnMZ@&fI)`!m_gN zC+C+(Kbmxp^Wx^{y4vgnPnKuweMf4YLXK;?n!KE~e%+fryX;pzc>BWk&TDgG~SV_A`C<&eYuI8FK;#=lrRmRCrU+h%6z`yM*zfu%~ zuwX;IoPU_LDC4Y)YA;@|u40UM_H2)s0ncgPxk4(ZKkr@E9DTm}`yJh!vSa%UgxTu0 z&wPHK^~P!?{%2h4)jsD2-T36r=@fK(^>3wYXU4O4R9q_Alo&ie9Aj#G9+GnPu_?pM zzx=Ci)SnB=KejDjXst7F5O>8Sk)4PA>=f@vc4lfRV|Mc#jRL)n$N1on&7#&vTKE=q!{Cqm| zB%f0~cAEEhH>a#9YZS6d+-0xzTQB$F|J2O1OOp=dl&5yvt&$U(lvuN7Gw(c3lWEr9 zW&i%EKE5qIw!z8i2TO1EzWS0^o8GeXKjog3Fk5=N_%V+thxhx!-|Y(Js6V^0O?*zO z^|gC$4A0EwWOKaPTfJw+@tC(9t7>MX<_Uk1e#o#V@uQ9*50jjoQRV%NMb`rrJwNcV zFt!^!SaG*lqdl)N#m`+ND^!uFG$S1vKBL@YmZD?0SHLB#owK8qK6 zRvR}LUSGniy~s=RfzdA6jYba^#2tOLbVcW)-v=`G+@84X8k>ZMQMu+%w`Ci?X4IVC zly_U<*~Y7C-?;i};*Z6tIfb5DdqGR&_}5eR0jJk}u&L48ves0ly!2vGswYdvGd_b;z| zd!D1%DlwDyjpFm(tt*_A4Fo0yb^J28*IZqcH(74JB;Un}O@7(Fo8#SB98M@$&Yd9m zp=Y%LlS-gWIlH~G|L*N`DxM2|oc=>C?(M;Ek6LsSvaI5QHdJ1-w5^#ORc*|u>p$rk zs}BRyrP;or%eWL2(${R&kxIXGbzZyqznHT&FM<=7zRGBqbjc|?a`dIf)4R=u$;a$Z z?Ej~GwLDYv-r4^~Nr%lVUUyiX61;5L$>=I_SuIuPRpzD7C%dg~SIIs!)38(xJa_Bt zT*WE1`}#!GPdsttTEfuex8dB&M*qiemWSM58uC)|nSO60CqtEtq+rUboU4jHS=BoN zT=t%MF53UM?*7;2i=5Y2+zMu3s&OgIJN9ZZyn@!WvaI~+iJePyNz|Bcc=C*<$9|t zm){mkO`E2Y!2A8*G|7E&E`FbrI5wM}3DV)(x@T^$wo(4Ik2fOTJga>i`!tfBQEbA4 z=jSD)_owHIzYua1umw$F_Q*7MoSik+e~CFLnv&}C^61(f&(^vxzhLny;G|o`1PfcCUm58?4$CI`Z#>J+c8@0@I{7A(fRm=s zI@9RmN&3EOoNKi{gk5^%a3}b|*7q`1gw>ee6_l)4ykX<(SXho0^eT z8Dw`jZquzC|L61i)8}=kyM20BKi4uQ>!KLr9i@y)-H)Mr-=05S?2vipe1nq8mcO6> z9{-l0)nCae$rV9_;sa-g6 z%Y_Z@No()!`FmiurL0JZ>9s{Ovfs(P`gQ4)+*zCJm8r~yGi4XWFDVXxV|urA${|?DeCAMPu37XXmzUw!S5GR(hI{M1xAwgRXrqTxAcoY%|u; zQaI{c-T(je#vNL{Yo591O3r#H(EEfd{GCnBii}$-JI^eu`S;4mU8S~kg>=L$san5( z?*nUUL-Rcxiog1YIx;XS?%PxTXWhi)glR5uGjeyD@rMeCJp6g`iF&z=Re(WaWLNh* zjYXQdd6D;as)<}U(;cq=tST9B(=pq4{hi7wX>VY$MH~j#j?^4wXHX0c=PUVDEj!a{N4eL=RLQ-$<@Bd zSad%y@2#|G;HiiP{dXL7+x9>H)3ImxY59MZDm-AV?T(&aF$aZ$5zyS{_?u4oFb7eo~bFp7zskz(tY0LBr&k7FK zS_fCyPQ5>~bn`T2FN=`HH%{H-wffY)e0_xEhndS3zZd4{d3mVe|BJmFj~@@-+m|%2 z^0kW)!>Qv(GTfI-jH-yvhw9#|Ddrv1!*_iO}QNr=J%fB>cWa?H19?-aJ(W2rb zc6T?QkB#L-Ed!+>4W-k?e}5XE=aQIWx-H>tyK>|0wq5ncQpfh3Px7Ty+o^e&LB#P=$>bDCwhL#b2?|6!41T_q-R`RF&IQJAN+r}! z^h_6$NEHg$nU#ER>dF06&%Hk*;>Pu^CEKVi)`7{fam6IFD-jp z>k#YpfNR^)H9JmiOIUc2>4V_OTiTs*rr-W8(6cQt-Ff|^@L8Q}JOAjMO_clK&1~bG zRUhz4<@E25-u!-6DO>-X`uk`Sf5ZR%r~fmCPZxK6vN3c%0|SFRdP{k zVo554k%5tku7R1Zfk}vgxs{2bm5I5wfq|8QK~?CSZzvja^HVa@DsgMz=1}osU|`UI u+fb63n_66wm|FnXV`LIyXl!L*WMyCou_W{H+s_OP3=E#GelF{r5}E*OoaAi) literal 0 HcmV?d00001 diff --git a/foundry/packages/desktop/src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-40x40@2x.png b/foundry/packages/desktop/src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-40x40@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..a414e65bb05f202d6d3bd3e6e0762fc02c6124bb GIT binary patch literal 4794 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 literal 0 HcmV?d00001 diff --git a/foundry/packages/desktop/src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-40x40@3x.png b/foundry/packages/desktop/src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-40x40@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..a0807e5dfdad18ce50a5f44e9c116e96d6e606d6 GIT binary patch literal 7288 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

-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 X#FEU%Z$C3IFfe$!`njxgN@xNATaBvW literal 0 HcmV?d00001 diff --git a/foundry/packages/desktop/src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-60x60@2x.png b/foundry/packages/desktop/src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-60x60@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..a0807e5dfdad18ce50a5f44e9c116e96d6e606d6 GIT binary patch literal 7288 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 L>gTe~DWM4f6pSSZ literal 0 HcmV?d00001 diff --git a/foundry/packages/desktop/src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-76x76@1x.png b/foundry/packages/desktop/src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-76x76@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..2cdf18485f69316a5ae921f83997baa4c0042e50 GIT binary patch literal 4515 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 N22WQ%mvv4FO#oSeU~2#X literal 0 HcmV?d00001 diff --git a/foundry/packages/desktop/src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-76x76@2x.png b/foundry/packages/desktop/src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-76x76@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..4723e4b45ea6377219fcf9475c2c75ae075fed5e GIT binary patch literal 9257 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 literal 0 HcmV?d00001 diff --git a/foundry/packages/desktop/src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-83.5x83.5@2x.png b/foundry/packages/desktop/src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset/AppIcon-83.5x83.5@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..f26fee45c06c140414d4de5ef4a6911edb665b3e GIT binary patch literal 10219 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 + + + + method + debugging + + diff --git a/foundry/packages/desktop/src-tauri/gen/apple/LaunchScreen.storyboard b/foundry/packages/desktop/src-tauri/gen/apple/LaunchScreen.storyboard new file mode 100644 index 0000000..81b5f90 --- /dev/null +++ b/foundry/packages/desktop/src-tauri/gen/apple/LaunchScreen.storyboard @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/foundry/packages/desktop/src-tauri/gen/apple/Podfile b/foundry/packages/desktop/src-tauri/gen/apple/Podfile new file mode 100644 index 0000000..110c081 --- /dev/null +++ b/foundry/packages/desktop/src-tauri/gen/apple/Podfile @@ -0,0 +1,21 @@ +# Uncomment the next line to define a global platform for your project + +target 'foundry_iOS' do +platform :ios, '14.0' + # Pods for foundry_iOS +end + +target 'foundry_macOS' do +platform :osx, '11.0' + # Pods for foundry_macOS +end + +# Delete the deployment target for iOS and macOS, causing it to be inherited from the Podfile +post_install do |installer| + installer.pods_project.targets.each do |target| + target.build_configurations.each do |config| + config.build_settings.delete 'IPHONEOS_DEPLOYMENT_TARGET' + config.build_settings.delete 'MACOSX_DEPLOYMENT_TARGET' + end + end +end diff --git a/foundry/packages/desktop/src-tauri/gen/apple/Sources/foundry/bindings/bindings.h b/foundry/packages/desktop/src-tauri/gen/apple/Sources/foundry/bindings/bindings.h new file mode 100644 index 0000000..5152200 --- /dev/null +++ b/foundry/packages/desktop/src-tauri/gen/apple/Sources/foundry/bindings/bindings.h @@ -0,0 +1,8 @@ +#pragma once + +namespace ffi { + extern "C" { + void start_app(); + } +} + diff --git a/foundry/packages/desktop/src-tauri/gen/apple/Sources/foundry/main.mm b/foundry/packages/desktop/src-tauri/gen/apple/Sources/foundry/main.mm new file mode 100644 index 0000000..7793a9d --- /dev/null +++ b/foundry/packages/desktop/src-tauri/gen/apple/Sources/foundry/main.mm @@ -0,0 +1,6 @@ +#include "bindings/bindings.h" + +int main(int argc, char * argv[]) { + ffi::start_app(); + return 0; +} diff --git a/foundry/packages/desktop/src-tauri/gen/apple/foundry.xcodeproj/project.pbxproj b/foundry/packages/desktop/src-tauri/gen/apple/foundry.xcodeproj/project.pbxproj new file mode 100644 index 0000000..0d27a2c --- /dev/null +++ b/foundry/packages/desktop/src-tauri/gen/apple/foundry.xcodeproj/project.pbxproj @@ -0,0 +1,460 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 77; + objects = { + +/* Begin PBXBuildFile section */ + 18AA2DEF7E37375920E5C2A0 /* assets in Resources */ = {isa = PBXBuildFile; fileRef = 5839511CE1969F167776E5BA /* assets */; }; + 41F61AA6A6395C0E1A22A01D /* Metal.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C796B246B7EFC59BE22BEAE /* Metal.framework */; }; + 46451E98CD8CC918B270DF4E /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4CA3839E082C9EE1FBE47017 /* CoreGraphics.framework */; }; + 5823D1D3CF428AB8675028CA /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 916B38007890BE6F5229D88A /* QuartzCore.framework */; }; + 63828790DD4F121B20E1314C /* libapp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 61706E406133F9FEA10A02CF /* libapp.a */; }; + 6DF20201B9860B37359D8373 /* WebKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7FB0AF0861142E98564AE14D /* WebKit.framework */; }; + 84F2A1451B638E04DC7D9C77 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0FFD378E56937244899E32B9 /* UIKit.framework */; }; + A391FE2BDE082320542B786E /* MetalKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9503D8DA5A521E10DE980308 /* MetalKit.framework */; }; + A9D64B11D3591BA69A9FF24D /* main.mm in Sources */ = {isa = PBXBuildFile; fileRef = 41768F9AEEC30C6F3A657349 /* main.mm */; }; + C2EC09AB9A1F311F389731DA /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 73239B7F777F17978C5F9FB3 /* LaunchScreen.storyboard */; }; + E05514D9EF3C91D648336FAF /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1BE59BDC6646E6E88C37132A /* Security.framework */; }; + EF8153BCCF98E828B21D22B8 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 2C2D23C60F5F67FF1B8EF9BE /* Assets.xcassets */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 0FFD378E56937244899E32B9 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; + 1BE59BDC6646E6E88C37132A /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; }; + 2C2D23C60F5F67FF1B8EF9BE /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 41768F9AEEC30C6F3A657349 /* main.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = main.mm; sourceTree = ""; }; + 46675940F25D441B14F4D9BD /* bindings.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = bindings.h; sourceTree = ""; }; + 4BF135A484B3FD794B6BE633 /* main.rs */ = {isa = PBXFileReference; path = main.rs; sourceTree = ""; }; + 4C796B246B7EFC59BE22BEAE /* Metal.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Metal.framework; path = System/Library/Frameworks/Metal.framework; sourceTree = SDKROOT; }; + 4CA3839E082C9EE1FBE47017 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; + 5839511CE1969F167776E5BA /* assets */ = {isa = PBXFileReference; lastKnownFileType = folder; path = assets; sourceTree = SOURCE_ROOT; }; + 61706E406133F9FEA10A02CF /* libapp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libapp.a; sourceTree = ""; }; + 6C52C06D919E696C88F980CA /* lib.rs */ = {isa = PBXFileReference; path = lib.rs; sourceTree = ""; }; + 73239B7F777F17978C5F9FB3 /* LaunchScreen.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = LaunchScreen.storyboard; sourceTree = ""; }; + 7A2D8F7E3AD2D4401F4C016B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; }; + 7CD23EC29DD8E675CF62425F /* foundry_iOS.app */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = wrapper.application; path = foundry_iOS.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 7FB0AF0861142E98564AE14D /* WebKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WebKit.framework; path = System/Library/Frameworks/WebKit.framework; sourceTree = SDKROOT; }; + 916B38007890BE6F5229D88A /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; }; + 9503D8DA5A521E10DE980308 /* MetalKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MetalKit.framework; path = System/Library/Frameworks/MetalKit.framework; sourceTree = SDKROOT; }; + E33D510DA88C9082AA568044 /* foundry_iOS.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = foundry_iOS.entitlements; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 2A55D5F956F7DFC89A1EF6A3 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 63828790DD4F121B20E1314C /* libapp.a in Frameworks */, + 46451E98CD8CC918B270DF4E /* CoreGraphics.framework in Frameworks */, + 41F61AA6A6395C0E1A22A01D /* Metal.framework in Frameworks */, + A391FE2BDE082320542B786E /* MetalKit.framework in Frameworks */, + 5823D1D3CF428AB8675028CA /* QuartzCore.framework in Frameworks */, + E05514D9EF3C91D648336FAF /* Security.framework in Frameworks */, + 84F2A1451B638E04DC7D9C77 /* UIKit.framework in Frameworks */, + 6DF20201B9860B37359D8373 /* WebKit.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 1C4A0974016D1DFD8F8C4DDB /* Frameworks */ = { + isa = PBXGroup; + children = ( + 4CA3839E082C9EE1FBE47017 /* CoreGraphics.framework */, + 61706E406133F9FEA10A02CF /* libapp.a */, + 4C796B246B7EFC59BE22BEAE /* Metal.framework */, + 9503D8DA5A521E10DE980308 /* MetalKit.framework */, + 916B38007890BE6F5229D88A /* QuartzCore.framework */, + 1BE59BDC6646E6E88C37132A /* Security.framework */, + 0FFD378E56937244899E32B9 /* UIKit.framework */, + 7FB0AF0861142E98564AE14D /* WebKit.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + 2FD745FA11757414C89CF97B /* Products */ = { + isa = PBXGroup; + children = ( + 7CD23EC29DD8E675CF62425F /* foundry_iOS.app */, + ); + name = Products; + sourceTree = ""; + }; + 3BB81CF687DD217A69E52F28 /* src */ = { + isa = PBXGroup; + children = ( + 6C52C06D919E696C88F980CA /* lib.rs */, + 4BF135A484B3FD794B6BE633 /* main.rs */, + ); + name = src; + path = ../../src; + sourceTree = ""; + }; + 57E35B817B051AAFCDF3B583 /* bindings */ = { + isa = PBXGroup; + children = ( + 46675940F25D441B14F4D9BD /* bindings.h */, + ); + path = bindings; + sourceTree = ""; + }; + 8A9C64E5F1382764F31A9C3E = { + isa = PBXGroup; + children = ( + 5839511CE1969F167776E5BA /* assets */, + 2C2D23C60F5F67FF1B8EF9BE /* Assets.xcassets */, + 73239B7F777F17978C5F9FB3 /* LaunchScreen.storyboard */, + D848E3356050EA6A0C214268 /* Externals */, + A8C8B8DF2C7F39FBBD9C49F8 /* foundry_iOS */, + F7BF3354D37B8C8E0475FD89 /* Sources */, + 3BB81CF687DD217A69E52F28 /* src */, + 1C4A0974016D1DFD8F8C4DDB /* Frameworks */, + 2FD745FA11757414C89CF97B /* Products */, + ); + sourceTree = ""; + }; + A8C8B8DF2C7F39FBBD9C49F8 /* foundry_iOS */ = { + isa = PBXGroup; + children = ( + E33D510DA88C9082AA568044 /* foundry_iOS.entitlements */, + 7A2D8F7E3AD2D4401F4C016B /* Info.plist */, + ); + path = foundry_iOS; + sourceTree = ""; + }; + D848E3356050EA6A0C214268 /* Externals */ = { + isa = PBXGroup; + children = ( + ); + path = Externals; + sourceTree = ""; + }; + F5B02224172A9BB7345E5123 /* foundry */ = { + isa = PBXGroup; + children = ( + 41768F9AEEC30C6F3A657349 /* main.mm */, + 57E35B817B051AAFCDF3B583 /* bindings */, + ); + path = foundry; + sourceTree = ""; + }; + F7BF3354D37B8C8E0475FD89 /* Sources */ = { + isa = PBXGroup; + children = ( + F5B02224172A9BB7345E5123 /* foundry */, + ); + path = Sources; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + B133A72EA416CD7D39FE3E92 /* foundry_iOS */ = { + isa = PBXNativeTarget; + buildConfigurationList = D445EACB90281484F8FFC686 /* Build configuration list for PBXNativeTarget "foundry_iOS" */; + buildPhases = ( + FB6BE1E1013DC03BA292046D /* Build Rust Code */, + 5D12D268150FB53F48EDE74C /* Sources */, + 0391435C164ED2F1E2300246 /* Resources */, + 2A55D5F956F7DFC89A1EF6A3 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = foundry_iOS; + packageProductDependencies = ( + ); + productName = foundry_iOS; + productReference = 7CD23EC29DD8E675CF62425F /* foundry_iOS.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 376A77EF2CEF8254085FAA46 /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = YES; + LastUpgradeCheck = 1430; + TargetAttributes = { + }; + }; + buildConfigurationList = 98E4F3D9D125FB8973826CB2 /* Build configuration list for PBXProject "foundry" */; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + Base, + en, + ); + mainGroup = 8A9C64E5F1382764F31A9C3E; + minimizedProjectReferenceProxies = 1; + preferredProjectObjectVersion = 77; + productRefGroup = 2FD745FA11757414C89CF97B /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + B133A72EA416CD7D39FE3E92 /* foundry_iOS */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 0391435C164ED2F1E2300246 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + EF8153BCCF98E828B21D22B8 /* Assets.xcassets in Resources */, + C2EC09AB9A1F311F389731DA /* LaunchScreen.storyboard in Resources */, + 18AA2DEF7E37375920E5C2A0 /* assets in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + FB6BE1E1013DC03BA292046D /* Build Rust Code */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + name = "Build Rust Code"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(SRCROOT)/Externals/x86_64/${CONFIGURATION}/libapp.a", + "$(SRCROOT)/Externals/arm64/${CONFIGURATION}/libapp.a", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "pnpm tauri ios xcode-script -v --platform ${PLATFORM_DISPLAY_NAME:?} --sdk-root ${SDKROOT:?} --framework-search-paths \"${FRAMEWORK_SEARCH_PATHS:?}\" --header-search-paths \"${HEADER_SEARCH_PATHS:?}\" --gcc-preprocessor-definitions \"${GCC_PREPROCESSOR_DEFINITIONS:-}\" --configuration ${CONFIGURATION:?} ${FORCE_COLOR} ${ARCHS:?}"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 5D12D268150FB53F48EDE74C /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + A9D64B11D3591BA69A9FF24D /* main.mm in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 2B285D0ECCDEA51DB6635985 /* debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "$(inherited)", + "DEBUG=1", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + }; + name = debug; + }; + 362B62575264ECB0984A8FC7 /* release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; + ARCHS = ( + arm64, + ); + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_ENTITLEMENTS = foundry_iOS/foundry_iOS.entitlements; + CODE_SIGN_IDENTITY = "iPhone Developer"; + ENABLE_BITCODE = NO; + "EXCLUDED_ARCHS[sdk=iphoneos*]" = x86_64; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "\".\"", + ); + INFOPLIST_FILE = foundry_iOS/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + "LIBRARY_SEARCH_PATHS[arch=arm64]" = "$(inherited) $(PROJECT_DIR)/Externals/arm64/$(CONFIGURATION) $(SDKROOT)/usr/lib/swift $(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME) $(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)"; + "LIBRARY_SEARCH_PATHS[arch=x86_64]" = "$(inherited) $(PROJECT_DIR)/Externals/x86_64/$(CONFIGURATION) $(SDKROOT)/usr/lib/swift $(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME) $(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)"; + PRODUCT_BUNDLE_IDENTIFIER = dev.sandboxagent.foundry; + PRODUCT_NAME = "Foundry"; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALID_ARCHS = arm64; + }; + name = release; + }; + 6503634097DB1CB8102F723F /* debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; + ARCHS = ( + arm64, + ); + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_ENTITLEMENTS = foundry_iOS/foundry_iOS.entitlements; + CODE_SIGN_IDENTITY = "iPhone Developer"; + ENABLE_BITCODE = NO; + "EXCLUDED_ARCHS[sdk=iphoneos*]" = x86_64; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "\".\"", + ); + INFOPLIST_FILE = foundry_iOS/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + "LIBRARY_SEARCH_PATHS[arch=arm64]" = "$(inherited) $(PROJECT_DIR)/Externals/arm64/$(CONFIGURATION) $(SDKROOT)/usr/lib/swift $(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME) $(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)"; + "LIBRARY_SEARCH_PATHS[arch=x86_64]" = "$(inherited) $(PROJECT_DIR)/Externals/x86_64/$(CONFIGURATION) $(SDKROOT)/usr/lib/swift $(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME) $(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)"; + PRODUCT_BUNDLE_IDENTIFIER = dev.sandboxagent.foundry; + PRODUCT_NAME = "Foundry"; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALID_ARCHS = arm64; + }; + name = debug; + }; + 7DD9B8183C37530AE219A355 /* release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + SWIFT_VERSION = 5.0; + }; + name = release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 98E4F3D9D125FB8973826CB2 /* Build configuration list for PBXProject "foundry" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 2B285D0ECCDEA51DB6635985 /* debug */, + 7DD9B8183C37530AE219A355 /* release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = debug; + }; + D445EACB90281484F8FFC686 /* Build configuration list for PBXNativeTarget "foundry_iOS" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 6503634097DB1CB8102F723F /* debug */, + 362B62575264ECB0984A8FC7 /* release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = debug; + }; +/* End XCConfigurationList section */ + }; + rootObject = 376A77EF2CEF8254085FAA46 /* Project object */; +} diff --git a/foundry/packages/desktop/src-tauri/gen/apple/foundry.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/foundry/packages/desktop/src-tauri/gen/apple/foundry.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..919434a --- /dev/null +++ b/foundry/packages/desktop/src-tauri/gen/apple/foundry.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/foundry/packages/desktop/src-tauri/gen/apple/foundry.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/foundry/packages/desktop/src-tauri/gen/apple/foundry.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 0000000..ac90d5a --- /dev/null +++ b/foundry/packages/desktop/src-tauri/gen/apple/foundry.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,10 @@ + + + + + BuildSystemType + Original + DisableBuildSystemDeprecationDiagnostic + + + diff --git a/foundry/packages/desktop/src-tauri/gen/apple/foundry.xcodeproj/xcshareddata/xcschemes/foundry_iOS.xcscheme b/foundry/packages/desktop/src-tauri/gen/apple/foundry.xcodeproj/xcshareddata/xcschemes/foundry_iOS.xcscheme new file mode 100644 index 0000000..0e103fa --- /dev/null +++ b/foundry/packages/desktop/src-tauri/gen/apple/foundry.xcodeproj/xcshareddata/xcschemes/foundry_iOS.xcscheme @@ -0,0 +1,123 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/foundry/packages/desktop/src-tauri/gen/apple/foundry_iOS/Info.plist b/foundry/packages/desktop/src-tauri/gen/apple/foundry_iOS/Info.plist new file mode 100644 index 0000000..19c7bde --- /dev/null +++ b/foundry/packages/desktop/src-tauri/gen/apple/foundry_iOS/Info.plist @@ -0,0 +1,49 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 0.1.0 + CFBundleVersion + 0.1.0 + LSRequiresIPhoneOS + + NSAppTransportSecurity + + NSAllowsArbitraryLoads + + + UILaunchStoryboardName + LaunchScreen + UIRequiredDeviceCapabilities + + arm64 + metal + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + \ No newline at end of file diff --git a/foundry/packages/desktop/src-tauri/gen/apple/foundry_iOS/foundry_iOS.entitlements b/foundry/packages/desktop/src-tauri/gen/apple/foundry_iOS/foundry_iOS.entitlements new file mode 100644 index 0000000..0c67376 --- /dev/null +++ b/foundry/packages/desktop/src-tauri/gen/apple/foundry_iOS/foundry_iOS.entitlements @@ -0,0 +1,5 @@ + + + + + diff --git a/foundry/packages/desktop/src-tauri/gen/apple/project.yml b/foundry/packages/desktop/src-tauri/gen/apple/project.yml new file mode 100644 index 0000000..e46690b --- /dev/null +++ b/foundry/packages/desktop/src-tauri/gen/apple/project.yml @@ -0,0 +1,88 @@ +name: foundry +options: + bundleIdPrefix: dev.sandboxagent.foundry + deploymentTarget: + iOS: 14.0 +fileGroups: [../../src] +configs: + debug: debug + release: release +settingGroups: + app: + base: + PRODUCT_NAME: Foundry + PRODUCT_BUNDLE_IDENTIFIER: dev.sandboxagent.foundry +targetTemplates: + app: + type: application + sources: + - path: Sources + scheme: + environmentVariables: + RUST_BACKTRACE: full + RUST_LOG: info + settings: + groups: [app] +targets: + foundry_iOS: + type: application + platform: iOS + sources: + - path: Sources + - path: Assets.xcassets + - path: Externals + - path: foundry_iOS + - path: assets + buildPhase: resources + type: folder + - path: LaunchScreen.storyboard + info: + path: foundry_iOS/Info.plist + properties: + LSRequiresIPhoneOS: true + UILaunchStoryboardName: LaunchScreen + UIRequiredDeviceCapabilities: [arm64, metal] + UISupportedInterfaceOrientations: + - UIInterfaceOrientationPortrait + - UIInterfaceOrientationLandscapeLeft + - UIInterfaceOrientationLandscapeRight + UISupportedInterfaceOrientations~ipad: + - UIInterfaceOrientationPortrait + - UIInterfaceOrientationPortraitUpsideDown + - UIInterfaceOrientationLandscapeLeft + - UIInterfaceOrientationLandscapeRight + CFBundleShortVersionString: 0.1.0 + CFBundleVersion: "0.1.0" + entitlements: + path: foundry_iOS/foundry_iOS.entitlements + scheme: + environmentVariables: + RUST_BACKTRACE: full + RUST_LOG: info + settings: + base: + ENABLE_BITCODE: false + ARCHS: [arm64] + VALID_ARCHS: arm64 + LIBRARY_SEARCH_PATHS[arch=x86_64]: $(inherited) $(PROJECT_DIR)/Externals/x86_64/$(CONFIGURATION) $(SDKROOT)/usr/lib/swift $(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME) $(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME) + LIBRARY_SEARCH_PATHS[arch=arm64]: $(inherited) $(PROJECT_DIR)/Externals/arm64/$(CONFIGURATION) $(SDKROOT)/usr/lib/swift $(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME) $(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME) + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES: true + EXCLUDED_ARCHS[sdk=iphoneos*]: x86_64 + groups: [app] + dependencies: + - framework: libapp.a + embed: false + - sdk: CoreGraphics.framework + - sdk: Metal.framework + - sdk: MetalKit.framework + - sdk: QuartzCore.framework + - sdk: Security.framework + - sdk: UIKit.framework + - sdk: WebKit.framework + preBuildScripts: + - script: pnpm tauri ios xcode-script -v --platform ${PLATFORM_DISPLAY_NAME:?} --sdk-root ${SDKROOT:?} --framework-search-paths "${FRAMEWORK_SEARCH_PATHS:?}" --header-search-paths "${HEADER_SEARCH_PATHS:?}" --gcc-preprocessor-definitions "${GCC_PREPROCESSOR_DEFINITIONS:-}" --configuration ${CONFIGURATION:?} ${FORCE_COLOR} ${ARCHS:?} + name: Build Rust Code + basedOnDependencyAnalysis: false + outputFiles: + - $(SRCROOT)/Externals/x86_64/${CONFIGURATION}/libapp.a + - $(SRCROOT)/Externals/arm64/${CONFIGURATION}/libapp.a \ No newline at end of file diff --git a/foundry/packages/desktop/src-tauri/gen/schemas/capabilities.json b/foundry/packages/desktop/src-tauri/gen/schemas/capabilities.json index fe3a6f3..d351e57 100644 --- a/foundry/packages/desktop/src-tauri/gen/schemas/capabilities.json +++ b/foundry/packages/desktop/src-tauri/gen/schemas/capabilities.json @@ -1 +1,24 @@ -{"default":{"identifier":"default","description":"Default capability for Foundry desktop","local":true,"windows":["main"],"permissions":["core:default","core:window:allow-start-dragging","shell:allow-open",{"identifier":"shell:allow-execute","allow":[{"args":true,"name":"sidecars/foundry-backend","sidecar":true}]},{"identifier":"shell:allow-spawn","allow":[{"args":true,"name":"sidecars/foundry-backend","sidecar":true}]}]}} \ No newline at end of file +{ + "default": { + "identifier": "default", + "description": "Default capability for Foundry desktop", + "local": true, + "windows": ["main"], + "permissions": [ + "core:default", + "core:window:allow-start-dragging", + "shell:allow-open", + { "identifier": "shell:allow-execute", "allow": [{ "args": true, "name": "sidecars/foundry-backend", "sidecar": true }] }, + { "identifier": "shell:allow-spawn", "allow": [{ "args": true, "name": "sidecars/foundry-backend", "sidecar": true }] } + ], + "platforms": ["macOS", "windows", "linux"] + }, + "mobile": { + "identifier": "mobile", + "description": "Capability for Foundry mobile (iOS/Android)", + "local": true, + "windows": ["main"], + "permissions": ["core:default"], + "platforms": ["iOS", "android"] + } +} diff --git a/foundry/packages/desktop/src-tauri/gen/schemas/iOS-schema.json b/foundry/packages/desktop/src-tauri/gen/schemas/iOS-schema.json new file mode 100644 index 0000000..39c4610 --- /dev/null +++ b/foundry/packages/desktop/src-tauri/gen/schemas/iOS-schema.json @@ -0,0 +1,2216 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "CapabilityFile", + "description": "Capability formats accepted in a capability file.", + "anyOf": [ + { + "description": "A single capability.", + "allOf": [ + { + "$ref": "#/definitions/Capability" + } + ] + }, + { + "description": "A list of capabilities.", + "type": "array", + "items": { + "$ref": "#/definitions/Capability" + } + }, + { + "description": "A list of capabilities.", + "type": "object", + "required": ["capabilities"], + "properties": { + "capabilities": { + "description": "The list of capabilities.", + "type": "array", + "items": { + "$ref": "#/definitions/Capability" + } + } + } + } + ], + "definitions": { + "Capability": { + "description": "A grouping and boundary mechanism developers can use to isolate access to the IPC layer.\n\nIt controls application windows' and webviews' fine grained access to the Tauri core, application, or plugin commands. If a webview or its window is not matching any capability then it has no access to the IPC layer at all.\n\nThis can be done to create groups of windows, based on their required system access, which can reduce impact of frontend vulnerabilities in less privileged windows. Windows can be added to a capability by exact name (e.g. `main-window`) or glob patterns like `*` or `admin-*`. A Window can have none, one, or multiple associated capabilities.\n\n## Example\n\n```json { \"identifier\": \"main-user-files-write\", \"description\": \"This capability allows the `main` window on macOS and Windows access to `filesystem` write related commands and `dialog` commands to enable programmatic access to files selected by the user.\", \"windows\": [ \"main\" ], \"permissions\": [ \"core:default\", \"dialog:open\", { \"identifier\": \"fs:allow-write-text-file\", \"allow\": [{ \"path\": \"$HOME/test.txt\" }] }, ], \"platforms\": [\"macOS\",\"windows\"] } ```", + "type": "object", + "required": ["identifier", "permissions"], + "properties": { + "identifier": { + "description": "Identifier of the capability.\n\n## Example\n\n`main-user-files-write`", + "type": "string" + }, + "description": { + "description": "Description of what the capability is intended to allow on associated windows.\n\nIt should contain a description of what the grouped permissions should allow.\n\n## Example\n\nThis capability allows the `main` window access to `filesystem` write related commands and `dialog` commands to enable programmatic access to files selected by the user.", + "default": "", + "type": "string" + }, + "remote": { + "description": "Configure remote URLs that can use the capability permissions.\n\nThis setting is optional and defaults to not being set, as our default use case is that the content is served from our local application.\n\n:::caution Make sure you understand the security implications of providing remote sources with local system access. :::\n\n## Example\n\n```json { \"urls\": [\"https://*.mydomain.dev\"] } ```", + "anyOf": [ + { + "$ref": "#/definitions/CapabilityRemote" + }, + { + "type": "null" + } + ] + }, + "local": { + "description": "Whether this capability is enabled for local app URLs or not. Defaults to `true`.", + "default": true, + "type": "boolean" + }, + "windows": { + "description": "List of windows that are affected by this capability. Can be a glob pattern.\n\nIf a window label matches any of the patterns in this list, the capability will be enabled on all the webviews of that window, regardless of the value of [`Self::webviews`].\n\nOn multiwebview windows, prefer specifying [`Self::webviews`] and omitting [`Self::windows`] for a fine grained access control.\n\n## Example\n\n`[\"main\"]`", + "type": "array", + "items": { + "type": "string" + } + }, + "webviews": { + "description": "List of webviews that are affected by this capability. Can be a glob pattern.\n\nThe capability will be enabled on all the webviews whose label matches any of the patterns in this list, regardless of whether the webview's window label matches a pattern in [`Self::windows`].\n\n## Example\n\n`[\"sub-webview-one\", \"sub-webview-two\"]`", + "type": "array", + "items": { + "type": "string" + } + }, + "permissions": { + "description": "List of permissions attached to this capability.\n\nMust include the plugin name as prefix in the form of `${plugin-name}:${permission-name}`. For commands directly implemented in the application itself only `${permission-name}` is required.\n\n## Example\n\n```json [ \"core:default\", \"shell:allow-open\", \"dialog:open\", { \"identifier\": \"fs:allow-write-text-file\", \"allow\": [{ \"path\": \"$HOME/test.txt\" }] } ] ```", + "type": "array", + "items": { + "$ref": "#/definitions/PermissionEntry" + }, + "uniqueItems": true + }, + "platforms": { + "description": "Limit which target platforms this capability applies to.\n\nBy default all platforms are targeted.\n\n## Example\n\n`[\"macOS\",\"windows\"]`", + "type": ["array", "null"], + "items": { + "$ref": "#/definitions/Target" + } + } + } + }, + "CapabilityRemote": { + "description": "Configuration for remote URLs that are associated with the capability.", + "type": "object", + "required": ["urls"], + "properties": { + "urls": { + "description": "Remote domains this capability refers to using the [URLPattern standard](https://urlpattern.spec.whatwg.org/).\n\n## Examples\n\n- \"https://*.mydomain.dev\": allows subdomains of mydomain.dev - \"https://mydomain.dev/api/*\": allows any subpath of mydomain.dev/api", + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "PermissionEntry": { + "description": "An entry for a permission value in a [`Capability`] can be either a raw permission [`Identifier`] or an object that references a permission and extends its scope.", + "anyOf": [ + { + "description": "Reference a permission or permission set by identifier.", + "allOf": [ + { + "$ref": "#/definitions/Identifier" + } + ] + }, + { + "description": "Reference a permission or permission set by identifier and extends its scope.", + "type": "object", + "allOf": [ + { + "properties": { + "identifier": { + "description": "Identifier of the permission or permission set.", + "allOf": [ + { + "$ref": "#/definitions/Identifier" + } + ] + }, + "allow": { + "description": "Data that defines what is allowed by the scope.", + "type": ["array", "null"], + "items": { + "$ref": "#/definitions/Value" + } + }, + "deny": { + "description": "Data that defines what is denied by the scope. This should be prioritized by validation logic.", + "type": ["array", "null"], + "items": { + "$ref": "#/definitions/Value" + } + } + } + } + ], + "required": ["identifier"] + } + ] + }, + "Identifier": { + "description": "Permission identifier", + "oneOf": [ + { + "description": "Default core plugins set.\n#### This default permission set includes:\n\n- `core:path:default`\n- `core:event:default`\n- `core:window:default`\n- `core:webview:default`\n- `core:app:default`\n- `core:image:default`\n- `core:resources:default`\n- `core:menu:default`\n- `core:tray:default`", + "type": "string", + "const": "core:default", + "markdownDescription": "Default core plugins set.\n#### This default permission set includes:\n\n- `core:path:default`\n- `core:event:default`\n- `core:window:default`\n- `core:webview:default`\n- `core:app:default`\n- `core:image:default`\n- `core:resources:default`\n- `core:menu:default`\n- `core:tray:default`" + }, + { + "description": "Default permissions for the plugin.\n#### This default permission set includes:\n\n- `allow-version`\n- `allow-name`\n- `allow-tauri-version`\n- `allow-identifier`\n- `allow-bundle-type`\n- `allow-register-listener`\n- `allow-remove-listener`", + "type": "string", + "const": "core:app:default", + "markdownDescription": "Default permissions for the plugin.\n#### This default permission set includes:\n\n- `allow-version`\n- `allow-name`\n- `allow-tauri-version`\n- `allow-identifier`\n- `allow-bundle-type`\n- `allow-register-listener`\n- `allow-remove-listener`" + }, + { + "description": "Enables the app_hide command without any pre-configured scope.", + "type": "string", + "const": "core:app:allow-app-hide", + "markdownDescription": "Enables the app_hide command without any pre-configured scope." + }, + { + "description": "Enables the app_show command without any pre-configured scope.", + "type": "string", + "const": "core:app:allow-app-show", + "markdownDescription": "Enables the app_show command without any pre-configured scope." + }, + { + "description": "Enables the bundle_type command without any pre-configured scope.", + "type": "string", + "const": "core:app:allow-bundle-type", + "markdownDescription": "Enables the bundle_type command without any pre-configured scope." + }, + { + "description": "Enables the default_window_icon command without any pre-configured scope.", + "type": "string", + "const": "core:app:allow-default-window-icon", + "markdownDescription": "Enables the default_window_icon command without any pre-configured scope." + }, + { + "description": "Enables the fetch_data_store_identifiers command without any pre-configured scope.", + "type": "string", + "const": "core:app:allow-fetch-data-store-identifiers", + "markdownDescription": "Enables the fetch_data_store_identifiers command without any pre-configured scope." + }, + { + "description": "Enables the identifier command without any pre-configured scope.", + "type": "string", + "const": "core:app:allow-identifier", + "markdownDescription": "Enables the identifier command without any pre-configured scope." + }, + { + "description": "Enables the name command without any pre-configured scope.", + "type": "string", + "const": "core:app:allow-name", + "markdownDescription": "Enables the name command without any pre-configured scope." + }, + { + "description": "Enables the register_listener command without any pre-configured scope.", + "type": "string", + "const": "core:app:allow-register-listener", + "markdownDescription": "Enables the register_listener command without any pre-configured scope." + }, + { + "description": "Enables the remove_data_store command without any pre-configured scope.", + "type": "string", + "const": "core:app:allow-remove-data-store", + "markdownDescription": "Enables the remove_data_store command without any pre-configured scope." + }, + { + "description": "Enables the remove_listener command without any pre-configured scope.", + "type": "string", + "const": "core:app:allow-remove-listener", + "markdownDescription": "Enables the remove_listener command without any pre-configured scope." + }, + { + "description": "Enables the set_app_theme command without any pre-configured scope.", + "type": "string", + "const": "core:app:allow-set-app-theme", + "markdownDescription": "Enables the set_app_theme command without any pre-configured scope." + }, + { + "description": "Enables the set_dock_visibility command without any pre-configured scope.", + "type": "string", + "const": "core:app:allow-set-dock-visibility", + "markdownDescription": "Enables the set_dock_visibility command without any pre-configured scope." + }, + { + "description": "Enables the tauri_version command without any pre-configured scope.", + "type": "string", + "const": "core:app:allow-tauri-version", + "markdownDescription": "Enables the tauri_version command without any pre-configured scope." + }, + { + "description": "Enables the version command without any pre-configured scope.", + "type": "string", + "const": "core:app:allow-version", + "markdownDescription": "Enables the version command without any pre-configured scope." + }, + { + "description": "Denies the app_hide command without any pre-configured scope.", + "type": "string", + "const": "core:app:deny-app-hide", + "markdownDescription": "Denies the app_hide command without any pre-configured scope." + }, + { + "description": "Denies the app_show command without any pre-configured scope.", + "type": "string", + "const": "core:app:deny-app-show", + "markdownDescription": "Denies the app_show command without any pre-configured scope." + }, + { + "description": "Denies the bundle_type command without any pre-configured scope.", + "type": "string", + "const": "core:app:deny-bundle-type", + "markdownDescription": "Denies the bundle_type command without any pre-configured scope." + }, + { + "description": "Denies the default_window_icon command without any pre-configured scope.", + "type": "string", + "const": "core:app:deny-default-window-icon", + "markdownDescription": "Denies the default_window_icon command without any pre-configured scope." + }, + { + "description": "Denies the fetch_data_store_identifiers command without any pre-configured scope.", + "type": "string", + "const": "core:app:deny-fetch-data-store-identifiers", + "markdownDescription": "Denies the fetch_data_store_identifiers command without any pre-configured scope." + }, + { + "description": "Denies the identifier command without any pre-configured scope.", + "type": "string", + "const": "core:app:deny-identifier", + "markdownDescription": "Denies the identifier command without any pre-configured scope." + }, + { + "description": "Denies the name command without any pre-configured scope.", + "type": "string", + "const": "core:app:deny-name", + "markdownDescription": "Denies the name command without any pre-configured scope." + }, + { + "description": "Denies the register_listener command without any pre-configured scope.", + "type": "string", + "const": "core:app:deny-register-listener", + "markdownDescription": "Denies the register_listener command without any pre-configured scope." + }, + { + "description": "Denies the remove_data_store command without any pre-configured scope.", + "type": "string", + "const": "core:app:deny-remove-data-store", + "markdownDescription": "Denies the remove_data_store command without any pre-configured scope." + }, + { + "description": "Denies the remove_listener command without any pre-configured scope.", + "type": "string", + "const": "core:app:deny-remove-listener", + "markdownDescription": "Denies the remove_listener command without any pre-configured scope." + }, + { + "description": "Denies the set_app_theme command without any pre-configured scope.", + "type": "string", + "const": "core:app:deny-set-app-theme", + "markdownDescription": "Denies the set_app_theme command without any pre-configured scope." + }, + { + "description": "Denies the set_dock_visibility command without any pre-configured scope.", + "type": "string", + "const": "core:app:deny-set-dock-visibility", + "markdownDescription": "Denies the set_dock_visibility command without any pre-configured scope." + }, + { + "description": "Denies the tauri_version command without any pre-configured scope.", + "type": "string", + "const": "core:app:deny-tauri-version", + "markdownDescription": "Denies the tauri_version command without any pre-configured scope." + }, + { + "description": "Denies the version command without any pre-configured scope.", + "type": "string", + "const": "core:app:deny-version", + "markdownDescription": "Denies the version command without any pre-configured scope." + }, + { + "description": "Default permissions for the plugin, which enables all commands.\n#### This default permission set includes:\n\n- `allow-listen`\n- `allow-unlisten`\n- `allow-emit`\n- `allow-emit-to`", + "type": "string", + "const": "core:event:default", + "markdownDescription": "Default permissions for the plugin, which enables all commands.\n#### This default permission set includes:\n\n- `allow-listen`\n- `allow-unlisten`\n- `allow-emit`\n- `allow-emit-to`" + }, + { + "description": "Enables the emit command without any pre-configured scope.", + "type": "string", + "const": "core:event:allow-emit", + "markdownDescription": "Enables the emit command without any pre-configured scope." + }, + { + "description": "Enables the emit_to command without any pre-configured scope.", + "type": "string", + "const": "core:event:allow-emit-to", + "markdownDescription": "Enables the emit_to command without any pre-configured scope." + }, + { + "description": "Enables the listen command without any pre-configured scope.", + "type": "string", + "const": "core:event:allow-listen", + "markdownDescription": "Enables the listen command without any pre-configured scope." + }, + { + "description": "Enables the unlisten command without any pre-configured scope.", + "type": "string", + "const": "core:event:allow-unlisten", + "markdownDescription": "Enables the unlisten command without any pre-configured scope." + }, + { + "description": "Denies the emit command without any pre-configured scope.", + "type": "string", + "const": "core:event:deny-emit", + "markdownDescription": "Denies the emit command without any pre-configured scope." + }, + { + "description": "Denies the emit_to command without any pre-configured scope.", + "type": "string", + "const": "core:event:deny-emit-to", + "markdownDescription": "Denies the emit_to command without any pre-configured scope." + }, + { + "description": "Denies the listen command without any pre-configured scope.", + "type": "string", + "const": "core:event:deny-listen", + "markdownDescription": "Denies the listen command without any pre-configured scope." + }, + { + "description": "Denies the unlisten command without any pre-configured scope.", + "type": "string", + "const": "core:event:deny-unlisten", + "markdownDescription": "Denies the unlisten command without any pre-configured scope." + }, + { + "description": "Default permissions for the plugin, which enables all commands.\n#### This default permission set includes:\n\n- `allow-new`\n- `allow-from-bytes`\n- `allow-from-path`\n- `allow-rgba`\n- `allow-size`", + "type": "string", + "const": "core:image:default", + "markdownDescription": "Default permissions for the plugin, which enables all commands.\n#### This default permission set includes:\n\n- `allow-new`\n- `allow-from-bytes`\n- `allow-from-path`\n- `allow-rgba`\n- `allow-size`" + }, + { + "description": "Enables the from_bytes command without any pre-configured scope.", + "type": "string", + "const": "core:image:allow-from-bytes", + "markdownDescription": "Enables the from_bytes command without any pre-configured scope." + }, + { + "description": "Enables the from_path command without any pre-configured scope.", + "type": "string", + "const": "core:image:allow-from-path", + "markdownDescription": "Enables the from_path command without any pre-configured scope." + }, + { + "description": "Enables the new command without any pre-configured scope.", + "type": "string", + "const": "core:image:allow-new", + "markdownDescription": "Enables the new command without any pre-configured scope." + }, + { + "description": "Enables the rgba command without any pre-configured scope.", + "type": "string", + "const": "core:image:allow-rgba", + "markdownDescription": "Enables the rgba command without any pre-configured scope." + }, + { + "description": "Enables the size command without any pre-configured scope.", + "type": "string", + "const": "core:image:allow-size", + "markdownDescription": "Enables the size command without any pre-configured scope." + }, + { + "description": "Denies the from_bytes command without any pre-configured scope.", + "type": "string", + "const": "core:image:deny-from-bytes", + "markdownDescription": "Denies the from_bytes command without any pre-configured scope." + }, + { + "description": "Denies the from_path command without any pre-configured scope.", + "type": "string", + "const": "core:image:deny-from-path", + "markdownDescription": "Denies the from_path command without any pre-configured scope." + }, + { + "description": "Denies the new command without any pre-configured scope.", + "type": "string", + "const": "core:image:deny-new", + "markdownDescription": "Denies the new command without any pre-configured scope." + }, + { + "description": "Denies the rgba command without any pre-configured scope.", + "type": "string", + "const": "core:image:deny-rgba", + "markdownDescription": "Denies the rgba command without any pre-configured scope." + }, + { + "description": "Denies the size command without any pre-configured scope.", + "type": "string", + "const": "core:image:deny-size", + "markdownDescription": "Denies the size command without any pre-configured scope." + }, + { + "description": "Default permissions for the plugin, which enables all commands.\n#### This default permission set includes:\n\n- `allow-new`\n- `allow-append`\n- `allow-prepend`\n- `allow-insert`\n- `allow-remove`\n- `allow-remove-at`\n- `allow-items`\n- `allow-get`\n- `allow-popup`\n- `allow-create-default`\n- `allow-set-as-app-menu`\n- `allow-set-as-window-menu`\n- `allow-text`\n- `allow-set-text`\n- `allow-is-enabled`\n- `allow-set-enabled`\n- `allow-set-accelerator`\n- `allow-set-as-windows-menu-for-nsapp`\n- `allow-set-as-help-menu-for-nsapp`\n- `allow-is-checked`\n- `allow-set-checked`\n- `allow-set-icon`", + "type": "string", + "const": "core:menu:default", + "markdownDescription": "Default permissions for the plugin, which enables all commands.\n#### This default permission set includes:\n\n- `allow-new`\n- `allow-append`\n- `allow-prepend`\n- `allow-insert`\n- `allow-remove`\n- `allow-remove-at`\n- `allow-items`\n- `allow-get`\n- `allow-popup`\n- `allow-create-default`\n- `allow-set-as-app-menu`\n- `allow-set-as-window-menu`\n- `allow-text`\n- `allow-set-text`\n- `allow-is-enabled`\n- `allow-set-enabled`\n- `allow-set-accelerator`\n- `allow-set-as-windows-menu-for-nsapp`\n- `allow-set-as-help-menu-for-nsapp`\n- `allow-is-checked`\n- `allow-set-checked`\n- `allow-set-icon`" + }, + { + "description": "Enables the append command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-append", + "markdownDescription": "Enables the append command without any pre-configured scope." + }, + { + "description": "Enables the create_default command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-create-default", + "markdownDescription": "Enables the create_default command without any pre-configured scope." + }, + { + "description": "Enables the get command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-get", + "markdownDescription": "Enables the get command without any pre-configured scope." + }, + { + "description": "Enables the insert command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-insert", + "markdownDescription": "Enables the insert command without any pre-configured scope." + }, + { + "description": "Enables the is_checked command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-is-checked", + "markdownDescription": "Enables the is_checked command without any pre-configured scope." + }, + { + "description": "Enables the is_enabled command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-is-enabled", + "markdownDescription": "Enables the is_enabled command without any pre-configured scope." + }, + { + "description": "Enables the items command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-items", + "markdownDescription": "Enables the items command without any pre-configured scope." + }, + { + "description": "Enables the new command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-new", + "markdownDescription": "Enables the new command without any pre-configured scope." + }, + { + "description": "Enables the popup command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-popup", + "markdownDescription": "Enables the popup command without any pre-configured scope." + }, + { + "description": "Enables the prepend command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-prepend", + "markdownDescription": "Enables the prepend command without any pre-configured scope." + }, + { + "description": "Enables the remove command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-remove", + "markdownDescription": "Enables the remove command without any pre-configured scope." + }, + { + "description": "Enables the remove_at command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-remove-at", + "markdownDescription": "Enables the remove_at command without any pre-configured scope." + }, + { + "description": "Enables the set_accelerator command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-set-accelerator", + "markdownDescription": "Enables the set_accelerator command without any pre-configured scope." + }, + { + "description": "Enables the set_as_app_menu command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-set-as-app-menu", + "markdownDescription": "Enables the set_as_app_menu command without any pre-configured scope." + }, + { + "description": "Enables the set_as_help_menu_for_nsapp command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-set-as-help-menu-for-nsapp", + "markdownDescription": "Enables the set_as_help_menu_for_nsapp command without any pre-configured scope." + }, + { + "description": "Enables the set_as_window_menu command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-set-as-window-menu", + "markdownDescription": "Enables the set_as_window_menu command without any pre-configured scope." + }, + { + "description": "Enables the set_as_windows_menu_for_nsapp command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-set-as-windows-menu-for-nsapp", + "markdownDescription": "Enables the set_as_windows_menu_for_nsapp command without any pre-configured scope." + }, + { + "description": "Enables the set_checked command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-set-checked", + "markdownDescription": "Enables the set_checked command without any pre-configured scope." + }, + { + "description": "Enables the set_enabled command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-set-enabled", + "markdownDescription": "Enables the set_enabled command without any pre-configured scope." + }, + { + "description": "Enables the set_icon command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-set-icon", + "markdownDescription": "Enables the set_icon command without any pre-configured scope." + }, + { + "description": "Enables the set_text command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-set-text", + "markdownDescription": "Enables the set_text command without any pre-configured scope." + }, + { + "description": "Enables the text command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-text", + "markdownDescription": "Enables the text command without any pre-configured scope." + }, + { + "description": "Denies the append command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-append", + "markdownDescription": "Denies the append command without any pre-configured scope." + }, + { + "description": "Denies the create_default command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-create-default", + "markdownDescription": "Denies the create_default command without any pre-configured scope." + }, + { + "description": "Denies the get command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-get", + "markdownDescription": "Denies the get command without any pre-configured scope." + }, + { + "description": "Denies the insert command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-insert", + "markdownDescription": "Denies the insert command without any pre-configured scope." + }, + { + "description": "Denies the is_checked command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-is-checked", + "markdownDescription": "Denies the is_checked command without any pre-configured scope." + }, + { + "description": "Denies the is_enabled command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-is-enabled", + "markdownDescription": "Denies the is_enabled command without any pre-configured scope." + }, + { + "description": "Denies the items command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-items", + "markdownDescription": "Denies the items command without any pre-configured scope." + }, + { + "description": "Denies the new command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-new", + "markdownDescription": "Denies the new command without any pre-configured scope." + }, + { + "description": "Denies the popup command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-popup", + "markdownDescription": "Denies the popup command without any pre-configured scope." + }, + { + "description": "Denies the prepend command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-prepend", + "markdownDescription": "Denies the prepend command without any pre-configured scope." + }, + { + "description": "Denies the remove command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-remove", + "markdownDescription": "Denies the remove command without any pre-configured scope." + }, + { + "description": "Denies the remove_at command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-remove-at", + "markdownDescription": "Denies the remove_at command without any pre-configured scope." + }, + { + "description": "Denies the set_accelerator command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-set-accelerator", + "markdownDescription": "Denies the set_accelerator command without any pre-configured scope." + }, + { + "description": "Denies the set_as_app_menu command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-set-as-app-menu", + "markdownDescription": "Denies the set_as_app_menu command without any pre-configured scope." + }, + { + "description": "Denies the set_as_help_menu_for_nsapp command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-set-as-help-menu-for-nsapp", + "markdownDescription": "Denies the set_as_help_menu_for_nsapp command without any pre-configured scope." + }, + { + "description": "Denies the set_as_window_menu command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-set-as-window-menu", + "markdownDescription": "Denies the set_as_window_menu command without any pre-configured scope." + }, + { + "description": "Denies the set_as_windows_menu_for_nsapp command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-set-as-windows-menu-for-nsapp", + "markdownDescription": "Denies the set_as_windows_menu_for_nsapp command without any pre-configured scope." + }, + { + "description": "Denies the set_checked command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-set-checked", + "markdownDescription": "Denies the set_checked command without any pre-configured scope." + }, + { + "description": "Denies the set_enabled command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-set-enabled", + "markdownDescription": "Denies the set_enabled command without any pre-configured scope." + }, + { + "description": "Denies the set_icon command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-set-icon", + "markdownDescription": "Denies the set_icon command without any pre-configured scope." + }, + { + "description": "Denies the set_text command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-set-text", + "markdownDescription": "Denies the set_text command without any pre-configured scope." + }, + { + "description": "Denies the text command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-text", + "markdownDescription": "Denies the text command without any pre-configured scope." + }, + { + "description": "Default permissions for the plugin, which enables all commands.\n#### This default permission set includes:\n\n- `allow-resolve-directory`\n- `allow-resolve`\n- `allow-normalize`\n- `allow-join`\n- `allow-dirname`\n- `allow-extname`\n- `allow-basename`\n- `allow-is-absolute`", + "type": "string", + "const": "core:path:default", + "markdownDescription": "Default permissions for the plugin, which enables all commands.\n#### This default permission set includes:\n\n- `allow-resolve-directory`\n- `allow-resolve`\n- `allow-normalize`\n- `allow-join`\n- `allow-dirname`\n- `allow-extname`\n- `allow-basename`\n- `allow-is-absolute`" + }, + { + "description": "Enables the basename command without any pre-configured scope.", + "type": "string", + "const": "core:path:allow-basename", + "markdownDescription": "Enables the basename command without any pre-configured scope." + }, + { + "description": "Enables the dirname command without any pre-configured scope.", + "type": "string", + "const": "core:path:allow-dirname", + "markdownDescription": "Enables the dirname command without any pre-configured scope." + }, + { + "description": "Enables the extname command without any pre-configured scope.", + "type": "string", + "const": "core:path:allow-extname", + "markdownDescription": "Enables the extname command without any pre-configured scope." + }, + { + "description": "Enables the is_absolute command without any pre-configured scope.", + "type": "string", + "const": "core:path:allow-is-absolute", + "markdownDescription": "Enables the is_absolute command without any pre-configured scope." + }, + { + "description": "Enables the join command without any pre-configured scope.", + "type": "string", + "const": "core:path:allow-join", + "markdownDescription": "Enables the join command without any pre-configured scope." + }, + { + "description": "Enables the normalize command without any pre-configured scope.", + "type": "string", + "const": "core:path:allow-normalize", + "markdownDescription": "Enables the normalize command without any pre-configured scope." + }, + { + "description": "Enables the resolve command without any pre-configured scope.", + "type": "string", + "const": "core:path:allow-resolve", + "markdownDescription": "Enables the resolve command without any pre-configured scope." + }, + { + "description": "Enables the resolve_directory command without any pre-configured scope.", + "type": "string", + "const": "core:path:allow-resolve-directory", + "markdownDescription": "Enables the resolve_directory command without any pre-configured scope." + }, + { + "description": "Denies the basename command without any pre-configured scope.", + "type": "string", + "const": "core:path:deny-basename", + "markdownDescription": "Denies the basename command without any pre-configured scope." + }, + { + "description": "Denies the dirname command without any pre-configured scope.", + "type": "string", + "const": "core:path:deny-dirname", + "markdownDescription": "Denies the dirname command without any pre-configured scope." + }, + { + "description": "Denies the extname command without any pre-configured scope.", + "type": "string", + "const": "core:path:deny-extname", + "markdownDescription": "Denies the extname command without any pre-configured scope." + }, + { + "description": "Denies the is_absolute command without any pre-configured scope.", + "type": "string", + "const": "core:path:deny-is-absolute", + "markdownDescription": "Denies the is_absolute command without any pre-configured scope." + }, + { + "description": "Denies the join command without any pre-configured scope.", + "type": "string", + "const": "core:path:deny-join", + "markdownDescription": "Denies the join command without any pre-configured scope." + }, + { + "description": "Denies the normalize command without any pre-configured scope.", + "type": "string", + "const": "core:path:deny-normalize", + "markdownDescription": "Denies the normalize command without any pre-configured scope." + }, + { + "description": "Denies the resolve command without any pre-configured scope.", + "type": "string", + "const": "core:path:deny-resolve", + "markdownDescription": "Denies the resolve command without any pre-configured scope." + }, + { + "description": "Denies the resolve_directory command without any pre-configured scope.", + "type": "string", + "const": "core:path:deny-resolve-directory", + "markdownDescription": "Denies the resolve_directory command without any pre-configured scope." + }, + { + "description": "Default permissions for the plugin, which enables all commands.\n#### This default permission set includes:\n\n- `allow-close`", + "type": "string", + "const": "core:resources:default", + "markdownDescription": "Default permissions for the plugin, which enables all commands.\n#### This default permission set includes:\n\n- `allow-close`" + }, + { + "description": "Enables the close command without any pre-configured scope.", + "type": "string", + "const": "core:resources:allow-close", + "markdownDescription": "Enables the close command without any pre-configured scope." + }, + { + "description": "Denies the close command without any pre-configured scope.", + "type": "string", + "const": "core:resources:deny-close", + "markdownDescription": "Denies the close command without any pre-configured scope." + }, + { + "description": "Default permissions for the plugin, which enables all commands.\n#### This default permission set includes:\n\n- `allow-new`\n- `allow-get-by-id`\n- `allow-remove-by-id`\n- `allow-set-icon`\n- `allow-set-menu`\n- `allow-set-tooltip`\n- `allow-set-title`\n- `allow-set-visible`\n- `allow-set-temp-dir-path`\n- `allow-set-icon-as-template`\n- `allow-set-show-menu-on-left-click`", + "type": "string", + "const": "core:tray:default", + "markdownDescription": "Default permissions for the plugin, which enables all commands.\n#### This default permission set includes:\n\n- `allow-new`\n- `allow-get-by-id`\n- `allow-remove-by-id`\n- `allow-set-icon`\n- `allow-set-menu`\n- `allow-set-tooltip`\n- `allow-set-title`\n- `allow-set-visible`\n- `allow-set-temp-dir-path`\n- `allow-set-icon-as-template`\n- `allow-set-show-menu-on-left-click`" + }, + { + "description": "Enables the get_by_id command without any pre-configured scope.", + "type": "string", + "const": "core:tray:allow-get-by-id", + "markdownDescription": "Enables the get_by_id command without any pre-configured scope." + }, + { + "description": "Enables the new command without any pre-configured scope.", + "type": "string", + "const": "core:tray:allow-new", + "markdownDescription": "Enables the new command without any pre-configured scope." + }, + { + "description": "Enables the remove_by_id command without any pre-configured scope.", + "type": "string", + "const": "core:tray:allow-remove-by-id", + "markdownDescription": "Enables the remove_by_id command without any pre-configured scope." + }, + { + "description": "Enables the set_icon command without any pre-configured scope.", + "type": "string", + "const": "core:tray:allow-set-icon", + "markdownDescription": "Enables the set_icon command without any pre-configured scope." + }, + { + "description": "Enables the set_icon_as_template command without any pre-configured scope.", + "type": "string", + "const": "core:tray:allow-set-icon-as-template", + "markdownDescription": "Enables the set_icon_as_template command without any pre-configured scope." + }, + { + "description": "Enables the set_menu command without any pre-configured scope.", + "type": "string", + "const": "core:tray:allow-set-menu", + "markdownDescription": "Enables the set_menu command without any pre-configured scope." + }, + { + "description": "Enables the set_show_menu_on_left_click command without any pre-configured scope.", + "type": "string", + "const": "core:tray:allow-set-show-menu-on-left-click", + "markdownDescription": "Enables the set_show_menu_on_left_click command without any pre-configured scope." + }, + { + "description": "Enables the set_temp_dir_path command without any pre-configured scope.", + "type": "string", + "const": "core:tray:allow-set-temp-dir-path", + "markdownDescription": "Enables the set_temp_dir_path command without any pre-configured scope." + }, + { + "description": "Enables the set_title command without any pre-configured scope.", + "type": "string", + "const": "core:tray:allow-set-title", + "markdownDescription": "Enables the set_title command without any pre-configured scope." + }, + { + "description": "Enables the set_tooltip command without any pre-configured scope.", + "type": "string", + "const": "core:tray:allow-set-tooltip", + "markdownDescription": "Enables the set_tooltip command without any pre-configured scope." + }, + { + "description": "Enables the set_visible command without any pre-configured scope.", + "type": "string", + "const": "core:tray:allow-set-visible", + "markdownDescription": "Enables the set_visible command without any pre-configured scope." + }, + { + "description": "Denies the get_by_id command without any pre-configured scope.", + "type": "string", + "const": "core:tray:deny-get-by-id", + "markdownDescription": "Denies the get_by_id command without any pre-configured scope." + }, + { + "description": "Denies the new command without any pre-configured scope.", + "type": "string", + "const": "core:tray:deny-new", + "markdownDescription": "Denies the new command without any pre-configured scope." + }, + { + "description": "Denies the remove_by_id command without any pre-configured scope.", + "type": "string", + "const": "core:tray:deny-remove-by-id", + "markdownDescription": "Denies the remove_by_id command without any pre-configured scope." + }, + { + "description": "Denies the set_icon command without any pre-configured scope.", + "type": "string", + "const": "core:tray:deny-set-icon", + "markdownDescription": "Denies the set_icon command without any pre-configured scope." + }, + { + "description": "Denies the set_icon_as_template command without any pre-configured scope.", + "type": "string", + "const": "core:tray:deny-set-icon-as-template", + "markdownDescription": "Denies the set_icon_as_template command without any pre-configured scope." + }, + { + "description": "Denies the set_menu command without any pre-configured scope.", + "type": "string", + "const": "core:tray:deny-set-menu", + "markdownDescription": "Denies the set_menu command without any pre-configured scope." + }, + { + "description": "Denies the set_show_menu_on_left_click command without any pre-configured scope.", + "type": "string", + "const": "core:tray:deny-set-show-menu-on-left-click", + "markdownDescription": "Denies the set_show_menu_on_left_click command without any pre-configured scope." + }, + { + "description": "Denies the set_temp_dir_path command without any pre-configured scope.", + "type": "string", + "const": "core:tray:deny-set-temp-dir-path", + "markdownDescription": "Denies the set_temp_dir_path command without any pre-configured scope." + }, + { + "description": "Denies the set_title command without any pre-configured scope.", + "type": "string", + "const": "core:tray:deny-set-title", + "markdownDescription": "Denies the set_title command without any pre-configured scope." + }, + { + "description": "Denies the set_tooltip command without any pre-configured scope.", + "type": "string", + "const": "core:tray:deny-set-tooltip", + "markdownDescription": "Denies the set_tooltip command without any pre-configured scope." + }, + { + "description": "Denies the set_visible command without any pre-configured scope.", + "type": "string", + "const": "core:tray:deny-set-visible", + "markdownDescription": "Denies the set_visible command without any pre-configured scope." + }, + { + "description": "Default permissions for the plugin.\n#### This default permission set includes:\n\n- `allow-get-all-webviews`\n- `allow-webview-position`\n- `allow-webview-size`\n- `allow-internal-toggle-devtools`", + "type": "string", + "const": "core:webview:default", + "markdownDescription": "Default permissions for the plugin.\n#### This default permission set includes:\n\n- `allow-get-all-webviews`\n- `allow-webview-position`\n- `allow-webview-size`\n- `allow-internal-toggle-devtools`" + }, + { + "description": "Enables the clear_all_browsing_data command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-clear-all-browsing-data", + "markdownDescription": "Enables the clear_all_browsing_data command without any pre-configured scope." + }, + { + "description": "Enables the create_webview command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-create-webview", + "markdownDescription": "Enables the create_webview command without any pre-configured scope." + }, + { + "description": "Enables the create_webview_window command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-create-webview-window", + "markdownDescription": "Enables the create_webview_window command without any pre-configured scope." + }, + { + "description": "Enables the get_all_webviews command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-get-all-webviews", + "markdownDescription": "Enables the get_all_webviews command without any pre-configured scope." + }, + { + "description": "Enables the internal_toggle_devtools command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-internal-toggle-devtools", + "markdownDescription": "Enables the internal_toggle_devtools command without any pre-configured scope." + }, + { + "description": "Enables the print command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-print", + "markdownDescription": "Enables the print command without any pre-configured scope." + }, + { + "description": "Enables the reparent command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-reparent", + "markdownDescription": "Enables the reparent command without any pre-configured scope." + }, + { + "description": "Enables the set_webview_auto_resize command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-set-webview-auto-resize", + "markdownDescription": "Enables the set_webview_auto_resize command without any pre-configured scope." + }, + { + "description": "Enables the set_webview_background_color command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-set-webview-background-color", + "markdownDescription": "Enables the set_webview_background_color command without any pre-configured scope." + }, + { + "description": "Enables the set_webview_focus command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-set-webview-focus", + "markdownDescription": "Enables the set_webview_focus command without any pre-configured scope." + }, + { + "description": "Enables the set_webview_position command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-set-webview-position", + "markdownDescription": "Enables the set_webview_position command without any pre-configured scope." + }, + { + "description": "Enables the set_webview_size command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-set-webview-size", + "markdownDescription": "Enables the set_webview_size command without any pre-configured scope." + }, + { + "description": "Enables the set_webview_zoom command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-set-webview-zoom", + "markdownDescription": "Enables the set_webview_zoom command without any pre-configured scope." + }, + { + "description": "Enables the webview_close command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-webview-close", + "markdownDescription": "Enables the webview_close command without any pre-configured scope." + }, + { + "description": "Enables the webview_hide command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-webview-hide", + "markdownDescription": "Enables the webview_hide command without any pre-configured scope." + }, + { + "description": "Enables the webview_position command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-webview-position", + "markdownDescription": "Enables the webview_position command without any pre-configured scope." + }, + { + "description": "Enables the webview_show command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-webview-show", + "markdownDescription": "Enables the webview_show command without any pre-configured scope." + }, + { + "description": "Enables the webview_size command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-webview-size", + "markdownDescription": "Enables the webview_size command without any pre-configured scope." + }, + { + "description": "Denies the clear_all_browsing_data command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-clear-all-browsing-data", + "markdownDescription": "Denies the clear_all_browsing_data command without any pre-configured scope." + }, + { + "description": "Denies the create_webview command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-create-webview", + "markdownDescription": "Denies the create_webview command without any pre-configured scope." + }, + { + "description": "Denies the create_webview_window command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-create-webview-window", + "markdownDescription": "Denies the create_webview_window command without any pre-configured scope." + }, + { + "description": "Denies the get_all_webviews command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-get-all-webviews", + "markdownDescription": "Denies the get_all_webviews command without any pre-configured scope." + }, + { + "description": "Denies the internal_toggle_devtools command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-internal-toggle-devtools", + "markdownDescription": "Denies the internal_toggle_devtools command without any pre-configured scope." + }, + { + "description": "Denies the print command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-print", + "markdownDescription": "Denies the print command without any pre-configured scope." + }, + { + "description": "Denies the reparent command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-reparent", + "markdownDescription": "Denies the reparent command without any pre-configured scope." + }, + { + "description": "Denies the set_webview_auto_resize command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-set-webview-auto-resize", + "markdownDescription": "Denies the set_webview_auto_resize command without any pre-configured scope." + }, + { + "description": "Denies the set_webview_background_color command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-set-webview-background-color", + "markdownDescription": "Denies the set_webview_background_color command without any pre-configured scope." + }, + { + "description": "Denies the set_webview_focus command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-set-webview-focus", + "markdownDescription": "Denies the set_webview_focus command without any pre-configured scope." + }, + { + "description": "Denies the set_webview_position command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-set-webview-position", + "markdownDescription": "Denies the set_webview_position command without any pre-configured scope." + }, + { + "description": "Denies the set_webview_size command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-set-webview-size", + "markdownDescription": "Denies the set_webview_size command without any pre-configured scope." + }, + { + "description": "Denies the set_webview_zoom command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-set-webview-zoom", + "markdownDescription": "Denies the set_webview_zoom command without any pre-configured scope." + }, + { + "description": "Denies the webview_close command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-webview-close", + "markdownDescription": "Denies the webview_close command without any pre-configured scope." + }, + { + "description": "Denies the webview_hide command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-webview-hide", + "markdownDescription": "Denies the webview_hide command without any pre-configured scope." + }, + { + "description": "Denies the webview_position command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-webview-position", + "markdownDescription": "Denies the webview_position command without any pre-configured scope." + }, + { + "description": "Denies the webview_show command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-webview-show", + "markdownDescription": "Denies the webview_show command without any pre-configured scope." + }, + { + "description": "Denies the webview_size command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-webview-size", + "markdownDescription": "Denies the webview_size command without any pre-configured scope." + }, + { + "description": "Default permissions for the plugin.\n#### This default permission set includes:\n\n- `allow-get-all-windows`\n- `allow-scale-factor`\n- `allow-inner-position`\n- `allow-outer-position`\n- `allow-inner-size`\n- `allow-outer-size`\n- `allow-is-fullscreen`\n- `allow-is-minimized`\n- `allow-is-maximized`\n- `allow-is-focused`\n- `allow-is-decorated`\n- `allow-is-resizable`\n- `allow-is-maximizable`\n- `allow-is-minimizable`\n- `allow-is-closable`\n- `allow-is-visible`\n- `allow-is-enabled`\n- `allow-title`\n- `allow-current-monitor`\n- `allow-primary-monitor`\n- `allow-monitor-from-point`\n- `allow-available-monitors`\n- `allow-cursor-position`\n- `allow-theme`\n- `allow-is-always-on-top`\n- `allow-internal-toggle-maximize`", + "type": "string", + "const": "core:window:default", + "markdownDescription": "Default permissions for the plugin.\n#### This default permission set includes:\n\n- `allow-get-all-windows`\n- `allow-scale-factor`\n- `allow-inner-position`\n- `allow-outer-position`\n- `allow-inner-size`\n- `allow-outer-size`\n- `allow-is-fullscreen`\n- `allow-is-minimized`\n- `allow-is-maximized`\n- `allow-is-focused`\n- `allow-is-decorated`\n- `allow-is-resizable`\n- `allow-is-maximizable`\n- `allow-is-minimizable`\n- `allow-is-closable`\n- `allow-is-visible`\n- `allow-is-enabled`\n- `allow-title`\n- `allow-current-monitor`\n- `allow-primary-monitor`\n- `allow-monitor-from-point`\n- `allow-available-monitors`\n- `allow-cursor-position`\n- `allow-theme`\n- `allow-is-always-on-top`\n- `allow-internal-toggle-maximize`" + }, + { + "description": "Enables the available_monitors command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-available-monitors", + "markdownDescription": "Enables the available_monitors command without any pre-configured scope." + }, + { + "description": "Enables the center command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-center", + "markdownDescription": "Enables the center command without any pre-configured scope." + }, + { + "description": "Enables the close command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-close", + "markdownDescription": "Enables the close command without any pre-configured scope." + }, + { + "description": "Enables the create command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-create", + "markdownDescription": "Enables the create command without any pre-configured scope." + }, + { + "description": "Enables the current_monitor command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-current-monitor", + "markdownDescription": "Enables the current_monitor command without any pre-configured scope." + }, + { + "description": "Enables the cursor_position command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-cursor-position", + "markdownDescription": "Enables the cursor_position command without any pre-configured scope." + }, + { + "description": "Enables the destroy command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-destroy", + "markdownDescription": "Enables the destroy command without any pre-configured scope." + }, + { + "description": "Enables the get_all_windows command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-get-all-windows", + "markdownDescription": "Enables the get_all_windows command without any pre-configured scope." + }, + { + "description": "Enables the hide command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-hide", + "markdownDescription": "Enables the hide command without any pre-configured scope." + }, + { + "description": "Enables the inner_position command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-inner-position", + "markdownDescription": "Enables the inner_position command without any pre-configured scope." + }, + { + "description": "Enables the inner_size command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-inner-size", + "markdownDescription": "Enables the inner_size command without any pre-configured scope." + }, + { + "description": "Enables the internal_toggle_maximize command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-internal-toggle-maximize", + "markdownDescription": "Enables the internal_toggle_maximize command without any pre-configured scope." + }, + { + "description": "Enables the is_always_on_top command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-is-always-on-top", + "markdownDescription": "Enables the is_always_on_top command without any pre-configured scope." + }, + { + "description": "Enables the is_closable command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-is-closable", + "markdownDescription": "Enables the is_closable command without any pre-configured scope." + }, + { + "description": "Enables the is_decorated command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-is-decorated", + "markdownDescription": "Enables the is_decorated command without any pre-configured scope." + }, + { + "description": "Enables the is_enabled command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-is-enabled", + "markdownDescription": "Enables the is_enabled command without any pre-configured scope." + }, + { + "description": "Enables the is_focused command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-is-focused", + "markdownDescription": "Enables the is_focused command without any pre-configured scope." + }, + { + "description": "Enables the is_fullscreen command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-is-fullscreen", + "markdownDescription": "Enables the is_fullscreen command without any pre-configured scope." + }, + { + "description": "Enables the is_maximizable command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-is-maximizable", + "markdownDescription": "Enables the is_maximizable command without any pre-configured scope." + }, + { + "description": "Enables the is_maximized command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-is-maximized", + "markdownDescription": "Enables the is_maximized command without any pre-configured scope." + }, + { + "description": "Enables the is_minimizable command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-is-minimizable", + "markdownDescription": "Enables the is_minimizable command without any pre-configured scope." + }, + { + "description": "Enables the is_minimized command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-is-minimized", + "markdownDescription": "Enables the is_minimized command without any pre-configured scope." + }, + { + "description": "Enables the is_resizable command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-is-resizable", + "markdownDescription": "Enables the is_resizable command without any pre-configured scope." + }, + { + "description": "Enables the is_visible command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-is-visible", + "markdownDescription": "Enables the is_visible command without any pre-configured scope." + }, + { + "description": "Enables the maximize command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-maximize", + "markdownDescription": "Enables the maximize command without any pre-configured scope." + }, + { + "description": "Enables the minimize command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-minimize", + "markdownDescription": "Enables the minimize command without any pre-configured scope." + }, + { + "description": "Enables the monitor_from_point command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-monitor-from-point", + "markdownDescription": "Enables the monitor_from_point command without any pre-configured scope." + }, + { + "description": "Enables the outer_position command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-outer-position", + "markdownDescription": "Enables the outer_position command without any pre-configured scope." + }, + { + "description": "Enables the outer_size command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-outer-size", + "markdownDescription": "Enables the outer_size command without any pre-configured scope." + }, + { + "description": "Enables the primary_monitor command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-primary-monitor", + "markdownDescription": "Enables the primary_monitor command without any pre-configured scope." + }, + { + "description": "Enables the request_user_attention command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-request-user-attention", + "markdownDescription": "Enables the request_user_attention command without any pre-configured scope." + }, + { + "description": "Enables the scale_factor command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-scale-factor", + "markdownDescription": "Enables the scale_factor command without any pre-configured scope." + }, + { + "description": "Enables the set_always_on_bottom command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-always-on-bottom", + "markdownDescription": "Enables the set_always_on_bottom command without any pre-configured scope." + }, + { + "description": "Enables the set_always_on_top command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-always-on-top", + "markdownDescription": "Enables the set_always_on_top command without any pre-configured scope." + }, + { + "description": "Enables the set_background_color command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-background-color", + "markdownDescription": "Enables the set_background_color command without any pre-configured scope." + }, + { + "description": "Enables the set_badge_count command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-badge-count", + "markdownDescription": "Enables the set_badge_count command without any pre-configured scope." + }, + { + "description": "Enables the set_badge_label command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-badge-label", + "markdownDescription": "Enables the set_badge_label command without any pre-configured scope." + }, + { + "description": "Enables the set_closable command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-closable", + "markdownDescription": "Enables the set_closable command without any pre-configured scope." + }, + { + "description": "Enables the set_content_protected command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-content-protected", + "markdownDescription": "Enables the set_content_protected command without any pre-configured scope." + }, + { + "description": "Enables the set_cursor_grab command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-cursor-grab", + "markdownDescription": "Enables the set_cursor_grab command without any pre-configured scope." + }, + { + "description": "Enables the set_cursor_icon command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-cursor-icon", + "markdownDescription": "Enables the set_cursor_icon command without any pre-configured scope." + }, + { + "description": "Enables the set_cursor_position command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-cursor-position", + "markdownDescription": "Enables the set_cursor_position command without any pre-configured scope." + }, + { + "description": "Enables the set_cursor_visible command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-cursor-visible", + "markdownDescription": "Enables the set_cursor_visible command without any pre-configured scope." + }, + { + "description": "Enables the set_decorations command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-decorations", + "markdownDescription": "Enables the set_decorations command without any pre-configured scope." + }, + { + "description": "Enables the set_effects command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-effects", + "markdownDescription": "Enables the set_effects command without any pre-configured scope." + }, + { + "description": "Enables the set_enabled command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-enabled", + "markdownDescription": "Enables the set_enabled command without any pre-configured scope." + }, + { + "description": "Enables the set_focus command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-focus", + "markdownDescription": "Enables the set_focus command without any pre-configured scope." + }, + { + "description": "Enables the set_focusable command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-focusable", + "markdownDescription": "Enables the set_focusable command without any pre-configured scope." + }, + { + "description": "Enables the set_fullscreen command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-fullscreen", + "markdownDescription": "Enables the set_fullscreen command without any pre-configured scope." + }, + { + "description": "Enables the set_icon command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-icon", + "markdownDescription": "Enables the set_icon command without any pre-configured scope." + }, + { + "description": "Enables the set_ignore_cursor_events command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-ignore-cursor-events", + "markdownDescription": "Enables the set_ignore_cursor_events command without any pre-configured scope." + }, + { + "description": "Enables the set_max_size command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-max-size", + "markdownDescription": "Enables the set_max_size command without any pre-configured scope." + }, + { + "description": "Enables the set_maximizable command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-maximizable", + "markdownDescription": "Enables the set_maximizable command without any pre-configured scope." + }, + { + "description": "Enables the set_min_size command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-min-size", + "markdownDescription": "Enables the set_min_size command without any pre-configured scope." + }, + { + "description": "Enables the set_minimizable command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-minimizable", + "markdownDescription": "Enables the set_minimizable command without any pre-configured scope." + }, + { + "description": "Enables the set_overlay_icon command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-overlay-icon", + "markdownDescription": "Enables the set_overlay_icon command without any pre-configured scope." + }, + { + "description": "Enables the set_position command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-position", + "markdownDescription": "Enables the set_position command without any pre-configured scope." + }, + { + "description": "Enables the set_progress_bar command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-progress-bar", + "markdownDescription": "Enables the set_progress_bar command without any pre-configured scope." + }, + { + "description": "Enables the set_resizable command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-resizable", + "markdownDescription": "Enables the set_resizable command without any pre-configured scope." + }, + { + "description": "Enables the set_shadow command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-shadow", + "markdownDescription": "Enables the set_shadow command without any pre-configured scope." + }, + { + "description": "Enables the set_simple_fullscreen command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-simple-fullscreen", + "markdownDescription": "Enables the set_simple_fullscreen command without any pre-configured scope." + }, + { + "description": "Enables the set_size command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-size", + "markdownDescription": "Enables the set_size command without any pre-configured scope." + }, + { + "description": "Enables the set_size_constraints command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-size-constraints", + "markdownDescription": "Enables the set_size_constraints command without any pre-configured scope." + }, + { + "description": "Enables the set_skip_taskbar command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-skip-taskbar", + "markdownDescription": "Enables the set_skip_taskbar command without any pre-configured scope." + }, + { + "description": "Enables the set_theme command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-theme", + "markdownDescription": "Enables the set_theme command without any pre-configured scope." + }, + { + "description": "Enables the set_title command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-title", + "markdownDescription": "Enables the set_title command without any pre-configured scope." + }, + { + "description": "Enables the set_title_bar_style command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-title-bar-style", + "markdownDescription": "Enables the set_title_bar_style command without any pre-configured scope." + }, + { + "description": "Enables the set_visible_on_all_workspaces command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-visible-on-all-workspaces", + "markdownDescription": "Enables the set_visible_on_all_workspaces command without any pre-configured scope." + }, + { + "description": "Enables the show command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-show", + "markdownDescription": "Enables the show command without any pre-configured scope." + }, + { + "description": "Enables the start_dragging command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-start-dragging", + "markdownDescription": "Enables the start_dragging command without any pre-configured scope." + }, + { + "description": "Enables the start_resize_dragging command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-start-resize-dragging", + "markdownDescription": "Enables the start_resize_dragging command without any pre-configured scope." + }, + { + "description": "Enables the theme command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-theme", + "markdownDescription": "Enables the theme command without any pre-configured scope." + }, + { + "description": "Enables the title command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-title", + "markdownDescription": "Enables the title command without any pre-configured scope." + }, + { + "description": "Enables the toggle_maximize command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-toggle-maximize", + "markdownDescription": "Enables the toggle_maximize command without any pre-configured scope." + }, + { + "description": "Enables the unmaximize command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-unmaximize", + "markdownDescription": "Enables the unmaximize command without any pre-configured scope." + }, + { + "description": "Enables the unminimize command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-unminimize", + "markdownDescription": "Enables the unminimize command without any pre-configured scope." + }, + { + "description": "Denies the available_monitors command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-available-monitors", + "markdownDescription": "Denies the available_monitors command without any pre-configured scope." + }, + { + "description": "Denies the center command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-center", + "markdownDescription": "Denies the center command without any pre-configured scope." + }, + { + "description": "Denies the close command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-close", + "markdownDescription": "Denies the close command without any pre-configured scope." + }, + { + "description": "Denies the create command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-create", + "markdownDescription": "Denies the create command without any pre-configured scope." + }, + { + "description": "Denies the current_monitor command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-current-monitor", + "markdownDescription": "Denies the current_monitor command without any pre-configured scope." + }, + { + "description": "Denies the cursor_position command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-cursor-position", + "markdownDescription": "Denies the cursor_position command without any pre-configured scope." + }, + { + "description": "Denies the destroy command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-destroy", + "markdownDescription": "Denies the destroy command without any pre-configured scope." + }, + { + "description": "Denies the get_all_windows command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-get-all-windows", + "markdownDescription": "Denies the get_all_windows command without any pre-configured scope." + }, + { + "description": "Denies the hide command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-hide", + "markdownDescription": "Denies the hide command without any pre-configured scope." + }, + { + "description": "Denies the inner_position command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-inner-position", + "markdownDescription": "Denies the inner_position command without any pre-configured scope." + }, + { + "description": "Denies the inner_size command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-inner-size", + "markdownDescription": "Denies the inner_size command without any pre-configured scope." + }, + { + "description": "Denies the internal_toggle_maximize command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-internal-toggle-maximize", + "markdownDescription": "Denies the internal_toggle_maximize command without any pre-configured scope." + }, + { + "description": "Denies the is_always_on_top command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-is-always-on-top", + "markdownDescription": "Denies the is_always_on_top command without any pre-configured scope." + }, + { + "description": "Denies the is_closable command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-is-closable", + "markdownDescription": "Denies the is_closable command without any pre-configured scope." + }, + { + "description": "Denies the is_decorated command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-is-decorated", + "markdownDescription": "Denies the is_decorated command without any pre-configured scope." + }, + { + "description": "Denies the is_enabled command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-is-enabled", + "markdownDescription": "Denies the is_enabled command without any pre-configured scope." + }, + { + "description": "Denies the is_focused command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-is-focused", + "markdownDescription": "Denies the is_focused command without any pre-configured scope." + }, + { + "description": "Denies the is_fullscreen command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-is-fullscreen", + "markdownDescription": "Denies the is_fullscreen command without any pre-configured scope." + }, + { + "description": "Denies the is_maximizable command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-is-maximizable", + "markdownDescription": "Denies the is_maximizable command without any pre-configured scope." + }, + { + "description": "Denies the is_maximized command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-is-maximized", + "markdownDescription": "Denies the is_maximized command without any pre-configured scope." + }, + { + "description": "Denies the is_minimizable command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-is-minimizable", + "markdownDescription": "Denies the is_minimizable command without any pre-configured scope." + }, + { + "description": "Denies the is_minimized command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-is-minimized", + "markdownDescription": "Denies the is_minimized command without any pre-configured scope." + }, + { + "description": "Denies the is_resizable command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-is-resizable", + "markdownDescription": "Denies the is_resizable command without any pre-configured scope." + }, + { + "description": "Denies the is_visible command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-is-visible", + "markdownDescription": "Denies the is_visible command without any pre-configured scope." + }, + { + "description": "Denies the maximize command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-maximize", + "markdownDescription": "Denies the maximize command without any pre-configured scope." + }, + { + "description": "Denies the minimize command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-minimize", + "markdownDescription": "Denies the minimize command without any pre-configured scope." + }, + { + "description": "Denies the monitor_from_point command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-monitor-from-point", + "markdownDescription": "Denies the monitor_from_point command without any pre-configured scope." + }, + { + "description": "Denies the outer_position command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-outer-position", + "markdownDescription": "Denies the outer_position command without any pre-configured scope." + }, + { + "description": "Denies the outer_size command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-outer-size", + "markdownDescription": "Denies the outer_size command without any pre-configured scope." + }, + { + "description": "Denies the primary_monitor command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-primary-monitor", + "markdownDescription": "Denies the primary_monitor command without any pre-configured scope." + }, + { + "description": "Denies the request_user_attention command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-request-user-attention", + "markdownDescription": "Denies the request_user_attention command without any pre-configured scope." + }, + { + "description": "Denies the scale_factor command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-scale-factor", + "markdownDescription": "Denies the scale_factor command without any pre-configured scope." + }, + { + "description": "Denies the set_always_on_bottom command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-always-on-bottom", + "markdownDescription": "Denies the set_always_on_bottom command without any pre-configured scope." + }, + { + "description": "Denies the set_always_on_top command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-always-on-top", + "markdownDescription": "Denies the set_always_on_top command without any pre-configured scope." + }, + { + "description": "Denies the set_background_color command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-background-color", + "markdownDescription": "Denies the set_background_color command without any pre-configured scope." + }, + { + "description": "Denies the set_badge_count command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-badge-count", + "markdownDescription": "Denies the set_badge_count command without any pre-configured scope." + }, + { + "description": "Denies the set_badge_label command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-badge-label", + "markdownDescription": "Denies the set_badge_label command without any pre-configured scope." + }, + { + "description": "Denies the set_closable command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-closable", + "markdownDescription": "Denies the set_closable command without any pre-configured scope." + }, + { + "description": "Denies the set_content_protected command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-content-protected", + "markdownDescription": "Denies the set_content_protected command without any pre-configured scope." + }, + { + "description": "Denies the set_cursor_grab command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-cursor-grab", + "markdownDescription": "Denies the set_cursor_grab command without any pre-configured scope." + }, + { + "description": "Denies the set_cursor_icon command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-cursor-icon", + "markdownDescription": "Denies the set_cursor_icon command without any pre-configured scope." + }, + { + "description": "Denies the set_cursor_position command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-cursor-position", + "markdownDescription": "Denies the set_cursor_position command without any pre-configured scope." + }, + { + "description": "Denies the set_cursor_visible command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-cursor-visible", + "markdownDescription": "Denies the set_cursor_visible command without any pre-configured scope." + }, + { + "description": "Denies the set_decorations command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-decorations", + "markdownDescription": "Denies the set_decorations command without any pre-configured scope." + }, + { + "description": "Denies the set_effects command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-effects", + "markdownDescription": "Denies the set_effects command without any pre-configured scope." + }, + { + "description": "Denies the set_enabled command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-enabled", + "markdownDescription": "Denies the set_enabled command without any pre-configured scope." + }, + { + "description": "Denies the set_focus command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-focus", + "markdownDescription": "Denies the set_focus command without any pre-configured scope." + }, + { + "description": "Denies the set_focusable command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-focusable", + "markdownDescription": "Denies the set_focusable command without any pre-configured scope." + }, + { + "description": "Denies the set_fullscreen command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-fullscreen", + "markdownDescription": "Denies the set_fullscreen command without any pre-configured scope." + }, + { + "description": "Denies the set_icon command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-icon", + "markdownDescription": "Denies the set_icon command without any pre-configured scope." + }, + { + "description": "Denies the set_ignore_cursor_events command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-ignore-cursor-events", + "markdownDescription": "Denies the set_ignore_cursor_events command without any pre-configured scope." + }, + { + "description": "Denies the set_max_size command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-max-size", + "markdownDescription": "Denies the set_max_size command without any pre-configured scope." + }, + { + "description": "Denies the set_maximizable command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-maximizable", + "markdownDescription": "Denies the set_maximizable command without any pre-configured scope." + }, + { + "description": "Denies the set_min_size command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-min-size", + "markdownDescription": "Denies the set_min_size command without any pre-configured scope." + }, + { + "description": "Denies the set_minimizable command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-minimizable", + "markdownDescription": "Denies the set_minimizable command without any pre-configured scope." + }, + { + "description": "Denies the set_overlay_icon command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-overlay-icon", + "markdownDescription": "Denies the set_overlay_icon command without any pre-configured scope." + }, + { + "description": "Denies the set_position command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-position", + "markdownDescription": "Denies the set_position command without any pre-configured scope." + }, + { + "description": "Denies the set_progress_bar command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-progress-bar", + "markdownDescription": "Denies the set_progress_bar command without any pre-configured scope." + }, + { + "description": "Denies the set_resizable command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-resizable", + "markdownDescription": "Denies the set_resizable command without any pre-configured scope." + }, + { + "description": "Denies the set_shadow command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-shadow", + "markdownDescription": "Denies the set_shadow command without any pre-configured scope." + }, + { + "description": "Denies the set_simple_fullscreen command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-simple-fullscreen", + "markdownDescription": "Denies the set_simple_fullscreen command without any pre-configured scope." + }, + { + "description": "Denies the set_size command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-size", + "markdownDescription": "Denies the set_size command without any pre-configured scope." + }, + { + "description": "Denies the set_size_constraints command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-size-constraints", + "markdownDescription": "Denies the set_size_constraints command without any pre-configured scope." + }, + { + "description": "Denies the set_skip_taskbar command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-skip-taskbar", + "markdownDescription": "Denies the set_skip_taskbar command without any pre-configured scope." + }, + { + "description": "Denies the set_theme command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-theme", + "markdownDescription": "Denies the set_theme command without any pre-configured scope." + }, + { + "description": "Denies the set_title command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-title", + "markdownDescription": "Denies the set_title command without any pre-configured scope." + }, + { + "description": "Denies the set_title_bar_style command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-title-bar-style", + "markdownDescription": "Denies the set_title_bar_style command without any pre-configured scope." + }, + { + "description": "Denies the set_visible_on_all_workspaces command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-visible-on-all-workspaces", + "markdownDescription": "Denies the set_visible_on_all_workspaces command without any pre-configured scope." + }, + { + "description": "Denies the show command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-show", + "markdownDescription": "Denies the show command without any pre-configured scope." + }, + { + "description": "Denies the start_dragging command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-start-dragging", + "markdownDescription": "Denies the start_dragging command without any pre-configured scope." + }, + { + "description": "Denies the start_resize_dragging command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-start-resize-dragging", + "markdownDescription": "Denies the start_resize_dragging command without any pre-configured scope." + }, + { + "description": "Denies the theme command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-theme", + "markdownDescription": "Denies the theme command without any pre-configured scope." + }, + { + "description": "Denies the title command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-title", + "markdownDescription": "Denies the title command without any pre-configured scope." + }, + { + "description": "Denies the toggle_maximize command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-toggle-maximize", + "markdownDescription": "Denies the toggle_maximize command without any pre-configured scope." + }, + { + "description": "Denies the unmaximize command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-unmaximize", + "markdownDescription": "Denies the unmaximize command without any pre-configured scope." + }, + { + "description": "Denies the unminimize command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-unminimize", + "markdownDescription": "Denies the unminimize command without any pre-configured scope." + } + ] + }, + "Value": { + "description": "All supported ACL values.", + "anyOf": [ + { + "description": "Represents a null JSON value.", + "type": "null" + }, + { + "description": "Represents a [`bool`].", + "type": "boolean" + }, + { + "description": "Represents a valid ACL [`Number`].", + "allOf": [ + { + "$ref": "#/definitions/Number" + } + ] + }, + { + "description": "Represents a [`String`].", + "type": "string" + }, + { + "description": "Represents a list of other [`Value`]s.", + "type": "array", + "items": { + "$ref": "#/definitions/Value" + } + }, + { + "description": "Represents a map of [`String`] keys to [`Value`]s.", + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/Value" + } + } + ] + }, + "Number": { + "description": "A valid ACL number.", + "anyOf": [ + { + "description": "Represents an [`i64`].", + "type": "integer", + "format": "int64" + }, + { + "description": "Represents a [`f64`].", + "type": "number", + "format": "double" + } + ] + }, + "Target": { + "description": "Platform target.", + "oneOf": [ + { + "description": "MacOS.", + "type": "string", + "enum": ["macOS"] + }, + { + "description": "Windows.", + "type": "string", + "enum": ["windows"] + }, + { + "description": "Linux.", + "type": "string", + "enum": ["linux"] + }, + { + "description": "Android.", + "type": "string", + "enum": ["android"] + }, + { + "description": "iOS.", + "type": "string", + "enum": ["iOS"] + } + ] + } + } +} diff --git a/foundry/packages/desktop/src-tauri/gen/schemas/mobile-schema.json b/foundry/packages/desktop/src-tauri/gen/schemas/mobile-schema.json new file mode 100644 index 0000000..39c4610 --- /dev/null +++ b/foundry/packages/desktop/src-tauri/gen/schemas/mobile-schema.json @@ -0,0 +1,2216 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "CapabilityFile", + "description": "Capability formats accepted in a capability file.", + "anyOf": [ + { + "description": "A single capability.", + "allOf": [ + { + "$ref": "#/definitions/Capability" + } + ] + }, + { + "description": "A list of capabilities.", + "type": "array", + "items": { + "$ref": "#/definitions/Capability" + } + }, + { + "description": "A list of capabilities.", + "type": "object", + "required": ["capabilities"], + "properties": { + "capabilities": { + "description": "The list of capabilities.", + "type": "array", + "items": { + "$ref": "#/definitions/Capability" + } + } + } + } + ], + "definitions": { + "Capability": { + "description": "A grouping and boundary mechanism developers can use to isolate access to the IPC layer.\n\nIt controls application windows' and webviews' fine grained access to the Tauri core, application, or plugin commands. If a webview or its window is not matching any capability then it has no access to the IPC layer at all.\n\nThis can be done to create groups of windows, based on their required system access, which can reduce impact of frontend vulnerabilities in less privileged windows. Windows can be added to a capability by exact name (e.g. `main-window`) or glob patterns like `*` or `admin-*`. A Window can have none, one, or multiple associated capabilities.\n\n## Example\n\n```json { \"identifier\": \"main-user-files-write\", \"description\": \"This capability allows the `main` window on macOS and Windows access to `filesystem` write related commands and `dialog` commands to enable programmatic access to files selected by the user.\", \"windows\": [ \"main\" ], \"permissions\": [ \"core:default\", \"dialog:open\", { \"identifier\": \"fs:allow-write-text-file\", \"allow\": [{ \"path\": \"$HOME/test.txt\" }] }, ], \"platforms\": [\"macOS\",\"windows\"] } ```", + "type": "object", + "required": ["identifier", "permissions"], + "properties": { + "identifier": { + "description": "Identifier of the capability.\n\n## Example\n\n`main-user-files-write`", + "type": "string" + }, + "description": { + "description": "Description of what the capability is intended to allow on associated windows.\n\nIt should contain a description of what the grouped permissions should allow.\n\n## Example\n\nThis capability allows the `main` window access to `filesystem` write related commands and `dialog` commands to enable programmatic access to files selected by the user.", + "default": "", + "type": "string" + }, + "remote": { + "description": "Configure remote URLs that can use the capability permissions.\n\nThis setting is optional and defaults to not being set, as our default use case is that the content is served from our local application.\n\n:::caution Make sure you understand the security implications of providing remote sources with local system access. :::\n\n## Example\n\n```json { \"urls\": [\"https://*.mydomain.dev\"] } ```", + "anyOf": [ + { + "$ref": "#/definitions/CapabilityRemote" + }, + { + "type": "null" + } + ] + }, + "local": { + "description": "Whether this capability is enabled for local app URLs or not. Defaults to `true`.", + "default": true, + "type": "boolean" + }, + "windows": { + "description": "List of windows that are affected by this capability. Can be a glob pattern.\n\nIf a window label matches any of the patterns in this list, the capability will be enabled on all the webviews of that window, regardless of the value of [`Self::webviews`].\n\nOn multiwebview windows, prefer specifying [`Self::webviews`] and omitting [`Self::windows`] for a fine grained access control.\n\n## Example\n\n`[\"main\"]`", + "type": "array", + "items": { + "type": "string" + } + }, + "webviews": { + "description": "List of webviews that are affected by this capability. Can be a glob pattern.\n\nThe capability will be enabled on all the webviews whose label matches any of the patterns in this list, regardless of whether the webview's window label matches a pattern in [`Self::windows`].\n\n## Example\n\n`[\"sub-webview-one\", \"sub-webview-two\"]`", + "type": "array", + "items": { + "type": "string" + } + }, + "permissions": { + "description": "List of permissions attached to this capability.\n\nMust include the plugin name as prefix in the form of `${plugin-name}:${permission-name}`. For commands directly implemented in the application itself only `${permission-name}` is required.\n\n## Example\n\n```json [ \"core:default\", \"shell:allow-open\", \"dialog:open\", { \"identifier\": \"fs:allow-write-text-file\", \"allow\": [{ \"path\": \"$HOME/test.txt\" }] } ] ```", + "type": "array", + "items": { + "$ref": "#/definitions/PermissionEntry" + }, + "uniqueItems": true + }, + "platforms": { + "description": "Limit which target platforms this capability applies to.\n\nBy default all platforms are targeted.\n\n## Example\n\n`[\"macOS\",\"windows\"]`", + "type": ["array", "null"], + "items": { + "$ref": "#/definitions/Target" + } + } + } + }, + "CapabilityRemote": { + "description": "Configuration for remote URLs that are associated with the capability.", + "type": "object", + "required": ["urls"], + "properties": { + "urls": { + "description": "Remote domains this capability refers to using the [URLPattern standard](https://urlpattern.spec.whatwg.org/).\n\n## Examples\n\n- \"https://*.mydomain.dev\": allows subdomains of mydomain.dev - \"https://mydomain.dev/api/*\": allows any subpath of mydomain.dev/api", + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "PermissionEntry": { + "description": "An entry for a permission value in a [`Capability`] can be either a raw permission [`Identifier`] or an object that references a permission and extends its scope.", + "anyOf": [ + { + "description": "Reference a permission or permission set by identifier.", + "allOf": [ + { + "$ref": "#/definitions/Identifier" + } + ] + }, + { + "description": "Reference a permission or permission set by identifier and extends its scope.", + "type": "object", + "allOf": [ + { + "properties": { + "identifier": { + "description": "Identifier of the permission or permission set.", + "allOf": [ + { + "$ref": "#/definitions/Identifier" + } + ] + }, + "allow": { + "description": "Data that defines what is allowed by the scope.", + "type": ["array", "null"], + "items": { + "$ref": "#/definitions/Value" + } + }, + "deny": { + "description": "Data that defines what is denied by the scope. This should be prioritized by validation logic.", + "type": ["array", "null"], + "items": { + "$ref": "#/definitions/Value" + } + } + } + } + ], + "required": ["identifier"] + } + ] + }, + "Identifier": { + "description": "Permission identifier", + "oneOf": [ + { + "description": "Default core plugins set.\n#### This default permission set includes:\n\n- `core:path:default`\n- `core:event:default`\n- `core:window:default`\n- `core:webview:default`\n- `core:app:default`\n- `core:image:default`\n- `core:resources:default`\n- `core:menu:default`\n- `core:tray:default`", + "type": "string", + "const": "core:default", + "markdownDescription": "Default core plugins set.\n#### This default permission set includes:\n\n- `core:path:default`\n- `core:event:default`\n- `core:window:default`\n- `core:webview:default`\n- `core:app:default`\n- `core:image:default`\n- `core:resources:default`\n- `core:menu:default`\n- `core:tray:default`" + }, + { + "description": "Default permissions for the plugin.\n#### This default permission set includes:\n\n- `allow-version`\n- `allow-name`\n- `allow-tauri-version`\n- `allow-identifier`\n- `allow-bundle-type`\n- `allow-register-listener`\n- `allow-remove-listener`", + "type": "string", + "const": "core:app:default", + "markdownDescription": "Default permissions for the plugin.\n#### This default permission set includes:\n\n- `allow-version`\n- `allow-name`\n- `allow-tauri-version`\n- `allow-identifier`\n- `allow-bundle-type`\n- `allow-register-listener`\n- `allow-remove-listener`" + }, + { + "description": "Enables the app_hide command without any pre-configured scope.", + "type": "string", + "const": "core:app:allow-app-hide", + "markdownDescription": "Enables the app_hide command without any pre-configured scope." + }, + { + "description": "Enables the app_show command without any pre-configured scope.", + "type": "string", + "const": "core:app:allow-app-show", + "markdownDescription": "Enables the app_show command without any pre-configured scope." + }, + { + "description": "Enables the bundle_type command without any pre-configured scope.", + "type": "string", + "const": "core:app:allow-bundle-type", + "markdownDescription": "Enables the bundle_type command without any pre-configured scope." + }, + { + "description": "Enables the default_window_icon command without any pre-configured scope.", + "type": "string", + "const": "core:app:allow-default-window-icon", + "markdownDescription": "Enables the default_window_icon command without any pre-configured scope." + }, + { + "description": "Enables the fetch_data_store_identifiers command without any pre-configured scope.", + "type": "string", + "const": "core:app:allow-fetch-data-store-identifiers", + "markdownDescription": "Enables the fetch_data_store_identifiers command without any pre-configured scope." + }, + { + "description": "Enables the identifier command without any pre-configured scope.", + "type": "string", + "const": "core:app:allow-identifier", + "markdownDescription": "Enables the identifier command without any pre-configured scope." + }, + { + "description": "Enables the name command without any pre-configured scope.", + "type": "string", + "const": "core:app:allow-name", + "markdownDescription": "Enables the name command without any pre-configured scope." + }, + { + "description": "Enables the register_listener command without any pre-configured scope.", + "type": "string", + "const": "core:app:allow-register-listener", + "markdownDescription": "Enables the register_listener command without any pre-configured scope." + }, + { + "description": "Enables the remove_data_store command without any pre-configured scope.", + "type": "string", + "const": "core:app:allow-remove-data-store", + "markdownDescription": "Enables the remove_data_store command without any pre-configured scope." + }, + { + "description": "Enables the remove_listener command without any pre-configured scope.", + "type": "string", + "const": "core:app:allow-remove-listener", + "markdownDescription": "Enables the remove_listener command without any pre-configured scope." + }, + { + "description": "Enables the set_app_theme command without any pre-configured scope.", + "type": "string", + "const": "core:app:allow-set-app-theme", + "markdownDescription": "Enables the set_app_theme command without any pre-configured scope." + }, + { + "description": "Enables the set_dock_visibility command without any pre-configured scope.", + "type": "string", + "const": "core:app:allow-set-dock-visibility", + "markdownDescription": "Enables the set_dock_visibility command without any pre-configured scope." + }, + { + "description": "Enables the tauri_version command without any pre-configured scope.", + "type": "string", + "const": "core:app:allow-tauri-version", + "markdownDescription": "Enables the tauri_version command without any pre-configured scope." + }, + { + "description": "Enables the version command without any pre-configured scope.", + "type": "string", + "const": "core:app:allow-version", + "markdownDescription": "Enables the version command without any pre-configured scope." + }, + { + "description": "Denies the app_hide command without any pre-configured scope.", + "type": "string", + "const": "core:app:deny-app-hide", + "markdownDescription": "Denies the app_hide command without any pre-configured scope." + }, + { + "description": "Denies the app_show command without any pre-configured scope.", + "type": "string", + "const": "core:app:deny-app-show", + "markdownDescription": "Denies the app_show command without any pre-configured scope." + }, + { + "description": "Denies the bundle_type command without any pre-configured scope.", + "type": "string", + "const": "core:app:deny-bundle-type", + "markdownDescription": "Denies the bundle_type command without any pre-configured scope." + }, + { + "description": "Denies the default_window_icon command without any pre-configured scope.", + "type": "string", + "const": "core:app:deny-default-window-icon", + "markdownDescription": "Denies the default_window_icon command without any pre-configured scope." + }, + { + "description": "Denies the fetch_data_store_identifiers command without any pre-configured scope.", + "type": "string", + "const": "core:app:deny-fetch-data-store-identifiers", + "markdownDescription": "Denies the fetch_data_store_identifiers command without any pre-configured scope." + }, + { + "description": "Denies the identifier command without any pre-configured scope.", + "type": "string", + "const": "core:app:deny-identifier", + "markdownDescription": "Denies the identifier command without any pre-configured scope." + }, + { + "description": "Denies the name command without any pre-configured scope.", + "type": "string", + "const": "core:app:deny-name", + "markdownDescription": "Denies the name command without any pre-configured scope." + }, + { + "description": "Denies the register_listener command without any pre-configured scope.", + "type": "string", + "const": "core:app:deny-register-listener", + "markdownDescription": "Denies the register_listener command without any pre-configured scope." + }, + { + "description": "Denies the remove_data_store command without any pre-configured scope.", + "type": "string", + "const": "core:app:deny-remove-data-store", + "markdownDescription": "Denies the remove_data_store command without any pre-configured scope." + }, + { + "description": "Denies the remove_listener command without any pre-configured scope.", + "type": "string", + "const": "core:app:deny-remove-listener", + "markdownDescription": "Denies the remove_listener command without any pre-configured scope." + }, + { + "description": "Denies the set_app_theme command without any pre-configured scope.", + "type": "string", + "const": "core:app:deny-set-app-theme", + "markdownDescription": "Denies the set_app_theme command without any pre-configured scope." + }, + { + "description": "Denies the set_dock_visibility command without any pre-configured scope.", + "type": "string", + "const": "core:app:deny-set-dock-visibility", + "markdownDescription": "Denies the set_dock_visibility command without any pre-configured scope." + }, + { + "description": "Denies the tauri_version command without any pre-configured scope.", + "type": "string", + "const": "core:app:deny-tauri-version", + "markdownDescription": "Denies the tauri_version command without any pre-configured scope." + }, + { + "description": "Denies the version command without any pre-configured scope.", + "type": "string", + "const": "core:app:deny-version", + "markdownDescription": "Denies the version command without any pre-configured scope." + }, + { + "description": "Default permissions for the plugin, which enables all commands.\n#### This default permission set includes:\n\n- `allow-listen`\n- `allow-unlisten`\n- `allow-emit`\n- `allow-emit-to`", + "type": "string", + "const": "core:event:default", + "markdownDescription": "Default permissions for the plugin, which enables all commands.\n#### This default permission set includes:\n\n- `allow-listen`\n- `allow-unlisten`\n- `allow-emit`\n- `allow-emit-to`" + }, + { + "description": "Enables the emit command without any pre-configured scope.", + "type": "string", + "const": "core:event:allow-emit", + "markdownDescription": "Enables the emit command without any pre-configured scope." + }, + { + "description": "Enables the emit_to command without any pre-configured scope.", + "type": "string", + "const": "core:event:allow-emit-to", + "markdownDescription": "Enables the emit_to command without any pre-configured scope." + }, + { + "description": "Enables the listen command without any pre-configured scope.", + "type": "string", + "const": "core:event:allow-listen", + "markdownDescription": "Enables the listen command without any pre-configured scope." + }, + { + "description": "Enables the unlisten command without any pre-configured scope.", + "type": "string", + "const": "core:event:allow-unlisten", + "markdownDescription": "Enables the unlisten command without any pre-configured scope." + }, + { + "description": "Denies the emit command without any pre-configured scope.", + "type": "string", + "const": "core:event:deny-emit", + "markdownDescription": "Denies the emit command without any pre-configured scope." + }, + { + "description": "Denies the emit_to command without any pre-configured scope.", + "type": "string", + "const": "core:event:deny-emit-to", + "markdownDescription": "Denies the emit_to command without any pre-configured scope." + }, + { + "description": "Denies the listen command without any pre-configured scope.", + "type": "string", + "const": "core:event:deny-listen", + "markdownDescription": "Denies the listen command without any pre-configured scope." + }, + { + "description": "Denies the unlisten command without any pre-configured scope.", + "type": "string", + "const": "core:event:deny-unlisten", + "markdownDescription": "Denies the unlisten command without any pre-configured scope." + }, + { + "description": "Default permissions for the plugin, which enables all commands.\n#### This default permission set includes:\n\n- `allow-new`\n- `allow-from-bytes`\n- `allow-from-path`\n- `allow-rgba`\n- `allow-size`", + "type": "string", + "const": "core:image:default", + "markdownDescription": "Default permissions for the plugin, which enables all commands.\n#### This default permission set includes:\n\n- `allow-new`\n- `allow-from-bytes`\n- `allow-from-path`\n- `allow-rgba`\n- `allow-size`" + }, + { + "description": "Enables the from_bytes command without any pre-configured scope.", + "type": "string", + "const": "core:image:allow-from-bytes", + "markdownDescription": "Enables the from_bytes command without any pre-configured scope." + }, + { + "description": "Enables the from_path command without any pre-configured scope.", + "type": "string", + "const": "core:image:allow-from-path", + "markdownDescription": "Enables the from_path command without any pre-configured scope." + }, + { + "description": "Enables the new command without any pre-configured scope.", + "type": "string", + "const": "core:image:allow-new", + "markdownDescription": "Enables the new command without any pre-configured scope." + }, + { + "description": "Enables the rgba command without any pre-configured scope.", + "type": "string", + "const": "core:image:allow-rgba", + "markdownDescription": "Enables the rgba command without any pre-configured scope." + }, + { + "description": "Enables the size command without any pre-configured scope.", + "type": "string", + "const": "core:image:allow-size", + "markdownDescription": "Enables the size command without any pre-configured scope." + }, + { + "description": "Denies the from_bytes command without any pre-configured scope.", + "type": "string", + "const": "core:image:deny-from-bytes", + "markdownDescription": "Denies the from_bytes command without any pre-configured scope." + }, + { + "description": "Denies the from_path command without any pre-configured scope.", + "type": "string", + "const": "core:image:deny-from-path", + "markdownDescription": "Denies the from_path command without any pre-configured scope." + }, + { + "description": "Denies the new command without any pre-configured scope.", + "type": "string", + "const": "core:image:deny-new", + "markdownDescription": "Denies the new command without any pre-configured scope." + }, + { + "description": "Denies the rgba command without any pre-configured scope.", + "type": "string", + "const": "core:image:deny-rgba", + "markdownDescription": "Denies the rgba command without any pre-configured scope." + }, + { + "description": "Denies the size command without any pre-configured scope.", + "type": "string", + "const": "core:image:deny-size", + "markdownDescription": "Denies the size command without any pre-configured scope." + }, + { + "description": "Default permissions for the plugin, which enables all commands.\n#### This default permission set includes:\n\n- `allow-new`\n- `allow-append`\n- `allow-prepend`\n- `allow-insert`\n- `allow-remove`\n- `allow-remove-at`\n- `allow-items`\n- `allow-get`\n- `allow-popup`\n- `allow-create-default`\n- `allow-set-as-app-menu`\n- `allow-set-as-window-menu`\n- `allow-text`\n- `allow-set-text`\n- `allow-is-enabled`\n- `allow-set-enabled`\n- `allow-set-accelerator`\n- `allow-set-as-windows-menu-for-nsapp`\n- `allow-set-as-help-menu-for-nsapp`\n- `allow-is-checked`\n- `allow-set-checked`\n- `allow-set-icon`", + "type": "string", + "const": "core:menu:default", + "markdownDescription": "Default permissions for the plugin, which enables all commands.\n#### This default permission set includes:\n\n- `allow-new`\n- `allow-append`\n- `allow-prepend`\n- `allow-insert`\n- `allow-remove`\n- `allow-remove-at`\n- `allow-items`\n- `allow-get`\n- `allow-popup`\n- `allow-create-default`\n- `allow-set-as-app-menu`\n- `allow-set-as-window-menu`\n- `allow-text`\n- `allow-set-text`\n- `allow-is-enabled`\n- `allow-set-enabled`\n- `allow-set-accelerator`\n- `allow-set-as-windows-menu-for-nsapp`\n- `allow-set-as-help-menu-for-nsapp`\n- `allow-is-checked`\n- `allow-set-checked`\n- `allow-set-icon`" + }, + { + "description": "Enables the append command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-append", + "markdownDescription": "Enables the append command without any pre-configured scope." + }, + { + "description": "Enables the create_default command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-create-default", + "markdownDescription": "Enables the create_default command without any pre-configured scope." + }, + { + "description": "Enables the get command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-get", + "markdownDescription": "Enables the get command without any pre-configured scope." + }, + { + "description": "Enables the insert command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-insert", + "markdownDescription": "Enables the insert command without any pre-configured scope." + }, + { + "description": "Enables the is_checked command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-is-checked", + "markdownDescription": "Enables the is_checked command without any pre-configured scope." + }, + { + "description": "Enables the is_enabled command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-is-enabled", + "markdownDescription": "Enables the is_enabled command without any pre-configured scope." + }, + { + "description": "Enables the items command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-items", + "markdownDescription": "Enables the items command without any pre-configured scope." + }, + { + "description": "Enables the new command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-new", + "markdownDescription": "Enables the new command without any pre-configured scope." + }, + { + "description": "Enables the popup command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-popup", + "markdownDescription": "Enables the popup command without any pre-configured scope." + }, + { + "description": "Enables the prepend command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-prepend", + "markdownDescription": "Enables the prepend command without any pre-configured scope." + }, + { + "description": "Enables the remove command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-remove", + "markdownDescription": "Enables the remove command without any pre-configured scope." + }, + { + "description": "Enables the remove_at command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-remove-at", + "markdownDescription": "Enables the remove_at command without any pre-configured scope." + }, + { + "description": "Enables the set_accelerator command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-set-accelerator", + "markdownDescription": "Enables the set_accelerator command without any pre-configured scope." + }, + { + "description": "Enables the set_as_app_menu command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-set-as-app-menu", + "markdownDescription": "Enables the set_as_app_menu command without any pre-configured scope." + }, + { + "description": "Enables the set_as_help_menu_for_nsapp command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-set-as-help-menu-for-nsapp", + "markdownDescription": "Enables the set_as_help_menu_for_nsapp command without any pre-configured scope." + }, + { + "description": "Enables the set_as_window_menu command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-set-as-window-menu", + "markdownDescription": "Enables the set_as_window_menu command without any pre-configured scope." + }, + { + "description": "Enables the set_as_windows_menu_for_nsapp command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-set-as-windows-menu-for-nsapp", + "markdownDescription": "Enables the set_as_windows_menu_for_nsapp command without any pre-configured scope." + }, + { + "description": "Enables the set_checked command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-set-checked", + "markdownDescription": "Enables the set_checked command without any pre-configured scope." + }, + { + "description": "Enables the set_enabled command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-set-enabled", + "markdownDescription": "Enables the set_enabled command without any pre-configured scope." + }, + { + "description": "Enables the set_icon command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-set-icon", + "markdownDescription": "Enables the set_icon command without any pre-configured scope." + }, + { + "description": "Enables the set_text command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-set-text", + "markdownDescription": "Enables the set_text command without any pre-configured scope." + }, + { + "description": "Enables the text command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-text", + "markdownDescription": "Enables the text command without any pre-configured scope." + }, + { + "description": "Denies the append command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-append", + "markdownDescription": "Denies the append command without any pre-configured scope." + }, + { + "description": "Denies the create_default command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-create-default", + "markdownDescription": "Denies the create_default command without any pre-configured scope." + }, + { + "description": "Denies the get command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-get", + "markdownDescription": "Denies the get command without any pre-configured scope." + }, + { + "description": "Denies the insert command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-insert", + "markdownDescription": "Denies the insert command without any pre-configured scope." + }, + { + "description": "Denies the is_checked command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-is-checked", + "markdownDescription": "Denies the is_checked command without any pre-configured scope." + }, + { + "description": "Denies the is_enabled command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-is-enabled", + "markdownDescription": "Denies the is_enabled command without any pre-configured scope." + }, + { + "description": "Denies the items command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-items", + "markdownDescription": "Denies the items command without any pre-configured scope." + }, + { + "description": "Denies the new command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-new", + "markdownDescription": "Denies the new command without any pre-configured scope." + }, + { + "description": "Denies the popup command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-popup", + "markdownDescription": "Denies the popup command without any pre-configured scope." + }, + { + "description": "Denies the prepend command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-prepend", + "markdownDescription": "Denies the prepend command without any pre-configured scope." + }, + { + "description": "Denies the remove command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-remove", + "markdownDescription": "Denies the remove command without any pre-configured scope." + }, + { + "description": "Denies the remove_at command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-remove-at", + "markdownDescription": "Denies the remove_at command without any pre-configured scope." + }, + { + "description": "Denies the set_accelerator command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-set-accelerator", + "markdownDescription": "Denies the set_accelerator command without any pre-configured scope." + }, + { + "description": "Denies the set_as_app_menu command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-set-as-app-menu", + "markdownDescription": "Denies the set_as_app_menu command without any pre-configured scope." + }, + { + "description": "Denies the set_as_help_menu_for_nsapp command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-set-as-help-menu-for-nsapp", + "markdownDescription": "Denies the set_as_help_menu_for_nsapp command without any pre-configured scope." + }, + { + "description": "Denies the set_as_window_menu command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-set-as-window-menu", + "markdownDescription": "Denies the set_as_window_menu command without any pre-configured scope." + }, + { + "description": "Denies the set_as_windows_menu_for_nsapp command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-set-as-windows-menu-for-nsapp", + "markdownDescription": "Denies the set_as_windows_menu_for_nsapp command without any pre-configured scope." + }, + { + "description": "Denies the set_checked command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-set-checked", + "markdownDescription": "Denies the set_checked command without any pre-configured scope." + }, + { + "description": "Denies the set_enabled command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-set-enabled", + "markdownDescription": "Denies the set_enabled command without any pre-configured scope." + }, + { + "description": "Denies the set_icon command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-set-icon", + "markdownDescription": "Denies the set_icon command without any pre-configured scope." + }, + { + "description": "Denies the set_text command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-set-text", + "markdownDescription": "Denies the set_text command without any pre-configured scope." + }, + { + "description": "Denies the text command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-text", + "markdownDescription": "Denies the text command without any pre-configured scope." + }, + { + "description": "Default permissions for the plugin, which enables all commands.\n#### This default permission set includes:\n\n- `allow-resolve-directory`\n- `allow-resolve`\n- `allow-normalize`\n- `allow-join`\n- `allow-dirname`\n- `allow-extname`\n- `allow-basename`\n- `allow-is-absolute`", + "type": "string", + "const": "core:path:default", + "markdownDescription": "Default permissions for the plugin, which enables all commands.\n#### This default permission set includes:\n\n- `allow-resolve-directory`\n- `allow-resolve`\n- `allow-normalize`\n- `allow-join`\n- `allow-dirname`\n- `allow-extname`\n- `allow-basename`\n- `allow-is-absolute`" + }, + { + "description": "Enables the basename command without any pre-configured scope.", + "type": "string", + "const": "core:path:allow-basename", + "markdownDescription": "Enables the basename command without any pre-configured scope." + }, + { + "description": "Enables the dirname command without any pre-configured scope.", + "type": "string", + "const": "core:path:allow-dirname", + "markdownDescription": "Enables the dirname command without any pre-configured scope." + }, + { + "description": "Enables the extname command without any pre-configured scope.", + "type": "string", + "const": "core:path:allow-extname", + "markdownDescription": "Enables the extname command without any pre-configured scope." + }, + { + "description": "Enables the is_absolute command without any pre-configured scope.", + "type": "string", + "const": "core:path:allow-is-absolute", + "markdownDescription": "Enables the is_absolute command without any pre-configured scope." + }, + { + "description": "Enables the join command without any pre-configured scope.", + "type": "string", + "const": "core:path:allow-join", + "markdownDescription": "Enables the join command without any pre-configured scope." + }, + { + "description": "Enables the normalize command without any pre-configured scope.", + "type": "string", + "const": "core:path:allow-normalize", + "markdownDescription": "Enables the normalize command without any pre-configured scope." + }, + { + "description": "Enables the resolve command without any pre-configured scope.", + "type": "string", + "const": "core:path:allow-resolve", + "markdownDescription": "Enables the resolve command without any pre-configured scope." + }, + { + "description": "Enables the resolve_directory command without any pre-configured scope.", + "type": "string", + "const": "core:path:allow-resolve-directory", + "markdownDescription": "Enables the resolve_directory command without any pre-configured scope." + }, + { + "description": "Denies the basename command without any pre-configured scope.", + "type": "string", + "const": "core:path:deny-basename", + "markdownDescription": "Denies the basename command without any pre-configured scope." + }, + { + "description": "Denies the dirname command without any pre-configured scope.", + "type": "string", + "const": "core:path:deny-dirname", + "markdownDescription": "Denies the dirname command without any pre-configured scope." + }, + { + "description": "Denies the extname command without any pre-configured scope.", + "type": "string", + "const": "core:path:deny-extname", + "markdownDescription": "Denies the extname command without any pre-configured scope." + }, + { + "description": "Denies the is_absolute command without any pre-configured scope.", + "type": "string", + "const": "core:path:deny-is-absolute", + "markdownDescription": "Denies the is_absolute command without any pre-configured scope." + }, + { + "description": "Denies the join command without any pre-configured scope.", + "type": "string", + "const": "core:path:deny-join", + "markdownDescription": "Denies the join command without any pre-configured scope." + }, + { + "description": "Denies the normalize command without any pre-configured scope.", + "type": "string", + "const": "core:path:deny-normalize", + "markdownDescription": "Denies the normalize command without any pre-configured scope." + }, + { + "description": "Denies the resolve command without any pre-configured scope.", + "type": "string", + "const": "core:path:deny-resolve", + "markdownDescription": "Denies the resolve command without any pre-configured scope." + }, + { + "description": "Denies the resolve_directory command without any pre-configured scope.", + "type": "string", + "const": "core:path:deny-resolve-directory", + "markdownDescription": "Denies the resolve_directory command without any pre-configured scope." + }, + { + "description": "Default permissions for the plugin, which enables all commands.\n#### This default permission set includes:\n\n- `allow-close`", + "type": "string", + "const": "core:resources:default", + "markdownDescription": "Default permissions for the plugin, which enables all commands.\n#### This default permission set includes:\n\n- `allow-close`" + }, + { + "description": "Enables the close command without any pre-configured scope.", + "type": "string", + "const": "core:resources:allow-close", + "markdownDescription": "Enables the close command without any pre-configured scope." + }, + { + "description": "Denies the close command without any pre-configured scope.", + "type": "string", + "const": "core:resources:deny-close", + "markdownDescription": "Denies the close command without any pre-configured scope." + }, + { + "description": "Default permissions for the plugin, which enables all commands.\n#### This default permission set includes:\n\n- `allow-new`\n- `allow-get-by-id`\n- `allow-remove-by-id`\n- `allow-set-icon`\n- `allow-set-menu`\n- `allow-set-tooltip`\n- `allow-set-title`\n- `allow-set-visible`\n- `allow-set-temp-dir-path`\n- `allow-set-icon-as-template`\n- `allow-set-show-menu-on-left-click`", + "type": "string", + "const": "core:tray:default", + "markdownDescription": "Default permissions for the plugin, which enables all commands.\n#### This default permission set includes:\n\n- `allow-new`\n- `allow-get-by-id`\n- `allow-remove-by-id`\n- `allow-set-icon`\n- `allow-set-menu`\n- `allow-set-tooltip`\n- `allow-set-title`\n- `allow-set-visible`\n- `allow-set-temp-dir-path`\n- `allow-set-icon-as-template`\n- `allow-set-show-menu-on-left-click`" + }, + { + "description": "Enables the get_by_id command without any pre-configured scope.", + "type": "string", + "const": "core:tray:allow-get-by-id", + "markdownDescription": "Enables the get_by_id command without any pre-configured scope." + }, + { + "description": "Enables the new command without any pre-configured scope.", + "type": "string", + "const": "core:tray:allow-new", + "markdownDescription": "Enables the new command without any pre-configured scope." + }, + { + "description": "Enables the remove_by_id command without any pre-configured scope.", + "type": "string", + "const": "core:tray:allow-remove-by-id", + "markdownDescription": "Enables the remove_by_id command without any pre-configured scope." + }, + { + "description": "Enables the set_icon command without any pre-configured scope.", + "type": "string", + "const": "core:tray:allow-set-icon", + "markdownDescription": "Enables the set_icon command without any pre-configured scope." + }, + { + "description": "Enables the set_icon_as_template command without any pre-configured scope.", + "type": "string", + "const": "core:tray:allow-set-icon-as-template", + "markdownDescription": "Enables the set_icon_as_template command without any pre-configured scope." + }, + { + "description": "Enables the set_menu command without any pre-configured scope.", + "type": "string", + "const": "core:tray:allow-set-menu", + "markdownDescription": "Enables the set_menu command without any pre-configured scope." + }, + { + "description": "Enables the set_show_menu_on_left_click command without any pre-configured scope.", + "type": "string", + "const": "core:tray:allow-set-show-menu-on-left-click", + "markdownDescription": "Enables the set_show_menu_on_left_click command without any pre-configured scope." + }, + { + "description": "Enables the set_temp_dir_path command without any pre-configured scope.", + "type": "string", + "const": "core:tray:allow-set-temp-dir-path", + "markdownDescription": "Enables the set_temp_dir_path command without any pre-configured scope." + }, + { + "description": "Enables the set_title command without any pre-configured scope.", + "type": "string", + "const": "core:tray:allow-set-title", + "markdownDescription": "Enables the set_title command without any pre-configured scope." + }, + { + "description": "Enables the set_tooltip command without any pre-configured scope.", + "type": "string", + "const": "core:tray:allow-set-tooltip", + "markdownDescription": "Enables the set_tooltip command without any pre-configured scope." + }, + { + "description": "Enables the set_visible command without any pre-configured scope.", + "type": "string", + "const": "core:tray:allow-set-visible", + "markdownDescription": "Enables the set_visible command without any pre-configured scope." + }, + { + "description": "Denies the get_by_id command without any pre-configured scope.", + "type": "string", + "const": "core:tray:deny-get-by-id", + "markdownDescription": "Denies the get_by_id command without any pre-configured scope." + }, + { + "description": "Denies the new command without any pre-configured scope.", + "type": "string", + "const": "core:tray:deny-new", + "markdownDescription": "Denies the new command without any pre-configured scope." + }, + { + "description": "Denies the remove_by_id command without any pre-configured scope.", + "type": "string", + "const": "core:tray:deny-remove-by-id", + "markdownDescription": "Denies the remove_by_id command without any pre-configured scope." + }, + { + "description": "Denies the set_icon command without any pre-configured scope.", + "type": "string", + "const": "core:tray:deny-set-icon", + "markdownDescription": "Denies the set_icon command without any pre-configured scope." + }, + { + "description": "Denies the set_icon_as_template command without any pre-configured scope.", + "type": "string", + "const": "core:tray:deny-set-icon-as-template", + "markdownDescription": "Denies the set_icon_as_template command without any pre-configured scope." + }, + { + "description": "Denies the set_menu command without any pre-configured scope.", + "type": "string", + "const": "core:tray:deny-set-menu", + "markdownDescription": "Denies the set_menu command without any pre-configured scope." + }, + { + "description": "Denies the set_show_menu_on_left_click command without any pre-configured scope.", + "type": "string", + "const": "core:tray:deny-set-show-menu-on-left-click", + "markdownDescription": "Denies the set_show_menu_on_left_click command without any pre-configured scope." + }, + { + "description": "Denies the set_temp_dir_path command without any pre-configured scope.", + "type": "string", + "const": "core:tray:deny-set-temp-dir-path", + "markdownDescription": "Denies the set_temp_dir_path command without any pre-configured scope." + }, + { + "description": "Denies the set_title command without any pre-configured scope.", + "type": "string", + "const": "core:tray:deny-set-title", + "markdownDescription": "Denies the set_title command without any pre-configured scope." + }, + { + "description": "Denies the set_tooltip command without any pre-configured scope.", + "type": "string", + "const": "core:tray:deny-set-tooltip", + "markdownDescription": "Denies the set_tooltip command without any pre-configured scope." + }, + { + "description": "Denies the set_visible command without any pre-configured scope.", + "type": "string", + "const": "core:tray:deny-set-visible", + "markdownDescription": "Denies the set_visible command without any pre-configured scope." + }, + { + "description": "Default permissions for the plugin.\n#### This default permission set includes:\n\n- `allow-get-all-webviews`\n- `allow-webview-position`\n- `allow-webview-size`\n- `allow-internal-toggle-devtools`", + "type": "string", + "const": "core:webview:default", + "markdownDescription": "Default permissions for the plugin.\n#### This default permission set includes:\n\n- `allow-get-all-webviews`\n- `allow-webview-position`\n- `allow-webview-size`\n- `allow-internal-toggle-devtools`" + }, + { + "description": "Enables the clear_all_browsing_data command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-clear-all-browsing-data", + "markdownDescription": "Enables the clear_all_browsing_data command without any pre-configured scope." + }, + { + "description": "Enables the create_webview command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-create-webview", + "markdownDescription": "Enables the create_webview command without any pre-configured scope." + }, + { + "description": "Enables the create_webview_window command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-create-webview-window", + "markdownDescription": "Enables the create_webview_window command without any pre-configured scope." + }, + { + "description": "Enables the get_all_webviews command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-get-all-webviews", + "markdownDescription": "Enables the get_all_webviews command without any pre-configured scope." + }, + { + "description": "Enables the internal_toggle_devtools command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-internal-toggle-devtools", + "markdownDescription": "Enables the internal_toggle_devtools command without any pre-configured scope." + }, + { + "description": "Enables the print command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-print", + "markdownDescription": "Enables the print command without any pre-configured scope." + }, + { + "description": "Enables the reparent command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-reparent", + "markdownDescription": "Enables the reparent command without any pre-configured scope." + }, + { + "description": "Enables the set_webview_auto_resize command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-set-webview-auto-resize", + "markdownDescription": "Enables the set_webview_auto_resize command without any pre-configured scope." + }, + { + "description": "Enables the set_webview_background_color command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-set-webview-background-color", + "markdownDescription": "Enables the set_webview_background_color command without any pre-configured scope." + }, + { + "description": "Enables the set_webview_focus command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-set-webview-focus", + "markdownDescription": "Enables the set_webview_focus command without any pre-configured scope." + }, + { + "description": "Enables the set_webview_position command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-set-webview-position", + "markdownDescription": "Enables the set_webview_position command without any pre-configured scope." + }, + { + "description": "Enables the set_webview_size command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-set-webview-size", + "markdownDescription": "Enables the set_webview_size command without any pre-configured scope." + }, + { + "description": "Enables the set_webview_zoom command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-set-webview-zoom", + "markdownDescription": "Enables the set_webview_zoom command without any pre-configured scope." + }, + { + "description": "Enables the webview_close command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-webview-close", + "markdownDescription": "Enables the webview_close command without any pre-configured scope." + }, + { + "description": "Enables the webview_hide command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-webview-hide", + "markdownDescription": "Enables the webview_hide command without any pre-configured scope." + }, + { + "description": "Enables the webview_position command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-webview-position", + "markdownDescription": "Enables the webview_position command without any pre-configured scope." + }, + { + "description": "Enables the webview_show command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-webview-show", + "markdownDescription": "Enables the webview_show command without any pre-configured scope." + }, + { + "description": "Enables the webview_size command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-webview-size", + "markdownDescription": "Enables the webview_size command without any pre-configured scope." + }, + { + "description": "Denies the clear_all_browsing_data command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-clear-all-browsing-data", + "markdownDescription": "Denies the clear_all_browsing_data command without any pre-configured scope." + }, + { + "description": "Denies the create_webview command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-create-webview", + "markdownDescription": "Denies the create_webview command without any pre-configured scope." + }, + { + "description": "Denies the create_webview_window command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-create-webview-window", + "markdownDescription": "Denies the create_webview_window command without any pre-configured scope." + }, + { + "description": "Denies the get_all_webviews command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-get-all-webviews", + "markdownDescription": "Denies the get_all_webviews command without any pre-configured scope." + }, + { + "description": "Denies the internal_toggle_devtools command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-internal-toggle-devtools", + "markdownDescription": "Denies the internal_toggle_devtools command without any pre-configured scope." + }, + { + "description": "Denies the print command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-print", + "markdownDescription": "Denies the print command without any pre-configured scope." + }, + { + "description": "Denies the reparent command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-reparent", + "markdownDescription": "Denies the reparent command without any pre-configured scope." + }, + { + "description": "Denies the set_webview_auto_resize command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-set-webview-auto-resize", + "markdownDescription": "Denies the set_webview_auto_resize command without any pre-configured scope." + }, + { + "description": "Denies the set_webview_background_color command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-set-webview-background-color", + "markdownDescription": "Denies the set_webview_background_color command without any pre-configured scope." + }, + { + "description": "Denies the set_webview_focus command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-set-webview-focus", + "markdownDescription": "Denies the set_webview_focus command without any pre-configured scope." + }, + { + "description": "Denies the set_webview_position command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-set-webview-position", + "markdownDescription": "Denies the set_webview_position command without any pre-configured scope." + }, + { + "description": "Denies the set_webview_size command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-set-webview-size", + "markdownDescription": "Denies the set_webview_size command without any pre-configured scope." + }, + { + "description": "Denies the set_webview_zoom command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-set-webview-zoom", + "markdownDescription": "Denies the set_webview_zoom command without any pre-configured scope." + }, + { + "description": "Denies the webview_close command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-webview-close", + "markdownDescription": "Denies the webview_close command without any pre-configured scope." + }, + { + "description": "Denies the webview_hide command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-webview-hide", + "markdownDescription": "Denies the webview_hide command without any pre-configured scope." + }, + { + "description": "Denies the webview_position command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-webview-position", + "markdownDescription": "Denies the webview_position command without any pre-configured scope." + }, + { + "description": "Denies the webview_show command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-webview-show", + "markdownDescription": "Denies the webview_show command without any pre-configured scope." + }, + { + "description": "Denies the webview_size command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-webview-size", + "markdownDescription": "Denies the webview_size command without any pre-configured scope." + }, + { + "description": "Default permissions for the plugin.\n#### This default permission set includes:\n\n- `allow-get-all-windows`\n- `allow-scale-factor`\n- `allow-inner-position`\n- `allow-outer-position`\n- `allow-inner-size`\n- `allow-outer-size`\n- `allow-is-fullscreen`\n- `allow-is-minimized`\n- `allow-is-maximized`\n- `allow-is-focused`\n- `allow-is-decorated`\n- `allow-is-resizable`\n- `allow-is-maximizable`\n- `allow-is-minimizable`\n- `allow-is-closable`\n- `allow-is-visible`\n- `allow-is-enabled`\n- `allow-title`\n- `allow-current-monitor`\n- `allow-primary-monitor`\n- `allow-monitor-from-point`\n- `allow-available-monitors`\n- `allow-cursor-position`\n- `allow-theme`\n- `allow-is-always-on-top`\n- `allow-internal-toggle-maximize`", + "type": "string", + "const": "core:window:default", + "markdownDescription": "Default permissions for the plugin.\n#### This default permission set includes:\n\n- `allow-get-all-windows`\n- `allow-scale-factor`\n- `allow-inner-position`\n- `allow-outer-position`\n- `allow-inner-size`\n- `allow-outer-size`\n- `allow-is-fullscreen`\n- `allow-is-minimized`\n- `allow-is-maximized`\n- `allow-is-focused`\n- `allow-is-decorated`\n- `allow-is-resizable`\n- `allow-is-maximizable`\n- `allow-is-minimizable`\n- `allow-is-closable`\n- `allow-is-visible`\n- `allow-is-enabled`\n- `allow-title`\n- `allow-current-monitor`\n- `allow-primary-monitor`\n- `allow-monitor-from-point`\n- `allow-available-monitors`\n- `allow-cursor-position`\n- `allow-theme`\n- `allow-is-always-on-top`\n- `allow-internal-toggle-maximize`" + }, + { + "description": "Enables the available_monitors command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-available-monitors", + "markdownDescription": "Enables the available_monitors command without any pre-configured scope." + }, + { + "description": "Enables the center command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-center", + "markdownDescription": "Enables the center command without any pre-configured scope." + }, + { + "description": "Enables the close command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-close", + "markdownDescription": "Enables the close command without any pre-configured scope." + }, + { + "description": "Enables the create command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-create", + "markdownDescription": "Enables the create command without any pre-configured scope." + }, + { + "description": "Enables the current_monitor command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-current-monitor", + "markdownDescription": "Enables the current_monitor command without any pre-configured scope." + }, + { + "description": "Enables the cursor_position command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-cursor-position", + "markdownDescription": "Enables the cursor_position command without any pre-configured scope." + }, + { + "description": "Enables the destroy command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-destroy", + "markdownDescription": "Enables the destroy command without any pre-configured scope." + }, + { + "description": "Enables the get_all_windows command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-get-all-windows", + "markdownDescription": "Enables the get_all_windows command without any pre-configured scope." + }, + { + "description": "Enables the hide command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-hide", + "markdownDescription": "Enables the hide command without any pre-configured scope." + }, + { + "description": "Enables the inner_position command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-inner-position", + "markdownDescription": "Enables the inner_position command without any pre-configured scope." + }, + { + "description": "Enables the inner_size command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-inner-size", + "markdownDescription": "Enables the inner_size command without any pre-configured scope." + }, + { + "description": "Enables the internal_toggle_maximize command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-internal-toggle-maximize", + "markdownDescription": "Enables the internal_toggle_maximize command without any pre-configured scope." + }, + { + "description": "Enables the is_always_on_top command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-is-always-on-top", + "markdownDescription": "Enables the is_always_on_top command without any pre-configured scope." + }, + { + "description": "Enables the is_closable command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-is-closable", + "markdownDescription": "Enables the is_closable command without any pre-configured scope." + }, + { + "description": "Enables the is_decorated command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-is-decorated", + "markdownDescription": "Enables the is_decorated command without any pre-configured scope." + }, + { + "description": "Enables the is_enabled command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-is-enabled", + "markdownDescription": "Enables the is_enabled command without any pre-configured scope." + }, + { + "description": "Enables the is_focused command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-is-focused", + "markdownDescription": "Enables the is_focused command without any pre-configured scope." + }, + { + "description": "Enables the is_fullscreen command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-is-fullscreen", + "markdownDescription": "Enables the is_fullscreen command without any pre-configured scope." + }, + { + "description": "Enables the is_maximizable command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-is-maximizable", + "markdownDescription": "Enables the is_maximizable command without any pre-configured scope." + }, + { + "description": "Enables the is_maximized command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-is-maximized", + "markdownDescription": "Enables the is_maximized command without any pre-configured scope." + }, + { + "description": "Enables the is_minimizable command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-is-minimizable", + "markdownDescription": "Enables the is_minimizable command without any pre-configured scope." + }, + { + "description": "Enables the is_minimized command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-is-minimized", + "markdownDescription": "Enables the is_minimized command without any pre-configured scope." + }, + { + "description": "Enables the is_resizable command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-is-resizable", + "markdownDescription": "Enables the is_resizable command without any pre-configured scope." + }, + { + "description": "Enables the is_visible command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-is-visible", + "markdownDescription": "Enables the is_visible command without any pre-configured scope." + }, + { + "description": "Enables the maximize command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-maximize", + "markdownDescription": "Enables the maximize command without any pre-configured scope." + }, + { + "description": "Enables the minimize command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-minimize", + "markdownDescription": "Enables the minimize command without any pre-configured scope." + }, + { + "description": "Enables the monitor_from_point command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-monitor-from-point", + "markdownDescription": "Enables the monitor_from_point command without any pre-configured scope." + }, + { + "description": "Enables the outer_position command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-outer-position", + "markdownDescription": "Enables the outer_position command without any pre-configured scope." + }, + { + "description": "Enables the outer_size command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-outer-size", + "markdownDescription": "Enables the outer_size command without any pre-configured scope." + }, + { + "description": "Enables the primary_monitor command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-primary-monitor", + "markdownDescription": "Enables the primary_monitor command without any pre-configured scope." + }, + { + "description": "Enables the request_user_attention command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-request-user-attention", + "markdownDescription": "Enables the request_user_attention command without any pre-configured scope." + }, + { + "description": "Enables the scale_factor command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-scale-factor", + "markdownDescription": "Enables the scale_factor command without any pre-configured scope." + }, + { + "description": "Enables the set_always_on_bottom command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-always-on-bottom", + "markdownDescription": "Enables the set_always_on_bottom command without any pre-configured scope." + }, + { + "description": "Enables the set_always_on_top command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-always-on-top", + "markdownDescription": "Enables the set_always_on_top command without any pre-configured scope." + }, + { + "description": "Enables the set_background_color command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-background-color", + "markdownDescription": "Enables the set_background_color command without any pre-configured scope." + }, + { + "description": "Enables the set_badge_count command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-badge-count", + "markdownDescription": "Enables the set_badge_count command without any pre-configured scope." + }, + { + "description": "Enables the set_badge_label command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-badge-label", + "markdownDescription": "Enables the set_badge_label command without any pre-configured scope." + }, + { + "description": "Enables the set_closable command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-closable", + "markdownDescription": "Enables the set_closable command without any pre-configured scope." + }, + { + "description": "Enables the set_content_protected command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-content-protected", + "markdownDescription": "Enables the set_content_protected command without any pre-configured scope." + }, + { + "description": "Enables the set_cursor_grab command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-cursor-grab", + "markdownDescription": "Enables the set_cursor_grab command without any pre-configured scope." + }, + { + "description": "Enables the set_cursor_icon command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-cursor-icon", + "markdownDescription": "Enables the set_cursor_icon command without any pre-configured scope." + }, + { + "description": "Enables the set_cursor_position command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-cursor-position", + "markdownDescription": "Enables the set_cursor_position command without any pre-configured scope." + }, + { + "description": "Enables the set_cursor_visible command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-cursor-visible", + "markdownDescription": "Enables the set_cursor_visible command without any pre-configured scope." + }, + { + "description": "Enables the set_decorations command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-decorations", + "markdownDescription": "Enables the set_decorations command without any pre-configured scope." + }, + { + "description": "Enables the set_effects command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-effects", + "markdownDescription": "Enables the set_effects command without any pre-configured scope." + }, + { + "description": "Enables the set_enabled command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-enabled", + "markdownDescription": "Enables the set_enabled command without any pre-configured scope." + }, + { + "description": "Enables the set_focus command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-focus", + "markdownDescription": "Enables the set_focus command without any pre-configured scope." + }, + { + "description": "Enables the set_focusable command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-focusable", + "markdownDescription": "Enables the set_focusable command without any pre-configured scope." + }, + { + "description": "Enables the set_fullscreen command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-fullscreen", + "markdownDescription": "Enables the set_fullscreen command without any pre-configured scope." + }, + { + "description": "Enables the set_icon command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-icon", + "markdownDescription": "Enables the set_icon command without any pre-configured scope." + }, + { + "description": "Enables the set_ignore_cursor_events command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-ignore-cursor-events", + "markdownDescription": "Enables the set_ignore_cursor_events command without any pre-configured scope." + }, + { + "description": "Enables the set_max_size command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-max-size", + "markdownDescription": "Enables the set_max_size command without any pre-configured scope." + }, + { + "description": "Enables the set_maximizable command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-maximizable", + "markdownDescription": "Enables the set_maximizable command without any pre-configured scope." + }, + { + "description": "Enables the set_min_size command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-min-size", + "markdownDescription": "Enables the set_min_size command without any pre-configured scope." + }, + { + "description": "Enables the set_minimizable command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-minimizable", + "markdownDescription": "Enables the set_minimizable command without any pre-configured scope." + }, + { + "description": "Enables the set_overlay_icon command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-overlay-icon", + "markdownDescription": "Enables the set_overlay_icon command without any pre-configured scope." + }, + { + "description": "Enables the set_position command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-position", + "markdownDescription": "Enables the set_position command without any pre-configured scope." + }, + { + "description": "Enables the set_progress_bar command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-progress-bar", + "markdownDescription": "Enables the set_progress_bar command without any pre-configured scope." + }, + { + "description": "Enables the set_resizable command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-resizable", + "markdownDescription": "Enables the set_resizable command without any pre-configured scope." + }, + { + "description": "Enables the set_shadow command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-shadow", + "markdownDescription": "Enables the set_shadow command without any pre-configured scope." + }, + { + "description": "Enables the set_simple_fullscreen command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-simple-fullscreen", + "markdownDescription": "Enables the set_simple_fullscreen command without any pre-configured scope." + }, + { + "description": "Enables the set_size command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-size", + "markdownDescription": "Enables the set_size command without any pre-configured scope." + }, + { + "description": "Enables the set_size_constraints command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-size-constraints", + "markdownDescription": "Enables the set_size_constraints command without any pre-configured scope." + }, + { + "description": "Enables the set_skip_taskbar command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-skip-taskbar", + "markdownDescription": "Enables the set_skip_taskbar command without any pre-configured scope." + }, + { + "description": "Enables the set_theme command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-theme", + "markdownDescription": "Enables the set_theme command without any pre-configured scope." + }, + { + "description": "Enables the set_title command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-title", + "markdownDescription": "Enables the set_title command without any pre-configured scope." + }, + { + "description": "Enables the set_title_bar_style command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-title-bar-style", + "markdownDescription": "Enables the set_title_bar_style command without any pre-configured scope." + }, + { + "description": "Enables the set_visible_on_all_workspaces command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-visible-on-all-workspaces", + "markdownDescription": "Enables the set_visible_on_all_workspaces command without any pre-configured scope." + }, + { + "description": "Enables the show command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-show", + "markdownDescription": "Enables the show command without any pre-configured scope." + }, + { + "description": "Enables the start_dragging command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-start-dragging", + "markdownDescription": "Enables the start_dragging command without any pre-configured scope." + }, + { + "description": "Enables the start_resize_dragging command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-start-resize-dragging", + "markdownDescription": "Enables the start_resize_dragging command without any pre-configured scope." + }, + { + "description": "Enables the theme command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-theme", + "markdownDescription": "Enables the theme command without any pre-configured scope." + }, + { + "description": "Enables the title command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-title", + "markdownDescription": "Enables the title command without any pre-configured scope." + }, + { + "description": "Enables the toggle_maximize command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-toggle-maximize", + "markdownDescription": "Enables the toggle_maximize command without any pre-configured scope." + }, + { + "description": "Enables the unmaximize command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-unmaximize", + "markdownDescription": "Enables the unmaximize command without any pre-configured scope." + }, + { + "description": "Enables the unminimize command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-unminimize", + "markdownDescription": "Enables the unminimize command without any pre-configured scope." + }, + { + "description": "Denies the available_monitors command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-available-monitors", + "markdownDescription": "Denies the available_monitors command without any pre-configured scope." + }, + { + "description": "Denies the center command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-center", + "markdownDescription": "Denies the center command without any pre-configured scope." + }, + { + "description": "Denies the close command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-close", + "markdownDescription": "Denies the close command without any pre-configured scope." + }, + { + "description": "Denies the create command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-create", + "markdownDescription": "Denies the create command without any pre-configured scope." + }, + { + "description": "Denies the current_monitor command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-current-monitor", + "markdownDescription": "Denies the current_monitor command without any pre-configured scope." + }, + { + "description": "Denies the cursor_position command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-cursor-position", + "markdownDescription": "Denies the cursor_position command without any pre-configured scope." + }, + { + "description": "Denies the destroy command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-destroy", + "markdownDescription": "Denies the destroy command without any pre-configured scope." + }, + { + "description": "Denies the get_all_windows command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-get-all-windows", + "markdownDescription": "Denies the get_all_windows command without any pre-configured scope." + }, + { + "description": "Denies the hide command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-hide", + "markdownDescription": "Denies the hide command without any pre-configured scope." + }, + { + "description": "Denies the inner_position command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-inner-position", + "markdownDescription": "Denies the inner_position command without any pre-configured scope." + }, + { + "description": "Denies the inner_size command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-inner-size", + "markdownDescription": "Denies the inner_size command without any pre-configured scope." + }, + { + "description": "Denies the internal_toggle_maximize command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-internal-toggle-maximize", + "markdownDescription": "Denies the internal_toggle_maximize command without any pre-configured scope." + }, + { + "description": "Denies the is_always_on_top command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-is-always-on-top", + "markdownDescription": "Denies the is_always_on_top command without any pre-configured scope." + }, + { + "description": "Denies the is_closable command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-is-closable", + "markdownDescription": "Denies the is_closable command without any pre-configured scope." + }, + { + "description": "Denies the is_decorated command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-is-decorated", + "markdownDescription": "Denies the is_decorated command without any pre-configured scope." + }, + { + "description": "Denies the is_enabled command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-is-enabled", + "markdownDescription": "Denies the is_enabled command without any pre-configured scope." + }, + { + "description": "Denies the is_focused command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-is-focused", + "markdownDescription": "Denies the is_focused command without any pre-configured scope." + }, + { + "description": "Denies the is_fullscreen command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-is-fullscreen", + "markdownDescription": "Denies the is_fullscreen command without any pre-configured scope." + }, + { + "description": "Denies the is_maximizable command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-is-maximizable", + "markdownDescription": "Denies the is_maximizable command without any pre-configured scope." + }, + { + "description": "Denies the is_maximized command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-is-maximized", + "markdownDescription": "Denies the is_maximized command without any pre-configured scope." + }, + { + "description": "Denies the is_minimizable command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-is-minimizable", + "markdownDescription": "Denies the is_minimizable command without any pre-configured scope." + }, + { + "description": "Denies the is_minimized command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-is-minimized", + "markdownDescription": "Denies the is_minimized command without any pre-configured scope." + }, + { + "description": "Denies the is_resizable command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-is-resizable", + "markdownDescription": "Denies the is_resizable command without any pre-configured scope." + }, + { + "description": "Denies the is_visible command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-is-visible", + "markdownDescription": "Denies the is_visible command without any pre-configured scope." + }, + { + "description": "Denies the maximize command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-maximize", + "markdownDescription": "Denies the maximize command without any pre-configured scope." + }, + { + "description": "Denies the minimize command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-minimize", + "markdownDescription": "Denies the minimize command without any pre-configured scope." + }, + { + "description": "Denies the monitor_from_point command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-monitor-from-point", + "markdownDescription": "Denies the monitor_from_point command without any pre-configured scope." + }, + { + "description": "Denies the outer_position command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-outer-position", + "markdownDescription": "Denies the outer_position command without any pre-configured scope." + }, + { + "description": "Denies the outer_size command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-outer-size", + "markdownDescription": "Denies the outer_size command without any pre-configured scope." + }, + { + "description": "Denies the primary_monitor command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-primary-monitor", + "markdownDescription": "Denies the primary_monitor command without any pre-configured scope." + }, + { + "description": "Denies the request_user_attention command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-request-user-attention", + "markdownDescription": "Denies the request_user_attention command without any pre-configured scope." + }, + { + "description": "Denies the scale_factor command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-scale-factor", + "markdownDescription": "Denies the scale_factor command without any pre-configured scope." + }, + { + "description": "Denies the set_always_on_bottom command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-always-on-bottom", + "markdownDescription": "Denies the set_always_on_bottom command without any pre-configured scope." + }, + { + "description": "Denies the set_always_on_top command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-always-on-top", + "markdownDescription": "Denies the set_always_on_top command without any pre-configured scope." + }, + { + "description": "Denies the set_background_color command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-background-color", + "markdownDescription": "Denies the set_background_color command without any pre-configured scope." + }, + { + "description": "Denies the set_badge_count command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-badge-count", + "markdownDescription": "Denies the set_badge_count command without any pre-configured scope." + }, + { + "description": "Denies the set_badge_label command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-badge-label", + "markdownDescription": "Denies the set_badge_label command without any pre-configured scope." + }, + { + "description": "Denies the set_closable command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-closable", + "markdownDescription": "Denies the set_closable command without any pre-configured scope." + }, + { + "description": "Denies the set_content_protected command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-content-protected", + "markdownDescription": "Denies the set_content_protected command without any pre-configured scope." + }, + { + "description": "Denies the set_cursor_grab command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-cursor-grab", + "markdownDescription": "Denies the set_cursor_grab command without any pre-configured scope." + }, + { + "description": "Denies the set_cursor_icon command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-cursor-icon", + "markdownDescription": "Denies the set_cursor_icon command without any pre-configured scope." + }, + { + "description": "Denies the set_cursor_position command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-cursor-position", + "markdownDescription": "Denies the set_cursor_position command without any pre-configured scope." + }, + { + "description": "Denies the set_cursor_visible command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-cursor-visible", + "markdownDescription": "Denies the set_cursor_visible command without any pre-configured scope." + }, + { + "description": "Denies the set_decorations command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-decorations", + "markdownDescription": "Denies the set_decorations command without any pre-configured scope." + }, + { + "description": "Denies the set_effects command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-effects", + "markdownDescription": "Denies the set_effects command without any pre-configured scope." + }, + { + "description": "Denies the set_enabled command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-enabled", + "markdownDescription": "Denies the set_enabled command without any pre-configured scope." + }, + { + "description": "Denies the set_focus command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-focus", + "markdownDescription": "Denies the set_focus command without any pre-configured scope." + }, + { + "description": "Denies the set_focusable command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-focusable", + "markdownDescription": "Denies the set_focusable command without any pre-configured scope." + }, + { + "description": "Denies the set_fullscreen command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-fullscreen", + "markdownDescription": "Denies the set_fullscreen command without any pre-configured scope." + }, + { + "description": "Denies the set_icon command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-icon", + "markdownDescription": "Denies the set_icon command without any pre-configured scope." + }, + { + "description": "Denies the set_ignore_cursor_events command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-ignore-cursor-events", + "markdownDescription": "Denies the set_ignore_cursor_events command without any pre-configured scope." + }, + { + "description": "Denies the set_max_size command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-max-size", + "markdownDescription": "Denies the set_max_size command without any pre-configured scope." + }, + { + "description": "Denies the set_maximizable command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-maximizable", + "markdownDescription": "Denies the set_maximizable command without any pre-configured scope." + }, + { + "description": "Denies the set_min_size command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-min-size", + "markdownDescription": "Denies the set_min_size command without any pre-configured scope." + }, + { + "description": "Denies the set_minimizable command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-minimizable", + "markdownDescription": "Denies the set_minimizable command without any pre-configured scope." + }, + { + "description": "Denies the set_overlay_icon command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-overlay-icon", + "markdownDescription": "Denies the set_overlay_icon command without any pre-configured scope." + }, + { + "description": "Denies the set_position command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-position", + "markdownDescription": "Denies the set_position command without any pre-configured scope." + }, + { + "description": "Denies the set_progress_bar command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-progress-bar", + "markdownDescription": "Denies the set_progress_bar command without any pre-configured scope." + }, + { + "description": "Denies the set_resizable command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-resizable", + "markdownDescription": "Denies the set_resizable command without any pre-configured scope." + }, + { + "description": "Denies the set_shadow command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-shadow", + "markdownDescription": "Denies the set_shadow command without any pre-configured scope." + }, + { + "description": "Denies the set_simple_fullscreen command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-simple-fullscreen", + "markdownDescription": "Denies the set_simple_fullscreen command without any pre-configured scope." + }, + { + "description": "Denies the set_size command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-size", + "markdownDescription": "Denies the set_size command without any pre-configured scope." + }, + { + "description": "Denies the set_size_constraints command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-size-constraints", + "markdownDescription": "Denies the set_size_constraints command without any pre-configured scope." + }, + { + "description": "Denies the set_skip_taskbar command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-skip-taskbar", + "markdownDescription": "Denies the set_skip_taskbar command without any pre-configured scope." + }, + { + "description": "Denies the set_theme command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-theme", + "markdownDescription": "Denies the set_theme command without any pre-configured scope." + }, + { + "description": "Denies the set_title command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-title", + "markdownDescription": "Denies the set_title command without any pre-configured scope." + }, + { + "description": "Denies the set_title_bar_style command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-title-bar-style", + "markdownDescription": "Denies the set_title_bar_style command without any pre-configured scope." + }, + { + "description": "Denies the set_visible_on_all_workspaces command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-visible-on-all-workspaces", + "markdownDescription": "Denies the set_visible_on_all_workspaces command without any pre-configured scope." + }, + { + "description": "Denies the show command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-show", + "markdownDescription": "Denies the show command without any pre-configured scope." + }, + { + "description": "Denies the start_dragging command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-start-dragging", + "markdownDescription": "Denies the start_dragging command without any pre-configured scope." + }, + { + "description": "Denies the start_resize_dragging command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-start-resize-dragging", + "markdownDescription": "Denies the start_resize_dragging command without any pre-configured scope." + }, + { + "description": "Denies the theme command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-theme", + "markdownDescription": "Denies the theme command without any pre-configured scope." + }, + { + "description": "Denies the title command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-title", + "markdownDescription": "Denies the title command without any pre-configured scope." + }, + { + "description": "Denies the toggle_maximize command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-toggle-maximize", + "markdownDescription": "Denies the toggle_maximize command without any pre-configured scope." + }, + { + "description": "Denies the unmaximize command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-unmaximize", + "markdownDescription": "Denies the unmaximize command without any pre-configured scope." + }, + { + "description": "Denies the unminimize command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-unminimize", + "markdownDescription": "Denies the unminimize command without any pre-configured scope." + } + ] + }, + "Value": { + "description": "All supported ACL values.", + "anyOf": [ + { + "description": "Represents a null JSON value.", + "type": "null" + }, + { + "description": "Represents a [`bool`].", + "type": "boolean" + }, + { + "description": "Represents a valid ACL [`Number`].", + "allOf": [ + { + "$ref": "#/definitions/Number" + } + ] + }, + { + "description": "Represents a [`String`].", + "type": "string" + }, + { + "description": "Represents a list of other [`Value`]s.", + "type": "array", + "items": { + "$ref": "#/definitions/Value" + } + }, + { + "description": "Represents a map of [`String`] keys to [`Value`]s.", + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/Value" + } + } + ] + }, + "Number": { + "description": "A valid ACL number.", + "anyOf": [ + { + "description": "Represents an [`i64`].", + "type": "integer", + "format": "int64" + }, + { + "description": "Represents a [`f64`].", + "type": "number", + "format": "double" + } + ] + }, + "Target": { + "description": "Platform target.", + "oneOf": [ + { + "description": "MacOS.", + "type": "string", + "enum": ["macOS"] + }, + { + "description": "Windows.", + "type": "string", + "enum": ["windows"] + }, + { + "description": "Linux.", + "type": "string", + "enum": ["linux"] + }, + { + "description": "Android.", + "type": "string", + "enum": ["android"] + }, + { + "description": "iOS.", + "type": "string", + "enum": ["iOS"] + } + ] + } + } +} diff --git a/foundry/packages/desktop/src-tauri/src/lib.rs b/foundry/packages/desktop/src-tauri/src/lib.rs index f8117bc..eda4761 100644 --- a/foundry/packages/desktop/src-tauri/src/lib.rs +++ b/foundry/packages/desktop/src-tauri/src/lib.rs @@ -1,28 +1,44 @@ use std::sync::Mutex; -use tauri::{AppHandle, LogicalPosition, Manager, WebviewUrl, WebviewWindowBuilder}; + +#[cfg(not(mobile))] +use tauri::{LogicalPosition, Manager, WebviewUrl, WebviewWindowBuilder}; + +#[cfg(not(mobile))] use tauri_plugin_shell::process::CommandChild; +#[cfg(not(mobile))] use tauri_plugin_shell::ShellExt; struct BackendState { + #[cfg(not(mobile))] child: Mutex>, + backend_url: Mutex, } #[tauri::command] -fn get_backend_url() -> String { - "http://127.0.0.1:7741".to_string() +fn get_backend_url(state: tauri::State) -> String { + state.backend_url.lock().unwrap().clone() } #[tauri::command] -async fn backend_health() -> Result { - match reqwest::get("http://127.0.0.1:7741/api/rivet/metadata").await { +fn set_backend_url(url: String, state: tauri::State) { + *state.backend_url.lock().unwrap() = url; +} + +#[tauri::command] +async fn backend_health(state: tauri::State<'_, BackendState>) -> Result { + let base = state.backend_url.lock().unwrap().clone(); + let url = format!("{}/api/rivet/metadata", base); + match reqwest::get(&url).await { Ok(resp) => Ok(resp.status().is_success()), Err(_) => Ok(false), } } -async fn wait_for_backend(timeout_secs: u64) -> Result<(), String> { +#[cfg(not(mobile))] +async fn wait_for_backend(base_url: String, timeout_secs: u64) -> Result<(), String> { let start = std::time::Instant::now(); let timeout = std::time::Duration::from_secs(timeout_secs); + let url = format!("{}/api/rivet/metadata", base_url); loop { if start.elapsed() > timeout { @@ -32,7 +48,7 @@ async fn wait_for_backend(timeout_secs: u64) -> Result<(), String> { )); } - match reqwest::get("http://127.0.0.1:7741/api/rivet/metadata").await { + match reqwest::get(&url).await { Ok(resp) if resp.status().is_success() => return Ok(()), _ => {} } @@ -41,7 +57,8 @@ async fn wait_for_backend(timeout_secs: u64) -> Result<(), String> { } } -fn spawn_backend(app: &AppHandle) -> Result<(), String> { +#[cfg(not(mobile))] +fn spawn_backend(app: &tauri::AppHandle) -> Result<(), String> { let sidecar = app .shell() .sidecar("sidecars/foundry-backend") @@ -88,65 +105,95 @@ fn spawn_backend(app: &AppHandle) -> Result<(), String> { #[cfg_attr(mobile, tauri::mobile_entry_point)] pub fn run() { - tauri::Builder::default() - .plugin(tauri_plugin_shell::init()) + let builder = tauri::Builder::default(); + + // Shell plugin is desktop-only (used for sidecar spawning) + #[cfg(not(mobile))] + let builder = builder.plugin(tauri_plugin_shell::init()); + + builder .manage(BackendState { + #[cfg(not(mobile))] child: Mutex::new(None), + backend_url: Mutex::new("http://127.0.0.1:7741".to_string()), }) - .invoke_handler(tauri::generate_handler![get_backend_url, backend_health]) - .setup(|app| { - // Create main window programmatically so we can set traffic light position - let url = if cfg!(debug_assertions) { - WebviewUrl::External("http://localhost:4173".parse().unwrap()) - } else { - WebviewUrl::default() - }; - - let mut builder = WebviewWindowBuilder::new(app, "main", url) - .title("Foundry") - .inner_size(1280.0, 800.0) - .min_inner_size(900.0, 600.0) - .resizable(true) - .theme(Some(tauri::Theme::Dark)) - .title_bar_style(tauri::TitleBarStyle::Overlay) - .hidden_title(true); - - #[cfg(target_os = "macos")] + .invoke_handler(tauri::generate_handler![ + get_backend_url, + set_backend_url, + backend_health + ]) + .setup(|_app| { + #[cfg(not(mobile))] + let app = _app; + // On desktop, create window programmatically for traffic light position + #[cfg(not(mobile))] { - builder = builder.traffic_light_position(LogicalPosition::new(14.0, 14.0)); - } + let url = if cfg!(debug_assertions) { + WebviewUrl::External("http://localhost:4173".parse().unwrap()) + } else { + WebviewUrl::default() + }; - builder.build()?; + let mut win_builder = WebviewWindowBuilder::new(app, "main", url) + .title("Foundry") + .inner_size(1280.0, 800.0) + .min_inner_size(900.0, 600.0) + .resizable(true) + .theme(Some(tauri::Theme::Dark)) + .title_bar_style(tauri::TitleBarStyle::Overlay) + .hidden_title(true); - // In debug mode, assume the developer is running the backend externally - if cfg!(debug_assertions) { - eprintln!("[foundry-desktop] Dev mode: skipping sidecar spawn. Run the backend separately."); - return Ok(()); - } - - let handle = app.handle().clone(); - tauri::async_runtime::spawn(async move { - if let Err(e) = spawn_backend(&handle) { - eprintln!("[foundry-desktop] Failed to start backend: {}", e); - return; + #[cfg(target_os = "macos")] + { + win_builder = + win_builder.traffic_light_position(LogicalPosition::new(14.0, 14.0)); } - match wait_for_backend(30).await { - Ok(()) => eprintln!("[foundry-desktop] Backend is ready."), - Err(e) => eprintln!("[foundry-desktop] {}", e), + win_builder.build()?; + } + + // On mobile, Tauri creates the webview automatically — no window setup needed. + // The backend URL will be set by the frontend via set_backend_url. + + // Sidecar spawning is desktop-only + #[cfg(not(mobile))] + { + // In debug mode, assume the developer is running the backend externally + if cfg!(debug_assertions) { + eprintln!( + "[foundry] Dev mode: skipping sidecar spawn. Run the backend separately." + ); + return Ok(()); } - }); + + let handle = app.handle().clone(); + tauri::async_runtime::spawn(async move { + if let Err(e) = spawn_backend(&handle) { + eprintln!("[foundry] Failed to start backend: {}", e); + return; + } + + match wait_for_backend("http://127.0.0.1:7741".to_string(), 30).await { + Ok(()) => eprintln!("[foundry] Backend is ready."), + Err(e) => eprintln!("[foundry] {}", e), + } + }); + } Ok(()) }) .on_window_event(|window, event| { if let tauri::WindowEvent::Destroyed = event { - let state = window.state::(); - let child = state.child.lock().unwrap().take(); - if let Some(child) = child { - let _ = child.kill(); - eprintln!("[foundry-desktop] Backend sidecar killed."); + #[cfg(not(mobile))] + { + let state = window.state::(); + let child = state.child.lock().unwrap().take(); + if let Some(child) = child { + let _ = child.kill(); + eprintln!("[foundry] Backend sidecar killed."); + } } + let _ = window; // suppress unused warning on mobile } }) .run(tauri::generate_context!()) diff --git a/foundry/packages/desktop/src-tauri/tauri.android.conf.json b/foundry/packages/desktop/src-tauri/tauri.android.conf.json new file mode 100644 index 0000000..3020e36 --- /dev/null +++ b/foundry/packages/desktop/src-tauri/tauri.android.conf.json @@ -0,0 +1,10 @@ +{ + "$schema": "https://raw.githubusercontent.com/tauri-apps/tauri/dev/crates/tauri-cli/schema.json", + "build": { + "beforeDevCommand": "FOUNDRY_FRONTEND_CLIENT_MODE=mock VITE_MOBILE=1 pnpm --filter @sandbox-agent/foundry-frontend dev --host 0.0.0.0 --port 4173" + }, + "bundle": { + "externalBin": [] + }, + "plugins": {} +} diff --git a/foundry/packages/desktop/src-tauri/tauri.ios.conf.json b/foundry/packages/desktop/src-tauri/tauri.ios.conf.json new file mode 100644 index 0000000..8a13e6d --- /dev/null +++ b/foundry/packages/desktop/src-tauri/tauri.ios.conf.json @@ -0,0 +1,11 @@ +{ + "$schema": "https://raw.githubusercontent.com/tauri-apps/tauri/dev/crates/tauri-cli/schema.json", + "build": { + "beforeDevCommand": "FOUNDRY_FRONTEND_CLIENT_MODE=mock VITE_MOBILE=1 pnpm --filter @sandbox-agent/foundry-frontend dev --host 0.0.0.0 --port 4173", + "devUrl": "http://localhost:4173" + }, + "bundle": { + "externalBin": [] + }, + "plugins": {} +} diff --git a/foundry/packages/frontend/index.html b/foundry/packages/frontend/index.html index dc0af73..f0e8694 100644 --- a/foundry/packages/frontend/index.html +++ b/foundry/packages/frontend/index.html @@ -13,7 +13,7 @@ - + Foundry diff --git a/foundry/packages/frontend/public/sounds/notification-1.mp3 b/foundry/packages/frontend/public/sounds/notification-1.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..d678983cadf271636268521d83b77e275fb5a942 GIT binary patch literal 25389 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

{CuYQZD@G{_9E^ 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 literal 0 HcmV?d00001 diff --git a/foundry/packages/frontend/src/components/mock-layout.tsx b/foundry/packages/frontend/src/components/mock-layout.tsx index 213109e..0c4c2b1 100644 --- a/foundry/packages/frontend/src/components/mock-layout.tsx +++ b/foundry/packages/frontend/src/components/mock-layout.tsx @@ -2,8 +2,10 @@ import { memo, useCallback, useEffect, useLayoutEffect, useMemo, useRef, useStat import { useNavigate } from "@tanstack/react-router"; import { useStyletron } from "baseui"; +import type { WorkbenchPresence } from "@sandbox-agent/foundry-shared"; import { PanelLeft, PanelRight } from "lucide-react"; import { useFoundryTokens } from "../app/theme"; +import { useAgentDoneNotification } from "../lib/notification-sound"; import { DiffContent } from "./mock-layout/diff-content"; import { MessageList } from "./mock-layout/message-list"; @@ -11,15 +13,17 @@ import { PromptComposer } from "./mock-layout/prompt-composer"; import { RightSidebar } from "./mock-layout/right-sidebar"; import { Sidebar } from "./mock-layout/sidebar"; import { TabStrip } from "./mock-layout/tab-strip"; -import { TerminalPane } from "./mock-layout/terminal-pane"; +import { TerminalPane, type ProcessTab } from "./mock-layout/terminal-pane"; import { TranscriptHeader } from "./mock-layout/transcript-header"; -import { PROMPT_TEXTAREA_MAX_HEIGHT, PROMPT_TEXTAREA_MIN_HEIGHT, SPanel, ScrollBody, Shell } from "./mock-layout/ui"; +import { PROMPT_TEXTAREA_MAX_HEIGHT, PROMPT_TEXTAREA_MIN_HEIGHT, SPanel, ScrollBody, Shell, Tooltip } from "./mock-layout/ui"; import { buildDisplayMessages, diffPath, diffTabId, formatThinkingDuration, isDiffTab, + isTerminalTab, + terminalTabId, buildHistoryEvents, type Task, type HistoryEvent, @@ -27,8 +31,10 @@ import { type Message, type ModelId, } from "./mock-layout/view-model"; -import { activeMockOrganization, useMockAppSnapshot } from "../lib/mock-app"; +import { activeMockOrganization, activeMockUser, useMockAppSnapshot } from "../lib/mock-app"; +import { useIsMobile } from "../lib/platform"; import { getTaskWorkbenchClient } from "../lib/workbench"; +import { MobileLayout } from "./mock-layout/mobile-layout"; function firstAgentTabId(task: Task): string | null { return task.tabs[0]?.id ?? null; @@ -58,12 +64,127 @@ function sanitizeActiveTabId(task: Task, tabId: string | null | undefined, openD if (isDiffTab(tabId) && openDiffs.includes(diffPath(tabId))) { return tabId; } + if (isTerminalTab(tabId)) { + return tabId; + } } return openDiffs.length > 0 ? diffTabId(openDiffs[openDiffs.length - 1]!) : lastAgentTabId; } +function TypingIndicator({ presence, currentUserId }: { presence: WorkbenchPresence[]; currentUserId: string | null }) { + const [css] = useStyletron(); + const t = useFoundryTokens(); + const typingMembers = presence.filter((member) => member.typing && member.memberId !== currentUserId); + const isTyping = typingMembers.length > 0; + const [animState, setAnimState] = useState<"in" | "out" | "hidden">(isTyping ? "in" : "hidden"); + const lastMembersRef = useRef(typingMembers); + + if (isTyping) { + lastMembersRef.current = typingMembers; + } + + useEffect(() => { + if (isTyping) { + setAnimState("in"); + } else if (lastMembersRef.current.length > 0) { + setAnimState("out"); + } + }, [isTyping]); + + if (animState === "hidden") return null; + + const members = lastMembersRef.current; + if (members.length === 0) return null; + const label = + members.length === 1 + ? `${members[0]!.name} is typing` + : members.length === 2 + ? `${members[0]!.name} & ${members[1]!.name} are typing` + : `${members[0]!.name} & ${members.length - 1} others are typing`; + + return ( +

{ + if (animState === "out") setAnimState("hidden"); + }} + > +
+ {members.slice(0, 3).map((member) => + member.avatarUrl ? ( + + ) : ( +
+ {member.name.charAt(0).toUpperCase()} +
+ ), + )} +
+ + {label} + {[0, 1, 2].map((i) => ( + + . + + ))} + +
+ ); +} + const TranscriptPanel = memo(function TranscriptPanel({ + workspaceId, taskWorkbenchClient, task, activeTabId, @@ -80,7 +201,18 @@ const TranscriptPanel = memo(function TranscriptPanel({ rightSidebarCollapsed, onToggleRightSidebar, onNavigateToUsage, + terminalTabOpen, + onOpenTerminalTab, + onCloseTerminalTab, + terminalProcessTabs, + onTerminalProcessTabsChange, + terminalActiveTabId, + onTerminalActiveTabIdChange, + terminalCustomNames, + onTerminalCustomNamesChange, + mobile, }: { + workspaceId: string; taskWorkbenchClient: ReturnType; task: Task; activeTabId: string | null; @@ -97,8 +229,20 @@ const TranscriptPanel = memo(function TranscriptPanel({ rightSidebarCollapsed?: boolean; onToggleRightSidebar?: () => void; onNavigateToUsage?: () => void; + terminalTabOpen?: boolean; + onOpenTerminalTab?: () => void; + onCloseTerminalTab?: () => void; + terminalProcessTabs?: ProcessTab[]; + onTerminalProcessTabsChange?: (tabs: ProcessTab[]) => void; + terminalActiveTabId?: string | null; + onTerminalActiveTabIdChange?: (id: string | null) => void; + terminalCustomNames?: Record; + onTerminalCustomNamesChange?: (names: Record) => void; + mobile?: boolean; }) { const t = useFoundryTokens(); + const transcriptAppSnapshot = useMockAppSnapshot(); + const currentUser = activeMockUser(transcriptAppSnapshot); const [defaultModel, setDefaultModel] = useState("claude-sonnet-4"); const [editingField, setEditingField] = useState<"title" | "branch" | null>(null); const [editValue, setEditValue] = useState(""); @@ -111,9 +255,11 @@ const TranscriptPanel = memo(function TranscriptPanel({ const textareaRef = useRef(null); const messageRefs = useRef(new Map()); const activeDiff = activeTabId && isDiffTab(activeTabId) ? diffPath(activeTabId) : null; - const activeAgentTab = activeDiff ? null : (task.tabs.find((candidate) => candidate.id === activeTabId) ?? task.tabs[0] ?? null); + const activeTerminal = activeTabId && isTerminalTab(activeTabId) ? true : false; + const activeAgentTab = activeDiff || activeTerminal ? null : (task.tabs.find((candidate) => candidate.id === activeTabId) ?? task.tabs[0] ?? null); const promptTab = task.tabs.find((candidate) => candidate.id === lastAgentTabId) ?? task.tabs[0] ?? null; const isTerminal = task.status === "archived"; + useAgentDoneNotification(promptTab?.status); const historyEvents = useMemo(() => buildHistoryEvents(task.tabs), [task.tabs]); const activeMessages = useMemo(() => buildDisplayMessages(activeAgentTab), [activeAgentTab]); const draft = promptTab?.draft.text ?? ""; @@ -271,7 +417,7 @@ const TranscriptPanel = memo(function TranscriptPanel({ (tabId: string) => { onSetActiveTabId(tabId); - if (!isDiffTab(tabId)) { + if (!isDiffTab(tabId) && !isTerminalTab(tabId)) { onSetLastAgentTabId(tabId); const tab = task.tabs.find((candidate) => candidate.id === tabId); if (tab?.unread) { @@ -448,28 +594,30 @@ const TranscriptPanel = memo(function TranscriptPanel({ return ( - { - if (activeAgentTab) { - setTabUnread(activeAgentTab.id, unread); - } - }} - sidebarCollapsed={sidebarCollapsed} - onToggleSidebar={onToggleSidebar} - onSidebarPeekStart={onSidebarPeekStart} - onSidebarPeekEnd={onSidebarPeekEnd} - rightSidebarCollapsed={rightSidebarCollapsed} - onToggleRightSidebar={onToggleRightSidebar} - onNavigateToUsage={onNavigateToUsage} - /> + {!mobile && ( + { + if (activeAgentTab) { + setTabUnread(activeAgentTab.id, unread); + } + }} + sidebarCollapsed={sidebarCollapsed} + onToggleSidebar={onToggleSidebar} + onSidebarPeekStart={onSidebarPeekStart} + onSidebarPeekEnd={onSidebarPeekEnd} + rightSidebarCollapsed={rightSidebarCollapsed} + onToggleRightSidebar={onToggleRightSidebar} + onNavigateToUsage={onNavigateToUsage} + /> + )}
- {activeDiff ? ( + {activeTerminal ? ( +
+ +
+ ) : activeDiff ? ( file.path === activeDiff)} @@ -563,25 +732,30 @@ const TranscriptPanel = memo(function TranscriptPanel({ void copyMessage(message); }} thinkingTimerLabel={thinkingTimerLabel} + userName={currentUser?.name ?? null} + userAvatarUrl={currentUser?.avatarUrl ?? null} /> )} - {!isTerminal && promptTab ? ( - updateDraft(value, attachments)} - onSend={sendMessage} - onStop={stopAgent} - onRemoveAttachment={removeAttachment} - onChangeModel={changeModel} - onSetDefaultModel={setDefaultModel} - /> + {!isTerminal && !activeTerminal && promptTab ? ( + <> + + updateDraft(value, attachments)} + onSend={sendMessage} + onStop={stopAgent} + onRemoveAttachment={removeAttachment} + onChangeModel={changeModel} + onSetDefaultModel={setDefaultModel} + /> + ) : null}
@@ -670,6 +844,14 @@ const RightRail = memo(function RightRail({ onRevertFile, onPublishPr, onToggleSidebar, + onOpenTerminalTab, + terminalTabOpen, + terminalProcessTabs, + onTerminalProcessTabsChange, + terminalActiveTabId, + onTerminalActiveTabIdChange, + terminalCustomNames, + onTerminalCustomNamesChange, }: { workspaceId: string; task: Task; @@ -679,6 +861,14 @@ const RightRail = memo(function RightRail({ onRevertFile: (path: string) => void; onPublishPr: () => void; onToggleSidebar?: () => void; + onOpenTerminalTab?: () => void; + terminalTabOpen?: boolean; + terminalProcessTabs?: ProcessTab[]; + onTerminalProcessTabsChange?: (tabs: ProcessTab[]) => void; + terminalActiveTabId?: string | null; + onTerminalActiveTabIdChange?: (id: string | null) => void; + terminalCustomNames?: Record; + onTerminalCustomNamesChange?: (names: Record) => void; }) { const [css] = useStyletron(); const t = useFoundryTokens(); @@ -761,6 +951,13 @@ const RightRail = memo(function RightRail({ minWidth: 0, display: "flex", flexDirection: "column", + ...(terminalTabOpen + ? { + borderBottomRightRadius: "12px", + borderBottom: `1px solid ${t.borderDefault}`, + overflow: "hidden", + } + : {}), })} >
@@ -802,6 +999,13 @@ const RightRail = memo(function RightRail({ onCollapse={() => { setTerminalHeight(43); }} + onOpenTerminalTab={onOpenTerminalTab} + processTabs={terminalProcessTabs} + onProcessTabsChange={onTerminalProcessTabsChange} + activeProcessTabId={terminalActiveTabId} + onActiveProcessTabIdChange={onTerminalActiveTabIdChange} + customTabNames={terminalCustomNames} + onCustomTabNamesChange={onTerminalCustomNamesChange} />
@@ -909,6 +1113,11 @@ export function MockLayout({ workspaceId, selectedTaskId, selectedSessionId }: M void navigate({ to: "/organizations/$organizationId/billing" as never, params: { organizationId: activeOrg.id } }); } }, [activeOrg, navigate]); + const navigateToSettings = useCallback(() => { + if (activeOrg) { + void navigate({ to: "/organizations/$organizationId/settings" as never, params: { organizationId: activeOrg.id } as never }); + } + }, [activeOrg, navigate]); const [projectOrder, setProjectOrder] = useState(null); const projects = useMemo(() => { if (!projectOrder) return rawProjects; @@ -922,6 +1131,10 @@ export function MockLayout({ workspaceId, selectedTaskId, selectedSessionId }: M const [activeTabIdByTask, setActiveTabIdByTask] = useState>({}); const [lastAgentTabIdByTask, setLastAgentTabIdByTask] = useState>({}); const [openDiffsByTask, setOpenDiffsByTask] = useState>({}); + const [terminalTabOpenByTask, setTerminalTabOpenByTask] = useState>({}); + const [terminalProcessTabsByTask, setTerminalProcessTabsByTask] = useState>({}); + const [terminalActiveTabIdByTask, setTerminalActiveTabIdByTask] = useState>({}); + const [terminalCustomNamesByTask, setTerminalCustomNamesByTask] = useState>>({}); const [selectedNewTaskRepoId, setSelectedNewTaskRepoId] = useState(""); const [leftWidth, setLeftWidth] = useState(() => readStoredWidth(LEFT_WIDTH_STORAGE_KEY, LEFT_SIDEBAR_DEFAULT_WIDTH)); const [rightWidth, setRightWidth] = useState(() => readStoredWidth(RIGHT_WIDTH_STORAGE_KEY, RIGHT_SIDEBAR_DEFAULT_WIDTH)); @@ -1021,6 +1234,10 @@ export function MockLayout({ workspaceId, selectedTaskId, selectedSessionId }: M }, [activeTask, tasks, navigate, workspaceId]); const openDiffs = activeTask ? sanitizeOpenDiffs(activeTask, openDiffsByTask[activeTask.id]) : []; + const terminalTabOpen = activeTask ? (terminalTabOpenByTask[activeTask.id] ?? false) : false; + const terminalProcessTabs = activeTask ? (terminalProcessTabsByTask[activeTask.id] ?? []) : []; + const terminalActiveTabId = activeTask ? (terminalActiveTabIdByTask[activeTask.id] ?? null) : null; + const terminalCustomNames = activeTask ? (terminalCustomNamesByTask[activeTask.id] ?? {}) : {}; const lastAgentTabId = activeTask ? sanitizeLastAgentTabId(activeTask, lastAgentTabIdByTask[activeTask.id]) : null; const activeTabId = activeTask ? sanitizeActiveTabId(activeTask, activeTabIdByTask[activeTask.id], openDiffs, lastAgentTabId) : null; @@ -1115,29 +1332,32 @@ export function MockLayout({ workspaceId, selectedTaskId, selectedSessionId }: M })(); }, [activeTask, selectedSessionId, syncRouteSession, taskWorkbenchClient]); - const createTask = useCallback(() => { - void (async () => { - const repoId = selectedNewTaskRepoId; - if (!repoId) { - throw new Error("Cannot create a task without an available repo"); - } + const createTask = useCallback( + (overrideRepoId?: string) => { + void (async () => { + const repoId = overrideRepoId || selectedNewTaskRepoId; + if (!repoId) { + throw new Error("Cannot create a task without an available repo"); + } - const { taskId, tabId } = await taskWorkbenchClient.createTask({ - repoId, - task: "New task", - model: "gpt-4o", - title: "New task", - }); - await navigate({ - to: "/workspaces/$workspaceId/tasks/$taskId", - params: { - workspaceId, - taskId, - }, - search: { sessionId: tabId ?? undefined }, - }); - })(); - }, [navigate, selectedNewTaskRepoId, workspaceId]); + const { taskId, tabId } = await taskWorkbenchClient.createTask({ + repoId, + task: "New task", + model: "gpt-4o", + title: "New task", + }); + await navigate({ + to: "/workspaces/$workspaceId/tasks/$taskId", + params: { + workspaceId, + taskId, + }, + search: { sessionId: tabId ?? undefined }, + }); + })(); + }, + [navigate, selectedNewTaskRepoId, workspaceId], + ); const openDiffTab = useCallback( (path: string) => { @@ -1163,6 +1383,46 @@ export function MockLayout({ workspaceId, selectedTaskId, selectedSessionId }: M [activeTask], ); + const openTerminalTab = useCallback(() => { + if (!activeTask) return; + setTerminalTabOpenByTask((current) => ({ ...current, [activeTask.id]: true })); + setActiveTabIdByTask((current) => ({ ...current, [activeTask.id]: terminalTabId() })); + }, [activeTask]); + + const closeTerminalTab = useCallback(() => { + if (!activeTask) return; + setTerminalTabOpenByTask((current) => ({ ...current, [activeTask.id]: false })); + const currentActive = activeTabIdByTask[activeTask.id]; + if (currentActive && isTerminalTab(currentActive)) { + const fallback = lastAgentTabIdByTask[activeTask.id] ?? activeTask.tabs[0]?.id ?? null; + setActiveTabIdByTask((current) => ({ ...current, [activeTask.id]: fallback })); + } + }, [activeTask, activeTabIdByTask, lastAgentTabIdByTask]); + + const setTerminalProcessTabs = useCallback( + (tabs: ProcessTab[]) => { + if (!activeTask) return; + setTerminalProcessTabsByTask((current) => ({ ...current, [activeTask.id]: tabs })); + }, + [activeTask], + ); + + const setTerminalActiveTabId = useCallback( + (id: string | null) => { + if (!activeTask) return; + setTerminalActiveTabIdByTask((current) => ({ ...current, [activeTask.id]: id })); + }, + [activeTask], + ); + + const setTerminalCustomNames = useCallback( + (names: Record) => { + if (!activeTask) return; + setTerminalCustomNamesByTask((current) => ({ ...current, [activeTask.id]: names })); + }, + [activeTask], + ); + const selectTask = useCallback( (id: string) => { const task = tasks.find((candidate) => candidate.id === id) ?? null; @@ -1265,6 +1525,8 @@ export function MockLayout({ workspaceId, selectedTaskId, selectedSessionId }: M [activeTask, lastAgentTabIdByTask], ); + const isMobile = useIsMobile(); + const isDesktop = !!import.meta.env.VITE_DESKTOP; const onDragMouseDown = useCallback((event: ReactPointerEvent) => { if (event.button !== 0) return; @@ -1274,6 +1536,58 @@ export function MockLayout({ workspaceId, selectedTaskId, selectedSessionId }: M ipc.invoke("plugin:window|start_dragging").catch(() => {}); } }, []); + + // Mobile layout: single-panel stack navigation with bottom tab bar + if (isMobile && activeTask) { + return ( + setActiveTabIdByTask((current) => ({ ...current, [activeTask.id]: tabId }))} + onSetLastAgentTabId={(tabId) => setLastAgentTabIdByTask((current) => ({ ...current, [activeTask.id]: tabId }))} + onSetOpenDiffs={(paths) => setOpenDiffsByTask((current) => ({ ...current, [activeTask.id]: paths }))} + onNavigateToUsage={navigateToUsage} + mobile + /> + } + onOpenDiff={openDiffTab} + onArchive={archiveTask} + onRevertFile={revertFile} + onPublishPr={publishPr} + terminalProcessTabs={terminalProcessTabs} + onTerminalProcessTabsChange={setTerminalProcessTabs} + terminalActiveTabId={terminalActiveTabId} + onTerminalActiveTabIdChange={setTerminalActiveTabId} + terminalCustomNames={terminalCustomNames} + onTerminalCustomNamesChange={setTerminalCustomNames} + onOpenSettings={navigateToSettings} + /> + ); + } + const dragRegion = isDesktop ? (
{leftSidebarOpen ? null : ( -
setLeftSidebarOpen(true)}> - -
+ +
setLeftSidebarOpen(true)}> + +
+
)}
{rightSidebarOpen ? null : ( -
setRightSidebarOpen(true)}> - -
+ +
setRightSidebarOpen(true)}> + +
+
)}
) : null} @@ -1409,7 +1727,7 @@ export function MockLayout({ workspaceId, selectedTaskId, selectedSessionId }: M

diff --git a/foundry/packages/frontend/src/components/mock-layout/history-minimap.tsx b/foundry/packages/frontend/src/components/mock-layout/history-minimap.tsx index 3c48a27..29ee29a 100644 --- a/foundry/packages/frontend/src/components/mock-layout/history-minimap.tsx +++ b/foundry/packages/frontend/src/components/mock-layout/history-minimap.tsx @@ -4,6 +4,7 @@ import { LabelXSmall } from "baseui/typography"; import { History } from "lucide-react"; import { useFoundryTokens } from "../../app/theme"; +import { Tooltip } from "./ui"; import { formatMessageTimestamp, type HistoryEvent } from "./view-model"; export const HistoryMinimap = memo(function HistoryMinimap({ events, onSelect }: { events: HistoryEvent[]; onSelect: (event: HistoryEvent) => void }) { @@ -41,29 +42,31 @@ export const HistoryMinimap = memo(function HistoryMinimap({ events, onSelect }: gap: "6px", })} > -
setOpen((prev) => !prev)} - onKeyDown={(e) => { - if (e.key === "Enter" || e.key === " ") setOpen((prev) => !prev); - }} - className={css({ - width: "26px", - height: "26px", - borderRadius: "6px", - display: "flex", - alignItems: "center", - justifyContent: "center", - cursor: "pointer", - color: open ? t.textSecondary : t.textTertiary, - backgroundColor: open ? t.interactiveHover : "transparent", - transition: "background 200ms ease, color 200ms ease", - ":hover": { color: t.textSecondary, backgroundColor: t.interactiveHover }, - })} - > - -
+ +
setOpen((prev) => !prev)} + onKeyDown={(e) => { + if (e.key === "Enter" || e.key === " ") setOpen((prev) => !prev); + }} + className={css({ + width: "26px", + height: "26px", + borderRadius: "6px", + display: "flex", + alignItems: "center", + justifyContent: "center", + cursor: "pointer", + color: open ? t.textSecondary : t.textTertiary, + backgroundColor: open ? t.interactiveHover : "transparent", + transition: "background 200ms ease, color 200ms ease", + ":hover": { color: t.textSecondary, backgroundColor: t.interactiveHover }, + })} + > + +
+
{open ? (
>; copiedMessageId: string | null; onCopyMessage: (message: Message) => void; + userName?: string | null; + userAvatarUrl?: string | null; }) { const [css] = useStyletron(); const t = useFoundryTokens(); @@ -81,12 +85,52 @@ const TranscriptMessageBody = memo(function TranscriptMessageBody({ className={css({ display: "flex", alignItems: "center", - gap: "10px", + gap: "6px", justifyContent: isUser ? "flex-end" : "flex-start", minHeight: "16px", paddingLeft: isUser ? undefined : "2px", })} > + {isUser && (userAvatarUrl || userName) ? ( + <> + {userAvatarUrl ? ( + + ) : userName ? ( +
+ {userName.charAt(0).toUpperCase()} +
+ ) : null} + {userName ? ( + + {userName} + + ) : null} + + ) : null} {displayFooter ? ( {displayFooter} @@ -130,6 +174,8 @@ export const MessageList = memo(function MessageList({ copiedMessageId, onCopyMessage, thinkingTimerLabel, + userName, + userAvatarUrl, }: { tab: AgentTab | null | undefined; scrollRef: Ref; @@ -139,6 +185,8 @@ export const MessageList = memo(function MessageList({ copiedMessageId: string | null; onCopyMessage: (message: Message) => void; thinkingTimerLabel: string | null; + userName?: string | null; + userAvatarUrl?: string | null; }) { const [css] = useStyletron(); const t = useFoundryTokens(); @@ -238,7 +286,16 @@ export const MessageList = memo(function MessageList({ return null; } - return ; + return ( + + ); }} isThinking={Boolean(tab && tab.status === "running" && transcriptEntries.length > 0)} renderThinkingState={() => ( diff --git a/foundry/packages/frontend/src/components/mock-layout/mobile-layout.tsx b/foundry/packages/frontend/src/components/mock-layout/mobile-layout.tsx new file mode 100644 index 0000000..0d071d7 --- /dev/null +++ b/foundry/packages/frontend/src/components/mock-layout/mobile-layout.tsx @@ -0,0 +1,338 @@ +import { memo, useCallback, useRef, useState } from "react"; +import { useStyletron } from "baseui"; +import { FileText, List, MessageSquare, Settings, Terminal as TerminalIcon } from "lucide-react"; +import { useFoundryTokens } from "../../app/theme"; + +import type { WorkbenchProjectSection, WorkbenchRepo } from "@sandbox-agent/foundry-shared"; +import { RightSidebar } from "./right-sidebar"; +import { Sidebar } from "./sidebar"; +import { TerminalPane, type ProcessTab } from "./terminal-pane"; +import type { Task } from "./view-model"; + +type MobileView = "tasks" | "chat" | "changes" | "terminal"; +const VIEW_ORDER: MobileView[] = ["tasks", "chat", "changes", "terminal"]; + +const SWIPE_THRESHOLD = 50; +const SWIPE_MAX_VERTICAL = 80; + +interface MobileLayoutProps { + workspaceId: string; + task: Task; + tasks: Task[]; + projects: WorkbenchProjectSection[]; + repos: WorkbenchRepo[]; + selectedNewTaskRepoId: string; + onSelectNewTaskRepo: (id: string) => void; + onSelectTask: (id: string) => void; + onCreateTask: (repoId?: string) => void; + onMarkUnread: (id: string) => void; + onRenameTask: (id: string) => void; + onRenameBranch: (id: string) => void; + onReorderProjects: (from: number, to: number) => void; + taskOrderByProject: Record; + onReorderTasks: (projectId: string, from: number, to: number) => void; + // Transcript panel (rendered by parent) + transcriptPanel: React.ReactNode; + // Diff/file actions + onOpenDiff: (path: string) => void; + onArchive: () => void; + onRevertFile: (path: string) => void; + onPublishPr: () => void; + // Tab state + activeTabId: string | null; + // Terminal state + terminalProcessTabs: ProcessTab[]; + onTerminalProcessTabsChange: (tabs: ProcessTab[]) => void; + terminalActiveTabId: string | null; + onTerminalActiveTabIdChange: (id: string | null) => void; + terminalCustomNames: Record; + onTerminalCustomNamesChange: (names: Record) => void; + onOpenSettings?: () => void; +} + +export const MobileLayout = memo(function MobileLayout(props: MobileLayoutProps) { + const [css] = useStyletron(); + const t = useFoundryTokens(); + const [activeView, setActiveView] = useState("tasks"); + + // Swipe gesture tracking + const touchStartRef = useRef<{ x: number; y: number } | null>(null); + + const handleTouchStart = useCallback((e: React.TouchEvent) => { + const touch = e.touches[0]; + if (touch) { + touchStartRef.current = { x: touch.clientX, y: touch.clientY }; + } + }, []); + + const handleTouchEnd = useCallback( + (e: React.TouchEvent) => { + const start = touchStartRef.current; + const touch = e.changedTouches[0]; + if (!start || !touch) return; + touchStartRef.current = null; + + const dx = touch.clientX - start.x; + const dy = touch.clientY - start.y; + + if (Math.abs(dx) < SWIPE_THRESHOLD || Math.abs(dy) > SWIPE_MAX_VERTICAL) return; + + const currentIndex = VIEW_ORDER.indexOf(activeView); + if (dx > 0 && currentIndex > 0) { + // Swipe right -> go back + setActiveView(VIEW_ORDER[currentIndex - 1]!); + } else if (dx < 0 && currentIndex < VIEW_ORDER.length - 1) { + // Swipe left -> go forward + setActiveView(VIEW_ORDER[currentIndex + 1]!); + } + }, + [activeView], + ); + + const handleSelectTask = useCallback( + (id: string) => { + props.onSelectTask(id); + setActiveView("chat"); + }, + [props.onSelectTask], + ); + + return ( +
+ {/* Header - show task info when not on tasks view */} + {activeView !== "tasks" && } + + {/* Content area */} +
+ {activeView === "tasks" ? ( +
+ +
+ ) : activeView === "chat" ? ( +
{props.transcriptPanel}
+ ) : activeView === "changes" ? ( +
+ +
+ ) : ( +
+ +
+ )} +
+ + {/* Bottom tab bar - always fixed at bottom */} + +
+ ); +}); + +function MobileHeader({ task }: { task: Task }) { + const [css] = useStyletron(); + const t = useFoundryTokens(); + + return ( +
+
+
+ {task.title} +
+
+ {task.repoName} +
+
+
+ ); +} + +function MobileTabBar({ + activeView, + onViewChange, + changesCount, + onOpenSettings, +}: { + activeView: MobileView; + onViewChange: (view: MobileView) => void; + changesCount: number; + onOpenSettings?: () => void; +}) { + const [css] = useStyletron(); + const t = useFoundryTokens(); + + const tabs: { id: MobileView; icon: React.ReactNode; badge?: number }[] = [ + { id: "tasks", icon: }, + { id: "chat", icon: }, + { id: "changes", icon: , badge: changesCount > 0 ? changesCount : undefined }, + { id: "terminal", icon: }, + ]; + + const iconButtonClass = css({ + border: "none", + background: "transparent", + display: "flex", + alignItems: "center", + justifyContent: "center", + width: "42px", + height: "42px", + borderRadius: "12px", + cursor: "pointer", + position: "relative", + transition: "background 150ms ease, color 150ms ease", + }); + + return ( +
+ {/* Pill container */} +
+ {tabs.map((tab) => { + const isActive = activeView === tab.id; + return ( + + ); + })} + {onOpenSettings && ( + + )} +
+
+ ); +} diff --git a/foundry/packages/frontend/src/components/mock-layout/right-sidebar.tsx b/foundry/packages/frontend/src/components/mock-layout/right-sidebar.tsx index d3c67f3..e2e7ebe 100644 --- a/foundry/packages/frontend/src/components/mock-layout/right-sidebar.tsx +++ b/foundry/packages/frontend/src/components/mock-layout/right-sidebar.tsx @@ -4,7 +4,7 @@ import { LabelSmall } from "baseui/typography"; import { Archive, ArrowUpFromLine, ChevronRight, FileCode, FilePlus, FileX, FolderOpen, GitPullRequest, PanelRight } from "lucide-react"; import { useFoundryTokens } from "../../app/theme"; -import { type ContextMenuItem, ContextMenuOverlay, PanelHeaderBar, SPanel, ScrollBody, useContextMenu } from "./ui"; +import { type ContextMenuItem, ContextMenuOverlay, PanelHeaderBar, SPanel, ScrollBody, Tooltip, useContextMenu } from "./ui"; import { type FileTreeNode, type Task, diffTabId } from "./view-model"; const FileTree = memo(function FileTree({ @@ -96,6 +96,7 @@ export const RightSidebar = memo(function RightSidebar({ onRevertFile, onPublishPr, onToggleSidebar, + mobile, }: { task: Task; activeTabId: string | null; @@ -104,6 +105,7 @@ export const RightSidebar = memo(function RightSidebar({ onRevertFile: (path: string) => void; onPublishPr: () => void; onToggleSidebar?: () => void; + mobile?: boolean; }) { const [css] = useStyletron(); const t = useFoundryTokens(); @@ -151,128 +153,138 @@ export const RightSidebar = memo(function RightSidebar({ return ( - -
- {!isTerminal ? ( -
- - - -
- ) : null} - {onToggleSidebar ? ( -
{ - if (event.key === "Enter" || event.key === " ") onToggleSidebar(); - }} - className={css({ - width: "26px", - height: "26px", - borderRadius: "6px", - color: t.textTertiary, - cursor: "pointer", - display: "flex", - alignItems: "center", - justifyContent: "center", - flexShrink: 0, - ":hover": { color: t.textSecondary, backgroundColor: t.interactiveHover }, - })} - > - -
- ) : null} -
-
+ onPublishPr(); + }} + className={css({ + appearance: "none", + WebkitAppearance: "none", + background: "none", + border: "none", + margin: "0", + boxSizing: "border-box", + display: "inline-flex", + alignItems: "center", + gap: "5px", + padding: compact ? "4px 6px" : "4px 10px", + borderRadius: "6px", + fontSize: "11px", + fontWeight: 500, + lineHeight: 1, + whiteSpace: "nowrap", + flexShrink: 0, + color: t.textSecondary, + cursor: "pointer", + transition: "all 200ms ease", + ":hover": { backgroundColor: t.interactiveHover, color: t.textPrimary }, + })} + > + + {!compact && {pullRequestUrl ? "Open PR" : "Publish PR"}} + + + + + + + + +
+ ) : null} + {onToggleSidebar ? ( + +
{ + if (event.key === "Enter" || event.key === " ") onToggleSidebar(); + }} + className={css({ + width: "26px", + height: "26px", + borderRadius: "6px", + color: t.textTertiary, + cursor: "pointer", + display: "flex", + alignItems: "center", + justifyContent: "center", + flexShrink: 0, + ":hover": { color: t.textSecondary, backgroundColor: t.interactiveHover }, + })} + > + +
+
+ ) : null} + + + )}
@@ -296,7 +312,7 @@ export const RightSidebar = memo(function RightSidebar({ height: "41px", minHeight: "41px", flexShrink: 0, - borderTopRightRadius: "12px", + ...(mobile ? {} : { borderTopRightRadius: "12px" }), })} >
+ ); +}); + +const PresenceAvatars = memo(function PresenceAvatars({ presence }: { presence: WorkbenchPresence[] }) { + const [css] = useStyletron(); + const t = useFoundryTokens(); + const maxShow = 3; + const visible = presence.slice(0, maxShow); + const overflow = presence.length - maxShow; + const now = Date.now(); + + return ( +
+
+ {visible.map((member, idx) => { + const isAway = now - member.lastSeenAtMs > AWAY_THRESHOLD_MS; + return ; + })} + {overflow > 0 && ( +
div:last-child": { + opacity: 1, + transform: "translateX(-50%) translateY(0)", + pointerEvents: "auto", + }, + })} + > +
+ +{overflow} +
+
+ {presence + .slice(maxShow) + .map((m) => m.name) + .join(", ")} +
+
+ )} +
+ {presence.length <= 2 && ( + + {presence.map((m) => m.name).join(", ")} + + )} +
+ ); +}); + function projectInitial(label: string): string { const parts = label.split("/"); const name = parts[parts.length - 1] ?? label; @@ -55,13 +207,15 @@ export const Sidebar = memo(function Sidebar({ taskOrderByProject, onReorderTasks, onToggleSidebar, + hideSettings, + panelStyle, }: { projects: ProjectSection[]; newTaskRepos: Array<{ id: string; label: string }>; selectedNewTaskRepoId: string; activeId: string; onSelect: (id: string) => void; - onCreate: () => void; + onCreate: (repoId?: string) => void; onSelectNewTaskRepo: (repoId: string) => void; onMarkUnread: (id: string) => void; onRenameTask: (id: string) => void; @@ -70,6 +224,8 @@ export const Sidebar = memo(function Sidebar({ taskOrderByProject: Record; onReorderTasks: (projectId: string, fromIndex: number, toIndex: number) => void; onToggleSidebar?: () => void; + hideSettings?: boolean; + panelStyle?: Record; }) { const [css] = useStyletron(); const t = useFoundryTokens(); @@ -90,6 +246,7 @@ export const Sidebar = memo(function Sidebar({ // Attach global mousemove/mouseup when dragging useEffect(() => { if (!drag) return; + document.body.style.cursor = "grabbing"; const onMove = (e: MouseEvent) => { // Detect which element is under the cursor using data attributes const el = document.elementFromPoint(e.clientX, e.clientY); @@ -132,6 +289,7 @@ export const Sidebar = memo(function Sidebar({ document.addEventListener("mousemove", onMove); document.addEventListener("mouseup", onUp); return () => { + document.body.style.cursor = ""; document.removeEventListener("mousemove", onMove); document.removeEventListener("mouseup", onUp); }; @@ -152,12 +310,12 @@ export const Sidebar = memo(function Sidebar({ }, [createMenuOpen]); return ( - + @@ -175,6 +333,43 @@ export const Sidebar = memo(function Sidebar({ })} > {onToggleSidebar ? ( + +
{ + if (event.key === "Enter" || event.key === " ") onToggleSidebar(); + }} + className={css({ + width: "26px", + height: "26px", + borderRadius: "6px", + color: t.textTertiary, + cursor: "pointer", + display: "flex", + alignItems: "center", + justifyContent: "center", + flexShrink: 0, + ":hover": { color: t.textSecondary, backgroundColor: t.interactiveHover }, + })} + > + +
+
+ ) : null} + + ) : null} + + + + Tasks + + {!import.meta.env.VITE_DESKTOP && onToggleSidebar ? ( +
- ) : null} - - ) : null} - - - - Tasks - - {!import.meta.env.VITE_DESKTOP && onToggleSidebar ? ( -
{ - if (event.key === "Enter" || event.key === " ") onToggleSidebar(); - }} - className={css({ - width: "26px", - height: "26px", - borderRadius: "6px", - color: t.textTertiary, - cursor: "pointer", - display: "flex", - alignItems: "center", - justifyContent: "center", - flexShrink: 0, - ":hover": { color: t.textSecondary, backgroundColor: t.interactiveHover }, - })} - > - -
+
) : null}
-
{ - if (newTaskRepos.length === 0) return; - if (newTaskRepos.length === 1) { - onSelectNewTaskRepo(newTaskRepos[0]!.id); - onCreate(); - } else { - setCreateMenuOpen((prev) => !prev); - } - }} - onKeyDown={(event) => { - if (newTaskRepos.length === 0) return; - if (event.key === "Enter" || event.key === " ") { + +
{ + if (newTaskRepos.length === 0) return; if (newTaskRepos.length === 1) { onSelectNewTaskRepo(newTaskRepos[0]!.id); - onCreate(); + onCreate(newTaskRepos[0]!.id); } else { setCreateMenuOpen((prev) => !prev); } - } - }} - className={css({ - width: "26px", - height: "26px", - borderRadius: "8px", - backgroundColor: newTaskRepos.length > 0 ? t.borderMedium : t.interactiveHover, - color: t.textPrimary, - cursor: newTaskRepos.length > 0 ? "pointer" : "not-allowed", - display: "flex", - alignItems: "center", - justifyContent: "center", - transition: "background 200ms ease", - flexShrink: 0, - opacity: newTaskRepos.length > 0 ? 1 : 0.6, - ":hover": newTaskRepos.length > 0 ? { backgroundColor: "rgba(255, 255, 255, 0.20)" } : undefined, - })} - > - -
+ }} + onKeyDown={(event) => { + if (newTaskRepos.length === 0) return; + if (event.key === "Enter" || event.key === " ") { + if (newTaskRepos.length === 1) { + onSelectNewTaskRepo(newTaskRepos[0]!.id); + onCreate(newTaskRepos[0]!.id); + } else { + setCreateMenuOpen((prev) => !prev); + } + } + }} + className={css({ + width: "26px", + height: "26px", + borderRadius: "8px", + backgroundColor: newTaskRepos.length > 0 ? t.borderMedium : t.interactiveHover, + color: t.textPrimary, + cursor: newTaskRepos.length > 0 ? "pointer" : "not-allowed", + display: "flex", + alignItems: "center", + justifyContent: "center", + transition: "background 200ms ease", + flexShrink: 0, + opacity: newTaskRepos.length > 0 ? 1 : 0.6, + ":hover": newTaskRepos.length > 0 ? { backgroundColor: "rgba(255, 255, 255, 0.20)" } : undefined, + })} + > + +
+ {createMenuOpen && newTaskRepos.length > 1 ? (
{ onSelectNewTaskRepo(repo.id); setCreateMenuOpen(false); - onCreate(); + onCreate(repo.id); }} className={css({ display: "flex", @@ -442,9 +606,31 @@ export const Sidebar = memo(function Sidebar({ > {projectInitial(project.label)} - +
e.stopPropagation()} className={css({ @@ -543,7 +729,7 @@ export const Sidebar = memo(function Sidebar({ position: "relative", backgroundColor: isActive ? t.interactiveHover : "transparent", opacity: isTaskBeingDragged ? 0.4 : 1, - cursor: "pointer", + cursor: drag?.type === "task" ? "grabbing" : "pointer", transition: "all 150ms ease", "::before": { content: '""', @@ -607,6 +793,7 @@ export const Sidebar = memo(function Sidebar({ {formatRelativeAge(task.updatedAtMs)}
+ {task.presence.length > 0 && } ); })} @@ -658,7 +845,7 @@ export const Sidebar = memo(function Sidebar({ /> - + {!hideSettings && } {contextMenu.menu ? : null}
); @@ -945,34 +1132,36 @@ function SidebarFooter() { ) : null}
- + + +
); diff --git a/foundry/packages/frontend/src/components/mock-layout/tab-strip.tsx b/foundry/packages/frontend/src/components/mock-layout/tab-strip.tsx index e96989e..7dd4e73 100644 --- a/foundry/packages/frontend/src/components/mock-layout/tab-strip.tsx +++ b/foundry/packages/frontend/src/components/mock-layout/tab-strip.tsx @@ -1,11 +1,11 @@ import { memo } from "react"; import { useStyletron } from "baseui"; import { LabelXSmall } from "baseui/typography"; -import { FileCode, Plus, X } from "lucide-react"; +import { FileCode, Plus, SquareTerminal, X } from "lucide-react"; import { useFoundryTokens } from "../../app/theme"; -import { ContextMenuOverlay, TabAvatar, useContextMenu } from "./ui"; -import { diffTabId, fileName, type Task } from "./view-model"; +import { ContextMenuOverlay, TabAvatar, Tooltip, useContextMenu } from "./ui"; +import { diffTabId, fileName, terminalTabId, type Task } from "./view-model"; export const TabStrip = memo(function TabStrip({ task, @@ -22,6 +22,8 @@ export const TabStrip = memo(function TabStrip({ onCloseTab, onCloseDiffTab, onAddTab, + terminalTabOpen, + onCloseTerminalTab, sidebarCollapsed, }: { task: Task; @@ -38,6 +40,8 @@ export const TabStrip = memo(function TabStrip({ onCloseTab: (tabId: string) => void; onCloseDiffTab: (path: string) => void; onAddTab: () => void; + terminalTabOpen?: boolean; + onCloseTerminalTab?: () => void; sidebarCollapsed?: boolean; }) { const [css] = useStyletron(); @@ -216,21 +220,71 @@ export const TabStrip = memo(function TabStrip({ ); })} -
- -
+ {terminalTabOpen + ? (() => { + const tabId = terminalTabId(); + const isActive = tabId === activeTabId; + return ( +
onSwitchTab(tabId)} + onMouseDown={(event) => { + if (event.button === 1) { + event.preventDefault(); + onCloseTerminalTab?.(); + } + }} + data-tab + className={css({ + display: "flex", + alignItems: "center", + gap: "6px", + padding: "4px 12px", + marginTop: "6px", + marginBottom: "6px", + borderRadius: "8px", + backgroundColor: isActive ? t.interactiveHover : "transparent", + cursor: "pointer", + transition: "color 200ms ease, background-color 200ms ease", + flexShrink: 0, + ":hover": { color: t.textPrimary, backgroundColor: isActive ? t.interactiveHover : t.interactiveSubtle }, + })} + > + + + Terminal + + { + event.stopPropagation(); + onCloseTerminalTab?.(); + }} + /> +
+ ); + })() + : null} + +
+ +
+
{contextMenu.menu ? : null} diff --git a/foundry/packages/frontend/src/components/mock-layout/terminal-pane.tsx b/foundry/packages/frontend/src/components/mock-layout/terminal-pane.tsx index d0e011d..6098c99 100644 --- a/foundry/packages/frontend/src/components/mock-layout/terminal-pane.tsx +++ b/foundry/packages/frontend/src/components/mock-layout/terminal-pane.tsx @@ -3,7 +3,7 @@ import { ProcessTerminal } from "@sandbox-agent/react"; import { useQuery } from "@tanstack/react-query"; import { useStyletron } from "baseui"; import { useFoundryTokens } from "../../app/theme"; -import { ChevronDown, ChevronUp, Plus, SquareTerminal, Trash2 } from "lucide-react"; +import { ArrowUpLeft, ChevronDown, ChevronUp, Plus, SquareTerminal, Trash2 } from "lucide-react"; import { useCallback, useEffect, useMemo, useRef, useState } from "react"; import { SandboxAgent } from "sandbox-agent"; import { backendClient } from "../../lib/backend"; @@ -12,11 +12,21 @@ interface TerminalPaneProps { workspaceId: string; taskId: string | null; isExpanded?: boolean; + hideHeader?: boolean; onExpand?: () => void; onCollapse?: () => void; onStartResize?: (e: React.PointerEvent) => void; + onOpenTerminalTab?: () => void; + processTabs?: ProcessTab[]; + onProcessTabsChange?: (tabs: ProcessTab[]) => void; + activeProcessTabId?: string | null; + onActiveProcessTabIdChange?: (id: string | null) => void; + customTabNames?: Record; + onCustomTabNamesChange?: (names: Record) => void; } +export type { ProcessTab }; + interface ProcessTab { id: string; processId: string; @@ -94,15 +104,66 @@ function HeaderIconButton({ ); } -export function TerminalPane({ workspaceId, taskId, isExpanded, onExpand, onCollapse, onStartResize }: TerminalPaneProps) { +export function TerminalPane({ + workspaceId, + taskId, + isExpanded, + hideHeader, + onExpand, + onCollapse, + onStartResize, + onOpenTerminalTab, + processTabs: controlledProcessTabs, + onProcessTabsChange, + activeProcessTabId: controlledActiveTabId, + onActiveProcessTabIdChange, + customTabNames: controlledCustomTabNames, + onCustomTabNamesChange, +}: TerminalPaneProps) { const [css] = useStyletron(); const t = useFoundryTokens(); - const [activeTabId, setActiveTabId] = useState(null); - const [processTabs, setProcessTabs] = useState([]); + const [internalActiveTabId, setInternalActiveTabId] = useState(null); + const [internalProcessTabs, setInternalProcessTabs] = useState([]); const [creatingProcess, setCreatingProcess] = useState(false); const [hoveredTabId, setHoveredTabId] = useState(null); const [terminalClient, setTerminalClient] = useState(null); - const [customTabNames, setCustomTabNames] = useState>({}); + const [internalCustomTabNames, setInternalCustomTabNames] = useState>({}); + + const processTabs = controlledProcessTabs ?? internalProcessTabs; + const setProcessTabs = useCallback( + (update: ProcessTab[] | ((prev: ProcessTab[]) => ProcessTab[])) => { + if (onProcessTabsChange) { + const next = typeof update === "function" ? update(controlledProcessTabs ?? []) : update; + onProcessTabsChange(next); + } else { + setInternalProcessTabs(update); + } + }, + [onProcessTabsChange, controlledProcessTabs], + ); + const activeTabId = controlledActiveTabId !== undefined ? controlledActiveTabId : internalActiveTabId; + const setActiveTabId = useCallback( + (id: string | null) => { + if (onActiveProcessTabIdChange) { + onActiveProcessTabIdChange(id); + } else { + setInternalActiveTabId(id); + } + }, + [onActiveProcessTabIdChange], + ); + const customTabNames = controlledCustomTabNames ?? internalCustomTabNames; + const setCustomTabNames = useCallback( + (update: Record | ((prev: Record) => Record)) => { + if (onCustomTabNamesChange) { + const next = typeof update === "function" ? update(controlledCustomTabNames ?? {}) : update; + onCustomTabNamesChange(next); + } else { + setInternalCustomTabNames(update); + } + }, + [onCustomTabNamesChange, controlledCustomTabNames], + ); const [editingTabId, setEditingTabId] = useState(null); const editInputRef = useRef(null); @@ -135,7 +196,7 @@ export function TerminalPane({ workspaceId, taskId, isExpanded, onExpand, onColl setProcessTabs((prev) => { const next = [...prev]; const [moved] = next.splice(d.fromIdx, 1); - next.splice(d.overIdx!, 0, moved); + if (moved) next.splice(d.overIdx!, 0, moved); return next; }); } @@ -306,43 +367,48 @@ export function TerminalPane({ workspaceId, taskId, isExpanded, onExpand, onColl }; }, [terminalClient]); + // Only reset on taskId change when using internal (uncontrolled) state. + // When controlled, the parent (MockLayout) owns per-task state via keyed records. useEffect(() => { - setActiveTabId(null); - setProcessTabs([]); - }, [taskId]); + if (!controlledProcessTabs) { + setActiveTabId(null); + setProcessTabs([]); + } + }, [taskId]); // eslint-disable-line react-hooks/exhaustive-deps const processes = processesQuery.data?.processes ?? []; - const openTerminalTab = useCallback((process: SandboxProcessRecord) => { - setProcessTabs((current) => { - const existing = current.find((tab) => tab.processId === process.id); - if (existing) { - setActiveTabId(existing.id); - return current; - } - - const nextTab: ProcessTab = { - id: `terminal:${process.id}`, - processId: process.id, - title: formatProcessTabTitle(process, current.length + 1), - }; - setActiveTabId(nextTab.id); - return [...current, nextTab]; - }); - }, []); - - const closeTerminalTab = useCallback((tabId: string) => { - setProcessTabs((current) => { - const next = current.filter((tab) => tab.id !== tabId); - setActiveTabId((currentActive) => { - if (currentActive === tabId) { - return next.length > 0 ? next[next.length - 1]!.id : null; + const openTerminalTab = useCallback( + (process: SandboxProcessRecord) => { + setProcessTabs((current) => { + const existing = current.find((tab) => tab.processId === process.id); + if (existing) { + setActiveTabId(existing.id); + return current; } - return currentActive; + + const nextTab: ProcessTab = { + id: `terminal:${process.id}`, + processId: process.id, + title: formatProcessTabTitle(process, current.length + 1), + }; + setActiveTabId(nextTab.id); + return [...current, nextTab]; }); - return next; - }); - }, []); + }, + [setProcessTabs, setActiveTabId], + ); + + const closeTerminalTab = useCallback( + (tabId: string) => { + const next = processTabs.filter((tab) => tab.id !== tabId); + setProcessTabs(next); + if (activeTabId === tabId) { + setActiveTabId(next.length > 0 ? next[next.length - 1]!.id : null); + } + }, + [processTabs, activeTabId, setProcessTabs, setActiveTabId], + ); const spawnTerminal = useCallback(async () => { if (!activeSandbox?.sandboxId) { @@ -527,25 +593,27 @@ export function TerminalPane({ workspaceId, taskId, isExpanded, onExpand, onColl overflow: "hidden", })} > - {/* Resize handle */} -
- {/* Full-width header bar */} + {/* Resize handle — hidden when in tab view */} + {!hideHeader && ( +
+ )} + {/* Header bar — in tab view, only show action buttons (no title/expand/chevron) */}
- - Terminal + {!hideHeader && ( + <> + + Terminal + + )}
- - {isExpanded ? : } - + {!hideHeader && onOpenTerminalTab ? ( + + + + ) : null} + {!hideHeader && ( + + {isExpanded ? : } + + )}
- {/* Two-column body: terminal left, list right — hidden when no tabs */} - {processTabs.length > 0 && ( + {/* Two-column body: terminal left, list right — visible when expanded or when tabs exist */} + {(processTabs.length > 0 || hideHeader) && (
{/* Left: terminal content */}
{renderBody()}
diff --git a/foundry/packages/frontend/src/components/mock-layout/transcript-header.tsx b/foundry/packages/frontend/src/components/mock-layout/transcript-header.tsx index 00e8b0c..17a4023 100644 --- a/foundry/packages/frontend/src/components/mock-layout/transcript-header.tsx +++ b/foundry/packages/frontend/src/components/mock-layout/transcript-header.tsx @@ -4,7 +4,7 @@ import { LabelSmall } from "baseui/typography"; import { Clock, PanelLeft, PanelRight } from "lucide-react"; import { useFoundryTokens } from "../../app/theme"; -import { PanelHeaderBar } from "./ui"; +import { PanelHeaderBar, Tooltip } from "./ui"; import { type AgentTab, type Task } from "./view-model"; export const TranscriptHeader = memo(function TranscriptHeader({ @@ -50,25 +50,27 @@ export const TranscriptHeader = memo(function TranscriptHeader({ return ( {sidebarCollapsed && onToggleSidebar ? ( -
- -
+ +
+ +
+
) : null} {editingField === "title" ? ( {task.minutesUsed ?? 0} min used
{rightSidebarCollapsed && onToggleRightSidebar ? ( -
- -
+ +
+ +
+
) : null} ); diff --git a/foundry/packages/frontend/src/components/mock-layout/ui.tsx b/foundry/packages/frontend/src/components/mock-layout/ui.tsx index 66722f1..824ee16 100644 --- a/foundry/packages/frontend/src/components/mock-layout/ui.tsx +++ b/foundry/packages/frontend/src/components/mock-layout/ui.tsx @@ -1,4 +1,5 @@ -import { memo, useCallback, useEffect, useState, type MouseEvent } from "react"; +import { memo, useCallback, useEffect, useRef, useState, type MouseEvent, type ReactNode } from "react"; +import { createPortal } from "react-dom"; import { styled, useStyletron } from "baseui"; import { GitPullRequest, GitPullRequestDraft } from "lucide-react"; @@ -210,6 +211,115 @@ export const ScrollBody = styled("div", () => ({ flexDirection: "column" as const, })); +export const Tooltip = memo(function Tooltip({ + label, + children, + placement = "bottom", +}: { + label: string; + children: ReactNode; + placement?: "top" | "bottom" | "left" | "right"; +}) { + const [css] = useStyletron(); + const t = useFoundryTokens(); + const triggerRef = useRef(null); + const tooltipRef = useRef(null); + const [pos, setPos] = useState<{ top: number; left: number } | null>(null); + + const show = useCallback(() => { + const el = triggerRef.current; + if (!el) return; + const rect = el.getBoundingClientRect(); + let top: number; + let left: number; + if (placement === "bottom") { + top = rect.bottom + 6; + left = rect.left + rect.width / 2; + } else if (placement === "top") { + top = rect.top - 6; + left = rect.left + rect.width / 2; + } else if (placement === "left") { + top = rect.top + rect.height / 2; + left = rect.left - 6; + } else { + top = rect.top + rect.height / 2; + left = rect.right + 6; + } + setPos({ top, left }); + }, [placement]); + + const hide = useCallback(() => setPos(null), []); + + // Clamp tooltip position after it renders so it stays within the viewport + useEffect(() => { + if (!pos) return; + const tip = tooltipRef.current; + if (!tip) return; + const tipRect = tip.getBoundingClientRect(); + const pad = 8; + let adjustLeft = 0; + let adjustTop = 0; + if (tipRect.right > window.innerWidth - pad) { + adjustLeft = window.innerWidth - pad - tipRect.right; + } + if (tipRect.left < pad) { + adjustLeft = pad - tipRect.left; + } + if (tipRect.bottom > window.innerHeight - pad) { + adjustTop = window.innerHeight - pad - tipRect.bottom; + } + if (tipRect.top < pad) { + adjustTop = pad - tipRect.top; + } + if (adjustLeft !== 0 || adjustTop !== 0) { + setPos((prev) => prev && { top: prev.top + adjustTop, left: prev.left + adjustLeft }); + } + }, [pos]); + + const transform = + placement === "bottom" + ? "translateX(-50%)" + : placement === "top" + ? "translateX(-50%) translateY(-100%)" + : placement === "left" + ? "translateX(-100%) translateY(-50%)" + : "translateY(-50%)"; + + return ( +
+ {children} + {pos && + createPortal( +
+ {label} +
, + document.body, + )} +
+ ); +}); + export const HEADER_HEIGHT = "42px"; export const PROMPT_TEXTAREA_MIN_HEIGHT = 56; export const PROMPT_TEXTAREA_MAX_HEIGHT = 100; diff --git a/foundry/packages/frontend/src/components/mock-layout/view-model.ts b/foundry/packages/frontend/src/components/mock-layout/view-model.ts index d22ea5c..edf8e2e 100644 --- a/foundry/packages/frontend/src/components/mock-layout/view-model.ts +++ b/foundry/packages/frontend/src/components/mock-layout/view-model.ts @@ -102,6 +102,7 @@ export function providerAgent(provider: string): AgentKind { } const DIFF_PREFIX = "diff:"; +const TERMINAL_PREFIX = "terminal:"; export function isDiffTab(id: string): boolean { return id.startsWith(DIFF_PREFIX); @@ -115,6 +116,14 @@ export function diffTabId(path: string): string { return `${DIFF_PREFIX}${path}`; } +export function isTerminalTab(id: string): boolean { + return id.startsWith(TERMINAL_PREFIX); +} + +export function terminalTabId(): string { + return `${TERMINAL_PREFIX}main`; +} + export function fileName(path: string): string { return path.split("/").pop() ?? path; } diff --git a/foundry/packages/frontend/src/components/mock-onboarding.tsx b/foundry/packages/frontend/src/components/mock-onboarding.tsx index f583397..2e60a3c 100644 --- a/foundry/packages/frontend/src/components/mock-onboarding.tsx +++ b/foundry/packages/frontend/src/components/mock-onboarding.tsx @@ -1,9 +1,11 @@ -import { useCallback, useEffect, useMemo, useState } from "react"; +import { useCallback, useEffect, useMemo, useRef, useState } from "react"; import { type FoundryBillingPlanId, type FoundryOrganization, type FoundryOrganizationMember, type FoundryUser } from "@sandbox-agent/foundry-shared"; import { useNavigate } from "@tanstack/react-router"; -import { ArrowLeft, Clock, CreditCard, FileText, Github, LogOut, Moon, Settings, Sun, Users } from "lucide-react"; +import { ArrowLeft, Clock, CreditCard, FileText, Github, LogOut, Moon, Settings, Sun, Users, Volume2 } from "lucide-react"; +import { NOTIFICATION_SOUND_OPTIONS, previewNotificationSound, useNotificationSound } from "../lib/notification-sound"; import { activeMockUser, eligibleOrganizations, useMockAppClient, useMockAppSnapshot } from "../lib/mock-app"; import { isMockFrontendClient } from "../lib/env"; +import { useIsMobile } from "../lib/platform"; import { useColorMode, useFoundryTokens } from "../app/theme"; import type { FoundryTokens } from "../styles/tokens"; import { appSurfaceStyle, primaryButtonStyle, secondaryButtonStyle, subtleButtonStyle, cardStyle, badgeStyle, inputStyle } from "../styles/shared-styles"; @@ -124,7 +126,7 @@ function statusBadge(t: FoundryTokens, organization: FoundryOrganization) { function githubBadge(t: FoundryTokens, organization: FoundryOrganization) { if (organization.github.installationStatus === "connected") { - return GitHub connected; + return GitHub connected; } if (organization.github.installationStatus === "reconnect_required") { return Reconnect required; @@ -164,9 +166,42 @@ function MemberRow({ member }: { member: FoundryOrganizationMember }) { alignItems: "center", }} > -
-
{member.name}
-
{member.email}
+
+ {member.avatarUrl ? ( + {member.name} + ) : ( +
+ {member.name.charAt(0).toUpperCase()} +
+ )} +
+
{member.name}
+
{member.email}
+
{member.role}
@@ -551,16 +586,130 @@ function SettingsLayout({ const user = activeMockUser(snapshot); const navigate = useNavigate(); const t = useFoundryTokens(); + const isMobile = useIsMobile(); const navSections: Array<{ section: SettingsSection; icon: React.ReactNode; label: string }> = [ { section: "settings", icon: , label: "Settings" }, { section: "members", icon: , label: "Members" }, - { section: "billing", icon: , label: "Billing & Invoices" }, + { section: "billing", icon: , label: "Billing" }, { section: "docs", icon: , label: "Docs" }, ]; + const goBack = () => { + void (async () => { + await client.selectOrganization(organization.id); + await navigate({ to: workspacePath(organization) }); + })(); + }; + + const handleNavClick = (item: (typeof navSections)[0]) => { + if (item.section === "billing") { + void navigate({ to: billingPath(organization) }); + } else if (onSectionChange) { + onSectionChange(item.section); + } else { + void navigate({ to: settingsPath(organization) }); + } + }; + + if (isMobile) { + return ( +
+ {/* Mobile header */} +
+ +
+
{organization.settings.displayName}
+
{planCatalog[organization.billing.planId]?.label ?? "Free"} Plan
+
+
+ + {/* Mobile tab strip */} +
+ {navSections.map((item) => { + const isActive = activeSection === item.section; + return ( + + ); + })} +
+ + {/* Content */} +
+
{children}
+
+
+ ); + } + return ( -
+
{/* Left nav */} @@ -579,12 +728,7 @@ function SettingsLayout({ {/* Back to workspace */}
@@ -692,6 +828,8 @@ export function MockOrganizationSettingsPage({ organization }: { organization: F + + +
+

Account

+

Manage your personal account settings.

+
+ + +
+ {user?.avatarUrl ? ( + {user.name} + ) : ( +
+ {(user?.name ?? "U").charAt(0).toUpperCase()} +
+ )} +
+
{user?.name ?? "User"}
+
@{user?.githubLogin ?? ""}
+
+
+ + + +
+ +
+
+ + + + + + +
+ +
+
+ + + + Delete + + } + /> + +
+ ); + + if (isMobile) { + return ( +
+ {/* Mobile header */} +
+ +
Account
+
+ + {/* Content */} +
+
{accountContent}
+
+
+ ); + } + return ( -
+
{/* Left nav */} @@ -1131,9 +1430,32 @@ export function MockAccountSettingsPage() { Back to workspace -
- {user?.name ?? "User"} - {user?.email ?? ""} +
+ {user?.avatarUrl ? ( + {user.name} + ) : ( +
+ {(user?.name ?? "U").charAt(0).toUpperCase()} +
+ )} +
+ {user?.name ?? "User"} + {user?.email ?? ""} +
} label="General" active onClick={() => {}} /> @@ -1141,77 +1463,7 @@ export function MockAccountSettingsPage() { {/* Content */}
-
-
-
-

Account

-

Manage your personal account settings.

-
- - - - - -
- -
-
- - - - - - -
- -
-
- - - - Delete - - } - /> - -
-
+
{accountContent}
@@ -1238,7 +1490,7 @@ function AppearanceSection() { height: "20px", borderRadius: "10px", border: "1px solid rgba(128, 128, 128, 0.3)", - background: isDark ? t.borderDefault : t.accent, + background: isDark ? t.borderDefault : t.textPrimary, cursor: "pointer", padding: 0, transition: "background 0.2s", @@ -1260,7 +1512,7 @@ function AppearanceSection() { justifyContent: "center", }} > - {isDark ? : } + {isDark ? : }
} @@ -1268,3 +1520,130 @@ function AppearanceSection() { ); } + +function NotificationSoundSection() { + const t = useFoundryTokens(); + const [selected, setSelected] = useNotificationSound(); + const [open, setOpen] = useState(false); + const containerRef = useRef(null); + const selectedLabel = NOTIFICATION_SOUND_OPTIONS.find((o) => o.id === selected)?.label ?? "None"; + + useEffect(() => { + if (!open) return; + const handler = (e: MouseEvent) => { + if (containerRef.current && !containerRef.current.contains(e.target as Node)) { + setOpen(false); + } + }; + document.addEventListener("mousedown", handler); + return () => document.removeEventListener("mousedown", handler); + }, [open]); + + return ( + + + + {open && ( +
+ {NOTIFICATION_SOUND_OPTIONS.map((option) => { + const isActive = option.id === selected; + return ( + + ); + })} +
+ )} +
+ } + /> + + ); +} diff --git a/foundry/packages/frontend/src/lib/notification-sound.ts b/foundry/packages/frontend/src/lib/notification-sound.ts new file mode 100644 index 0000000..f78b955 --- /dev/null +++ b/foundry/packages/frontend/src/lib/notification-sound.ts @@ -0,0 +1,77 @@ +import { useCallback, useEffect, useRef, useSyncExternalStore } from "react"; + +export type NotificationSoundId = "none" | "chime" | "ping"; + +const SOUNDS: Record, { label: string; src: string }> = { + chime: { label: "Chime", src: "/sounds/notification-1.mp3" }, + ping: { label: "Ping", src: "/sounds/notification-2.mp3" }, +}; + +const STORAGE_KEY = "foundry:notification-sound"; + +let currentValue: NotificationSoundId = (localStorage.getItem(STORAGE_KEY) as NotificationSoundId) || "none"; +const listeners = new Set<() => void>(); + +function notify() { + for (const listener of listeners) { + listener(); + } +} + +function getSnapshot(): NotificationSoundId { + return currentValue; +} + +function subscribe(listener: () => void): () => void { + listeners.add(listener); + return () => listeners.delete(listener); +} + +export function setNotificationSound(id: NotificationSoundId) { + currentValue = id; + localStorage.setItem(STORAGE_KEY, id); + notify(); +} + +export function useNotificationSound(): [NotificationSoundId, (id: NotificationSoundId) => void] { + const value = useSyncExternalStore(subscribe, getSnapshot); + return [value, setNotificationSound]; +} + +export function playNotificationSound() { + const id = getSnapshot(); + if (id === "none") return; + const sound = SOUNDS[id]; + if (!sound) return; + const audio = new Audio(sound.src); + audio.volume = 0.6; + audio.play().catch(() => {}); +} + +export function previewNotificationSound(id: NotificationSoundId) { + if (id === "none") return; + const sound = SOUNDS[id]; + if (!sound) return; + const audio = new Audio(sound.src); + audio.volume = 0.6; + audio.play().catch(() => {}); +} + +export function useAgentDoneNotification(status: "running" | "idle" | "error" | undefined) { + const prevStatus = useRef(status); + + useEffect(() => { + const prev = prevStatus.current; + prevStatus.current = status; + + if (prev === "running" && status === "idle") { + playNotificationSound(); + } + }, [status]); +} + +export const NOTIFICATION_SOUND_OPTIONS: { id: NotificationSoundId; label: string }[] = [ + { id: "none", label: "None" }, + { id: "chime", label: "Chime" }, + { id: "ping", label: "Ping" }, +]; diff --git a/foundry/packages/frontend/src/lib/platform.ts b/foundry/packages/frontend/src/lib/platform.ts new file mode 100644 index 0000000..1952133 --- /dev/null +++ b/foundry/packages/frontend/src/lib/platform.ts @@ -0,0 +1,55 @@ +import { useSyncExternalStore } from "react"; + +const MOBILE_BREAKPOINT = 768; + +/** True when built with VITE_MOBILE=1 (Tauri mobile build) */ +export const isNativeMobile = !!import.meta.env.VITE_MOBILE; + +/** True when built with VITE_DESKTOP=1 (Tauri desktop build) */ +export const isNativeDesktop = !!import.meta.env.VITE_DESKTOP; + +/** True when running inside any Tauri shell */ +export const isNativeApp = isNativeMobile || isNativeDesktop; + +function getIsMobileViewport(): boolean { + if (typeof window === "undefined") return false; + return window.innerWidth < MOBILE_BREAKPOINT; +} + +let currentIsMobile = isNativeMobile || getIsMobileViewport(); + +const listeners = new Set<() => void>(); + +if (typeof window !== "undefined") { + const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`); + mql.addEventListener("change", (e) => { + const next = isNativeMobile || e.matches; + if (next !== currentIsMobile) { + currentIsMobile = next; + for (const fn of listeners) fn(); + } + }); +} + +function subscribe(cb: () => void) { + listeners.add(cb); + return () => { + listeners.delete(cb); + }; +} + +function getSnapshot() { + return currentIsMobile; +} + +/** + * Returns true when the app should render in mobile layout. + * This is true when: + * - Built with VITE_MOBILE=1 (always mobile), OR + * - Viewport width is below 768px (responsive web) + * + * Re-renders when the viewport crosses the breakpoint. + */ +export function useIsMobile(): boolean { + return useSyncExternalStore(subscribe, getSnapshot, () => false); +} diff --git a/foundry/packages/frontend/src/styles.css b/foundry/packages/frontend/src/styles.css index 9967938..a9567e6 100644 --- a/foundry/packages/frontend/src/styles.css +++ b/foundry/packages/frontend/src/styles.css @@ -5,6 +5,10 @@ font-family: "IBM Plex Sans", "Segoe UI", sans-serif; background: var(--f-surface-primary, #000000); color: var(--f-text-primary, #ffffff); + --safe-area-top: env(safe-area-inset-top, 0px); + --safe-area-bottom: env(safe-area-inset-bottom, 0px); + --safe-area-left: env(safe-area-inset-left, 0px); + --safe-area-right: env(safe-area-inset-right, 0px); } html, @@ -44,6 +48,41 @@ a { } } +@keyframes hf-dot-fade { + 0%, 80%, 100% { + opacity: 0.2; + } + 40% { + opacity: 1; + } +} + +@keyframes hf-typing-in { + from { + opacity: 0; + max-height: 0; + transform: translateY(8px); + } + to { + opacity: 1; + max-height: 40px; + transform: translateY(0); + } +} + +@keyframes hf-typing-out { + from { + opacity: 1; + max-height: 40px; + transform: translateY(0); + } + to { + opacity: 0; + max-height: 0; + transform: translateY(8px); + } +} + button, input, textarea, diff --git a/foundry/packages/shared/src/app-shell.ts b/foundry/packages/shared/src/app-shell.ts index 8e757c5..f309b0e 100644 --- a/foundry/packages/shared/src/app-shell.ts +++ b/foundry/packages/shared/src/app-shell.ts @@ -10,6 +10,7 @@ export interface FoundryUser { name: string; email: string; githubLogin: string; + avatarUrl: string | null; roleLabel: string; eligibleOrganizationIds: string[]; } @@ -20,6 +21,8 @@ export interface FoundryOrganizationMember { email: string; role: "owner" | "admin" | "member"; state: "active" | "invited"; + avatarUrl: string | null; + githubLogin: string | null; } export interface FoundryInvoice { diff --git a/foundry/packages/shared/src/workbench.ts b/foundry/packages/shared/src/workbench.ts index 21118b7..d4898fc 100644 --- a/foundry/packages/shared/src/workbench.ts +++ b/foundry/packages/shared/src/workbench.ts @@ -76,6 +76,14 @@ export interface WorkbenchPullRequestSummary { status: "draft" | "ready"; } +export interface WorkbenchPresence { + memberId: string; + name: string; + avatarUrl: string | null; + lastSeenAtMs: number; + typing?: boolean; +} + export interface WorkbenchTask { id: string; repoId: string; @@ -90,6 +98,7 @@ export interface WorkbenchTask { diffs: Record; fileTree: WorkbenchFileTreeNode[]; minutesUsed: number; + presence: WorkbenchPresence[]; } export interface WorkbenchRepo {