From 6de7c3065e53f2074098119c786de9e32a2e56da Mon Sep 17 00:00:00 2001 From: -Puter <22245429+puterhimself@users.noreply.github.com> Date: Sun, 19 Jul 2026 17:29:11 +0530 Subject: [PATCH] Consolidate env at repo root - Move all application env vars to repository-root .env (with .env.example as the committed template) and drop the per-app .env.example files. - Add @code/env subpaths (agent, convex) and consume validated exports everywhere instead of reading process.env directly. - Wire every dev/build/start script to load ../../.env via bun --env-file and point vite.config.ts envDir at the repo root. --- .env.example | 32 ++++++++++++++++++++++++++++++++ .gitignore | 3 ++- apps/daemon/.env.example | 7 ------- apps/daemon/package.json | 6 +++--- apps/native/package.json | 13 ++++++------- apps/web/package.json | 1 - apps/web/vite.config.ts | 3 +++ bun.lock | 13 ++++--------- package.json | 8 +++----- packages/env/package.json | 7 ++++--- packages/env/src/agent.ts | 17 +++++++++++++++++ packages/env/src/convex.ts | 13 +++++++++++++ packages/env/src/server.ts | 1 + packages/env/src/vite-env.d.ts | 9 +++++++++ packages/env/src/web.ts | 7 +++---- 15 files changed, 100 insertions(+), 40 deletions(-) create mode 100644 .env.example delete mode 100644 apps/daemon/.env.example create mode 100644 packages/env/src/agent.ts create mode 100644 packages/env/src/convex.ts create mode 100644 packages/env/src/vite-env.d.ts diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..9e68162 --- /dev/null +++ b/.env.example @@ -0,0 +1,32 @@ +# Shared application endpoints +CONVEX_DEPLOYMENT=dev:example-deployment +CONVEX_URL=https://example.convex.cloud +CONVEX_SITE_URL=https://example.convex.site +SITE_URL=http://localhost:5173 +NATIVE_APP_URL=code:// + +# Browser and native public endpoints +VITE_CONVEX_URL=https://example.convex.cloud +VITE_CONVEX_SITE_URL=https://example.convex.site +EXPO_PUBLIC_CONVEX_URL=https://example.convex.cloud +EXPO_PUBLIC_CONVEX_SITE_URL=https://example.convex.site + +# Daemon identity and control plane +DAEMON_ID=local-macbook +DAEMON_NAME=Local MacBook +DAEMON_VERSION=0.0.0 +DAEMON_HEARTBEAT_MS=15000 +DAEMON_COMMAND_LEASE_MS=60000 +# RIVET_ENDPOINT=http://localhost:6420 + +# Flue persistence adapter +FLUE_DB_TOKEN=replace-with-a-long-random-token + +# Agent model provider +AGENT_MODEL_PROVIDER=cheaptricks +AGENT_MODEL_NAME=minimax-m3 +AGENT_MODEL_API=openai-completions +AGENT_MODEL_BASE_URL=https://ai.example.com/v1 +AGENT_MODEL_API_KEY=replace-with-provider-api-key +AGENT_MODEL_CONTEXT_WINDOW=262000 +AGENT_MODEL_MAX_TOKENS=131072 diff --git a/.gitignore b/.gitignore index e5ccdf8..2a1c54f 100644 --- a/.gitignore +++ b/.gitignore @@ -11,9 +11,10 @@ build # Generated files apps/web/src/routeTree.gen.ts -# Environment variables +# Environment variables live at the repository root .env .env*.local +!.env.example # IDEs and editors .vscode/* diff --git a/apps/daemon/.env.example b/apps/daemon/.env.example deleted file mode 100644 index 6d7a156..0000000 --- a/apps/daemon/.env.example +++ /dev/null @@ -1,7 +0,0 @@ -CONVEX_URL=https://example.convex.cloud -DAEMON_ID=local-macbook -DAEMON_NAME=Local MacBook -DAEMON_VERSION=0.0.0 -DAEMON_HEARTBEAT_MS=15000 -DAEMON_COMMAND_LEASE_MS=60000 -# RIVET_ENDPOINT=http://localhost:6420 diff --git a/apps/daemon/package.json b/apps/daemon/package.json index d1cdd56..1a5cafe 100644 --- a/apps/daemon/package.json +++ b/apps/daemon/package.json @@ -5,9 +5,9 @@ "type": "module", "module": "src/index.ts", "scripts": { - "dev": "bun run --watch src/index.ts", - "build": "bun build src/index.ts --compile --outfile dist/code-daemon", - "start": "./dist/code-daemon", + "dev": "bun --env-file=../../.env run --watch src/index.ts", + "build": "bun --env-file=../../.env build src/index.ts --compile --outfile dist/code-daemon", + "start": "bun --env-file=../../.env ./dist/code-daemon", "check-types": "tsc --noEmit" }, "dependencies": { diff --git a/apps/native/package.json b/apps/native/package.json index ea229ba..b3204a3 100644 --- a/apps/native/package.json +++ b/apps/native/package.json @@ -4,12 +4,12 @@ "private": true, "main": "expo-router/entry", "scripts": { - "start": "expo start", - "dev": "expo start --clear", - "android": "expo run:android", - "ios": "expo run:ios", - "prebuild": "expo prebuild", - "web": "expo start --web" + "start": "bun --env-file=../../.env expo start", + "dev": "bun --env-file=../../.env expo start --clear", + "android": "bun --env-file=../../.env expo run:android", + "ios": "bun --env-file=../../.env expo run:ios", + "prebuild": "bun --env-file=../../.env expo prebuild", + "web": "bun --env-file=../../.env expo start --web" }, "dependencies": { "@better-auth/expo": "catalog:", @@ -22,7 +22,6 @@ "@tanstack/react-form": "catalog:", "better-auth": "catalog:", "convex": "catalog:", - "dotenv": "catalog:", "expo": "~57.0.1", "expo-constants": "~57.0.2", "expo-font": "~57.0.0", diff --git a/apps/web/package.json b/apps/web/package.json index 4dfc1ae..d33fa38 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -19,7 +19,6 @@ "@tanstack/react-form": "catalog:", "better-auth": "catalog:", "convex": "catalog:", - "dotenv": "catalog:", "isbot": "^5.1.44", "lucide-react": "catalog:", "next-themes": "catalog:", diff --git a/apps/web/vite.config.ts b/apps/web/vite.config.ts index db5e501..dda6827 100644 --- a/apps/web/vite.config.ts +++ b/apps/web/vite.config.ts @@ -1,8 +1,11 @@ +import path from "node:path"; + import { reactRouter } from "@react-router/dev/vite"; import tailwindcss from "@tailwindcss/vite"; import { defineConfig } from "vite-plus"; import tsconfigPaths from "vite-tsconfig-paths"; export default defineConfig({ + envDir: path.resolve(import.meta.dirname, "../.."), plugins: [tailwindcss(), reactRouter(), tsconfigPaths()], }); diff --git a/bun.lock b/bun.lock index 7e13a00..84e7479 100644 --- a/bun.lock +++ b/bun.lock @@ -4,11 +4,6 @@ "workspaces": { "": { "name": "code", - "dependencies": { - "@code/env": "workspace:*", - "dotenv": "catalog:", - "zod": "catalog:", - }, "devDependencies": { "@code/config": "workspace:*", "@types/bun": "latest", @@ -67,7 +62,6 @@ "@tanstack/react-form": "catalog:", "better-auth": "catalog:", "convex": "catalog:", - "dotenv": "catalog:", "expo": "~57.0.1", "expo-constants": "~57.0.2", "expo-font": "~57.0.0", @@ -130,7 +124,6 @@ "@tanstack/react-form": "catalog:", "better-auth": "catalog:", "convex": "catalog:", - "dotenv": "catalog:", "isbot": "^5.1.44", "lucide-react": "catalog:", "next-themes": "catalog:", @@ -158,7 +151,10 @@ "name": "@code/agents", "version": "0.0.0", "dependencies": { + "@code/env": "workspace:*", "@flue/runtime": "latest", + "convex": "catalog:", + "hono": "^4.12.30", }, "devDependencies": { "@code/config": "workspace:*", @@ -171,10 +167,10 @@ "version": "1.0.0", "dependencies": { "@better-auth/expo": "catalog:", + "@code/env": "workspace:*", "@convex-dev/better-auth": "catalog:", "better-auth": "catalog:", "convex": "catalog:", - "dotenv": "catalog:", "zod": "catalog:", }, "devDependencies": { @@ -192,7 +188,6 @@ "version": "0.0.0", "dependencies": { "@t3-oss/env-core": "^0.13.11", - "dotenv": "catalog:", "zod": "catalog:", }, "devDependencies": { diff --git a/package.json b/package.json index 95e8ba5..ba2d1dc 100644 --- a/package.json +++ b/package.json @@ -34,6 +34,7 @@ "hooks:setup": "vp config", "dev:native": "vp run --filter native dev", "dev:web": "vp run --filter web dev", + "dev:agents": "vp run --filter @code/agents dev", "dev:desktop": "vp run --filter desktop dev:hmr", "build:desktop": "vp run --filter desktop build:stable", "build:desktop:canary": "vp run --filter desktop build:canary", @@ -42,15 +43,12 @@ "dev:setup": "vp run --filter @code/backend dev:setup", "dev:daemon": "vp run --filter daemon dev", "build:daemon": "vp run --filter daemon build", + "build:agents": "vp run --filter @code/agents build", "docs:update": "bun run scripts/update-docs.ts", "subtree": "bun run scripts/subtree.ts", "fix": "ultracite fix" }, - "dependencies": { - "@code/env": "workspace:*", - "dotenv": "catalog:", - "zod": "catalog:" - }, + "dependencies": {}, "devDependencies": { "@code/config": "workspace:*", "@types/bun": "latest", diff --git a/packages/env/package.json b/packages/env/package.json index 8e930ae..ce7c205 100644 --- a/packages/env/package.json +++ b/packages/env/package.json @@ -4,13 +4,14 @@ "private": true, "type": "module", "exports": { - "./web": "./src/web.ts", + "./agent": "./src/agent.ts", + "./convex": "./src/convex.ts", "./native": "./src/native.ts", - "./server": "./src/server.ts" + "./server": "./src/server.ts", + "./web": "./src/web.ts" }, "dependencies": { "@t3-oss/env-core": "^0.13.11", - "dotenv": "catalog:", "zod": "catalog:" }, "devDependencies": { diff --git a/packages/env/src/agent.ts b/packages/env/src/agent.ts new file mode 100644 index 0000000..36ad666 --- /dev/null +++ b/packages/env/src/agent.ts @@ -0,0 +1,17 @@ +import { z } from "zod"; + +const agentEnvSchema = z.object({ + AGENT_MODEL_API: z.literal("openai-completions"), + AGENT_MODEL_API_KEY: z.string().min(1), + AGENT_MODEL_BASE_URL: z.url(), + AGENT_MODEL_CONTEXT_WINDOW: z.coerce.number().int().positive(), + AGENT_MODEL_MAX_TOKENS: z.coerce.number().int().positive(), + AGENT_MODEL_NAME: z.string().min(1), + AGENT_MODEL_PROVIDER: z.string().min(1), +}); + +export type AgentEnv = z.infer; + +export const parseAgentEnv = ( + runtimeEnv: Record +): AgentEnv => agentEnvSchema.parse(runtimeEnv); diff --git a/packages/env/src/convex.ts b/packages/env/src/convex.ts new file mode 100644 index 0000000..8578e41 --- /dev/null +++ b/packages/env/src/convex.ts @@ -0,0 +1,13 @@ +import { createEnv } from "@t3-oss/env-core"; +import { z } from "zod"; + +export const env = createEnv({ + emptyStringAsUndefined: true, + runtimeEnv: process.env, + server: { + CONVEX_SITE_URL: z.url(), + FLUE_DB_TOKEN: z.string().min(1), + NATIVE_APP_URL: z.string().min(1).default("code://"), + SITE_URL: z.url(), + }, +}); diff --git a/packages/env/src/server.ts b/packages/env/src/server.ts index 32e5fe2..2359302 100644 --- a/packages/env/src/server.ts +++ b/packages/env/src/server.ts @@ -14,6 +14,7 @@ export const env = createEnv({ DAEMON_VERSION: z.string().default("0.0.0"), DAEMON_HEARTBEAT_MS: z.coerce.number().int().positive().default(15_000), DAEMON_COMMAND_LEASE_MS: z.coerce.number().int().positive().default(60_000), + FLUE_DB_TOKEN: z.string().min(1), RIVET_ENDPOINT: z.url().optional(), }, runtimeEnv: process.env, diff --git a/packages/env/src/vite-env.d.ts b/packages/env/src/vite-env.d.ts new file mode 100644 index 0000000..86b84fa --- /dev/null +++ b/packages/env/src/vite-env.d.ts @@ -0,0 +1,9 @@ +interface ImportMetaEnv { + readonly [key: string]: string | number | boolean | undefined; + readonly VITE_CONVEX_SITE_URL: string; + readonly VITE_CONVEX_URL: string; +} + +interface ImportMeta { + readonly env: ImportMetaEnv; +} diff --git a/packages/env/src/web.ts b/packages/env/src/web.ts index dfca322..ac891bb 100644 --- a/packages/env/src/web.ts +++ b/packages/env/src/web.ts @@ -7,12 +7,11 @@ const convexUrlSchema = (exampleHost: string) => }); export const env = createEnv({ - clientPrefix: "VITE_", client: { - VITE_CONVEX_URL: convexUrlSchema("example.convex.cloud"), VITE_CONVEX_SITE_URL: convexUrlSchema("example.convex.site"), + VITE_CONVEX_URL: convexUrlSchema("example.convex.cloud"), }, - runtimeEnv: (import.meta as any).env, - skipValidation: !!process.env.SKIP_ENV_VALIDATION, + clientPrefix: "VITE_", emptyStringAsUndefined: true, + runtimeEnv: import.meta.env, });