| author | |
| committer | |
| log | f6f2be32d8bc072e87753e41ad77c7c67e8b0b95 |
| tree | a6895891771b8df09200826996e53a7fe9f60690 |
| parent | 73f8cfc023d70adbc8bf45afeab12cc8761d722b |
| signature | Signed by PGP key B5690EEEBB952194 |
Co-authored-by: t3-code[bot] <269035359+t3-code[bot]@users.noreply.github.com>
Co-authored-by: Julius Marminge <51714798+juliusmarminge@users.noreply.github.com>10 files changed, 3 insertions(+), 213 deletions(-)
apps/server/scripts/cliErrors.test.ts deleted-31| ... | ... | @@ -1,31 +0,0 @@ |
| 1 | import { assert, describe, it } from "@effect/vitest"; | |
| 2 | ||
| 3 | import { ServerCliBuildAssetMissingError, ServerCliCommandExitError } from "./cliErrors.ts"; | |
| 4 | ||
| 5 | describe("server CLI errors", () => { | |
| 6 | it("preserves failed command context without changing its message", () => { | |
| 7 | const error = new ServerCliCommandExitError({ | |
| 8 | command: "vp", | |
| 9 | args: ["pm", "publish"], | |
| 10 | cwd: "/repo", | |
| 11 | exitCode: 17, | |
| 12 | }); | |
| 13 | ||
| 14 | assert.equal(error._tag, "ServerCliCommandExitError"); | |
| 15 | assert.equal(error.command, "vp"); | |
| 16 | assert.deepEqual(error.args, ["pm", "publish"]); | |
| 17 | assert.equal(error.cwd, "/repo"); | |
| 18 | assert.equal(error.exitCode, 17); | |
| 19 | assert.equal(error.message, "Command exited with non-zero exit code (17)"); | |
| 20 | }); | |
| 21 | ||
| 22 | it("preserves a representative missing asset path", () => { | |
| 23 | const error = new ServerCliBuildAssetMissingError({ assetPath: "/repo/server.mjs" }); | |
| 24 | ||
| 25 | assert.equal(error.assetPath, "/repo/server.mjs"); | |
| 26 | assert.equal( | |
| 27 | error.message, | |
| 28 | "Missing build asset: /repo/server.mjs. Run the build subcommand first.", | |
| 29 | ); | |
| 30 | }); | |
| 31 | }); |
apps/server/src/checkpointing/Errors.test.ts deleted-39| ... | ... | @@ -1,39 +0,0 @@ |
| 1 | import { expect, it } from "@effect/vitest"; | |
| 2 | import { ThreadId } from "@t3tools/contracts"; | |
| 3 | ||
| 4 | import { | |
| 5 | CheckpointRefUnavailableError, | |
| 6 | CheckpointTurnRangeUnavailableError, | |
| 7 | CheckpointWorkspacePathMissingError, | |
| 8 | } from "./Errors.ts"; | |
| 9 | ||
| 10 | const threadId = ThreadId.make("thread-1"); | |
| 11 | ||
| 12 | it("derives checkpoint messages from structured context", () => { | |
| 13 | const range = new CheckpointTurnRangeUnavailableError({ | |
| 14 | operation: "CheckpointDiffQuery.getTurnDiff", | |
| 15 | threadId, | |
| 16 | requestedTurnCount: 4, | |
| 17 | availableTurnCount: 2, | |
| 18 | }); | |
| 19 | const checkpoint = new CheckpointRefUnavailableError({ | |
| 20 | operation: "CheckpointDiffQuery.getTurnDiff", | |
| 21 | threadId, | |
| 22 | turnCount: 2, | |
| 23 | checkpoint: "to", | |
| 24 | }); | |
| 25 | const workspace = new CheckpointWorkspacePathMissingError({ | |
| 26 | operation: "CheckpointDiffQuery.getFullThreadDiff", | |
| 27 | threadId, | |
| 28 | }); | |
| 29 | ||
| 30 | expect(range.message).toBe( | |
| 31 | "Checkpoint unavailable for thread thread-1 turn 4: Turn diff range exceeds current turn count: requested 4, current 2.", | |
| 32 | ); | |
| 33 | expect(checkpoint.message).toBe( | |
| 34 | "Checkpoint unavailable for thread thread-1 turn 2: Checkpoint ref is unavailable for turn 2.", | |
| 35 | ); | |
| 36 | expect(workspace.message).toBe( | |
| 37 | "Checkpoint invariant violation in CheckpointDiffQuery.getFullThreadDiff: Workspace path missing for thread 'thread-1' when computing full thread diff.", | |
| 38 | ); | |
| 39 | }); |
apps/server/src/terminal/PtyAdapter.test.ts deleted-34| ... | ... | @@ -1,34 +0,0 @@ |
| 1 | import { assert, describe, it } from "@effect/vitest"; | |
| 2 | import * as Schema from "effect/Schema"; | |
| 3 | ||
| 4 | import * as PtyAdapter from "./PtyAdapter.ts"; | |
| 5 | ||
| 6 | const isPtySpawnError = Schema.is(PtyAdapter.PtySpawnError); | |
| 7 | ||
| 8 | describe("PtySpawnError", () => { | |
| 9 | it("derives messages from structural context while preserving the full cause chain", () => { | |
| 10 | const spawnCause = new Error("spawn /bin/zsh ENOENT"); | |
| 11 | const adapterError = new PtyAdapter.PtySpawnError({ | |
| 12 | adapter: "node-pty", | |
| 13 | shell: "/bin/zsh", | |
| 14 | cause: spawnCause, | |
| 15 | }); | |
| 16 | const managerError = new PtyAdapter.PtySpawnError({ | |
| 17 | adapter: "terminal-manager", | |
| 18 | attemptedShells: ["/bin/zsh -o nopromptsp", "/bin/bash"], | |
| 19 | cause: adapterError, | |
| 20 | }); | |
| 21 | ||
| 22 | assert(isPtySpawnError(managerError)); | |
| 23 | assert.strictEqual( | |
| 24 | managerError.message, | |
| 25 | "Failed to spawn PTY process with terminal-manager. Tried shells: /bin/zsh -o nopromptsp, /bin/bash.", | |
| 26 | ); | |
| 27 | assert.strictEqual( | |
| 28 | adapterError.message, | |
| 29 | "Failed to spawn PTY process '/bin/zsh' with node-pty.", | |
| 30 | ); | |
| 31 | assert.strictEqual(managerError.cause, adapterError); | |
| 32 | assert.strictEqual(adapterError.cause, spawnCause); | |
| 33 | }); | |
| 34 | }); |
apps/web/src/components/threadSidebarWidth.test.ts deleted-48| ... | ... | @@ -1,48 +0,0 @@ |
| 1 | // @effect-diagnostics nodeBuiltinImport:off - Regression coverage compares the sidebar component with its width contract. | |
| 2 | import * as NodeFS from "node:fs"; | |
| 3 | ||
| 4 | import { describe, expect, it } from "vite-plus/test"; | |
| 5 | ||
| 6 | import { | |
| 7 | resolveInitialThreadSidebarWidth, | |
| 8 | THREAD_MAIN_CONTENT_MIN_WIDTH, | |
| 9 | THREAD_SIDEBAR_DEFAULT_WIDTH, | |
| 10 | THREAD_SIDEBAR_MIN_WIDTH, | |
| 11 | } from "./threadSidebarWidth"; | |
| 12 | ||
| 13 | describe("thread sidebar width", () => { | |
| 14 | it("uses the default width when no preference is stored", () => { | |
| 15 | expect(resolveInitialThreadSidebarWidth(null, 1200)).toBe(THREAD_SIDEBAR_DEFAULT_WIDTH); | |
| 16 | }); | |
| 17 | ||
| 18 | it("uses a stored width in the initial render", () => { | |
| 19 | expect(resolveInitialThreadSidebarWidth(360, 1200)).toBe(360); | |
| 20 | }); | |
| 21 | ||
| 22 | it("clamps a stored width to the sidebar minimum", () => { | |
| 23 | expect(resolveInitialThreadSidebarWidth(120, 1200)).toBe(THREAD_SIDEBAR_MIN_WIDTH); | |
| 24 | }); | |
| 25 | ||
| 26 | it("leaves enough room for the main content on a smaller window", () => { | |
| 27 | const viewportWidth = 1000; | |
| 28 | ||
| 29 | expect(resolveInitialThreadSidebarWidth(900, viewportWidth)).toBe( | |
| 30 | viewportWidth - THREAD_MAIN_CONTENT_MIN_WIDTH, | |
| 31 | ); | |
| 32 | }); | |
| 33 | ||
| 34 | it("keeps the sidebar minimum when the whole layout is narrower than its minimums", () => { | |
| 35 | expect(resolveInitialThreadSidebarWidth(900, 700)).toBe(THREAD_SIDEBAR_MIN_WIDTH); | |
| 36 | }); | |
| 37 | ||
| 38 | it("shows the desktop wordmark across the sidebar's full legal width range", () => { | |
| 39 | const sidebarSource = NodeFS.readFileSync( | |
| 40 | new URL("./sidebar/SidebarChrome.tsx", import.meta.url), | |
| 41 | "utf8", | |
| 42 | ); | |
| 43 | ||
| 44 | expect(sidebarSource).toContain("hidden h-7 w-fit min-w-0 shrink-0 items-center gap-1"); | |
| 45 | expect(sidebarSource).toContain("md:flex"); | |
| 46 | expect(THREAD_SIDEBAR_MIN_WIDTH).toBe(13 * 16); | |
| 47 | }); | |
| 48 | }); |
apps/web/src/components/threadSidebarWidth.ts+1-1| ... | ... | @@ -1,5 +1,5 @@ |
| 1 | 1 | export const THREAD_SIDEBAR_WIDTH_STORAGE_KEY = "chat_thread_sidebar_width"; |
| 2 | export const THREAD_SIDEBAR_DEFAULT_WIDTH = 16 * 16; | |
| 2 | const THREAD_SIDEBAR_DEFAULT_WIDTH = 16 * 16; | |
| 3 | 3 | export const THREAD_SIDEBAR_MIN_WIDTH = 13 * 16; |
| 4 | 4 | export const THREAD_MAIN_CONTENT_MIN_WIDTH = 40 * 16; |
| 5 | 5 |
packages/client-runtime/src/state/session.test.ts deleted-21| ... | ... | @@ -1,21 +0,0 @@ |
| 1 | import { describe, expect, it } from "@effect/vitest"; | |
| 2 | import * as Effect from "effect/Effect"; | |
| 3 | import * as Option from "effect/Option"; | |
| 4 | import * as Schema from "effect/Schema"; | |
| 5 | ||
| 6 | import { initialConfigOption } from "./session.ts"; | |
| 7 | ||
| 8 | class TestConfigError extends Schema.TaggedErrorClass<TestConfigError>()("TestConfigError", { | |
| 9 | message: Schema.String, | |
| 10 | }) {} | |
| 11 | ||
| 12 | describe("environment session state", () => { | |
| 13 | it.effect("turns an initial config failure into an empty value", () => | |
| 14 | Effect.gen(function* () { | |
| 15 | const result = yield* initialConfigOption( | |
| 16 | Effect.fail(new TestConfigError({ message: "temporary failure" })), | |
| 17 | ); | |
| 18 | expect(Option.isNone(result)).toBe(true); | |
| 19 | }), | |
| 20 | ); | |
| 21 | }); |
packages/client-runtime/src/state/session.ts+1-1| ... | ... | @@ -16,7 +16,7 @@ import { executeEnvironmentHttpRequest, makeEnvironmentHttpApiClient } from "../ |
| 16 | 16 | import { buildEnvironmentAuthHeaders, withEnvironmentCredentials } from "./environmentHttpAuth.ts"; |
| 17 | 17 | import { followStreamInEnvironment } from "./runtime.ts"; |
| 18 | 18 | |
| 19 | export function initialConfigOption<E>( | |
| 19 | function initialConfigOption<E>( | |
| 20 | 20 | initialConfig: Effect.Effect<ServerConfig, E>, |
| 21 | 21 | ): Effect.Effect<Option.Option<ServerConfig>> { |
| 22 | 22 | return initialConfig.pipe( |
packages/shared/src/String.test.ts deleted-17| ... | ... | @@ -1,17 +0,0 @@ |
| 1 | import { describe, expect, it } from "vite-plus/test"; | |
| 2 | ||
| 3 | import { truncate } from "./String.ts"; | |
| 4 | ||
| 5 | describe("truncate", () => { | |
| 6 | it("trims surrounding whitespace", () => { | |
| 7 | expect(truncate(" hello world ")).toBe("hello world"); | |
| 8 | }); | |
| 9 | ||
| 10 | it("returns shorter strings unchanged", () => { | |
| 11 | expect(truncate("alpha", 10)).toBe("alpha"); | |
| 12 | }); | |
| 13 | ||
| 14 | it("truncates long strings and appends an ellipsis", () => { | |
| 15 | expect(truncate("abcdefghij", 5)).toBe("abcde..."); | |
| 16 | }); | |
| 17 | }); |
scripts/lib/resolve-catalog.test.ts deleted-20| ... | ... | @@ -1,20 +0,0 @@ |
| 1 | import { assert, it } from "@effect/vitest"; | |
| 2 | ||
| 3 | import { CatalogDependencyResolutionError, resolveCatalogDependencies } from "./resolve-catalog.ts"; | |
| 4 | ||
| 5 | it("reports unresolved catalog dependencies with lookup context", () => { | |
| 6 | try { | |
| 7 | resolveCatalogDependencies({ effect: "catalog:runtime" }, {}, "apps/server"); | |
| 8 | assert.fail("Expected catalog resolution to fail."); | |
| 9 | } catch (error) { | |
| 10 | assert.instanceOf(error, CatalogDependencyResolutionError); | |
| 11 | assert.equal(error.workspacePackage, "apps/server"); | |
| 12 | assert.equal(error.dependencyName, "effect"); | |
| 13 | assert.equal(error.catalogSpec, "catalog:runtime"); | |
| 14 | assert.equal(error.catalogKey, "runtime"); | |
| 15 | assert.equal( | |
| 16 | error.message, | |
| 17 | "Unable to resolve 'catalog:runtime' for apps/server dependency 'effect'. Expected key 'runtime' in root workspace catalog.", | |
| 18 | ); | |
| 19 | } | |
| 20 | }); |
scripts/lib/resolve-catalog.ts+1-1| ... | ... | @@ -1,6 +1,6 @@ |
| 1 | 1 | import * as Schema from "effect/Schema"; |
| 2 | 2 | |
| 3 | export class CatalogDependencyResolutionError extends Schema.TaggedErrorClass<CatalogDependencyResolutionError>()( | |
| 3 | class CatalogDependencyResolutionError extends Schema.TaggedErrorClass<CatalogDependencyResolutionError>()( | |
| 4 | 4 | "CatalogDependencyResolutionError", |
| 5 | 5 | { |
| 6 | 6 | workspacePackage: Schema.String, |