Merge upstream: Auto runtime mode, t3.json config, glass-surface redesign - #8

Merged
jetblk merged 21 commits into
mainfrom
t3code/upstream-merge-20260723
Jul 23, 2026
Merged

Merge upstream: Auto runtime mode, t3.json config, glass-surface redesign#8
jetblk merged 21 commits into
mainfrom
t3code/upstream-merge-20260723

Conversation

@jetblk

@jetblkjetblk commented Jul 23, 2026

Copy link
Copy Markdown
Owner

Brings in 20 new commits from pingdotgg/t3code main (origin/main..upstream/main, up to 4d8343641), evaluated per the fork's upstream-merge workflow. Full merge (no cherry-pick) to keep the RPC contract in sync.

Highlights

CommitSummary
fbd77420f (pingdotgg#4272)"Auto" runtime mode — AI-reviewed tool-call approvals for Codex & Claude
1c9a6de26 (pingdotgg#4317)Shared t3.json project configuration support
16491a84b (pingdotgg#4276)Fix: new-thread defaults ignored for remote environments
b44ed835c / 9c9916aefSync provider banner dismissal + redesign review fixes
~15 commitsWeb "glass surfaces" visual redesign (dialogs, glass-opacity slider, command palette / model picker / tooltip styling, light/dark)

Conflicts

None. Auto-merge succeeded on all 6 overlap files (server.ts, server.test.ts, ChatComposer.tsx, ModelPickerContent.tsx, SettingsSidebarNav.tsx, contracts/index.ts); provider-usage wiring preserved in each. No fork-identity files touched. pingdotgg#4272's provider changes don't collide with the fork's usage layers or driver baseEnv threading.

Verification

  • Typecheck clean: @t3tools/contracts, t3 (server), @t3tools/web
  • Tests green: contracts 203, client-runtime 453, server provider-usage suites 156

After squash-merge

Squashing breaks upstream ancestry; will follow with a git merge -s ours upstream/main reconciliation so the next merge stays clean.

🤖 Generated with Claude Code

Note

Add auto runtime mode, t3.json config support, and glass-surface UI redesign

  • Adds an auto runtime mode across contracts, Claude adapter, Codex runtime, and all composer/composer-menu UIs; in auto mode, permissionMode is set to 'auto' and approvals are routed to auto_review.
  • Introduces t3.json project file support: a new schema (t3ProjectFile.ts), server-side loader (T3ProjectFileLoader.ts), and a marketing endpoint serving the JSON Schema for LSP/editor consumption.
  • ProjectFaviconResolver now reads iconPath from t3.json before falling back to well-known icon locations.
  • Scripts declared in t3.json can be imported directly into the project actions UI via ProjectScriptsControl; on failure, the add-action dialog pre-fills for correction.
  • Overhauls UI surfaces with translucent glass effects (backdrop-filter, color-mix) for composer, alerts, dropdowns, and dialogs; sidebar color tokens are unified to a zinc-based hierarchy for both v1 and v2.
  • Adds a user-adjustable glassOpacity setting (range 40–100, default 80) persisted to client settings and applied via --glass-opacity CSS variable in real time.
  • Provider status banners in the chat view are now dismissible and rendered as an overlay, preventing content height shifts.
  • SVG definition IDs in SidebarStageBackdrop components are now generated with useId to prevent collisions when rendered multiple times.
  • New thread defaults (defaultThreadEnvMode, newWorktreesStartFromOrigin) are now sourced from the primary server's settings rather than the target environment's server configs.
  • Risk: The glass/backdrop-filter effects are visually significant and affect many surfaces; reduced-transparency environments fall back to opaque backgrounds, but intermediate system configurations may show unexpected blending.
📊 Macroscope summarized c6b76cd. 63 files reviewed, 0 issues evaluated, 0 issues filtered, 0 comments posted

🗂️ Filtered Issues

No issues evaluated.

maria-rcksand others added 21 commits July 23, 2026 01:13
Co-authored-by: codex <codex@users.noreply.github.com>
…tgg#4276)
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
…laude (pingdotgg#4272)
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
- Restore light-mode glass, dialog, dropdown, and composer colors
- Refine provider wizard, changed-file cards, sidebar controls, and buttons
- Update wizard step tests for the new list structure
Co-authored-by: codex <codex@users.noreply.github.com>
@jetblk
jetblk merged commit a7f2315 into mainJul 23, 2026
1 check passed
jetblk added a commit that referenced this pull request Jul 23, 2026
Records upstream/main (4d83436) as merged. Its content already landed in
main via the squash-merge of #8; this commit only restores git ancestry so
the fork stays 'fully merged' and future upstream merges don't re-present
these commits. No file changes (tree identical to origin/main).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
updateSettings({ glassOpacity });
}
}}
step={5}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Mediumsettings/SettingsPanels.tsx:613

The glass opacity slider uses step={5}, but the settings contract accepts every integer from MIN_GLASS_OPACITY through MAX_GLASS_OPACITY. For a valid persisted value like 72, the range input has a step-mismatched value — the browser may render the thumb at the nearest valid step (e.g. 70), while the adjacent output and custom fill are calculated from 72. The next interaction can then overwrite the valid 72 with the rounded value. Consider using step={1} so the slider can represent every valid value, or restrict the schema to multiples of five.

Suggested change
step={5}
step={1}
🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @apps/web/src/components/settings/SettingsPanels.tsx around line 613:
The glass opacity slider uses `step={5}`, but the settings contract accepts every integer from `MIN_GLASS_OPACITY` through `MAX_GLASS_OPACITY`. For a valid persisted value like `72`, the range input has a step-mismatched value — the browser may render the thumb at the nearest valid step (e.g. `70`), while the adjacent output and custom fill are calculated from `72`. The next interaction can then overwrite the valid `72` with the rounded value. Consider using `step={1}` so the slider can represent every valid value, or restrict the schema to multiples of five.

Comment threadt3.json
"scripts": [
{
"name": "Setup Worktree",
"command": "vp i && ln -sf $T3CODE_PROJECT_ROOT/.env .env && ln -sf $T3CODE_PROJECT_ROOT/infra/relay/.env infra/relay/.env",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Mediumt3.json:7

The Setup Worktree command expands $T3CODE_PROJECT_ROOT without quotes in both ln source paths. If the project root contains spaces, shell word splitting passes multiple operands to ln, so the first link fails and, due to &&, neither .env link is created. Quote each expanded source path, e.g. "$T3CODE_PROJECT_ROOT/.env".

Suggested change
"command": "vp i && ln -sf $T3CODE_PROJECT_ROOT/.env .env && ln -sf $T3CODE_PROJECT_ROOT/infra/relay/.env infra/relay/.env",
vp i && ln -sf "$T3CODE_PROJECT_ROOT/.env" .env && ln -sf "$T3CODE_PROJECT_ROOT/infra/relay/.env" infra/relay/.env
🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @t3.json around line 7:
The `Setup Worktree` command expands `$T3CODE_PROJECT_ROOT` without quotes in both `ln` source paths. If the project root contains spaces, shell word splitting passes multiple operands to `ln`, so the first link fails and, due to `&&`, neither `.env` link is created. Quote each expanded source path, e.g. `"$T3CODE_PROJECT_ROOT/.env"`.

return currentIndex < threadIds.length - 1 ? (threadIds[currentIndex + 1] ?? null) : null;
}

export function shouldNavigateAfterProjectRemoval(input: {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Mediumcomponents/Sidebar.logic.ts:381

shouldNavigateAfterProjectRemoval returns false for a server route whose thread was added to the project after the projectThreads snapshot was captured — for example, a thread synced while the delete confirmation is pending. After the project is actually removed, the UI stays on that route instead of navigating away, because the thread's environmentId/id match the current route but were not present in the stale snapshot. Consider computing project ownership from current thread state at call time (after the await), or retaining the removed project id and comparing it against the route's project rather than relying on the pre-removal thread list.

🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @apps/web/src/components/Sidebar.logic.ts around line 381:
`shouldNavigateAfterProjectRemoval` returns `false` for a server route whose thread was added to the project after the `projectThreads` snapshot was captured — for example, a thread synced while the delete confirmation is pending. After the project is actually removed, the UI stays on that route instead of navigating away, because the thread's `environmentId`/`id` match the current route but were not present in the stale snapshot. Consider computing project ownership from current thread state at call time (after the await), or retaining the removed project id and comparing it against the route's project rather than relying on the pre-removal thread list.

const api = readLocalApi();
if (!api) return;

const projectThreads = threads.filter(

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟠 Highcomponents/SidebarV2.tsx:854

handleRemoveProject filters threads (live shells only) to compute projectThreads, then shows the user a confirmation dialog saying exactly projectThreads.length thread histories will be deleted. But the deleteProject call passes force: true, which makes the server delete all threads in the project including archived ones. Archived threads are not in the live shell list, so the dialog undercounts: it says "delete its 1 thread" while the server actually deletes every archived history too. Consider counting archived threads for the project (or wording the confirmation to account for archived histories) so the dialog reflects what force: true actually removes.

🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @apps/web/src/components/SidebarV2.tsx around line 854:
`handleRemoveProject` filters `threads` (live shells only) to compute `projectThreads`, then shows the user a confirmation dialog saying exactly `projectThreads.length` thread histories will be deleted. But the `deleteProject` call passes `force: true`, which makes the server delete *all* threads in the project including archived ones. Archived threads are not in the live shell list, so the dialog undercounts: it says "delete its 1 thread" while the server actually deletes every archived history too. Consider counting archived threads for the project (or wording the confirmation to account for archived histories) so the dialog reflects what `force: true` actually removes.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@jetblk@maria-rcks@juliusmarminge@t3dotgg
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Merge upstream: Auto runtime mode, t3.json config, glass-surface redesign - #8

Merged
jetblk merged 21 commits into
mainfrom
t3code/upstream-merge-20260723
Jul 23, 2026
Merged

Merge upstream: Auto runtime mode, t3.json config, glass-surface redesign#8
jetblk merged 21 commits into
mainfrom
t3code/upstream-merge-20260723

Conversation

@jetblk

@jetblkjetblk commented Jul 23, 2026

Copy link
Copy Markdown
Owner

Brings in 20 new commits from pingdotgg/t3code main (origin/main..upstream/main, up to 4d8343641), evaluated per the fork's upstream-merge workflow. Full merge (no cherry-pick) to keep the RPC contract in sync.

Highlights

CommitSummary
fbd77420f (pingdotgg#4272)"Auto" runtime mode — AI-reviewed tool-call approvals for Codex & Claude
1c9a6de26 (pingdotgg#4317)Shared t3.json project configuration support
16491a84b (pingdotgg#4276)Fix: new-thread defaults ignored for remote environments
b44ed835c / 9c9916aefSync provider banner dismissal + redesign review fixes
~15 commitsWeb "glass surfaces" visual redesign (dialogs, glass-opacity slider, command palette / model picker / tooltip styling, light/dark)

Conflicts

None. Auto-merge succeeded on all 6 overlap files (server.ts, server.test.ts, ChatComposer.tsx, ModelPickerContent.tsx, SettingsSidebarNav.tsx, contracts/index.ts); provider-usage wiring preserved in each. No fork-identity files touched. pingdotgg#4272's provider changes don't collide with the fork's usage layers or driver baseEnv threading.

Verification

  • Typecheck clean: @t3tools/contracts, t3 (server), @t3tools/web
  • Tests green: contracts 203, client-runtime 453, server provider-usage suites 156

After squash-merge

Squashing breaks upstream ancestry; will follow with a git merge -s ours upstream/main reconciliation so the next merge stays clean.

🤖 Generated with Claude Code

Note

Add auto runtime mode, t3.json config support, and glass-surface UI redesign

  • Adds an auto runtime mode across contracts, Claude adapter, Codex runtime, and all composer/composer-menu UIs; in auto mode, permissionMode is set to 'auto' and approvals are routed to auto_review.
  • Introduces t3.json project file support: a new schema (t3ProjectFile.ts), server-side loader (T3ProjectFileLoader.ts), and a marketing endpoint serving the JSON Schema for LSP/editor consumption.
  • ProjectFaviconResolver now reads iconPath from t3.json before falling back to well-known icon locations.
  • Scripts declared in t3.json can be imported directly into the project actions UI via ProjectScriptsControl; on failure, the add-action dialog pre-fills for correction.
  • Overhauls UI surfaces with translucent glass effects (backdrop-filter, color-mix) for composer, alerts, dropdowns, and dialogs; sidebar color tokens are unified to a zinc-based hierarchy for both v1 and v2.
  • Adds a user-adjustable glassOpacity setting (range 40–100, default 80) persisted to client settings and applied via --glass-opacity CSS variable in real time.
  • Provider status banners in the chat view are now dismissible and rendered as an overlay, preventing content height shifts.
  • SVG definition IDs in SidebarStageBackdrop components are now generated with useId to prevent collisions when rendered multiple times.
  • New thread defaults (defaultThreadEnvMode, newWorktreesStartFromOrigin) are now sourced from the primary server's settings rather than the target environment's server configs.
  • Risk: The glass/backdrop-filter effects are visually significant and affect many surfaces; reduced-transparency environments fall back to opaque backgrounds, but intermediate system configurations may show unexpected blending.
📊 Macroscope summarized c6b76cd. 63 files reviewed, 0 issues evaluated, 0 issues filtered, 0 comments posted

🗂️ Filtered Issues

No issues evaluated.

maria-rcksand others added 21 commits July 23, 2026 01:13
Co-authored-by: codex <codex@users.noreply.github.com>
…tgg#4276)
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
…laude (pingdotgg#4272)
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
- Restore light-mode glass, dialog, dropdown, and composer colors
- Refine provider wizard, changed-file cards, sidebar controls, and buttons
- Update wizard step tests for the new list structure
Co-authored-by: codex <codex@users.noreply.github.com>
@jetblk
jetblk merged commit a7f2315 into mainJul 23, 2026
1 check passed
jetblk added a commit that referenced this pull request Jul 23, 2026
Records upstream/main (4d83436) as merged. Its content already landed in
main via the squash-merge of #8; this commit only restores git ancestry so
the fork stays 'fully merged' and future upstream merges don't re-present
these commits. No file changes (tree identical to origin/main).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
updateSettings({ glassOpacity });
}
}}
step={5}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Mediumsettings/SettingsPanels.tsx:613

The glass opacity slider uses step={5}, but the settings contract accepts every integer from MIN_GLASS_OPACITY through MAX_GLASS_OPACITY. For a valid persisted value like 72, the range input has a step-mismatched value — the browser may render the thumb at the nearest valid step (e.g. 70), while the adjacent output and custom fill are calculated from 72. The next interaction can then overwrite the valid 72 with the rounded value. Consider using step={1} so the slider can represent every valid value, or restrict the schema to multiples of five.

Suggested change
step={5}
step={1}
🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @apps/web/src/components/settings/SettingsPanels.tsx around line 613:
The glass opacity slider uses `step={5}`, but the settings contract accepts every integer from `MIN_GLASS_OPACITY` through `MAX_GLASS_OPACITY`. For a valid persisted value like `72`, the range input has a step-mismatched value — the browser may render the thumb at the nearest valid step (e.g. `70`), while the adjacent output and custom fill are calculated from `72`. The next interaction can then overwrite the valid `72` with the rounded value. Consider using `step={1}` so the slider can represent every valid value, or restrict the schema to multiples of five.

Comment threadt3.json
"scripts": [
{
"name": "Setup Worktree",
"command": "vp i && ln -sf $T3CODE_PROJECT_ROOT/.env .env && ln -sf $T3CODE_PROJECT_ROOT/infra/relay/.env infra/relay/.env",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Mediumt3.json:7

The Setup Worktree command expands $T3CODE_PROJECT_ROOT without quotes in both ln source paths. If the project root contains spaces, shell word splitting passes multiple operands to ln, so the first link fails and, due to &&, neither .env link is created. Quote each expanded source path, e.g. "$T3CODE_PROJECT_ROOT/.env".

Suggested change
"command": "vp i && ln -sf $T3CODE_PROJECT_ROOT/.env .env && ln -sf $T3CODE_PROJECT_ROOT/infra/relay/.env infra/relay/.env",
vp i && ln -sf "$T3CODE_PROJECT_ROOT/.env" .env && ln -sf "$T3CODE_PROJECT_ROOT/infra/relay/.env" infra/relay/.env
🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @t3.json around line 7:
The `Setup Worktree` command expands `$T3CODE_PROJECT_ROOT` without quotes in both `ln` source paths. If the project root contains spaces, shell word splitting passes multiple operands to `ln`, so the first link fails and, due to `&&`, neither `.env` link is created. Quote each expanded source path, e.g. `"$T3CODE_PROJECT_ROOT/.env"`.

return currentIndex < threadIds.length - 1 ? (threadIds[currentIndex + 1] ?? null) : null;
}

export function shouldNavigateAfterProjectRemoval(input: {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Mediumcomponents/Sidebar.logic.ts:381

shouldNavigateAfterProjectRemoval returns false for a server route whose thread was added to the project after the projectThreads snapshot was captured — for example, a thread synced while the delete confirmation is pending. After the project is actually removed, the UI stays on that route instead of navigating away, because the thread's environmentId/id match the current route but were not present in the stale snapshot. Consider computing project ownership from current thread state at call time (after the await), or retaining the removed project id and comparing it against the route's project rather than relying on the pre-removal thread list.

🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @apps/web/src/components/Sidebar.logic.ts around line 381:
`shouldNavigateAfterProjectRemoval` returns `false` for a server route whose thread was added to the project after the `projectThreads` snapshot was captured — for example, a thread synced while the delete confirmation is pending. After the project is actually removed, the UI stays on that route instead of navigating away, because the thread's `environmentId`/`id` match the current route but were not present in the stale snapshot. Consider computing project ownership from current thread state at call time (after the await), or retaining the removed project id and comparing it against the route's project rather than relying on the pre-removal thread list.

const api = readLocalApi();
if (!api) return;

const projectThreads = threads.filter(

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟠 Highcomponents/SidebarV2.tsx:854

handleRemoveProject filters threads (live shells only) to compute projectThreads, then shows the user a confirmation dialog saying exactly projectThreads.length thread histories will be deleted. But the deleteProject call passes force: true, which makes the server delete all threads in the project including archived ones. Archived threads are not in the live shell list, so the dialog undercounts: it says "delete its 1 thread" while the server actually deletes every archived history too. Consider counting archived threads for the project (or wording the confirmation to account for archived histories) so the dialog reflects what force: true actually removes.

🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @apps/web/src/components/SidebarV2.tsx around line 854:
`handleRemoveProject` filters `threads` (live shells only) to compute `projectThreads`, then shows the user a confirmation dialog saying exactly `projectThreads.length` thread histories will be deleted. But the `deleteProject` call passes `force: true`, which makes the server delete *all* threads in the project including archived ones. Archived threads are not in the live shell list, so the dialog undercounts: it says "delete its 1 thread" while the server actually deletes every archived history too. Consider counting archived threads for the project (or wording the confirmation to account for archived histories) so the dialog reflects what `force: true` actually removes.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@jetblk@maria-rcks@juliusmarminge@t3dotgg
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Merge upstream: Auto runtime mode, t3.json config, glass-surface redesign - #8

Merged
jetblk merged 21 commits into
mainfrom
t3code/upstream-merge-20260723
Jul 23, 2026
Merged

Merge upstream: Auto runtime mode, t3.json config, glass-surface redesign#8
jetblk merged 21 commits into
mainfrom
t3code/upstream-merge-20260723

Conversation

@jetblk

@jetblkjetblk commented Jul 23, 2026

Copy link
Copy Markdown
Owner

Brings in 20 new commits from pingdotgg/t3code main (origin/main..upstream/main, up to 4d8343641), evaluated per the fork's upstream-merge workflow. Full merge (no cherry-pick) to keep the RPC contract in sync.

Highlights

CommitSummary
fbd77420f (pingdotgg#4272)"Auto" runtime mode — AI-reviewed tool-call approvals for Codex & Claude
1c9a6de26 (pingdotgg#4317)Shared t3.json project configuration support
16491a84b (pingdotgg#4276)Fix: new-thread defaults ignored for remote environments
b44ed835c / 9c9916aefSync provider banner dismissal + redesign review fixes
~15 commitsWeb "glass surfaces" visual redesign (dialogs, glass-opacity slider, command palette / model picker / tooltip styling, light/dark)

Conflicts

None. Auto-merge succeeded on all 6 overlap files (server.ts, server.test.ts, ChatComposer.tsx, ModelPickerContent.tsx, SettingsSidebarNav.tsx, contracts/index.ts); provider-usage wiring preserved in each. No fork-identity files touched. pingdotgg#4272's provider changes don't collide with the fork's usage layers or driver baseEnv threading.

Verification

  • Typecheck clean: @t3tools/contracts, t3 (server), @t3tools/web
  • Tests green: contracts 203, client-runtime 453, server provider-usage suites 156

After squash-merge

Squashing breaks upstream ancestry; will follow with a git merge -s ours upstream/main reconciliation so the next merge stays clean.

🤖 Generated with Claude Code

Note

Add auto runtime mode, t3.json config support, and glass-surface UI redesign

  • Adds an auto runtime mode across contracts, Claude adapter, Codex runtime, and all composer/composer-menu UIs; in auto mode, permissionMode is set to 'auto' and approvals are routed to auto_review.
  • Introduces t3.json project file support: a new schema (t3ProjectFile.ts), server-side loader (T3ProjectFileLoader.ts), and a marketing endpoint serving the JSON Schema for LSP/editor consumption.
  • ProjectFaviconResolver now reads iconPath from t3.json before falling back to well-known icon locations.
  • Scripts declared in t3.json can be imported directly into the project actions UI via ProjectScriptsControl; on failure, the add-action dialog pre-fills for correction.
  • Overhauls UI surfaces with translucent glass effects (backdrop-filter, color-mix) for composer, alerts, dropdowns, and dialogs; sidebar color tokens are unified to a zinc-based hierarchy for both v1 and v2.
  • Adds a user-adjustable glassOpacity setting (range 40–100, default 80) persisted to client settings and applied via --glass-opacity CSS variable in real time.
  • Provider status banners in the chat view are now dismissible and rendered as an overlay, preventing content height shifts.
  • SVG definition IDs in SidebarStageBackdrop components are now generated with useId to prevent collisions when rendered multiple times.
  • New thread defaults (defaultThreadEnvMode, newWorktreesStartFromOrigin) are now sourced from the primary server's settings rather than the target environment's server configs.
  • Risk: The glass/backdrop-filter effects are visually significant and affect many surfaces; reduced-transparency environments fall back to opaque backgrounds, but intermediate system configurations may show unexpected blending.
📊 Macroscope summarized c6b76cd. 63 files reviewed, 0 issues evaluated, 0 issues filtered, 0 comments posted

🗂️ Filtered Issues

No issues evaluated.

maria-rcksand others added 21 commits July 23, 2026 01:13
Co-authored-by: codex <codex@users.noreply.github.com>
…tgg#4276)
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
…laude (pingdotgg#4272)
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
- Restore light-mode glass, dialog, dropdown, and composer colors
- Refine provider wizard, changed-file cards, sidebar controls, and buttons
- Update wizard step tests for the new list structure
Co-authored-by: codex <codex@users.noreply.github.com>
@jetblk
jetblk merged commit a7f2315 into mainJul 23, 2026
1 check passed
jetblk added a commit that referenced this pull request Jul 23, 2026
Records upstream/main (4d83436) as merged. Its content already landed in
main via the squash-merge of #8; this commit only restores git ancestry so
the fork stays 'fully merged' and future upstream merges don't re-present
these commits. No file changes (tree identical to origin/main).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
updateSettings({ glassOpacity });
}
}}
step={5}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Mediumsettings/SettingsPanels.tsx:613

The glass opacity slider uses step={5}, but the settings contract accepts every integer from MIN_GLASS_OPACITY through MAX_GLASS_OPACITY. For a valid persisted value like 72, the range input has a step-mismatched value — the browser may render the thumb at the nearest valid step (e.g. 70), while the adjacent output and custom fill are calculated from 72. The next interaction can then overwrite the valid 72 with the rounded value. Consider using step={1} so the slider can represent every valid value, or restrict the schema to multiples of five.

Suggested change
step={5}
step={1}
🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @apps/web/src/components/settings/SettingsPanels.tsx around line 613:
The glass opacity slider uses `step={5}`, but the settings contract accepts every integer from `MIN_GLASS_OPACITY` through `MAX_GLASS_OPACITY`. For a valid persisted value like `72`, the range input has a step-mismatched value — the browser may render the thumb at the nearest valid step (e.g. `70`), while the adjacent output and custom fill are calculated from `72`. The next interaction can then overwrite the valid `72` with the rounded value. Consider using `step={1}` so the slider can represent every valid value, or restrict the schema to multiples of five.

Comment threadt3.json
"scripts": [
{
"name": "Setup Worktree",
"command": "vp i && ln -sf $T3CODE_PROJECT_ROOT/.env .env && ln -sf $T3CODE_PROJECT_ROOT/infra/relay/.env infra/relay/.env",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Mediumt3.json:7

The Setup Worktree command expands $T3CODE_PROJECT_ROOT without quotes in both ln source paths. If the project root contains spaces, shell word splitting passes multiple operands to ln, so the first link fails and, due to &&, neither .env link is created. Quote each expanded source path, e.g. "$T3CODE_PROJECT_ROOT/.env".

Suggested change
"command": "vp i && ln -sf $T3CODE_PROJECT_ROOT/.env .env && ln -sf $T3CODE_PROJECT_ROOT/infra/relay/.env infra/relay/.env",
vp i && ln -sf "$T3CODE_PROJECT_ROOT/.env" .env && ln -sf "$T3CODE_PROJECT_ROOT/infra/relay/.env" infra/relay/.env
🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @t3.json around line 7:
The `Setup Worktree` command expands `$T3CODE_PROJECT_ROOT` without quotes in both `ln` source paths. If the project root contains spaces, shell word splitting passes multiple operands to `ln`, so the first link fails and, due to `&&`, neither `.env` link is created. Quote each expanded source path, e.g. `"$T3CODE_PROJECT_ROOT/.env"`.

return currentIndex < threadIds.length - 1 ? (threadIds[currentIndex + 1] ?? null) : null;
}

export function shouldNavigateAfterProjectRemoval(input: {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Mediumcomponents/Sidebar.logic.ts:381

shouldNavigateAfterProjectRemoval returns false for a server route whose thread was added to the project after the projectThreads snapshot was captured — for example, a thread synced while the delete confirmation is pending. After the project is actually removed, the UI stays on that route instead of navigating away, because the thread's environmentId/id match the current route but were not present in the stale snapshot. Consider computing project ownership from current thread state at call time (after the await), or retaining the removed project id and comparing it against the route's project rather than relying on the pre-removal thread list.

🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @apps/web/src/components/Sidebar.logic.ts around line 381:
`shouldNavigateAfterProjectRemoval` returns `false` for a server route whose thread was added to the project after the `projectThreads` snapshot was captured — for example, a thread synced while the delete confirmation is pending. After the project is actually removed, the UI stays on that route instead of navigating away, because the thread's `environmentId`/`id` match the current route but were not present in the stale snapshot. Consider computing project ownership from current thread state at call time (after the await), or retaining the removed project id and comparing it against the route's project rather than relying on the pre-removal thread list.

const api = readLocalApi();
if (!api) return;

const projectThreads = threads.filter(

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟠 Highcomponents/SidebarV2.tsx:854

handleRemoveProject filters threads (live shells only) to compute projectThreads, then shows the user a confirmation dialog saying exactly projectThreads.length thread histories will be deleted. But the deleteProject call passes force: true, which makes the server delete all threads in the project including archived ones. Archived threads are not in the live shell list, so the dialog undercounts: it says "delete its 1 thread" while the server actually deletes every archived history too. Consider counting archived threads for the project (or wording the confirmation to account for archived histories) so the dialog reflects what force: true actually removes.

🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @apps/web/src/components/SidebarV2.tsx around line 854:
`handleRemoveProject` filters `threads` (live shells only) to compute `projectThreads`, then shows the user a confirmation dialog saying exactly `projectThreads.length` thread histories will be deleted. But the `deleteProject` call passes `force: true`, which makes the server delete *all* threads in the project including archived ones. Archived threads are not in the live shell list, so the dialog undercounts: it says "delete its 1 thread" while the server actually deletes every archived history too. Consider counting archived threads for the project (or wording the confirmation to account for archived histories) so the dialog reflects what `force: true` actually removes.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@jetblk@maria-rcks@juliusmarminge@t3dotgg
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Merge upstream: Auto runtime mode, t3.json config, glass-surface redesign - #8

Merged
jetblk merged 21 commits into
mainfrom
t3code/upstream-merge-20260723
Jul 23, 2026
Merged

Merge upstream: Auto runtime mode, t3.json config, glass-surface redesign#8
jetblk merged 21 commits into
mainfrom
t3code/upstream-merge-20260723

Conversation

@jetblk

@jetblkjetblk commented Jul 23, 2026

Copy link
Copy Markdown
Owner

Brings in 20 new commits from pingdotgg/t3code main (origin/main..upstream/main, up to 4d8343641), evaluated per the fork's upstream-merge workflow. Full merge (no cherry-pick) to keep the RPC contract in sync.

Highlights

CommitSummary
fbd77420f (pingdotgg#4272)"Auto" runtime mode — AI-reviewed tool-call approvals for Codex & Claude
1c9a6de26 (pingdotgg#4317)Shared t3.json project configuration support
16491a84b (pingdotgg#4276)Fix: new-thread defaults ignored for remote environments
b44ed835c / 9c9916aefSync provider banner dismissal + redesign review fixes
~15 commitsWeb "glass surfaces" visual redesign (dialogs, glass-opacity slider, command palette / model picker / tooltip styling, light/dark)

Conflicts

None. Auto-merge succeeded on all 6 overlap files (server.ts, server.test.ts, ChatComposer.tsx, ModelPickerContent.tsx, SettingsSidebarNav.tsx, contracts/index.ts); provider-usage wiring preserved in each. No fork-identity files touched. pingdotgg#4272's provider changes don't collide with the fork's usage layers or driver baseEnv threading.

Verification

  • Typecheck clean: @t3tools/contracts, t3 (server), @t3tools/web
  • Tests green: contracts 203, client-runtime 453, server provider-usage suites 156

After squash-merge

Squashing breaks upstream ancestry; will follow with a git merge -s ours upstream/main reconciliation so the next merge stays clean.

🤖 Generated with Claude Code

Note

Add auto runtime mode, t3.json config support, and glass-surface UI redesign

  • Adds an auto runtime mode across contracts, Claude adapter, Codex runtime, and all composer/composer-menu UIs; in auto mode, permissionMode is set to 'auto' and approvals are routed to auto_review.
  • Introduces t3.json project file support: a new schema (t3ProjectFile.ts), server-side loader (T3ProjectFileLoader.ts), and a marketing endpoint serving the JSON Schema for LSP/editor consumption.
  • ProjectFaviconResolver now reads iconPath from t3.json before falling back to well-known icon locations.
  • Scripts declared in t3.json can be imported directly into the project actions UI via ProjectScriptsControl; on failure, the add-action dialog pre-fills for correction.
  • Overhauls UI surfaces with translucent glass effects (backdrop-filter, color-mix) for composer, alerts, dropdowns, and dialogs; sidebar color tokens are unified to a zinc-based hierarchy for both v1 and v2.
  • Adds a user-adjustable glassOpacity setting (range 40–100, default 80) persisted to client settings and applied via --glass-opacity CSS variable in real time.
  • Provider status banners in the chat view are now dismissible and rendered as an overlay, preventing content height shifts.
  • SVG definition IDs in SidebarStageBackdrop components are now generated with useId to prevent collisions when rendered multiple times.
  • New thread defaults (defaultThreadEnvMode, newWorktreesStartFromOrigin) are now sourced from the primary server's settings rather than the target environment's server configs.
  • Risk: The glass/backdrop-filter effects are visually significant and affect many surfaces; reduced-transparency environments fall back to opaque backgrounds, but intermediate system configurations may show unexpected blending.
📊 Macroscope summarized c6b76cd. 63 files reviewed, 0 issues evaluated, 0 issues filtered, 0 comments posted

🗂️ Filtered Issues

No issues evaluated.

maria-rcksand others added 21 commits July 23, 2026 01:13
Co-authored-by: codex <codex@users.noreply.github.com>
…tgg#4276)
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
…laude (pingdotgg#4272)
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
- Restore light-mode glass, dialog, dropdown, and composer colors
- Refine provider wizard, changed-file cards, sidebar controls, and buttons
- Update wizard step tests for the new list structure
Co-authored-by: codex <codex@users.noreply.github.com>
@jetblk
jetblk merged commit a7f2315 into mainJul 23, 2026
1 check passed
jetblk added a commit that referenced this pull request Jul 23, 2026
Records upstream/main (4d83436) as merged. Its content already landed in
main via the squash-merge of #8; this commit only restores git ancestry so
the fork stays 'fully merged' and future upstream merges don't re-present
these commits. No file changes (tree identical to origin/main).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
updateSettings({ glassOpacity });
}
}}
step={5}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Mediumsettings/SettingsPanels.tsx:613

The glass opacity slider uses step={5}, but the settings contract accepts every integer from MIN_GLASS_OPACITY through MAX_GLASS_OPACITY. For a valid persisted value like 72, the range input has a step-mismatched value — the browser may render the thumb at the nearest valid step (e.g. 70), while the adjacent output and custom fill are calculated from 72. The next interaction can then overwrite the valid 72 with the rounded value. Consider using step={1} so the slider can represent every valid value, or restrict the schema to multiples of five.

Suggested change
step={5}
step={1}
🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @apps/web/src/components/settings/SettingsPanels.tsx around line 613:
The glass opacity slider uses `step={5}`, but the settings contract accepts every integer from `MIN_GLASS_OPACITY` through `MAX_GLASS_OPACITY`. For a valid persisted value like `72`, the range input has a step-mismatched value — the browser may render the thumb at the nearest valid step (e.g. `70`), while the adjacent output and custom fill are calculated from `72`. The next interaction can then overwrite the valid `72` with the rounded value. Consider using `step={1}` so the slider can represent every valid value, or restrict the schema to multiples of five.

Comment threadt3.json
"scripts": [
{
"name": "Setup Worktree",
"command": "vp i && ln -sf $T3CODE_PROJECT_ROOT/.env .env && ln -sf $T3CODE_PROJECT_ROOT/infra/relay/.env infra/relay/.env",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Mediumt3.json:7

The Setup Worktree command expands $T3CODE_PROJECT_ROOT without quotes in both ln source paths. If the project root contains spaces, shell word splitting passes multiple operands to ln, so the first link fails and, due to &&, neither .env link is created. Quote each expanded source path, e.g. "$T3CODE_PROJECT_ROOT/.env".

Suggested change
"command": "vp i && ln -sf $T3CODE_PROJECT_ROOT/.env .env && ln -sf $T3CODE_PROJECT_ROOT/infra/relay/.env infra/relay/.env",
vp i && ln -sf "$T3CODE_PROJECT_ROOT/.env" .env && ln -sf "$T3CODE_PROJECT_ROOT/infra/relay/.env" infra/relay/.env
🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @t3.json around line 7:
The `Setup Worktree` command expands `$T3CODE_PROJECT_ROOT` without quotes in both `ln` source paths. If the project root contains spaces, shell word splitting passes multiple operands to `ln`, so the first link fails and, due to `&&`, neither `.env` link is created. Quote each expanded source path, e.g. `"$T3CODE_PROJECT_ROOT/.env"`.

return currentIndex < threadIds.length - 1 ? (threadIds[currentIndex + 1] ?? null) : null;
}

export function shouldNavigateAfterProjectRemoval(input: {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Mediumcomponents/Sidebar.logic.ts:381

shouldNavigateAfterProjectRemoval returns false for a server route whose thread was added to the project after the projectThreads snapshot was captured — for example, a thread synced while the delete confirmation is pending. After the project is actually removed, the UI stays on that route instead of navigating away, because the thread's environmentId/id match the current route but were not present in the stale snapshot. Consider computing project ownership from current thread state at call time (after the await), or retaining the removed project id and comparing it against the route's project rather than relying on the pre-removal thread list.

🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @apps/web/src/components/Sidebar.logic.ts around line 381:
`shouldNavigateAfterProjectRemoval` returns `false` for a server route whose thread was added to the project after the `projectThreads` snapshot was captured — for example, a thread synced while the delete confirmation is pending. After the project is actually removed, the UI stays on that route instead of navigating away, because the thread's `environmentId`/`id` match the current route but were not present in the stale snapshot. Consider computing project ownership from current thread state at call time (after the await), or retaining the removed project id and comparing it against the route's project rather than relying on the pre-removal thread list.

const api = readLocalApi();
if (!api) return;

const projectThreads = threads.filter(

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟠 Highcomponents/SidebarV2.tsx:854

handleRemoveProject filters threads (live shells only) to compute projectThreads, then shows the user a confirmation dialog saying exactly projectThreads.length thread histories will be deleted. But the deleteProject call passes force: true, which makes the server delete all threads in the project including archived ones. Archived threads are not in the live shell list, so the dialog undercounts: it says "delete its 1 thread" while the server actually deletes every archived history too. Consider counting archived threads for the project (or wording the confirmation to account for archived histories) so the dialog reflects what force: true actually removes.

🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @apps/web/src/components/SidebarV2.tsx around line 854:
`handleRemoveProject` filters `threads` (live shells only) to compute `projectThreads`, then shows the user a confirmation dialog saying exactly `projectThreads.length` thread histories will be deleted. But the `deleteProject` call passes `force: true`, which makes the server delete *all* threads in the project including archived ones. Archived threads are not in the live shell list, so the dialog undercounts: it says "delete its 1 thread" while the server actually deletes every archived history too. Consider counting archived threads for the project (or wording the confirmation to account for archived histories) so the dialog reflects what `force: true` actually removes.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@jetblk@maria-rcks@juliusmarminge@t3dotgg
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Merge upstream: Auto runtime mode, t3.json config, glass-surface redesign - #8

Merged
jetblk merged 21 commits into
mainfrom
t3code/upstream-merge-20260723
Jul 23, 2026
Merged

Merge upstream: Auto runtime mode, t3.json config, glass-surface redesign#8
jetblk merged 21 commits into
mainfrom
t3code/upstream-merge-20260723

Conversation

@jetblk

@jetblkjetblk commented Jul 23, 2026

Copy link
Copy Markdown
Owner

Brings in 20 new commits from pingdotgg/t3code main (origin/main..upstream/main, up to 4d8343641), evaluated per the fork's upstream-merge workflow. Full merge (no cherry-pick) to keep the RPC contract in sync.

Highlights

CommitSummary
fbd77420f (pingdotgg#4272)"Auto" runtime mode — AI-reviewed tool-call approvals for Codex & Claude
1c9a6de26 (pingdotgg#4317)Shared t3.json project configuration support
16491a84b (pingdotgg#4276)Fix: new-thread defaults ignored for remote environments
b44ed835c / 9c9916aefSync provider banner dismissal + redesign review fixes
~15 commitsWeb "glass surfaces" visual redesign (dialogs, glass-opacity slider, command palette / model picker / tooltip styling, light/dark)

Conflicts

None. Auto-merge succeeded on all 6 overlap files (server.ts, server.test.ts, ChatComposer.tsx, ModelPickerContent.tsx, SettingsSidebarNav.tsx, contracts/index.ts); provider-usage wiring preserved in each. No fork-identity files touched. pingdotgg#4272's provider changes don't collide with the fork's usage layers or driver baseEnv threading.

Verification

  • Typecheck clean: @t3tools/contracts, t3 (server), @t3tools/web
  • Tests green: contracts 203, client-runtime 453, server provider-usage suites 156

After squash-merge

Squashing breaks upstream ancestry; will follow with a git merge -s ours upstream/main reconciliation so the next merge stays clean.

🤖 Generated with Claude Code

Note

Add auto runtime mode, t3.json config support, and glass-surface UI redesign

  • Adds an auto runtime mode across contracts, Claude adapter, Codex runtime, and all composer/composer-menu UIs; in auto mode, permissionMode is set to 'auto' and approvals are routed to auto_review.
  • Introduces t3.json project file support: a new schema (t3ProjectFile.ts), server-side loader (T3ProjectFileLoader.ts), and a marketing endpoint serving the JSON Schema for LSP/editor consumption.
  • ProjectFaviconResolver now reads iconPath from t3.json before falling back to well-known icon locations.
  • Scripts declared in t3.json can be imported directly into the project actions UI via ProjectScriptsControl; on failure, the add-action dialog pre-fills for correction.
  • Overhauls UI surfaces with translucent glass effects (backdrop-filter, color-mix) for composer, alerts, dropdowns, and dialogs; sidebar color tokens are unified to a zinc-based hierarchy for both v1 and v2.
  • Adds a user-adjustable glassOpacity setting (range 40–100, default 80) persisted to client settings and applied via --glass-opacity CSS variable in real time.
  • Provider status banners in the chat view are now dismissible and rendered as an overlay, preventing content height shifts.
  • SVG definition IDs in SidebarStageBackdrop components are now generated with useId to prevent collisions when rendered multiple times.
  • New thread defaults (defaultThreadEnvMode, newWorktreesStartFromOrigin) are now sourced from the primary server's settings rather than the target environment's server configs.
  • Risk: The glass/backdrop-filter effects are visually significant and affect many surfaces; reduced-transparency environments fall back to opaque backgrounds, but intermediate system configurations may show unexpected blending.
📊 Macroscope summarized c6b76cd. 63 files reviewed, 0 issues evaluated, 0 issues filtered, 0 comments posted

🗂️ Filtered Issues

No issues evaluated.

maria-rcksand others added 21 commits July 23, 2026 01:13
Co-authored-by: codex <codex@users.noreply.github.com>
…tgg#4276)
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
…laude (pingdotgg#4272)
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
- Restore light-mode glass, dialog, dropdown, and composer colors
- Refine provider wizard, changed-file cards, sidebar controls, and buttons
- Update wizard step tests for the new list structure
Co-authored-by: codex <codex@users.noreply.github.com>
@jetblk
jetblk merged commit a7f2315 into mainJul 23, 2026
1 check passed
jetblk added a commit that referenced this pull request Jul 23, 2026
Records upstream/main (4d83436) as merged. Its content already landed in
main via the squash-merge of #8; this commit only restores git ancestry so
the fork stays 'fully merged' and future upstream merges don't re-present
these commits. No file changes (tree identical to origin/main).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
updateSettings({ glassOpacity });
}
}}
step={5}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Mediumsettings/SettingsPanels.tsx:613

The glass opacity slider uses step={5}, but the settings contract accepts every integer from MIN_GLASS_OPACITY through MAX_GLASS_OPACITY. For a valid persisted value like 72, the range input has a step-mismatched value — the browser may render the thumb at the nearest valid step (e.g. 70), while the adjacent output and custom fill are calculated from 72. The next interaction can then overwrite the valid 72 with the rounded value. Consider using step={1} so the slider can represent every valid value, or restrict the schema to multiples of five.

Suggested change
step={5}
step={1}
🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @apps/web/src/components/settings/SettingsPanels.tsx around line 613:
The glass opacity slider uses `step={5}`, but the settings contract accepts every integer from `MIN_GLASS_OPACITY` through `MAX_GLASS_OPACITY`. For a valid persisted value like `72`, the range input has a step-mismatched value — the browser may render the thumb at the nearest valid step (e.g. `70`), while the adjacent output and custom fill are calculated from `72`. The next interaction can then overwrite the valid `72` with the rounded value. Consider using `step={1}` so the slider can represent every valid value, or restrict the schema to multiples of five.

Comment threadt3.json
"scripts": [
{
"name": "Setup Worktree",
"command": "vp i && ln -sf $T3CODE_PROJECT_ROOT/.env .env && ln -sf $T3CODE_PROJECT_ROOT/infra/relay/.env infra/relay/.env",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Mediumt3.json:7

The Setup Worktree command expands $T3CODE_PROJECT_ROOT without quotes in both ln source paths. If the project root contains spaces, shell word splitting passes multiple operands to ln, so the first link fails and, due to &&, neither .env link is created. Quote each expanded source path, e.g. "$T3CODE_PROJECT_ROOT/.env".

Suggested change
"command": "vp i && ln -sf $T3CODE_PROJECT_ROOT/.env .env && ln -sf $T3CODE_PROJECT_ROOT/infra/relay/.env infra/relay/.env",
vp i && ln -sf "$T3CODE_PROJECT_ROOT/.env" .env && ln -sf "$T3CODE_PROJECT_ROOT/infra/relay/.env" infra/relay/.env
🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @t3.json around line 7:
The `Setup Worktree` command expands `$T3CODE_PROJECT_ROOT` without quotes in both `ln` source paths. If the project root contains spaces, shell word splitting passes multiple operands to `ln`, so the first link fails and, due to `&&`, neither `.env` link is created. Quote each expanded source path, e.g. `"$T3CODE_PROJECT_ROOT/.env"`.

return currentIndex < threadIds.length - 1 ? (threadIds[currentIndex + 1] ?? null) : null;
}

export function shouldNavigateAfterProjectRemoval(input: {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Mediumcomponents/Sidebar.logic.ts:381

shouldNavigateAfterProjectRemoval returns false for a server route whose thread was added to the project after the projectThreads snapshot was captured — for example, a thread synced while the delete confirmation is pending. After the project is actually removed, the UI stays on that route instead of navigating away, because the thread's environmentId/id match the current route but were not present in the stale snapshot. Consider computing project ownership from current thread state at call time (after the await), or retaining the removed project id and comparing it against the route's project rather than relying on the pre-removal thread list.

🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @apps/web/src/components/Sidebar.logic.ts around line 381:
`shouldNavigateAfterProjectRemoval` returns `false` for a server route whose thread was added to the project after the `projectThreads` snapshot was captured — for example, a thread synced while the delete confirmation is pending. After the project is actually removed, the UI stays on that route instead of navigating away, because the thread's `environmentId`/`id` match the current route but were not present in the stale snapshot. Consider computing project ownership from current thread state at call time (after the await), or retaining the removed project id and comparing it against the route's project rather than relying on the pre-removal thread list.

const api = readLocalApi();
if (!api) return;

const projectThreads = threads.filter(

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟠 Highcomponents/SidebarV2.tsx:854

handleRemoveProject filters threads (live shells only) to compute projectThreads, then shows the user a confirmation dialog saying exactly projectThreads.length thread histories will be deleted. But the deleteProject call passes force: true, which makes the server delete all threads in the project including archived ones. Archived threads are not in the live shell list, so the dialog undercounts: it says "delete its 1 thread" while the server actually deletes every archived history too. Consider counting archived threads for the project (or wording the confirmation to account for archived histories) so the dialog reflects what force: true actually removes.

🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @apps/web/src/components/SidebarV2.tsx around line 854:
`handleRemoveProject` filters `threads` (live shells only) to compute `projectThreads`, then shows the user a confirmation dialog saying exactly `projectThreads.length` thread histories will be deleted. But the `deleteProject` call passes `force: true`, which makes the server delete *all* threads in the project including archived ones. Archived threads are not in the live shell list, so the dialog undercounts: it says "delete its 1 thread" while the server actually deletes every archived history too. Consider counting archived threads for the project (or wording the confirmation to account for archived histories) so the dialog reflects what `force: true` actually removes.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@jetblk@maria-rcks@juliusmarminge@t3dotgg
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Merge upstream: Auto runtime mode, t3.json config, glass-surface redesign - #8

Merged
jetblk merged 21 commits into
mainfrom
t3code/upstream-merge-20260723
Jul 23, 2026
Merged

Merge upstream: Auto runtime mode, t3.json config, glass-surface redesign#8
jetblk merged 21 commits into
mainfrom
t3code/upstream-merge-20260723

Conversation

@jetblk

@jetblkjetblk commented Jul 23, 2026

Copy link
Copy Markdown
Owner

Brings in 20 new commits from pingdotgg/t3code main (origin/main..upstream/main, up to 4d8343641), evaluated per the fork's upstream-merge workflow. Full merge (no cherry-pick) to keep the RPC contract in sync.

Highlights

CommitSummary
fbd77420f (pingdotgg#4272)"Auto" runtime mode — AI-reviewed tool-call approvals for Codex & Claude
1c9a6de26 (pingdotgg#4317)Shared t3.json project configuration support
16491a84b (pingdotgg#4276)Fix: new-thread defaults ignored for remote environments
b44ed835c / 9c9916aefSync provider banner dismissal + redesign review fixes
~15 commitsWeb "glass surfaces" visual redesign (dialogs, glass-opacity slider, command palette / model picker / tooltip styling, light/dark)

Conflicts

None. Auto-merge succeeded on all 6 overlap files (server.ts, server.test.ts, ChatComposer.tsx, ModelPickerContent.tsx, SettingsSidebarNav.tsx, contracts/index.ts); provider-usage wiring preserved in each. No fork-identity files touched. pingdotgg#4272's provider changes don't collide with the fork's usage layers or driver baseEnv threading.

Verification

  • Typecheck clean: @t3tools/contracts, t3 (server), @t3tools/web
  • Tests green: contracts 203, client-runtime 453, server provider-usage suites 156

After squash-merge

Squashing breaks upstream ancestry; will follow with a git merge -s ours upstream/main reconciliation so the next merge stays clean.

🤖 Generated with Claude Code

Note

Add auto runtime mode, t3.json config support, and glass-surface UI redesign

  • Adds an auto runtime mode across contracts, Claude adapter, Codex runtime, and all composer/composer-menu UIs; in auto mode, permissionMode is set to 'auto' and approvals are routed to auto_review.
  • Introduces t3.json project file support: a new schema (t3ProjectFile.ts), server-side loader (T3ProjectFileLoader.ts), and a marketing endpoint serving the JSON Schema for LSP/editor consumption.
  • ProjectFaviconResolver now reads iconPath from t3.json before falling back to well-known icon locations.
  • Scripts declared in t3.json can be imported directly into the project actions UI via ProjectScriptsControl; on failure, the add-action dialog pre-fills for correction.
  • Overhauls UI surfaces with translucent glass effects (backdrop-filter, color-mix) for composer, alerts, dropdowns, and dialogs; sidebar color tokens are unified to a zinc-based hierarchy for both v1 and v2.
  • Adds a user-adjustable glassOpacity setting (range 40–100, default 80) persisted to client settings and applied via --glass-opacity CSS variable in real time.
  • Provider status banners in the chat view are now dismissible and rendered as an overlay, preventing content height shifts.
  • SVG definition IDs in SidebarStageBackdrop components are now generated with useId to prevent collisions when rendered multiple times.
  • New thread defaults (defaultThreadEnvMode, newWorktreesStartFromOrigin) are now sourced from the primary server's settings rather than the target environment's server configs.
  • Risk: The glass/backdrop-filter effects are visually significant and affect many surfaces; reduced-transparency environments fall back to opaque backgrounds, but intermediate system configurations may show unexpected blending.
📊 Macroscope summarized c6b76cd. 63 files reviewed, 0 issues evaluated, 0 issues filtered, 0 comments posted

🗂️ Filtered Issues

No issues evaluated.

maria-rcksand others added 21 commits July 23, 2026 01:13
Co-authored-by: codex <codex@users.noreply.github.com>
…tgg#4276)
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
…laude (pingdotgg#4272)
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
- Restore light-mode glass, dialog, dropdown, and composer colors
- Refine provider wizard, changed-file cards, sidebar controls, and buttons
- Update wizard step tests for the new list structure
Co-authored-by: codex <codex@users.noreply.github.com>
@jetblk
jetblk merged commit a7f2315 into mainJul 23, 2026
1 check passed
jetblk added a commit that referenced this pull request Jul 23, 2026
Records upstream/main (4d83436) as merged. Its content already landed in
main via the squash-merge of #8; this commit only restores git ancestry so
the fork stays 'fully merged' and future upstream merges don't re-present
these commits. No file changes (tree identical to origin/main).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
updateSettings({ glassOpacity });
}
}}
step={5}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Mediumsettings/SettingsPanels.tsx:613

The glass opacity slider uses step={5}, but the settings contract accepts every integer from MIN_GLASS_OPACITY through MAX_GLASS_OPACITY. For a valid persisted value like 72, the range input has a step-mismatched value — the browser may render the thumb at the nearest valid step (e.g. 70), while the adjacent output and custom fill are calculated from 72. The next interaction can then overwrite the valid 72 with the rounded value. Consider using step={1} so the slider can represent every valid value, or restrict the schema to multiples of five.

Suggested change
step={5}
step={1}
🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @apps/web/src/components/settings/SettingsPanels.tsx around line 613:
The glass opacity slider uses `step={5}`, but the settings contract accepts every integer from `MIN_GLASS_OPACITY` through `MAX_GLASS_OPACITY`. For a valid persisted value like `72`, the range input has a step-mismatched value — the browser may render the thumb at the nearest valid step (e.g. `70`), while the adjacent output and custom fill are calculated from `72`. The next interaction can then overwrite the valid `72` with the rounded value. Consider using `step={1}` so the slider can represent every valid value, or restrict the schema to multiples of five.

Comment threadt3.json
"scripts": [
{
"name": "Setup Worktree",
"command": "vp i && ln -sf $T3CODE_PROJECT_ROOT/.env .env && ln -sf $T3CODE_PROJECT_ROOT/infra/relay/.env infra/relay/.env",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Mediumt3.json:7

The Setup Worktree command expands $T3CODE_PROJECT_ROOT without quotes in both ln source paths. If the project root contains spaces, shell word splitting passes multiple operands to ln, so the first link fails and, due to &&, neither .env link is created. Quote each expanded source path, e.g. "$T3CODE_PROJECT_ROOT/.env".

Suggested change
"command": "vp i && ln -sf $T3CODE_PROJECT_ROOT/.env .env && ln -sf $T3CODE_PROJECT_ROOT/infra/relay/.env infra/relay/.env",
vp i && ln -sf "$T3CODE_PROJECT_ROOT/.env" .env && ln -sf "$T3CODE_PROJECT_ROOT/infra/relay/.env" infra/relay/.env
🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @t3.json around line 7:
The `Setup Worktree` command expands `$T3CODE_PROJECT_ROOT` without quotes in both `ln` source paths. If the project root contains spaces, shell word splitting passes multiple operands to `ln`, so the first link fails and, due to `&&`, neither `.env` link is created. Quote each expanded source path, e.g. `"$T3CODE_PROJECT_ROOT/.env"`.

return currentIndex < threadIds.length - 1 ? (threadIds[currentIndex + 1] ?? null) : null;
}

export function shouldNavigateAfterProjectRemoval(input: {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Mediumcomponents/Sidebar.logic.ts:381

shouldNavigateAfterProjectRemoval returns false for a server route whose thread was added to the project after the projectThreads snapshot was captured — for example, a thread synced while the delete confirmation is pending. After the project is actually removed, the UI stays on that route instead of navigating away, because the thread's environmentId/id match the current route but were not present in the stale snapshot. Consider computing project ownership from current thread state at call time (after the await), or retaining the removed project id and comparing it against the route's project rather than relying on the pre-removal thread list.

🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @apps/web/src/components/Sidebar.logic.ts around line 381:
`shouldNavigateAfterProjectRemoval` returns `false` for a server route whose thread was added to the project after the `projectThreads` snapshot was captured — for example, a thread synced while the delete confirmation is pending. After the project is actually removed, the UI stays on that route instead of navigating away, because the thread's `environmentId`/`id` match the current route but were not present in the stale snapshot. Consider computing project ownership from current thread state at call time (after the await), or retaining the removed project id and comparing it against the route's project rather than relying on the pre-removal thread list.

const api = readLocalApi();
if (!api) return;

const projectThreads = threads.filter(

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟠 Highcomponents/SidebarV2.tsx:854

handleRemoveProject filters threads (live shells only) to compute projectThreads, then shows the user a confirmation dialog saying exactly projectThreads.length thread histories will be deleted. But the deleteProject call passes force: true, which makes the server delete all threads in the project including archived ones. Archived threads are not in the live shell list, so the dialog undercounts: it says "delete its 1 thread" while the server actually deletes every archived history too. Consider counting archived threads for the project (or wording the confirmation to account for archived histories) so the dialog reflects what force: true actually removes.

🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @apps/web/src/components/SidebarV2.tsx around line 854:
`handleRemoveProject` filters `threads` (live shells only) to compute `projectThreads`, then shows the user a confirmation dialog saying exactly `projectThreads.length` thread histories will be deleted. But the `deleteProject` call passes `force: true`, which makes the server delete *all* threads in the project including archived ones. Archived threads are not in the live shell list, so the dialog undercounts: it says "delete its 1 thread" while the server actually deletes every archived history too. Consider counting archived threads for the project (or wording the confirmation to account for archived histories) so the dialog reflects what `force: true` actually removes.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@jetblk@maria-rcks@juliusmarminge@t3dotgg
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Merge upstream: Auto runtime mode, t3.json config, glass-surface redesign - #8

Merged
jetblk merged 21 commits into
mainfrom
t3code/upstream-merge-20260723
Jul 23, 2026
Merged

Merge upstream: Auto runtime mode, t3.json config, glass-surface redesign#8
jetblk merged 21 commits into
mainfrom
t3code/upstream-merge-20260723

Conversation

@jetblk

@jetblkjetblk commented Jul 23, 2026

Copy link
Copy Markdown
Owner

Brings in 20 new commits from pingdotgg/t3code main (origin/main..upstream/main, up to 4d8343641), evaluated per the fork's upstream-merge workflow. Full merge (no cherry-pick) to keep the RPC contract in sync.

Highlights

CommitSummary
fbd77420f (pingdotgg#4272)"Auto" runtime mode — AI-reviewed tool-call approvals for Codex & Claude
1c9a6de26 (pingdotgg#4317)Shared t3.json project configuration support
16491a84b (pingdotgg#4276)Fix: new-thread defaults ignored for remote environments
b44ed835c / 9c9916aefSync provider banner dismissal + redesign review fixes
~15 commitsWeb "glass surfaces" visual redesign (dialogs, glass-opacity slider, command palette / model picker / tooltip styling, light/dark)

Conflicts

None. Auto-merge succeeded on all 6 overlap files (server.ts, server.test.ts, ChatComposer.tsx, ModelPickerContent.tsx, SettingsSidebarNav.tsx, contracts/index.ts); provider-usage wiring preserved in each. No fork-identity files touched. pingdotgg#4272's provider changes don't collide with the fork's usage layers or driver baseEnv threading.

Verification

  • Typecheck clean: @t3tools/contracts, t3 (server), @t3tools/web
  • Tests green: contracts 203, client-runtime 453, server provider-usage suites 156

After squash-merge

Squashing breaks upstream ancestry; will follow with a git merge -s ours upstream/main reconciliation so the next merge stays clean.

🤖 Generated with Claude Code

Note

Add auto runtime mode, t3.json config support, and glass-surface UI redesign

  • Adds an auto runtime mode across contracts, Claude adapter, Codex runtime, and all composer/composer-menu UIs; in auto mode, permissionMode is set to 'auto' and approvals are routed to auto_review.
  • Introduces t3.json project file support: a new schema (t3ProjectFile.ts), server-side loader (T3ProjectFileLoader.ts), and a marketing endpoint serving the JSON Schema for LSP/editor consumption.
  • ProjectFaviconResolver now reads iconPath from t3.json before falling back to well-known icon locations.
  • Scripts declared in t3.json can be imported directly into the project actions UI via ProjectScriptsControl; on failure, the add-action dialog pre-fills for correction.
  • Overhauls UI surfaces with translucent glass effects (backdrop-filter, color-mix) for composer, alerts, dropdowns, and dialogs; sidebar color tokens are unified to a zinc-based hierarchy for both v1 and v2.
  • Adds a user-adjustable glassOpacity setting (range 40–100, default 80) persisted to client settings and applied via --glass-opacity CSS variable in real time.
  • Provider status banners in the chat view are now dismissible and rendered as an overlay, preventing content height shifts.
  • SVG definition IDs in SidebarStageBackdrop components are now generated with useId to prevent collisions when rendered multiple times.
  • New thread defaults (defaultThreadEnvMode, newWorktreesStartFromOrigin) are now sourced from the primary server's settings rather than the target environment's server configs.
  • Risk: The glass/backdrop-filter effects are visually significant and affect many surfaces; reduced-transparency environments fall back to opaque backgrounds, but intermediate system configurations may show unexpected blending.
📊 Macroscope summarized c6b76cd. 63 files reviewed, 0 issues evaluated, 0 issues filtered, 0 comments posted

🗂️ Filtered Issues

No issues evaluated.

maria-rcksand others added 21 commits July 23, 2026 01:13
Co-authored-by: codex <codex@users.noreply.github.com>
…tgg#4276)
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
…laude (pingdotgg#4272)
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
- Restore light-mode glass, dialog, dropdown, and composer colors
- Refine provider wizard, changed-file cards, sidebar controls, and buttons
- Update wizard step tests for the new list structure
Co-authored-by: codex <codex@users.noreply.github.com>
@jetblk
jetblk merged commit a7f2315 into mainJul 23, 2026
1 check passed
jetblk added a commit that referenced this pull request Jul 23, 2026
Records upstream/main (4d83436) as merged. Its content already landed in
main via the squash-merge of #8; this commit only restores git ancestry so
the fork stays 'fully merged' and future upstream merges don't re-present
these commits. No file changes (tree identical to origin/main).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
updateSettings({ glassOpacity });
}
}}
step={5}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Mediumsettings/SettingsPanels.tsx:613

The glass opacity slider uses step={5}, but the settings contract accepts every integer from MIN_GLASS_OPACITY through MAX_GLASS_OPACITY. For a valid persisted value like 72, the range input has a step-mismatched value — the browser may render the thumb at the nearest valid step (e.g. 70), while the adjacent output and custom fill are calculated from 72. The next interaction can then overwrite the valid 72 with the rounded value. Consider using step={1} so the slider can represent every valid value, or restrict the schema to multiples of five.

Suggested change
step={5}
step={1}
🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @apps/web/src/components/settings/SettingsPanels.tsx around line 613:
The glass opacity slider uses `step={5}`, but the settings contract accepts every integer from `MIN_GLASS_OPACITY` through `MAX_GLASS_OPACITY`. For a valid persisted value like `72`, the range input has a step-mismatched value — the browser may render the thumb at the nearest valid step (e.g. `70`), while the adjacent output and custom fill are calculated from `72`. The next interaction can then overwrite the valid `72` with the rounded value. Consider using `step={1}` so the slider can represent every valid value, or restrict the schema to multiples of five.

Comment threadt3.json
"scripts": [
{
"name": "Setup Worktree",
"command": "vp i && ln -sf $T3CODE_PROJECT_ROOT/.env .env && ln -sf $T3CODE_PROJECT_ROOT/infra/relay/.env infra/relay/.env",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Mediumt3.json:7

The Setup Worktree command expands $T3CODE_PROJECT_ROOT without quotes in both ln source paths. If the project root contains spaces, shell word splitting passes multiple operands to ln, so the first link fails and, due to &&, neither .env link is created. Quote each expanded source path, e.g. "$T3CODE_PROJECT_ROOT/.env".

Suggested change
"command": "vp i && ln -sf $T3CODE_PROJECT_ROOT/.env .env && ln -sf $T3CODE_PROJECT_ROOT/infra/relay/.env infra/relay/.env",
vp i && ln -sf "$T3CODE_PROJECT_ROOT/.env" .env && ln -sf "$T3CODE_PROJECT_ROOT/infra/relay/.env" infra/relay/.env
🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @t3.json around line 7:
The `Setup Worktree` command expands `$T3CODE_PROJECT_ROOT` without quotes in both `ln` source paths. If the project root contains spaces, shell word splitting passes multiple operands to `ln`, so the first link fails and, due to `&&`, neither `.env` link is created. Quote each expanded source path, e.g. `"$T3CODE_PROJECT_ROOT/.env"`.

return currentIndex < threadIds.length - 1 ? (threadIds[currentIndex + 1] ?? null) : null;
}

export function shouldNavigateAfterProjectRemoval(input: {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Mediumcomponents/Sidebar.logic.ts:381

shouldNavigateAfterProjectRemoval returns false for a server route whose thread was added to the project after the projectThreads snapshot was captured — for example, a thread synced while the delete confirmation is pending. After the project is actually removed, the UI stays on that route instead of navigating away, because the thread's environmentId/id match the current route but were not present in the stale snapshot. Consider computing project ownership from current thread state at call time (after the await), or retaining the removed project id and comparing it against the route's project rather than relying on the pre-removal thread list.

🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @apps/web/src/components/Sidebar.logic.ts around line 381:
`shouldNavigateAfterProjectRemoval` returns `false` for a server route whose thread was added to the project after the `projectThreads` snapshot was captured — for example, a thread synced while the delete confirmation is pending. After the project is actually removed, the UI stays on that route instead of navigating away, because the thread's `environmentId`/`id` match the current route but were not present in the stale snapshot. Consider computing project ownership from current thread state at call time (after the await), or retaining the removed project id and comparing it against the route's project rather than relying on the pre-removal thread list.

const api = readLocalApi();
if (!api) return;

const projectThreads = threads.filter(

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟠 Highcomponents/SidebarV2.tsx:854

handleRemoveProject filters threads (live shells only) to compute projectThreads, then shows the user a confirmation dialog saying exactly projectThreads.length thread histories will be deleted. But the deleteProject call passes force: true, which makes the server delete all threads in the project including archived ones. Archived threads are not in the live shell list, so the dialog undercounts: it says "delete its 1 thread" while the server actually deletes every archived history too. Consider counting archived threads for the project (or wording the confirmation to account for archived histories) so the dialog reflects what force: true actually removes.

🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @apps/web/src/components/SidebarV2.tsx around line 854:
`handleRemoveProject` filters `threads` (live shells only) to compute `projectThreads`, then shows the user a confirmation dialog saying exactly `projectThreads.length` thread histories will be deleted. But the `deleteProject` call passes `force: true`, which makes the server delete *all* threads in the project including archived ones. Archived threads are not in the live shell list, so the dialog undercounts: it says "delete its 1 thread" while the server actually deletes every archived history too. Consider counting archived threads for the project (or wording the confirmation to account for archived histories) so the dialog reflects what `force: true` actually removes.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@jetblk@maria-rcks@juliusmarminge@t3dotgg
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Merge upstream: Auto runtime mode, t3.json config, glass-surface redesign - #8

Merged
jetblk merged 21 commits into
mainfrom
t3code/upstream-merge-20260723
Jul 23, 2026
Merged

Merge upstream: Auto runtime mode, t3.json config, glass-surface redesign#8
jetblk merged 21 commits into
mainfrom
t3code/upstream-merge-20260723

Conversation

@jetblk

@jetblkjetblk commented Jul 23, 2026

Copy link
Copy Markdown
Owner

Brings in 20 new commits from pingdotgg/t3code main (origin/main..upstream/main, up to 4d8343641), evaluated per the fork's upstream-merge workflow. Full merge (no cherry-pick) to keep the RPC contract in sync.

Highlights

CommitSummary
fbd77420f (pingdotgg#4272)"Auto" runtime mode — AI-reviewed tool-call approvals for Codex & Claude
1c9a6de26 (pingdotgg#4317)Shared t3.json project configuration support
16491a84b (pingdotgg#4276)Fix: new-thread defaults ignored for remote environments
b44ed835c / 9c9916aefSync provider banner dismissal + redesign review fixes
~15 commitsWeb "glass surfaces" visual redesign (dialogs, glass-opacity slider, command palette / model picker / tooltip styling, light/dark)

Conflicts

None. Auto-merge succeeded on all 6 overlap files (server.ts, server.test.ts, ChatComposer.tsx, ModelPickerContent.tsx, SettingsSidebarNav.tsx, contracts/index.ts); provider-usage wiring preserved in each. No fork-identity files touched. pingdotgg#4272's provider changes don't collide with the fork's usage layers or driver baseEnv threading.

Verification

  • Typecheck clean: @t3tools/contracts, t3 (server), @t3tools/web
  • Tests green: contracts 203, client-runtime 453, server provider-usage suites 156

After squash-merge

Squashing breaks upstream ancestry; will follow with a git merge -s ours upstream/main reconciliation so the next merge stays clean.

🤖 Generated with Claude Code

Note

Add auto runtime mode, t3.json config support, and glass-surface UI redesign

  • Adds an auto runtime mode across contracts, Claude adapter, Codex runtime, and all composer/composer-menu UIs; in auto mode, permissionMode is set to 'auto' and approvals are routed to auto_review.
  • Introduces t3.json project file support: a new schema (t3ProjectFile.ts), server-side loader (T3ProjectFileLoader.ts), and a marketing endpoint serving the JSON Schema for LSP/editor consumption.
  • ProjectFaviconResolver now reads iconPath from t3.json before falling back to well-known icon locations.
  • Scripts declared in t3.json can be imported directly into the project actions UI via ProjectScriptsControl; on failure, the add-action dialog pre-fills for correction.
  • Overhauls UI surfaces with translucent glass effects (backdrop-filter, color-mix) for composer, alerts, dropdowns, and dialogs; sidebar color tokens are unified to a zinc-based hierarchy for both v1 and v2.
  • Adds a user-adjustable glassOpacity setting (range 40–100, default 80) persisted to client settings and applied via --glass-opacity CSS variable in real time.
  • Provider status banners in the chat view are now dismissible and rendered as an overlay, preventing content height shifts.
  • SVG definition IDs in SidebarStageBackdrop components are now generated with useId to prevent collisions when rendered multiple times.
  • New thread defaults (defaultThreadEnvMode, newWorktreesStartFromOrigin) are now sourced from the primary server's settings rather than the target environment's server configs.
  • Risk: The glass/backdrop-filter effects are visually significant and affect many surfaces; reduced-transparency environments fall back to opaque backgrounds, but intermediate system configurations may show unexpected blending.
📊 Macroscope summarized c6b76cd. 63 files reviewed, 0 issues evaluated, 0 issues filtered, 0 comments posted

🗂️ Filtered Issues

No issues evaluated.

maria-rcksand others added 21 commits July 23, 2026 01:13
Co-authored-by: codex <codex@users.noreply.github.com>
…tgg#4276)
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
…laude (pingdotgg#4272)
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
- Restore light-mode glass, dialog, dropdown, and composer colors
- Refine provider wizard, changed-file cards, sidebar controls, and buttons
- Update wizard step tests for the new list structure
Co-authored-by: codex <codex@users.noreply.github.com>
@jetblk
jetblk merged commit a7f2315 into mainJul 23, 2026
1 check passed
jetblk added a commit that referenced this pull request Jul 23, 2026
Records upstream/main (4d83436) as merged. Its content already landed in
main via the squash-merge of #8; this commit only restores git ancestry so
the fork stays 'fully merged' and future upstream merges don't re-present
these commits. No file changes (tree identical to origin/main).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
updateSettings({ glassOpacity });
}
}}
step={5}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Mediumsettings/SettingsPanels.tsx:613

The glass opacity slider uses step={5}, but the settings contract accepts every integer from MIN_GLASS_OPACITY through MAX_GLASS_OPACITY. For a valid persisted value like 72, the range input has a step-mismatched value — the browser may render the thumb at the nearest valid step (e.g. 70), while the adjacent output and custom fill are calculated from 72. The next interaction can then overwrite the valid 72 with the rounded value. Consider using step={1} so the slider can represent every valid value, or restrict the schema to multiples of five.

Suggested change
step={5}
step={1}
🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @apps/web/src/components/settings/SettingsPanels.tsx around line 613:
The glass opacity slider uses `step={5}`, but the settings contract accepts every integer from `MIN_GLASS_OPACITY` through `MAX_GLASS_OPACITY`. For a valid persisted value like `72`, the range input has a step-mismatched value — the browser may render the thumb at the nearest valid step (e.g. `70`), while the adjacent output and custom fill are calculated from `72`. The next interaction can then overwrite the valid `72` with the rounded value. Consider using `step={1}` so the slider can represent every valid value, or restrict the schema to multiples of five.

Comment threadt3.json
"scripts": [
{
"name": "Setup Worktree",
"command": "vp i && ln -sf $T3CODE_PROJECT_ROOT/.env .env && ln -sf $T3CODE_PROJECT_ROOT/infra/relay/.env infra/relay/.env",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Mediumt3.json:7

The Setup Worktree command expands $T3CODE_PROJECT_ROOT without quotes in both ln source paths. If the project root contains spaces, shell word splitting passes multiple operands to ln, so the first link fails and, due to &&, neither .env link is created. Quote each expanded source path, e.g. "$T3CODE_PROJECT_ROOT/.env".

Suggested change
"command": "vp i && ln -sf $T3CODE_PROJECT_ROOT/.env .env && ln -sf $T3CODE_PROJECT_ROOT/infra/relay/.env infra/relay/.env",
vp i && ln -sf "$T3CODE_PROJECT_ROOT/.env" .env && ln -sf "$T3CODE_PROJECT_ROOT/infra/relay/.env" infra/relay/.env
🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @t3.json around line 7:
The `Setup Worktree` command expands `$T3CODE_PROJECT_ROOT` without quotes in both `ln` source paths. If the project root contains spaces, shell word splitting passes multiple operands to `ln`, so the first link fails and, due to `&&`, neither `.env` link is created. Quote each expanded source path, e.g. `"$T3CODE_PROJECT_ROOT/.env"`.

return currentIndex < threadIds.length - 1 ? (threadIds[currentIndex + 1] ?? null) : null;
}

export function shouldNavigateAfterProjectRemoval(input: {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Mediumcomponents/Sidebar.logic.ts:381

shouldNavigateAfterProjectRemoval returns false for a server route whose thread was added to the project after the projectThreads snapshot was captured — for example, a thread synced while the delete confirmation is pending. After the project is actually removed, the UI stays on that route instead of navigating away, because the thread's environmentId/id match the current route but were not present in the stale snapshot. Consider computing project ownership from current thread state at call time (after the await), or retaining the removed project id and comparing it against the route's project rather than relying on the pre-removal thread list.

🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @apps/web/src/components/Sidebar.logic.ts around line 381:
`shouldNavigateAfterProjectRemoval` returns `false` for a server route whose thread was added to the project after the `projectThreads` snapshot was captured — for example, a thread synced while the delete confirmation is pending. After the project is actually removed, the UI stays on that route instead of navigating away, because the thread's `environmentId`/`id` match the current route but were not present in the stale snapshot. Consider computing project ownership from current thread state at call time (after the await), or retaining the removed project id and comparing it against the route's project rather than relying on the pre-removal thread list.

const api = readLocalApi();
if (!api) return;

const projectThreads = threads.filter(

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟠 Highcomponents/SidebarV2.tsx:854

handleRemoveProject filters threads (live shells only) to compute projectThreads, then shows the user a confirmation dialog saying exactly projectThreads.length thread histories will be deleted. But the deleteProject call passes force: true, which makes the server delete all threads in the project including archived ones. Archived threads are not in the live shell list, so the dialog undercounts: it says "delete its 1 thread" while the server actually deletes every archived history too. Consider counting archived threads for the project (or wording the confirmation to account for archived histories) so the dialog reflects what force: true actually removes.

🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @apps/web/src/components/SidebarV2.tsx around line 854:
`handleRemoveProject` filters `threads` (live shells only) to compute `projectThreads`, then shows the user a confirmation dialog saying exactly `projectThreads.length` thread histories will be deleted. But the `deleteProject` call passes `force: true`, which makes the server delete *all* threads in the project including archived ones. Archived threads are not in the live shell list, so the dialog undercounts: it says "delete its 1 thread" while the server actually deletes every archived history too. Consider counting archived threads for the project (or wording the confirmation to account for archived histories) so the dialog reflects what `force: true` actually removes.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@jetblk@maria-rcks@juliusmarminge@t3dotgg