mirror of
https://github.com/block/buzz.git
synced 2026-08-18 06:50:31 +02:00
chore(desktop): merge origin/main into workspace-scoped-agent-store
Adopt spawn_hash → spawn_snapshot rename from main; migrate spawn_config_hash: 0 test fixtures to prospective_spawn_config_snapshot() calls in global_agent_config tests, epoch tests, and runtime_commands tests. Co-authored-by: Will Pfleger <pfleger.will@gmail.com> Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
This commit is contained in:
co-authored by
Will Pfleger
commit
4634fe1b39
@@ -44,6 +44,7 @@ import {
|
||||
KIND_MEMBER_ADDED_NOTIFICATION,
|
||||
KIND_MEMBER_REMOVED_NOTIFICATION,
|
||||
KIND_PERSONA,
|
||||
KIND_PROJECT_ANNOUNCEMENT,
|
||||
KIND_REPO_ANNOUNCEMENT,
|
||||
KIND_REPO_STATE,
|
||||
KIND_STREAM_MESSAGE_EDIT,
|
||||
@@ -88,6 +89,7 @@ export type MockManagedAgentSeed = {
|
||||
lastError?: string | null;
|
||||
lastErrorCode?: number | null;
|
||||
needsRestart?: boolean;
|
||||
restartDiff?: Array<{ field: string; change: unknown }>;
|
||||
autoRestartOnConfigChange?: boolean;
|
||||
respondTo?: RawManagedAgent["respond_to"];
|
||||
respondToAllowlist?: string[];
|
||||
@@ -265,6 +267,8 @@ type E2eConfig = {
|
||||
parent_added: boolean;
|
||||
parent_error: string | null;
|
||||
};
|
||||
/** When set, the mocked `add_agent_to_huddle` command throws. */
|
||||
addAgentToHuddleError?: string;
|
||||
/** Delay an invocation-time huddle snapshot to exercise hydration ordering. */
|
||||
huddleStateReadDelayMs?: number;
|
||||
/** Delay companion creation to expose the newly-started huddle handoff state. */
|
||||
@@ -369,6 +373,8 @@ type E2eConfig = {
|
||||
// (e.g. a generic PDF) without a real upload pipeline. See
|
||||
// tests/helpers/bridge.ts:MockBridgeOptions.uploadDescriptors.
|
||||
uploadDelayMs?: number;
|
||||
/** Exercise the production composer path that queues files until send. */
|
||||
deferredComposerUploads?: boolean;
|
||||
/** Delay (ms) applied to `encode_agent_snapshot_for_send` so E2E tests can
|
||||
* observe the "preparing" phase before the upload begins. 0/undefined = instant. */
|
||||
encodeDelayMs?: number;
|
||||
@@ -398,21 +404,6 @@ type E2eConfig = {
|
||||
// Seed rows returned by `list_save_subscriptions`. Each entry uses the same
|
||||
// snake_case wire shape the Rust backend returns so tests can drive the
|
||||
// LocalArchiveSettingsCard without a real SQLite database.
|
||||
observerArchiveDefaultEnabled?: boolean;
|
||||
/**
|
||||
* Delay (ms) applied to `observer_archive_default_enabled` so E2E tests
|
||||
* can exercise short-lived loading UI. 0/undefined = instant. Prefer the
|
||||
* explicit defer/release seam for pending-state ordering assertions.
|
||||
*/
|
||||
observerArchiveDefaultEnabledDelayMs?: number;
|
||||
/** Hold the observer policy command until the E2E release seam is called. */
|
||||
deferObserverArchiveDefaultEnabled?: boolean;
|
||||
/**
|
||||
* When set, `observer_archive_default_enabled` throws with this message
|
||||
* instead of resolving — drives the fail-closed `.catch()` path in
|
||||
* `useObserverArchiveReconciliation` / `LocalArchiveSettingsCard`.
|
||||
*/
|
||||
observerArchiveDefaultEnabledError?: string;
|
||||
agentMetricArchiveDefaultEnabled?: boolean;
|
||||
saveSubscriptions?: Array<{
|
||||
scope_type: string;
|
||||
@@ -824,6 +815,7 @@ type RawManagedAgent = {
|
||||
last_error: string | null;
|
||||
last_error_code: number | null;
|
||||
needs_restart?: boolean;
|
||||
restart_diff?: Array<{ field: string; change: unknown }>;
|
||||
log_path: string;
|
||||
start_on_app_launch: boolean;
|
||||
auto_restart_on_config_change?: boolean;
|
||||
@@ -1066,6 +1058,15 @@ declare global {
|
||||
command: string;
|
||||
payload: unknown;
|
||||
}>;
|
||||
__BUZZ_E2E_EMIT_MEDIA_UPLOAD_PHASE__?: (input: {
|
||||
id: string;
|
||||
phase: string;
|
||||
}) => Promise<void>;
|
||||
__BUZZ_E2E_EMIT_MEDIA_UPLOAD_PROGRESS__?: (input: {
|
||||
id: string;
|
||||
sent: number;
|
||||
total: number;
|
||||
}) => Promise<void>;
|
||||
__BUZZ_E2E_EMIT_MOCK_HUDDLE_TTS_SPEAKER__?: (payload: {
|
||||
pubkey: string | null;
|
||||
level: number;
|
||||
@@ -1134,8 +1135,33 @@ declare global {
|
||||
kind: number;
|
||||
tags: string[][];
|
||||
}>;
|
||||
/** Project-scoped events accepted by the mock relay. */
|
||||
__BUZZ_E2E_ACCEPTED_PROJECT_EVENTS__?: Array<{
|
||||
content: string;
|
||||
kind: number;
|
||||
tags: string[][];
|
||||
}>;
|
||||
/** Project event kinds rejected once, in order, to exercise retry flows. */
|
||||
__BUZZ_E2E_REJECT_PROJECT_EVENT_KINDS__?: number[];
|
||||
/** Makes the mock relay reject project announcements as an unknown kind. */
|
||||
__BUZZ_E2E_UNSUPPORTED_PROJECT_ANNOUNCEMENTS__?: boolean;
|
||||
/** Project event kinds accepted once but reported as failed to test lost acknowledgements. */
|
||||
__BUZZ_E2E_FAIL_PROJECT_EVENT_ACK_KINDS__?: number[];
|
||||
/**
|
||||
* Extra project events appended to the mock store on first access.
|
||||
* Use to seed standalone repositories (kind 30617) or other project-scoped
|
||||
* events before a test interaction, without mutating the fixed seed data.
|
||||
* Events must be complete RelayEvent shapes; id is a required field so that
|
||||
* id-keyed queries (e.g. lost-ACK recovery) can match them.
|
||||
*/
|
||||
__BUZZ_E2E_EXTRA_PROJECT_EVENTS__?: Array<{
|
||||
id: string;
|
||||
kind: number;
|
||||
pubkey: string;
|
||||
created_at: number;
|
||||
content: string;
|
||||
tags: string[][];
|
||||
}>;
|
||||
/** Structured merge error returned by the mock native merge command. */
|
||||
__BUZZ_E2E_PROJECT_MERGE_ERROR__?: {
|
||||
code: string;
|
||||
@@ -1173,6 +1199,12 @@ declare global {
|
||||
};
|
||||
__BUZZ_E2E_SET_RELAY_CONNECTION_STATE__?: (state: ConnectionState) => void;
|
||||
__BUZZ_E2E_GET_RELAY_CONNECTION_STATE__?: () => ConnectionState;
|
||||
/** Queue deterministic mock AUTH outcomes, consumed in order. */
|
||||
__BUZZ_E2E_QUEUE_AUTH_RESPONSES__?: (
|
||||
responses: Array<{ success: boolean; message: string }>,
|
||||
) => void;
|
||||
/** Inject CLOSED into every active mock live subscription. */
|
||||
__BUZZ_E2E_CLOSE_LIVE_SUBSCRIPTIONS__?: (reason: string) => number;
|
||||
__BUZZ_E2E_SET_STALL_WEBSOCKET_SENDS__?: (stall: boolean) => void;
|
||||
__BUZZ_E2E_DISCONNECT_MOCK_WEBSOCKETS__?: () => number;
|
||||
__BUZZ_E2E_RESTART_MOCK_WEBSOCKETS__?: () => number;
|
||||
@@ -1279,10 +1311,6 @@ declare global {
|
||||
/** Count of `get_event` invocations for the current defer-target ID since
|
||||
* the last time `__BUZZ_E2E_DEFER_GET_EVENT__` was set. */
|
||||
__BUZZ_E2E_GET_EVENT_CALL_COUNT__?: number;
|
||||
/** Release every deferred observer archive policy command. */
|
||||
__BUZZ_E2E_RELEASE_OBSERVER_ARCHIVE_POLICY__?: () => number;
|
||||
/** Number of observer archive policy commands currently held by the seam. */
|
||||
__BUZZ_E2E_OBSERVER_ARCHIVE_POLICY_PENDING__?: number;
|
||||
/** Hold the next channel read until released. */
|
||||
__BUZZ_E2E_DEFER_NEXT_CHANNELS_READ__?: () => void;
|
||||
/** Disarm the latch and release the held channel read, if any. */
|
||||
@@ -1392,7 +1420,6 @@ type DeferredGetEvent = {
|
||||
run: () => Promise<string>;
|
||||
};
|
||||
let deferredGetEventQueue: DeferredGetEvent[] = [];
|
||||
let deferredObserverArchivePolicyQueue: Array<() => void> = [];
|
||||
let deferNextChannelsRead = false;
|
||||
let deferredChannelsReadResolve: (() => void) | null = null;
|
||||
|
||||
@@ -1616,6 +1643,7 @@ function cloneManagedAgent(agent: MockManagedAgent): RawManagedAgent {
|
||||
last_error: agent.last_error,
|
||||
last_error_code: agent.last_error_code,
|
||||
needs_restart: agent.needs_restart ?? false,
|
||||
restart_diff: agent.restart_diff ? [...agent.restart_diff] : [],
|
||||
log_path: agent.log_path,
|
||||
start_on_app_launch: agent.start_on_app_launch,
|
||||
auto_restart_on_config_change: agent.auto_restart_on_config_change ?? true,
|
||||
@@ -2169,6 +2197,7 @@ function buildSeededManagedAgent(seed: MockManagedAgentSeed): MockManagedAgent {
|
||||
last_error: seed.lastError ?? null,
|
||||
last_error_code: seed.lastErrorCode ?? null,
|
||||
needs_restart: seed.needsRestart ?? false,
|
||||
restart_diff: seed.restartDiff ?? [],
|
||||
log_path: `/tmp/mock-agent-${seed.pubkey}.log`,
|
||||
start_on_app_launch: true,
|
||||
auto_restart_on_config_change: seed.autoRestartOnConfigChange ?? true,
|
||||
@@ -2927,6 +2956,7 @@ const mockReminderEvents: RelayEvent[] = [];
|
||||
const mockPersonaEvents: RelayEvent[] = [];
|
||||
let mockRelayMembers: RawRelayMember[] = [];
|
||||
const mockSockets = new Map<number, MockSocket>();
|
||||
const mockAuthResponses: Array<{ success: boolean; message: string }> = [];
|
||||
let mockWebsocketUnavailable = false;
|
||||
const relayWebsocketConnectAttemptStarts: number[] = [];
|
||||
let mockWebsocketSendMutexWedged = false;
|
||||
@@ -2941,8 +2971,8 @@ let mockManagedAgentRuntimes: MockManagedAgentRuntimeRow[] = [];
|
||||
// mutated by `create_save_subscription` / `delete_save_subscription` /
|
||||
// `merge_save_subscription_kinds` / `remove_save_subscription_kind` exactly
|
||||
// as the real SQLite-backed Rust commands would (see `archive/store.rs`).
|
||||
// This lets E2E specs drive the fresh-internal-repair path (start from `[]`,
|
||||
// reconcile, observe a kind-24200 row appear) and OSS toggle ON/OFF, neither
|
||||
// This lets E2E specs drive the default-on seeding path (start from `[]`,
|
||||
// reconcile, observe a kind-24200 row appear) and toggle ON/OFF, neither
|
||||
// of which an immutable seed can represent.
|
||||
type MockSaveSubscriptionRow = {
|
||||
scope_type: string;
|
||||
@@ -3041,7 +3071,7 @@ type MockHuddleState = {
|
||||
tts_enabled: boolean;
|
||||
transcription_enabled: boolean;
|
||||
is_creator: boolean;
|
||||
voice_input_mode: "voice_activity";
|
||||
voice_input_mode: "push_to_talk" | "voice_activity";
|
||||
};
|
||||
|
||||
type PersistedMockHuddle = {
|
||||
@@ -3156,7 +3186,7 @@ function initializeMockHuddle(
|
||||
tts_enabled: seed.ttsEnabled ?? false,
|
||||
transcription_enabled: seed.transcriptionEnabled ?? false,
|
||||
is_creator: seed.isCreator ?? true,
|
||||
voice_input_mode: "voice_activity",
|
||||
voice_input_mode: "push_to_talk",
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -5190,6 +5220,7 @@ const MOCK_PROJECT_SEEDS = [
|
||||
name: "buzz",
|
||||
description:
|
||||
"Relay, desktop, and mobile clients for the Buzz community platform.",
|
||||
cloneUrl: `${DEFAULT_RELAY_HTTP_URL}/git/${MOCK_IDENTITY_PUBKEY}/buzz`,
|
||||
owner: MOCK_IDENTITY_PUBKEY,
|
||||
contributors: [ALICE_PUBKEY, BOB_PUBKEY, CHARLIE_PUBKEY],
|
||||
activityLevel: 4,
|
||||
@@ -5198,6 +5229,7 @@ const MOCK_PROJECT_SEEDS = [
|
||||
dtag: "relay-tools",
|
||||
name: "relay-tools",
|
||||
description: "Operator tooling and admin CLI for relay deployments.",
|
||||
cloneUrl: "https://github.com/block/relay-tools.git",
|
||||
owner: ALICE_PUBKEY,
|
||||
contributors: [MOCK_IDENTITY_PUBKEY, BOB_PUBKEY],
|
||||
activityLevel: 2,
|
||||
@@ -5206,6 +5238,7 @@ const MOCK_PROJECT_SEEDS = [
|
||||
dtag: "design-system",
|
||||
name: "design-system",
|
||||
description: "Shared UI tokens, typography ramps, and component library.",
|
||||
cloneUrl: `${DEFAULT_RELAY_HTTP_URL}/git/${BOB_PUBKEY}/design-system`,
|
||||
owner: BOB_PUBKEY,
|
||||
contributors: [ALICE_PUBKEY],
|
||||
activityLevel: 1,
|
||||
@@ -5224,6 +5257,7 @@ const MOCK_PROJECT_SUBJECTS = [
|
||||
];
|
||||
|
||||
const MOCK_PROJECT_KINDS = new Set<number>([
|
||||
KIND_PROJECT_ANNOUNCEMENT,
|
||||
KIND_REPO_ANNOUNCEMENT,
|
||||
KIND_REPO_STATE,
|
||||
KIND_GIT_PATCH,
|
||||
@@ -5302,7 +5336,8 @@ function buildMockProjectEvents(): RelayEvent[] {
|
||||
["d", seed.dtag],
|
||||
["name", seed.name],
|
||||
["description", seed.description],
|
||||
["clone", `https://relay.example.com/git/${owner}/${seed.dtag}`],
|
||||
["buzz-channel", "9a1657ac-f7aa-5db0-b632-d8bbeb6dfb50"],
|
||||
["clone", seed.cloneUrl],
|
||||
...seed.contributors.map((pubkey) => ["p", pubkey]),
|
||||
],
|
||||
owner,
|
||||
@@ -5367,10 +5402,7 @@ function buildMockProjectEvents(): RelayEvent[] {
|
||||
? [
|
||||
["h", "9a1657ac-f7aa-5db0-b632-d8bbeb6dfb50"],
|
||||
["branch-name", `feature/mock-${dayOffset}-${index}`],
|
||||
[
|
||||
"clone",
|
||||
`https://relay.example.com/git/${owner}/${seed.dtag}`,
|
||||
],
|
||||
["clone", seed.cloneUrl],
|
||||
]
|
||||
: []),
|
||||
];
|
||||
@@ -5380,11 +5412,39 @@ function buildMockProjectEvents(): RelayEvent[] {
|
||||
}
|
||||
}
|
||||
|
||||
const projectOwner =
|
||||
window.__BUZZ_E2E_PROJECT_OWNER_OVERRIDE__ ?? MOCK_PROJECT_SEEDS[0].owner;
|
||||
events.push(
|
||||
createMockEvent(
|
||||
KIND_PROJECT_ANNOUNCEMENT,
|
||||
"",
|
||||
[
|
||||
["d", "buzz"],
|
||||
["name", "buzz"],
|
||||
["description", "The complete Buzz community platform."],
|
||||
["a", `${KIND_REPO_ANNOUNCEMENT}:${projectOwner}:buzz`],
|
||||
["a", `${KIND_REPO_ANNOUNCEMENT}:${ALICE_PUBKEY}:relay-tools`],
|
||||
],
|
||||
projectOwner,
|
||||
now,
|
||||
"project-buzz".padEnd(64, "0"),
|
||||
),
|
||||
);
|
||||
|
||||
return events;
|
||||
}
|
||||
|
||||
function getMockProjectEventStore(): RelayEvent[] {
|
||||
mockProjectEventStore ??= buildMockProjectEvents();
|
||||
if (!mockProjectEventStore) {
|
||||
mockProjectEventStore = buildMockProjectEvents();
|
||||
// Append any extra events injected by the test via addInitScript before
|
||||
// the app boots. This lets a test seed standalone repositories or other
|
||||
// project-scoped events without modifying the fixed seed data.
|
||||
const extras = window.__BUZZ_E2E_EXTRA_PROJECT_EVENTS__;
|
||||
if (extras && extras.length > 0) {
|
||||
mockProjectEventStore.push(...(extras as RelayEvent[]));
|
||||
}
|
||||
}
|
||||
return mockProjectEventStore;
|
||||
}
|
||||
|
||||
@@ -5396,19 +5456,23 @@ function isMockProjectScopedEvent(event: RelayEvent): boolean {
|
||||
(tag) => tag[0] === "a" && (tag[1] ?? "").startsWith("30617:"),
|
||||
);
|
||||
return (
|
||||
hasRepoAddressTag &&
|
||||
(event.kind === KIND_REPO_ANNOUNCEMENT || hasRepoAddressTag) &&
|
||||
(event.kind === 1 || MOCK_PROJECT_KINDS.has(event.kind))
|
||||
);
|
||||
}
|
||||
|
||||
function filterMockProjectEvents(filter: MockFilter): RelayEvent[] {
|
||||
const authors = filter.authors?.map((author) => author.toLowerCase());
|
||||
const idsSet =
|
||||
filter.ids && filter.ids.length > 0 ? new Set(filter.ids) : null;
|
||||
return getMockProjectEventStore()
|
||||
.filter((event) => {
|
||||
if (filter.kinds && !filter.kinds.includes(event.kind)) return false;
|
||||
if (authors && !authors.includes(event.pubkey.toLowerCase())) {
|
||||
return false;
|
||||
}
|
||||
// Filter by event ids when present — required for lost-ACK recovery queries.
|
||||
if (idsSet && !idsSet.has(event.id)) return false;
|
||||
if (
|
||||
filter["#d"] &&
|
||||
!event.tags.some(
|
||||
@@ -8806,7 +8870,7 @@ async function resolveMockUploadDescriptors(
|
||||
}
|
||||
|
||||
async function resolveMockUploadDescriptorForBytes(
|
||||
args: { data: number[]; filename?: string | null },
|
||||
args: { data: number[] | Uint8Array; filename?: string | null },
|
||||
config: E2eConfig | undefined,
|
||||
): Promise<RawBlobDescriptor> {
|
||||
const configured = config?.mock?.uploadDescriptors;
|
||||
@@ -9428,7 +9492,16 @@ function sendToMockSocket(args: {
|
||||
|
||||
if (type === "AUTH") {
|
||||
const event = rest[0] as RelayEvent;
|
||||
sendWsText(socket.handler, ["OK", event.id, true, ""]);
|
||||
const response = mockAuthResponses.shift() ?? {
|
||||
success: true,
|
||||
message: "",
|
||||
};
|
||||
sendWsText(socket.handler, [
|
||||
"OK",
|
||||
event.id,
|
||||
response.success,
|
||||
response.message,
|
||||
]);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -9724,6 +9797,18 @@ function sendToMockSocket(args: {
|
||||
]);
|
||||
return;
|
||||
}
|
||||
if (
|
||||
event.kind === KIND_PROJECT_ANNOUNCEMENT &&
|
||||
window.__BUZZ_E2E_UNSUPPORTED_PROJECT_ANNOUNCEMENTS__
|
||||
) {
|
||||
sendWsText(socket.handler, [
|
||||
"OK",
|
||||
event.id,
|
||||
false,
|
||||
"restricted: unknown event kind",
|
||||
]);
|
||||
return;
|
||||
}
|
||||
const rejectionIndex =
|
||||
window.__BUZZ_E2E_REJECT_PROJECT_EVENT_KINDS__?.indexOf(event.kind) ??
|
||||
-1;
|
||||
@@ -9741,6 +9826,30 @@ function sendToMockSocket(args: {
|
||||
return;
|
||||
}
|
||||
getMockProjectEventStore().push(event);
|
||||
const acceptedProjectEvents =
|
||||
window.__BUZZ_E2E_ACCEPTED_PROJECT_EVENTS__ ?? [];
|
||||
acceptedProjectEvents.push({
|
||||
content: event.content,
|
||||
kind: event.kind,
|
||||
tags: event.tags,
|
||||
});
|
||||
window.__BUZZ_E2E_ACCEPTED_PROJECT_EVENTS__ = acceptedProjectEvents;
|
||||
const failedAckIndex =
|
||||
window.__BUZZ_E2E_FAIL_PROJECT_EVENT_ACK_KINDS__?.indexOf(event.kind) ??
|
||||
-1;
|
||||
if (failedAckIndex >= 0) {
|
||||
window.__BUZZ_E2E_FAIL_PROJECT_EVENT_ACK_KINDS__?.splice(
|
||||
failedAckIndex,
|
||||
1,
|
||||
);
|
||||
sendWsText(socket.handler, [
|
||||
"OK",
|
||||
event.id,
|
||||
false,
|
||||
"mock lost project acknowledgement",
|
||||
]);
|
||||
return;
|
||||
}
|
||||
sendWsText(socket.handler, ["OK", event.id, true, ""]);
|
||||
return;
|
||||
}
|
||||
@@ -9791,6 +9900,7 @@ export function maybeInstallE2eTauriMocks() {
|
||||
|
||||
mockClosedChannelLiveSubscription = false;
|
||||
mockWebsocketUnavailable = false;
|
||||
mockAuthResponses.length = 0;
|
||||
relayWebsocketConnectAttemptStarts.length = 0;
|
||||
mockGlobalAgentConfig = config.mock?.globalAgentConfig
|
||||
? { ...config.mock.globalAgentConfig }
|
||||
@@ -9820,6 +9930,12 @@ export function maybeInstallE2eTauriMocks() {
|
||||
emit("huddle-tts-speaker-level", payload);
|
||||
window.__BUZZ_E2E_SIGNED_EVENTS__ = [];
|
||||
window.__BUZZ_E2E_WEBVIEW_ZOOM__ = 1;
|
||||
window.__BUZZ_E2E_EMIT_MEDIA_UPLOAD_PHASE__ = async (input) => {
|
||||
await emit("media-upload-phase", input);
|
||||
};
|
||||
window.__BUZZ_E2E_EMIT_MEDIA_UPLOAD_PROGRESS__ = async (input) => {
|
||||
await emit("media-upload-progress", input);
|
||||
};
|
||||
window.__BUZZ_E2E_SET_MOCK_HUDDLE_SNAPSHOT__ = async ({
|
||||
members,
|
||||
transcriptionEnabled,
|
||||
@@ -9958,14 +10074,6 @@ export function maybeInstallE2eTauriMocks() {
|
||||
window.__BUZZ_E2E_GET_EVENT_CALL_COUNT__ = 0;
|
||||
window.__BUZZ_E2E_DEFER_GET_EVENT__ = null;
|
||||
deferredGetEventQueue = [];
|
||||
deferredObserverArchivePolicyQueue = [];
|
||||
window.__BUZZ_E2E_OBSERVER_ARCHIVE_POLICY_PENDING__ = 0;
|
||||
window.__BUZZ_E2E_RELEASE_OBSERVER_ARCHIVE_POLICY__ = () => {
|
||||
const queued = deferredObserverArchivePolicyQueue.splice(0);
|
||||
window.__BUZZ_E2E_OBSERVER_ARCHIVE_POLICY_PENDING__ = 0;
|
||||
for (const resolve of queued) resolve();
|
||||
return queued.length;
|
||||
};
|
||||
deferNextChannelsRead = false;
|
||||
deferredChannelsReadResolve = null;
|
||||
window.__BUZZ_E2E_CHANNELS_READ_PENDING__ = 0;
|
||||
@@ -10032,6 +10140,20 @@ export function maybeInstallE2eTauriMocks() {
|
||||
};
|
||||
window.__BUZZ_E2E_GET_RELAY_CONNECTION_STATE__ = () =>
|
||||
relayClient.getConnectionState();
|
||||
window.__BUZZ_E2E_QUEUE_AUTH_RESPONSES__ = (responses) => {
|
||||
mockAuthResponses.push(...responses);
|
||||
};
|
||||
window.__BUZZ_E2E_CLOSE_LIVE_SUBSCRIPTIONS__ = (reason) => {
|
||||
let closed = 0;
|
||||
for (const socket of mockSockets.values()) {
|
||||
for (const subId of [...socket.subscriptions.keys()]) {
|
||||
sendWsText(socket.handler, ["CLOSED", subId, reason]);
|
||||
socket.subscriptions.delete(subId);
|
||||
closed += 1;
|
||||
}
|
||||
}
|
||||
return closed;
|
||||
};
|
||||
|
||||
window.__BUZZ_E2E_SEED_MOCK_REMINDERS__ = (reminders) => {
|
||||
mockReminderEvents.length = 0;
|
||||
@@ -10160,6 +10282,9 @@ export function maybeInstallE2eTauriMocks() {
|
||||
const identity = getActiveIdentity(activeConfig);
|
||||
window.__BUZZ_E2E_COMMANDS__?.push(command);
|
||||
const loggedPayload = (() => {
|
||||
if (payload instanceof Uint8Array) {
|
||||
return { rawByteLength: payload.byteLength };
|
||||
}
|
||||
try {
|
||||
return JSON.parse(JSON.stringify(payload ?? null));
|
||||
} catch {
|
||||
@@ -10181,6 +10306,21 @@ export function maybeInstallE2eTauriMocks() {
|
||||
}
|
||||
return snapshot;
|
||||
}
|
||||
case "get_voice_input_mode":
|
||||
return mockHuddle?.state.voice_input_mode ?? "push_to_talk";
|
||||
case "set_voice_input_mode": {
|
||||
if (!mockHuddle) throw new Error("No active mock huddle.");
|
||||
const mode = (payload as { mode?: unknown }).mode;
|
||||
if (mode !== "push_to_talk" && mode !== "voice_activity") {
|
||||
throw new Error("Missing voice input mode.");
|
||||
}
|
||||
mockHuddle.state.voice_input_mode = mode;
|
||||
persistMockHuddle();
|
||||
await emitMockHuddleState();
|
||||
return null;
|
||||
}
|
||||
case "set_huddle_manual_mic_unmuted":
|
||||
return null;
|
||||
case "get_huddle_agent_pubkeys":
|
||||
if (!mockHuddle) return [];
|
||||
return [...mockHuddle.state.agent_pubkeys];
|
||||
@@ -10212,7 +10352,7 @@ export function maybeInstallE2eTauriMocks() {
|
||||
tts_enabled: false,
|
||||
transcription_enabled: false,
|
||||
is_creator: true,
|
||||
voice_input_mode: "voice_activity",
|
||||
voice_input_mode: "push_to_talk",
|
||||
},
|
||||
};
|
||||
refreshMockHuddleMembership(activeConfig);
|
||||
@@ -10306,7 +10446,7 @@ export function maybeInstallE2eTauriMocks() {
|
||||
tts_enabled: false,
|
||||
transcription_enabled: false,
|
||||
is_creator: false,
|
||||
voice_input_mode: "voice_activity",
|
||||
voice_input_mode: "push_to_talk",
|
||||
});
|
||||
return null;
|
||||
case "set_huddle_transcription_enabled":
|
||||
@@ -10387,12 +10527,33 @@ export function maybeInstallE2eTauriMocks() {
|
||||
return { matched_active_huddle: true, added };
|
||||
}
|
||||
case "add_agent_to_huddle": {
|
||||
const error = activeConfig?.mock?.addAgentToHuddleError;
|
||||
if (error) {
|
||||
throw new Error(error);
|
||||
}
|
||||
const result = activeConfig?.mock?.addAgentToHuddleResult;
|
||||
if (!result) {
|
||||
throw new Error("No mock add-agent result configured.");
|
||||
}
|
||||
return structuredClone(result);
|
||||
}
|
||||
case "remove_agent_from_huddle": {
|
||||
const agentPubkey = (payload as { agentPubkey?: string })?.agentPubkey;
|
||||
if (!mockHuddle || !agentPubkey) {
|
||||
throw new Error("No active huddle agent to remove.");
|
||||
}
|
||||
const initialCount = mockHuddle.members.length;
|
||||
mockHuddle.members = mockHuddle.members.filter(
|
||||
(member) => member.role !== "bot" || member.pubkey !== agentPubkey,
|
||||
);
|
||||
if (mockHuddle.members.length === initialCount) {
|
||||
throw new Error("Agent is not in this huddle.");
|
||||
}
|
||||
refreshMockHuddleMembership(activeConfig);
|
||||
persistMockHuddle();
|
||||
await emitMockHuddleState();
|
||||
return;
|
||||
}
|
||||
case "get_model_status":
|
||||
return { stt: "ready", tts: "ready" };
|
||||
case "get_tts_settings":
|
||||
@@ -10525,6 +10686,8 @@ export function maybeInstallE2eTauriMocks() {
|
||||
}
|
||||
return settings;
|
||||
}
|
||||
case "interrupt_huddle_speech":
|
||||
return;
|
||||
case "set_pocket_voice": {
|
||||
const voiceKey = (payload as { voiceKey?: string })?.voiceKey;
|
||||
if (!voiceKey) throw new Error("Missing Pocket voice key");
|
||||
@@ -12309,6 +12472,13 @@ export function maybeInstallE2eTauriMocks() {
|
||||
payload as { data: number[]; filename?: string | null },
|
||||
activeConfig,
|
||||
);
|
||||
case "upload_media_bytes_raw":
|
||||
return resolveMockUploadDescriptorForBytes(
|
||||
{
|
||||
data: payload as Uint8Array,
|
||||
},
|
||||
activeConfig,
|
||||
);
|
||||
case "fetch_media_bytes": {
|
||||
// The real command fetches relay media through Rust reqwest and
|
||||
// replies with raw bytes (`tauri::ipc::Response` → ArrayBuffer). In
|
||||
@@ -12587,7 +12757,7 @@ export function maybeInstallE2eTauriMocks() {
|
||||
// install); create/merge/delete/remove mutate it with the same
|
||||
// union / delete-row-when-empty semantics as the real Rust commands
|
||||
// (see `archive/store.rs::merge_owner_p_kinds` / `remove_owner_p_kind`)
|
||||
// so specs can drive fresh-internal-repair and toggle ON/OFF flows.
|
||||
// so specs can drive default-on seeding and toggle ON/OFF flows.
|
||||
case "list_save_subscriptions": {
|
||||
const win = window as unknown as Record<string, unknown>;
|
||||
if (!win.__BUZZ_E2E_IPC_COUNTERS__) {
|
||||
@@ -12645,27 +12815,8 @@ export function maybeInstallE2eTauriMocks() {
|
||||
case "archive_events":
|
||||
// Returns the ArchiveBatchResult shape the UI expects.
|
||||
return { persisted: 0, dropped: 0 };
|
||||
case "observer_archive_default_enabled": {
|
||||
if (activeConfig?.mock?.deferObserverArchiveDefaultEnabled) {
|
||||
await new Promise<void>((resolve) => {
|
||||
deferredObserverArchivePolicyQueue.push(resolve);
|
||||
window.__BUZZ_E2E_OBSERVER_ARCHIVE_POLICY_PENDING__ =
|
||||
deferredObserverArchivePolicyQueue.length;
|
||||
});
|
||||
}
|
||||
const delayMs =
|
||||
activeConfig?.mock?.observerArchiveDefaultEnabledDelayMs;
|
||||
if (delayMs && delayMs > 0) {
|
||||
await new Promise((resolve) => window.setTimeout(resolve, delayMs));
|
||||
}
|
||||
const error = activeConfig?.mock?.observerArchiveDefaultEnabledError;
|
||||
if (error) {
|
||||
throw new Error(error);
|
||||
}
|
||||
return activeConfig?.mock?.observerArchiveDefaultEnabled ?? false;
|
||||
}
|
||||
case "agent_metric_archive_default_enabled":
|
||||
return activeConfig?.mock?.agentMetricArchiveDefaultEnabled ?? false;
|
||||
return activeConfig?.mock?.agentMetricArchiveDefaultEnabled ?? true;
|
||||
case "set_prevent_sleep_active":
|
||||
return null;
|
||||
case "plugin:window|is_fullscreen":
|
||||
|
||||
Reference in New Issue
Block a user