Skip to content

Commit 244bd4f

Browse files
chore: merge main into terminal clipboard fix
Co-authored-by: Dara Adedeji <[email protected]>
2 parents aecd962 + 44df336 commit 244bd4f

198 files changed

Lines changed: 9780 additions & 1525 deletions

File tree

Some content is hidden

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

‎.github/workflows/web-preview.yml‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,8 @@ jobs:
8282
--archive=tgz \
8383
--yes \
8484
--token "$VERCEL_TOKEN" \
85-
--scope "$vercel_scope"
85+
--scope "$vercel_scope" \
86+
--build-env "VITE_RELEASE_CHANNEL=preview"
8687
)"
8788
printf '%s\n' "$deployment_output"
8889
# Vercel can print lockfile warnings to stdout before the deployment URL.

‎AGENTS.md‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ For authorized mobile verification, a missing or outdated native client is an in
139139
## Pull requests
140140

141141
- Never make a PR unless the developer explicitly asks you to do so.
142-
- If `origin` is git.cafe, follow [GitCafe mirror](docs/operations/development.md#gitcafe-mirror-optional): use `cafe` for existing PRs, issues, comments and labels, but push and open PRs on GitHub, where CI runs.
142+
- If `origin` is git.cafe, follow [GitCafe mirror](docs/operations/development.md#gitcafe-mirror-optional): push to `origin`, open and track PRs with `cafe` and their git.cafe URLs, and keep `gh` for CI logs and merging.
143143
- Conventional commit titles, plain language: `fix(web): new threads no longer spike CPU`.
144144
- Body: the problem in a sentence or two, then how you fixed it. End with the model and harness that did the work.
145145
- UI changes need before/after images. Motion or timing needs a short video.
@@ -194,6 +194,7 @@ Architecture and its constraints: `docs/internals/overview.md`. Glossary: `docs/
194194
options, and pass combinators as additional function-builder arguments.
195195
- Inferred types over annotations. `any` is the enemy.
196196
- Default to no comment. Write one only for a constraint, an external quirk, or an invariant the code can't show, in one line where you can and four at most. Don't restate names or signatures, narrate steps, record history, or explain the fix you just made; the PR carries that. `t3code/no-low-value-comments` enforces the length cap and the mechanical cases.
197+
- React effects are a last resort: derive in render, act in handlers, reset with `key`, or use a ref callback or store. The `t3code/react-effect-budget` lint rule holds each file to its entry in `scripts/effect-budget.json`; raise an entry only in the PR that needs the effect, and lower it when you remove one.
197198
- Our users drive agents all day and notice a dropped frame, a lying spinner, and a stale label. No continuously repainting animations; they peg the GPU on high-refresh displays.
198199
- If a rule here fights the task in front of you, say so loudly and get a human sign-off before breaking it.
199200

‎apps/desktop/src/app/DesktopObservability.test.ts‎

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -342,4 +342,36 @@ describe("DesktopObservability", () => {
342342
Effect.provide(Layer.mergeAll(NodeServices.layer, layerCollector(requests), layerEmptyEnv)),
343343
);
344344
});
345+
346+
it.effect("describes the Node runtime and the desktop mode under semantic or t3code keys", () => {
347+
const requests: Array<ExportedRequest> = [];
348+
return Effect.gen(function* () {
349+
const fileSystem = yield* FileSystem.FileSystem;
350+
const baseDir = yield* fileSystem.makeTempDirectoryScoped({
351+
prefix: "t3-desktop-observability-test-",
352+
});
353+
const layerEnvironment = layerEnvironmentFor(baseDir);
354+
yield* writeObservabilitySettings(layerEnvironment, {
355+
otlpLogsUrl: "https://settings.example.com/v1/logs",
356+
});
357+
358+
yield* Effect.scoped(
359+
Effect.logInfo("desktop resource under test").pipe(
360+
Effect.provide(DesktopObservability.layer.pipe(Layer.provideMerge(layerEnvironment))),
361+
),
362+
);
363+
364+
const body = requests.map((request) => request.body).join("\n");
365+
assert.include(body, '"key":"process.runtime.name","value":{"stringValue":"nodejs"}');
366+
assert.include(
367+
body,
368+
`"key":"process.runtime.version","value":{"stringValue":"${process.versions.node}"}`,
369+
);
370+
assert.include(body, '"key":"t3code.desktop.mode","value":{"stringValue":"development"}');
371+
assert.notInclude(body, "service.mode");
372+
}).pipe(
373+
Effect.scoped,
374+
Effect.provide(Layer.mergeAll(NodeServices.layer, layerCollector(requests), layerEmptyEnv)),
375+
);
376+
});
345377
});

‎apps/desktop/src/app/DesktopObservability.ts‎

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,14 @@ import { PRIMARY_LOCAL_ENVIRONMENT_ID } from "@t3tools/contracts";
22
import {
33
makeLocalFileTracer,
44
makeTraceSink,
5+
nodeProcessRuntimeAttributes,
6+
processServiceInstanceId,
57
type SignalExport,
68
} from "@t3tools/shared/observability";
79
import * as HostProcess from "@t3tools/shared/HostProcess";
810
import * as SharedObservability from "@t3tools/shared/observability";
911
import * as OtelEnvironment from "@t3tools/shared/otelEnvironment";
12+
import { releaseChannelOf, releaseResourceAttributes } from "@t3tools/shared/releaseResource";
1013
import {
1114
parsePersistedServerObservabilitySettings,
1215
type PersistedServerObservabilitySettings,
@@ -595,15 +598,24 @@ const layerTelemetry = Layer.unwrap(
595598
Effect.gen(function* () {
596599
const environment = yield* DesktopEnvironment.DesktopEnvironment;
597600
const endpoints = yield* resolveOtlpEndpoints;
601+
// Unpackaged runs launch a script, so Electron reports its own version.
602+
const serviceVersion = environment.isPackaged
603+
? environment.appVersion
604+
: desktopPackageJson.version;
598605
const resource = {
599606
serviceName: "t3code-desktop",
600-
// Unpackaged runs launch a script, so Electron reports its own version.
601-
serviceVersion: environment.isPackaged ? environment.appVersion : desktopPackageJson.version,
607+
serviceVersion,
602608
attributes: {
603609
"service.namespace": "t3code",
604610
"service.runtime": "desktop",
605-
"service.mode": environment.isDevelopment ? "development" : "packaged",
611+
"t3code.desktop.mode": environment.isDevelopment ? "development" : "packaged",
612+
"service.instance.id": processServiceInstanceId(endpoints.resourceAttributes),
613+
...releaseResourceAttributes(
614+
environment.isDevelopment ? "dev" : releaseChannelOf(serviceVersion),
615+
endpoints.resourceAttributes,
616+
),
606617
"host.name": endpoints.resourceAttributes["host.name"] || (yield* HostProcess.Hostname),
618+
...nodeProcessRuntimeAttributes(),
607619
},
608620
};
609621

‎apps/desktop/src/backend/DesktopBackendConfiguration.test.ts‎

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -678,7 +678,7 @@ describe("DesktopBackendConfiguration", () => {
678678
),
679679
);
680680

681-
it.effect("resolveWsl carries the kill switch into the distro", () =>
681+
it.effect("resolveWsl carries the kill switch and resource attributes into the distro", () =>
682682
Effect.gen(function* () {
683683
const fileSystem = yield* FileSystem.FileSystem;
684684
const baseDir = yield* fileSystem.makeTempDirectoryScoped({
@@ -688,10 +688,12 @@ describe("DesktopBackendConfiguration", () => {
688688
const previousWslEnv = process.env.WSLENV;
689689
const previousDisabled = process.env.OTEL_SDK_DISABLED;
690690
const previousTelemetry = process.env.T3CODE_TELEMETRY_ENABLED;
691+
const previousResourceAttributes = process.env.OTEL_RESOURCE_ATTRIBUTES;
691692
try {
692693
delete process.env.WSLENV;
693694
process.env.OTEL_SDK_DISABLED = "true";
694695
process.env.T3CODE_TELEMETRY_ENABLED = "false";
696+
process.env.OTEL_RESOURCE_ATTRIBUTES = "deployment.environment.name=staging";
695697

696698
yield* Effect.gen(function* () {
697699
const configuration = yield* DesktopBackendConfiguration.DesktopBackendConfiguration;
@@ -701,6 +703,8 @@ describe("DesktopBackendConfiguration", () => {
701703
assert.include((config.env.WSLENV ?? "").split(":"), "OTEL_SDK_DISABLED");
702704
assert.equal(config.env.T3CODE_TELEMETRY_ENABLED, "false");
703705
assert.include((config.env.WSLENV ?? "").split(":"), "T3CODE_TELEMETRY_ENABLED");
706+
assert.equal(config.env.OTEL_RESOURCE_ATTRIBUTES, "deployment.environment.name=staging");
707+
assert.include((config.env.WSLENV ?? "").split(":"), "OTEL_RESOURCE_ATTRIBUTES");
704708
}).pipe(
705709
Effect.provide(
706710
layerBackendConfiguration().pipe(
@@ -722,6 +726,7 @@ describe("DesktopBackendConfiguration", () => {
722726
restoreEnv("WSLENV", previousWslEnv);
723727
restoreEnv("OTEL_SDK_DISABLED", previousDisabled);
724728
restoreEnv("T3CODE_TELEMETRY_ENABLED", previousTelemetry);
729+
restoreEnv("OTEL_RESOURCE_ATTRIBUTES", previousResourceAttributes);
725730
}
726731
}).pipe(Effect.scoped, Effect.provide(NodeServices.layer)),
727732
);

‎apps/desktop/src/backend/DesktopBackendConfiguration.ts‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ const WSL_FORWARDED_ENV_NAMES = [
110110
"OTEL_TRACES_EXPORTER",
111111
"OTEL_METRICS_EXPORTER",
112112
"OTEL_LOGS_EXPORTER",
113+
"OTEL_RESOURCE_ATTRIBUTES",
113114
] as const;
114115

115116
const WSL_SERVER_SYSTEM_PATH = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin";

‎apps/mobile/package.json‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@
129129
"react-native-enriched-markdown": "file:deps/react-native-enriched-markdown-1.2.0-t3.16-558767d9.tgz",
130130
"react-native-gesture-handler": "~3.3.0",
131131
"react-native-image-viewing": "^0.2.2",
132-
"react-native-keyboard-controller": "1.22.7",
132+
"react-native-keyboard-controller": "1.22.8",
133133
"react-native-nitro-modules": "0.37.1",
134134
"react-native-pdf-jsi": "5.0.0",
135135
"react-native-reanimated": "4.7.1",

‎apps/mobile/src/Stack.tsx‎

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,10 @@ import { ThreadPullRequestsSheet } from "./features/threads/ThreadPullRequestsSh
6565
import { ThreadAgentsSheet } from "./features/threads/ThreadAgentsSheet";
6666
import { ThreadBackgroundWorkSheet } from "./features/threads/ThreadBackgroundWorkSheet";
6767
import { ThreadQueueSheet } from "./features/threads/ThreadQueueControl";
68-
import { ThreadRouteScreen } from "./features/threads/ThreadRouteScreen";
68+
import {
69+
FullscreenThreadRouteScreen,
70+
ThreadRouteScreen,
71+
} from "./features/threads/ThreadRouteScreen";
6972
import { McpAppFullscreenScreen } from "./features/threads/McpAppFullscreenScreen";
7073
import { ConnectionsRouteScreen } from "./features/connection/ConnectionsRouteScreen";
7174
import { ConnectionsNewRouteScreen } from "./features/connection/ConnectionsNewRouteScreen";
@@ -813,6 +816,13 @@ const RootStackConfig = createWorkspaceStackNavigator({
813816
linking: `${THREAD_LINKING_PREFIX}/terminal`,
814817
options: SOLID_HEADER_OPTIONS,
815818
}),
819+
ThreadInspectorFullscreen: createNativeStackScreen({
820+
screen: FullscreenThreadRouteScreen,
821+
options: {
822+
...THREAD_HEADER_OPTIONS,
823+
presentation: "fullScreenModal",
824+
},
825+
}),
816826
ThreadDevicePreview: createNativeStackScreen({
817827
screen: DevicePreviewRouteScreen,
818828
linking: `${THREAD_LINKING_PREFIX}/devices`,

‎apps/mobile/src/components/ui/Toast.tsx‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ function ToastContent(props: ToastProps & { readonly glassReady?: boolean }) {
9393
</AppText>
9494
) : null}
9595
</View>
96-
{inlineAction ? action : null}
96+
{inlineAction && action ? <View className="self-center">{action}</View> : null}
9797
{props.onDismiss && props.dismissMode !== "swipe" ? (
9898
<IconButton accessibilityLabel="Dismiss message" icon="xmark" onPress={props.onDismiss} />
9999
) : null}

0 commit comments

Comments
 (0)