Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
327f3fc
fix(mobile): keep home brand visible during secondary retries (#21388)
maria-rcks Oct 21, 2026
043c9c3
fix(mobile): collapse pull request repository errors (#21389)
maria-rcks Oct 21, 2026
e27fffa
fix(mobile): show terminal arrow keys before secondary controls (#21398)
maria-rcks Oct 21, 2026
145d73b
fix(mobile): update outdated servers and respect provider permissions…
maria-rcks Oct 21, 2026
2f6755b
fix(mobile): live activity tracks thread status and settlement (#21405)
maria-rcks Oct 21, 2026
4db2533
fix(mobile): use current checkout for non-git projects (#21404)
maria-rcks Oct 21, 2026
0dc38c7
fix(mobile): add project and checkout removal (#21409)
maria-rcks Oct 21, 2026
77e4f56
fix(mobile): show plans and fold settled progress notes (#21393)
maria-rcks Oct 21, 2026
afc33ff
fix(mobile): open transcript file links at the resolved path (#21403)
maria-rcks Oct 21, 2026
834ae4f
fix(mobile): lock the composer while queued edits save (#21390)
maria-rcks Oct 21, 2026
f16251f
fix(mobile): bring model controls in line with web (#21406)
maria-rcks Oct 21, 2026
6efe9a0
fix(mobile): restore archive and thread action undo (#21401)
maria-rcks Oct 21, 2026
fe414eb
fix(mobile): expose background work and thread status actions (#21395)
maria-rcks Oct 21, 2026
d356059
fix(web): keep approval menu actions compact (#22566)
Yash-Singh1 Oct 21, 2026
c3540a7
fix(web): main typecheck passes again after the Mermaid switch to pel…
t3dotgg Oct 21, 2026
05696c6
test: delete 11k low-signal tests so CI runs faster and flakes less (…
t3dotgg Oct 21, 2026
2085ea3
fix(mobile): thread rows show wake status and elapsed time (#21394)
maria-rcks Oct 21, 2026
8cd561e
fix(web,mobile): list database space for all machines in one notice (…
juliusmarminge Oct 21, 2026
b280e7d
test(lint): ban per-test timeouts and unreasoned skips (#22560)
juliusmarminge Oct 21, 2026
7895a2b
test(web): ban frame and transition waits in browser tests (#22561)
juliusmarminge Oct 21, 2026
dd4506a
test: ban wall-clock readings in tests (#22562)
juliusmarminge Oct 21, 2026
bde6206
test(server): ban real-clock waits in tests (#22564)
juliusmarminge Oct 21, 2026
08dbf83
test: warn on polling loops in tests and make adapter test harnesses …
juliusmarminge Oct 21, 2026
3719fd2
fix(mobile): iOS new-thread skill picker stops shifting the screen (#…
flamboh Oct 21, 2026
5bc19ac
fix(web): dialogs keep their content while they close (#21960)
flamboh Oct 21, 2026
569bd02
ci(release): build Windows x64 on Linux like arm64 (#22584)
t3dotgg Oct 21, 2026
849b3f8
fix(server): idle orphaned follow-ups can be cancelled without a runn…
t3dotgg Oct 21, 2026
a01f410
chore(web): remove "use client" directives (#22587)
flamboh Oct 21, 2026
7c16a40
test(mobile): prune low-value tests in mobile (second pass) (#22588)
juliusmarminge Oct 21, 2026
2edddbc
test(desktop): prune low-value tests in desktop (second pass) (#22589)
juliusmarminge Oct 21, 2026
eb10859
test(web): prune low-value tests in apps/web (second pass) (#22591)
juliusmarminge Oct 21, 2026
a2f4df0
test(server): prune low-value tests in apps/server (second pass) (#22…
juliusmarminge Oct 21, 2026
8feddd6
test(packages): prune low-value tests in packages (second pass) (#22593)
juliusmarminge Oct 21, 2026
32d8f8f
test(server): prune low-value tests in orchestration-v2 (second pass)…
juliusmarminge Oct 21, 2026
c728c8c
test(web): every browser test starts with the mouse off the page (#22…
juliusmarminge Oct 21, 2026
5b2ee39
chore(tailscale): drop parseTailscaleMagicDnsName, which nothing impo…
juliusmarminge Oct 21, 2026
31dcc7c
fix(server): make the remaining flaky server tests deterministic (#22…
juliusmarminge Oct 21, 2026
ecfe4f7
fix(mobile): composer chips match chat chips (#22518)
flamboh Oct 21, 2026
8bbb85c
fix(mobile): show each turn's diffstat on its work row (#21392)
maria-rcks Oct 21, 2026
c22ace2
chore(release): prepare v0.1.1
t3-code[bot] Oct 21, 2026
4741dc5
fix(web): silence notifications when stopping a watch (#22615)
Yash-Singh1 Oct 21, 2026
e64766c
ci(release): build macOS desktop on Blacksmith runners again (#22613)
t3dotgg Oct 21, 2026
733a303
fix(usage): Codex compaction and resumed sessions no longer show skip…
t3dotgg Oct 21, 2026
8a9d0e0
fix(web): thread search shows the same PR badge as the sidebar (#22627)
maria-rcks Oct 21, 2026
3e250a8
Delete .github/workflows/cursor-hygiene-webhook.yml
juliusmarminge Oct 21, 2026
bfdc584
Merge remote-tracking branch 'upstream/main' into yordis/chore-sync-u…
yordis Oct 21, 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
  •  
  •  
  •  
45 changes: 0 additions & 45 deletions .github/scripts/check-nightly-release.test.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -61,12 +61,6 @@ for (const releaseChannel of ["stable", "nightly"]) {
);
assert.equal(calls.length, 0);
});

test(`allows a manual ${releaseChannel} release from main`, async () => {
const { options, calls } = releaseSourceFixture();
await assertReleaseSource({ ...options, releaseChannel });
assert.equal(calls[0].basehead, "candidate...main");
});
}

for (const comparisonStatus of ["behind", "diverged"]) {
Expand All @@ -79,13 +73,6 @@ for (const comparisonStatus of ["behind", "diverged"]) {
});
}

test("accepts a release commit already contained in main", async () => {
for (const comparisonStatus of ["ahead", "identical"]) {
const { options } = releaseSourceFixture({ comparisonStatus, eventName: "push" });
await assertCommitOnDefaultBranch({ ...options, sha: "release-commit" });
}
});

function fixture({ releases = [nightly(7)], comparisonStatus = "ahead" } = {}) {
const calls = [];
return {
Expand Down Expand Up @@ -119,26 +106,6 @@ test("releases the first nightly when no nightly is published", async () => {
assert.equal(await shouldReleaseNightly(options), true);
});

test("waits six hours after publication, including manual nightlies", async () => {
for (const age of [0, 3, 6 - 1 / 3600]) {
const { options, calls } = fixture({ releases: [nightly(age)] });
assert.equal(await shouldReleaseNightly(options), false);
assert.equal(calls.length, 0);
}
});

test("releases new commits at six hours and after an idle period", async () => {
for (const age of [6, 7, 24]) {
const { options } = fixture({ releases: [nightly(age)] });
assert.equal(await shouldReleaseNightly(options), true);
}
});

test("skips unchanged commits after the gap", async () => {
const { options } = fixture({ comparisonStatus: "identical" });
assert.equal(await shouldReleaseNightly(options), false);
});

test("uses publication time, not release order or the tagged commit date", async () => {
const { options } = fixture({
releases: [nightly(10), nightly(1), nightly(20, { tag_name: "nightly-v0.9.0" })],
Expand All @@ -153,13 +120,6 @@ test("ignores stable releases and drafts when checking the gap", async () => {
assert.equal(await shouldReleaseNightly(options), true);
});

test("compares against the published tag, including legacy nightly tags", async () => {
const tag = "nightly-v0.9.0";
const { options, calls } = fixture({ releases: [nightly(7, { tag_name: tag })] });
assert.equal(await shouldReleaseNightly(options), true);
assert.equal(calls[0].basehead, `${tag}...new`);
});

test("fails instead of releasing when GitHub cannot supply release state", async () => {
const { options } = fixture();
options.github.paginate = async () => {
Expand Down Expand Up @@ -211,8 +171,3 @@ test("stable releases derive the version from legacy nightly tags", async () =>
});
assert.equal((await resolveLatestNightlyCommit(options)).version, "0.9.0");
});

test("stable releases fail without a published nightly", async () => {
const { options } = nightlyCommitFixture({ releases: [nightly(0, { tag_name: "v1.0.0" })] });
await assert.rejects(resolveLatestNightlyCommit(options), /No published nightly/);
});
52 changes: 0 additions & 52 deletions .github/scripts/thread-transfer-report.test.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ const assert = require("node:assert/strict");
const test = require("node:test");

const {
renderComment,
resolve,
upsertCommentForCurrentHead,
validateResult,
Expand Down Expand Up @@ -53,39 +52,6 @@ test("validates the fixed artifact schema", () => {
);
});

test("renders baseline, impact, ceiling, and ceiling changes", () => {
const baseline = result();
const current = result({ measuredTurnWebSocketWireBytes: 260_000 });
current.providers.codex.ceiling = {
...current.providers.codex.ceiling,
measuredTurnWebSocketWireBytes: 330_000,
};
const comment = renderComment({
current,
baseline,
currentRun: {
sha: "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
conclusion: "success",
url: "https://github.com/pingdotgg/t3code/actions/runs/2",
},
baselineRun: {
sha: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
matchesBase: true,
url: "https://github.com/pingdotgg/t3code/actions/runs/1",
},
});

assert.match(comment, /Main baseline \| This PR \| Impact \| PR ceiling/);
assert.match(comment, /\+9\.8 KiB \(\+4\.0%\)/);
assert.match(comment, /This PR changes transfer ceilings/);
assert.match(comment, /312\.5 KiB → 322\.3 KiB/);
assert.match(comment, /<!-- t3-thread-transfer-report -->/);
assert.match(
comment,
/<!-- t3-thread-transfer-result-sha:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb -->/,
);
});

test("resolves a fallback PR with a redacted head repo and exact main baseline", async () => {
const outputs = {};
const listWorkflowRunArtifacts = () => {};
Expand Down Expand Up @@ -373,21 +339,3 @@ test("preserves a successful result when a same-SHA rerun has no artifact", asyn
assert.equal(published, true);
assert.equal(updatedComment, false);
});

test("accepts V2 without comparing it to the V1 scenario", () => {
const current = result();
current.scenario.id = "thread-transfer-v2";
current.providers.codex.ceiling = { ...current.providers.codex.ceiling, totalWireBytes: 3000000 };
assert.equal(validateResult(current), current);
const comment = renderComment({
current,
baseline: result(),
currentRun: { sha: "bbbbbbbb", conclusion: "success", url: "https://example.com/current" },
baselineRun: { sha: "aaaaaaaa", matchesBase: true, url: "https://example.com/baseline" },
});
assert.match(comment, /fixture changed/);
assert.doesNotMatch(comment, /This PR changes transfer ceilings/);
assert.doesNotMatch(comment, /[+-]\d+\.\d+%/);
current.scenario.id = "unrecognized";
assert.throws(() => validateResult(current), /not supported/);
});
52 changes: 0 additions & 52 deletions .github/workflows/cursor-hygiene-webhook.yml

This file was deleted.

114 changes: 15 additions & 99 deletions .github/workflows/release-desktop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,11 @@ on:
required: true
type: string

# electron-builder leaves the default arch (x64) out of the unpacked app's
# directory name.
env:
UNPACKED_DIR: ${{ inputs.platform }}-${{ inputs.arch != 'x64' && format('{0}-', inputs.arch) || '' }}unpacked

permissions:
# Windows builds read this run's artifact list to wait for the Linux CLI archive.
actions: read
Expand Down Expand Up @@ -136,17 +141,11 @@ jobs:
git sparse-checkout set --no-cone '/*' '!/.repos/'
git -c checkout.workers=0 checkout --detach FETCH_HEAD

# Windows installs straight from the registry. There, linking the packages
# takes the time, not downloading them, so a ~700 MB package cache did not
# pay for its own restore. Across recent nightlies, restore plus install
# took 183-233s on arm64 and 116-172s on x64, while a plain install took
# 142-210s and 84-160s. The arm64 entries also filled 4 GB of the
# repository's 10 GB Actions cache.
- name: Setup Vite+
uses: voidzero-dev/setup-vp@250f29ce396baf5e8f24498e17c0dfdebabc26eb # v1
with:
node-version-file: package.json
cache: ${{ runner.os != 'Windows' }}
cache: true
run-install: false

# pnpm checks the lockfile and policy before reusing this result. A missing
Expand Down Expand Up @@ -215,28 +214,8 @@ jobs:
name: js-bundle
path: apps

# Only the resource monitor build needs these libraries. With a cached
# monitor, the desktop build's preflight skips its MSVC check, and node-pty
# ships prebuilt Windows binaries, so the 30-60s install is skipped too.
- name: Install Spectre-mitigated MSVC libs
if: runner.os == 'Windows' && steps.resource_monitor_cache.outputs.cache-hit != 'true'
shell: pwsh
run: |
$vswhere = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe"
$installPath = & $vswhere -products * -latest -property installationPath
$setupExe = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\setup.exe"
$proc = Start-Process -FilePath $setupExe `
-ArgumentList "modify", "--installPath", "`"$installPath`"", "--add", `
"Microsoft.VisualStudio.Component.VC.Runtimes.${{ inputs.arch == 'arm64' && 'ARM64' || 'x86.x64' }}.Spectre", "--quiet", "--norestart" `
-Wait -PassThru -NoNewWindow
if ($null -eq $proc -or $proc.ExitCode -ne 0) {
$code = if ($null -ne $proc) { $proc.ExitCode } else { 1 }
Write-Error "Visual Studio Installer failed with exit code $code"
exit $code
}

- name: Install cargo-xwin
if: runner.os != 'Windows' && inputs.platform == 'win' && steps.resource_monitor_cache.outputs.cache-hit != 'true'
if: inputs.platform == 'win' && steps.resource_monitor_cache.outputs.cache-hit != 'true'
uses: taiki-e/install-action@8cca0918f8471c33515202b73f56ab27f2bed283 # v2
with:
tool: cargo-xwin@0.23.1
Expand All @@ -246,74 +225,12 @@ jobs:
- name: Build resource monitor
if: steps.resource_monitor_cache.outputs.cache-hit != 'true'
shell: bash
run: cargo ${{ runner.os != 'Windows' && inputs.platform == 'win' && 'xwin build' || 'build' }} --locked --release --manifest-path native/resource-monitor/Cargo.toml --target "${{ inputs.rust_target }}"

- name: Prepare Azure Trusted Signing
if: inputs.platform == 'win' && runner.os == 'Windows'
shell: pwsh
env:
AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}
AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }}
AZURE_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }}
AZURE_TRUSTED_SIGNING_ENDPOINT: ${{ secrets.AZURE_TRUSTED_SIGNING_ENDPOINT }}
AZURE_TRUSTED_SIGNING_ACCOUNT_NAME: ${{ secrets.AZURE_TRUSTED_SIGNING_ACCOUNT_NAME }}
AZURE_TRUSTED_SIGNING_CERTIFICATE_PROFILE_NAME: ${{ secrets.AZURE_TRUSTED_SIGNING_CERTIFICATE_PROFILE_NAME }}
AZURE_TRUSTED_SIGNING_PUBLISHER_NAME: ${{ secrets.AZURE_TRUSTED_SIGNING_PUBLISHER_NAME }}
run: |
$ErrorActionPreference = "Stop"

$requiredSecrets = @(
$env:AZURE_TENANT_ID,
$env:AZURE_CLIENT_ID,
$env:AZURE_CLIENT_SECRET,
$env:AZURE_TRUSTED_SIGNING_ENDPOINT,
$env:AZURE_TRUSTED_SIGNING_ACCOUNT_NAME,
$env:AZURE_TRUSTED_SIGNING_CERTIFICATE_PROFILE_NAME,
$env:AZURE_TRUSTED_SIGNING_PUBLISHER_NAME
)
if ($requiredSecrets | Where-Object { [string]::IsNullOrWhiteSpace($_) }) {
Write-Host "Azure Trusted Signing disabled; skipping TrustedSigning module preparation."
exit 0
}

try {
Install-PackageProvider `
-Name NuGet `
-MinimumVersion 2.8.5.201 `
-Force `
-Scope CurrentUser `
-ErrorAction Stop
} catch {
Write-Warning "Could not bootstrap NuGet package provider. Continuing because the runner may already have a usable provider. $($_.Exception.Message)"
}

Install-Module `
-Name TrustedSigning `
-MinimumVersion 0.5.0 `
-Force `
-AllowClobber `
-Repository PSGallery `
-Scope CurrentUser `
-ErrorAction Stop

Import-Module TrustedSigning -MinimumVersion 0.5.0 -Force
Get-Command Invoke-TrustedSigning -ErrorAction Stop

$moduleRoots = @(
[System.IO.Path]::Combine([Environment]::GetFolderPath("MyDocuments"), "PowerShell", "Modules"),
[System.IO.Path]::Combine([Environment]::GetFolderPath("MyDocuments"), "WindowsPowerShell", "Modules"),
[System.IO.Path]::Combine($env:ProgramFiles, "PowerShell", "Modules"),
[System.IO.Path]::Combine($env:ProgramFiles, "WindowsPowerShell", "Modules")
)
$modulePathEntries = @($moduleRoots + ($env:PSModulePath -split ";")) |
Where-Object { $_ -and (Test-Path $_) } |
Select-Object -Unique
"PSModulePath=$($modulePathEntries -join ';')" >> $env:GITHUB_ENV
run: cargo ${{ inputs.platform == 'win' && 'xwin build' || 'build' }} --locked --release --manifest-path native/resource-monitor/Cargo.toml --target "${{ inputs.rust_target }}"

# Off Windows, scripts/lib/windows-jsign.ts signs through jsign instead of
# the TrustedSigning PowerShell module.
- name: Install jsign
if: inputs.platform == 'win' && runner.os != 'Windows'
if: inputs.platform == 'win'
shell: bash
run: |
set -euo pipefail
Expand All @@ -338,9 +255,8 @@ jobs:

# The single-executable is built with a Node that supports --build-sea
# (25.7+); the repo itself stays on the engines.node version. A native
# build injects into the runner's own Node: tsdown's cross-target download
# path runs `tar` on a drive-letter path on Windows, which GNU tar reads as
# a remote host. Off Windows, a Windows target downloads its node.exe.
# build injects into the runner's own Node; a Windows target downloads its
# node.exe.
- name: Build CLI single-executable
if: inputs.cli_archive
shell: bash
Expand All @@ -352,7 +268,7 @@ jobs:
# The executable bundles the server again, so it needs the same stamp
# as release.yml's JS bundle.
T3CODE_TELEMETRY_CHANNEL: ${{ github.repository == 'pingdotgg/t3code' && inputs.release_channel || 'dev' }}
run: node apps/server/scripts/cli.ts build-exe --verbose ${{ runner.os != 'Windows' && inputs.platform == 'win' && format('--target win-{0}', inputs.arch) || '' }}
run: node apps/server/scripts/cli.ts build-exe --verbose ${{ inputs.platform == 'win' && format('--target win-{0}', inputs.arch) || '' }}

- name: Import macOS signing certificate for the CLI archive
if: inputs.cli_archive && inputs.platform == 'mac'
Expand Down Expand Up @@ -614,7 +530,7 @@ jobs:
run: |
set -euo pipefail
mkdir -p verify
unpacked=$(ls -d "${TMPDIR:-/tmp}"/t3code-desktop-${{ inputs.platform }}-stage-*/app/dist/${{ inputs.platform }}-${{ inputs.arch }}-unpacked)
unpacked=$(ls -d "${TMPDIR:-/tmp}"/t3code-desktop-${{ inputs.platform }}-stage-*/app/dist/"$UNPACKED_DIR")
tar -C "$(dirname "$unpacked")" -cf verify/unpacked.tar "$(basename "$unpacked")"
esbuild=scripts/node_modules/.bin/esbuild
banner="import{createRequire as __cr}from'node:module';const require=__cr(import.meta.url);"
Expand Down Expand Up @@ -734,7 +650,7 @@ jobs:
set -euo pipefail
tar -C verify -xf verify/unpacked.tar
node verify/verify-windows-desktop-artifact.mjs \
--app-dir "$(cygpath -w "$PWD/verify/${{ inputs.platform }}-${{ inputs.arch }}-unpacked")" \
--app-dir "$(cygpath -w "$PWD/verify/$UNPACKED_DIR")" \
--arch "${{ inputs.arch }}" --build-version "${{ inputs.version }}" --verbose

- name: Smoke-test CLI archive
Expand All @@ -749,7 +665,7 @@ jobs:
- name: Smoke-test resource monitor
shell: bash
env:
MONITOR: verify/${{ inputs.platform }}-${{ inputs.arch }}-unpacked/resources/resource-monitor/t3-resource-monitor.exe
MONITOR: verify/${{ env.UNPACKED_DIR }}/resources/resource-monitor/t3-resource-monitor.exe
EXPECTED_ARCH: ${{ inputs.arch == 'arm64' && 'aarch64' || 'x86_64' }}
run: |
node --input-type=module <<'EOF'
Expand Down
Loading
Loading