| author | |
| committer | |
| log | b3de243d5ed44783c4e7990d8e63cb519d390a03 |
| tree | 13557e4ad2a5227c94a6cf3ab4059ff042011707 |
| parent | d10bd1360ace3ab1dbccc1ee706c9169982d98ae |
| signature | Signed by PGP key B5690EEEBB952194 |
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>4 files changed, 51 insertions(+), 12 deletions(-)
docs/operations/development.md+1-2| ... | ... | @@ -76,8 +76,7 @@ Put that value in the main checkout's gitignored `.env`: |
| 76 | 76 | T3CODE_DEV_AUTH_TOKEN=<the value generated above> |
| 77 | 77 | ``` |
| 78 | 78 | |
| 79 | The `t3.json` Setup Worktree commands on Unix and Windows link that file to each worktree's | |
| 80 | `.env`. The dev runner reads repository env files at startup. `.env.local` and inherited process | |
| 79 | The `t3.json` Setup Worktree action links that file to each worktree's `.env`. The dev runner reads repository env files at startup. `.env.local` and inherited process | |
| 81 | 80 | environment values override `.env`, so no per-worktree export is needed after setup. |
| 82 | 81 | |
| 83 | 82 | For a manual worktree or launcher without that link, export the same fixed value instead: |
knip.jsonc+4-3| ... | ... | @@ -13,8 +13,9 @@ |
| 13 | 13 | "vitest": { "entry": [".github/**/*.test.cjs"] }, |
| 14 | 14 | }, |
| 15 | 15 | "scripts": { |
| 16 | // Knip loads its preprocessor through a CLI option; native verification runs directly. | |
| 17 | "entry": ["knip-schemas.ts", "mobile-native-client.ts"], | |
| 16 | // Knip loads its preprocessor through a CLI option; native verification and | |
| 17 | // worktree setup (from t3.json) run directly. | |
| 18 | "entry": ["knip-schemas.ts", "mobile-native-client.ts", "setup-worktree.ts"], | |
| 18 | 19 | }, |
| 19 | 20 | "apps/server": { |
| 20 | 21 | // Vite+ pack entries and the launcher used by installed background services. |
| ... | ... | @@ -52,7 +53,7 @@ |
| 52 | 53 | "ignoreDependencies": ["playwright-core", "electron-builder"], |
| 53 | 54 | }, |
| 54 | 55 | "apps/web": { |
| 55 | // Worktree setup invokes this directly from t3.json. | |
| 56 | // Worktree setup (scripts/setup-worktree.ts) runs this directly. | |
| 56 | 57 | "entry": ["scripts/warm-dep-cache.ts"], |
| 57 | 58 | // UI component modules are copied and adapted as cohesive sets. Keep their |
| 58 | 59 | // named subcomponents even before they have callers; the file audit still |
scripts/setup-worktree.ts created+45| ... | ... | @@ -0,0 +1,45 @@ |
| 1 | // @effect-diagnostics nodeBuiltinImport:off - runs before `vp i`, so only Node built-ins exist. | |
| 2 | /** | |
| 3 | * Worktree setup, run by the t3.json "Setup Worktree" action as | |
| 4 | * `node scripts/setup-worktree.ts`. Plain Node keeps one command working in | |
| 5 | * every shell T3 Code spawns (zsh, bash, fish, PowerShell): it installs | |
| 6 | * dependencies, links the main checkout's gitignored env files into this | |
| 7 | * worktree, then warms the web dependency cache. | |
| 8 | */ | |
| 9 | import * as NodeChildProcess from "node:child_process"; | |
| 10 | import * as NodeFS from "node:fs"; | |
| 11 | import * as NodePath from "node:path"; | |
| 12 | ||
| 13 | const ENV_FILES = [".env", NodePath.join("infra", "relay", ".env")]; | |
| 14 | ||
| 15 | const projectRoot = process.env.T3CODE_PROJECT_ROOT; | |
| 16 | if (!projectRoot) { | |
| 17 | throw new Error("T3CODE_PROJECT_ROOT is not set. Run this through the t3.json setup action."); | |
| 18 | } | |
| 19 | const worktree = NodePath.dirname(import.meta.dirname); | |
| 20 | ||
| 21 | // `shell` resolves `vp` through PATH, including Windows command shims. | |
| 22 | const install = NodeChildProcess.spawnSync("vp i", { | |
| 23 | cwd: worktree, | |
| 24 | shell: true, | |
| 25 | stdio: "inherit", | |
| 26 | }); | |
| 27 | if (install.status !== 0) process.exit(install.status ?? 1); | |
| 28 | ||
| 29 | // In the main checkout itself, relinking would replace the real env files. | |
| 30 | if (NodeFS.realpathSync(projectRoot) !== NodeFS.realpathSync(worktree)) { | |
| 31 | for (const file of ENV_FILES) { | |
| 32 | const source = NodePath.join(projectRoot, file); | |
| 33 | if (!NodeFS.existsSync(source)) continue; | |
| 34 | const target = NodePath.join(worktree, file); | |
| 35 | NodeFS.rmSync(target, { force: true }); | |
| 36 | NodeFS.symlinkSync(source, target); | |
| 37 | } | |
| 38 | } | |
| 39 | ||
| 40 | const warm = NodeChildProcess.spawnSync( | |
| 41 | process.execPath, | |
| 42 | [NodePath.join(worktree, "apps", "web", "scripts", "warm-dep-cache.ts")], | |
| 43 | { cwd: worktree, stdio: "inherit" }, | |
| 44 | ); | |
| 45 | process.exit(warm.status ?? 1); |
t3.json+1-7| ... | ... | @@ -4,13 +4,7 @@ |
| 4 | 4 | "scripts": [ |
| 5 | 5 | { |
| 6 | 6 | "name": "Setup Worktree", |
| 7 | "command": "vp i && ln -sf $T3CODE_PROJECT_ROOT/.env .env && ln -sf $T3CODE_PROJECT_ROOT/infra/relay/.env infra/relay/.env && node apps/web/scripts/warm-dep-cache.ts", | |
| 8 | "icon": "configure", | |
| 9 | "runOnWorktreeCreate": true | |
| 10 | }, | |
| 11 | { | |
| 12 | "name": "Setup Worktree (Windows)", | |
| 13 | "command": "vp i && New-Item -ItemType SymbolicLink -Path .env -Target \"$env:T3CODE_PROJECT_ROOT\\.env\" -Force && New-Item -ItemType SymbolicLink -Path \"infra\\relay\\.env\" -Target \"$env:T3CODE_PROJECT_ROOT\\infra\\relay\\.env\" -Force && node apps\\web\\scripts\\warm-dep-cache.ts", | |
| 7 | "command": "node scripts/setup-worktree.ts", | |
| 14 | 8 | "icon": "configure", |
| 15 | 9 | "runOnWorktreeCreate": true |
| 16 | 10 | } |