Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
163 commits
Select commit Hold shift + click to select a range
0c4fd9a
chore(fork-base): fork workflows, stack tools, and docs
github-actions[bot] Aug 5, 2026
6f041e7
feat(tim): import tim-smart/t3code#4
tim-smart Jul 26, 2026
d0a0f27
feat(tim): import tim-smart/t3code#5
tim-smart Jul 26, 2026
3fc1b9d
feat(tim): import tim-smart/t3code#6
tim-smart Jul 26, 2026
c764e77
feat(tim): import tim-smart/t3code#7
tim-smart Jul 26, 2026
39de3ca
feat(tim): import tim-smart/t3code#8
tim-smart Jul 26, 2026
b0430ba
feat(tim): import tim-smart/t3code#9
tim-smart Jul 26, 2026
d684900
feat(tim): import tim-smart/t3code#10
tim-smart Jul 26, 2026
0b72243
feat(tim): import tim-smart/t3code#11
tim-smart Jul 26, 2026
a4bfaf5
feat(tim): import tim-smart/t3code#12
tim-smart Jul 26, 2026
02293d4
feat(tim): import tim-smart/t3code#13
tim-smart Jul 26, 2026
09de734
feat(tim): import tim-smart/t3code#14
tim-smart Jul 26, 2026
6efa3aa
feat(tim): import tim-smart/t3code#15
tim-smart Jul 26, 2026
05a8164
feat(tim): import tim-smart/t3code#16
tim-smart Jul 26, 2026
204a84c
feat(tim): import tim-smart/t3code#17
tim-smart Jul 26, 2026
54fb15c
fix(tim-compat): product-merge VCS #4727 with fork failureKind; green…
github-actions[bot] Jul 29, 2026
f9bf8f9
fix(tim): restore resource telemetry join + TRACE2 hook exits
github-actions[bot] Jul 29, 2026
0b208e6
fix(tim): settings search test after worktree-confirm catalog entry
github-actions[bot] Aug 1, 2026
f19efaa
chore: initialize upstream candidate registry
patroza Jul 25, 2026
a618f5f
perf: import bounded web thread history (upstream #4018) (#29)
patroza Jul 25, 2026
555c6f2
perf: import mobile pagination and bounded replay (upstream #3510) (#35)
patroza Jul 25, 2026
7edd051
perf: import bounded long-lived state (upstream #4176) (#34)
patroza Jul 25, 2026
110a84c
feat(web): import answered question timeline (upstream #4506) (#44)
patroza Jul 25, 2026
b516a87
feat(orchestrator): import upstream follow-up queue (#4245) (#63)
patroza Jul 25, 2026
2420ef7
fix(client-runtime): re-read network status when the app resumes (ups…
patroza Jul 26, 2026
fa85f1d
perf(server): compress and cache packaged web assets (upstream #4516)
patroza Jul 26, 2026
b11f894
perf(server): back off repeated checkpoint capture failures (upstream…
patroza Jul 26, 2026
00c56ac
fix(server): preserve manually renamed thread titles (upstream #4558)
patroza Jul 26, 2026
fa43102
fix(client): refresh workspace files after disk changes (upstream #43…
github-actions[bot] Aug 5, 2026
21d5c6f
perf(client): batch large thread sync updates (upstream #5344) (#328)
patroza Aug 5, 2026
ab949db
chore(fork): stack docs, overlays, tooling, CI, and workspace
github-actions[bot] Jul 31, 2026
605402b
feat(contracts): fork protocol and settings schema extensions
github-actions[bot] Jul 31, 2026
5c015e2
feat(shared): shared helpers and Hermes lint guards
github-actions[bot] Jul 31, 2026
5b114fb
feat(client-runtime): reconnect diagnostics, VCS actions, and list state
github-actions[bot] Jul 31, 2026
5365f31
feat(packages): ssh, tailscale, and effect-acp fork deltas
github-actions[bot] Jul 31, 2026
3457d61
feat(server): queue, recovery, VCS, Jira, orchestration, and RPC auth
github-actions[bot] Jul 31, 2026
bfceb4f
feat(web): sidebar, composer, timeline, search, and chrome fork product
github-actions[bot] Jul 31, 2026
732406a
feat(mobile): home modes, board, queue composer, and scroll baseline
github-actions[bot] Jul 31, 2026
4f29edd
feat(desktop): packaging, open-with, and backend ownership deltas
github-actions[bot] Jul 31, 2026
ec288c3
feat(settings): default new threads to new worktree from origin (#252)
omegent-app[bot] Jul 31, 2026
e9ee7c5
feat(web): recover cleanly across hot-swapped deployments
omegent-app[bot] Jul 31, 2026
873a284
fix(mobile): make EAS continuous delivery resilient
patroza Jul 31, 2026
38b47de
fix(server): preserve and resume threads through restart recovery
patroza Aug 1, 2026
aef0bc3
feat(sidebar): align clients with v2 shelves, pinning, and pull requests
omegent-app[bot] Aug 1, 2026
7667f93
feat(worktrees): coordinate lifecycle scripts and asynchronous setup
omegent-app[bot] Aug 2, 2026
78a1167
fix(server): isolate and bound provider command workers
patroza Aug 2, 2026
2ef0709
feat(tooling): enforce repository-owned agent ship gates
omegent-app[bot] Aug 2, 2026
57bf439
feat(server): link Jira replies and isolate auto-created worktrees
patroza Aug 3, 2026
dd2b438
feat(server): reap idle dev stacks from a level-triggered sweep (#296)
patroza Aug 3, 2026
818ba27
fix(vcs): treat bare repositories as valid worktree sources (#307)
patroza Aug 4, 2026
b002f66
fix(usage): stop extra-usage credit pools from marking a provider out…
patroza Aug 4, 2026
271c4b2
feat(queue): keep queued sends out of timelines and support send-now …
patroza Aug 4, 2026
2521758
chore(f7d37879-desktop-deeplinks): reapply product after upstream res…
github-actions[bot] Jul 31, 2026
03c7ebe
fix(desktop): keep upstream Clerk catalog after reapply
github-actions[bot] Jul 31, 2026
7b63754
fix(desktop): type ClerkBridge mocks with isPrimaryInstance
github-actions[bot] Jul 31, 2026
d0b2e4b
fix(desktop): include requestSingleInstanceLock in update test stubs
github-actions[bot] Jul 31, 2026
5ba2606
fix(desktop): stop overlay reapply from stripping project search cont…
github-actions[bot] Jul 31, 2026
b925c48
fix(desktop): restore hydratePosixHome after overlay reapply
github-actions[bot] Jul 31, 2026
7833b3c
fix(desktop): bind Clerk bridge for isPrimaryInstance check
github-actions[bot] Aug 1, 2026
ec97b5a
fix(desktop): keep Effect beta.103 catalogs after overlay reapply
patroza Aug 4, 2026
3f6153a
chore(discord): reapply bot product without shared web deep links
github-actions[bot] Jul 31, 2026
42c2567
fix(discord-bot): always put T3 deep link on final stats footer (#268)
omegent-app[bot] Jul 31, 2026
c407f11
fix(discord-bot): resolve worktree-relative files for Discord attach …
omegent-app[bot] Jul 31, 2026
b644b64
style(discord): satisfy oxfmt on asciiTables fence check
github-actions[bot] Aug 1, 2026
340099c
fix(discord): fail-closed agent gate for unmapped users (#277)
omegent-app[bot] Aug 1, 2026
faacdb2
fix(discord-bot): stop sticky session last_error re-paging forever (#…
omegent-app[bot] Aug 1, 2026
a459f53
fix(server): abandon unadoptable pending turn starts (#278)
omegent-app[bot] Aug 1, 2026
643facd
fix(discord-bot): put T3 thread id on short ops alerts; skip interrup…
omegent-app[bot] Aug 1, 2026
cb3904f
fix(discord-bot): stop double channel rename for mid-busy ▫️ (#287)
omegent-app[bot] Aug 2, 2026
7aac541
chore(vscode): reapply product after upstream restack (no docs reorg)
github-actions[bot] Jul 31, 2026
acc41d5
fix(vscode): regenerate lockfile for apps/vscode importer
github-actions[bot] Jul 31, 2026
d307c29
feat(identity): session identity overlay with participation and Jira …
github-actions[bot] Jul 31, 2026
5d94e59
fix(identity): Mine includes unattributed and channel-only threads (#…
omegent-app[bot] Jul 31, 2026
b7ca076
fix(identity): keep resolveSelectableModelSelection after overlay rea…
github-actions[bot] Jul 31, 2026
4a62ba6
feat(identity): persist ownership filters and add relation sub-filter…
patroza Jul 31, 2026
ac5de34
fix(identity): make ownership relation refine, not invert Theirs (#259)
patroza Jul 31, 2026
66ea845
fix(identity): restore showcase iOS orientation field after restack
github-actions[bot] Aug 1, 2026
d90796f
fix(identity): restore app-update launch import after restack
github-actions[bot] Aug 1, 2026
df3106c
fix(identity): align showcase URL tests with production scheme
github-actions[bot] Aug 1, 2026
c55e737
fix(identity): fail-closed connector agent access without map (#276)
omegent-app[bot] Aug 1, 2026
2efd257
docs(identity): correct stale claim-persistence comment (#279)
patroza Aug 1, 2026
da25a47
feat(identity): reload the identity map without a server restart (#280)
patroza Aug 1, 2026
2e43243
feat(web): Mine/Theirs ownership filter on sidebar v1, default Mine (…
omegent-app[bot] Aug 2, 2026
f9efba3
fix(identity): attribute commits from every client (#314)
patroza Aug 4, 2026
d82a8e7
fix(identity): dedupe connector attribution (#315)
patroza Aug 4, 2026
aa830e8
fix(identity): restore ForwardCompatibleArray after restack
patroza Aug 4, 2026
803d3a6
fix(identity): move migrations to fork ledger
github-actions[bot] Aug 5, 2026
4f113db
test(server): cover deployed migration ledgers
github-actions[bot] Aug 5, 2026
21badd0
chore(integration): regenerate pnpm-lock.yaml after overlay compose
github-actions[bot] Aug 5, 2026
e4bd4b1
ci(fork): run Fork CI for fork/dev PRs and merges (#343)
omegent-app[bot] Aug 6, 2026
a8de419
fix(mobile): accept a release branch other than fork/integration (#344)
omegent-app[bot] Aug 6, 2026
ae4719b
sync(provenance): import upstream stack C1..C2 (#345)
omegent-app[bot] Aug 6, 2026
cc023c1
fix(mobile): declare the release_branch input on EAS development (#346)
omegent-app[bot] Aug 6, 2026
3a7e7a4
chore(provenance): record upstream a2ca89aa1 as an ancestor
omegent-app[bot] Aug 6, 2026
a5ff7e4
ci(fork): split release dispatch out of the validation gate (#347)
omegent-app[bot] Aug 6, 2026
6a982f7
chore(stack): drain the integration overlays (#348)
omegent-app[bot] Aug 6, 2026
885f127
ci(fork): report the full release scope, not just mobile (#349)
omegent-app[bot] Aug 6, 2026
563ab39
feat(identity): centralize thread attribution (#318)
patroza Aug 6, 2026
c592ad4
refactor(discord): defer commit attribution to server (#319)
patroza Aug 6, 2026
2e5da8e
fix(discord): preserve inbound message order (#350)
patroza Aug 6, 2026
4a13d96
feat(vscode): pair with pairing URL (#351)
omegent-app[bot] Aug 6, 2026
912340b
fix(web): show Monitoring on board cards instead of Working (#356)
omegent-app[bot] Aug 6, 2026
9187733
ci(fork): coalesce releases instead of cancelling validation (#353)
omegent-app[bot] Aug 6, 2026
65c3850
docs: record the stable fork/dev development and release branch (#342)
patroza Aug 6, 2026
ace285b
ci(fork): run PR checks when a PR is retargeted or marked ready (#359)
omegent-app[bot] Aug 6, 2026
cc8f899
fix(discord-bot): suppress embeds on all bot messages (#355)
omegent-app[bot] Aug 6, 2026
5e0c51e
fix(discord-bot): queue mentions while T3 is still connecting (#354)
omegent-app[bot] Aug 6, 2026
a6dacf8
docs(server): gh auth retry lives in gh-app-wrapper (ops) (#358)
omegent-app[bot] Aug 6, 2026
24f5735
fix: vscode queue parity, V2 env filters, empty web deploys (#361)
patroza Aug 6, 2026
62708e8
fix(server): stop re-fetching PRs for settled/merged worktrees (#362)
patroza Aug 6, 2026
9ba9b1d
fix(discord-bot): rewrite GFM tables to bullets for Discord (#357)
omegent-app[bot] Aug 6, 2026
f5a759f
sync(upstream): merge upstream/main a483337a0 into fork/dev
omegent-app[bot] Aug 6, 2026
707b68a
chore(stack): remove stack tooling, scope the draft lock, align docs …
omegent-app[bot] Aug 6, 2026
8750458
ci(fork): drop the edited trigger, it can clear a red PR (#365)
omegent-app[bot] Aug 6, 2026
7fec007
fix(vscode): support upstream T3 Code servers (#366)
patroza Aug 6, 2026
93fadd2
fix(server): preserve dist/client across pack so deploys stay non-emp…
patroza Aug 6, 2026
15a0c5d
sync(upstream): merge upstream/main aa16c180e into fork/dev
omegent-app[bot] Aug 6, 2026
009b3f9
sync(upstream): merge upstream/main 4f5834ba7 into fork/dev
omegent-app[bot] Aug 6, 2026
b8df938
ci(fork): move to a new concurrency generation (#369)
omegent-app[bot] Aug 7, 2026
a19d3ea
sync(upstream): merge upstream/main 6b73b3def into fork/dev
omegent-app[bot] Aug 7, 2026
54187a4
Merge pull request #368 from patroza/sync/upstream-6b73b3def
patroza Aug 7, 2026
d5ac3b9
sync(upstream): merge upstream/main 48aa875c0 into fork/dev
omegent-app[bot] Aug 7, 2026
95aea55
Merge pull request #372 from patroza/sync/upstream-48aa875c0
patroza Aug 7, 2026
1e80411
fix(tooling): keep GitHub App auth when the agent gh shim delegates (…
omegent-app[bot] Aug 7, 2026
68f5bf6
sync(upstream): merge upstream/main 23f0a1ae3 into fork/dev
omegent-app[bot] Aug 7, 2026
74a1459
Merge pull request #374 from patroza/sync/upstream-23f0a1ae3
patroza Aug 7, 2026
61734b8
sync(upstream): merge upstream/main 8100062a7 into fork/dev
omegent-app[bot] Aug 7, 2026
daa964a
Merge pull request #375 from patroza/sync/upstream-8100062a7
patroza Aug 7, 2026
5063fab
sync(upstream): merge upstream/main b2ee17d7c into fork/dev
omegent-app[bot] Aug 7, 2026
f8d8555
Merge pull request #377 from patroza/sync/upstream-b2ee17d7c
patroza Aug 7, 2026
4fdb933
sync(upstream): merge upstream/main 239ef1c54 into fork/dev
omegent-app[bot] Aug 7, 2026
25af886
Merge pull request #378 from patroza/sync/upstream-239ef1c54
omegent-app[bot] Aug 7, 2026
687a2d9
sync(upstream): merge upstream/main 6d70e6d77 into fork/dev
omegent-app[bot] Aug 7, 2026
b962e2b
sync(upstream): merge upstream/main 5661c6116 into fork/dev
omegent-app[bot] Aug 7, 2026
ee09e67
fix(mobile): stop iOS crash when attaching images (#380)
patroza Aug 8, 2026
6ebaa5f
Merge pull request #379 from patroza/sync/upstream-6d70e6d77
patroza Aug 8, 2026
f00ff8c
sync(upstream): merge upstream/main 064041072 into fork/dev
omegent-app[bot] Aug 8, 2026
9bbb0a0
Merge pull request #381 from patroza/sync/upstream-064041072
patroza Aug 8, 2026
3cbce35
sync(upstream): merge upstream/main a20923ce4 into fork/dev
omegent-app[bot] Aug 8, 2026
89ed356
Merge pull request #382 from patroza/sync/upstream-a20923ce4
omegent-app[bot] Aug 8, 2026
be8393d
merge: sync upstream through ba9c9ae81
omegent-app[bot] Aug 9, 2026
885b287
fix: repair the merge welds both adversarial reviews found
omegent-app[bot] Aug 9, 2026
0b23962
Merge pull request #383 from patroza/sync/upstream-ba9c9ae81
patroza Aug 9, 2026
841252c
merge: sync upstream through 02f4ce566
omegent-app[bot] Aug 9, 2026
3c22551
fix(discord-bot): page long-running turns on 15m×2ⁿ milestones (#384)
patroza Aug 9, 2026
53c56fd
Merge pull request #385 from patroza/sync/upstream-02f4ce566
patroza Aug 9, 2026
b89de3a
ci: point the adopted web-preview workflow at the fork's runners (#386)
omegent-app[bot] Aug 9, 2026
13a789e
feat(usage): report Grok and Kimi in the usage overviews (#387)
omegent-app[bot] Aug 10, 2026
21a7be1
merge: sync upstream through 3d74474f6
omegent-app[bot] Aug 10, 2026
d577ef0
fix(usage): make the provider order exhaustive by type
omegent-app[bot] Aug 10, 2026
5f0e08c
ci: point the adopted fingerprint check at the fork's runners
omegent-app[bot] Aug 10, 2026
f067b34
Merge pull request #388 from patroza/sync/upstream-3d74474f6
omegent-app[bot] Aug 10, 2026
b61ab57
fix(web): the board follows the mine/theirs filter (#389)
omegent-app[bot] Aug 10, 2026
4f3b2a5
feat(web): board cards show where a thread came from (#390)
omegent-app[bot] Aug 10, 2026
e0c2932
feat(discord-bot): flag app-originated echoes with a thought bubble (…
omegent-app[bot] Aug 10, 2026
b4617a7
merge: sync upstream through 0a7c662d3
omegent-app[bot] Aug 10, 2026
46200ae
fix: retire the superseded native confirm and finish the PR wiring
omegent-app[bot] Aug 10, 2026
bd5fac7
Merge pull request #392 from patroza/sync/upstream-0a7c662d3
omegent-app[bot] Aug 10, 2026
4ad8660
fix(vscode): pad server system info bars (#393)
patroza Aug 10, 2026
fd87ef9
merge: sync upstream through 9c7622dac
omegent-app[bot] Aug 11, 2026
01a4cee
docs(web): say what the snoozed-shelf key actually is
omegent-app[bot] Aug 11, 2026
d84653d
Merge pull request #394 from patroza/sync/upstream-9c7622dac
omegent-app[bot] Aug 11, 2026
2c66555
feat(discord-bot): offload >10MB attachments to Azure Blob with 3-day…
omegent-app[bot] Aug 11, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
17 changes: 17 additions & 0 deletions .agents/skills/test-t3-app/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,23 @@ Shared browser dev is single-origin: Vite proxies the backend paths, so never se

The dev runner disables browser auto-open by default. Do not pass `--browser` during automated testing: an automatically opened page can consume the one-time bootstrap token before the controlled browser uses it.

### Previewing the dev server from a remote client

When T3 itself is being driven from another machine — the app connected to this environment over a
tailnet or LAN address rather than `localhost` — a dev server bound to loopback is not reachable at
that address just because the hostname is. Opening it does **not** require `--share`: the
environment resolves the port on demand, reusing an existing `tailscale serve` route, using the
environment's own address when the port already answers there, and otherwise publishing a
tailnet-only HTTPS route for the port and withdrawing it when the dev server exits.

Give the preview a `localhost:<port>` URL and let it resolve. Never hand-write the environment's
hostname with the dev port appended — that is the shape that fails, because nothing promises the
dev port is published under the same number or scheme.

If the port cannot be made reachable, the preview reports why and what to do (dev server not
running, tailscale not logged in, no permission to manage routes, tailnet port already taken).
Treat that message as the result; do not retry the same URL.

### Verify a shared environment before human handoff

When another person will use the printed pairing URL, first open the shared origin without the pairing path or fragment in the controlled browser and confirm the T3 Code app loads. This browser navigation is required even when curl succeeds because browsers block some otherwise reachable ports before making a network request.
Expand Down
2 changes: 1 addition & 1 deletion .agents/skills/test-t3-mobile/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ Use these client origins:
- Android Emulator: `http://10.0.2.2:<server-port>`
- Physical device: bind the backend to `0.0.0.0` and use the host's reachable LAN origin

Enter the complete `http://` origin to make the test transport explicit. Bare IP addresses default to HTTP, while bare hostnames default to HTTPS. When testing web and mobile together, run `vp run dev --home-dir <base-dir> --host 127.0.0.1` instead and do not launch a second backend over the same base directory.
Always enter the complete `http://` origin; the mobile host field otherwise assumes HTTPS. When testing web and mobile together, run `vp run dev --home-dir <base-dir> --host 127.0.0.1` instead and do not launch a second backend over the same base directory.

## Start or reuse Metro safely

Expand Down
56 changes: 56 additions & 0 deletions .easignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# Keep EAS project archives small. Mobile only needs the monorepo packages it
# resolves through pnpm — not vendored agent reference trees or desktop shells.

# Vendored reference repos (agents only; never imported by app code)
.repos/

# Desktop / electron / native host tooling
apps/desktop/
apps/vscode/
apps/discord-bot/
/native/
release/
release-mock/
dist-electron/
.electron-runtime/

# Infra, docs, agent metadata
docs/
.agents/
.grok/
.github/
.claude/
.cursor/
.vscode/
infra/
artifacts/
.showcase/
apps/mobile/.showcase/

# Tests and snapshots (not needed for EAS bundle)
**/__screenshots__/
**/*.test.ts
**/*.test.tsx
**/*.spec.ts
**/*.spec.tsx
**/test-results/
**/playwright-report/
**/.vitest-*/

# Local / generated
node_modules/
.t3/
.turbo/
.alchemy/
.dir-deploy-n
.logs/
*.log
.DS_Store
.env
.env.*
!.env.example

# Git / IDE noise
.git/
.idea/
*.tsbuildinfo
21 changes: 21 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,17 @@ T3CODE_CLERK_CLI_OAUTH_CLIENT_ID=hzxSgY2cH10sDU2r
# automatically.
T3CODE_RELAY_URL=https://relay.t3.codes

# Optional: GitHub App bridge for continuing an existing worktree-backed T3 thread
# from a pull-request comment. See docs/integrations/github-app-setup.md.
# The webhook route stays disabled unless all four required values are set.
# T3CODE_GITHUB_APP_ID=123456
# T3CODE_GITHUB_APP_PRIVATE_KEY_PATH=/absolute/path/to/private-key.pem
# T3CODE_GITHUB_WEBHOOK_SECRET=replace-with-a-random-secret
# T3CODE_GITHUB_APP_MENTION=t3-code-dev
# T3CODE_GITHUB_ALLOWED_REPOSITORIES=owner/repository,owner/another-repository
# T3CODE_GITHUB_MIN_PERMISSION=write
# T3CODE_GITHUB_TURN_TIMEOUT_MS=1800000

# Optional: hosted app origin used by the CLI's out-of-band OAuth flow.
# Defaults to https://app.t3.codes; override to test against a staging deployment.
# T3CODE_HOSTED_APP_URL=https://nightly.app.t3.codes
Expand All @@ -29,3 +40,13 @@ T3CODE_RELAY_URL=https://relay.t3.codes
# T3CODE_MOBILE_OTLP_TRACES_URL=https://api.axiom.co/v1/traces
# T3CODE_MOBILE_OTLP_TRACES_DATASET=t3-code-mobile-traces-dev
# T3CODE_MOBILE_OTLP_TRACES_TOKEN=xaat-...

# Optional: sign and publish the mobile app from your own Expo and Apple teams.
# Development and preview builds append .dev and .preview to the bundle identifier.
# T3CODE_MOBILE_IOS_TEAM_ID=ABC1234567
# T3CODE_MOBILE_IOS_BUNDLE_IDENTIFIER=com.example.t3code
# Set to 1 only for free Xcode Personal Team builds. This disables paid-only
# widgets, push capabilities, App Groups, associated domains, and EAS updates.
# T3CODE_MOBILE_IOS_PERSONAL_TEAM=1
# T3CODE_MOBILE_EAS_PROJECT_ID=00000000-0000-0000-0000-000000000000
# T3CODE_MOBILE_EXPO_OWNER=your-expo-username
9 changes: 9 additions & 0 deletions .envrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Prefer the repo gh policy shim so coding agents cannot undraft with raw
# `gh pr ready` (use `pnpm pr:ready`). Installed by scripts/install-git-hooks.mjs.
PATH_add .tools/bin

# Default bare `gh` commands to the fork, not gh's upstream-parent default
# (`pingdotgg/t3code`). Without this, `gh pr view`/`create`/`checks` resolve
# against upstream and miss the fork's PRs. Explicit `--repo` always overrides,
# so the stack tooling (which always passes `--repo`) is unaffected.
export GH_REPO="${T3CODE_FORK_REPOSITORY:-patroza/t3code}"
47 changes: 47 additions & 0 deletions .githooks/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# Native Git hooks

`pnpm install` configures `core.hooksPath=.githooks`. The tracked hooks exist
immediately in every linked worktree; `post-checkout` reconciles dependencies
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
for bare or stale source repositories.

When T3 will launch a configured worktree setup script, its VCS driver sets
`T3CODE_DEFER_DEPENDENCY_INSTALL=1`. The hook still clears stale emit and copies
seed files, but skips `pnpm install` so setup can perform it asynchronously in
the thread terminal. Raw Git worktree creation does not set this marker and
continues to return with dependencies prepared.

Lefthook may later orchestrate parallel jobs, but is intentionally unused now.
168 changes: 168 additions & 0 deletions .githooks/post-checkout
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
#!/bin/sh
# Reconcile packages after branch checkout and prepare linked git worktrees.
#
# Canonical hook: scripts/install-git-hooks.mjs installs this into the shared
# hooks dir (core.hooksPath) on EVERY host via `pnpm install`, so a raw
# `git worktree add` sets up node_modules identically on smart and the t3vm
# guest -- not only when a worktree is created through the T3 app / t3.json.
#
# Strategy (metadata-safe):
# 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.
# 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.

# Host-agnostic: pick up pnpm/mise from the invoking user's home on either host.
PATH="$HOME/.local/bin:$HOME/.local/share/pnpm:$HOME/.local/share/mise/shims:/run/current-system/sw/bin:/usr/local/sbin:/usr/local/bin:/usr/bin:/bin:$PATH"
export PATH

# post-checkout also runs after file-only checkouts; those do not change packages.
[ "${3:-0}" = "1" ] || exit 0

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=""
if [ -f "$main_wt/.worktreeinclude" ]; then
include="$main_wt/.worktreeinclude"
fi

# Probe once: reflink (CoW fs) > hard link (same fs) > plain copy (cross-device).
probe="$main_wt/.git-hook-clone-probe.$$"
probe_dst="$wt_root/.clone-probe.$$"
: >"$probe"
if cp --reflink=always "$probe" "$probe_dst" 2>/dev/null; then
clone() { cp -a --reflink=always "$1" "$2"; }
elif ln "$probe" "$probe_dst" 2>/dev/null; then
clone() { cp -al "$1" "$2"; }
else
clone() { cp -a "$1" "$2"; }
fi
rm -f "$probe" "$probe_dst"

# True if path is node_modules or under one (never clone these).
is_node_modules_path() {
case "/$1/" in
*/node_modules/*) return 0 ;;
*) return 1 ;;
esac
}

if [ -n "$include" ] && [ -f "$include" ]; then
git -C "$main_wt" ls-files --others --ignored --exclude-from="$include" --directory |
while IFS= read -r rel; do
rel=${rel%/}
[ -n "$rel" ] || continue
is_node_modules_path "$rel" && continue
src="$main_wt/$rel"
dst="$wt_root/$rel"
[ -e "$dst" ] && continue
[ -e "$src" ] || continue
mkdir -p "$(dirname "$dst")"
if [ -d "$src" ]; then
clone "$src" "$dst"
else
cp "$src" "$dst"
fi
done
fi
fi

# T3 can hand dependency installation to its asynchronous worktree setup
# terminal. Keep the metadata cleanup and seed copy above synchronous so the
# checkout is structurally ready, but let the UI become responsive before a
# potentially slow package install finishes.
if [ "${T3CODE_DEFER_DEPENDENCY_INSTALL:-0}" = "1" ]; then
echo "post-checkout: dependency installation deferred to T3 workspace initialization" >&2
exit 0
fi

# Shared-store hardlink install: fast when the store is warm, no inode clone storm.
[ -f "$wt_root/package.json" ] || exit 0
[ -f "$wt_root/pnpm-lock.yaml" ] || {
echo "post-checkout: package.json without pnpm-lock.yaml; skip install" >&2
exit 0
}
state_file="$wt_root/node_modules/.pnpm-checkout-state"
state=$(cksum "$wt_root/package.json" "$wt_root/pnpm-lock.yaml" | cksum | awk '{print $1 ":" $2}')
if [ -f "$wt_root/node_modules/.modules.yaml" ] && [ "$(cat "$state_file" 2>/dev/null)" = "$state" ]; then
exit 0
fi
command -v pnpm >/dev/null 2>&1 || {
echo "post-checkout: pnpm not on PATH; node_modules not installed" >&2
exit 0
}

export CI=1
echo "post-checkout: pnpm install (hardlink from store) in $wt_root" >&2
cd "$wt_root" || exit 1
if pnpm install \
--frozen-lockfile \
--prefer-offline \
--config.package-import-method=hardlink \
--config.confirmModulesPurge=false
then
printf '%s\n' "$state" >"$state_file"
else
status=$?
echo "post-checkout: dependency preparation failed (exit $status); worktree remains usable but degraded" >&2
echo "post-checkout: fix the lockfile/configuration or rerun this hook after transient failures clear" >&2
# Native Git invokes this hook inside `git worktree add`; dependency setup
# must not turn an already-created worktree into a structural Git failure.
[ "${T3CODE_WORKTREE_PREPARATION_STRICT:-0}" = "1" ] && exit "$status"
exit 0
fi
8 changes: 8 additions & 0 deletions .githooks/pre-commit
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#!/bin/sh
root=$(git rev-parse --show-toplevel 2>/dev/null) || exit 1
if [ ! -x "$root/node_modules/.bin/lint-staged" ]; then
echo "pre-commit: worktree preparation is incomplete (lint-staged is missing)" >&2
echo "pre-commit: T3/manual checkout must finish post-checkout before commit" >&2
exit 1
fi
exec pnpm lint-staged
16 changes: 16 additions & 0 deletions .githooks/pre-push
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Agent-only ship gate (humans: no-op). See scripts/agent-pre-push.mjs.
# Draft / no PR: static gate (vp check + typecheck). Ready PR: + unit tests.
# Publish: pnpm pr:ready, or raw `gh pr ready` — the shim runs the same full gate first.
#
# Humans: SKIP_AGENT_PREPUSH=1 git push
# Agents: never SKIP_AGENT_PREPUSH / never --no-verify
# Nested Git commands must discover their own repositories, not inherit this
# hook's GIT_DIR/GIT_WORK_TREE from the outer push.
for name in $(git rev-parse --local-env-vars); do
unset "$name"
done
# Plain `node`, not `pnpm exec node`: pnpm runs a dependency-status check first
# and will try to purge node_modules when the lockfile moved (a rebase does it),
# which aborts without a TTY — the hook then fails with a pnpm error instead of
# anything about the gate. The gate puts node_modules/.bin on PATH itself.
node scripts/agent-pre-push.mjs
Loading
Loading