| 1 | import { act } from "react"; |
| 2 | |
| 3 | import type { SettingsView } from "../lib/types"; |
| 4 | |
| 5 | export function flushPromises(): Promise<void> { |
| 6 | return new Promise((resolve) => setTimeout(resolve, 0)); |
| 7 | } |
| 8 | |
| 9 | export function installCanvasMock(win: Window) { |
| 10 | const canvasElement = (win as Window & typeof globalThis).HTMLCanvasElement; |
| 11 | Object.defineProperty(canvasElement.prototype, "getContext", { |
| 12 | configurable: true, |
| 13 | value(type: string) { |
| 14 | if (type !== "2d") return null; |
| 15 | return { |
| 16 | font: "", |
| 17 | measureText: () => ({ width: 0 }), |
| 18 | } as unknown as CanvasRenderingContext2D; |
| 19 | }, |
| 20 | }); |
| 21 | } |
| 22 | |
| 23 | export async function waitFor(label: string, predicate: () => boolean) { |
| 24 | for (let attempt = 0; attempt < 20; attempt += 1) { |
| 25 | await act(async () => { |
| 26 | await flushPromises(); |
| 27 | }); |
| 28 | if (predicate()) return; |
| 29 | } |
| 30 | throw new Error(`timed out waiting for ${label}`); |
| 31 | } |
| 32 | |
| 33 | export function baseSettings(displayMode: "standard" | "compact" = "standard"): SettingsView { |
| 34 | return { |
| 35 | modelSettingsFingerprint: "test-model-settings-revision", |
| 36 | defaultModel: "", |
| 37 | plannerModel: "", |
| 38 | visionModel: "", |
| 39 | subagentModel: "", |
| 40 | subagentEffort: "", |
| 41 | autoPlan: "off", |
| 42 | providers: [], |
| 43 | officialProviders: [], |
| 44 | providerPresets: [], |
| 45 | permissions: { mode: "ask", allow: [], ask: [], deny: [] }, |
| 46 | sandbox: { bash: "enforce", network: false, workspaceRoot: "", allowWrite: [], effectiveWorkspaceRoot: "/work", effectiveWriteRoots: ["/work"], shell: "auto", shellCapabilities: [{ id: "bash", variant: "system", available: true, path: "/bin/bash", source: "path" }] }, |
| 47 | network: { proxyMode: "auto", proxyUrl: "", noProxy: "", proxy: { type: "socks5", server: "", port: 0, username: "", password: "" } }, |
| 48 | agent: { temperature: 0, maxSteps: 0, plannerMaxSteps: 0, maxSubagentDepth: 2, maxSubagentConcurrency: 6, maxParallelWriters: 3, systemPrompt: "", reasoningLanguage: "auto", compactRatio: 0.80 }, |
| 49 | bot: { |
| 50 | enabled: false, |
| 51 | model: "", |
| 52 | toolApprovalMode: "", |
| 53 | maxSteps: 0, |
| 54 | debounceMs: 0, |
| 55 | queueMode: "steer", |
| 56 | queueCap: 20, |
| 57 | queueDrop: "summarize", |
| 58 | ignoreSelfMessages: true, |
| 59 | selfUserIds: { qq: [], feishu: [], weixin: [], dingtalk: [] }, |
| 60 | control: { enabled: false, addr: "127.0.0.1:37913", tokenEnv: "REASONIX_BOT_CONTROL_TOKEN" }, |
| 61 | pairing: { enabled: true, requestTtlMinutes: 60, maxPendingPerPlatform: 3 }, |
| 62 | routes: [], |
| 63 | allowlist: { |
| 64 | enabled: false, |
| 65 | allowAll: false, |
| 66 | qqUsers: [], |
| 67 | feishuUsers: [], |
| 68 | weixinUsers: [], |
| 69 | qqApprovers: [], |
| 70 | feishuApprovers: [], |
| 71 | weixinApprovers: [], |
| 72 | qqAdmins: [], |
| 73 | feishuAdmins: [], |
| 74 | weixinAdmins: [], |
| 75 | qqGroups: [], |
| 76 | feishuGroups: [], |
| 77 | weixinGroups: [], |
| 78 | dingtalkUsers: [], |
| 79 | dingtalkApprovers: [], |
| 80 | dingtalkAdmins: [], |
| 81 | dingtalkGroups: [], |
| 82 | }, |
| 83 | qq: { |
| 84 | enabled: false, |
| 85 | appId: "", |
| 86 | appSecretEnv: "", |
| 87 | secretSet: false, |
| 88 | sandbox: false, |
| 89 | model: "", |
| 90 | toolApprovalMode: "ask", |
| 91 | workspaceRoot: "", |
| 92 | access: { enabled: true, allowAll: false, pairingEnabled: true, users: [], groups: [], approvers: [], admins: [] }, |
| 93 | }, |
| 94 | feishu: { enabled: false, domain: "feishu", appId: "", appSecretEnv: "", secretSet: false, verificationToken: "", mode: "webhook", webhookPort: 0, requireMention: false }, |
| 95 | weixin: { enabled: false, accountId: "", tokenEnv: "", tokenSet: false, apiBase: "" }, |
| 96 | dingtalk: { enabled: false, clientId: "", clientSecretEnv: "DINGTALK_CLIENT_SECRET", secretSet: false, botName: "", requireMention: true, model: "", toolApprovalMode: "", workspaceRoot: "", access: { enabled: true, allowAll: false, pairingEnabled: true, users: [], groups: [], approvers: [], admins: [] } }, |
| 97 | connections: [], |
| 98 | }, |
| 99 | desktopLanguage: "en", |
| 100 | desktopTheme: "auto", |
| 101 | desktopThemeStyle: "graphite", |
| 102 | desktopTerminalTheme: "auto", |
| 103 | closeBehavior: "background", |
| 104 | displayMode, |
| 105 | reasoningDisplayMode: "auto", |
| 106 | reasoningDisplayModeExplicit: false, |
| 107 | statusBarStyle: "text", |
| 108 | statusBarItems: ["model", "workspace", "git_branch", "cache", "balance"], |
| 109 | defaultToolApprovalMode: "auto", |
| 110 | checkUpdates: true, |
| 111 | updaterEnabled: true, |
| 112 | updateChannel: "stable", |
| 113 | telemetry: true, |
| 114 | metrics: true, |
| 115 | configPath: "/tmp/reasonix/config.toml", |
| 116 | providerKinds: [], |
| 117 | autoApproveTools: false, |
| 118 | bypass: false, |
| 119 | }; |
| 120 | } |
| 121 |