authorgravatar for julius0216@outlook.comJulius Marminge <julius0216@outlook.com> 2026-06-20 20:41:58-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2026-06-20 20:41:58-07:00
log0debebafbb7d98a3c77d3e636fa54616a98d26da
tree40a00aa72741c8234e92555af9776d418e004921
parent2a29de7502cdd02686bda7d12fb2671060fd1979
signature Signed by PGP key B5690EEEBB952194

[codex] Structure thread archive blocked error (#3451)


2 files changed, 34 insertions(+), 6 deletions(-)

apps/web/src/hooks/useThreadActions.test.ts created+19
......@@ -0,0 +1,19 @@
1import { EnvironmentId, ThreadId } from "@t3tools/contracts";
2import { describe, expect, it } from "vite-plus/test";
3
4import { ThreadArchiveBlockedError } from "./useThreadActions";
5
6describe("ThreadArchiveBlockedError", () => {
7 it("keeps the blocked thread context with the fixed message", () => {
8 const error = new ThreadArchiveBlockedError({
9 environmentId: EnvironmentId.make("environment-1"),
10 threadId: ThreadId.make("thread-1"),
11 });
12
13 expect(error).toMatchObject({
14 environmentId: "environment-1",
15 threadId: "thread-1",
16 });
17 expect(error.message).toBe("Cannot archive a running thread.");
18 });
19});
apps/web/src/hooks/useThreadActions.ts+15-6
......@@ -4,9 +4,9 @@ import {
44 scopeThreadRef,
55} from "@t3tools/client-runtime/environment";
66import { settlePromise, squashAtomCommandFailure } from "@t3tools/client-runtime/state/runtime";
7import { type ScopedThreadRef, ThreadId } from "@t3tools/contracts";
7import { EnvironmentId, type ScopedThreadRef, ThreadId } from "@t3tools/contracts";
88import * as Cause from "effect/Cause";
9import * as Data from "effect/Data";
9import * as Schema from "effect/Schema";
1010import { AsyncResult } from "effect/unstable/reactivity";
1111import { useRouter } from "@tanstack/react-router";
1212import { useCallback, useMemo, useRef } from "react";
......@@ -27,9 +27,17 @@ import { stackedThreadToast, toastManager } from "../components/ui/toast";
2727import { useClientSettings } from "./useSettings";
2828import { useAtomCommand } from "../state/use-atom-command";
2929
30export class ThreadArchiveBlockedError extends Data.TaggedError("ThreadArchiveBlockedError")<{
31 readonly message: string;
32}> {}
30export class ThreadArchiveBlockedError extends Schema.TaggedErrorClass<ThreadArchiveBlockedError>()(
31 "ThreadArchiveBlockedError",
32 {
33 environmentId: EnvironmentId,
34 threadId: ThreadId,
35 },
36) {
37 override get message(): string {
38 return "Cannot archive a running thread.";
39 }
40}
3341
3442export function useThreadActions() {
3543 const closeTerminal = useAtomCommand(terminalEnvironment.close);
......@@ -89,7 +97,8 @@ export function useThreadActions() {
8997 return AsyncResult.failure(
9098 Cause.fail(
9199 new ThreadArchiveBlockedError({
92 message: "Cannot archive a running thread.",
100 environmentId: threadRef.environmentId,
101 threadId: threadRef.threadId,
93102 }),
94103 ),
95104 );