History

desktop app, setup page, keychain secrets, release pipeline

- Electron desktop app with sidecar CLI binary bundling - Setup page on marketing site with OS-detected download buttons - GitHub Actions workflow for building desktop distributables - Re-enable keychain secrets plugin - Fix React production build (resolve.dedupe) - Support EXECUTOR_SCOPE_DIR env var for scope selection

Rhys Sullivan committed 7 months ago

Commit e4bd2fa1 parent 723b8f313 files · +470 −138Browse files

Unified · Split

13 files
  1. .changeset/desktop-app-release.md +5 −0
  2. .github/workflows/publish-desktop.yml +146 −0
  3. .github/workflows/publish-executor-package.yml +1 −1
  4. .github/workflows/release.yml +3 −2
  5. .gitignore +4 −1
  6. apps/desktop/package.json +43 −6
  7. apps/desktop/scripts/bundle-cli.js +58 −0
  8. apps/desktop/src/main.ts +32 −13
  9. apps/marketing/src/pages/index.astro +13 −82
  10. apps/marketing/src/pages/setup.astro +159 −0
  11. apps/server/src/services/executor.ts +3 −3
  12. bun.lock +2 −29
  13. package.json +1 −1
.changeset/desktop-app-release.md+5−0
@@ -0,0 +1,5 @@
1+---
2+"executor": minor
3+---
4+
5+Desktop app, setup page, and re-enable keychain secrets
.github/workflows/publish-desktop.yml+146−0
@@ -0,0 +1,146 @@
1+name: Publish Desktop App
2+run-name: "${{ format('publish desktop {0}', github.event_name == 'workflow_dispatch' && inputs.tag || github.ref_name) }}"
3+
4+on:
5+ push:
6+ tags:
7+ - "v*"
8+ workflow_dispatch:
9+ inputs:
10+ tag:
11+ description: Git tag to publish
12+ required: true
13+ type: string
14+
15+permissions:
16+ contents: write
17+
18+concurrency:
19+ group: publish-desktop-${{ github.ref }}
20+ cancel-in-progress: false
21+
22+jobs:
23+ build:
24+ strategy:
25+ fail-fast: false
26+ matrix:
27+ include:
28+ - os: macos-latest
29+ arch: arm64
30+ platform: mac
31+ - os: macos-13
32+ arch: x64
33+ platform: mac
34+ - os: ubuntu-latest
35+ arch: x64
36+ platform: linux
37+ - os: windows-latest
38+ arch: x64
39+ platform: win
40+
41+ runs-on: ${{ matrix.os }}
42+
43+ steps:
44+ - name: Checkout
45+ uses: actions/checkout@v4
46+ with:
47+ ref: ${{ github.event_name == 'workflow_dispatch' && format('refs/tags/{0}', inputs.tag) || github.ref }}
48+
49+ - name: Setup Bun
50+ uses: oven-sh/setup-bun@v2
51+ with:
52+ bun-version: 1.3.11
53+
54+ - name: Setup Node
55+ uses: actions/setup-node@v4
56+ with:
57+ node-version: 24
58+
59+ - name: Install dependencies
60+ run: bun install --frozen-lockfile
61+
62+ - name: Build web app
63+ run: bun run build
64+ working-directory: apps/web
65+
66+ - name: Build CLI sidecar binary
67+ run: bun run src/build.ts binary --single
68+ working-directory: apps/cli
69+
70+ - name: Copy sidecar to desktop resources
71+ shell: bash
72+ run: |
73+ mkdir -p apps/desktop/resources
74+ if [ "${{ matrix.platform }}" = "win" ]; then
75+ BINARY_NAME="executor.exe"
76+ else
77+ BINARY_NAME="executor"
78+ fi
79+
80+ PLATFORM="${{ matrix.platform == 'mac' && 'darwin' || matrix.platform == 'win' && 'windows' || 'linux' }}"
81+ ARCH="${{ matrix.arch }}"
82+ SRC="apps/cli/dist/executor-${PLATFORM}-${ARCH}/bin"
83+
84+ cp "${SRC}/${BINARY_NAME}" "apps/desktop/resources/${BINARY_NAME}"
85+ chmod +x "apps/desktop/resources/${BINARY_NAME}" 2>/dev/null || true
86+
87+ if [ -f "${SRC}/emscripten-module.wasm" ]; then
88+ cp "${SRC}/emscripten-module.wasm" "apps/desktop/resources/"
89+ fi
90+
91+ - name: Build desktop app (TypeScript)
92+ run: npx tsc -p tsconfig.json
93+ working-directory: apps/desktop
94+
95+ - name: Build desktop distributables
96+ env:
97+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
98+ run: npx electron-builder --${{ matrix.platform }} --${{ matrix.arch }} --publish never
99+ working-directory: apps/desktop
100+
101+ - name: Upload artifacts
102+ uses: actions/upload-artifact@v4
103+ with:
104+ name: desktop-${{ matrix.platform }}-${{ matrix.arch }}
105+ path: |
106+ apps/desktop/dist/*.dmg
107+ apps/desktop/dist/*.zip
108+ apps/desktop/dist/*.exe
109+ apps/desktop/dist/*.AppImage
110+ apps/desktop/dist/*.deb
111+ if-no-files-found: warn
112+
113+ release:
114+ needs: build
115+ runs-on: ubuntu-latest
116+
117+ steps:
118+ - name: Download all artifacts
119+ uses: actions/download-artifact@v4
120+ with:
121+ path: artifacts
122+ merge-multiple: true
123+
124+ - name: List artifacts
125+ run: find artifacts -type f | head -20
126+
127+ - name: Upload to GitHub Release
128+ env:
129+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
130+ TAG: ${{ github.event_name == 'workflow_dispatch' && inputs.tag || github.ref_name }}
131+ run: |
132+ # Wait for the CLI release to create the GitHub release first
133+ for i in $(seq 1 30); do
134+ if gh release view "$TAG" --repo "$GITHUB_REPOSITORY" >/dev/null 2>&1; then
135+ echo "Release $TAG found"
136+ break
137+ fi
138+ echo "Waiting for release $TAG to be created... ($i/30)"
139+ sleep 10
140+ done
141+
142+ # Upload desktop artifacts
143+ find artifacts -type f \( -name "*.dmg" -o -name "*.zip" -o -name "*.exe" -o -name "*.AppImage" -o -name "*.deb" \) | while read file; do
144+ echo "Uploading: $file"
145+ gh release upload "$TAG" "$file" --repo "$GITHUB_REPOSITORY" --clobber || true
146+ done
.github/workflows/publish-executor-package.yml+1−1
@@ -34,7 +34,7 @@ jobs: · 33 unmodified lines
3434 - name: Setup Bun
3535 uses: oven-sh/setup-bun@v2
3636 with:
37− bun-version: 1.3.10
37+ bun-version: 1.3.11
3838
3939 - name: Setup Node
4040 uses: actions/setup-node@v4
.github/workflows/release.yml+3−2
@@ -29,7 +29,7 @@ jobs: · 28 unmodified lines
2929 - name: Setup Bun
3030 uses: oven-sh/setup-bun@v2
3131 with:
32− bun-version: 1.3.10
32+ bun-version: 1.3.11
3333
3434 - name: Setup Node
3535 uses: actions/setup-node@v4
@@ -88,10 +88,11 @@ jobs: · 52 unmodified lines
8888 git tag "$tag"
8989 git push origin "$tag"
9090
91− - name: Trigger publish workflow
91+ - name: Trigger publish workflows
9292 if: steps.changesets.outputs.hasChangesets == 'false' && steps.detect_release.outputs.changed == 'true'
9393 env:
9494 GH_TOKEN: ${{ github.token }}
9595 run: |
9696 tag="v${{ steps.detect_release.outputs.version }}"
9797 gh workflow run publish-executor-package.yml --ref "$tag" -f tag="$tag"
98+ gh workflow run publish-desktop.yml --ref "$tag" -f tag="$tag"
.gitignore+4−1
@@ -36,4 +36,7 @@ report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json · 35 unmodified lines
3636 personal-notes/
3737 *.har.executor
3838 executor.har
39−.executor/
39+.executor/
40+
41+# desktop app build artifacts
42+apps/desktop/resources/
apps/desktop/package.json+43−6
@@ -2,18 +2,23 @@ · 1 unmodified line
22 "name": "@executor/desktop",
33 "version": "1.4.0",
44 "private": true,
5+ "description": "Executor desktop app",
6+ "author": "Rhys Sullivan",
57 "main": "dist/main.js",
68 "scripts": {
79 "dev": "node scripts/dev.js",
8− "build": "tsc && electron-builder",
10+ "build": "tsc -p tsconfig.json",
11+ "bundle-cli": "node scripts/bundle-cli.js",
12+ "dist": "npm run build && npm run bundle-cli && electron-builder",
13+ "dist:mac": "npm run build && npm run bundle-cli && electron-builder --mac",
14+ "dist:win": "npm run build && npm run bundle-cli && electron-builder --win",
15+ "dist:linux": "npm run build && npm run bundle-cli && electron-builder --linux",
916 "typecheck": "tsc --noEmit"
1017 },
11− "dependencies": {
12− "electron-store": "^10.0.0"
13− },
18+ "dependencies": {},
1419 "devDependencies": {
1520 "@types/node": "catalog:",
16− "electron": "^35.0.1",
21+ "electron": "35.7.5",
1722 "electron-builder": "^26.0.12",
1823 "typescript": "^5.9.3"
1924 },
@@ -23,8 +28,40 @@ · 3 unmodified lines
2328 "files": [
2429 "dist/**/*"
2530 ],
31+ "extraResources": [
32+ {
33+ "from": "resources/",
34+ "to": "",
35+ "filter": ["executor*", "emscripten-module.wasm"]
36+ }
37+ ],
2638 "mac": {
27− "category": "public.app-category.developer-tools"
39+ "category": "public.app-category.developer-tools",
40+ "target": [
41+ { "target": "dmg", "arch": ["arm64", "x64"] },
42+ { "target": "zip", "arch": ["arm64", "x64"] }
43+ ],
44+ "icon": "build/icon.icns"
45+ },
46+ "win": {
47+ "target": ["nsis"],
48+ "icon": "build/icon.ico"
49+ },
50+ "linux": {
51+ "target": ["AppImage", "deb"],
52+ "category": "Development",
53+ "icon": "build/icons"
54+ },
55+ "dmg": {
56+ "title": "Executor",
57+ "contents": [
58+ { "x": 130, "y": 220 },
59+ { "x": 410, "y": 220, "type": "link", "path": "/Applications" }
60+ ]
61+ },
62+ "nsis": {
63+ "oneClick": false,
64+ "allowToChangeInstallationDirectory": true
2865 }
2966 }
3067 }
apps/desktop/scripts/bundle-cli.js+58−0
@@ -0,0 +1,58 @@
1+/**
2+ * Builds the executor CLI binary and copies it into the desktop app's
3+ * resources/ folder so electron-builder can bundle it as a sidecar.
4+ */
5+const { execSync, spawnSync } = require("node:child_process");
6+const { existsSync, mkdirSync, cpSync, chmodSync } = require("node:fs");
7+const { resolve, join } = require("node:path");
8+
9+const root = resolve(__dirname, "..");
10+const repoRoot = resolve(root, "../..");
11+const cliRoot = resolve(repoRoot, "apps/cli");
12+const resourcesDir = resolve(root, "resources");
13+
14+// Build CLI for current platform
15+console.log("Building executor CLI binary...");
16+
17+// Resolve bun binary path explicitly
18+const { homedir } = require("node:os");
19+const bunBin = resolve(process.env.BUN_INSTALL || join(homedir(), ".bun"), "bin", "bun");
20+
21+const result = spawnSync(bunBin, ["run", "src/build.ts", "binary", "--single"], {
22+ cwd: cliRoot,
23+ stdio: "inherit",
24+});
25+
26+if (result.error) {
27+ console.error("CLI build spawn error:", result.error.message);
28+ process.exit(1);
29+}
30+
31+if (result.status !== 0) {
32+ console.error(`CLI build failed with exit code ${result.status}`);
33+ process.exit(1);
34+}
35+
36+// Find the built binary
37+const platform = process.platform === "win32" ? "windows" : process.platform;
38+const arch = process.arch === "arm64" ? "arm64" : "x64";
39+const binaryName = process.platform === "win32" ? "executor.exe" : "executor";
40+const targetDir = join(cliRoot, "dist", `executor-${platform}-${arch}`, "bin");
41+
42+if (!existsSync(join(targetDir, binaryName))) {
43+ console.error(`Binary not found at ${join(targetDir, binaryName)}`);
44+ process.exit(1);
45+}
46+
47+// Copy to resources/
48+mkdirSync(resourcesDir, { recursive: true });
49+cpSync(join(targetDir, binaryName), join(resourcesDir, binaryName));
50+chmodSync(join(resourcesDir, binaryName), 0o755);
51+
52+// Copy QuickJS WASM if present
53+const wasmPath = join(targetDir, "emscripten-module.wasm");
54+if (existsSync(wasmPath)) {
55+ cpSync(wasmPath, join(resourcesDir, "emscripten-module.wasm"));
56+}
57+
58+console.log(`Sidecar binary copied to ${resourcesDir}`);
apps/desktop/src/main.ts+32−13
@@ -63,16 +63,31 @@ let serverProcess: ChildProcess | null = null; · 62 unmodified lines
6363 let currentScope: string | null = null;
6464 let currentPort = DEFAULT_PORT;
6565
66−const findServerScript = (): string => {
67− // In development, use the CLI source directly
68− const cliMain = resolve(__dirname, "../../cli/src/main.ts");
69− if (existsSync(cliMain)) return cliMain;
66+const isDev = !app.isPackaged;
67+
68+const binaryName = process.platform === "win32" ? "executor.exe" : "executor";
69+
70+/**
71+ * Returns { command, args, cwd } for spawning the server.
72+ * - In dev mode: uses `bun run` with the CLI source
73+ * - In production: uses the bundled sidecar binary
74+ */
75+const resolveServerCommand = (): { command: string; args: string[] } => {
76+ if (isDev) {
77+ const cliMain = resolve(__dirname, "../../cli/src/main.ts");
78+ if (existsSync(cliMain)) {
79+ return { command: "bun", args: ["run", cliMain] };
80+ }
81+ throw new Error("Could not find executor CLI entry point for dev mode");
82+ }
7083
71− // Fallback: look for compiled CLI
72− const cliBin = resolve(__dirname, "../../cli/bin/executor.ts");
73− if (existsSync(cliBin)) return cliBin;
84+ // Production: sidecar binary bundled via extraResources
85+ const sidecar = join(process.resourcesPath, binaryName);
86+ if (existsSync(sidecar)) {
87+ return { command: sidecar, args: [] };
88+ }
7489
75− throw new Error("Could not find executor CLI entry point");
90+ throw new Error(`Sidecar binary not found at ${sidecar}`);
7691 };
7792
7893 const isServerReady = async (port: number): Promise<boolean> => {
@@ -117,13 +132,17 @@ const startServer = async ( · 38 unmodified lines
117132 currentScope = scopePath;
118133 currentPort = port;
119134
120− const script = findServerScript();
121− const args = ["run", script, "web", "--port", String(port)];
135+ const server = resolveServerCommand();
136+ const args = [...server.args, "web", "--port", String(port)];
137+
138+ // In dev mode, run from repo root so bun can resolve workspace deps.
139+ // In production, the sidecar is self-contained.
140+ const cwd = isDev ? resolve(__dirname, "../../..") : scopePath;
122141
123− serverProcess = spawn("bun", args, {
124− cwd: scopePath,
142+ serverProcess = spawn(server.command, args, {
143+ cwd,
125144 stdio: ["ignore", "pipe", "pipe"],
126− env: { ...process.env },
145+ env: { ...process.env, EXECUTOR_SCOPE_DIR: scopePath },
127146 });
128147
129148 serverProcess.stdout?.on("data", (data: Buffer) => {
apps/marketing/src/pages/index.astro+13−82
@@ -1,8 +1,5 @@
11 ---
22 import Layout from '../layouts/Layout.astro'
3−
4−const mcpCode = `<span class="text-ink-muted">$</span> executor mcp --stdio
5−<span class="text-ink-faint"> 482 tools · policies active · auth shared</span>`
63 ---
74
85 <Layout>
@@ -11,11 +8,11 @@ const mcpCode = `<span class="text-ink-muted">$</span> executor mcp --stdio · 2 unmodified lines
118 <div class="max-w-[1200px] mx-auto px-6 sm:px-10 h-14 flex items-center justify-between border-b border-rule">
129 <a href="/" class="font-display text-xl italic text-ink tracking-tight hover:text-teal transition-colors">executor</a>
1310 <div class="flex items-center gap-8">
14− <a href="#how-it-works" class="hidden sm:block text-[13px] text-ink-muted hover:text-ink transition-colors">How it works</a>
1511 <a href="#roadmap" class="hidden sm:block text-[13px] text-ink-muted hover:text-ink transition-colors">Roadmap</a>
12+ <a href="/setup" class="hidden sm:block text-[13px] text-ink-muted hover:text-ink transition-colors">Setup</a>
1613 <a href="https://github.com/RhysSullivan/executor" class="hidden sm:block text-[13px] text-ink-muted hover:text-ink transition-colors">GitHub</a>
17− <a href="https://github.com/RhysSullivan/executor" class="text-[13px] font-medium text-surface bg-teal hover:bg-teal-dim px-4 py-1.5 rounded-md transition-colors">
18− Get started
14+ <a href="/setup" class="text-[13px] font-medium text-surface bg-teal hover:bg-teal-dim px-4 py-1.5 rounded-md transition-colors">
15+ Download
1916 </a>
2017 </div>
2118 </div>
@@ -38,13 +35,10 @@ const mcpCode = `<span class="text-ink-muted">$</span> executor mcp --stdio · 16 unmodified lines
3835 </p>
3936
4037 <div class="rise-d3 flex flex-wrap items-center justify-center gap-4">
41− <a href="https://github.com/RhysSullivan/executor" class="inline-flex items-center gap-2 text-[14px] font-medium text-surface bg-teal hover:bg-teal-dim px-5 py-2.5 rounded-md transition-colors">
38+ <a href="/setup" class="inline-flex items-center gap-2 text-[14px] font-medium text-surface bg-teal hover:bg-teal-dim px-5 py-2.5 rounded-md transition-colors">
4239 Get started
4340 <svg class="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M13 7l5 5m0 0l-5 5m5-5H6" /></svg>
4441 </a>
45− <a href="#how-it-works" class="inline-flex items-center gap-2 text-[14px] text-ink-muted hover:text-ink border border-rule hover:border-ink-faint px-5 py-2.5 rounded-md transition-colors">
46− How it works
47− </a>
4842 </div>
4943 </div>
5044
@@ -686,75 +680,6 @@ const mcpCode = `<span class="text-ink-muted">$</span> executor mcp --stdio · 635 unmodified lines
686680 </div>
687681 </section>
688682
689− <!-- ─── HOW IT WORKS: compact ─── -->
690− <section id="how-it-works" class="py-32 sm:py-40 relative">
691− <div class="max-w-[1200px] mx-auto px-6 sm:px-10">
692− <div class="reveal mb-20">
693− <span class="text-[11px] font-mono uppercase tracking-[0.2em] text-ink-faint mb-4 block">How it works</span>
694− <h2 class="font-display text-[clamp(2rem,4.5vw,3.5rem)] leading-[1.05] tracking-tight">
695− Four steps to<br /><span class="italic text-teal">every integration</span>
696− </h2>
697− </div>
698−
699− <!-- Horizontal steps on desktop -->
700− <div class="reveal grid md:grid-cols-4 gap-px bg-rule rounded-xl overflow-hidden mb-16">
701− <div class="bg-surface p-6 sm:p-8">
702− <span class="font-display text-4xl text-teal/20 leading-none block mb-4">1</span>
703− <h3 class="text-[14px] font-medium mb-2">Add sources</h3>
704− <p class="text-[13px] text-ink-muted">Point at any API. If it has a schema, Executor indexes it.</p>
705− </div>
706− <div class="bg-surface p-6 sm:p-8">
707− <span class="font-display text-4xl text-teal/20 leading-none block mb-4">2</span>
708− <h3 class="text-[14px] font-medium mb-2">Tools are indexed</h3>
709− <p class="text-[13px] text-ink-muted">Every endpoint becomes a typed, discoverable tool in your catalog.</p>
710− </div>
711− <div class="bg-surface p-6 sm:p-8">
712− <span class="font-display text-4xl text-teal/20 leading-none block mb-4">3</span>
713− <h3 class="text-[14px] font-medium mb-2">Set policies</h3>
714− <p class="text-[13px] text-ink-muted">Define what's auto-approved and what needs human sign-off.</p>
715− </div>
716− <div class="bg-surface p-6 sm:p-8">
717− <span class="font-display text-4xl text-teal/20 leading-none block mb-4">4</span>
718− <h3 class="text-[14px] font-medium mb-2">Connect agents</h3>
719− <p class="text-[13px] text-ink-muted">Expose your catalog over MCP. Any agent gets your tools and auth.</p>
720− </div>
721− </div>
722−
723− <!-- Single code block showing the MCP bridge -->
724− <div class="reveal max-w-lg mx-auto">
725− <div class="bg-surface-raised border border-rule rounded-lg overflow-hidden">
726− <div class="px-4 py-2.5 border-b border-rule">
727− <span class="text-[11px] font-mono text-ink-faint">terminal</span>
728− </div>
729− <div class="p-5 font-mono text-[13px] leading-[1.8]">
730− <pre set:html={mcpCode} />
731− </div>
732− </div>
733− </div>
734− </div>
735− </section>
736−
737− <!-- ─── SOURCES: visual strip ─── -->
738− <section class="py-20 relative">
739− <div class="absolute inset-0 border-t border-b border-rule"></div>
740−
741− <div class="relative max-w-[1200px] mx-auto px-6 sm:px-10">
742− <div class="flex flex-wrap items-center justify-between gap-6">
743− <span class="text-[13px] text-ink-muted">If you can represent it in JSON schema, it's an integration</span>
744− <div class="flex items-center gap-4 sm:gap-8">
745− <span class="font-mono text-[13px] text-teal/70">OpenAPI</span>
746− <span class="text-ink-faint">&middot;</span>
747− <span class="font-mono text-[13px] text-teal/70">GraphQL</span>
748− <span class="text-ink-faint">&middot;</span>
749− <span class="font-mono text-[13px] text-teal/70">MCP</span>
750− <span class="text-ink-faint">&middot;</span>
751− <span class="font-mono text-[13px] text-teal/70">Google Discovery</span>
752− <span class="text-ink-faint">&middot;</span>
753− <span class="font-mono text-[13px] text-ink-muted italic">yours</span>
754− </div>
755− </div>
756− </div>
757− </section>
758683
759684 <!-- ─── ROADMAP ─── -->
760685 <section id="roadmap" class="py-32 sm:py-40 relative">
@@ -792,6 +717,10 @@ const mcpCode = `<span class="text-ink-muted">$</span> executor mcp --stdio · 31 unmodified lines
792717 <svg class="w-4 h-4 text-teal mt-0.5 shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5" /></svg>
793718 <span class="text-ink-muted">Local web UI</span>
794719 </li>
720+ <li class="flex items-start gap-2.5">
721+ <svg class="w-4 h-4 text-teal mt-0.5 shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5" /></svg>
722+ <span class="text-ink-muted">Desktop app</span>
723+ </li>
795724 </ul>
796725 </div>
797726 </div>
@@ -803,7 +732,6 @@ const mcpCode = `<span class="text-ink-muted">$</span> executor mcp --stdio · 5 unmodified lines
803732 <span class="font-mono text-[11px] text-ink-muted uppercase tracking-[0.15em]">Soon</span>
804733 </div>
805734 <ul class="space-y-3 text-[14px]">
806− <li class="text-ink-muted">Desktop app</li>
807735 <li class="text-ink-muted">Team management &amp; SaaS</li>
808736 <li class="text-ink-muted">Advanced approval workflows</li>
809737 <li class="text-ink-muted">Org-wide source catalog</li>
@@ -838,9 +766,12 @@ const mcpCode = `<span class="text-ink-muted">$</span> executor mcp --stdio · 28 unmodified lines
838766 </h2>
839767
840768 <div class="flex flex-col sm:flex-row items-center justify-center gap-4 mb-10">
841− <a href="https://github.com/RhysSullivan/executor" class="inline-flex items-center gap-2 text-[14px] font-medium text-surface bg-teal hover:bg-teal-dim px-6 py-3 rounded-md transition-colors">
769+ <a href="/setup" class="inline-flex items-center gap-2 text-[14px] font-medium text-surface bg-teal hover:bg-teal-dim px-6 py-3 rounded-md transition-colors">
842770 Get started
843− <svg class="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M13 7l5 5m0 0l-5 5m5-5H6" /></svg>
771+ <svg class="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M19 14l-7 7m0 0l-7-7m7 7V3"/></svg>
772+ </a>
773+ <a href="https://github.com/RhysSullivan/executor" class="inline-flex items-center gap-2 text-[14px] text-ink-muted hover:text-ink border border-rule hover:border-ink-faint px-6 py-3 rounded-md transition-colors">
774+ View on GitHub
844775 </a>
845776 </div>
846777
apps/marketing/src/pages/setup.astro+159−0
@@ -0,0 +1,159 @@
1+---
2+import Layout from '../layouts/Layout.astro'
3+---
4+
5+<Layout title="Setup Executor" description="Get started with Executor — download the desktop app or install via CLI.">
6+ <!-- ─── NAV ─── -->
7+ <nav class="fixed top-0 w-full z-50 bg-surface/80 backdrop-blur-lg">
8+ <div class="max-w-[1200px] mx-auto px-6 sm:px-10 h-14 flex items-center justify-between border-b border-rule">
9+ <a href="/" class="font-display text-xl italic text-ink tracking-tight hover:text-teal transition-colors">executor</a>
10+ <div class="flex items-center gap-8">
11+ <a href="/setup" class="hidden sm:block text-[13px] text-ink hover:text-ink transition-colors">Setup</a>
12+ <a href="https://github.com/RhysSullivan/executor" class="hidden sm:block text-[13px] text-ink-muted hover:text-ink transition-colors">GitHub</a>
13+ </div>
14+ </div>
15+ </nav>
16+
17+ <main class="pt-14">
18+ <section class="py-24 sm:py-32 relative">
19+ <div class="absolute top-[20%] left-[50%] -translate-x-1/2 w-[600px] h-[400px] bg-teal/[0.03] rounded-full blur-[150px] pointer-events-none"></div>
20+
21+ <div class="max-w-[1200px] mx-auto px-6 sm:px-10">
22+ <div class="text-center max-w-2xl mx-auto mb-16">
23+ <h1 class="font-display text-[clamp(2.5rem,5vw,4rem)] leading-[1.05] tracking-tight mb-6">
24+ Get started with <span class="italic text-teal">Executor</span>
25+ </h1>
26+ <p class="text-[16px] leading-[1.7] text-ink-muted">
27+ Manage sources, secrets, and tools from a native desktop app &mdash; or run straight from the command line.
28+ </p>
29+ </div>
30+
31+ <!-- ─── PRIMARY: auto-detected download ─── -->
32+ <div class="max-w-md mx-auto text-center mb-6" id="primary-download">
33+ <a id="primary-btn" href="#" class="inline-flex items-center gap-2.5 text-[15px] font-medium text-surface bg-teal hover:bg-teal-dim px-8 py-3.5 rounded-lg transition-colors">
34+ <svg class="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M19 14l-7 7m0 0l-7-7m7 7V3"/></svg>
35+ <span id="primary-label">Download for macOS</span>
36+ </a>
37+ <p class="mt-3 text-[12px] text-ink-faint" id="primary-meta">Apple Silicon &amp; Intel &middot; .dmg</p>
38+ </div>
39+
40+ <!-- Other platforms link -->
41+ <div class="text-center mb-20">
42+ <button onclick="document.getElementById('all-platforms').classList.toggle('hidden')" class="text-[13px] text-ink-faint hover:text-ink transition-colors underline underline-offset-2 decoration-rule hover:decoration-ink-faint">
43+ Other platforms
44+ </button>
45+ </div>
46+
47+ <!-- ─── EXPANDED: all platforms (hidden by default) ─── -->
48+ <div class="hidden max-w-2xl mx-auto mb-20" id="all-platforms">
49+ <div class="grid sm:grid-cols-3 gap-4">
50+ <a id="link-mac" href="#" class="group rounded-xl border border-rule hover:border-teal/30 p-5 text-center transition-all">
51+ <div class="text-[14px] font-medium text-ink mb-1">macOS</div>
52+ <p class="text-[11px] text-ink-faint">Apple Silicon &amp; Intel &middot; .dmg</p>
53+ </a>
54+ <a id="link-win" href="#" class="group rounded-xl border border-rule hover:border-teal/30 p-5 text-center transition-all">
55+ <div class="text-[14px] font-medium text-ink mb-1">Windows</div>
56+ <p class="text-[11px] text-ink-faint">Windows 10+ &middot; .exe</p>
57+ </a>
58+ <a id="link-linux" href="#" class="group rounded-xl border border-rule hover:border-teal/30 p-5 text-center transition-all">
59+ <div class="text-[14px] font-medium text-ink mb-1">Linux</div>
60+ <p class="text-[11px] text-ink-faint">AppImage &amp; .deb</p>
61+ </a>
62+ </div>
63+ </div>
64+
65+ <!-- ─── CLI alternative ─── -->
66+ <div class="max-w-md mx-auto">
67+ <div class="flex items-center justify-center gap-3 mb-6">
68+ <div class="h-px flex-1 bg-rule"></div>
69+ <span class="font-mono text-[11px] text-ink-faint uppercase tracking-[0.15em]">Or via CLI</span>
70+ <div class="h-px flex-1 bg-rule"></div>
71+ </div>
72+
73+ <button onclick="copyCommand('npx executor web')" class="group w-full flex items-center justify-between gap-3 bg-surface-raised border border-rule rounded-lg px-4 py-3 font-mono text-[13px] hover:border-ink-faint transition-colors text-left">
74+ <div>
75+ <span class="text-ink-faint select-none">$ </span><span class="text-ink">npx executor web</span>
76+ </div>
77+ <svg class="w-4 h-4 text-ink-faint group-hover:text-ink transition-colors shrink-0 copy-icon" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.5"><rect x="9" y="9" width="13" height="13" rx="2"/><path d="M5 15H4a2 2 0 01-2-2V4a2 2 0 012-2h9a2 2 0 012 2v1"/></svg>
78+ <svg class="w-4 h-4 text-teal shrink-0 check-icon hidden" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"/></svg>
79+ </button>
80+ </div>
81+ </div>
82+ </section>
83+ </main>
84+
85+ <!-- ─── FOOTER ─── -->
86+ <footer class="border-t border-rule py-10">
87+ <div class="max-w-[1200px] mx-auto px-6 sm:px-10 flex items-center justify-between">
88+ <span class="font-display italic text-ink-faint text-sm">executor</span>
89+ <a href="https://github.com/RhysSullivan/executor" class="text-[13px] text-ink-faint hover:text-ink transition-colors">GitHub</a>
90+ </div>
91+ </footer>
92+
93+ <script is:inline>
94+ const REPO = 'RhysSullivan/executor';
95+ const RELEASE_API = `https://api.github.com/repos/${REPO}/releases/latest`;
96+
97+ const PLATFORMS = {
98+ mac: { label: 'Download for macOS', meta: 'Apple Silicon & Intel \u00b7 .dmg', ext: '.dmg' },
99+ win: { label: 'Download for Windows', meta: 'Windows 10+ \u00b7 .exe', ext: '.exe' },
100+ linux: { label: 'Download for Linux', meta: 'AppImage', ext: '.AppImage' },
101+ };
102+
103+ function detectOS() {
104+ const ua = navigator.userAgent.toLowerCase();
105+ if (ua.includes('mac')) return 'mac';
106+ if (ua.includes('win')) return 'win';
107+ return 'linux';
108+ }
109+
110+ async function setup() {
111+ const userOS = detectOS();
112+ const platform = PLATFORMS[userOS];
113+
114+ // Set primary button text immediately
115+ document.getElementById('primary-label').textContent = platform.label;
116+ document.getElementById('primary-meta').textContent = platform.meta;
117+
118+ try {
119+ const res = await fetch(RELEASE_API);
120+ if (!res.ok) return;
121+ const release = await res.json();
122+ const assets = release.assets || [];
123+
124+ const findAsset = (ext) => assets.find(a => a.name.endsWith(ext));
125+
126+ const macUrl = findAsset('.dmg')?.browser_download_url;
127+ const winUrl = findAsset('.exe')?.browser_download_url;
128+ const linuxUrl = findAsset('.AppImage')?.browser_download_url;
129+
130+ const urls = { mac: macUrl, win: winUrl, linux: linuxUrl };
131+
132+ // Set primary button to user's OS
133+ if (urls[userOS]) {
134+ document.getElementById('primary-btn').href = urls[userOS];
135+ }
136+
137+ // Set "other platforms" links
138+ if (macUrl) document.getElementById('link-mac').href = macUrl;
139+ if (winUrl) document.getElementById('link-win').href = winUrl;
140+ if (linuxUrl) document.getElementById('link-linux').href = linuxUrl;
141+ } catch {
142+ // Silent fail — buttons just won't have hrefs
143+ }
144+ }
145+
146+ function copyCommand(cmd) {
147+ const btn = event.currentTarget;
148+ navigator.clipboard.writeText(cmd);
149+ btn.querySelector('.copy-icon').classList.add('hidden');
150+ btn.querySelector('.check-icon').classList.remove('hidden');
151+ setTimeout(() => {
152+ btn.querySelector('.copy-icon').classList.remove('hidden');
153+ btn.querySelector('.check-icon').classList.add('hidden');
154+ }, 1500);
155+ }
156+
157+ setup();
158+ </script>
159+</Layout>
apps/server/src/services/executor.ts+3−3
@@ -93,12 +93,12 @@ const ExecutorLayer = Layer.effect( · 92 unmodified lines
9393
9494 yield* migrate.pipe(Effect.catchAll((e) => Effect.die(e)));
9595
96− const cwd = process.cwd();
96+ const cwd = process.env.EXECUTOR_SCOPE_DIR || process.cwd();
9797 const kv = makeSqliteKv(sql);
9898 const config = makeKvConfig(kv, { cwd });
9999 const scopedKv = makeScopedKv(kv, cwd);
100100
101− const configPath = join(process.cwd(), "executor.jsonc");
101+ const configPath = join(cwd, "executor.jsonc");
102102 const fsLayer = NodeFileSystem.layer;
103103
104104 return yield* createExecutor({
@@ -131,7 +131,7 @@ const ExecutorLayer = Layer.effect( · 26 unmodified lines
131131 fsLayer,
132132 ),
133133 }),
134− // keychainPlugin(),
134+ keychainPlugin(),
135135 fileSecretsPlugin(),
136136 onepasswordPlugin({
137137 kv: scopeKv(scopedKv, "onepassword"),
bun.lock+2−29
@@ -41,12 +41,9 @@ · 40 unmodified lines
4141 "apps/desktop": {
4242 "name": "@executor/desktop",
4343 "version": "1.4.0",
44− "dependencies": {
45− "electron-store": "^10.0.0",
46− },
4744 "devDependencies": {
4845 "@types/node": "catalog:",
49− "electron": "^35.0.1",
46+ "electron": "35.7.5",
5047 "electron-builder": "^26.0.12",
5148 "typescript": "^5.9.3",
5249 },
@@ -1537,8 +1534,6 @@ · 1484 unmodified lines
15371534
15381535 "at-least-node": ["at-least-node@1.0.0", "", {}, "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg=="],
15391536
1540− "atomically": ["atomically@2.1.1", "", { "dependencies": { "stubborn-fs": "^2.0.0", "when-exit": "^2.1.4" } }, "sha512-P4w9o2dqARji6P7MHprklbfiArZAWvo07yW7qs3pdljb3BWr12FIB7W+p0zJiuiVsUpRO0iZn1kFFcpPegg0tQ=="],
1541−
15421537 "autoprefixer": ["autoprefixer@10.4.27", "", { "dependencies": { "browserslist": "^4.28.1", "caniuse-lite": "^1.0.30001774", "fraction.js": "^5.3.4", "picocolors": "^1.1.1", "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.1.0" }, "bin": { "autoprefixer": "bin/autoprefixer" } }, "sha512-NP9APE+tO+LuJGn7/9+cohklunJsXWiaWEfV3si4Gi/XHDwVNgkwr1J3RQYFIvPy76GmJ9/bW8vyoU1LcxwKHA=="],
15431538
15441539 "axobject-query": ["axobject-query@4.1.0", "", {}, "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ=="],
@@ -1665,8 +1660,6 @@ · 120 unmodified lines
16651660
16661661 "concat-map": ["concat-map@0.0.1", "", {}, "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="],
16671662
1668− "conf": ["conf@14.0.0", "", { "dependencies": { "ajv": "^8.17.1", "ajv-formats": "^3.0.1", "atomically": "^2.0.3", "debounce-fn": "^6.0.0", "dot-prop": "^9.0.0", "env-paths": "^3.0.0", "json-schema-typed": "^8.0.1", "semver": "^7.7.2", "uint8array-extras": "^1.4.0" } }, "sha512-L6BuueHTRuJHQvQVc6YXYZRtN5vJUtOdCTLn0tRYYV5azfbAFcPghB5zEE40mVrV6w7slMTqUfkDomutIK14fw=="],
1669−
16701663 "confbox": ["confbox@0.1.8", "", {}, "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w=="],
16711664
16721665 "consola": ["consola@3.4.2", "", {}, "sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA=="],
@@ -1785,8 +1778,6 @@ · 112 unmodified lines
17851778
17861779 "dayjs": ["dayjs@1.11.20", "", {}, "sha512-YbwwqR/uYpeoP4pu043q+LTDLFBLApUP6VxRihdfNTqu4ubqMlGDLd6ErXhEgsyvY0K6nCs7nggYumAN+9uEuQ=="],
17871780
1788− "debounce-fn": ["debounce-fn@6.0.0", "", { "dependencies": { "mimic-function": "^5.0.0" } }, "sha512-rBMW+F2TXryBwB54Q0d8drNEI+TfoS9JpNTAoVpukbWEhjXQq4rySFYLaqXMFXwdv61Zb2OHtj5bviSoimqxRQ=="],
1789−
17901781 "debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="],
17911782
17921783 "decimal.js-light": ["decimal.js-light@2.5.1", "", {}, "sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg=="],
@@ -1853,8 +1844,6 @@ · 60 unmodified lines
18531844
18541845 "domutils": ["domutils@3.2.2", "", { "dependencies": { "dom-serializer": "^2.0.0", "domelementtype": "^2.3.0", "domhandler": "^5.0.3" } }, "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw=="],
18551846
1856− "dot-prop": ["dot-prop@9.0.0", "", { "dependencies": { "type-fest": "^4.18.2" } }, "sha512-1gxPBJpI/pcjQhKgIU91II6Wkay+dLcN3M6rf2uwP8hRur3HtQXjVrdAK3sjC0piaEuxzMwjXChcETiJl47lAQ=="],
1857−
18581847 "dotenv": ["dotenv@16.6.1", "", {}, "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow=="],
18591848
18601849 "dotenv-expand": ["dotenv-expand@11.0.7", "", { "dependencies": { "dotenv": "^16.4.5" } }, "sha512-zIHwmZPRshsCdpMDyVsqGmgyP0yT8GAgXUnkdAoJisxvf33k7yO6OuoKmcTGuXPWSsm8Oh88nZicRLA9Y0rUeA=="],
@@ -1879,8 +1868,6 @@ · 18 unmodified lines
18791868
18801869 "electron-publish": ["electron-publish@26.8.1", "", { "dependencies": { "@types/fs-extra": "^9.0.11", "builder-util": "26.8.1", "builder-util-runtime": "9.5.1", "chalk": "^4.1.2", "form-data": "^4.0.5", "fs-extra": "^10.1.0", "lazy-val": "^1.0.5", "mime": "^2.5.2" } }, "sha512-q+jrSTIh/Cv4eGZa7oVR+grEJo/FoLMYBAnSL5GCtqwUpr1T+VgKB/dn1pnzxIxqD8S/jP1yilT9VrwCqINR4w=="],
18811870
1882− "electron-store": ["electron-store@10.1.0", "", { "dependencies": { "conf": "^14.0.0", "type-fest": "^4.41.0" } }, "sha512-oL8bRy7pVCLpwhmXy05Rh/L6O93+k9t6dqSw0+MckIc3OmCTZm6Mp04Q4f/J0rtu84Ky6ywkR8ivtGOmrq+16w=="],
1883−
18841871 "electron-to-chromium": ["electron-to-chromium@1.5.330", "", {}, "sha512-jFNydB5kFtYUobh4IkWUnXeyDbjf/r9gcUEXe1xcrcUxIGfTdzPXA+ld6zBRbwvgIGVzDll/LTIiDztEtckSnA=="],
18851872
18861873 "electron-winstaller": ["electron-winstaller@5.4.0", "", { "dependencies": { "@electron/asar": "^3.2.1", "debug": "^4.1.1", "fs-extra": "^7.0.1", "lodash": "^4.17.21", "temp": "^0.9.0" }, "optionalDependencies": { "@electron/windows-sign": "^1.1.2" } }, "sha512-bO3y10YikuUwUuDUQRM4KfwNkKhnpVO7IPdbsrejwN9/AABJzzTQ4GeHwyzNSrVO+tEH3/Np255a3sVZpZDjvg=="],
@@ -2401,8 +2388,6 @@ · 514 unmodified lines
24012388
24022389 "mimic-fn": ["mimic-fn@2.1.0", "", {}, "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg=="],
24032390
2404− "mimic-function": ["mimic-function@5.0.1", "", {}, "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA=="],
2405−
24062391 "mimic-response": ["mimic-response@3.1.0", "", {}, "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ=="],
24072392
24082393 "minimatch": ["minimatch@10.2.5", "", { "dependencies": { "brace-expansion": "^5.0.5" } }, "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg=="],
@@ -2855,10 +2840,6 @@ · 446 unmodified lines
28552840
28562841 "strip-literal": ["strip-literal@3.1.0", "", { "dependencies": { "js-tokens": "^9.0.1" } }, "sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg=="],
28572842
2858− "stubborn-fs": ["stubborn-fs@2.0.0", "", { "dependencies": { "stubborn-utils": "^1.0.1" } }, "sha512-Y0AvSwDw8y+nlSNFXMm2g6L51rBGdAQT20J3YSOqxC53Lo3bjWRtr2BKcfYoAf352WYpsZSTURrA0tqhfgudPA=="],
2859−
2860− "stubborn-utils": ["stubborn-utils@1.0.2", "", {}, "sha512-zOh9jPYI+xrNOyisSelgym4tolKTJCQd5GBhK0+0xJvcYDcwlOoxF/rnFKQ2KRZknXSG9jWAp66fwP6AxN9STg=="],
2861−
28622843 "style-to-js": ["style-to-js@1.1.21", "", { "dependencies": { "style-to-object": "1.0.14" } }, "sha512-RjQetxJrrUJLQPHbLku6U/ocGtzyjbJMP9lCNK7Ag0CNh690nSH8woqWH9u16nMjYBAok+i7JO1NP2pOy8IsPQ=="],
28632844
28642845 "style-to-object": ["style-to-object@1.0.14", "", { "dependencies": { "inline-style-parser": "0.2.7" } }, "sha512-LIN7rULI0jBscWQYaSswptyderlarFkjQ+t79nzty8tcIAceVomEVlLzH5VP4Cmsv6MtKhs7qaAiwlcp+Mgaxw=="],
@@ -2939,7 +2920,7 @@ · 74 unmodified lines
29392920
29402921 "turbo": ["turbo@2.9.2", "", { "optionalDependencies": { "@turbo/darwin-64": "2.9.2", "@turbo/darwin-arm64": "2.9.2", "@turbo/linux-64": "2.9.2", "@turbo/linux-arm64": "2.9.2", "@turbo/windows-64": "2.9.2", "@turbo/windows-arm64": "2.9.2" }, "bin": { "turbo": "bin/turbo" } }, "sha512-DUUWysctg/vax8W05UJcyrHm4LvxtX0umAT4bZB5lab4inNXTbwoYSFpdgqzBxON23j8ls3xGxvx0kwQz6Q8wQ=="],
29412922
2942− "type-fest": ["type-fest@4.41.0", "", {}, "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA=="],
2923+ "type-fest": ["type-fest@0.13.1", "", {}, "sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg=="],
29432924
29442925 "type-is": ["type-is@2.0.1", "", { "dependencies": { "content-type": "^1.0.5", "media-typer": "^1.1.0", "mime-types": "^3.0.0" } }, "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw=="],
29452926
@@ -2947,8 +2928,6 @@ · 1 unmodified line
29472928
29482929 "ufo": ["ufo@1.6.3", "", {}, "sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q=="],
29492930
2950− "uint8array-extras": ["uint8array-extras@1.5.0", "", {}, "sha512-rvKSBiC5zqCCiDZ9kAOszZcDvdAHwwIKJG33Ykj43OKcWsnmcBRL09YTU4nOeHZ8Y2a7l1MgTd08SBe9A8Qj6A=="],
2951−
29522931 "ultrahtml": ["ultrahtml@1.6.0", "", {}, "sha512-R9fBn90VTJrqqLDwyMph+HGne8eqY1iPfYhPzZrvKpIfwkWZbcYlfpsb8B9dTvBfpy1/hqAD7Wi8EKfP9e8zdw=="],
29532932
29542933 "uncrypto": ["uncrypto@0.1.3", "", {}, "sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q=="],
@@ -3047,8 +3026,6 @@ · 92 unmodified lines
30473026
30483027 "whatwg-url": ["whatwg-url@5.0.0", "", { "dependencies": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" } }, "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw=="],
30493028
3050− "when-exit": ["when-exit@2.1.5", "", {}, "sha512-VGkKJ564kzt6Ms1dbgPP/yuIoQCrsFAnRbptpC5wOEsDaNsbCB2bnfnaA8i/vRs5tjUSEOtIuvl9/MyVsvQZCg=="],
3051−
30523029 "which": ["which@5.0.0", "", { "dependencies": { "isexe": "^3.1.1" }, "bin": { "node-which": "bin/which.js" } }, "sha512-JEdGzHwwkrbWoGOlIHqQ5gtprKGOenpDHpxE9zVR1bWbOtYRyPPHMe9FaP6x61CmNaTThSkb0DAJte5jD+DmzQ=="],
30533030
30543031 "which-pm-runs": ["which-pm-runs@1.1.0", "", {}, "sha512-n1brCuqClxfFfq/Rb0ICg9giSZqCS+pLtccdag6C2HyufBrh3fBOiy9nb6ggRMvWOVH5GrdJskj5iGTZNxd7SA=="],
@@ -3207,8 +3184,6 @@ · 152 unmodified lines
32073184
32083185 "clone-response/mimic-response": ["mimic-response@1.0.1", "", {}, "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ=="],
32093186
3210− "conf/env-paths": ["env-paths@3.0.0", "", {}, "sha512-dtJUTepzMW3Lm/NPxRf3wP4642UWhjL2sQxc+ym2YMj1m/H2zDNQOlezafzkHwn6sMstjHTwG6iQQsctDW/b1A=="],
3211−
32123187 "cross-spawn/which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="],
32133188
32143189 "csso/css-tree": ["css-tree@2.2.1", "", { "dependencies": { "mdn-data": "2.0.28", "source-map-js": "^1.0.1" } }, "sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA=="],
@@ -3291,8 +3266,6 @@ · 76 unmodified lines
32913266
32923267 "router/path-to-regexp": ["path-to-regexp@8.4.2", "", {}, "sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA=="],
32933268
3294− "serialize-error/type-fest": ["type-fest@0.13.1", "", {}, "sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg=="],
3295−
32963269 "tar-fs/chownr": ["chownr@1.1.4", "", {}, "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg=="],
32973270
32983271 "temp-file/fs-extra": ["fs-extra@10.1.0", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ=="],
package.json+1−1
@@ -21,7 +21,7 @@ · 20 unmodified lines
2121 "license": "MIT",
2222 "private": true,
2323 "type": "module",
24− "packageManager": "bun@1.2.22",
24+ "packageManager": "bun@1.3.11",
2525 "workspaces": [
2626 "packages/*/*",
2727 "packages/ui",