/// import * as NodeCrypto from "node:crypto"; import { beforeEach, vi } from "vite-plus/test"; import { describe, expect, it } from "@effect/vitest"; import Constants from "expo-constants"; import * as Cause from "effect/Cause"; import type { LiveActivity } from "expo-widgets"; import * as DateTime from "effect/DateTime"; import * as TestClock from "effect/testing/TestClock"; import { makeRawThreadShell } from "../../test-fixtures"; import * as Effect from "effect/Effect"; import * as Deferred from "effect/Deferred"; import * as Exit from "effect/Exit"; import * as Fiber from "effect/Fiber"; import * as Layer from "effect/Layer"; import { Cookies, FetchHttpClient, HttpClientRequest, HttpClientResponse } from "effect/http"; import * as Option from "effect/Option"; import { Atom } from "effect/reactivity"; import { ManagedRelay } from "@t3tools/client-runtime/relay"; import { PrimaryConnectionTarget } from "@t3tools/client-runtime/connection"; import type { EnvironmentCatalogState } from "@t3tools/client-runtime/state/connections"; import type { EnvironmentShellState } from "@t3tools/client-runtime/state/shell"; import { EnvironmentId, ProjectId, ProviderInstanceId, ThreadId, type OrchestrationProjectShell, } from "@t3tools/contracts"; import type { RelayAgentActivitySnapshotResponse } from "@t3tools/contracts/relay"; import { verifyDpopProof } from "@t3tools/shared/dpop"; import * as Dpop from "../cloud/dpop"; import * as ManagedRelayLayer from "../cloud/managedRelayLayer"; import { clearAgentAwarenessRegistrationRecord, loadAgentAwarenessRegistrationRecord, loadOrCreateAgentAwarenessDeviceId, loadPreferences, saveAgentAwarenessRegistrationRecord, } from "../../persistence/imperative"; import type { Preferences } from "../../persistence/mobile-preferences"; import { makeRelayDeviceRegistrationRequest } from "./registrationPayload"; import { __resetAgentAwarenessRemoteRegistrationForTest, armAgentAwarenessLiveActivityForLocalWork, getAgentAwarenessRegistrationStatus, refreshActiveLiveActivityRemoteRegistration, refreshAgentAwarenessRegistration, registerLiveActivityPushToken, releaseAgentAwarenessRelayTokenProvider, setAgentAwarenessRelayTokenProvider, updateAgentAwarenessRegistrationPreferences, type AgentAwarenessRegistrationError, } from "./remoteRegistration"; import type { AgentActivityProps } from "../../widgets/AgentActivity"; import { publishAgentActivityWidget } from "./agentLiveActivity"; import { agentActivityTimeline, AGENT_ACTIVITY_FRESHNESS_MS, } from "../../widgets/agentActivityTimeline"; import * as Notifications from "expo-notifications"; import { Platform } from "react-native"; import { configureAndroidAgentNotifications } from "./androidNotifications"; import { agentWidgetToken, configureAgentWidgetRefresh, clearAgentWidgetRefresh, } from "./agentWidgetRefresh"; vi.mock("./agentWidgetRefresh", () => ({ agentWidgetToken: vi.fn(() => null), configureAgentWidgetRefresh: vi.fn(), clearAgentWidgetRefresh: vi.fn(), })); vi.mock("./androidNotifications", () => ({ supportsAndroidAgentNotifications: vi.fn(() => true), configureAndroidAgentNotifications: vi.fn(), clearAndroidAgentNotifications: vi.fn(), })); import { appAtomRegistry } from "../../state/atom-registry"; import { environmentCatalog } from "../../connection/catalog"; import { environmentShell } from "../../state/shell"; const secureStore = vi.hoisted(() => new Map()); const widgetMocks = vi.hoisted(() => ({ dismissEnded: vi.fn(), getInstances: vi.fn<() => ReadonlyArray>>>(() => []), start: vi.fn(() => ({})), })); const environmentConfigsMock = vi.hoisted(() => ({ configs: new Map< string, { environment: { capabilities: { agentActivityPublishing?: boolean } } } >(), })); const backgroundRuntime = vi.hoisted(() => ({ pending: [] as Array<{ readonly operation: unknown; readonly resolve: (exit: Exit.Exit) => void; }>, })); const appStateMock = vi.hoisted(() => ({ currentState: "active", listeners: [] as Array<(state: string) => void>, })); const registrationRecordStore = vi.hoisted(() => ({ current: null as { readonly identity: string; readonly signature: string; readonly pushToStartToken?: string; } | null, })); vi.mock("expo-constants", () => ({ default: { expoConfig: { version: "1.0.0", extra: {}, }, }, })); vi.mock("expo-widgets", () => ({ addPushToStartTokenListener: vi.fn(() => ({ remove: vi.fn() })), })); vi.mock("./agentLiveActivity", () => ({ dismissEndedAgentLiveActivities: widgetMocks.dismissEnded, getAgentLiveActivities: widgetMocks.getInstances, startAgentLiveActivity: widgetMocks.start, publishAgentActivityWidget: vi.fn(() => true), })); // Keep the native connection boundary synthetic while exercising the real atom // registry and widget observer used by the registered app callbacks. vi.mock("../../state/atom-registry", async () => { const { AtomRegistry } = await import("effect/reactivity"); return { appAtomRegistry: AtomRegistry.make() }; }); vi.mock("../../state/server", async () => { const { Atom } = await import("effect/reactivity"); return { environmentServerConfigsAtom: Atom.make(() => environmentConfigsMock.configs) }; }); vi.mock("../../connection/catalog", async () => { const { Atom } = await import("effect/reactivity"); return { environmentCatalog: { catalogValueAtom: Atom.make({ isReady: true, entries: new Map() }), }, }; }); vi.mock("../../state/shell", async () => { const { Atom } = await import("effect/reactivity"); const Option = await import("effect/Option"); return { environmentShell: { stateValueAtom: Atom.family((_id: EnvironmentId) => Atom.make({ status: "empty", generation: 0, removedAt: new Map(), snapshot: Option.none(), error: Option.none(), }), ), }, }; }); vi.mock("expo-notifications", () => ({ AndroidImportance: { NONE: 0, HIGH: 4 }, getNotificationChannelAsync: vi.fn(() => Promise.resolve(null)), addPushTokenListener: vi.fn(() => ({ remove: vi.fn() })), getDevicePushTokenAsync: vi.fn(() => Promise.resolve({ type: "ios", data: "apns-token" })), getPermissionsAsync: vi.fn(() => Promise.resolve({ granted: true })), })); vi.mock("expo-crypto", () => ({ CryptoDigestAlgorithm: { SHA1: "SHA-1", SHA256: "SHA-256", SHA384: "SHA-384", SHA512: "SHA-512", }, getRandomBytes: (byteCount: number) => new Uint8Array(NodeCrypto.randomBytes(byteCount)), getRandomBytesAsync: (byteCount: number) => Promise.resolve(new Uint8Array(NodeCrypto.randomBytes(byteCount))), digest: (algorithm: string, data: unknown) => { if (!(data instanceof Uint8Array)) { return Promise.reject(new TypeError("expo-crypto digest data must be a typed array.")); } return Promise.resolve( new Uint8Array(NodeCrypto.createHash(algorithm).update(data).digest()).buffer, ); }, })); vi.mock("expo", async () => { const { createNodeDpopKeysModule } = await import("../cloud/dpop.testing"); const dpopKeys = createNodeDpopKeysModule(); return { requireNativeModule: () => dpopKeys }; }); vi.mock("expo-secure-store", () => ({ getItemAsync: (key: string) => Promise.resolve(secureStore.get(key) ?? null), setItemAsync: (key: string, value: string) => { secureStore.set(key, value); return Promise.resolve(); }, })); vi.mock("react-native", () => ({ Platform: { get OS() { return "ios"; }, get Version() { return "18.0"; }, }, AppState: { get currentState() { return appStateMock.currentState; }, addEventListener: (_event: string, listener: (state: string) => void) => { appStateMock.listeners.push(listener); return { remove: () => { const index = appStateMock.listeners.indexOf(listener); if (index >= 0) { appStateMock.listeners.splice(index, 1); } }, }; }, }, })); vi.mock("../../lib/runtime", () => ({ runtime: { runPromiseExit: (operation: unknown) => new Promise((resolve) => { backgroundRuntime.pending.push({ operation, resolve }); }), }, })); vi.mock("../../persistence/imperative", () => ({ loadAgentAwarenessDeviceId: vi.fn(() => Promise.resolve("device-1")), loadOrCreateAgentAwarenessDeviceId: vi.fn(() => Promise.resolve("device-1")), loadPreferences: vi.fn(() => Promise.resolve({ liveActivitiesEnabled: false })), loadAgentAwarenessRegistrationRecord: vi.fn(() => Promise.resolve(registrationRecordStore.current), ), saveAgentAwarenessRegistrationRecord: vi.fn((record: { identity: string; signature: string }) => { registrationRecordStore.current = record; return Promise.resolve(); }), clearAgentAwarenessRegistrationRecord: vi.fn(() => { registrationRecordStore.current = null; return Promise.resolve(); }), })); function proofIat(proof: string): number { const payload = proof.split(".")[1]; if (!payload) { throw new Error("Missing DPoP payload."); } const decoded = JSON.parse(Buffer.from(payload, "base64url").toString("utf8")) as { readonly iat: number; }; return decoded.iat; } const activeAgentActivityRow = { environmentId: "env-1" as EnvironmentId, threadId: "thread-1" as ThreadId, projectTitle: "Project", threadTitle: "Thread", modelTitle: "gpt-5.4", phase: "running" as const, status: "Working", updatedAt: "2026-05-25T13:07:00.000Z", deepLink: "/threads/env-1/thread-1", }; const activeAgentActivitySnapshot = { aggregate: { title: "T3 Code", subtitle: "Agent work in progress", activeCount: 1, updatedAt: "2026-05-25T13:07:00.000Z", activities: [activeAgentActivityRow], }, } satisfies RelayAgentActivitySnapshotResponse; function snapshotRelayLayer( getAgentActivitySnapshot: ( input: Parameters[0], ) => Effect.Effect< RelayAgentActivitySnapshotResponse, ManagedRelay.ManagedRelayClientError > = () => Effect.succeed(activeAgentActivitySnapshot), ) { Constants.expoConfig!.extra = { relay: { url: "https://relay.example.test/", }, }; return Layer.succeed( ManagedRelay.ManagedRelayClient, ManagedRelay.ManagedRelayClient.of({ relayUrl: "https://relay.example.test", getT3ChatLink: () => Effect.die("unused"), createT3ChatLinkRequest: () => Effect.die("unused"), unlinkT3Chat: () => Effect.die("unused"), listEnvironments: () => Effect.die("unused"), listDevices: () => Effect.die("unused"), createEnvironmentLinkChallenge: () => Effect.die("unused"), linkEnvironment: () => Effect.die("unused"), unlinkEnvironment: () => Effect.die("unused"), getEnvironmentStatus: () => Effect.die("unused"), connectEnvironment: () => Effect.die("unused"), registerDevice: () => Effect.die("unused"), unregisterDevice: () => Effect.die("unused"), registerLiveActivity: () => Effect.succeed({ ok: true }), getAgentActivitySnapshot, resetTokenCache: Effect.void, }), ); } const layerRelayTest = ManagedRelayLayer.layer("https://relay.example.test").pipe( Layer.provide(Layer.mergeAll(FetchHttpClient.layer, Dpop.layer)), ); function setTestAtom(atom: Atom.Atom, value: A): void { if (!Atom.isWritable(atom)) throw new Error("Expected a writable fixture atom"); appAtomRegistry.set(atom, value); } const liveEnvironmentId = EnvironmentId.make("env-1"); const liveShellUpdatedAt = "2026-10-02T12:00:00.000Z"; const liveProjectId = ProjectId.make("project-1"); function setLiveShell( phase: "starting" | "running" | "ready" | null, status: EnvironmentShellState["status"] = "live", now = liveShellUpdatedAt, ): void { const project: OrchestrationProjectShell = { id: liveProjectId, title: "Live project", workspaceRoot: "/synthetic/project", defaultModelSelection: null, scripts: [], createdAt: now, updatedAt: now, }; const thread = makeRawThreadShell({ id: ThreadId.make("local-thread"), projectId: liveProjectId, title: "Live task", modelSelection: { instanceId: ProviderInstanceId.make("codex"), model: "test-model" }, createdAt: DateTime.makeUnsafe(now), updatedAt: DateTime.makeUnsafe(now), status: phase === "ready" ? "completed" : (phase ?? "idle"), }); setTestAtom(environmentShell.stateValueAtom(liveEnvironmentId), { status, generation: 0, removedAt: new Map(), error: Option.none(), snapshot: Option.some({ projects: [project], threads: phase === null ? [] : [thread], snapshotSequence: 1, archivedThreads: [], schemaVersion: 1, }), }); } function addLiveEnvironment(): void { setTestAtom(environmentCatalog.catalogValueAtom, { isReady: true, entries: new Map([ [ liveEnvironmentId, { target: new PrimaryConnectionTarget({ environmentId: liveEnvironmentId, label: "Live environment", httpBaseUrl: "https://local.example.test", wsBaseUrl: "wss://local.example.test/ws", }), profile: Option.none(), enabled: true, }, ], ]), }); setLiveShell(null); } const runBackgroundOperations = Effect.fn("TestRemoteRegistration.runBackgroundOperations")( function* () { let idlePasses = 0; // oxlint-disable-next-line t3code/no-polling-loop-in-tests -- This harness drains mocked runtime jobs and their promise continuations, not external I/O or elapsed time. for (;;) { yield* Effect.promise(() => Promise.resolve()); const pending = backgroundRuntime.pending.shift(); if (!pending) { idlePasses++; if (idlePasses >= 3) { return; } continue; } idlePasses = 0; const exit = yield* Effect.exit( pending.operation as Effect.Effect< unknown, AgentAwarenessRegistrationError, ManagedRelay.ManagedRelayClient >, ); yield* Effect.sync(() => { pending.resolve(exit); }); } }, ); describe("makeRelayDeviceRegistrationRequest", () => { beforeEach(() => { vi.restoreAllMocks(); // Freshness windows compare against fixture timestamps, not the runner clock. vi.spyOn(Date, "now").mockReturnValue(Date.parse(liveShellUpdatedAt)); vi.mocked(Notifications.getDevicePushTokenAsync).mockResolvedValue({ type: "ios", data: "apns-token", }); vi.mocked(Notifications.getPermissionsAsync).mockReset(); vi.mocked(Notifications.getPermissionsAsync).mockResolvedValue({ granted: true, } as Awaited>); vi.mocked(Notifications.getNotificationChannelAsync).mockResolvedValue(null); vi.unstubAllGlobals(); vi.stubGlobal("__DEV__", false); secureStore.clear(); backgroundRuntime.pending.length = 0; Constants.expoConfig!.extra = {}; __resetAgentAwarenessRemoteRegistrationForTest(); appAtomRegistry.reset(); appStateMock.currentState = "active"; appStateMock.listeners.length = 0; registrationRecordStore.current = null; vi.mocked(saveAgentAwarenessRegistrationRecord).mockClear(); vi.mocked(loadAgentAwarenessRegistrationRecord).mockClear(); vi.mocked(clearAgentAwarenessRegistrationRecord).mockClear(); vi.mocked(loadOrCreateAgentAwarenessDeviceId).mockResolvedValue("device-1"); vi.mocked(loadPreferences).mockReset(); vi.mocked(loadPreferences).mockResolvedValue({ liveActivitiesEnabled: false } as Preferences); widgetMocks.getInstances.mockReset(); widgetMocks.getInstances.mockReturnValue([]); widgetMocks.start.mockReset(); widgetMocks.start.mockReturnValue({ getId: () => "activity-1", getPushToken: () => Promise.resolve(null), addPushTokenListener: vi.fn(), }); widgetMocks.dismissEnded.mockReset(); environmentConfigsMock.configs.clear(); vi.mocked(publishAgentActivityWidget).mockReset().mockReturnValue(true); vi.mocked(agentWidgetToken).mockReset().mockReturnValue(null); vi.mocked(configureAgentWidgetRefresh).mockClear(); vi.mocked(clearAgentWidgetRefresh).mockClear(); }); it.effect.each(["unchanged", "sign-out", "account switch"] as const)( "keeps existing Live Activity tokens with their owner across %s during widget refresh", (transition) => Effect.gen(function* () { const readStarted = yield* Deferred.make(); const finishRead = yield* Deferred.make(); const activity = { getId: () => "activity-1", getPushToken: vi.fn(() => Promise.resolve("old-account-activity-token")), addPushTokenListener: vi.fn(), end: vi.fn(() => Promise.resolve()), }; widgetMocks.getInstances.mockReturnValue([activity]); const register = vi.fn( () => Effect.succeed({ ok: true }), ); const client = yield* ManagedRelay.ManagedRelayClient; setAgentAwarenessRelayTokenProvider(() => Promise.resolve("user-a-token"), "user-a"); backgroundRuntime.pending.length = 0; const refresh = yield* refreshActiveLiveActivityRemoteRegistration().pipe( Effect.provideService(ManagedRelay.ManagedRelayClient, { ...client, registerLiveActivity: register, getAgentActivitySnapshot: () => Deferred.succeed(readStarted, undefined).pipe( Effect.andThen(Deferred.await(finishRead)), Effect.as(activeAgentActivitySnapshot), ), }), Effect.forkChild, ); yield* Deferred.await(readStarted); if (transition !== "unchanged") { setAgentAwarenessRelayTokenProvider(null); expect(activity.end).toHaveBeenCalledExactlyOnceWith("immediate"); widgetMocks.getInstances.mockReturnValue([]); if (transition === "account switch") { setAgentAwarenessRelayTokenProvider(() => Promise.resolve("user-b-token"), "user-b"); } } yield* Deferred.succeed(finishRead, undefined); yield* Fiber.join(refresh); if (transition === "unchanged") { expect(register).toHaveBeenCalledExactlyOnceWith({ clerkToken: "user-a-token", payload: { deviceId: "device-1", activityPushToken: "old-account-activity-token" }, }); } else { expect(register).not.toHaveBeenCalled(); expect(activity.getPushToken).not.toHaveBeenCalled(); } }).pipe(Effect.provide(snapshotRelayLayer()), Effect.scoped), ); it.effect.each( (["global", "scoped"] as const).flatMap((blockedRead) => (["scope change", "sign-out", "account switch", "background"] as const).map((transition) => ({ blockedRead, transition, })), ), )( "keeps final relay priming independent of $transition during $blockedRead without crossing account ownership", ({ blockedRead, transition }) => Effect.gen(function* () { if (blockedRead === "scoped") addLiveEnvironment(); vi.mocked(loadPreferences).mockResolvedValue({ liveActivitiesEnabled: true, } as Preferences); const readStarted = yield* Deferred.make(); const finishRead = yield* Deferred.make(); const activity = { getId: () => "activity-1", getPushToken: vi.fn(() => Promise.resolve("activity-token")), addPushTokenListener: vi.fn(), }; widgetMocks.start.mockReturnValue(activity); const remoteSnapshot: RelayAgentActivitySnapshotResponse = { aggregate: { ...activeAgentActivitySnapshot.aggregate, activities: activeAgentActivitySnapshot.aggregate.activities.map((row) => ({ ...row, environmentId: EnvironmentId.make("remote-environment"), })), }, }; let globalReads = 0; let scopedReads = 0; const layer = snapshotRelayLayer(({ excludedEnvironmentIds }) => { const kind = excludedEnvironmentIds ? "scoped" : "global"; const ordinal = excludedEnvironmentIds ? ++scopedReads : ++globalReads; const snapshot = excludedEnvironmentIds ? { ...remoteSnapshot, excludedEnvironmentIds } : remoteSnapshot; return ordinal === 1 && kind === blockedRead ? Deferred.succeed(readStarted, undefined).pipe( Effect.andThen(Deferred.await(finishRead)), Effect.as(snapshot), ) : Effect.succeed(snapshot); }); setAgentAwarenessRelayTokenProvider(() => Promise.resolve("clerk-token-user-a"), "user-a"); backgroundRuntime.pending.length = 0; const prime = yield* refreshActiveLiveActivityRemoteRegistration().pipe( Effect.provide(layer), Effect.forkChild, ); yield* Deferred.await(readStarted); if (transition === "scope change") { if (blockedRead === "global") addLiveEnvironment(); else setTestAtom(environmentCatalog.catalogValueAtom, { isReady: true, entries: new Map(), }); // The in-flight read rechecks the scope before publishing; no second // foreground reconciliation is needed before that first response. expect(backgroundRuntime.pending).toHaveLength(0); } else if (transition === "background") { appStateMock.currentState = "background"; for (const listener of appStateMock.listeners) listener("background"); } else { setAgentAwarenessRelayTokenProvider(null); if (transition === "account switch") setAgentAwarenessRelayTokenProvider( () => Promise.resolve("clerk-token-user-b"), "user-b", ); } const widgetBeforeRelease = vi.mocked(publishAgentActivityWidget).mock.lastCall?.[0]; yield* Deferred.succeed(finishRead, undefined); yield* Fiber.join(prime); if (transition === "scope change") { expect({ globalReads, scopedReads }).toEqual({ globalReads: 1, scopedReads: 1, }); expect(backgroundRuntime.pending).toHaveLength(0); expect(widgetMocks.start).toHaveBeenCalledExactlyOnceWith( expect.objectContaining({ activeCount: 1, activities: remoteSnapshot.aggregate!.activities, }), expect.any(Date), ); } else if (transition === "background") { expect(widgetMocks.start).not.toHaveBeenCalled(); expect(activity.getPushToken).not.toHaveBeenCalled(); appStateMock.currentState = "active"; for (const listener of appStateMock.listeners) listener("active"); expect(backgroundRuntime.pending).toHaveLength(1); const foreground = backgroundRuntime.pending.shift(); if (!foreground) throw new Error("Expected foreground Live Activity reconciliation"); const exit = yield* Effect.exit( foreground.operation as Effect.Effect, ).pipe(Effect.provide(layer)); foreground.resolve(exit); expect(Exit.isSuccess(exit)).toBe(true); expect(widgetMocks.start).toHaveBeenCalledExactlyOnceWith( expect.objectContaining({ activeCount: 1, activities: remoteSnapshot.aggregate!.activities, }), expect.any(Date), ); expect(activity.getPushToken).toHaveBeenCalledTimes(1); expect(backgroundRuntime.pending).toHaveLength(0); } else { expect(globalReads).toBe(1); expect(widgetMocks.start).not.toHaveBeenCalled(); expect(activity.getPushToken).not.toHaveBeenCalled(); expect(widgetBeforeRelease?.activities).toEqual([]); expect(publishAgentActivityWidget).toHaveBeenLastCalledWith(widgetBeforeRelease); } }).pipe(Effect.scoped), ); it.each(["sign-out", "account switch"])( "does not restore local-work widget data after %s during preference loading", async (transition) => { let finishPreferences!: (preferences: Preferences) => void; const preferences = new Promise((resolve) => { finishPreferences = resolve; }); vi.mocked(loadPreferences).mockReturnValueOnce(preferences); setAgentAwarenessRelayTokenProvider(() => Promise.resolve("clerk-token-user-a"), "user-a"); environmentConfigsMock.configs.set("env-1", { environment: { capabilities: { agentActivityPublishing: true } }, }); armAgentAwarenessLiveActivityForLocalWork({ environmentId: "env-1" as EnvironmentId, threadTitle: "Previous account thread", projectTitle: "Previous account project", }); expect(loadPreferences).toHaveBeenCalledTimes(1); // Register the same catch/then depth after the production continuation. // Its receipt settles after the already-registered preference callback, // without a timer, polling, or executing queued relay operations. const preferenceCallbackDrained = preferences.catch(() => null).then(() => undefined); setAgentAwarenessRelayTokenProvider(null); if (transition === "account switch") { setAgentAwarenessRelayTokenProvider(() => Promise.resolve("clerk-token-user-b"), "user-b"); } expect(publishAgentActivityWidget).toHaveBeenLastCalledWith( expect.objectContaining({ activeCount: transition === "account switch" ? null : 0, activities: [], }), ); finishPreferences({ liveActivitiesEnabled: true } as Preferences); await preferenceCallbackDrained; expect(publishAgentActivityWidget).toHaveBeenLastCalledWith( expect.objectContaining({ activeCount: transition === "account switch" ? null : 0, activities: [], }), ); expect(widgetMocks.start).not.toHaveBeenCalled(); }, ); it("still arms local work after a same-account token refresh during preference loading", async () => { let finishPreferences!: (preferences: Preferences) => void; const preferences = new Promise((resolve) => { finishPreferences = resolve; }); vi.mocked(loadPreferences).mockReturnValueOnce(preferences); setAgentAwarenessRelayTokenProvider(() => Promise.resolve("clerk-token-user-a"), "user-a"); environmentConfigsMock.configs.set("env-1", { environment: { capabilities: { agentActivityPublishing: true } }, }); armAgentAwarenessLiveActivityForLocalWork({ environmentId: "env-1" as EnvironmentId, threadTitle: "Current account thread", projectTitle: "Current account project", }); const preferenceCallbackDrained = preferences.catch(() => null).then(() => undefined); setAgentAwarenessRelayTokenProvider(() => Promise.resolve("refreshed-token-user-a"), "user-a"); finishPreferences({ liveActivitiesEnabled: true } as Preferences); await preferenceCallbackDrained; expect(widgetMocks.start).toHaveBeenCalledTimes(1); expect(widgetMocks.start).toHaveBeenLastCalledWith( expect.objectContaining({ activeCount: 1, activities: [expect.objectContaining({ threadTitle: "Current account thread" })], }), expect.any(Date), ); expect(publishAgentActivityWidget).toHaveBeenCalledExactlyOnceWith( expect.objectContaining({ activeCount: null, activities: [] }), ); }); it("disables push features in Personal Team relay registrations", () => { Constants.expoConfig!.extra = { iosPersonalTeamBuild: true }; expect( makeRelayDeviceRegistrationRequest({ deviceId: "device-1", label: "Julius's iPhone", iosMajorVersion: 18, appVersion: "1.0.0", pushToken: "apns-token", pushToStartToken: "push-to-start-token", notificationsEnabled: true, preferences: {}, }).preferences, ).toMatchObject({ liveActivitiesEnabled: false, notificationsEnabled: false, }); }); it.effect("registers one push-token listener per Live Activity across wrappers", () => { const addPushTokenListener = vi.fn(); // getInstances() returns a new wrapper for the same native activity each call. const wrapper = () => ({ getId: () => "activity-1", getPushToken: vi.fn(() => Promise.resolve(null)), addPushTokenListener, }); return Effect.gen(function* () { expect(yield* registerLiveActivityPushToken({ activity: wrapper() as never })).toBe(false); expect(yield* registerLiveActivityPushToken({ activity: wrapper() as never })).toBe(false); expect(addPushTokenListener).toHaveBeenCalledTimes(1); }).pipe(Effect.provide(layerRelayTest)); }); it.effect("registers a Live Activity push token that rotates after registration", () => { const registeredTokens: Array = []; vi.stubGlobal("fetch", async (request: RequestInfo | URL, init?: RequestInit) => { const url = request instanceof Request ? request.url : String(request); if (url.endsWith("/v1/client/dpop-token")) { return Response.json({ access_token: "relay-dpop-token", issued_token_type: "urn:ietf:params:oauth:token-type:access_token", token_type: "DPoP", expires_in: 300, scope: "mobile:registration", }); } if (url.endsWith("/v1/mobile/live-activities")) { const body = request instanceof Request ? await request.text() : String(init?.body); registeredTokens.push( (JSON.parse(body) as { readonly activityPushToken: string }).activityPushToken, ); } return Response.json({ ok: true }); }); Constants.expoConfig!.extra = { relay: { url: "https://relay.example.test/" } }; setAgentAwarenessRelayTokenProvider(() => Promise.resolve("clerk-token-user-a")); let tokenListener: ((event: { readonly pushToken: string }) => void) | undefined; const activity = { getId: () => "activity-1", getPushToken: vi.fn(() => Promise.resolve("activity-token")), addPushTokenListener: vi.fn((listener: typeof tokenListener) => { tokenListener = listener; return { remove: vi.fn() }; }), }; return Effect.gen(function* () { yield* runBackgroundOperations(); expect(yield* registerLiveActivityPushToken({ activity: activity as never })).toBe(true); tokenListener?.({ pushToken: "rotated-activity-token" }); yield* runBackgroundOperations(); expect(registeredTokens).toEqual(["activity-token", "rotated-activity-token"]); }).pipe( Effect.provideService(FetchHttpClient.Fetch, globalThis.fetch), Effect.provide(layerRelayTest), ); }); it.effect("registers a rotated Live Activity token only after an older registration", () => { const arrivals: Array = []; let openOldRequest: (() => void) | undefined; const oldRequestGate = new Promise((resolve) => { openOldRequest = resolve; }); let markOldRequestArrived: (() => void) | undefined; const oldRequestArrived = new Promise((resolve) => { markOldRequestArrived = resolve; }); vi.stubGlobal("fetch", async (request: RequestInfo | URL, init?: RequestInit) => { const url = request instanceof Request ? request.url : String(request); if (url.endsWith("/v1/client/dpop-token")) { return Response.json({ access_token: "relay-dpop-token", issued_token_type: "urn:ietf:params:oauth:token-type:access_token", token_type: "DPoP", expires_in: 300, scope: "mobile:registration", }); } if (url.endsWith("/v1/mobile/live-activities")) { const body = request instanceof Request ? await request.text() : String(init?.body); const token = (JSON.parse(body) as { readonly activityPushToken: string }) .activityPushToken; arrivals.push(token); if (token === "activity-token") { markOldRequestArrived?.(); await oldRequestGate; } } return Response.json({ ok: true }); }); Constants.expoConfig!.extra = { relay: { url: "https://relay.example.test/" } }; setAgentAwarenessRelayTokenProvider(() => Promise.resolve("clerk-token-user-a")); let tokenListener: ((event: { readonly pushToken: string }) => void) | undefined; const activity = { getId: () => "activity-1", getPushToken: vi.fn(() => Promise.resolve("activity-token")), addPushTokenListener: vi.fn((listener: typeof tokenListener) => { tokenListener = listener; return { remove: vi.fn() }; }), }; return Effect.gen(function* () { yield* runBackgroundOperations(); const lookup = yield* Effect.forkChild( registerLiveActivityPushToken({ activity: activity as never }), ); yield* Effect.promise(() => oldRequestArrived); tokenListener?.({ pushToken: "rotated-activity-token" }); const deviceIdLookups = vi.mocked(loadOrCreateAgentAwarenessDeviceId).mock.calls.length; const rotated = backgroundRuntime.pending.shift()!; // Starting immediately runs the listener's registration until it suspends: on the // activity lock, or, without one, at its device-id lookup. const rotatedRegistration = yield* Effect.forkChild( Effect.exit( rotated.operation as Effect.Effect< unknown, AgentAwarenessRegistrationError, ManagedRelay.ManagedRelayClient >, ), { startImmediately: true }, ); expect(vi.mocked(loadOrCreateAgentAwarenessDeviceId).mock.calls).toHaveLength( deviceIdLookups, ); expect(arrivals).toEqual(["activity-token"]); openOldRequest?.(); yield* Fiber.join(lookup); rotated.resolve(yield* Fiber.join(rotatedRegistration)); expect(arrivals).toEqual(["activity-token", "rotated-activity-token"]); }).pipe( Effect.provideService(FetchHttpClient.Fetch, globalThis.fetch), Effect.provide(layerRelayTest), ); }); it.effect("still registers the active card when ended-card cleanup throws", () => { const registrations: unknown[] = []; vi.stubGlobal("fetch", async (input: RequestInfo | URL, init?: RequestInit) => { const request = new Request(input, init); if (request.url.endsWith("/v1/client/dpop-token")) { return Response.json({ access_token: "relay-dpop-token", issued_token_type: "urn:ietf:params:oauth:token-type:access_token", token_type: "DPoP", expires_in: 300, scope: "mobile:registration", }); } if (request.url.endsWith("/v1/mobile/live-activities")) { registrations.push(await request.json()); } return Response.json({ ok: true }); }); Constants.expoConfig!.extra = { relay: { url: "https://relay.example.test/" } }; setAgentAwarenessRelayTokenProvider(() => Promise.resolve("clerk-token-user-a")); const activity = { getId: () => "activity-1", getPushToken: vi.fn(() => Promise.resolve("activity-token")), addPushTokenListener: vi.fn(), end: vi.fn(), }; return Effect.gen(function* () { yield* runBackgroundOperations(); widgetMocks.dismissEnded.mockReset(); widgetMocks.dismissEnded.mockImplementation(() => { throw new Error("Cannot find function dismissEnded"); }); widgetMocks.getInstances.mockReturnValue([activity] as never); for (const listener of appStateMock.listeners) listener("active"); yield* runBackgroundOperations(); expect(widgetMocks.dismissEnded).toHaveBeenCalledOnce(); expect(registrations).toEqual([ { deviceId: "device-1", activityPushToken: "activity-token" }, ]); expect(activity.end).not.toHaveBeenCalled(); expect(widgetMocks.start).not.toHaveBeenCalled(); }).pipe( Effect.provideService(FetchHttpClient.Fetch, globalThis.fetch), Effect.provide(layerRelayTest), ); }); it.effect("refreshes the widget after a delayed Live Activity push token registers", () => { let onPushToken: ((event: { pushToken: string }) => void) | undefined; const activity = { getId: () => "activity-1", getPushToken: vi.fn(() => Promise.resolve(null)), addPushTokenListener: vi.fn((listener: (event: { pushToken: string }) => void) => { onPushToken = listener; return { remove: vi.fn() }; }), }; setAgentAwarenessRelayTokenProvider(() => Promise.resolve("clerk-token-user-a")); return Effect.gen(function* () { expect(yield* registerLiveActivityPushToken({ activity: activity as never })).toBe(false); expect(onPushToken).toBeDefined(); onPushToken?.({ pushToken: "delayed-activity-token" }); yield* runBackgroundOperations(); expect(publishAgentActivityWidget).toHaveBeenCalledWith( expect.objectContaining({ activeCount: 1, subtitle: "Agent work in progress", }), ); }).pipe(Effect.provide(snapshotRelayLayer())); }); it.effect("publishes the home-screen widget when a Live Activity is already armed", () => { const activity = { getId: () => "activity-1", getPushToken: vi.fn(() => Promise.resolve("activity-token")), addPushTokenListener: vi.fn(), start: vi.fn(), update: vi.fn(), end: vi.fn(), }; widgetMocks.getInstances.mockReturnValue([activity] as never); setAgentAwarenessRelayTokenProvider(() => Promise.resolve("clerk-token-user-a")); return Effect.gen(function* () { yield* refreshActiveLiveActivityRemoteRegistration(); expect(publishAgentActivityWidget).toHaveBeenCalledWith( expect.objectContaining({ activeCount: 1, subtitle: "Agent work in progress", activities: [expect.objectContaining({ status: "Working" })], }), ); expect(widgetMocks.start).not.toHaveBeenCalled(); expect(activity.start).not.toHaveBeenCalled(); }).pipe(Effect.provide(snapshotRelayLayer())); }); it.effect("publishes the home-screen widget when Live Activities are disabled", () => { setAgentAwarenessRelayTokenProvider(() => Promise.resolve("clerk-token-user-a")); return Effect.gen(function* () { yield* refreshActiveLiveActivityRemoteRegistration(); expect(publishAgentActivityWidget).toHaveBeenCalledWith( expect.objectContaining({ activeCount: 1, subtitle: "Agent work in progress", }), ); expect(widgetMocks.start).not.toHaveBeenCalled(); }).pipe(Effect.provide(snapshotRelayLayer())); }); it("ends local Live Activities and clears the home-screen widget on cloud sign-out", () => { widgetMocks.dismissEnded.mockReset(); const end = vi.fn(() => Promise.resolve()); const activity = { getId: () => "activity-1", getPushToken: vi.fn(() => Promise.resolve("activity-token")), addPushTokenListener: vi.fn(), end, }; widgetMocks.getInstances.mockReturnValue([activity] as never); setAgentAwarenessRelayTokenProvider(() => Promise.resolve("clerk-token-user-a")); expect(appStateMock.listeners).toHaveLength(1); setAgentAwarenessRelayTokenProvider(null); expect(end).toHaveBeenCalledWith("immediate"); expect(publishAgentActivityWidget).toHaveBeenCalledWith( expect.objectContaining({ title: "T3 Code", subtitle: "Sign in to see agent activity", isSignedOut: true, activeCount: 0, activities: [], }), ); widgetMocks.dismissEnded.mockReset(); expect(appStateMock.listeners).toHaveLength(0); vi.mocked(publishAgentActivityWidget).mockClear(); vi.mocked(clearAgentWidgetRefresh).mockClear(); setAgentAwarenessRelayTokenProvider(null); expect(clearAgentWidgetRefresh).toHaveBeenCalledOnce(); expect(publishAgentActivityWidget).toHaveBeenCalledWith( expect.objectContaining({ isSignedOut: true, subtitle: "Sign in to see agent activity" }), ); }); it.effect("registers the APNs device when cloud auth becomes available", () => { addLiveEnvironment(); setLiveShell("running"); let nativeObservation: Parameters[0] | undefined; vi.mocked(publishAgentActivityWidget).mockImplementation((props) => { nativeObservation = props; return true; }); vi.mocked(agentWidgetToken).mockImplementation((_identity, url) => { if (url) nativeObservation = undefined; return "a".repeat(64); }); let recoveryAtRegistration: Parameters | undefined; const fetchMock = vi.fn((request: RequestInfo | URL) => { const url = request instanceof Request ? request.url : String(request); if (url.endsWith("/v1/mobile/devices")) { recoveryAtRegistration = vi.mocked(configureAgentWidgetRefresh).mock.lastCall; } return Promise.resolve( Response.json( url.endsWith("/v1/client/dpop-token") ? { access_token: "relay-dpop-token", issued_token_type: "urn:ietf:params:oauth:token-type:access_token", token_type: "DPoP", expires_in: 300, scope: "mobile:registration", } : { ok: true }, ), ); }); vi.stubGlobal("fetch", fetchMock); Constants.expoConfig!.extra = { relay: { url: "https://relay.example.test/", }, }; setAgentAwarenessRelayTokenProvider(() => Promise.resolve("clerk-token-user-a"), "user-a"); return Effect.gen(function* () { yield* runBackgroundOperations(); expect(nativeObservation?.activities).toEqual([ expect.objectContaining({ threadId: "local-thread", phase: "running" }), ]); expect(agentWidgetToken).toHaveBeenLastCalledWith("user-a", "https://relay.example.test"); expect(recoveryAtRegistration).toEqual(["https://relay.example.test", "a".repeat(64)]); const deviceCall = fetchMock.mock.calls.find((call) => { const request = call[0]; const url = request instanceof Request ? request.url : String(request); return url === "https://relay.example.test/v1/mobile/devices"; }); expect(deviceCall).toBeDefined(); const [request, init] = deviceCall as unknown as [unknown, RequestInit | undefined]; const url = request instanceof Request ? request.url : String(request); const method = request instanceof Request ? request.method : init?.method; const headers = request instanceof Request ? request.headers : new Headers(init?.headers); const dpop = headers.get("dpop"); expect(url).toBe("https://relay.example.test/v1/mobile/devices"); expect(method).toBe("POST"); expect(headers.get("authorization")).toBe("DPoP relay-dpop-token"); expect(dpop).toEqual(expect.any(String)); if (!dpop) { throw new Error("Missing DPoP header."); } expect( verifyDpopProof({ proof: dpop, method: "POST", url: "https://relay.example.test/v1/mobile/devices", expectedAccessToken: "relay-dpop-token", nowEpochSeconds: proofIat(dpop), }), ).toMatchObject({ ok: true }); const payload = request instanceof Request ? yield* Effect.promise(() => request.json()) : JSON.parse(String(init?.body)); expect(payload.widgetAccessToken).toBe("a".repeat(64)); expect(configureAgentWidgetRefresh).toHaveBeenLastCalledWith( "https://relay.example.test", "a".repeat(64), ); expect(getAgentAwarenessRegistrationStatus()).toBe("registered"); releaseAgentAwarenessRelayTokenProvider(); expect(clearAgentWidgetRefresh).not.toHaveBeenCalled(); setAgentAwarenessRelayTokenProvider(null); expect(clearAgentWidgetRefresh).toHaveBeenCalledOnce(); }).pipe(Effect.provide(layerRelayTest)); }); it.effect("keeps a registered status when a later refresh fails", () => { Constants.expoConfig!.extra = { relay: { url: "https://relay.example.test/", }, }; setAgentAwarenessRelayTokenProvider(() => Promise.resolve("clerk-token-user-a")); return Effect.gen(function* () { yield* runBackgroundOperations(); expect(getAgentAwarenessRegistrationStatus()).toBe("registered"); vi.mocked(loadOrCreateAgentAwarenessDeviceId).mockRejectedValueOnce( new Error("transient failure"), ); yield* refreshAgentAwarenessRegistration(); expect(getAgentAwarenessRegistrationStatus()).toBe("registered"); }).pipe(Effect.provide(layerRelayTest)); }); it.effect("does not re-register the same account when nothing has changed", () => { Constants.expoConfig!.extra = { relay: { url: "https://relay.example.test/", }, }; setAgentAwarenessRelayTokenProvider(() => Promise.resolve("clerk-token-user-a")); return Effect.gen(function* () { yield* refreshAgentAwarenessRegistration(); expect(getAgentAwarenessRegistrationStatus()).toBe("registered"); expect(saveAgentAwarenessRegistrationRecord).toHaveBeenCalledTimes(1); expect(registrationRecordStore.current).not.toBeNull(); vi.mocked(saveAgentAwarenessRegistrationRecord).mockClear(); yield* refreshAgentAwarenessRegistration(); expect(getAgentAwarenessRegistrationStatus()).toBe("registered"); expect(saveAgentAwarenessRegistrationRecord).not.toHaveBeenCalled(); }).pipe(Effect.provide(layerRelayTest)); }); it.effect("continues queued device registration after a failed auth lookup", () => { Constants.expoConfig!.extra = { relay: { url: "https://relay.example.test/", }, }; const tokenProvider = vi .fn<() => Promise>() .mockRejectedValueOnce(new Error("auth unavailable")) .mockResolvedValue("clerk-token-user-a"); setAgentAwarenessRelayTokenProvider(tokenProvider); const tokenListener = vi.mocked(Notifications.addPushTokenListener).mock.calls.at(-1)?.[0]; expect(tokenListener).toBeDefined(); tokenListener?.({ type: "ios", data: "rotated-apns-token" } as never); return Effect.gen(function* () { yield* runBackgroundOperations(); expect(backgroundRuntime.pending).toHaveLength(0); // Device registration retries after the first auth miss, and the // home-screen widget refresh independently reads the relay token. expect(tokenProvider).toHaveBeenCalledTimes(3); }).pipe(Effect.provide(layerRelayTest)); }); it.effect.each(["ios", "android"] as const)( "does not enable %s notifications when a token rotates after permission is revoked", (os) => { vi.mocked(loadPreferences).mockResolvedValue({ liveActivitiesEnabled: true }); vi.spyOn(Platform, "OS", "get").mockReturnValue(os); vi.spyOn(Platform, "Version", "get").mockReturnValue(os === "ios" ? 18 : 36); vi.mocked(Notifications.getDevicePushTokenAsync).mockResolvedValue({ type: os, data: "initial", }); const registrations: unknown[] = []; vi.stubGlobal("fetch", async (input: RequestInfo | URL, init?: RequestInit) => { const request = new Request(input, init); if (request.url.endsWith("/v1/client/dpop-token")) { return Response.json({ access_token: "dpop", issued_token_type: "urn:ietf:params:oauth:token-type:access_token", token_type: "DPoP", expires_in: 300, scope: "mobile:registration", }); } registrations.push(await request.json()); return Response.json({ ok: true }); }); Constants.expoConfig!.extra = { relay: { url: "https://permission-relay.example.test" } }; setAgentAwarenessRelayTokenProvider(() => Promise.resolve("clerk"), "user-a"); return Effect.gen(function* () { yield* runBackgroundOperations(); expect(registrations.at(-1)).toMatchObject({ preferences: { notificationsEnabled: true, liveActivitiesEnabled: true }, }); vi.mocked(Notifications.getPermissionsAsync).mockResolvedValueOnce({ granted: false, } as Awaited>); const listener = vi.mocked(Notifications.addPushTokenListener).mock.calls.at(-1)![0]; listener({ type: os, data: "rotated" }); yield* runBackgroundOperations(); expect(registrations.at(-1)).toMatchObject({ preferences: { notificationsEnabled: false, liveActivitiesEnabled: os === "ios" }, }); if (os === "android") { expect(registrations.at(-1)).toMatchObject({ pushToken: "rotated" }); vi.mocked(Notifications.getPermissionsAsync).mockResolvedValueOnce({ granted: false, } as Awaited>); yield* refreshAgentAwarenessRegistration(); expect(registrations.at(-1)).toMatchObject({ pushToken: "initial", preferences: { notificationsEnabled: false, liveActivitiesEnabled: false }, }); } else { expect(registrations.at(-1)).not.toHaveProperty("pushToken"); } }).pipe( Effect.provideService(FetchHttpClient.Fetch, globalThis.fetch), Effect.provide( ManagedRelayLayer.layer("https://permission-relay.example.test").pipe( Layer.provide(Layer.mergeAll(FetchHttpClient.layer, Dpop.layer)), ), ), ); }, ); it.effect.each(["blocked", "unavailable"] as const)( "keeps Android push delivery registered when the alert channel is %s", (channelState) => { vi.mocked(loadPreferences).mockResolvedValue({ liveActivitiesEnabled: true }); vi.spyOn(Platform, "OS", "get").mockReturnValue("android"); vi.spyOn(Platform, "Version", "get").mockReturnValue(36); vi.mocked(Notifications.getDevicePushTokenAsync).mockResolvedValue({ type: "android", data: "fcm-token", }); vi.mocked(Notifications.getNotificationChannelAsync).mockResolvedValue({ id: "agent-alerts", name: "Agent alerts", importance: Notifications.AndroidImportance.NONE, } as Awaited>); if (channelState === "unavailable") { vi.mocked(Notifications.getNotificationChannelAsync).mockRejectedValue( new Error("Android channel lookup failed"), ); } const registrations: unknown[] = []; vi.stubGlobal("fetch", async (input: RequestInfo | URL, init?: RequestInit) => { const request = new Request(input, init); if (request.url.endsWith("/v1/client/dpop-token")) { return Response.json({ access_token: "dpop", issued_token_type: "urn:ietf:params:oauth:token-type:access_token", token_type: "DPoP", expires_in: 300, scope: "mobile:registration", }); } registrations.push(await request.json()); return Response.json({ ok: true }); }); Constants.expoConfig!.extra = { relay: { url: "https://relay.example.test" } }; setAgentAwarenessRelayTokenProvider(() => Promise.resolve("clerk"), "user-a"); return Effect.gen(function* () { yield* runBackgroundOperations(); expect(registrations.at(-1)).toMatchObject({ pushToken: "fcm-token", preferences: { notificationsEnabled: false, liveActivitiesEnabled: true }, }); expect(getAgentAwarenessRegistrationStatus()).toBe("registered"); const listener = vi.mocked(Notifications.addPushTokenListener).mock.calls.at(-1)![0]; listener({ type: "android", data: "rotated-fcm-token" }); yield* runBackgroundOperations(); expect(registrations.at(-1)).toMatchObject({ pushToken: "rotated-fcm-token", preferences: { notificationsEnabled: false, liveActivitiesEnabled: true }, }); vi.mocked(Notifications.getNotificationChannelAsync).mockResolvedValue(null); yield* refreshAgentAwarenessRegistration(); expect(registrations.at(-1)).toMatchObject({ pushToken: "fcm-token", preferences: { notificationsEnabled: true }, }); }).pipe( Effect.provideService(FetchHttpClient.Fetch, globalThis.fetch), Effect.provide(layerRelayTest), ); }, ); it.effect("preserves relay rejection errors with React Native response headers", () => { vi.spyOn(Platform, "OS", "get").mockReturnValue("android"); vi.mocked(Notifications.getDevicePushTokenAsync).mockResolvedValue({ type: "android", data: "fcm-token", }); const rejectedResponse = new Response("Unsupported device platform", { status: 400 }); Object.defineProperty(rejectedResponse.headers, "getSetCookie", { value: undefined }); vi.stubGlobal("fetch", (request: RequestInfo | URL) => { const url = request instanceof Request ? request.url : String(request); const response = url.endsWith("/v1/client/dpop-token") ? Response.json({ access_token: "relay-dpop-token", issued_token_type: "urn:ietf:params:oauth:token-type:access_token", token_type: "DPoP", expires_in: 300, scope: "mobile:registration", }) : rejectedResponse; Object.defineProperty(response.headers, "getSetCookie", { value: undefined }); return Promise.resolve(response); }); Constants.expoConfig!.extra = { relay: { url: "https://relay.example.test" } }; setAgentAwarenessRelayTokenProvider(() => Promise.resolve("clerk-token-user-a"), "user-a"); return Effect.gen(function* () { // Hermes' compiled error hashing reads the response's cookie getter. const httpResponse = HttpClientResponse.fromWeb( HttpClientRequest.post("https://relay.example.test/v1/mobile/devices"), rejectedResponse, ); expect(httpResponse.cookies).toEqual(Cookies.empty); const result = yield* Effect.exit( updateAgentAwarenessRegistrationPreferences({ liveActivitiesEnabled: true }), ); expect(Exit.isFailure(result)).toBe(true); if (Exit.isFailure(result)) { expect(Cause.hasDies(result.cause)).toBe(false); expect(Cause.squash(result.cause)).toBeInstanceOf( ManagedRelay.ManagedRelayRequestFailedError, ); } expect(getAgentAwarenessRegistrationStatus()).toBe("failed"); expect(saveAgentAwarenessRegistrationRecord).not.toHaveBeenCalled(); }).pipe(Effect.provide(layerRelayTest)); }); it.effect( "does not reconfigure or register a detached Android account from an in-flight operation", () => { vi.spyOn(Platform, "OS", "get").mockReturnValue("android"); vi.spyOn(Platform, "Version", "get").mockReturnValue(36); Constants.expoConfig!.extra = { relay: { url: "https://relay.example.test" } }; setAgentAwarenessRelayTokenProvider(() => Promise.resolve("clerk-token"), "user-a"); releaseAgentAwarenessRelayTokenProvider(); vi.mocked(configureAndroidAgentNotifications).mockClear(); return Effect.gen(function* () { yield* runBackgroundOperations(); expect(configureAndroidAgentNotifications).not.toHaveBeenCalled(); expect(saveAgentAwarenessRegistrationRecord).not.toHaveBeenCalled(); }).pipe(Effect.provide(layerRelayTest)); }, ); it.effect("refreshes the home-screen widget after arming local agent work", () => { const activity = { getId: () => "activity-1", getPushToken: vi.fn(() => Promise.resolve("activity-token")), addPushTokenListener: vi.fn(), }; widgetMocks.start.mockReturnValueOnce(activity); setAgentAwarenessRelayTokenProvider(() => Promise.resolve("clerk-token-user-a")); backgroundRuntime.pending.length = 0; environmentConfigsMock.configs.set("env-1", { environment: { capabilities: { agentActivityPublishing: true } }, }); const preferences = Promise.resolve({ liveActivitiesEnabled: true, } as Preferences); vi.mocked(loadPreferences).mockReturnValueOnce(preferences); armAgentAwarenessLiveActivityForLocalWork({ environmentId: "env-1" as EnvironmentId, threadTitle: "Fix the flaky test", projectTitle: "t3code", }); const preferenceCallbackDrained = preferences.catch(() => null).then(() => undefined); return Effect.gen(function* () { yield* Effect.promise(() => preferenceCallbackDrained); yield* runBackgroundOperations(); expect(publishAgentActivityWidget).toHaveBeenLastCalledWith( expect.objectContaining({ activeCount: 1, subtitle: "Agent work in progress", activities: [expect.objectContaining({ status: "Working" })], }), ); }).pipe(Effect.provide(snapshotRelayLayer())); }); it.effect("refreshes the home-screen widget when local Live Activities are disabled", () => { setAgentAwarenessRelayTokenProvider(() => Promise.resolve("clerk-token-user-a")); backgroundRuntime.pending.length = 0; environmentConfigsMock.configs.set("env-1", { environment: { capabilities: { agentActivityPublishing: true } }, }); const preferences = Promise.resolve({ liveActivitiesEnabled: false, } as Preferences); vi.mocked(loadPreferences).mockReturnValueOnce(preferences); armAgentAwarenessLiveActivityForLocalWork({ environmentId: "env-1" as EnvironmentId, threadTitle: "Fix the flaky test", projectTitle: "t3code", }); const preferenceCallbackDrained = preferences.catch(() => null).then(() => undefined); return Effect.gen(function* () { yield* Effect.promise(() => preferenceCallbackDrained); yield* runBackgroundOperations(); expect(widgetMocks.start).not.toHaveBeenCalled(); expect(publishAgentActivityWidget).toHaveBeenCalledTimes(2); expect(publishAgentActivityWidget).toHaveBeenLastCalledWith( expect.objectContaining({ activeCount: 1, activities: [expect.objectContaining({ status: "Working" })], }), ); }).pipe(Effect.provide(snapshotRelayLayer())); }); it.effect("refreshes the home-screen widget when a local Live Activity is already armed", () => { widgetMocks.getInstances.mockReturnValueOnce([{}] as never); setAgentAwarenessRelayTokenProvider(() => Promise.resolve("clerk-token-user-a")); backgroundRuntime.pending.length = 0; environmentConfigsMock.configs.set("env-1", { environment: { capabilities: { agentActivityPublishing: true } }, }); const preferences = Promise.resolve({ liveActivitiesEnabled: true, } as Preferences); vi.mocked(loadPreferences).mockReturnValueOnce(preferences); armAgentAwarenessLiveActivityForLocalWork({ environmentId: "env-1" as EnvironmentId, threadTitle: "Fix the flaky test", projectTitle: "t3code", }); const preferenceCallbackDrained = preferences.catch(() => null).then(() => undefined); return Effect.gen(function* () { yield* Effect.promise(() => preferenceCallbackDrained); yield* runBackgroundOperations(); expect(widgetMocks.start).not.toHaveBeenCalled(); expect(publishAgentActivityWidget).toHaveBeenCalledTimes(2); expect(publishAgentActivityWidget).toHaveBeenLastCalledWith( expect.objectContaining({ activeCount: 1, activities: [expect.objectContaining({ status: "Working" })], }), ); }).pipe(Effect.provide(snapshotRelayLayer())); }); it.effect("refreshes the home-screen widget when local Live Activity arming fails", () => { widgetMocks.start.mockImplementationOnce(() => { throw new Error("start failed"); }); setAgentAwarenessRelayTokenProvider(() => Promise.resolve("clerk-token-user-a")); backgroundRuntime.pending.length = 0; environmentConfigsMock.configs.set("env-1", { environment: { capabilities: { agentActivityPublishing: true } }, }); vi.mocked(loadPreferences).mockResolvedValueOnce({ liveActivitiesEnabled: true, } as Preferences); armAgentAwarenessLiveActivityForLocalWork({ environmentId: "env-1" as EnvironmentId, threadTitle: "Fix the flaky test", projectTitle: "t3code", }); return Effect.gen(function* () { yield* runBackgroundOperations(); expect(publishAgentActivityWidget).toHaveBeenLastCalledWith( expect.objectContaining({ activeCount: 1, subtitle: "Agent work in progress", activities: [expect.objectContaining({ status: "Working" })], }), ); }).pipe(Effect.provide(snapshotRelayLayer())); }); it.effect("discards an older widget snapshot when a newer refresh finishes first", () => Effect.gen(function* () { const firstReadStarted = yield* Deferred.make(); const finishFirstRead = yield* Deferred.make(); const olderSnapshot = { aggregate: { ...activeAgentActivitySnapshot.aggregate, updatedAt: "2026-05-25T13:06:00.000Z", activities: [ { ...activeAgentActivityRow, status: "Older status", updatedAt: "2026-05-25T13:06:00.000Z", }, ], }, } satisfies RelayAgentActivitySnapshotResponse; let readCount = 0; const layer = snapshotRelayLayer(() => { readCount++; if (readCount === 1) { return Deferred.succeed(firstReadStarted, undefined).pipe( Effect.andThen(Deferred.await(finishFirstRead)), Effect.as(olderSnapshot), ); } return Effect.succeed(activeAgentActivitySnapshot); }); setAgentAwarenessRelayTokenProvider(() => Promise.resolve("clerk-token-user-a")); backgroundRuntime.pending.length = 0; const olderRefresh = yield* refreshActiveLiveActivityRemoteRegistration().pipe( Effect.provide(layer), Effect.forkChild, ); yield* Deferred.await(firstReadStarted); yield* refreshActiveLiveActivityRemoteRegistration().pipe(Effect.provide(layer)); yield* Deferred.succeed(finishFirstRead, undefined); yield* Fiber.join(olderRefresh); expect(publishAgentActivityWidget).toHaveBeenCalledTimes(2); expect(publishAgentActivityWidget).toHaveBeenLastCalledWith( expect.objectContaining({ activities: [expect.objectContaining({ status: "Working" })], }), ); }).pipe(Effect.scoped), ); it.effect("does not prime a Live Activity from a read a newer one replaced", () => Effect.gen(function* () { const firstReadStarted = yield* Deferred.make(); const finishFirstRead = yield* Deferred.make(); let readCount = 0; const layer = snapshotRelayLayer(() => { readCount++; if (readCount === 1) { return Deferred.succeed(firstReadStarted, undefined).pipe( Effect.andThen(Deferred.await(finishFirstRead)), Effect.as(activeAgentActivitySnapshot), ); } return Effect.succeed({ aggregate: null }); }); vi.mocked(loadPreferences).mockResolvedValue({ liveActivitiesEnabled: true } as Preferences); setAgentAwarenessRelayTokenProvider(() => Promise.resolve("clerk-token-user-a")); backgroundRuntime.pending.length = 0; const olderRefresh = yield* refreshActiveLiveActivityRemoteRegistration().pipe( Effect.provide(layer), Effect.forkChild, ); yield* Deferred.await(firstReadStarted); yield* refreshActiveLiveActivityRemoteRegistration().pipe(Effect.provide(layer)); yield* Deferred.succeed(finishFirstRead, undefined); yield* Fiber.join(olderRefresh); expect(widgetMocks.start).not.toHaveBeenCalled(); }).pipe(Effect.scoped), ); it.effect("keeps the native local-work seed separate from an in-flight widget snapshot", () => Effect.gen(function* () { const readStarted = yield* Deferred.make(); const finishRead = yield* Deferred.make(); const layer = snapshotRelayLayer(() => Deferred.succeed(readStarted, undefined).pipe( Effect.andThen(Deferred.await(finishRead)), Effect.as({ aggregate: null }), ), ); const activity = { getId: () => "activity-1", getPushToken: vi.fn(() => Promise.resolve("activity-token")), addPushTokenListener: vi.fn(), }; widgetMocks.getInstances .mockReturnValueOnce([]) .mockReturnValueOnce([]) .mockReturnValue([activity] as never); widgetMocks.start.mockReturnValueOnce(activity); setAgentAwarenessRelayTokenProvider(() => Promise.resolve("clerk-token-user-a")); environmentConfigsMock.configs.set("env-1", { environment: { capabilities: { agentActivityPublishing: true } }, }); const preferences = Promise.resolve({ liveActivitiesEnabled: true, } as Preferences); vi.mocked(loadPreferences).mockReturnValue(preferences); const refresh = yield* refreshActiveLiveActivityRemoteRegistration().pipe( Effect.provide(layer), Effect.forkChild, ); yield* Deferred.await(readStarted); armAgentAwarenessLiveActivityForLocalWork({ environmentId: "env-1" as EnvironmentId, threadTitle: "Fix the flaky test", projectTitle: "t3code", }); const preferenceCallbackDrained = preferences.catch(() => null).then(() => undefined); yield* Effect.promise(() => preferenceCallbackDrained); yield* Deferred.succeed(finishRead, undefined); yield* Fiber.join(refresh); expect(widgetMocks.start).toHaveBeenCalledExactlyOnceWith( expect.objectContaining({ activeCount: 1, activities: [expect.objectContaining({ status: "Connecting" })], }), expect.any(Date), ); expect(publishAgentActivityWidget).toHaveBeenCalledTimes(2); expect(publishAgentActivityWidget).toHaveBeenLastCalledWith( expect.objectContaining({ activeCount: 0, activities: [], }), ); }).pipe(Effect.scoped), ); it.effect.each(["global", "scoped"] as const)( "adopts a local arm made during the final %s snapshot read instead of priming twice", (blockedRead) => Effect.gen(function* () { addLiveEnvironment(); const preferences = Promise.resolve({ liveActivitiesEnabled: true } as Preferences); vi.mocked(loadPreferences).mockReturnValue(preferences); environmentConfigsMock.configs.set("env-1", { environment: { capabilities: { agentActivityPublishing: true } }, }); const readStarted = yield* Deferred.make(); const finishRead = yield* Deferred.make(); let finishToken!: (token: string) => void; let tokenReadStarted!: () => void; const pendingToken = new Promise((resolve) => { finishToken = resolve; }); const tokenRead = new Promise((resolve) => { tokenReadStarted = resolve; }); const makeActivity = () => ({ getId: () => "activity-1", getPushToken: vi.fn(() => Promise.resolve("activity-token")), addPushTokenListener: vi.fn(), }); const activities: Array> = []; widgetMocks.getInstances.mockImplementation(() => activities as never); widgetMocks.start.mockImplementation(() => { const activity = makeActivity(); if (activities.length === 0) activity.getPushToken.mockImplementationOnce(() => { tokenReadStarted(); return pendingToken; }); activities.push(activity); return activity; }); let globalReads = 0; let scopedReads = 0; const layer = snapshotRelayLayer(({ excludedEnvironmentIds }) => { const kind = excludedEnvironmentIds ? "scoped" : "global"; const ordinal = excludedEnvironmentIds ? ++scopedReads : ++globalReads; const snapshot = excludedEnvironmentIds ? { aggregate: null, excludedEnvironmentIds } : activeAgentActivitySnapshot; return ordinal === 1 && kind === blockedRead ? Deferred.succeed(readStarted, undefined).pipe( Effect.andThen(Deferred.await(finishRead)), Effect.as(snapshot), ) : Effect.succeed(snapshot); }); setAgentAwarenessRelayTokenProvider(() => Promise.resolve("clerk-token-user-a"), "user-a"); backgroundRuntime.pending.length = 0; const refresh = yield* refreshActiveLiveActivityRemoteRegistration().pipe( Effect.provide(layer), Effect.forkChild, ); yield* Deferred.await(readStarted); armAgentAwarenessLiveActivityForLocalWork({ environmentId: liveEnvironmentId, projectTitle: "Live project", threadTitle: "Local task", }); yield* Effect.promise(() => preferences.catch(() => null).then(() => undefined)); expect(widgetMocks.start).toHaveBeenCalledTimes(1); const pending = backgroundRuntime.pending.shift(); if (!pending) throw new Error("Expected local token registration"); const localRegistration = yield* Effect.exit( pending.operation as Effect.Effect, ).pipe(Effect.provide(layer), Effect.forkChild); yield* Effect.promise(() => tokenRead); yield* Deferred.succeed(finishRead, undefined); const startsBeforeTokenResolved = widgetMocks.start.mock.calls.length; finishToken("activity-token"); yield* Fiber.join(refresh); pending.resolve(yield* Fiber.join(localRegistration)); expect({ global: globalReads, scoped: scopedReads }).toEqual({ global: 2, scoped: 2 }); expect(startsBeforeTokenResolved).toBe(1); expect(activities).toHaveLength(1); }).pipe(Effect.scoped), ); it.effect("does not prime a Live Activity after cloud sign-out", () => Effect.gen(function* () { let preferencesStarted!: () => void; let finishPreferences!: (preferences: Preferences) => void; const started = new Promise((resolve) => { preferencesStarted = resolve; }); const preferences = new Promise((resolve) => { finishPreferences = resolve; }); vi.mocked(loadPreferences).mockImplementationOnce(() => { preferencesStarted(); return preferences; }); setAgentAwarenessRelayTokenProvider(() => Promise.resolve("clerk-token-user-a")); const refresh = yield* refreshActiveLiveActivityRemoteRegistration().pipe( Effect.provide(snapshotRelayLayer()), Effect.forkChild, ); yield* Effect.promise(() => started); setAgentAwarenessRelayTokenProvider(null); finishPreferences({ liveActivitiesEnabled: true } as Preferences); yield* Fiber.join(refresh); expect(widgetMocks.start).not.toHaveBeenCalled(); expect(publishAgentActivityWidget).toHaveBeenLastCalledWith( expect.objectContaining({ subtitle: "Sign in to see agent activity", isSignedOut: true, activeCount: 0, activities: [], }), ); }).pipe(Effect.scoped), ); it.effect("does not prime from a snapshot that became idle while preferences loaded", () => Effect.gen(function* () { let preferencesStarted!: () => void; let finishPreferences!: (preferences: Preferences) => void; const started = new Promise((resolve) => { preferencesStarted = resolve; }); const preferences = new Promise((resolve) => { finishPreferences = resolve; }); vi.mocked(loadPreferences).mockImplementationOnce(() => { preferencesStarted(); return preferences; }); let snapshot: RelayAgentActivitySnapshotResponse = activeAgentActivitySnapshot; const readSnapshot = vi.fn(() => Effect.succeed(snapshot)); const layer = snapshotRelayLayer(readSnapshot); setAgentAwarenessRelayTokenProvider(() => Promise.resolve("clerk-token-user-a")); const refresh = yield* refreshActiveLiveActivityRemoteRegistration().pipe( Effect.provide(layer), Effect.forkChild, ); yield* Effect.promise(() => started); expect(readSnapshot).not.toHaveBeenCalled(); snapshot = { aggregate: null }; finishPreferences({ liveActivitiesEnabled: true } as Preferences); yield* Fiber.join(refresh); expect(readSnapshot).toHaveBeenCalledTimes(1); expect(widgetMocks.start).not.toHaveBeenCalled(); expect(publishAgentActivityWidget).toHaveBeenLastCalledWith( expect.objectContaining({ subtitle: "No active agents", activeCount: 0, activities: [], }), ); }).pipe(Effect.scoped), ); it.effect.each([false, true])( "publishes later local shell work after the registered local-start refresh was idle (Live Activities %s)", (liveActivitiesEnabled) => { addLiveEnvironment(); setAgentAwarenessRelayTokenProvider(() => Promise.resolve("clerk-token-user-a"), "user-a"); backgroundRuntime.pending.length = 0; const activity = { getId: () => "activity-1", getPushToken: vi.fn(() => Promise.resolve("activity-token")), addPushTokenListener: vi.fn(), }; widgetMocks.start.mockReturnValueOnce(activity); const preferences = Promise.resolve({ liveActivitiesEnabled } as Preferences); vi.mocked(loadPreferences).mockReturnValue(preferences); armAgentAwarenessLiveActivityForLocalWork({ environmentId: liveEnvironmentId, threadTitle: "Live task", projectTitle: "Live project", }); const preferencesDrained = preferences.catch(() => null).then(() => undefined); return Effect.gen(function* () { yield* Effect.promise(() => preferencesDrained); expect(widgetMocks.start).toHaveBeenCalledTimes(liveActivitiesEnabled ? 1 : 0); yield* runBackgroundOperations(); expect(publishAgentActivityWidget).toHaveBeenLastCalledWith( expect.objectContaining({ activeCount: 0, activities: [] }), ); setLiveShell("starting"); expect(publishAgentActivityWidget).toHaveBeenLastCalledWith( expect.objectContaining({ activeCount: 1, activities: [ expect.objectContaining({ threadTitle: "Live task", status: "Connecting" }), ], }), ); setLiveShell("running"); expect(publishAgentActivityWidget).toHaveBeenLastCalledWith( expect.objectContaining({ activeCount: 1, activities: [expect.objectContaining({ threadTitle: "Live task", status: "Working" })], }), ); setLiveShell("ready"); expect(publishAgentActivityWidget).toHaveBeenLastCalledWith( expect.objectContaining({ activeCount: 0, activities: [expect.objectContaining({ threadTitle: "Live task", status: "Done" })], }), ); setLiveShell(null); expect(publishAgentActivityWidget).toHaveBeenLastCalledWith( expect.objectContaining({ activeCount: 0, activities: [] }), ); expect(backgroundRuntime.pending).toHaveLength(0); }).pipe(Effect.provide(snapshotRelayLayer(() => Effect.succeed({ aggregate: null })))); }, ); it.effect.each(["completed", "multiple running"] as const)( "keeps %s widget rows when delayed local arming is followed by a relay failure", (state) => Effect.gen(function* () { addLiveEnvironment(); setAgentAwarenessRelayTokenProvider(() => Promise.resolve("clerk-token-user-a"), "user-a"); backgroundRuntime.pending.length = 0; yield* refreshActiveLiveActivityRemoteRegistration().pipe( Effect.provide(snapshotRelayLayer(() => Effect.succeed({ aggregate: null }))), ); setLiveShell("running"); const activity = { getId: () => "activity-1", getPushToken: vi.fn(() => Promise.resolve("activity-token")), addPushTokenListener: vi.fn(), }; widgetMocks.start.mockReturnValueOnce(activity); let finishPreferences!: (preferences: Preferences) => void; const preferences = new Promise((resolve) => { finishPreferences = resolve; }); vi.mocked(loadPreferences).mockReturnValueOnce(preferences); armAgentAwarenessLiveActivityForLocalWork({ environmentId: liveEnvironmentId, threadTitle: "Live task", projectTitle: "Live project", }); const preferenceCallbackDrained = preferences.catch(() => null).then(() => undefined); expect(widgetMocks.start).not.toHaveBeenCalled(); if (state === "completed") { setLiveShell("ready"); } else { const shell = appAtomRegistry.get(environmentShell.stateValueAtom(liveEnvironmentId)); const snapshot = Option.getOrThrow(shell.snapshot); const thread = snapshot.threads[0]; if (!thread) throw new Error("Expected the running fixture thread"); setTestAtom(environmentShell.stateValueAtom(liveEnvironmentId), { ...shell, snapshot: Option.some({ ...snapshot, threads: [ thread, { ...thread, id: ThreadId.make("second-thread"), title: "Second live task" }, ], }), }); } const observed = vi.mocked(publishAgentActivityWidget).mock.lastCall?.[0]; expect(observed?.activeCount).toBe(state === "completed" ? 0 : 2); expect(observed?.activities).toHaveLength(state === "completed" ? 1 : 2); finishPreferences({ liveActivitiesEnabled: true } as Preferences); yield* Effect.promise(() => preferenceCallbackDrained); expect(widgetMocks.start).toHaveBeenCalledExactlyOnceWith( expect.objectContaining({ activeCount: 1, activities: [expect.objectContaining({ status: "Connecting" })], }), expect.any(Date), ); expect(backgroundRuntime.pending).toHaveLength(1); const pending = backgroundRuntime.pending.shift(); if (!pending) throw new Error("Expected the local activity registration operation"); let failedReads = 0; const failedRelay = snapshotRelayLayer(() => { failedReads++; return Effect.fail( new ManagedRelay.ManagedRelayRequestFailedError({ action: "read relay agent activity snapshot", transportFailed: true, cause: new Error("Synthetic snapshot transport failure"), }), ); }); const exit = yield* Effect.exit( pending.operation as Effect.Effect, ).pipe(Effect.provide(failedRelay)); pending.resolve(exit); expect(Exit.isSuccess(exit)).toBe(true); expect(failedReads).toBe(1); expect(activity.getPushToken).toHaveBeenCalledTimes(1); expect(backgroundRuntime.pending).toHaveLength(0); expect(publishAgentActivityWidget).toHaveBeenLastCalledWith(observed); }), ); it.effect("does not let a delayed idle relay response hide current live work", () => Effect.gen(function* () { addLiveEnvironment(); setAgentAwarenessRelayTokenProvider(() => Promise.resolve("clerk-token-user-a"), "user-a"); backgroundRuntime.pending.length = 0; const readStarted = yield* Deferred.make(); const finishRead = yield* Deferred.make(); const layer = snapshotRelayLayer(() => Deferred.succeed(readStarted, undefined).pipe( Effect.andThen(Deferred.await(finishRead)), Effect.as({ aggregate: null }), ), ); const refresh = yield* refreshActiveLiveActivityRemoteRegistration().pipe( Effect.provide(layer), Effect.forkChild, ); yield* Deferred.await(readStarted); setLiveShell("running"); yield* Deferred.succeed(finishRead, undefined); yield* Fiber.join(refresh); expect(publishAgentActivityWidget).toHaveBeenLastCalledWith( expect.objectContaining({ activeCount: 1, activities: [expect.objectContaining({ threadTitle: "Live task", status: "Working" })], }), ); }).pipe(Effect.scoped), ); it.effect.each(["cached", "synchronizing"] as const)( "preserves last-observed work instead of false idle on %s", (status) => Effect.gen(function* () { addLiveEnvironment(); setAgentAwarenessRelayTokenProvider(() => Promise.resolve("clerk-token-user-a"), "user-a"); backgroundRuntime.pending.length = 0; yield* refreshActiveLiveActivityRemoteRegistration().pipe( Effect.provide(snapshotRelayLayer(() => Effect.succeed({ aggregate: null }))), ); setLiveShell("running"); expect(vi.mocked(publishAgentActivityWidget).mock.lastCall?.[0]?.activeCount).toBe(1); setLiveShell("running", status); expect(publishAgentActivityWidget).toHaveBeenLastCalledWith( expect.objectContaining({ activeCount: 1, isStale: true, activities: [expect.objectContaining({ status: "Working" })], }), ); setLiveShell(null); expect(publishAgentActivityWidget).toHaveBeenLastCalledWith( expect.objectContaining({ activeCount: 0, isStale: false, activities: [], }), ); }), ); it.effect("does not resurrect older relay Working after observed Done on disconnect", () => Effect.gen(function* () { addLiveEnvironment(); setAgentAwarenessRelayTokenProvider(() => Promise.resolve("clerk-token-user-a"), "user-a"); backgroundRuntime.pending.length = 0; const earlier = DateTime.formatIso( DateTime.makeUnsafe(Date.parse(liveShellUpdatedAt) - 1_000), ); const relaySnapshot: RelayAgentActivitySnapshotResponse = { aggregate: { ...activeAgentActivitySnapshot.aggregate, updatedAt: earlier, activities: [ { ...activeAgentActivityRow, threadId: ThreadId.make("local-thread"), updatedAt: earlier, }, ], }, }; const layer = snapshotRelayLayer(() => Effect.succeed(relaySnapshot)); yield* refreshActiveLiveActivityRemoteRegistration().pipe(Effect.provide(layer)); setLiveShell("running"); setLiveShell("ready"); const observed = vi.mocked(publishAgentActivityWidget).mock.lastCall?.[0]; expect(observed?.activeCount).toBe(0); setLiveShell("ready", "cached"); yield* refreshActiveLiveActivityRemoteRegistration().pipe(Effect.provide(layer)); expect(publishAgentActivityWidget).toHaveBeenLastCalledWith( expect.objectContaining({ activeCount: 0, isStale: true, activities: observed?.activities, }), ); }), ); it.effect.each([false, true])( "keeps widget counts separate from Live Activity opt-out %s", (disabled) => Effect.gen(function* () { addLiveEnvironment(); setLiveShell("running"); setAgentAwarenessRelayTokenProvider(() => Promise.resolve("clerk-token-user-a"), "user-a"); backgroundRuntime.pending.length = 0; widgetMocks.getInstances.mockReturnValue([]); vi.mocked(loadPreferences).mockResolvedValue({ liveActivitiesEnabled: true, } as Preferences); const queries: Array | undefined> = []; const layer = snapshotRelayLayer(({ excludedEnvironmentIds }) => { queries.push(excludedEnvironmentIds); return Effect.succeed( excludedEnvironmentIds ? { aggregate: null, excludedEnvironmentIds, } : { ...activeAgentActivitySnapshot, liveActivityAggregate: disabled ? null : { ...activeAgentActivitySnapshot.aggregate, activeCount: 6, workingCount: 4, attentionCount: 2, totalCount: 7, }, }, ); }); yield* refreshActiveLiveActivityRemoteRegistration().pipe(Effect.provide(layer)); expect(queries).toEqual([undefined, [liveEnvironmentId]]); if (disabled) expect(widgetMocks.start).not.toHaveBeenCalled(); else expect(widgetMocks.start).toHaveBeenCalledWith( expect.objectContaining({ activities: activeAgentActivitySnapshot.aggregate.activities, workingCount: 4, attentionCount: 2, totalCount: 7, }), expect.any(Date), ); expect(publishAgentActivityWidget).toHaveBeenLastCalledWith( expect.objectContaining({ activeCount: 1, isStale: false, activities: [expect.objectContaining({ threadId: "local-thread" })], }), ); }), ); it.effect( "publishes honest unknown totals for capped older relays without hiding current rows", () => Effect.gen(function* () { addLiveEnvironment(); setLiveShell("running"); setAgentAwarenessRelayTokenProvider(() => Promise.resolve("clerk-token-user-a"), "user-a"); backgroundRuntime.pending.length = 0; yield* refreshActiveLiveActivityRemoteRegistration().pipe( Effect.provide( snapshotRelayLayer(() => Effect.succeed({ aggregate: { ...activeAgentActivitySnapshot.aggregate, activeCount: 12 }, }), ), ), ); expect(publishAgentActivityWidget).toHaveBeenLastCalledWith( expect.objectContaining({ activeCount: null, isStale: false, subtitle: "Activity count unavailable", activities: [expect.objectContaining({ threadId: "local-thread", status: "Working" })], }), ); }), ); it.effect( "publishes complete local rows when the first relay read fails without inferring a total", () => Effect.gen(function* () { addLiveEnvironment(); setLiveShell("running"); setAgentAwarenessRelayTokenProvider(() => Promise.resolve("clerk-token-user-a"), "user-a"); backgroundRuntime.pending.length = 0; yield* refreshActiveLiveActivityRemoteRegistration().pipe( Effect.provide( snapshotRelayLayer(() => Effect.fail( new ManagedRelay.ManagedRelayRequestFailedError({ action: "read relay agent activity snapshot", transportFailed: true, cause: new Error("Synthetic first read failure"), }), ), ), ), ); expect(publishAgentActivityWidget).toHaveBeenLastCalledWith( expect.objectContaining({ activeCount: null, isStale: false, observedActivities: { [liveEnvironmentId]: [expect.objectContaining({ threadId: "local-thread" })], }, activities: [expect.objectContaining({ threadId: "local-thread", status: "Working" })], }), ); }), ); it.effect("re-reads a changed exclusion scope instead of publishing the old scoped total", () => Effect.gen(function* () { addLiveEnvironment(); setLiveShell("running"); setAgentAwarenessRelayTokenProvider(() => Promise.resolve("clerk-token-user-a"), "user-a"); backgroundRuntime.pending.length = 0; const started = yield* Deferred.make(); const finish = yield* Deferred.make(); const queries: Array | undefined> = []; const layer = snapshotRelayLayer(({ excludedEnvironmentIds }) => { queries.push(excludedEnvironmentIds); if (excludedEnvironmentIds?.length === 1) return Deferred.succeed(started, undefined).pipe( Effect.andThen(Deferred.await(finish)), Effect.as({ aggregate: { ...activeAgentActivitySnapshot.aggregate, activeCount: 12 }, excludedEnvironmentIds, }), ); return Effect.succeed({ aggregate: null, excludedEnvironmentIds: excludedEnvironmentIds ?? [], }); }); const refresh = yield* refreshActiveLiveActivityRemoteRegistration().pipe( Effect.provide(layer), Effect.forkChild, ); yield* Deferred.await(started); const other = EnvironmentId.make("other"); const catalog = appAtomRegistry.get(environmentCatalog.catalogValueAtom); setTestAtom(environmentShell.stateValueAtom(other), { status: "live", generation: 0, removedAt: new Map(), error: Option.none(), snapshot: Option.some({ projects: [], threads: [], snapshotSequence: 1, archivedThreads: [], schemaVersion: 1, }), }); setTestAtom(environmentCatalog.catalogValueAtom, { ...catalog, entries: new Map([ ...catalog.entries, [ other, { target: new PrimaryConnectionTarget({ environmentId: other, label: "Other", httpBaseUrl: "https://other.example.test", wsBaseUrl: "wss://other.example.test/ws", }), profile: Option.none(), enabled: true, }, ], ]), }); yield* Deferred.succeed(finish, undefined); yield* Fiber.join(refresh); expect(queries).toEqual([undefined, [liveEnvironmentId], [liveEnvironmentId, other]]); expect(publishAgentActivityWidget).toHaveBeenLastCalledWith( expect.objectContaining({ activeCount: 1, isStale: false }), ); expect( vi .mocked(publishAgentActivityWidget) .mock.calls.some(([props]) => props.activeCount === 13), ).toBe(false); }).pipe(Effect.scoped), ); it.effect("evicts retained observations on catalog removal and account switch", () => Effect.gen(function* () { addLiveEnvironment(); setAgentAwarenessRelayTokenProvider(() => Promise.resolve("clerk-token-user-a"), "user-a"); backgroundRuntime.pending.length = 0; const layer = snapshotRelayLayer(({ excludedEnvironmentIds }) => Effect.succeed({ aggregate: null, excludedEnvironmentIds: excludedEnvironmentIds ?? [] }), ); yield* refreshActiveLiveActivityRemoteRegistration().pipe(Effect.provide(layer)); setLiveShell("running"); setLiveShell("running", "cached"); expect(vi.mocked(publishAgentActivityWidget).mock.lastCall?.[0]?.isStale).toBe(true); setTestAtom(environmentCatalog.catalogValueAtom, { isReady: true, entries: new Map() }); yield* refreshActiveLiveActivityRemoteRegistration().pipe(Effect.provide(layer)); expect(publishAgentActivityWidget).toHaveBeenLastCalledWith( expect.objectContaining({ activeCount: 0, isStale: false, activities: [] }), ); addLiveEnvironment(); setLiveShell("running"); setLiveShell("running", "cached"); setAgentAwarenessRelayTokenProvider(() => Promise.resolve("clerk-token-user-b"), "user-b"); yield* refreshActiveLiveActivityRemoteRegistration().pipe(Effect.provide(layer)); expect(publishAgentActivityWidget).toHaveBeenLastCalledWith( expect.objectContaining({ activeCount: 0, isStale: false, activities: [] }), ); }), ); it.effect.each(["account switch", "provider remount"] as const)( "clears the prior account's native widget on %s even when the relay is unavailable", (transition) => Effect.gen(function* () { setAgentAwarenessRelayTokenProvider(() => Promise.resolve("token-a"), "user-a"); backgroundRuntime.pending.length = 0; yield* refreshActiveLiveActivityRemoteRegistration().pipe( Effect.provide(snapshotRelayLayer()), ); expect(publishAgentActivityWidget).toHaveBeenLastCalledWith( expect.objectContaining({ activeCount: 1, activities: activeAgentActivitySnapshot.aggregate.activities, }), ); if (transition === "provider remount") releaseAgentAwarenessRelayTokenProvider(); vi.mocked(clearAgentWidgetRefresh).mockClear(); vi.mocked(agentWidgetToken).mockClear(); setAgentAwarenessRelayTokenProvider(() => Promise.resolve("token-b"), "user-b"); expect(agentWidgetToken).toHaveBeenCalledWith("user-b"); if (transition === "account switch") expect(clearAgentWidgetRefresh).toHaveBeenCalledOnce(); expect(publishAgentActivityWidget).toHaveBeenLastCalledWith( expect.objectContaining({ activeCount: null, activities: [] }), ); backgroundRuntime.pending.length = 0; yield* refreshActiveLiveActivityRemoteRegistration().pipe( Effect.provide( snapshotRelayLayer(() => Effect.fail( new ManagedRelay.ManagedRelayRequestFailedError({ action: "read relay agent activity snapshot", transportFailed: true, cause: new Error("offline"), }), ), ), ), ); expect(publishAgentActivityWidget).toHaveBeenLastCalledWith( expect.objectContaining({ activeCount: null, activities: [] }), ); }), ); it.effect("publishes freshness changes even when rows and count are unchanged", () => Effect.gen(function* () { addLiveEnvironment(); setAgentAwarenessRelayTokenProvider(() => Promise.resolve("clerk-token-user-a"), "user-a"); backgroundRuntime.pending.length = 0; yield* refreshActiveLiveActivityRemoteRegistration().pipe( Effect.provide(snapshotRelayLayer(() => Effect.succeed({ aggregate: null }))), ); setLiveShell("running"); setLiveShell("running", "live", "2026-10-02T12:00:00.500Z"); expect(publishAgentActivityWidget).toHaveBeenLastCalledWith( expect.objectContaining({ observedActivities: { [liveEnvironmentId]: [ expect.objectContaining({ updatedAt: "2026-10-02T12:00:00.500Z" }), ], }, }), ); const count = vi.mocked(publishAgentActivityWidget).mock.calls.length; setLiveShell("running", "cached"); expect(publishAgentActivityWidget).toHaveBeenCalledTimes(count + 1); expect(vi.mocked(publishAgentActivityWidget).mock.lastCall?.[0]?.isStale).toBe(true); setLiveShell("running", "synchronizing"); expect(publishAgentActivityWidget).toHaveBeenCalledTimes(count + 1); setLiveShell("running"); expect(publishAgentActivityWidget).toHaveBeenCalledTimes(count + 2); expect(vi.mocked(publishAgentActivityWidget).mock.lastCall?.[0]?.isStale).toBe(false); }), ); it.effect( "uses live idle and deletion over relay work, retaining local evidence when disconnected", () => { addLiveEnvironment(); setAgentAwarenessRelayTokenProvider(() => Promise.resolve("clerk-token-user-a"), "user-a"); backgroundRuntime.pending.length = 0; return Effect.gen(function* () { yield* refreshActiveLiveActivityRemoteRegistration(); expect(publishAgentActivityWidget).toHaveBeenLastCalledWith( expect.objectContaining({ activeCount: 0, activities: [] }), ); setLiveShell("running"); expect(publishAgentActivityWidget).toHaveBeenLastCalledWith( expect.objectContaining({ activities: [expect.objectContaining({ threadTitle: "Live task" })], }), ); setLiveShell("ready", "cached"); expect(publishAgentActivityWidget).toHaveBeenLastCalledWith( expect.objectContaining({ activeCount: 1, isStale: true, activities: [expect.objectContaining({ threadTitle: "Live task" })], }), ); setLiveShell(null); expect(publishAgentActivityWidget).toHaveBeenLastCalledWith( expect.objectContaining({ activeCount: 0, activities: [] }), ); }).pipe(Effect.provide(snapshotRelayLayer())); }, ); it.effect("detaches on background and resumes from the latest shell on foreground", () => { addLiveEnvironment(); setAgentAwarenessRelayTokenProvider(() => Promise.resolve("clerk-token-user-a"), "user-a"); backgroundRuntime.pending.length = 0; return Effect.gen(function* () { yield* refreshActiveLiveActivityRemoteRegistration(); setLiveShell("running"); appStateMock.currentState = "background"; for (const listener of appStateMock.listeners) listener("background"); const publishedBeforeBackground = vi.mocked(publishAgentActivityWidget).mock.calls.length; expect(vi.mocked(publishAgentActivityWidget).mock.lastCall?.[0]?.isStale).toBe(false); setLiveShell("ready"); expect(publishAgentActivityWidget).toHaveBeenCalledTimes(publishedBeforeBackground); appStateMock.currentState = "active"; for (const listener of appStateMock.listeners) listener("active"); expect(publishAgentActivityWidget).toHaveBeenLastCalledWith( expect.objectContaining({ activeCount: 0, activities: [expect.objectContaining({ status: "Done" })], }), ); expect(backgroundRuntime.pending).toHaveLength(1); }).pipe(Effect.provide(snapshotRelayLayer(() => Effect.succeed({ aggregate: null })))); }); it.effect( "keeps the original deadline when a background relay read cannot validate retained observations", () => { addLiveEnvironment(); setAgentAwarenessRelayTokenProvider(() => Promise.resolve("clerk-token-user-a"), "user-a"); backgroundRuntime.pending.length = 0; return Effect.gen(function* () { yield* refreshActiveLiveActivityRemoteRegistration(); setLiveShell("running"); appStateMock.currentState = "background"; for (const listener of appStateMock.listeners) listener("background"); setLiveShell(null); yield* refreshActiveLiveActivityRemoteRegistration(); expect(publishAgentActivityWidget).toHaveBeenLastCalledWith( expect.objectContaining({ activeCount: 1, isStale: false, activities: [expect.objectContaining({ threadTitle: "Live task" })], }), ); }).pipe(Effect.provide(snapshotRelayLayer())); }, ); it.effect("deduplicates timestamp-only shell updates and same-account observer refreshes", () => { addLiveEnvironment(); setAgentAwarenessRelayTokenProvider(() => Promise.resolve("clerk-token-user-a"), "user-a"); backgroundRuntime.pending.length = 0; return Effect.gen(function* () { yield* refreshActiveLiveActivityRemoteRegistration(); setLiveShell("running"); const count = vi.mocked(publishAgentActivityWidget).mock.calls.length; setLiveShell("running"); setAgentAwarenessRelayTokenProvider( () => Promise.resolve("refreshed-token-user-a"), "user-a", ); setLiveShell("running"); expect(publishAgentActivityWidget).toHaveBeenCalledTimes(count); setLiveShell("ready"); expect(publishAgentActivityWidget).toHaveBeenCalledTimes(count + 1); }).pipe(Effect.provide(snapshotRelayLayer(() => Effect.succeed({ aggregate: null })))); }); it.effect("retries identical widget content after a failed native publish", () => { addLiveEnvironment(); setAgentAwarenessRelayTokenProvider(() => Promise.resolve("clerk-token-user-a"), "user-a"); backgroundRuntime.pending.length = 0; return Effect.gen(function* () { yield* refreshActiveLiveActivityRemoteRegistration(); vi.mocked(publishAgentActivityWidget).mockReturnValueOnce(false); setLiveShell("running"); const count = vi.mocked(publishAgentActivityWidget).mock.calls.length; setLiveShell("running"); expect(publishAgentActivityWidget).toHaveBeenCalledTimes(count + 1); setLiveShell("running"); expect(publishAgentActivityWidget).toHaveBeenCalledTimes(count + 1); }).pipe(Effect.provide(snapshotRelayLayer(() => Effect.succeed({ aggregate: null })))); }); it.effect( "does not renew disconnected work from a fresh read of an older relay observation", () => Effect.gen(function* () { const now = Date.parse("2026-10-02T12:00:00.000Z"); const clock = vi.spyOn(Date, "now").mockReturnValue(now); addLiveEnvironment(); setLiveShell("running"); setAgentAwarenessRelayTokenProvider(() => Promise.resolve("token-a"), "user-a"); backgroundRuntime.pending.length = 0; const layer = snapshotRelayLayer(() => Effect.succeed({ aggregate: null })); yield* refreshActiveLiveActivityRemoteRegistration().pipe(Effect.provide(layer)); const deadline = vi.mocked(publishAgentActivityWidget).mock.lastCall![0].expiresAt; clock.mockReturnValue(now + 60_000); setLiveShell("running", "cached"); yield* refreshActiveLiveActivityRemoteRegistration().pipe(Effect.provide(layer)); const retained = vi.mocked(publishAgentActivityWidget).mock.lastCall![0]; expect(retained).toMatchObject({ isStale: true, expiresAt: deadline }); expect(retained.activities[0]?.threadTitle).toBe("Live task"); appStateMock.currentState = "background"; for (const listener of appStateMock.listeners) listener("background"); expect(vi.mocked(publishAgentActivityWidget).mock.lastCall![0]).toMatchObject({ isStale: true, expiresAt: deadline, }); }), ); it("renews a confirmed live shell but not an unrelated atom recomputation", () => { const now = Date.parse("2026-10-02T12:00:00.000Z"); const clock = vi.spyOn(Date, "now").mockReturnValue(now); addLiveEnvironment(); setLiveShell("running"); setAgentAwarenessRelayTokenProvider(() => Promise.resolve("token-a"), "user-a"); const original = vi.mocked(publishAgentActivityWidget).mock.lastCall![0]; expect(original.expiresAt).toBe(now + AGENT_ACTIVITY_FRESHNESS_MS); const publications = vi.mocked(publishAgentActivityWidget).mock.calls.length; clock.mockReturnValue(now + 60_000); const catalog = appAtomRegistry.get(environmentCatalog.catalogValueAtom); setTestAtom(environmentCatalog.catalogValueAtom, { ...catalog }); expect(publishAgentActivityWidget).toHaveBeenCalledTimes(publications); setLiveShell("running"); expect(vi.mocked(publishAgentActivityWidget).mock.lastCall![0].expiresAt).toBe( now + 60_000 + AGENT_ACTIVITY_FRESHNESS_MS, ); expect(publishAgentActivityWidget).toHaveBeenCalledTimes(publications + 1); }); it("does not let an old idle environment expire freshly observed work", () => { const now = Date.parse("2026-10-02T12:00:00.000Z"); const clock = vi.spyOn(Date, "now").mockReturnValue(now); addLiveEnvironment(); const other = EnvironmentId.make("idle-environment"); setTestAtom( environmentShell.stateValueAtom(other), appAtomRegistry.get(environmentShell.stateValueAtom(liveEnvironmentId)), ); const catalog = appAtomRegistry.get(environmentCatalog.catalogValueAtom); setTestAtom(environmentCatalog.catalogValueAtom, { ...catalog, entries: new Map([ ...catalog.entries, [ other, { target: new PrimaryConnectionTarget({ environmentId: other, label: "Idle", httpBaseUrl: "https://idle.example.test", wsBaseUrl: "wss://idle.example.test/ws", }), profile: Option.none(), enabled: true, }, ], ]), }); setAgentAwarenessRelayTokenProvider(() => Promise.resolve("token-a"), "user-a"); clock.mockReturnValue(now + AGENT_ACTIVITY_FRESHNESS_MS + 60_000); setLiveShell("running"); expect(vi.mocked(publishAgentActivityWidget).mock.lastCall![0]).toMatchObject({ expiresAt: now + AGENT_ACTIVITY_FRESHNESS_MS * 2 + 60_000, }); }); it("keeps the full freshness interval for a shell observed late in a minute", () => { const now = Date.parse("2026-10-02T12:00:59.000Z"); vi.spyOn(Date, "now").mockReturnValue(now); addLiveEnvironment(); setLiveShell("running"); setAgentAwarenessRelayTokenProvider(() => Promise.resolve("token-a"), "user-a"); expect(vi.mocked(publishAgentActivityWidget).mock.lastCall![0].expiresAt).toBe( now + AGENT_ACTIVITY_FRESHNESS_MS, ); }); it.effect.each([ null, { ...activeAgentActivitySnapshot.aggregate, activeCount: 0, activities: [{ ...activeAgentActivityRow, phase: "completed" as const }], }, ])( "does not expire fresh direct work because an empty or terminal relay read is old: %s", (aggregate) => Effect.gen(function* () { const now = Date.parse("2026-10-02T12:00:00.000Z"); const clock = vi.spyOn(Date, "now").mockReturnValue(now); addLiveEnvironment(); setLiveShell("running"); setAgentAwarenessRelayTokenProvider(() => Promise.resolve("token-a"), "user-a"); yield* refreshActiveLiveActivityRemoteRegistration().pipe( Effect.provide(snapshotRelayLayer(() => Effect.succeed({ aggregate }))), ); clock.mockReturnValue(now + AGENT_ACTIVITY_FRESHNESS_MS + 59_000); setLiveShell("running"); expect(vi.mocked(publishAgentActivityWidget).mock.lastCall![0].expiresAt).toBe( now + AGENT_ACTIVITY_FRESHNESS_MS * 2 + 59_000, ); }), ); it.effect("renews unchanged confirmed relay content, but not a failed read", () => Effect.gen(function* () { const now = Date.parse("2026-10-02T12:00:00.000Z"); const clock = vi.spyOn(Date, "now").mockReturnValue(now); yield* TestClock.setTime(now); setAgentAwarenessRelayTokenProvider(() => Promise.resolve("token-a"), "user-a"); backgroundRuntime.pending.length = 0; const layer = snapshotRelayLayer(); yield* refreshActiveLiveActivityRemoteRegistration().pipe(Effect.provide(layer)); const original = vi.mocked(publishAgentActivityWidget).mock.lastCall![0]; expect(original.expiresAt).toBe(now + AGENT_ACTIVITY_FRESHNESS_MS); clock.mockReturnValue(now + 60_000); yield* TestClock.setTime(now + 60_000); yield* refreshActiveLiveActivityRemoteRegistration().pipe(Effect.provide(layer)); const renewed = vi.mocked(publishAgentActivityWidget).mock.lastCall![0]; expect(renewed.activities).toEqual(original.activities); expect(renewed.expiresAt).toBe(now + 60_000 + AGENT_ACTIVITY_FRESHNESS_MS); const publications = vi.mocked(publishAgentActivityWidget).mock.calls.length; clock.mockReturnValue(now + 120_000); yield* TestClock.setTime(now + 120_000); yield* refreshActiveLiveActivityRemoteRegistration().pipe( Effect.provide( snapshotRelayLayer(() => Effect.fail( new ManagedRelay.ManagedRelayRequestFailedError({ action: "read relay agent activity snapshot", transportFailed: true, cause: new Error("offline"), }), ), ), ), ); expect(publishAgentActivityWidget).toHaveBeenCalledTimes(publications); expect(vi.mocked(publishAgentActivityWidget).mock.lastCall![0].expiresAt).toBe( renewed.expiresAt, ); }), ); it.effect("does not renew expiration when an older unchanged relay read finishes last", () => Effect.gen(function* () { const now = Date.parse("2026-10-02T12:00:00.000Z"); const clock = vi.spyOn(Date, "now").mockReturnValue(now); yield* TestClock.setTime(now); const started = yield* Deferred.make(); const finish = yield* Deferred.make(); setAgentAwarenessRelayTokenProvider(() => Promise.resolve("token-a"), "user-a"); backgroundRuntime.pending.length = 0; const older = yield* refreshActiveLiveActivityRemoteRegistration().pipe( Effect.provide( snapshotRelayLayer(() => Deferred.succeed(started, undefined).pipe( Effect.andThen(Deferred.await(finish)), Effect.as(activeAgentActivitySnapshot), ), ), ), Effect.forkChild, ); yield* Deferred.await(started); clock.mockReturnValue(now + 60_000); yield* TestClock.setTime(now + 60_000); yield* refreshActiveLiveActivityRemoteRegistration().pipe( Effect.provide(snapshotRelayLayer()), ); const publications = vi.mocked(publishAgentActivityWidget).mock.calls.length; clock.mockReturnValue(now + 120_000); yield* TestClock.setTime(now + 120_000); yield* Deferred.succeed(finish, undefined); yield* Fiber.join(older); expect(publishAgentActivityWidget).toHaveBeenCalledTimes(publications); expect(vi.mocked(publishAgentActivityWidget).mock.lastCall![0].expiresAt).toBe( now + 60_000 + AGENT_ACTIVITY_FRESHNESS_MS, ); }).pipe(Effect.scoped), ); it.effect("keeps a slow read's original deadline instead of freshening it on arrival", () => Effect.gen(function* () { const now = Date.parse("2026-10-02T12:00:00.000Z"); const clock = vi.spyOn(Date, "now").mockReturnValue(now); yield* TestClock.setTime(now); const started = yield* Deferred.make(); const finish = yield* Deferred.make(); setAgentAwarenessRelayTokenProvider(() => Promise.resolve("token-a"), "user-a"); backgroundRuntime.pending.length = 0; const refresh = yield* refreshActiveLiveActivityRemoteRegistration().pipe( Effect.provide( snapshotRelayLayer(() => Deferred.succeed(started, undefined).pipe( Effect.andThen(Deferred.await(finish)), Effect.as(activeAgentActivitySnapshot), ), ), ), Effect.forkChild, ); yield* Deferred.await(started); const arrivedAt = now + AGENT_ACTIVITY_FRESHNESS_MS + 1; clock.mockReturnValue(arrivedAt); yield* TestClock.setTime(arrivedAt); yield* Deferred.succeed(finish, undefined); yield* Fiber.join(refresh); const publication = vi.mocked(publishAgentActivityWidget).mock.lastCall![0]; expect(publication.expiresAt).toBe(now + AGENT_ACTIVITY_FRESHNESS_MS); expect(agentActivityTimeline(publication, arrivedAt)).toEqual([ { date: DateTime.toDateUtc(DateTime.makeUnsafe(arrivedAt)), props: expect.objectContaining({ isExpired: true, activeCount: -1 }), }, ]); }).pipe(Effect.scoped), ); it.effect("renews unchanged live observations and preserves their deadline on background", () => Effect.gen(function* () { const now = Date.parse("2026-10-02T12:00:00.000Z"); const clock = vi.spyOn(Date, "now").mockReturnValue(now); addLiveEnvironment(); setLiveShell("running"); setAgentAwarenessRelayTokenProvider(() => Promise.resolve("token-a"), "user-a"); backgroundRuntime.pending.length = 0; const layer = snapshotRelayLayer(({ excludedEnvironmentIds }) => Effect.succeed({ aggregate: null, excludedEnvironmentIds: excludedEnvironmentIds ?? [] }), ); yield* refreshActiveLiveActivityRemoteRegistration().pipe(Effect.provide(layer)); const original = vi.mocked(publishAgentActivityWidget).mock.lastCall![0]; clock.mockReturnValue(now + 60_000); setLiveShell("running"); yield* refreshActiveLiveActivityRemoteRegistration().pipe(Effect.provide(layer)); const renewed = vi.mocked(publishAgentActivityWidget).mock.lastCall![0]; expect(renewed.activities.map(({ updatedAt: _updatedAt, ...row }) => row)).toEqual( original.activities.map(({ updatedAt: _updatedAt, ...row }) => row), ); expect(renewed.expiresAt).toBe(now + 60_000 + AGENT_ACTIVITY_FRESHNESS_MS); const backgroundedAt = now + 120_000; clock.mockReturnValue(backgroundedAt); appStateMock.currentState = "background"; for (const listener of appStateMock.listeners) listener("background"); expect(vi.mocked(publishAgentActivityWidget).mock.lastCall![0]).toMatchObject({ isStale: false, expiresAt: renewed.expiresAt, }); const timeline = agentActivityTimeline(renewed, backgroundedAt); expect(timeline[0]?.props.isExpired).toBeUndefined(); expect(timeline[1]?.date.getTime()).toBe(renewed.expiresAt); expect(timeline[1]?.props.activities[0]).toMatchObject({ phase: "stale", status: "Out of date", }); }), ); it.effect("detaches the shell publisher on sign-out and provider release", () => { addLiveEnvironment(); setAgentAwarenessRelayTokenProvider(() => Promise.resolve("clerk-token-user-a"), "user-a"); backgroundRuntime.pending.length = 0; return Effect.gen(function* () { yield* refreshActiveLiveActivityRemoteRegistration(); setLiveShell("running"); releaseAgentAwarenessRelayTokenProvider(); const count = vi.mocked(publishAgentActivityWidget).mock.calls.length; setLiveShell("ready"); expect(publishAgentActivityWidget).toHaveBeenCalledTimes(count); expect(clearAgentAwarenessRegistrationRecord).not.toHaveBeenCalled(); setAgentAwarenessRelayTokenProvider(() => Promise.resolve("clerk-token-user-a"), "user-a"); yield* refreshActiveLiveActivityRemoteRegistration(); setAgentAwarenessRelayTokenProvider(null); const countAfterSignout = vi.mocked(publishAgentActivityWidget).mock.calls.length; setLiveShell("running"); expect(publishAgentActivityWidget).toHaveBeenCalledTimes(countAfterSignout); expect(publishAgentActivityWidget).toHaveBeenLastCalledWith( expect.objectContaining({ activeCount: 0, activities: [] }), ); }).pipe(Effect.provide(snapshotRelayLayer(() => Effect.succeed({ aggregate: null })))); }); it.effect("does not restore an in-flight widget snapshot after cloud sign-out", () => Effect.gen(function* () { const readStarted = yield* Deferred.make(); const finishRead = yield* Deferred.make(); const layer = snapshotRelayLayer(() => Deferred.succeed(readStarted, undefined).pipe( Effect.andThen(Deferred.await(finishRead)), Effect.as(activeAgentActivitySnapshot), ), ); setAgentAwarenessRelayTokenProvider(() => Promise.resolve("clerk-token-user-a")); backgroundRuntime.pending.length = 0; const refresh = yield* refreshActiveLiveActivityRemoteRegistration().pipe( Effect.provide(layer), Effect.forkChild, ); yield* Deferred.await(readStarted); setAgentAwarenessRelayTokenProvider(null); yield* Deferred.succeed(finishRead, undefined); yield* Fiber.join(refresh); expect(publishAgentActivityWidget).toHaveBeenCalledTimes(2); expect(publishAgentActivityWidget).toHaveBeenLastCalledWith( expect.objectContaining({ subtitle: "Sign in to see agent activity", isSignedOut: true, activeCount: 0, activities: [], }), ); }).pipe(Effect.scoped), ); });