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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion examples/t3-code/app.contract
Original file line number Diff line number Diff line change
Expand Up @@ -1697,7 +1697,7 @@ component T3Code
taskModelPick = ""
if (op != "toggle" or not detailsPopover) and op != "dismiss" and op != "ui:project-settings" and op != "ui:add-script" and op != "ui:scheduled-tasks" and not commandPending
commandPending = true
send changed = command(op == "toggle" ? "shelllocal:details-inline" : op == "ui:changes" ? "diff" : op == "ui:editor" ? "shell:open-editor" : op, target, value, 0)
send changed = command(op == "toggle" ? "shelllocal:details-inline" : op == "ui:changes" ? "diff" : op == "ui:editor" ? "shell:select-editor" : op, target, value, 0)
if op == "select-thread" or op == "shell:merge-back"
draftOwner = "__unset__"
jumpRequest = jumpRequest + 1
Expand Down
9 changes: 9 additions & 0 deletions examples/t3-code/macos/src/contract_keys_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,14 @@ fn host() -> exact_apple::Host<Replies> {
] {
set(&plan, row_type, &mut row, &[name], value);
}
let (group_type, mut group) = element(&plan, "bindings", &["groups"]);
for (name, value) in [
("id", Value::str("chat")),
("title", Value::str("Chat")),
("rows", Value::list(vec![row.clone()])),
] {
set(&plan, group_type, &mut group, &[name], value);
}
replies.fixture(
&plan,
"bindings",
Expand All @@ -140,6 +148,7 @@ fn host() -> exact_apple::Host<Replies> {
(&["writable"], Value::Bool(true)),
(&["draftValid"], Value::Bool(true)),
(&["rows"], Value::list(vec![row])),
(&["groups"], Value::list(vec![group])),
],
);
let measurer = CallbackMeasurer::new(measure, std::ptr::null_mut(), None);
Expand Down
2 changes: 1 addition & 1 deletion examples/t3-code/macos/tests/real-key-chords/main.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import XCTest
/// The reference's ⌘ chords (packages/shared/src/keybindings.ts DEFAULT_KEYBINDINGS; keybindingDefaults) whose
/// `when` holds in an open thread with nothing focused or the composer focused, the composer's own send chords
/// (`composerFocus && …`) aside. search-key-and-timeline-commit-title.test.ts checks this list against them.
let referenceChords = ["mod+b", "mod+[", "mod+]", "mod+j", "mod+alt+b", "mod+w", "mod+d", "mod+shift+j", "mod+k", "mod+p",
let referenceChords = ["mod+b", "mod+[", "mod+]", "mod+j", "mod+alt+b", "mod+shift+b", "mod+w", "mod+d", "mod+shift+j", "mod+k", "mod+p",
"mod+shift+f", "mod+u", "mod+alt+a", "mod+alt+shift+a", "mod+alt+shift+t", "mod+s", "mod+shift+enter",
"mod+n", "mod+shift+o", "mod+shift+n", "mod+alt+n", "mod+shift+m", "mod+shift+h", "mod+shift+e",
"mod+shift+a", "mod+shift+x", "mod+shift+g", "mod+shift+l", "mod+shift+k", "mod+o", "mod+shift+[",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ shape Look
accent: string
accentText: string
message: string
wizardSteps: string
wizardPanel: string
chatMax: number
artwork: bool
pill: string
Expand Down
9 changes: 7 additions & 2 deletions examples/t3-code/src/appearance/settings-appearance-look.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
// palette's light-dark() tokens.
import type { T3Client } from '../client/client';
import { CLIENT_DEFAULTS, decodeClientPrefs, type ClientPrefs } from '../settings/settings-core';
import { effectiveMode, fontStack, palette, themeRoles } from './settings-appearance';
import { alpha, effectiveMode, fontStack, palette, themeRoles } from './settings-appearance';
import type { CustomTheme } from './settings-themes';
import type { DiffState } from '../diff/diff';
import { STANDARD, previewTheme } from './settings-appearance-editor';
Expand All @@ -18,6 +18,8 @@ export type Look = {
themed: boolean; mode: string;
canvas: string; sidebar: string; sidebarBorder: string; sidebarText: string; sidebarMuted: string; rowActive: string;
surface: string; popover: string; border: string; input: string; text: string; muted: string; accent: string; accentText: string; message: string;
/** ui/wizard.tsx: WizardSteps' bg-background (dark:bg-white/4) and WizardPanel's bg-background/80 (dark:bg-white/2). */
wizardSteps: string; wizardPanel: string;
chatMax: number; artwork: boolean; pill: string; diff: string;
diffAdd: string; diffDel: string; diffAddSurface: string; diffDelSurface: string; diffAddLine: string; diffDelLine: string;
terminalLight: string; terminalDark: string; terminalFont: string; terminalSize: number;
Expand Down Expand Up @@ -63,13 +65,16 @@ export function look(client: T3Client): Look {
const diff = DIFF[prefs.diffColorScheme === 'blue-orange' ? 'blue-orange' : 'red-green'];
// applyAppearanceFontVariables: the root font size (app.contract `rootFont` sets it), 16 until the preferences load.
const rootFontSize = clampInterfaceFontSize(prefs.fontSizeInterface);
// Light mode paints the theme's background; dark mode a white wash whatever the theme.
const background = themed ? palette(prefs, custom, 'light').canvas : '#fcfcfc';
const half = (light: string, dark: string) => mode === 'light' ? light : mode === 'dark' ? dark : `light-dark(${light}, ${dark})`;
return {
themed, mode,
terminalLight: terminalTheme(prefs.themeLight, 'light', custom), terminalDark: terminalTheme(prefs.themeDark, 'dark', custom),
terminalFont: prefs.typographyAdvanced ? prefs.fontFamilyTerminal : prefs.fontFamilyCode,
terminalSize: prefs.typographyAdvanced ? prefs.fontSizeTerminal : prefs.fontSizeCode,
canvas: pal.canvas, sidebar: pal.sidebar, sidebarBorder: pal.sidebarBorder, sidebarText: pal.sidebarText, sidebarMuted: pal.sidebarMuted, rowActive: pal.rowActive,
message: messageSurface(prefs, custom, mode), surface: pal.surface, popover: pal.popover, border: pal.border, input: pal.input, text: pal.text, muted: pal.muted, accent: pal.accent, accentText: pal.accentText,
message: messageSurface(prefs, custom, mode), wizardSteps: half(background, '#ffffff0a'), wizardPanel: half(alpha(background, 0.8), '#ffffff05'), surface: pal.surface, popover: pal.popover, border: pal.border, input: pal.input, text: pal.text, muted: pal.muted, accent: pal.accent, accentText: pal.accentText,
diff: prefs.diffColorScheme === 'blue-orange' ? 'blue-orange' : 'red-green', chatMax: chatMaxWidth(prefs.chatWidth, rootFontSize), artwork: prefs.environmentIdentificationMode === 'artwork', pill: prefs.environmentIdentificationMode === 'pill' ? 'Nightly' : '',
diffAdd: diff.add, diffDel: diff.del, diffAddSurface: diff.addSurface, diffDelSurface: diff.delSurface, diffAddLine: diff.addLine, diffDelLine: diff.delLine,
fontSans: fontStack(prefs.fontFamilySans, false) ?? 'system-ui', fontSize: rootFontSize, promptSize: clampPromptFontSize(prefs.fontSizePrompt), promptFont: fontStack(prefs.fontFamilyComposer.trim() ? prefs.fontFamilyComposer : prefs.fontFamilySans, false), codeFont: fontStack(prefs.fontFamilyCode, true) ?? 'ui-monospace',
Expand Down
5 changes: 4 additions & 1 deletion examples/t3-code/src/connections/connections.contract
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ shape SavedEnvironment
switchTip: string
active: bool
traceId: string
mcpUrl: string
update: string
updateVersion: string
// ServerUpdateAction: a desktop-managed server without remote app updates shows this sentence, no button.
Expand Down Expand Up @@ -312,7 +313,7 @@ component EnvironmentRow
routesOpen = not routesOpen
if closing and routeKeyboard.environmentId == environment.environmentId
routeKeyboardInput(environment.environmentId, environment.key, routeKeyboard.routeId, "cancel", false)
derive menuItems = [KmItem(id=`environment-icon-${environment.environmentId}`, label="Icon"), KmItem(id=(busy ? "" : `environment-routes-item-${environment.environmentId}`), label=(routesOpen ? "Hide routes" : "Routes")), KmItem(id=(busy or environment.traceId == "" ? "" : `environment-trace-${environment.environmentId}`), label="Copy trace ID"), KmItem(id=(busy ? "" : (environment.active ? "forget-server" : `environment-remove-${environment.environmentId}`)), label="Remove from this device…")].filter((item) => item.id != "")
derive menuItems = [KmItem(id=`environment-icon-${environment.environmentId}`, label="Icon"), KmItem(id=(busy ? "" : `environment-routes-item-${environment.environmentId}`), label=(routesOpen ? "Hide routes" : "Routes")), KmItem(id=(busy or environment.mcpUrl == "" ? "" : `environment-mcp-${environment.environmentId}`), label="Copy MCP URL"), KmItem(id=(busy or environment.traceId == "" ? "" : `environment-trace-${environment.environmentId}`), label="Copy trace ID"), KmItem(id=(busy ? "" : (environment.active ? "forget-server" : `environment-remove-${environment.environmentId}`)), label="Remove from this device…")].filter((item) => item.id != "")
action triggerKey(k: string, e: KeyboardEvent)
if not e.metaKey and not e.ctrlKey and not e.altKey and not e.shiftKey and kmTriggerKey(k)
preventDefault()
Expand Down Expand Up @@ -369,6 +370,8 @@ component EnvironmentRow
CnMenu(menuId=`environment-menu-${environment.environmentId}-popup`, invoker=`environment-menu-${environment.environmentId}`, label=`More actions for ${environment.label}`, width=196, area="bottom span-left", items=menuItems, keyed=0)
EnvironmentIconMenu(keysId=`environment-menu-${environment.environmentId}-popup-keys`, environment=environment, op=op)
RouteMenuItem(keysId=`environment-menu-${environment.environmentId}-popup-keys`, label=(routesOpen ? "Hide routes" : "Routes"), menuId=`environment-menu-${environment.environmentId}-popup`, itemId=`environment-routes-item-${environment.environmentId}`, disabled=busy, choose=toggleRoutes)
if environment.mcpUrl != ""
CnMenuItem(keysId=`environment-menu-${environment.environmentId}-popup-keys`, label="Copy MCP URL", menuId=`environment-menu-${environment.environmentId}-popup`, itemId=`environment-mcp-${environment.environmentId}`, destructive=false, disabled=busy, radio=false, highlighted=false, note="", icon="", submenu="", choose=op("environment-mcp", environment.key, environment.mcpUrl))
if environment.traceId != ""
CnMenuItem(keysId=`environment-menu-${environment.environmentId}-popup-keys`, label="Copy trace ID", menuId=`environment-menu-${environment.environmentId}-popup`, itemId=`environment-trace-${environment.environmentId}`, destructive=false, disabled=busy, radio=false, highlighted=false, note="", icon="", submenu="", choose=op("environment-trace", environment.key, environment.traceId))
CnSeparator()
Expand Down
24 changes: 22 additions & 2 deletions examples/t3-code/src/connections/connections.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import { CLIENT_VERSION, versionMismatch } from './version-skew';
import { nativeUpdateDeps, updateEnvironment, updateTargetFromConfig } from './server-update';
import { confirms } from './server-update-notices';
import { configInstallation, desktopManagedOnly, manualUpdateCopy, serverUpdateActionLabel, DESKTOP_MANAGED_NOTE } from './server-installation';
import { gitHubRoutingConnectionKey, savedRoutes, singleRouteKey, type ConnectionRoute } from './connection-routes';
import { gitHubRoutingConnectionKey, routeHttpBaseUrl, savedRoutes, singleRouteKey, type ConnectionRoute } from './connection-routes';
import { moveSavedRoute, placeRoute, removeSavedRoute, routeCountLabel, routeRows, routesTransportLabel, savedEntry, savedList } from './connection-routes-ops';
import { letGo } from '../client/let-go';

Expand Down Expand Up @@ -165,6 +165,17 @@ const sourceTransport = (source: Source, ssh: Record<string, SshTarget>) =>
/** The icon menu's row while there is no primary (the shape is fixed; the menu is not shown). */
const PLACEHOLDER: Source = { key: '', origin: '', environmentId: '', label: 'This machine', machine: 'desktop', enabled: false, phase: 'available', error: '', traceId: '',
config: {}, scopes: [], focused: false, routes: [], activeRouteId: '', primary: true };
/** T3 9c161462c9 presentation.ts environmentMcpUrl: prefer the connected route, then saved routes; SSH has no stable address. */
export function environmentMcpUrl(source: Pick<Source, 'routes' | 'activeRouteId' | 'phase' | 'origin'>, ssh: Record<string, SshTarget> = {}): string {
const routes = source.routes.length ? source.routes : [{ id: source.origin, origin: source.origin, kind: ssh[trimOrigin(source.origin)] ? 'ssh' : '' }];
const connected = source.phase === 'connected' ? routes.find(route => route.id === source.activeRouteId) : undefined;
for (const route of connected ? [connected, ...routes] : routes) {
const base = routeHttpBaseUrl(route);
if (base === null) continue;
try { const url = new URL(base); url.pathname = '/mcp'; url.search = ''; url.hash = ''; return url.toString(); } catch { /* Try the next route. */ }
}
return '';
}
/** One Environments row's projection (and the This machine icon menu's). */
export type SavedRowView = ReturnType<typeof savedRow>;
export const placeholderRow = (): SavedRowView => savedRow(PLACEHOLDER, 0);
Expand Down Expand Up @@ -192,7 +203,7 @@ export function savedRow(source: Source, index: number, ssh: Record<string, SshT
key: source.key, first: index === 0, origin: source.origin, environmentId: source.environmentId, label: source.label, kind,
subtitle, tooltip, errorTone: enabled && status.tone === 'error' && !outdated.resuming, enabled, dimmed: !enabled, unsupported,
outdatedAction: outdated.action, outdatedFrom: outdated.fromVersion, progress: outdated.progress, progressFailed: outdated.failure,
switchTip: unsupported ? 'Client not supported' : enabled ? 'Switch off' : 'Switch on', active: source.focused, traceId: source.traceId,
switchTip: unsupported ? 'Client not supported' : enabled ? 'Switch off' : 'Switch on', active: source.focused, traceId: source.traceId, mcpUrl: environmentMcpUrl(source, ssh),
// ServerUpdateAction (3b0093d716): the manual label follows the install; a desktop app that cannot
// update from here gets the sentence instead of a button.
update: updateLabel,
Expand Down Expand Up @@ -451,6 +462,15 @@ export async function runConnectionOp(native: Native, op: string, id: string, va
return { status: obj(reply.value), generation: reply.generation };
} catch (error) { failed(client, 'Could not remove backend', error); throw error; }
}
if (op === 'environment-mcp') {
try {
const url = new URL(value);
if (!['http:', 'https:'].includes(url.protocol) || url.pathname !== '/mcp') throw new ClientError('That MCP URL is unavailable.');
await call(native, { op: 'copyText', text: url.toString() });
if (client) pushToast(client, { kind: 'success', title: 'MCP URL copied', description: `Add it to an agent, e.g. claude mcp add --transport http t3 ${url}` });
} catch (error) { failed(client, 'Could not copy MCP URL', error); throw error; }
return { status: null, generation: -1 };
}
if (op === 'environment-trace') {
// "Copy trace ID" (useCopyToClipboard): value is the trace from the row.
try {
Expand Down
6 changes: 4 additions & 2 deletions examples/t3-code/src/details/git-publish.contract
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ component GitProviderMark
component PublishDialog
inject
linkOpen: action
wizardPanel: string
wizardSteps: string
props
git: GitCard
cwd: string
Expand All @@ -49,12 +51,12 @@ component PublishDialog
column gap="0.5rem" padding-left="1.5rem" padding-right="1.5rem" padding-top="1.5rem" padding-bottom="0.75rem" box-sizing="border-box"
text "Publish repository" font-size="1.25rem" font-weight=600 line-height="1.25rem" color="light-dark(#27272a, #f5f5f5)" role="heading" aria-level=2
text "Pick where to host it, then point us at a repo to push to." font-size="0.875rem" line-height="1.25rem" color="light-dark(#71717b, #818181)"
row gap="0.25rem" padding="0.25rem" box-sizing="border-box" border-radius="0.75rem" border-width=1 border-style="solid" border-color="light-dark(#0000000d, #ffffff0d)" background-color="light-dark(#fcfcfc, #ffffff0a)" role="list" aria-label="Setup progress"
row gap="0.25rem" padding="0.25rem" box-sizing="border-box" border-radius="0.75rem" border-width=1 border-style="solid" border-color="light-dark(#0000000d, #ffffff0d)" background-color=wizardSteps role="list" aria-label="Setup progress"
PublishStep(index=0, label="Provider", summary=git.publishProviderLabel, current=git.publishStep, local=local)
PublishStep(index=1, label="Repository", summary=git.publishName, current=git.publishStep, local=local)
PublishStep(index=2, label="Summary", summary="", current=git.publishStep, local=local)
// WizardPanel: a band with hairlines, px-6 py-5, space-y-4.
column gap="1rem" padding-left="1.5rem" padding-right="1.5rem" padding-top="1.25rem" padding-bottom="1.25rem" box-sizing="border-box" border-top-width=1 border-bottom-width=1 border-style="solid" border-color="light-dark(#0000000d, #ffffff0d)" background-color="light-dark(#fcfcfccc, #ffffff05)"
column gap="1rem" padding-left="1.5rem" padding-right="1.5rem" padding-top="1.25rem" padding-bottom="1.25rem" box-sizing="border-box" border-top-width=1 border-bottom-width=1 border-style="solid" border-color="light-dark(#0000000d, #ffffff0d)" background-color=wizardPanel
if git.publishStep == 0
column gap="0.5rem"
text "Provider" font-size="0.75rem" font-weight=500 line-height="1rem" color="light-dark(#27272a, #f5f5f5)"
Expand Down
4 changes: 3 additions & 1 deletion examples/t3-code/src/device/settings-a-hosts.contract
Original file line number Diff line number Diff line change
Expand Up @@ -160,8 +160,10 @@ component HostRowView
text host.label font-size="0.875rem" font-weight=500 line-height="1.25rem" line-clamp=1 color="light-dark(#27272a, #f5f5f5)"
for platform in host.platforms key=platform.id
box aria-label=platform.label role="img" flex-shrink=0
// The Apple mark is bottom-heavy; lifted 1pt so it does not dip under the label.
if platform.id == "ios"
AppleGlyph(size=14, color="light-dark(#71717b, #818181)")
box position="relative" top=-1
AppleGlyph(size=14, color="light-dark(#71717b, #818181)")
else
AndroidGlyph(size=14, color="light-dark(#71717b, #818181)")
text host.target font-size="0.75rem" line-height="1rem" line-clamp=1 color="light-dark(#71717b, #818181)"
Expand Down
Loading