Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
b2b43be
fix(server): preserve racy edits in review diff previews (#12613)
tris203 Sep 24, 2026
cb1a3f3
fix(web): show repository names on linked pull requests (#13061)
Bil0000 Sep 24, 2026
80fc23a
lint/unknown and static (#13366)
juliusmarminge Sep 24, 2026
315fcca
fix(web): web colors come from theme tokens (#13371)
juliusmarminge Sep 24, 2026
f26ee08
fix(web): appearance classes use theme tokens and scale values (#13397)
juliusmarminge Sep 24, 2026
ffb5fcc
fix(server): keep Codex's reset answer when the re-probe fails (#13363)
juliusmarminge Sep 24, 2026
84c436b
fix(mobile): branch search finds remote and space-typed branches (#13…
Bil0000 Sep 24, 2026
7cfb498
chore(ci): use GPT 6 Sol Max for check agents (#13473)
juliusmarminge Sep 24, 2026
3412097
feat(server): show and redeem Claude banked resets (#13118)
Bil0000 Sep 24, 2026
87d8428
fix(observability): a malformed OTEL_RESOURCE_ATTRIBUTES no longer st…
yordis Sep 24, 2026
cdb26fe
fix(antigravity): let Stop end commands that outlived their turn (#13…
juliusmarminge Sep 24, 2026
f61f979
fix(web,mobile): drop the baked-in tile from the Antigravity icon (#1…
flamboh Sep 24, 2026
53456bc
fix(marketing): use the official OpenCode and Antigravity logos (#13365)
flamboh Sep 24, 2026
e759847
fix(acp): keep one answer when a running tool reports progress (#13386)
juliusmarminge Sep 24, 2026
66129c6
feat(web): run shell commands from chat in the thread terminal (#13060)
Bil0000 Sep 24, 2026
f3cb2a1
fix(antigravity): keep Windows runtime unpacking under MAX_PATH (#13389)
juliusmarminge Sep 24, 2026
567783e
fix(codex): the protocol generator runs again on Effect rc.115 (#13480)
juliusmarminge Sep 24, 2026
d5d4874
feat(codex): require Codex 0.156 and regenerate its protocol (#13481)
juliusmarminge Sep 24, 2026
0109670
feat(threads): add per-thread auto-settle switch (#11846)
t3dotgg Sep 24, 2026
8251c8d
fix(web): working and monitoring threads fade in the sidebar again (#…
t3dotgg Sep 24, 2026
a36af06
fix(server): streamed section titles wait for the text under them (#1…
t3dotgg Sep 24, 2026
720490a
fix(web): normalize disabled control opacity (#11441)
t3-code[bot] Sep 24, 2026
9a91177
fix(web): sidebar Back always returns to the main app (#13516)
t3dotgg Sep 24, 2026
d4a3345
fix(desktop): desktop updates reconnect in seconds, not minutes (#12006)
t3dotgg Sep 24, 2026
8d7b5e9
fix(connect): remove tunnels after hosts go offline (#9386)
t3dotgg Sep 25, 2026
9c524d5
fix(mobile): capture a lit 6.9-inch lock screen in the agent-activity…
juliusmarminge Sep 25, 2026
72447f2
feat(grok): offer one-click updates through `grok update` (#13523)
juliusmarminge Sep 25, 2026
59abcd6
fix(mobile): make Android subscription usage widgets scrollable (#13474)
tris203 Sep 25, 2026
fd46510
fix(web): keep sidebar terminal pulses in sync (#12962)
t3dotgg Sep 25, 2026
46f3c2c
feat(web): add iPhone Duo 3D controls (#12813)
juliusmarminge Sep 25, 2026
d23eab1
fix(relay): export tunnel cleanup counters to Axiom (#13528)
juliusmarminge Sep 25, 2026
0cab7d5
fix(server): Grok accounts with no usage yet no longer vanish from Li…
jakeleventhal Sep 25, 2026
91e53e5
fix(server): report the Grok account email so usage limits merge acro…
jakeleventhal Sep 25, 2026
3e2370f
feat(web): add usage page keybinding (#9434)
jakeleventhal Sep 25, 2026
568c9bc
chore: clear Effect language service suggestions (#13536)
juliusmarminge Sep 25, 2026
fc46b8c
ci(relay): add a forced manual relay deploy (#13550)
juliusmarminge Sep 25, 2026
ebdcda1
fix(web): selected text stays visible on a revealed file line (#13548)
t3dotgg Sep 25, 2026
29abbf9
fix(web): collapsed composer bar stops flipping its labels while you …
t3dotgg Sep 25, 2026
ab70c89
fix(clients): sync status no longer flickers when opening running thr…
t3dotgg Sep 25, 2026
6391be2
fix(server): newer Codex models get T3 Code's instructions again (#13…
t3dotgg Sep 25, 2026
9957349
feat(web): control Android foldables in the Device panel (#13534)
juliusmarminge Sep 25, 2026
4f27a84
fix(mcp): preview snapshots fit in the agent's tool output again (#13…
t3dotgg Sep 25, 2026
0c84b42
fix(web): paste after clicking away from the composer lands in it aga…
t3dotgg Sep 25, 2026
99641fd
feat(desktop): keep running threads synced in the background (#13554)
t3dotgg Sep 25, 2026
1e192b2
fix(mcp): preview errors tell agents what to do instead (#13559)
t3dotgg Sep 25, 2026
df9826f
feat(web): agents working banner links to the Agents panel (#13572)
t3dotgg Sep 25, 2026
7b84431
fix(web): size the Android fold model from the inner display (#13574)
juliusmarminge Sep 25, 2026
a107f8a
fix(clients): a preview app no longer knocks the desktop's own server…
t3dotgg Sep 25, 2026
20f0ff1
fix(web): keep nested task states out of parent bullets (#11477)
dominic-r Sep 25, 2026
c13f7d9
feat(release): ship a Linux .deb that updates itself (#13575)
t3dotgg Sep 25, 2026
52b89d3
fix(server): reclaim leftover Antigravity _MEI temp dirs
macodev00 Sep 25, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
14 changes: 13 additions & 1 deletion .github/workflows/deploy-relay.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,15 @@ on:
push:
branches:
- main
# Alchemy does not redeploy the Worker when only a Config value read in its
# Init changes (alchemy-run/alchemy#1831), so a changed repository variable
# needs a forced deploy to reach production.
workflow_dispatch:
inputs:
force:
description: Redeploy every resource, including ones with no detected changes
type: boolean
default: true

permissions:
contents: read
Expand All @@ -17,6 +26,8 @@ concurrency:
jobs:
deploy_relay:
name: Deploy production relay
# A manual run from another branch would deploy that branch to production.
if: github.ref == 'refs/heads/main'
runs-on: blacksmith-8vcpu-ubuntu-2404
timeout-minutes: 15
environment:
Expand All @@ -28,6 +39,7 @@ jobs:
RELAY_DOMAIN: ${{ vars.RELAY_DOMAIN }}
RELAY_API_ZONE_NAME: ${{ vars.RELAY_API_ZONE_NAME }}
RELAY_TUNNEL_ZONE_NAME: ${{ vars.RELAY_TUNNEL_ZONE_NAME }}
RELAY_TUNNEL_CLEANUP_MODE: ${{ vars.RELAY_TUNNEL_CLEANUP_MODE }}
CLERK_PUBLISHABLE_KEY: ${{ vars.CLERK_PUBLISHABLE_KEY }}
CLERK_JWT_AUDIENCE: ${{ vars.CLERK_JWT_AUDIENCE }}
APNS_ENVIRONMENT: ${{ vars.APNS_ENVIRONMENT }}
Expand All @@ -54,7 +66,7 @@ jobs:
- --filter=t3code-relay...

- name: Deploy production relay stage
run: vp run --filter t3code-relay deploy --stage prod --yes --no-input
run: vp run --filter t3code-relay deploy --stage prod --yes --no-input ${{ inputs.force && '--force' || '' }}
env:
# The PublishClientConfig action writes the client env here instead
# of the repo-root .env; nothing on the runner reads it.
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/release-desktop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -510,6 +510,7 @@ jobs:
"release/*.dmg"
"release/*.zip"
"release/*.AppImage"
"release/*.deb"
"release/*.exe"
)
# Preview builds have no publish config, so electron-builder writes
Expand Down
3 changes: 2 additions & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -625,7 +625,7 @@ jobs:
clerk_cli_oauth_client_id: ${{ needs.relay_public_config.outputs.clerk_cli_oauth_client_id }}
relay_url: ${{ needs.relay_public_config.outputs.relay_url }}
label: Linux arm64
runner: ubuntu-24.04-arm
runner: blacksmith-16vcpu-ubuntu-2404-arm
platform: linux
target: AppImage
arch: arm64
Expand Down Expand Up @@ -875,6 +875,7 @@ jobs:
echo 'release-assets/*.dmg'
echo 'release-assets/*.zip'
echo 'release-assets/*.AppImage'
echo 'release-assets/*.deb'
echo 'release-assets/*.exe'
if [[ "${{ needs.preflight.outputs.release_channel }}" != "preview" ]]; then
echo 'release-assets/*.blockmap'
Expand Down
4 changes: 2 additions & 2 deletions .macroscope/check-run-agents/effect-service-conventions.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
title: Effect Service Conventions
model: gpt-5-6-sol
effort: medium
model: gpt-6-sol
effort: max
input: incremental
tools:
- browse_code
Expand Down
4 changes: 2 additions & 2 deletions .macroscope/check-run-agents/ui-consistency.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
title: UI Consistency
model: gpt-5-6-sol
effort: medium
model: gpt-6-sol
effort: max
input: incremental
tools:
- browse_code
Expand Down
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,14 @@ winget install T3Tools.T3Code
brew install --cask t3-code
```

#### Debian, Ubuntu (`.deb`)

Download the `.deb` from [GitHub Releases](https://github.com/pingdotgg/t3code/releases), then:

```bash
sudo apt install ./T3-Code-*.deb
```

#### Arch Linux (AUR)

Stable:
Expand Down
2 changes: 1 addition & 1 deletion apps/desktop/src/app/DesktopAppIdentity.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ const makeAssetsLayer = (png: Option.Option<string>) =>
icns: Option.none(),
png,
}),
resolveResourcePath: () => Effect.succeed(Option.none()),
resolveResourcePath: () => Effect.succeedNone,
} satisfies DesktopAssets.DesktopAssets["Service"]);

const makeEnvironmentLayer = (overrides: TestEnvironmentInput = {}) => {
Expand Down
2 changes: 1 addition & 1 deletion apps/desktop/src/app/DesktopConnectionCatalogStore.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ function makeSafeStorageLayer(available: boolean, failDecrypt: Ref.Ref<boolean>
return decoded.slice("encrypted:".length);
});
},
selectedStorageBackend: Effect.succeed(Option.none()),
selectedStorageBackend: Effect.succeedNone,
} satisfies ElectronSafeStorage.ElectronSafeStorage["Service"]);
}

Expand Down
2 changes: 1 addition & 1 deletion apps/desktop/src/app/DesktopConnectionCatalogStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ const readDocument = (
raw === null
? Effect.succeed(Option.none<EncryptedConnectionCatalogDocument>())
: decodeEncryptedConnectionCatalogDocumentJson(raw).pipe(
Effect.map(Option.some),
Effect.asSome,
Effect.mapError(
(cause) =>
new DesktopConnectionCatalogStoreDocumentDecodeError({
Expand Down
14 changes: 12 additions & 2 deletions apps/desktop/src/app/DesktopObservability.ts
Original file line number Diff line number Diff line change
Expand Up @@ -356,7 +356,13 @@ const readPersistedObservabilitySettings: Effect.Effect<
const resolveOtlpEndpoints = Effect.gen(function* () {
const otel = yield* OtelEnvironment.load;
if (otel.disabled) {
return { traces: undefined, metrics: undefined, logs: undefined, warnings: otel.warnings };
return {
traces: undefined,
metrics: undefined,
logs: undefined,
warnings: otel.warnings,
resourceAttributes: otel.resourceAttributes,
};
}

const environment = yield* DesktopEnvironment.DesktopEnvironment;
Expand All @@ -366,6 +372,7 @@ const resolveOtlpEndpoints = Effect.gen(function* () {
metrics: Option.getOrUndefined(environment.otlpMetricsUrl) ?? persisted.otlpMetricsUrl,
logs: Option.getOrUndefined(environment.otlpLogsUrl) ?? persisted.otlpLogsUrl,
warnings: otel.warnings,
resourceAttributes: otel.resourceAttributes,
};
});

Expand Down Expand Up @@ -683,7 +690,10 @@ const telemetryLayer = Layer.unwrap(
Effect.forEach(endpoints.warnings, (warning) => Effect.logWarning(warning)),
);

return otelWarningsLayer.pipe(Layer.provideMerge(Layer.mergeAll(loggerLayer, tracerLayer)));
return otelWarningsLayer.pipe(
Layer.provideMerge(Layer.mergeAll(loggerLayer, tracerLayer)),
Layer.provide(OtelEnvironment.layerResourceAttributes(endpoints.resourceAttributes)),
);
}),
);

Expand Down
4 changes: 2 additions & 2 deletions apps/desktop/src/backend/DesktopBackendConfiguration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -199,11 +199,11 @@ const readPersistedBackendObservabilitySettings = Effect.gen(function* () {
const fileSystem = yield* FileSystem.FileSystem;
const environment = yield* DesktopEnvironment.DesktopEnvironment;
const raw = yield* fileSystem.readFileString(environment.serverSettingsPath).pipe(
Effect.map(Option.some),
Effect.asSome,
Effect.catchTags({
PlatformError: (cause) =>
cause.reason._tag === "NotFound"
? Effect.succeed(Option.none())
? Effect.succeedNone
: logBackendObservabilitySettingsReadFailure(environment.serverSettingsPath, cause).pipe(
Effect.as(Option.none()),
),
Expand Down
4 changes: 2 additions & 2 deletions apps/desktop/src/backend/DesktopBackendManager.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ function makeTestInstance(input: MakeInstanceInput) {
forInstance: () => Effect.succeed(stubLog),
} satisfies DesktopObservability.DesktopBackendOutputLogFactory["Service"]),
Layer.succeed(DesktopTelemetryPublisher.DesktopTelemetryPublisher, {
latest: Effect.succeed(Option.none()),
latest: Effect.succeedNone,
changes: Stream.empty,
encoded: input.desktopTelemetryStream ?? Stream.empty,
handleControlForSource: () => Effect.void,
Expand Down Expand Up @@ -1545,7 +1545,7 @@ describe("DesktopBackendManager", () => {

const mockPool = Layer.succeed(DesktopBackendPool.DesktopBackendPool, {
list: Effect.succeed([instance1, instance2]),
get: () => Effect.succeed(Option.none()),
get: () => Effect.succeedNone,
primary: Effect.die(new Error("primary not implemented")),
register: () => Effect.die(new Error("register not implemented")),
unregister: () => Effect.die(new Error("unregister not implemented")),
Expand Down
6 changes: 2 additions & 4 deletions apps/desktop/src/backend/DesktopBackendPool.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ function makePoolLayer(
} satisfies DesktopObservability.DesktopBackendOutputLogShape),
} satisfies DesktopObservability.DesktopBackendOutputLogFactory["Service"]),
Layer.succeed(DesktopTelemetryPublisher.DesktopTelemetryPublisher, {
latest: Effect.succeed(Option.none()),
latest: Effect.succeedNone,
changes: Stream.empty,
encoded: Stream.empty,
handleControlForSource: () => Effect.void,
Expand Down Expand Up @@ -135,9 +135,7 @@ describe("DesktopBackendPool", () => {

it.effect("layerTest dies when no instances are supplied", () =>
Effect.exit(
Effect.gen(function* () {
yield* DesktopBackendPool.DesktopBackendPool;
}).pipe(Effect.provide(DesktopBackendPool.layerTest([]))),
DesktopBackendPool.DesktopBackendPool.pipe(Effect.provide(DesktopBackendPool.layerTest([]))),
).pipe(Effect.map((exit) => assert.equal(exit._tag, "Failure"))),
);

Expand Down
3 changes: 1 addition & 2 deletions apps/desktop/src/backend/DesktopLocalEnvironmentAuth.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { assert, describe, it } from "@effect/vitest";
import * as Effect from "effect/Effect";
import * as Layer from "effect/Layer";
import * as Option from "effect/Option";
import * as Ref from "effect/Ref";
import * as HttpClient from "effect/unstable/http/HttpClient";
import * as HttpClientResponse from "effect/unstable/http/HttpClientResponse";
Expand Down Expand Up @@ -60,7 +59,7 @@ describe("DesktopLocalEnvironmentAuth", () => {
{
id: PRIMARY_LOCAL_ENVIRONMENT_ID,
label: Effect.succeed("Windows"),
currentConfig: Effect.succeed(Option.some(config)),
currentConfig: Effect.succeedSome(config),
},
]),
} as unknown as DesktopBackendPool.DesktopBackendPool["Service"]);
Expand Down
4 changes: 3 additions & 1 deletion apps/desktop/src/electron/ElectronMenu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ function normalizeContextMenuItems(source: readonly ContextMenuItem[]): ContextM
destructive: sourceItem.destructive === true,
disabled: sourceItem.disabled === true,
...(sourceItem.separatorBefore === true ? { separatorBefore: true } : {}),
...(typeof sourceItem.checked === "boolean" ? { checked: sourceItem.checked } : {}),
};

if (sourceItem.children) {
Expand Down Expand Up @@ -168,6 +169,7 @@ export const make = Effect.gen(function* () {
const itemOption: Electron.MenuItemConstructorOptions = {
label: item.label,
enabled: !item.disabled,
...(typeof item.checked === "boolean" ? { type: "checkbox", checked: item.checked } : {}),
};
if (item.children && item.children.length > 0) {
itemOption.submenu = buildTemplate(item.children, complete);
Expand Down Expand Up @@ -224,7 +226,7 @@ export const make = Effect.gen(function* () {
Effect.callback<Option.Option<string>>((resume) => {
const normalizedItems = normalizeContextMenuItems(input.items);
if (normalizedItems.length === 0) {
resume(Effect.succeed(Option.none()));
resume(Effect.succeedNone);
return;
}

Expand Down
28 changes: 13 additions & 15 deletions apps/desktop/src/ipc/methods/snapShot.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ describe("window capture IPC", () => {
Effect.provide(
Layer.mergeAll(
Layer.succeed(ElectronWindow.ElectronWindow, {
main: Effect.succeed(Option.some({ webContents: { id: 7 } })),
main: Effect.succeedSome({ webContents: { id: 7 } }),
} as ElectronWindow.ElectronWindow["Service"]),
Layer.succeed(DesktopSnapShot.DesktopSnapShot, {
previewConfig: () =>
Expand Down Expand Up @@ -87,7 +87,7 @@ describe("window capture IPC", () => {
Effect.provide(
Layer.mergeAll(
Layer.succeed(ElectronWindow.ElectronWindow, {
main: Effect.succeed(Option.some({ webContents: { id: 7 } })),
main: Effect.succeedSome({ webContents: { id: 7 } }),
} as ElectronWindow.ElectronWindow["Service"]),
Layer.succeed(DesktopSnapShot.DesktopSnapShot, {
state: Effect.succeed({
Expand Down Expand Up @@ -120,7 +120,7 @@ describe("window capture IPC", () => {
Effect.provide(
Layer.mergeAll(
Layer.succeed(ElectronWindow.ElectronWindow, {
main: Effect.succeed(Option.some({ webContents: { id: 7 } })),
main: Effect.succeedSome({ webContents: { id: 7 } }),
} as ElectronWindow.ElectronWindow["Service"]),
Layer.succeed(DesktopSnapShot.DesktopSnapShot, {
state: Effect.succeed({ linuxBackend: "niri" }),
Expand Down Expand Up @@ -156,13 +156,11 @@ describe("window capture IPC", () => {
Layer.succeed(
ElectronWindow.ElectronWindow,
ElectronWindow.ElectronWindow.of({
main: Effect.succeed(
Option.some({
getBounds: () => ({ x: 100, y: 80, width: 1_000, height: 700 }),
getContentBounds: () => ({ x: 100, y: 118, width: 1_000, height: 662 }),
webContents,
}),
),
main: Effect.succeedSome({
getBounds: () => ({ x: 100, y: 80, width: 1_000, height: 700 }),
getContentBounds: () => ({ x: 100, y: 118, width: 1_000, height: 662 }),
webContents,
}),
} as ElectronWindow.ElectronWindow["Service"]),
),
Layer.succeed(
Expand Down Expand Up @@ -220,7 +218,7 @@ describe("window capture IPC", () => {
Layer.succeed(
ElectronWindow.ElectronWindow,
ElectronWindow.ElectronWindow.of({
main: Effect.succeed(Option.some({ webContents })),
main: Effect.succeedSome({ webContents }),
} as ElectronWindow.ElectronWindow["Service"]),
),
Layer.succeed(
Expand Down Expand Up @@ -256,7 +254,7 @@ describe("window capture IPC", () => {
Effect.provideService(
ElectronWindow.ElectronWindow,
ElectronWindow.ElectronWindow.of({
main: Effect.succeed(Option.some({ webContents: { id: 7 } })),
main: Effect.succeedSome({ webContents: { id: 7 } }),
} as ElectronWindow.ElectronWindow["Service"]),
),
Effect.provideService(DesktopSnapShot.DesktopSnapShot, null as never),
Expand All @@ -277,7 +275,7 @@ describe("window capture IPC", () => {
Effect.provide(
Layer.mergeAll(
Layer.succeed(ElectronWindow.ElectronWindow, {
main: Effect.succeed(Option.some({ webContents: { id: 7 } })),
main: Effect.succeedSome({ webContents: { id: 7 } }),
} as ElectronWindow.ElectronWindow["Service"]),
Layer.succeed(DesktopSnapShot.DesktopSnapShot, {
setup: (action: string) =>
Expand All @@ -295,7 +293,7 @@ describe("window capture IPC", () => {
Layer.succeed(
ElectronWindow.ElectronWindow,
ElectronWindow.ElectronWindow.of({
main: Effect.succeed(Option.some({ webContents: { id: 7 } })),
main: Effect.succeedSome({ webContents: { id: 7 } }),
} as ElectronWindow.ElectronWindow["Service"]),
),
Layer.succeed(
Expand All @@ -320,7 +318,7 @@ describe("window capture IPC", () => {
Layer.succeed(
ElectronWindow.ElectronWindow,
ElectronWindow.ElectronWindow.of({
main: Effect.succeed(Option.some({ webContents: { id: 7 } })),
main: Effect.succeedSome({ webContents: { id: 7 } }),
} as ElectronWindow.ElectronWindow["Service"]),
),
Layer.succeed(
Expand Down
12 changes: 5 additions & 7 deletions apps/desktop/src/ipc/methods/sshEnvironment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -137,13 +137,11 @@ export const ensureSshEnvironment = DesktopIpc.makeIpcMethod({
}) {
const sshEnvironment = yield* DesktopSshEnvironment.DesktopSshEnvironment;
return yield* sshEnvironment.ensureEnvironment(target, options).pipe(
Effect.catch((error) =>
DesktopSshEnvironment.isDesktopSshPasswordPromptCancellation(error)
? Effect.succeed({
type: DesktopSshPasswordPromptCancelledType,
message: error.message,
})
: Effect.fail(error),
Effect.catchIf(DesktopSshEnvironment.isDesktopSshPasswordPromptCancellation, (error) =>
Effect.succeed({
type: DesktopSshPasswordPromptCancelledType,
message: error.message,
}),
),
);
}),
Expand Down
Loading
Loading