- Consolidated environment variable management by centralizing all variables in the root .env file. - Updated development scripts across various packages to utilize the new environment loading mechanism. - Enhanced error handling for missing environment variables in the bot and server packages. - Adjusted Next.js configuration to map environment variables for client-side access.
Unified · Split
| @@ -1,24 +1,25 @@ | ||
| 1 | −# Required for the assistant to call Claude | |
| 2 | −ANTHROPIC_API_KEY=sk-ant-... | |
| 3 | −# Or use Claude Max OAuth token instead: | |
| 4 | −# ANTHROPIC_OAUTH_TOKEN=... | |
| 1 | +# All env vars live in this single root .env file. | |
| 2 | +# Sub-packages load it via `with-env` scripts (bun --env-file). | |
| 3 | +# Next.js vars are mapped from canonical names in next.config.ts. | |
| 5 | 4 | |
| 6 | −# Required for the Discord bot | |
| 7 | −DISCORD_BOT_TOKEN=... | |
| 5 | +# ── Convex (required) ── | |
| 6 | +CONVEX_DEPLOYMENT=dev:your-deployment-slug | |
| 7 | +CONVEX_URL=https://your-deployment.convex.cloud | |
| 8 | +CONVEX_SITE_URL=https://your-deployment.convex.site | |
| 8 | 9 | |
| 9 | −# Optional: executor URL (defaults to http://localhost:4001) | |
| 10 | −# EXECUTOR_URL=http://localhost:4001 | |
| 10 | +# ── WorkOS (optional — enables auth, omit for guest-only mode) ── | |
| 11 | +# WORKOS_CLIENT_ID=client_... | |
| 12 | +# WORKOS_API_KEY=sk_test_... | |
| 13 | +# WORKOS_WEBHOOK_SECRET=... | |
| 11 | 14 | |
| 12 | −# Optional: assistant server URL for the bot (defaults to http://localhost:3000) | |
| 13 | −# ASSISTANT_SERVER_URL=http://localhost:3000 | |
| 15 | +# ── Discord bot (optional — omit to skip bot startup) ── | |
| 16 | +# DISCORD_BOT_TOKEN=... | |
| 14 | 17 | |
| 15 | −# Optional: assistant server port (defaults to 3000) | |
| 16 | −# PORT=3000 | |
| 18 | +# ── Assistant (optional) ── | |
| 19 | +# OPENASSISTANT_EXECUTOR_URL=http://localhost:3001 | |
| 20 | +# OPENASSISTANT_CALLBACK_BASE_URL=http://localhost:3000 | |
| 17 | 21 | |
| 18 | −# Optional: executor server port (defaults to 4001) | |
| 19 | −# Configured in executor/.env or as env var | |
| 20 | − | |
| 21 | −# Optional: tool source API keys | |
| 22 | +# ── Tool source API keys (optional) ── | |
| 22 | 23 | # POSTHOG_PERSONAL_API_KEY=... |
| 23 | 24 | # POSTHOG_PROJECT_ID=... |
| 24 | 25 | # OPENASSISTANT_GITHUB_TOKEN=... |
| @@ -3,8 +3,9 @@ · 2 unmodified lines | ||
| 3 | 3 | "private": true, |
| 4 | 4 | "type": "module", |
| 5 | 5 | "scripts": { |
| 6 | − "dev": "bun --hot src/index.ts", | |
| 7 | − "start": "bun src/index.ts" | |
| 6 | + "with-env": "bun run --env-file=../../../.env --", | |
| 7 | + "dev": "bun with-env bun --hot src/index.ts", | |
| 8 | + "start": "bun with-env bun src/index.ts" | |
| 8 | 9 | }, |
| 9 | 10 | "dependencies": { |
| 10 | 11 | "@assistant/core": "workspace:*", |
| @@ -27,7 +27,10 @@ if (!DISCORD_TOKEN) { · 26 unmodified lines | ||
| 27 | 27 | } |
| 28 | 28 | |
| 29 | 29 | const SERVER_URL = Bun.env.ASSISTANT_SERVER_URL ?? "http://localhost:3000"; |
| 30 | −const CONVEX_URL = Bun.env.CONVEX_URL ?? "http://127.0.0.1:3210"; | |
| 30 | +const CONVEX_URL = Bun.env.CONVEX_URL; | |
| 31 | +if (!CONVEX_URL) { | |
| 32 | + throw new Error("CONVEX_URL is required. Set it in your environment."); | |
| 33 | +} | |
| 31 | 34 | |
| 32 | 35 | // --------------------------------------------------------------------------- |
| 33 | 36 | // Clients |
| @@ -7,8 +7,9 @@ · 6 unmodified lines | ||
| 7 | 7 | "./client": "./src/client.ts" |
| 8 | 8 | }, |
| 9 | 9 | "scripts": { |
| 10 | − "dev": "bun --hot src/index.ts", | |
| 11 | − "start": "bun src/index.ts" | |
| 10 | + "with-env": "bun run --env-file=../../../.env --", | |
| 11 | + "dev": "bun with-env bun --hot src/index.ts", | |
| 12 | + "start": "bun with-env bun src/index.ts" | |
| 12 | 13 | }, |
| 13 | 14 | "dependencies": { |
| 14 | 15 | "@assistant/core": "workspace:*", |
| @@ -7,7 +7,10 @@ import { ConvexHttpClient } from "convex/browser"; · 6 unmodified lines | ||
| 7 | 7 | import { api } from "@executor/convex/_generated/api"; |
| 8 | 8 | |
| 9 | 9 | const PORT = Number(Bun.env.PORT ?? 3000); |
| 10 | −const CONVEX_URL = Bun.env.CONVEX_URL ?? "http://127.0.0.1:3210"; | |
| 10 | +const CONVEX_URL = Bun.env.CONVEX_URL; | |
| 11 | +if (!CONVEX_URL) { | |
| 12 | + throw new Error("CONVEX_URL is required. Set it in your environment."); | |
| 13 | +} | |
| 11 | 14 | const EXECUTOR_URL = Bun.env.EXECUTOR_URL |
| 12 | 15 | ?? Bun.env.CONVEX_SITE_URL |
| 13 | 16 | ?? (CONVEX_URL.includes(".convex.cloud") |
| @@ -3,6 +3,8 @@ · 2 unmodified lines | ||
| 3 | 3 | * |
| 4 | 4 | * Usage: bun dev |
| 5 | 5 | * |
| 6 | + * Reads all configuration from the root .env file (auto-loaded by Bun). | |
| 7 | + * | |
| 6 | 8 | * Starts: |
| 7 | 9 | * 1. Convex cloud dev function push (once) |
| 8 | 10 | * 2. Convex cloud dev function watcher |
| @@ -36,39 +38,12 @@ function toSiteUrl(convexUrl: string): string { · 27 unmodified lines | ||
| 36 | 38 | return convexUrl; |
| 37 | 39 | } |
| 38 | 40 | |
| 39 | −async function resolveExecutorUrls(): Promise<{ convexUrl: string; executorUrl: string }> { | |
| 40 | − if (Bun.env.CONVEX_URL) { | |
| 41 | − const convexUrl = Bun.env.CONVEX_URL; | |
| 42 | − const executorUrl = Bun.env.CONVEX_SITE_URL ?? toSiteUrl(convexUrl); | |
| 43 | − return { convexUrl, executorUrl }; | |
| 44 | − } | |
| 45 | − | |
| 46 | − const envFile = Bun.file("./executor/.env.local"); | |
| 47 | − if (!(await envFile.exists())) { | |
| 48 | − throw new Error("Missing executor/.env.local with CONVEX_URL"); | |
| 49 | − } | |
| 50 | − | |
| 51 | − const content = await envFile.text(); | |
| 52 | − const lines = content | |
| 53 | − .split("\n") | |
| 54 | − .map((entry) => entry.trim()); | |
| 55 | − | |
| 56 | − const convexLine = lines.find((entry) => entry.startsWith("CONVEX_URL=")); | |
| 57 | − const siteLine = lines.find((entry) => entry.startsWith("CONVEX_SITE_URL=")); | |
| 58 | − | |
| 59 | − if (!convexLine) { | |
| 60 | − throw new Error("CONVEX_URL not found in executor/.env.local"); | |
| 61 | − } | |
| 62 | − | |
| 63 | − const convexUrl = convexLine.slice("CONVEX_URL=".length).trim(); | |
| 41 | +function resolveExecutorUrls(): { convexUrl: string; executorUrl: string } { | |
| 42 | + const convexUrl = Bun.env.CONVEX_URL; | |
| 64 | 43 | if (!convexUrl) { |
| 65 | − throw new Error("CONVEX_URL is empty in executor/.env.local"); | |
| 44 | + throw new Error("CONVEX_URL is not set. Add it to the root .env file."); | |
| 66 | 45 | } |
| 67 | − | |
| 68 | − const executorUrl = siteLine | |
| 69 | − ? siteLine.slice("CONVEX_SITE_URL=".length).trim() | |
| 70 | − : toSiteUrl(convexUrl); | |
| 71 | − | |
| 46 | + const executorUrl = Bun.env.CONVEX_SITE_URL ?? toSiteUrl(convexUrl); | |
| 72 | 47 | return { convexUrl, executorUrl }; |
| 73 | 48 | } |
| 74 | 49 | |
| @@ -161,7 +136,7 @@ if (!Bun.env.DISCORD_BOT_TOKEN) { · 86 unmodified lines | ||
| 161 | 136 | // 1. Push functions (must complete before executor starts) |
| 162 | 137 | await pushConvexFunctions(); |
| 163 | 138 | |
| 164 | −const urls = await resolveExecutorUrls(); | |
| 139 | +const urls = resolveExecutorUrls(); | |
| 165 | 140 | console.log(prefix("convex", `Using Convex URL: ${urls.convexUrl}`)); |
| 166 | 141 | console.log(prefix("convex", `Using executor HTTP URL: ${urls.executorUrl}`)); |
| 167 | 142 | |
| @@ -181,8 +156,8 @@ spawnService("web", ["bun", "run", "dev", "--", "-p", "3002"], { · 13 unmodified lines | ||
| 181 | 156 | // Small delay for web to be ready |
| 182 | 157 | await Bun.sleep(1200); |
| 183 | 158 | |
| 184 | −spawnService("assistant", ["bun", "run", "--cwd", "packages/server", "dev"], { | |
| 185 | − cwd: "./assistant", | |
| 159 | +spawnService("assistant", ["bun", "run", "dev"], { | |
| 160 | + cwd: "./assistant/packages/server", | |
| 186 | 161 | env: { |
| 187 | 162 | EXECUTOR_URL: urls.executorUrl, |
| 188 | 163 | CONVEX_URL: urls.convexUrl, |
| @@ -193,8 +168,8 @@ spawnService("assistant", ["bun", "run", "--cwd", "packages/server", "dev"], { · 4 unmodified lines | ||
| 193 | 168 | |
| 194 | 169 | if (Bun.env.DISCORD_BOT_TOKEN) { |
| 195 | 170 | await Bun.sleep(1000); |
| 196 | − spawnService("bot", ["bun", "run", "--cwd", "packages/bot", "dev"], { | |
| 197 | − cwd: "./assistant", | |
| 171 | + spawnService("bot", ["bun", "run", "dev"], { | |
| 172 | + cwd: "./assistant/packages/bot", | |
| 198 | 173 | env: { |
| 199 | 174 | CONVEX_URL: urls.convexUrl, |
| 200 | 175 | }, |
| @@ -1,6 +1,12 @@ | ||
| 1 | 1 | import type { NextConfig } from "next"; |
| 2 | 2 | const nextConfig: NextConfig = { |
| 3 | 3 | transpilePackages: ["@executor/contracts"], |
| 4 | + env: { | |
| 5 | + // Map canonical env vars to NEXT_PUBLIC_ so they're available client-side. | |
| 6 | + // This lets us keep a single root .env without NEXT_PUBLIC_ prefixes. | |
| 7 | + NEXT_PUBLIC_CONVEX_URL: process.env.CONVEX_URL, | |
| 8 | + NEXT_PUBLIC_WORKOS_CLIENT_ID: process.env.WORKOS_CLIENT_ID, | |
| 9 | + }, | |
| 4 | 10 | }; |
| 5 | 11 | |
| 6 | 12 | export default nextConfig; |
| @@ -3,9 +3,10 @@ · 2 unmodified lines | ||
| 3 | 3 | "version": "0.1.0", |
| 4 | 4 | "private": true, |
| 5 | 5 | "scripts": { |
| 6 | − "dev": "next dev", | |
| 7 | − "build": "next build", | |
| 8 | − "start": "next start", | |
| 6 | + "with-env": "bun run --env-file=../../../.env --", | |
| 7 | + "dev": "bun with-env next dev", | |
| 8 | + "build": "bun with-env next build", | |
| 9 | + "start": "bun with-env next start", | |
| 9 | 10 | "lint": "eslint" |
| 10 | 11 | }, |
| 11 | 12 | "dependencies": { |
| @@ -10,7 +10,10 @@ import { ConvexProvider, ConvexReactClient } from "convex/react"; · 9 unmodified lines | ||
| 10 | 10 | import type { ReactNode } from "react"; |
| 11 | 11 | import { workosEnabled } from "@/lib/auth-capabilities"; |
| 12 | 12 | |
| 13 | −const convexUrl = process.env.NEXT_PUBLIC_CONVEX_URL ?? "http://127.0.0.1:3210"; | |
| 13 | +const convexUrl = process.env.NEXT_PUBLIC_CONVEX_URL; | |
| 14 | +if (!convexUrl) { | |
| 15 | + throw new Error("CONVEX_URL is not set. Add it to the root .env file."); | |
| 16 | +} | |
| 14 | 17 | const convexClient = new ConvexReactClient(convexUrl, { |
| 15 | 18 | unsavedChangesWarning: false, |
| 16 | 19 | }); |
| @@ -10,18 +10,18 @@ · 9 unmodified lines | ||
| 10 | 10 | "assistant/packages/reacord" |
| 11 | 11 | ], |
| 12 | 12 | "scripts": { |
| 13 | + "with-env": "bun run --env-file=.env --", | |
| 13 | 14 | "dev": "bun run dev.ts", |
| 14 | − "dev:executor": "bun run dev:executor:convex", | |
| 15 | 15 | "dev:executor:convex": "bunx --cwd executor convex dev", |
| 16 | 16 | "dev:executor:web": "bun run --cwd executor/apps/web dev", |
| 17 | 17 | "dev:executor:all": "bun run dev:executor:convex & bun run dev:executor:web", |
| 18 | − "dev:assistant": "bun run --cwd assistant dev:server", | |
| 19 | − "dev:bot": "bun run --cwd assistant dev:bot", | |
| 18 | + "dev:assistant": "bun run --cwd assistant/packages/server dev", | |
| 19 | + "dev:bot": "bun run --cwd assistant/packages/bot dev", | |
| 20 | 20 | "test": "bun run test:executor && bun run test:assistant", |
| 21 | 21 | "test:executor": "bun test --cwd executor", |
| 22 | 22 | "test:assistant": "bun run --cwd assistant test", |
| 23 | 23 | "typecheck:executor": "bunx tsc --noEmit -p executor/tsconfig.json", |
| 24 | − "db:clear:executor": "bun run executor/wipe-convex-db.ts", | |
| 24 | + "db:clear:executor": "bun with-env bun run executor/wipe-convex-db.ts", | |
| 25 | 25 | "convex:codegen": "bunx --cwd executor convex codegen" |
| 26 | 26 | }, |
| 27 | 27 | "dependencies": { |