Skip to content

Commit 59c3df1

Browse files
authored
Merge branch 'main' into fix/show-more-cursor-and-transition
2 parents e35e43e + f47c1f1 commit 59c3df1

266 files changed

Lines changed: 29757 additions & 13300 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.docs/scripts.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
- `bun run dev:web` — Starts just the Vite dev server for the web app.
66
- Dev commands default `T3CODE_STATE_DIR` to `~/.t3/dev` to keep dev state isolated from desktop/prod state.
77
- Override server CLI-equivalent flags from root dev commands with `--`, for example:
8-
`bun run dev -- --state-dir ~/.t3/another-dev-state`
8+
`bun run dev -- --base-dir ~/.t3-2`
99
- `bun run start` — Runs the production server (serves built web app as static files).
1010
- `bun run build` — Builds contracts, web app, and server through Turbo.
1111
- `bun run typecheck` — Strict TypeScript checks for all packages.

.gitattributes

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# git autocrlf=true converts LF to CRLF on Windows, causing issues with oxfmt
2+
* text=auto eol=lf

.github/VOUCHED.td

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,4 +28,5 @@ github:realAhmedRoach
2828
github:shiroyasha9
2929
github:Yash-Singh1
3030
github:eggfriedrice24
31-
github:Ymit24
31+
github:Ymit24
32+
github:shivamhwp

.github/workflows/pr-size.yml

Lines changed: 101 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -24,32 +24,32 @@ jobs:
2424
{
2525
name: "size:XS",
2626
color: "0e8a16",
27-
description: "0-9 changed lines (additions + deletions).",
27+
description: "0-9 effective changed lines (test files excluded in mixed PRs).",
2828
},
2929
{
3030
name: "size:S",
3131
color: "5ebd3e",
32-
description: "10-29 changed lines (additions + deletions).",
32+
description: "10-29 effective changed lines (test files excluded in mixed PRs).",
3333
},
3434
{
3535
name: "size:M",
3636
color: "fbca04",
37-
description: "30-99 changed lines (additions + deletions).",
37+
description: "30-99 effective changed lines (test files excluded in mixed PRs).",
3838
},
3939
{
4040
name: "size:L",
4141
color: "fe7d37",
42-
description: "100-499 changed lines (additions + deletions).",
42+
description: "100-499 effective changed lines (test files excluded in mixed PRs).",
4343
},
4444
{
4545
name: "size:XL",
4646
color: "d93f0b",
47-
description: "500-999 changed lines (additions + deletions).",
47+
description: "500-999 effective changed lines (test files excluded in mixed PRs).",
4848
},
4949
{
5050
name: "size:XXL",
5151
color: "b60205",
52-
description: "1,000+ changed lines (additions + deletions).",
52+
description: "1,000+ effective changed lines (test files excluded in mixed PRs).",
5353
},
5454
];
5555
@@ -124,19 +124,49 @@ jobs:
124124
group: pr-size-${{ github.event.pull_request.number }}
125125
cancel-in-progress: true
126126
steps:
127+
- name: Checkout base repository
128+
uses: actions/checkout@v4
129+
with:
130+
fetch-depth: 0
127131
- name: Sync PR size label
128132
uses: actions/github-script@v8
129133
env:
130134
PR_SIZE_LABELS_JSON: ${{ needs.prepare-config.outputs.labels_json }}
131135
with:
132136
script: |
137+
const { execFileSync } = require("node:child_process");
138+
133139
const issueNumber = context.payload.pull_request.number;
134-
const additions = context.payload.pull_request.additions ?? 0;
135-
const deletions = context.payload.pull_request.deletions ?? 0;
136-
const changedLines = additions + deletions;
140+
const baseSha = context.payload.pull_request.base.sha;
141+
const headSha = context.payload.pull_request.head.sha;
142+
const headTrackingRef = `refs/remotes/pr-size/${issueNumber}`;
137143
const managedLabels = JSON.parse(process.env.PR_SIZE_LABELS_JSON ?? "[]");
138-
139144
const managedLabelNames = new Set(managedLabels.map((label) => label.name));
145+
// Keep this aligned with the repo's test entrypoints and test-only support files.
146+
const testExcludePathspecs = [
147+
":(glob,exclude)**/__tests__/**",
148+
":(glob,exclude)**/test/**",
149+
":(glob,exclude)**/tests/**",
150+
":(glob,exclude)apps/server/integration/**",
151+
":(glob,exclude)**/*.test.*",
152+
":(glob,exclude)**/*.spec.*",
153+
":(glob,exclude)**/*.browser.*",
154+
":(glob,exclude)**/*.integration.*",
155+
];
156+
157+
const sumNumstat = (text) =>
158+
text
159+
.split("\n")
160+
.filter(Boolean)
161+
.reduce((total, line) => {
162+
const [insertionsRaw = "0", deletionsRaw = "0"] = line.split("\t");
163+
const additions =
164+
insertionsRaw === "-" ? 0 : Number.parseInt(insertionsRaw, 10) || 0;
165+
const deletions =
166+
deletionsRaw === "-" ? 0 : Number.parseInt(deletionsRaw, 10) || 0;
167+
168+
return total + additions + deletions;
169+
}, 0);
140170
141171
const resolveSizeLabel = (totalChangedLines) => {
142172
if (totalChangedLines < 10) {
@@ -162,6 +192,55 @@ jobs:
162192
return "size:XXL";
163193
};
164194
195+
execFileSync("git", ["fetch", "--no-tags", "origin", baseSha], {
196+
stdio: "inherit",
197+
});
198+
199+
execFileSync(
200+
"git",
201+
["fetch", "--no-tags", "origin", `+refs/pull/${issueNumber}/head:${headTrackingRef}`],
202+
{
203+
stdio: "inherit",
204+
},
205+
);
206+
207+
const resolvedHeadSha = execFileSync("git", ["rev-parse", headTrackingRef], {
208+
encoding: "utf8",
209+
}).trim();
210+
211+
if (resolvedHeadSha !== headSha) {
212+
core.warning(
213+
`Fetched head SHA ${resolvedHeadSha} does not match pull request head SHA ${headSha}; using fetched ref for sizing.`,
214+
);
215+
}
216+
217+
execFileSync("git", ["cat-file", "-e", `${baseSha}^{commit}`], {
218+
stdio: "inherit",
219+
});
220+
221+
const diffArgs = [
222+
"diff",
223+
"--numstat",
224+
"--ignore-all-space",
225+
"--ignore-blank-lines",
226+
`${baseSha}...${resolvedHeadSha}`,
227+
];
228+
229+
const totalChangedLines = sumNumstat(
230+
execFileSync(
231+
"git",
232+
diffArgs,
233+
{ encoding: "utf8" },
234+
),
235+
);
236+
const nonTestChangedLines = sumNumstat(
237+
execFileSync("git", [...diffArgs, "--", ".", ...testExcludePathspecs], {
238+
encoding: "utf8",
239+
}),
240+
);
241+
const testChangedLines = Math.max(0, totalChangedLines - nonTestChangedLines);
242+
243+
const changedLines = nonTestChangedLines === 0 ? testChangedLines : nonTestChangedLines;
165244
const nextLabelName = resolveSizeLabel(changedLines);
166245
167246
const { data: currentLabels } = await github.rest.issues.listLabelsOnIssue({
@@ -199,4 +278,15 @@ jobs:
199278
});
200279
}
201280
202-
core.info(`PR #${issueNumber}: ${changedLines} changed lines -> ${nextLabelName}`);
281+
const classification =
282+
nonTestChangedLines === 0
283+
? testChangedLines > 0
284+
? "test-only PR"
285+
: "no line changes"
286+
: testChangedLines > 0
287+
? "test lines excluded"
288+
: "all non-test changes";
289+
290+
core.info(
291+
`PR #${issueNumber}: ${nonTestChangedLines} non-test lines, ${testChangedLines} test lines, ${changedLines} effective lines -> ${nextLabelName} (${classification})`,
292+
);

.gitignore

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,12 @@ packages/*/dist
1212
build/
1313
.logs/
1414
release/
15+
release-mock/
1516
.t3
1617
.idea/
1718
apps/web/.playwright
1819
apps/web/playwright-report
1920
apps/web/src/components/__screenshots__
20-
.vitest-*
21+
.vitest-*
22+
__screenshots__/
23+
.tanstack

CLAUDE.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
AGENTS.md
1+
AGENTS.md

README.md

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,42 @@
22

33
T3 Code is a minimal web GUI for coding agents (currently Codex and Claude, more coming soon).
44

5-
## How to use
5+
## Installation
66

77
> [!WARNING]
8-
> You need to have [Codex CLI](https://github.com/openai/codex) installed and authorized for T3 Code to work.
8+
> T3 Code currently supports Codex and Claude.
9+
> Install and authenticate at least one provider before use:
10+
>
11+
> - Codex: install [Codex CLI](https://github.com/openai/codex) and run `codex login`
12+
> - Claude: install Claude Code and run `claude auth login`
13+
14+
### Run without installing
915

1016
```bash
1117
npx t3
1218
```
1319

14-
You can also just install the desktop app. It's cooler.
20+
### Desktop app
21+
22+
Install the latest version of the desktop app from [GitHub Releases](https://github.com/pingdotgg/t3code/releases), or from your favorite package registry:
23+
24+
#### Windows (`winget`)
25+
26+
```bash
27+
winget install T3Tools.T3Code
28+
```
29+
30+
#### macOS (Homebrew)
1531

16-
Install the [desktop app from the Releases page](https://github.com/pingdotgg/t3code/releases)
32+
```bash
33+
brew install --cask t3-code
34+
```
35+
36+
#### Arch Linux (AUR)
37+
38+
```bash
39+
yay -S t3code-bin
40+
```
1741

1842
## Some notes
1943

REMOTE.md

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,21 +6,24 @@ Use this when you want to open T3 Code from another device (phone, tablet, anoth
66

77
The T3 Code CLI accepts the following configuration options, available either as CLI flags or environment variables:
88

9-
| CLI flag | Env var | Notes |
10-
| ----------------------- | --------------------- | ---------------------------------- |
11-
| `--mode <web\|desktop>` | `T3CODE_MODE` | Runtime mode. |
12-
| `--port <number>` | `T3CODE_PORT` | HTTP/WebSocket port. |
13-
| `--host <address>` | `T3CODE_HOST` | Bind interface/address. |
14-
| `--state-dir <path>` | `T3CODE_STATE_DIR` | State directory. |
15-
| `--dev-url <url>` | `VITE_DEV_SERVER_URL` | Dev web URL redirect/proxy target. |
16-
| `--no-browser` | `T3CODE_NO_BROWSER` | Disable auto-open browser. |
17-
| `--auth-token <token>` | `T3CODE_AUTH_TOKEN` | WebSocket auth token. |
9+
| CLI flag | Env var | Notes |
10+
| ----------------------- | --------------------- | ------------------------------------------------------------------------------------ |
11+
| `--mode <web\|desktop>` | `T3CODE_MODE` | Runtime mode. |
12+
| `--port <number>` | `T3CODE_PORT` | HTTP/WebSocket port. |
13+
| `--host <address>` | `T3CODE_HOST` | Bind interface/address. |
14+
| `--base-dir <path>` | `T3CODE_HOME` | Base directory. |
15+
| `--dev-url <url>` | `VITE_DEV_SERVER_URL` | Dev web URL redirect/proxy target. |
16+
| `--no-browser` | `T3CODE_NO_BROWSER` | Disable auto-open browser. |
17+
| `--auth-token <token>` | `T3CODE_AUTH_TOKEN` | WebSocket auth token. Use this for standard CLI and remote-server flows. |
18+
| `--bootstrap-fd <fd>` | `T3CODE_BOOTSTRAP_FD` | Read a one-shot bootstrap envelope from an inherited file descriptor during startup. |
1819

1920
> TIP: Use the `--help` flag to see all available options and their descriptions.
2021
2122
## Security First
2223

2324
- Always set `--auth-token` before exposing the server outside localhost.
25+
- When you control the process launcher, prefer sending the auth token in a JSON envelope via `--bootstrap-fd <fd>`.
26+
With `--bootstrap-fd <fd>`, the launcher starts the server first, then sends a one-shot JSON envelope over the inherited file descriptor. This allows the auth token to be delivered without putting it in process environment or command line arguments.
2427
- Treat the token like a password.
2528
- Prefer binding to trusted interfaces (LAN IP or Tailnet IP) instead of opening all interfaces unless needed.
2629

apps/desktop/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@t3tools/desktop",
3-
"version": "0.0.13",
3+
"version": "0.0.15",
44
"private": true,
55
"main": "dist-electron/main.js",
66
"scripts": {

apps/desktop/src/confirmDialog.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ export async function showDesktopConfirmDialog(
1414
const options = {
1515
type: "question" as const,
1616
buttons: ["No", "Yes"],
17-
defaultId: CONFIRM_BUTTON_INDEX,
17+
defaultId: 0,
1818
cancelId: 0,
1919
noLink: true,
2020
message: normalizedMessage,

0 commit comments

Comments
 (0)