From 7fdc43a00956901d59c5bf39d75c42902c28a02a Mon Sep 17 00:00:00 2001 From: Julius Marminge Date: Thu, 12 Nov 2026 17:15:36 +0000 Subject: [PATCH 1/2] test(muse): a slow `muse --version` is not reported as timed out Reproduces #24165: the Muse status check gives `muse --version` the shared 4 s budget, so a Muse that answers after 5 s shows Unavailable. AI-assisted; verified with the tests and tools listed above. Co-Authored-By: Claude Opus 5.5 --- .../provider-muse/src/server/status.test.ts | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/packages/provider-muse/src/server/status.test.ts b/packages/provider-muse/src/server/status.test.ts index 582b0ee37b6b9..e1c22fda9418d 100644 --- a/packages/provider-muse/src/server/status.test.ts +++ b/packages/provider-muse/src/server/status.test.ts @@ -2,8 +2,14 @@ import * as NodeServices from "@effect/platform-node/NodeServices"; import { expect, it } from "@effect/vitest"; import { MuseSettings } from "../settings.ts"; import * as Effect from "effect/Effect"; +import * as Fiber from "effect/Fiber"; import * as FileSystem from "effect/FileSystem"; +import * as Layer from "effect/Layer"; import * as Schema from "effect/Schema"; +import * as Sink from "effect/Sink"; +import * as Stream from "effect/Stream"; +import { ChildProcessSpawner } from "effect/process"; +import * as TestClock from "effect/testing/TestClock"; import { vi } from "vite-plus/test"; import { writeFakeCli } from "@t3tools/provider-testing/fakeCli"; @@ -54,7 +60,49 @@ const fakeCli = (source = 'process.stdout.write("muse 1.0.3-R2198.1\\n");') => return writeFakeCli({ directory, name: "muse", source }); }); +// A `muse --version` that answers only after `delay`, like Muse started inside a Windows job object. +const slowVersionSpawner = (delay: string) => + Layer.succeed( + ChildProcessSpawner.ChildProcessSpawner, + ChildProcessSpawner.make(() => { + const answered = Effect.sleep(delay); + return Effect.succeed( + ChildProcessSpawner.makeHandle({ + pid: ChildProcessSpawner.ProcessId(900_000_010), + exitCode: Effect.as(answered, ChildProcessSpawner.ExitCode(0)), + isRunning: Effect.succeed(false), + kill: () => Effect.void, + unref: Effect.succeed(Effect.void), + stdin: Sink.drain, + stdout: Stream.unwrap( + Effect.as(answered, Stream.succeed(new TextEncoder().encode("muse 1.4.12-R6909.1\n"))), + ), + stderr: Stream.empty, + all: Stream.empty, + getInputFd: () => Sink.drain, + getOutputFd: () => Stream.empty, + }), + ); + }), + ); + it.layer(NodeServices.layer)("Muse status", (it) => { + it.effect("waits for a `muse --version` that answers after 5 s", () => + Effect.gen(function* () { + const fiber = yield* checkMuseProviderStatus( + settings({ enabled: true, binaryPath: "muse" }), + undefined, + undefined, + async () => makeHost(metaCatalog), + ).pipe(Effect.provide(slowVersionSpawner("5 seconds")), Effect.forkChild); + yield* TestClock.adjust("5 seconds"); + const snapshot = yield* Fiber.join(fiber); + expect(snapshot.message).toBeUndefined(); + expect(snapshot.status).toBe("ready"); + expect(snapshot.version).toBe("1.4.12-R6909.1"); + }), + ); + it.effect("does not expose CLI stderr or start an SDK host after a failed version check", () => Effect.scoped( Effect.gen(function* () { From 1420943faf273bdbcbc3bb8ea358241ef372fffe Mon Sep 17 00:00:00 2001 From: Julius Marminge Date: Thu, 12 Nov 2026 17:22:23 +0000 Subject: [PATCH 2/2] fix(muse): Muse no longer shows Unavailable when `muse --version` is slow The Muse status check stopped `muse --version` after the shared 4 s limit. On Windows, Muse started inside the server's job object takes 4 to 9 s to answer, so it always showed "version check timed out". Give the version probe the 10 s budget the Kiro, Grok, Pi and fx probes already use. Fixes pingdotgg/t3code#24165 AI-assisted; verified with the tests and tools listed above. Co-Authored-By: Claude Opus 5.5 --- packages/provider-muse/src/server/status.test.ts | 3 ++- packages/provider-muse/src/server/status.ts | 5 +++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/provider-muse/src/server/status.test.ts b/packages/provider-muse/src/server/status.test.ts index e1c22fda9418d..84b4a693c6010 100644 --- a/packages/provider-muse/src/server/status.test.ts +++ b/packages/provider-muse/src/server/status.test.ts @@ -1,6 +1,7 @@ import * as NodeServices from "@effect/platform-node/NodeServices"; import { expect, it } from "@effect/vitest"; import { MuseSettings } from "../settings.ts"; +import * as Duration from "effect/Duration"; import * as Effect from "effect/Effect"; import * as Fiber from "effect/Fiber"; import * as FileSystem from "effect/FileSystem"; @@ -61,7 +62,7 @@ const fakeCli = (source = 'process.stdout.write("muse 1.0.3-R2198.1\\n");') => }); // A `muse --version` that answers only after `delay`, like Muse started inside a Windows job object. -const slowVersionSpawner = (delay: string) => +const slowVersionSpawner = (delay: Duration.Input) => Layer.succeed( ChildProcessSpawner.ChildProcessSpawner, ChildProcessSpawner.make(() => { diff --git a/packages/provider-muse/src/server/status.ts b/packages/provider-muse/src/server/status.ts index ef4940df11641..cd51250c22e60 100644 --- a/packages/provider-muse/src/server/status.ts +++ b/packages/provider-muse/src/server/status.ts @@ -13,7 +13,6 @@ import { discoverMuseModels, museModelCapabilities } from "./modelCatalog.ts"; import { buildServerProvider, COMPACT_SLASH_COMMAND, - DEFAULT_TIMEOUT_MS, isCommandMissingCause, parseCliVersionResult, providerModelsFromSettings, @@ -31,6 +30,8 @@ const MUSE_PRESENTATION = { } as const; const FALLBACK_CAPABILITIES = museModelCapabilities(); +// Muse can take 4 to 9 s to answer `--version` when started inside the server's Windows job object. +const VERSION_PROBE_TIMEOUT_MS = 10_000; export const makePendingMuseProvider = Effect.fn("makePendingMuseProvider")(function* ( settings: MuseSettings, @@ -83,7 +84,7 @@ export const checkMuseProviderStatus = Effect.fn("checkMuseProviderStatus")(func ...(cwd ? { cwd } : {}), }), ); - }).pipe(Effect.timeoutOption(DEFAULT_TIMEOUT_MS), Effect.result); + }).pipe(Effect.timeoutOption(VERSION_PROBE_TIMEOUT_MS), Effect.result); if (Result.isFailure(versionResult)) { const missing = isCommandMissingCause(versionResult.failure);