Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions .githooks/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,33 @@ after branch checkout and worktree creation before Git returns. T3 configures
the hook path and triggers that checkout once for a fresh clone, before exposing
the repository to the user.

## `post-checkout`

### 1. Clear TypeScript project emit (always on branch / worktree checkout)

Composite packages and build outputs leave gitignored `dist/` and
`*.tsbuildinfo`. After a branch switch those artifacts can still belong to
another tree while sources follow HEAD. That produces phantom type errors (or
stale emit consumers) that disappear after a clean rebuild — same class of
failure as [scanner#1495](https://github.com/macs-holding/scanner/pull/1495) /
[scanner#2166](https://github.com/macs-holding/scanner/pull/2166) and upstream
typescript-go incremental gaps.

On every **branch** checkout (flag `1`), this hook deletes:

- `apps/*/dist`, `apps/*/dist-electron`, `packages/*/dist`
- any remaining `*.tsbuildinfo` outside `node_modules` / `.git` / `.vite-plus`

File-only checkouts (flag `0`) are left alone.

**This is a workaround.** Remove when TypeScript/tsgo incremental invalidation
is reliable ([typescript-go#2666](https://github.com/microsoft/typescript-go/issues/2666),
[#4664](https://github.com/microsoft/typescript-go/issues/4664),
[#4262](https://github.com/microsoft/typescript-go/issues/4262)). Do not
re-enable cross-tree dist reuse without an exact source-identity key.

### 2. Seed copy + pnpm install

Successful reconciliation records the package/lockfile state under
`node_modules`, so T3's explicit handoff invocation does not repeat an install
which Git already completed. Explicit invocation from the target is required
Expand Down
52 changes: 50 additions & 2 deletions .githooks/post-checkout
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@
# guest -- not only when a worktree is created through the T3 app / t3.json.
#
# Strategy (metadata-safe):
# 1. Copy *small* gitignored seeds from .worktreeinclude (CLAUDE.md, .nuxt, …)
# 1. Drop TypeScript project emit (dist / tsbuildinfo) so composite/incremental
# builds never typecheck against foreign-tree .d.ts after a branch switch.
# 2. Copy *small* gitignored seeds from .worktreeinclude (CLAUDE.md, .nuxt, …)
# via reflink/hardlink when available. NEVER clone node_modules -- that
# creates millions of inodes per worktree on btrfs.
# 2. Populate node_modules with `pnpm install --frozen-lockfile --prefer-offline`
# 3. Populate node_modules with `pnpm install --frozen-lockfile --prefer-offline`
# against the shared store (hardlinks -> one inode per package file).
#
# Idempotent: never overwrites existing seed paths; pnpm is safe to re-run.
Expand All @@ -26,6 +28,52 @@ main_wt=$(git worktree list --porcelain | sed -n '1s/^worktree //p')
wt_root=$(git rev-parse --show-toplevel 2>/dev/null)
[ -n "$wt_root" ] || exit 0

# --- TS build-cache wipe (every branch / worktree checkout) -----------------
#
# Composite/incremental emit (and leftover dist from builds) can outlive a
# branch switch. Foreign .tsbuildinfo / .d.ts produce phantom type errors that
# vanish after clean rebuild — same class as macs-holding/scanner#1495 / #2166
# and typescript-go incremental gaps (#2666, #4664, #4262).
# Workaround until upstream invalidation is solid; see .githooks/README.md.
#
clean_ts_project_emit() {
root=$1
removed=0

for d in \
"$root"/apps/*/dist \
"$root"/apps/*/dist-electron \
"$root"/packages/*/dist
do
[ -e "$d" ] || continue
rm -rf "$d"
removed=1
done

if [ -d "$root" ]; then
# Prune by basename so nested apps/*/node_modules are skipped too.
tsbuild_files=$(
find "$root" \
\( -name node_modules -o -name .git -o -name .vite-plus \) -prune -o \
-type f -name '*.tsbuildinfo' -print 2>/dev/null || true
)
if [ -n "$tsbuild_files" ]; then
printf '%s\n' "$tsbuild_files" | while IFS= read -r f; do
[ -n "$f" ] || continue
rm -f "$f"
done
removed=1
fi
fi

if [ "$removed" = 1 ]; then
echo "post-checkout: cleared TypeScript project emit (dist / tsbuildinfo) under $root" >&2
echo "post-checkout: workaround for tsgo/tsc stale incremental cache after tree switch — see .githooks/README.md (remove when upstream fixed)" >&2
fi
}

clean_ts_project_emit "$wt_root"

if [ -n "$main_wt" ] && [ "$main_wt" != "$wt_root" ]; then
# Effective include: repo .worktreeinclude if present, else nothing to seed-copy.
include=""
Expand Down
Loading