diff --git a/.github/workflows/ci-fork.yml b/.github/workflows/ci-fork.yml index 73ab6ec9d5..afa1d53512 100644 --- a/.github/workflows/ci-fork.yml +++ b/.github/workflows/ci-fork.yml @@ -11,6 +11,7 @@ concurrency: env: BUN_VERSION: "1.3.10" + MILADY_SKIP_LOCAL_UPSTREAMS: "1" jobs: lint: diff --git a/.github/workflows/task-agent-cross-platform-review.yml b/.github/workflows/task-agent-cross-platform-review.yml index 37293a2b0c..1376cd7925 100644 --- a/.github/workflows/task-agent-cross-platform-review.yml +++ b/.github/workflows/task-agent-cross-platform-review.yml @@ -26,13 +26,7 @@ jobs: with: submodules: false - - name: Initialize Windows-safe workspace submodules - if: ${{ matrix.os == 'windows-latest' }} - shell: bash - run: git submodule update --init --depth 1 plugins/plugin-agent-orchestrator plugins/plugin-sql - - name: Initialize tracked workspace submodules - if: ${{ matrix.os != 'windows-latest' }} run: node scripts/init-submodules.mjs - name: Setup Node.js diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 1cfca4c566..374545e2dc 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -72,7 +72,7 @@ jobs: # --ignore-scripts, so we run it explicitly before buf generate. - name: Generate protobuf types run: | - if [ -d eliza/packages/schemas ] && [ ! -d eliza/packages/typescript/src/types/generated ]; then + if [ -d eliza/packages/schemas ] && [ -f eliza/packages/schemas/buf.gen.yaml ] && [ ! -d eliza/packages/typescript/src/types/generated ]; then cd eliza/packages/schemas node node_modules/@bufbuild/buf/install.js 2>/dev/null || true npx --yes @bufbuild/buf@1.67.0 generate @@ -119,7 +119,7 @@ jobs: # --ignore-scripts, so we run it explicitly before buf generate. - name: Generate protobuf types run: | - if [ -d eliza/packages/schemas ] && [ ! -d eliza/packages/typescript/src/types/generated ]; then + if [ -d eliza/packages/schemas ] && [ -f eliza/packages/schemas/buf.gen.yaml ] && [ ! -d eliza/packages/typescript/src/types/generated ]; then cd eliza/packages/schemas node node_modules/@bufbuild/buf/install.js 2>/dev/null || true npx --yes @bufbuild/buf@1.67.0 generate @@ -172,13 +172,7 @@ jobs: # Published-only CI restores the required non-eliza submodules explicitly. submodules: false - - name: Initialize Windows-safe workspace submodules - if: ${{ matrix.os == 'windows-latest' }} - shell: bash - run: git submodule update --init --depth 1 plugins/plugin-agent-orchestrator - - name: Initialize tracked workspace submodules - if: ${{ matrix.os != 'windows-latest' }} run: node scripts/init-submodules.mjs - name: Setup Node.js @@ -244,13 +238,7 @@ jobs: # Published-only CI restores the required non-eliza submodules explicitly. submodules: false - - name: Initialize Windows-safe workspace submodules - if: ${{ matrix.os == 'windows-latest' }} - shell: bash - run: git submodule update --init --depth 1 plugins/plugin-agent-orchestrator - - name: Initialize tracked workspace submodules - if: ${{ matrix.os != 'windows-latest' }} run: node scripts/init-submodules.mjs - name: Setup Node.js @@ -490,7 +478,7 @@ jobs: # --ignore-scripts, so we run it explicitly before buf generate. - name: Generate protobuf types run: | - if [ -d eliza/packages/schemas ] && [ ! -d eliza/packages/typescript/src/types/generated ]; then + if [ -d eliza/packages/schemas ] && [ -f eliza/packages/schemas/buf.gen.yaml ] && [ ! -d eliza/packages/typescript/src/types/generated ]; then cd eliza/packages/schemas node node_modules/@bufbuild/buf/install.js 2>/dev/null || true npx --yes @bufbuild/buf@1.67.0 generate diff --git a/.github/workflows/windows-desktop-preload-smoke.yml b/.github/workflows/windows-desktop-preload-smoke.yml index 1364c4ee43..44cc153824 100644 --- a/.github/workflows/windows-desktop-preload-smoke.yml +++ b/.github/workflows/windows-desktop-preload-smoke.yml @@ -23,9 +23,8 @@ jobs: with: submodules: false - - name: Initialize Windows-safe workspace submodules - shell: bash - run: git submodule update --init --depth 1 plugins/plugin-agent-orchestrator + - name: Initialize workspace submodules + run: node scripts/init-submodules.mjs - name: Enable long paths (Windows) run: git config --global core.longpaths true diff --git a/.github/workflows/windows-dev-smoke.yml b/.github/workflows/windows-dev-smoke.yml index 1d31bf281b..8bf7feb223 100644 --- a/.github/workflows/windows-dev-smoke.yml +++ b/.github/workflows/windows-dev-smoke.yml @@ -26,9 +26,8 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Initialize Windows-safe workspace submodules - shell: bash - run: git submodule update --init --depth 1 plugins/plugin-agent-orchestrator + - name: Initialize workspace submodules + run: node scripts/init-submodules.mjs - name: Setup Node.js uses: actions/setup-node@v4 diff --git a/apps/app/electrobun/src/__tests__/agent.test.ts b/apps/app/electrobun/src/__tests__/agent.test.ts index bc503f5701..8d6002fc83 100644 --- a/apps/app/electrobun/src/__tests__/agent.test.ts +++ b/apps/app/electrobun/src/__tests__/agent.test.ts @@ -1,3 +1,5 @@ +import path from "node:path"; + import { DEFAULT_DESKTOP_API_PORT } from "@miladyai/shared/runtime-env"; import { afterEach, @@ -71,9 +73,16 @@ vi.mock("../native/loopback-port", () => ({ const mockSpawn = vi.fn(); const mockSleep = vi.fn(() => Promise.resolve()); -// Bun global is non-configurable on globalThis but Bun.spawn and Bun.sleep are writable; assign directly. -(Bun as unknown as { spawn: unknown }).spawn = mockSpawn; -(Bun as unknown as { sleep: unknown }).sleep = mockSleep; +type BunLike = { spawn: unknown; sleep: unknown }; + +function bunGlobal(): BunLike { + const globalState = globalThis as typeof globalThis & { Bun?: BunLike }; + globalState.Bun ??= { spawn: vi.fn(), sleep: vi.fn(() => Promise.resolve()) }; + return globalState.Bun; +} + +bunGlobal().spawn = mockSpawn; +bunGlobal().sleep = mockSleep; // Mock fetch for health checks const mockFetch = vi.fn(); @@ -456,7 +465,9 @@ describe("AgentManager", () => { prefix: "../../escape\\..\\report bundle", }); - expect(bundle.directory).toContain("/bug-reports/escape-report-bundle-"); + expect(bundle.directory).toContain( + `${path.sep}bug-reports${path.sep}escape-report-bundle-`, + ); expect(bundle.directory).not.toContain("../"); expect(bundle.directory).not.toContain("..\\"); }); @@ -905,7 +916,9 @@ describe("AgentManager", () => { const spawnOptions = mockSpawn.mock.calls[0]?.[1]; expect(spawnOptions?.env?.NODE_PATH).toBe( - "/mock/milady-dist/node_modules:/mock/node_modules", + ["/mock/milady-dist/node_modules", "/mock/node_modules"].join( + path.delimiter, + ), ); } finally { if (originalNodePath === undefined) { diff --git a/apps/app/electrobun/src/__tests__/background-notice.test.ts b/apps/app/electrobun/src/__tests__/background-notice.test.ts index 38d0b78ec9..7853f7150e 100644 --- a/apps/app/electrobun/src/__tests__/background-notice.test.ts +++ b/apps/app/electrobun/src/__tests__/background-notice.test.ts @@ -1,3 +1,5 @@ +import path from "node:path"; + import { describe, expect, it } from "vitest"; import { BACKGROUND_NOTICE_MARKER_FILE, @@ -8,22 +10,24 @@ import { } from "../background-notice"; describe("background notice", () => { + const userDataDir = path.join("/tmp", "milady"); + const otherDataDir = path.join("/tmp", "other"); + const markerPath = path.join(userDataDir, BACKGROUND_NOTICE_MARKER_FILE); + it("resolves the marker path under the userData directory", () => { - expect(resolveBackgroundNoticeMarkerPath("/tmp/milady")).toBe( - `/tmp/milady/${BACKGROUND_NOTICE_MARKER_FILE}`, - ); + expect(resolveBackgroundNoticeMarkerPath(userDataDir)).toBe(markerPath); }); it("reports whether the background notice marker already exists", () => { - const seenPaths = new Set([`/tmp/milady/${BACKGROUND_NOTICE_MARKER_FILE}`]); + const seenPaths = new Set([markerPath]); const fileSystem = { existsSync: (filePath: string) => seenPaths.has(filePath), mkdirSync: () => {}, writeFileSync: () => {}, }; - expect(hasSeenBackgroundNotice(fileSystem, "/tmp/milady")).toBe(true); - expect(hasSeenBackgroundNotice(fileSystem, "/tmp/other")).toBe(false); + expect(hasSeenBackgroundNotice(fileSystem, userDataDir)).toBe(true); + expect(hasSeenBackgroundNotice(fileSystem, otherDataDir)).toBe(false); }); it("writes the marker file when the background notice is shown", () => { @@ -52,18 +56,18 @@ describe("background notice", () => { }, }; - const markerPath = markBackgroundNoticeSeen(fileSystem, "/tmp/milady"); + const createdMarkerPath = markBackgroundNoticeSeen(fileSystem, userDataDir); - expect(markerPath).toBe(`/tmp/milady/${BACKGROUND_NOTICE_MARKER_FILE}`); + expect(createdMarkerPath).toBe(markerPath); expect(mkdirCalls).toEqual([ { - dirPath: "/tmp/milady", + dirPath: userDataDir, recursive: true, }, ]); expect(writeCalls).toEqual([ { - filePath: `/tmp/milady/${BACKGROUND_NOTICE_MARKER_FILE}`, + filePath: markerPath, data: '{"seen":true}\n', encoding: "utf8", }, @@ -84,7 +88,7 @@ describe("background notice", () => { expect( showBackgroundNoticeOnce({ fileSystem, - userDataDir: "/tmp/milady", + userDataDir, showNotification: (options) => { notifications.push(options); }, @@ -93,7 +97,7 @@ describe("background notice", () => { expect( showBackgroundNoticeOnce({ fileSystem, - userDataDir: "/tmp/milady", + userDataDir, showNotification: (options) => { notifications.push(options); }, diff --git a/apps/app/electrobun/src/__tests__/kitchen-sink.test.ts b/apps/app/electrobun/src/__tests__/kitchen-sink.test.ts index cab38f5755..d8b21aa744 100644 --- a/apps/app/electrobun/src/__tests__/kitchen-sink.test.ts +++ b/apps/app/electrobun/src/__tests__/kitchen-sink.test.ts @@ -607,11 +607,18 @@ vi.mock("../native/desktop", async () => { }); function stubBunGlobal(): void { + const globalState = globalThis as typeof globalThis & { + Bun?: { spawn: unknown; sleep: unknown }; + }; + globalState.Bun ??= { + spawn: vi.fn(), + sleep: vi.fn(() => Promise.resolve()), + }; // Bun global is non-configurable on globalThis but Bun.spawn and Bun.sleep // are writable data properties, so direct assignment works. // Bun.version is non-writable/non-configurable — tests that read it will see // the real runtime version, which is acceptable since no test asserts its value. - (Bun as unknown as { spawn: unknown }).spawn = vi.fn(() => ({ + globalState.Bun.spawn = vi.fn(() => ({ exited: Promise.resolve(0), stdout: new ReadableStream({ start(c) { @@ -627,7 +634,7 @@ function stubBunGlobal(): void { pid: 12345, kill: vi.fn(), })); - (Bun as unknown as { sleep: unknown }).sleep = vi.fn(() => Promise.resolve()); + globalState.Bun.sleep = vi.fn(() => Promise.resolve()); } stubBunGlobal(); diff --git a/apps/app/electrobun/src/__tests__/renderer-static.test.ts b/apps/app/electrobun/src/__tests__/renderer-static.test.ts index 844faee905..894166decb 100644 --- a/apps/app/electrobun/src/__tests__/renderer-static.test.ts +++ b/apps/app/electrobun/src/__tests__/renderer-static.test.ts @@ -1,9 +1,12 @@ +import path from "node:path"; + import { describe, expect, it } from "vitest"; import { resolveRendererAsset } from "../renderer-static"; describe("resolveRendererAsset", () => { - const rendererDir = "/tmp/renderer"; + const rendererDir = path.join("/tmp", "renderer"); + const indexPath = path.join(rendererDir, "index.html"); function resolve(paths: Record, urlPath: string) { return resolveRendererAsset({ @@ -19,14 +22,14 @@ describe("resolveRendererAsset", () => { it("serves precompressed assets when the plain file is missing", () => { const result = resolve( { - "/tmp/renderer/index.html": "file", - "/tmp/renderer/animations/idle.glb.gz": "file", + [indexPath]: "file", + [path.join(rendererDir, "animations", "idle.glb.gz")]: "file", }, "/animations/idle.glb", ); expect(result).toEqual({ - filePath: "/tmp/renderer/animations/idle.glb.gz", + filePath: path.join(rendererDir, "animations", "idle.glb.gz"), isGzipped: true, mimeExt: ".glb", }); @@ -35,14 +38,14 @@ describe("resolveRendererAsset", () => { it("falls back to plain assets when packaged wrappers drop the .gz suffix", () => { const result = resolve( { - "/tmp/renderer/index.html": "file", - "/tmp/renderer/vrms/milady-1.vrm": "file", + [indexPath]: "file", + [path.join(rendererDir, "vrms", "milady-1.vrm")]: "file", }, "/vrms/milady-1.vrm.gz", ); expect(result).toEqual({ - filePath: "/tmp/renderer/vrms/milady-1.vrm", + filePath: path.join(rendererDir, "vrms", "milady-1.vrm"), isGzipped: false, mimeExt: ".vrm", }); @@ -51,13 +54,13 @@ describe("resolveRendererAsset", () => { it("falls back to index.html for traversal attempts", () => { const result = resolve( { - "/tmp/renderer/index.html": "file", + [indexPath]: "file", }, "/../../etc/passwd", ); expect(result).toEqual({ - filePath: "/tmp/renderer/index.html", + filePath: indexPath, isGzipped: false, mimeExt: ".html", }); diff --git a/apps/app/electrobun/src/__tests__/startup-trace.test.ts b/apps/app/electrobun/src/__tests__/startup-trace.test.ts index db4c7d1a1f..17066375e9 100644 --- a/apps/app/electrobun/src/__tests__/startup-trace.test.ts +++ b/apps/app/electrobun/src/__tests__/startup-trace.test.ts @@ -27,6 +27,25 @@ function readJson(filePath: string) { } describe("startup trace", () => { + const darwinBundlePath = path.join("/Applications", "Milady-canary.app"); + const darwinExecPath = path.join( + darwinBundlePath, + "Contents", + "MacOS", + "launcher", + ); + const darwinBootstrapPath = path.join( + darwinBundlePath, + "Contents", + "Resources", + "startup-session.json", + ); + const winBundlePath = path.join( + "/Users/test/AppData/Local/com.miladyai.milady/canary/self-extraction", + "Milady-canary", + ); + const winExecPath = path.join(winBundlePath, "bin", "launcher.exe"); + const winBootstrapPath = path.join(winBundlePath, "startup-session.json"); let tempDir: string; beforeEach(() => { @@ -46,7 +65,7 @@ describe("startup trace", () => { "main_start", { pid: 123, - exec_path: "/Applications/Milady-canary.app/Contents/MacOS/launcher", + exec_path: darwinExecPath, }, env, ); @@ -56,7 +75,7 @@ describe("startup trace", () => { expect(state.session_id).toBe("session-a"); expect(state.phase).toBe("main_start"); expect(state.pid).toBe(123); - expect(state.bundle_path).toBe("/Applications/Milady-canary.app"); + expect(state.bundle_path).toBe(darwinBundlePath); const events = fs .readFileSync(env.MILADY_STARTUP_EVENTS_FILE as string, "utf8") @@ -187,21 +206,11 @@ describe("startup trace", () => { }); it("derives bundle-local bootstrap sidecars from packaged launcher paths", () => { - expect( - resolveStartupTraceBootstrapFile( - "/Applications/Milady-canary.app/Contents/MacOS/launcher", - "darwin", - ), - ).toBe( - "/Applications/Milady-canary.app/Contents/Resources/startup-session.json", + expect(resolveStartupTraceBootstrapFile(darwinExecPath, "darwin")).toBe( + darwinBootstrapPath, ); - expect( - resolveStartupTraceBootstrapFile( - "/Users/test/AppData/Local/com.miladyai.milady/canary/self-extraction/Milady-canary/bin/launcher.exe", - "win32", - ), - ).toBe( - "/Users/test/AppData/Local/com.miladyai.milady/canary/self-extraction/Milady-canary/startup-session.json", + expect(resolveStartupTraceBootstrapFile(winExecPath, "win32")).toBe( + winBootstrapPath, ); }); diff --git a/apps/app/electrobun/src/native/__tests__/credentials.test.ts b/apps/app/electrobun/src/native/__tests__/credentials.test.ts index 3ba02b6a7d..c6232d80a8 100644 --- a/apps/app/electrobun/src/native/__tests__/credentials.test.ts +++ b/apps/app/electrobun/src/native/__tests__/credentials.test.ts @@ -1,5 +1,6 @@ import fs from "node:fs"; import os from "node:os"; +import path from "node:path"; import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; @@ -14,7 +15,7 @@ vi.mock("node:fs", () => { }); vi.mock("node:os", () => { - const homedir = vi.fn(() => "/Users/test"); + const homedir = vi.fn(() => path.join("/Users", "test")); return { default: { homedir }, homedir, @@ -35,6 +36,12 @@ type SpawnResult = { type BunLike = { spawn: unknown }; +const TEST_HOME_DIR = path.join("/Users", "test"); + +function homePath(...parts: string[]): string { + return path.join(TEST_HOME_DIR, ...parts); +} + function bunGlobal(): BunLike { const globalState = globalThis as typeof globalThis & { Bun?: BunLike }; globalState.Bun ??= { spawn: vi.fn() }; @@ -106,7 +113,7 @@ describe("scanProviderCredentials", () => { mockReadFileSync.mockImplementation( (filePath) => files[String(filePath)] ?? "", ); - mockHomedir.mockReturnValue("/Users/test"); + mockHomedir.mockReturnValue(TEST_HOME_DIR); mockSpawn = vi.fn((cmd: string[]) => { if (cmd[0] === "which") { @@ -137,7 +144,7 @@ describe("scanProviderCredentials", () => { it("returns openai-subscription from Codex ChatGPT auth and preserves auth mode", async () => { setPlatform("linux"); - files["/Users/test/.codex/auth.json"] = JSON.stringify({ + files[homePath(".codex", "auth.json")] = JSON.stringify({ OPENAI_API_KEY: "sk-openai", auth_mode: "chatgpt", }); @@ -164,7 +171,7 @@ describe("scanProviderCredentials", () => { it("returns anthropic from claude credentials file with oauth mode", async () => { setPlatform("linux"); - files["/Users/test/.claude/.credentials.json"] = JSON.stringify({ + files[homePath(".claude", ".credentials.json")] = JSON.stringify({ claudeAiOauth: { accessToken: "claude-oauth-token" }, }); installedClis.add("claude"); @@ -190,10 +197,10 @@ describe("scanProviderCredentials", () => { it("prefers file credentials over keychain and env values", async () => { setPlatform("darwin"); - files["/Users/test/.codex/auth.json"] = JSON.stringify({ + files[homePath(".codex", "auth.json")] = JSON.stringify({ OPENAI_API_KEY: "file-openai", }); - files["/Users/test/.claude/.credentials.json"] = JSON.stringify({ + files[homePath(".claude", ".credentials.json")] = JSON.stringify({ claudeAiOauth: { accessToken: "file-anthropic" }, }); installedClis.add("codex"); @@ -403,8 +410,8 @@ describe("scanProviderCredentials", () => { it("swallows malformed json and returns an empty result when no fallbacks exist", async () => { setPlatform("linux"); - files["/Users/test/.codex/auth.json"] = "{bad-json"; - files["/Users/test/.claude/.credentials.json"] = "{bad-json"; + files[homePath(".codex", "auth.json")] = "{bad-json"; + files[homePath(".claude", ".credentials.json")] = "{bad-json"; await expect(scanProviderCredentials()).resolves.toEqual([]); expect(mockSpawn).not.toHaveBeenCalled(); @@ -432,7 +439,7 @@ describe("scanAndValidateProviderCredentials", () => { mockReadFileSync.mockImplementation( (filePath) => files[String(filePath)] ?? "", ); - mockHomedir.mockReturnValue("/Users/test"); + mockHomedir.mockReturnValue(TEST_HOME_DIR); mockSpawn = vi.fn((cmd: string[]) => { if (cmd[0] === "which") return makeSpawnResult(installedClis.has(cmd[1] ?? "") ? 0 : 1); @@ -453,7 +460,7 @@ describe("scanAndValidateProviderCredentials", () => { }); it("valid key returns status 'valid'", async () => { - files["/Users/test/.codex/auth.json"] = JSON.stringify({ + files[homePath(".codex", "auth.json")] = JSON.stringify({ OPENAI_API_KEY: "sk-test", }); mockFetch.mockResolvedValue({ ok: true, status: 200 }); @@ -463,7 +470,7 @@ describe("scanAndValidateProviderCredentials", () => { }); it("401 response returns status 'invalid' with statusDetail", async () => { - files["/Users/test/.codex/auth.json"] = JSON.stringify({ + files[homePath(".codex", "auth.json")] = JSON.stringify({ OPENAI_API_KEY: "sk-bad", }); mockFetch.mockResolvedValue({ ok: false, status: 401 }); @@ -480,7 +487,7 @@ describe("scanAndValidateProviderCredentials", () => { }); it("network error returns status 'error' with message", async () => { - files["/Users/test/.codex/auth.json"] = JSON.stringify({ + files[homePath(".codex", "auth.json")] = JSON.stringify({ OPENAI_API_KEY: "sk-test", }); mockFetch.mockRejectedValue(new Error("fetch failed")); @@ -490,7 +497,7 @@ describe("scanAndValidateProviderCredentials", () => { }); it("OAuth token skips validation and returns 'unchecked'", async () => { - files["/Users/test/.claude/.credentials.json"] = JSON.stringify({ + files[homePath(".claude", ".credentials.json")] = JSON.stringify({ claudeAiOauth: { accessToken: "oauth-token" }, }); const providers = await scanAndValidateProviderCredentials(); @@ -500,7 +507,7 @@ describe("scanAndValidateProviderCredentials", () => { it("unknown provider returns 'unchecked'", async () => { vi.stubEnv("OPENAI_API_KEY", ""); - files["/Users/test/.codex/auth.json"] = JSON.stringify({ + files[homePath(".codex", "auth.json")] = JSON.stringify({ OPENAI_API_KEY: "sk-test", }); mockFetch.mockResolvedValue({ ok: true, status: 200 }); @@ -511,7 +518,7 @@ describe("scanAndValidateProviderCredentials", () => { }); it("HTTP 500 returns status 'error' with detail", async () => { - files["/Users/test/.codex/auth.json"] = JSON.stringify({ + files[homePath(".codex", "auth.json")] = JSON.stringify({ OPENAI_API_KEY: "sk-test", }); mockFetch.mockResolvedValue({ ok: false, status: 500 }); @@ -521,7 +528,7 @@ describe("scanAndValidateProviderCredentials", () => { }); it("provider without apiKey returns 'unchecked'", async () => { - files["/Users/test/.codex/auth.json"] = JSON.stringify({ + files[homePath(".codex", "auth.json")] = JSON.stringify({ OPENAI_API_KEY: "sk-key", }); mockFetch.mockResolvedValue({ ok: true, status: 200 }); @@ -552,7 +559,7 @@ describe("scanProviderCredentials — env var detection", () => { mockReadFileSync.mockImplementation( (filePath) => files[String(filePath)] ?? "", ); - mockHomedir.mockReturnValue("/Users/test"); + mockHomedir.mockReturnValue(TEST_HOME_DIR); mockSpawn = vi.fn((cmd: string[]) => { if (cmd[0] === "which") return makeSpawnResult(1); throw new Error(`unexpected spawn: ${cmd.join(" ")}`); @@ -699,7 +706,7 @@ describe("scanAndValidateProviderCredentials — endpoint validation", () => { mockReadFileSync.mockImplementation( (filePath) => files[String(filePath)] ?? "", ); - mockHomedir.mockReturnValue("/Users/test"); + mockHomedir.mockReturnValue(TEST_HOME_DIR); mockSpawn = vi.fn((cmd: string[]) => { if (cmd[0] === "which") return makeSpawnResult(1); throw new Error(`unexpected spawn: ${cmd.join(" ")}`); @@ -800,7 +807,7 @@ describe("scanAndValidateProviderCredentials — integration", () => { mockReadFileSync.mockImplementation( (filePath) => files[String(filePath)] ?? "", ); - mockHomedir.mockReturnValue("/Users/test"); + mockHomedir.mockReturnValue(TEST_HOME_DIR); mockSpawn = vi.fn((cmd: string[]) => { if (cmd[0] === "which") return makeSpawnResult(1); throw new Error(`unexpected spawn: ${cmd.join(" ")}`); diff --git a/bun.lock b/bun.lock index 50b30f05a8..440008bfbc 100644 --- a/bun.lock +++ b/bun.lock @@ -93,6 +93,7 @@ "@types/ws": "^8.18.1", "@vitest/coverage-v8": "^4.1.0", "@vitest/utils": "4.1.0", + "jsdom": "^28.1.0", "react": "^19.2.4", "react-dom": "^19.2.4", "react-test-renderer": "^19.2.4", @@ -547,6 +548,7 @@ "@elizaos/plugin-trust": "workspace:*", "@hapi/boom": "^10.0.1", "@mariozechner/pi-ai": "0.52.12", + "@miladyai/plugin-2004scape": "workspace:*", "@miladyai/plugin-roles": "github:milady-ai/plugin-roles#5b00c49", "@miladyai/plugin-selfcontrol": "workspace:*", "@miladyai/plugin-wechat": "github:milady-ai/plugin-wechat", @@ -1180,38 +1182,6 @@ "@elizaos/core": "workspace:*", }, }, - "plugins/plugin-groq": { - "name": "@elizaos/plugin-groq-root", - "version": "2.0.0-alpha.1", - "dependencies": { - "@ai-sdk/groq": "latest", - "ai": "latest", - }, - "devDependencies": { - "@biomejs/biome": "^2.3.11", - "@types/bun": "^1.3.5", - "@types/node": "^25.0.3", - "typescript": "^5.9.3", - }, - "peerDependencies": { - "@elizaos/core": "workspace:*", - }, - }, - "plugins/plugin-groq/typescript": { - "name": "@elizaos/plugin-groq", - "version": "2.0.0-alpha.8", - "dependencies": { - "@ai-sdk/groq": "^3.0.4", - "@elizaos/core": "workspace:*", - "ai": "^6.0.0", - }, - "devDependencies": { - "@biomejs/biome": "^2.3.11", - "@types/bun": "^1.3.10", - "@types/node": "^25.0.3", - "typescript": "^5.9.3", - }, - }, "plugins/plugin-local-embedding": { "name": "@elizaos/plugin-local-embedding-root", "version": "1.2.1", @@ -1321,44 +1291,6 @@ "zod": "^4.3.6", }, }, - "plugins/plugin-openrouter": { - "name": "@elizaos/plugin-openrouter-root", - "version": "2.0.0-alpha.1", - "devDependencies": { - "@biomejs/biome": "^2.3.11", - "@types/bun": "^1.3.5", - "@types/node": "^25.0.3", - "typescript": "^5.9.3", - }, - "peerDependencies": { - "@elizaos/core": "workspace:*", - }, - }, - "plugins/plugin-openrouter/typescript": { - "name": "@elizaos/plugin-openrouter", - "version": "2.0.0-alpha.13", - "dependencies": { - "@ai-sdk/openai": "^3.0.9", - "@ai-sdk/ui-utils": "^1.2.8", - "@openrouter/ai-sdk-provider": "^1.2.0", - "ai": "^6.0.30", - "undici": "^7.16.0", - }, - "devDependencies": { - "@biomejs/biome": "^2.3.11", - "@elizaos/core": "workspace:*", - "@elizaos/plugin-sql": "workspace:*", - "@types/bun": "^1.3.5", - "@types/json-schema": "^7.0.15", - "@types/node": "^25.0.3", - "dotenv": "^17.2.3", - "typescript": "^5.9.3", - "vitest": "^4.0.0", - }, - "peerDependencies": { - "@elizaos/core": "workspace:*", - }, - }, "plugins/plugin-pdf": { "name": "@elizaos/plugin-pdf-root", "version": "2.0.0-alpha.1", @@ -1725,8 +1657,6 @@ "@ai-sdk/google": ["@ai-sdk/google@3.0.60", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-ye/hG0LeO24VmjLbfgkFZV8V8k/l4nVBODutpJQkFPyUiGOCbFtFUTgxSeC7+njrk5+HhgyHrzJay4zmhwMH+w=="], - "@ai-sdk/groq": ["@ai-sdk/groq@3.0.31", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.21" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-XbbugpnFmXGu2TlXiq8KUJskP6/VVbuFcnFIGDzDIB/Chg6XHsNnqrTF80Zxkh0Pd3+NvbM+2Uqrtsndk6bDAg=="], - "@ai-sdk/openai": ["@ai-sdk/openai@3.0.52", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.23" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-4Rr8NCGmfWTz6DCUvixn9UmyZcMatiHn0zWoMzI3JCUe9R1P/vsPOpCBALKoSzVYOjyJnhtnVIbfUKujcS39uw=="], "@ai-sdk/provider": ["@ai-sdk/provider@3.0.8", "", { "dependencies": { "json-schema": "^0.4.0" } }, "sha512-oGMAgGoQdBXbZqNG0Ze56CHjDZ1IDYOwGYxYjO5KLSlz5HiNQ9udIXsPZ61VWaHGZ5XW/jyjmr6t2xz2jGVwbQ=="], @@ -2047,10 +1977,6 @@ "@elizaos/plugin-google-genai-root": ["@elizaos/plugin-google-genai-root@workspace:plugins/plugin-google-genai"], - "@elizaos/plugin-groq": ["@elizaos/plugin-groq@workspace:plugins/plugin-groq/typescript"], - - "@elizaos/plugin-groq-root": ["@elizaos/plugin-groq-root@workspace:plugins/plugin-groq"], - "@elizaos/plugin-local-embedding": ["@elizaos/plugin-local-embedding@workspace:plugins/plugin-local-embedding/typescript"], "@elizaos/plugin-local-embedding-root": ["@elizaos/plugin-local-embedding-root@workspace:plugins/plugin-local-embedding"], @@ -2067,9 +1993,7 @@ "@elizaos/plugin-openai-root": ["@elizaos/plugin-openai-root@workspace:plugins/plugin-openai"], - "@elizaos/plugin-openrouter": ["@elizaos/plugin-openrouter@workspace:plugins/plugin-openrouter/typescript"], - - "@elizaos/plugin-openrouter-root": ["@elizaos/plugin-openrouter-root@workspace:plugins/plugin-openrouter"], + "@elizaos/plugin-openrouter": ["@elizaos/plugin-openrouter@2.0.0-alpha.13", "", { "dependencies": { "@ai-sdk/openai": "^3.0.9", "@ai-sdk/ui-utils": "^1.2.8", "@openrouter/ai-sdk-provider": "^1.2.0", "ai": "^6.0.30", "undici": "^7.16.0" }, "peerDependencies": { "@elizaos/core": "2.0.0-alpha.114" } }, "sha512-1QFAOhtX2TtWwie1z2MXukhjH9hBBeuWAzHzT5PtDAlsJRtlJ9AiudqDTiZhXMD06GtvN20jqBdVJD+SiXpDVg=="], "@elizaos/plugin-pdf": ["@elizaos/plugin-pdf@workspace:plugins/plugin-pdf/typescript"], @@ -4919,7 +4843,7 @@ "parse-ms": ["parse-ms@4.0.0", "", {}, "sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw=="], - "parse5": ["parse5@5.1.1", "", {}, "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug=="], + "parse5": ["parse5@8.0.0", "", { "dependencies": { "entities": "^6.0.0" } }, "sha512-9m4m5GSgXjL4AjumKzq1Fgfp3Z8rsvjRNbnkVwfu2ImRqE5D0LnY2QfDen18FSY9C573YU5XxSapdHZTZ2WolA=="], "parse5-htmlparser2-tree-adapter": ["parse5-htmlparser2-tree-adapter@6.0.1", "", { "dependencies": { "parse5": "^6.0.1" } }, "sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA=="], @@ -5443,15 +5367,15 @@ "tinyspy": ["tinyspy@3.0.2", "", {}, "sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q=="], - "tldts": ["tldts@6.1.86", "", { "dependencies": { "tldts-core": "^6.1.86" }, "bin": { "tldts": "bin/cli.js" } }, "sha512-WMi/OQ2axVTf/ykqCQgXiIct+mSQDFdH2fkwhPwgEwvJ1kSzZRiinb0zF2Xb8u4+OqPChmyI6MEu4EezNJz+FQ=="], + "tldts": ["tldts@7.0.28", "", { "dependencies": { "tldts-core": "^7.0.28" }, "bin": { "tldts": "bin/cli.js" } }, "sha512-+Zg3vWhRUv8B1maGSTFdev9mjoo8Etn2Ayfs4cnjlD3CsGkxXX4QyW3j2WJ0wdjYcYmy7Lx2RDsZMhgCWafKIw=="], - "tldts-core": ["tldts-core@6.1.86", "", {}, "sha512-Je6p7pkk+KMzMv2XXKmAE3McmolOQFdxkKw0R8EYNr7sELW46JqnNeTX8ybPiQgvg1ymCoF8LXs5fzFaZvJPTA=="], + "tldts-core": ["tldts-core@7.0.28", "", {}, "sha512-7W5Efjhsc3chVdFhqtaU0KtK32J37Zcr9RKtID54nG+tIpcY79CQK/veYPODxtD/LJ4Lue66jvrQzIX2Z2/pUQ=="], "to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="], "token-types": ["token-types@6.1.2", "", { "dependencies": { "@borewit/text-codec": "^0.2.1", "@tokenizer/token": "^0.3.0", "ieee754": "^1.2.1" } }, "sha512-dRXchy+C0IgK8WPC6xvCHFRIWYUbqqdEIKPaKo/AcTUNzwLTK6AH7RjdLWsEZcAN/TBdtfUw3PYEgPr5VPr6ww=="], - "tough-cookie": ["tough-cookie@5.1.2", "", { "dependencies": { "tldts": "^6.1.32" } }, "sha512-FVDYdxtnj0G6Qm/DhNPSb8Ju59ULcup3tuJxkFb5K8Bv2pUXILbf0xZWU8PX8Ov19OXljbUyveOFwRMwkXzO+A=="], + "tough-cookie": ["tough-cookie@6.0.1", "", { "dependencies": { "tldts": "^7.0.5" } }, "sha512-LktZQb3IeoUWB9lqR5EWTHgW/VTITCXg4D21M+lvybRVdylLrRMnqaIONLVb5mav8vM19m44HIcGq4qASeu2Qw=="], "tr46": ["tr46@1.0.1", "", { "dependencies": { "punycode": "^2.1.0" } }, "sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA=="], @@ -5619,7 +5543,7 @@ "webdriver-bidi-protocol": ["webdriver-bidi-protocol@0.4.1", "", {}, "sha512-ARrjNjtWRRs2w4Tk7nqrf2gBI0QXWuOmMCx2hU+1jUt6d00MjMxURrhxhGbrsoiZKJrhTSTzbIrc554iKI10qw=="], - "webidl-conversions": ["webidl-conversions@4.0.2", "", {}, "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg=="], + "webidl-conversions": ["webidl-conversions@8.0.1", "", {}, "sha512-BMhLD/Sw+GbJC21C/UgyaZX41nPt8bUTg+jWyDeg7e7YN4xOM05YPSIXceACnXVtqyEw/LMClUQMtMZ+PGGpqQ=="], "webpack-virtual-modules": ["webpack-virtual-modules@0.6.2", "", {}, "sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ=="], @@ -5701,8 +5625,6 @@ "zwitch": ["zwitch@2.0.4", "", {}, "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A=="], - "@ai-sdk/groq/@ai-sdk/provider-utils": ["@ai-sdk/provider-utils@4.0.21", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@standard-schema/spec": "^1.1.0", "eventsource-parser": "^3.0.6" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-MtFUYI1/8mgDvRmaBDjbLJPFFrMG777AvSgyIFQtZHIMzm88R/12vYBBpnk7pfiWLFE1DSZzY4WDYzGbKAcmiw=="], - "@ai-sdk/ui-utils/@ai-sdk/provider": ["@ai-sdk/provider@1.1.3", "", { "dependencies": { "json-schema": "^0.4.0" } }, "sha512-qZMxYJ0qqX/RfnuIaab+zp8UAeJn/ygXXAffR5I4N0n1IrvA6qBsjc8hXLmBiMV2zoXlifkacF7sEFnYnjBcqg=="], "@ai-sdk/ui-utils/@ai-sdk/provider-utils": ["@ai-sdk/provider-utils@2.2.8", "", { "dependencies": { "@ai-sdk/provider": "1.1.3", "nanoid": "^3.3.8", "secure-json-parse": "^2.7.0" }, "peerDependencies": { "zod": "^3.23.8" } }, "sha512-fqhG+4sCVv8x7nFzYnFo19ryhAa3w096Kmc3hWxMQfW/TubPOmt3A6tYZhl4mUfQWWQMsuSkLrtjlWuXBVSGQA=="], @@ -5839,6 +5761,8 @@ "@discordjs/ws/tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], + "@distube/ytdl-core/tough-cookie": ["tough-cookie@5.1.2", "", { "dependencies": { "tldts": "^6.1.32" } }, "sha512-FVDYdxtnj0G6Qm/DhNPSb8Ju59ULcup3tuJxkFb5K8Bv2pUXILbf0xZWU8PX8Ov19OXljbUyveOFwRMwkXzO+A=="], + "@elizaos-plugins/client-telegram-account/glob": ["glob@11.0.0", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^4.0.1", "minimatch": "^10.0.0", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^2.0.0" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-9UiX/Bl6J2yaBbxKoEBRm4Cipxgok8kQYcOPEhScPwebu2I0HoQOuYdIO6S3hLuWoZgpDpwQZMzTFxgpkyT76g=="], "@elizaos/daemon/@biomejs/biome": ["@biomejs/biome@1.9.4", "", { "optionalDependencies": { "@biomejs/cli-darwin-arm64": "1.9.4", "@biomejs/cli-darwin-x64": "1.9.4", "@biomejs/cli-linux-arm64": "1.9.4", "@biomejs/cli-linux-arm64-musl": "1.9.4", "@biomejs/cli-linux-x64": "1.9.4", "@biomejs/cli-linux-x64-musl": "1.9.4", "@biomejs/cli-win32-arm64": "1.9.4", "@biomejs/cli-win32-x64": "1.9.4" }, "bin": { "biome": "bin/biome" } }, "sha512-1rkd7G70+o9KkTn5KLmDYXihGoTaIGO9PIIN2ZB7UJxFrWw04CZHPYiMRjYsaDvVV7hP1dYNRLxSANLaBFGpog=="], @@ -5873,7 +5797,7 @@ "@elizaos/plugin-edge-tts/@types/node": ["@types/node@24.12.2", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-A1sre26ke7HDIuY/M23nd9gfB+nrmhtYyMINbjI1zHJxYteKR6qSMX56FsmjMcDb3SMcjJg5BiRRgOCC/yBD0g=="], - "@elizaos/plugin-form/uuid": ["uuid@11.0.5", "", { "bin": { "uuid": "dist/esm/bin/uuid" } }, "sha512-508e6IcKLrhxKdBbcA2b4KQZlLVp2+J5UwQ6F7Drckkc5N9ZJwFa4TgWtsww9UG8fGHbm6gbV19TdM5pQ4GaIA=="], + "@elizaos/plugin-form/uuid": ["uuid@11.1.0", "", { "bin": { "uuid": "dist/esm/bin/uuid" } }, "sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A=="], "@elizaos/plugin-local-embedding/@types/uuid": ["@types/uuid@10.0.0", "", {}, "sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ=="], @@ -6023,8 +5947,6 @@ "@miladyai/agent/@elizaos/plugin-solana": ["@elizaos/plugin-solana@1.2.6", "", { "dependencies": { "@solana/spl-token": "0.4.14", "@solana/spl-token-metadata": "^0.1.6", "@solana/web3.js": "^1.98.0", "bignumber.js": "9.3.0", "bs58": "6.0.0", "tweetnacl": "^1.0.3" }, "peerDependencies": { "@elizaos/core": "latest", "@elizaos/service-interfaces": "latest", "form-data": "4.0.2", "whatwg-url": "7.1.0" } }, "sha512-VWp4u2jOkEOgqNNaVN8j3g2TWKwq56GZzIawFPsr6YsF4NuCiQOaWfmeq+edVxpze5LkkzVfC/KPeU19jjZDuA=="], - "@miladyai/agent/@miladyai/plugin-roles": ["@miladyai/plugin-roles@github:milady-ai/plugin-roles#5b00c49", { "peerDependencies": { "@elizaos/core": "alpha" } }, "milady-ai-plugin-roles-5b00c49", "sha512-QxrX3mPn9KLdor5PdRyVqYzOxVbIfR4cNW9YfqWL3jCE35zg6g1Pu0E9MDkTFmNOFbyjvCnkrFLxZtZfGdlu+A=="], - "@miladyai/app/vite": ["vite@5.4.21", "", { "dependencies": { "esbuild": "^0.21.3", "postcss": "^8.4.43", "rollup": "^4.20.0" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^18.0.0 || >=20.0.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", "terser": "^5.4.0" }, "optionalPeers": ["@types/node", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser"], "bin": { "vite": "bin/vite.js" } }, "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw=="], "@miladyai/app/vitest": ["vitest@2.1.9", "", { "dependencies": { "@vitest/expect": "2.1.9", "@vitest/mocker": "2.1.9", "@vitest/pretty-format": "^2.1.9", "@vitest/runner": "2.1.9", "@vitest/snapshot": "2.1.9", "@vitest/spy": "2.1.9", "@vitest/utils": "2.1.9", "chai": "^5.1.2", "debug": "^4.3.7", "expect-type": "^1.1.0", "magic-string": "^0.30.12", "pathe": "^1.1.2", "std-env": "^3.8.0", "tinybench": "^2.9.0", "tinyexec": "^0.3.1", "tinypool": "^1.0.1", "tinyrainbow": "^1.2.0", "vite": "^5.0.0", "vite-node": "2.1.9", "why-is-node-running": "^2.3.0" }, "peerDependencies": { "@edge-runtime/vm": "*", "@types/node": "^18.0.0 || >=20.0.0", "@vitest/browser": "2.1.9", "@vitest/ui": "2.1.9", "happy-dom": "*", "jsdom": "*" }, "optionalPeers": ["@edge-runtime/vm", "@types/node", "@vitest/browser", "@vitest/ui", "happy-dom", "jsdom"], "bin": { "vitest": "vitest.mjs" } }, "sha512-MSmPM9REYqDGBI8439mA4mWhV5sKmDlBKWIYbA3lRb2PTHACE0mgKwA8yQ2xq9vxDTuk4iPrECBAEW2aoFXY0Q=="], @@ -6045,8 +5967,6 @@ "@miladyai/homepage/vite": ["vite@5.4.21", "", { "dependencies": { "esbuild": "^0.21.3", "postcss": "^8.4.43", "rollup": "^4.20.0" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^18.0.0 || >=20.0.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", "terser": "^5.4.0" }, "optionalPeers": ["@types/node", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser"], "bin": { "vite": "bin/vite.js" } }, "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw=="], - "@miladyai/plugin-selfcontrol/@miladyai/plugin-roles": ["@miladyai/plugin-roles@github:milady-ai/plugin-roles#5b00c49", { "peerDependencies": { "@elizaos/core": "alpha" } }, "milady-ai-plugin-roles-5b00c49", "sha512-QxrX3mPn9KLdor5PdRyVqYzOxVbIfR4cNW9YfqWL3jCE35zg6g1Pu0E9MDkTFmNOFbyjvCnkrFLxZtZfGdlu+A=="], - "@miladyai/ui/jsdom": ["jsdom@29.0.2", "", { "dependencies": { "@asamuzakjp/css-color": "^5.1.5", "@asamuzakjp/dom-selector": "^7.0.6", "@bramus/specificity": "^2.4.2", "@csstools/css-syntax-patches-for-csstree": "^1.1.1", "@exodus/bytes": "^1.15.0", "css-tree": "^3.2.1", "data-urls": "^7.0.0", "decimal.js": "^10.6.0", "html-encoding-sniffer": "^6.0.0", "is-potential-custom-element-name": "^1.0.1", "lru-cache": "^11.2.7", "parse5": "^8.0.0", "saxes": "^6.0.0", "symbol-tree": "^3.2.4", "tough-cookie": "^6.0.1", "undici": "^7.24.5", "w3c-xmlserializer": "^5.0.0", "webidl-conversions": "^8.0.1", "whatwg-mimetype": "^5.0.0", "whatwg-url": "^16.0.1", "xml-name-validator": "^5.0.0" }, "peerDependencies": { "canvas": "^3.0.0" }, "optionalPeers": ["canvas"] }, "sha512-9VnGEBosc/ZpwyOsJBCQ/3I5p7Q5ngOY14a9bf5btenAORmZfDse1ZEheMiWcJ3h81+Fv7HmJFdS0szo/waF2w=="], "@miladyai/ui/lucide-react": ["lucide-react@0.575.0", "", { "peerDependencies": { "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-VuXgKZrk0uiDlWjGGXmKV6MSk9Yy4l10qgVvzGn2AWBx1Ylt0iBexKOAoA6I7JO3m+M9oeovJd3yYENfkUbOeg=="], @@ -6293,6 +6213,8 @@ "cli-highlight/chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], + "cli-highlight/parse5": ["parse5@5.1.1", "", {}, "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug=="], + "cliui/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], "clone-response/mimic-response": ["mimic-response@1.0.1", "", {}, "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ=="], @@ -6441,12 +6363,6 @@ "js-yaml/argparse": ["argparse@2.0.1", "", {}, "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="], - "jsdom/parse5": ["parse5@8.0.0", "", { "dependencies": { "entities": "^6.0.0" } }, "sha512-9m4m5GSgXjL4AjumKzq1Fgfp3Z8rsvjRNbnkVwfu2ImRqE5D0LnY2QfDen18FSY9C573YU5XxSapdHZTZ2WolA=="], - - "jsdom/tough-cookie": ["tough-cookie@6.0.1", "", { "dependencies": { "tldts": "^7.0.5" } }, "sha512-LktZQb3IeoUWB9lqR5EWTHgW/VTITCXg4D21M+lvybRVdylLrRMnqaIONLVb5mav8vM19m44HIcGq4qASeu2Qw=="], - - "jsdom/webidl-conversions": ["webidl-conversions@8.0.1", "", {}, "sha512-BMhLD/Sw+GbJC21C/UgyaZX41nPt8bUTg+jWyDeg7e7YN4xOM05YPSIXceACnXVtqyEw/LMClUQMtMZ+PGGpqQ=="], - "jsdom/whatwg-url": ["whatwg-url@16.0.1", "", { "dependencies": { "@exodus/bytes": "^1.11.0", "tr46": "^6.0.0", "webidl-conversions": "^8.0.1" } }, "sha512-1to4zXBxmXHV3IiSSEInrreIlu02vUOvrhxJJH5vcxYTBDAx51cqZiKdyTxlecdKNSjj8EcxGBxNf6Vg+945gw=="], "jszip/pako": ["pako@1.0.11", "", {}, "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw=="], @@ -6517,6 +6433,8 @@ "parse-entities/@types/unist": ["@types/unist@2.0.11", "", {}, "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA=="], + "parse5/entities": ["entities@6.0.1", "", {}, "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g=="], + "parse5-htmlparser2-tree-adapter/parse5": ["parse5@6.0.1", "", {}, "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw=="], "playwright/fsevents": ["fsevents@2.3.2", "", { "os": "darwin" }, "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA=="], @@ -6653,6 +6571,8 @@ "websocket/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], + "whatwg-url/webidl-conversions": ["webidl-conversions@4.0.2", "", {}, "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg=="], + "which-builtin-type/isarray": ["isarray@2.0.5", "", {}, "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw=="], "wrap-ansi/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], @@ -6683,6 +6603,8 @@ "@discordjs/node-pre-gyp/rimraf/glob": ["glob@7.2.3", "", { "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q=="], + "@distube/ytdl-core/tough-cookie/tldts": ["tldts@6.1.86", "", { "dependencies": { "tldts-core": "^6.1.86" }, "bin": { "tldts": "bin/cli.js" } }, "sha512-WMi/OQ2axVTf/ykqCQgXiIct+mSQDFdH2fkwhPwgEwvJ1kSzZRiinb0zF2Xb8u4+OqPChmyI6MEu4EezNJz+FQ=="], + "@elizaos-plugins/client-telegram-account/glob/jackspeak": ["jackspeak@4.2.3", "", { "dependencies": { "@isaacs/cliui": "^9.0.0" } }, "sha512-ykkVRwrYvFm1nb2AJfKKYPr0emF6IiXDYUaFx4Zn9ZuIH7MrzEZ3sD5RlqGXNRpHtvUHJyOnCEFxOlNDtGo7wg=="], "@elizaos/daemon/@biomejs/biome/@biomejs/cli-darwin-arm64": ["@biomejs/cli-darwin-arm64@1.9.4", "", { "os": "darwin", "cpu": "arm64" }, "sha512-bFBsPWrNvkdKrNCYeAp+xo2HecOGPAy9WyNyB/jKnnedgzl4W4Hb9ZMzYNbf8dMCGmUdSavlYHiR01QaYR58cw=="], @@ -7153,22 +7075,10 @@ "@miladyai/homepage/jsdom/@asamuzakjp/dom-selector": ["@asamuzakjp/dom-selector@7.0.8", "", { "dependencies": { "@asamuzakjp/nwsapi": "^2.3.9", "bidi-js": "^1.0.3", "css-tree": "^3.2.1", "is-potential-custom-element-name": "^1.0.1" } }, "sha512-erMO6FgtM02dC24NGm0xufMzWz5OF0wXKR7BpvGD973bq/GbmR8/DbxNZbj0YevQ5hlToJaWSVK/G9/NDgGEVw=="], - "@miladyai/homepage/jsdom/parse5": ["parse5@8.0.0", "", { "dependencies": { "entities": "^6.0.0" } }, "sha512-9m4m5GSgXjL4AjumKzq1Fgfp3Z8rsvjRNbnkVwfu2ImRqE5D0LnY2QfDen18FSY9C573YU5XxSapdHZTZ2WolA=="], - - "@miladyai/homepage/jsdom/tough-cookie": ["tough-cookie@6.0.1", "", { "dependencies": { "tldts": "^7.0.5" } }, "sha512-LktZQb3IeoUWB9lqR5EWTHgW/VTITCXg4D21M+lvybRVdylLrRMnqaIONLVb5mav8vM19m44HIcGq4qASeu2Qw=="], - - "@miladyai/homepage/jsdom/webidl-conversions": ["webidl-conversions@8.0.1", "", {}, "sha512-BMhLD/Sw+GbJC21C/UgyaZX41nPt8bUTg+jWyDeg7e7YN4xOM05YPSIXceACnXVtqyEw/LMClUQMtMZ+PGGpqQ=="], - "@miladyai/homepage/jsdom/whatwg-url": ["whatwg-url@16.0.1", "", { "dependencies": { "@exodus/bytes": "^1.11.0", "tr46": "^6.0.0", "webidl-conversions": "^8.0.1" } }, "sha512-1to4zXBxmXHV3IiSSEInrreIlu02vUOvrhxJJH5vcxYTBDAx51cqZiKdyTxlecdKNSjj8EcxGBxNf6Vg+945gw=="], "@miladyai/ui/jsdom/@asamuzakjp/dom-selector": ["@asamuzakjp/dom-selector@7.0.8", "", { "dependencies": { "@asamuzakjp/nwsapi": "^2.3.9", "bidi-js": "^1.0.3", "css-tree": "^3.2.1", "is-potential-custom-element-name": "^1.0.1" } }, "sha512-erMO6FgtM02dC24NGm0xufMzWz5OF0wXKR7BpvGD973bq/GbmR8/DbxNZbj0YevQ5hlToJaWSVK/G9/NDgGEVw=="], - "@miladyai/ui/jsdom/parse5": ["parse5@8.0.0", "", { "dependencies": { "entities": "^6.0.0" } }, "sha512-9m4m5GSgXjL4AjumKzq1Fgfp3Z8rsvjRNbnkVwfu2ImRqE5D0LnY2QfDen18FSY9C573YU5XxSapdHZTZ2WolA=="], - - "@miladyai/ui/jsdom/tough-cookie": ["tough-cookie@6.0.1", "", { "dependencies": { "tldts": "^7.0.5" } }, "sha512-LktZQb3IeoUWB9lqR5EWTHgW/VTITCXg4D21M+lvybRVdylLrRMnqaIONLVb5mav8vM19m44HIcGq4qASeu2Qw=="], - - "@miladyai/ui/jsdom/webidl-conversions": ["webidl-conversions@8.0.1", "", {}, "sha512-BMhLD/Sw+GbJC21C/UgyaZX41nPt8bUTg+jWyDeg7e7YN4xOM05YPSIXceACnXVtqyEw/LMClUQMtMZ+PGGpqQ=="], - "@miladyai/ui/jsdom/whatwg-url": ["whatwg-url@16.0.1", "", { "dependencies": { "@exodus/bytes": "^1.11.0", "tr46": "^6.0.0", "webidl-conversions": "^8.0.1" } }, "sha512-1to4zXBxmXHV3IiSSEInrreIlu02vUOvrhxJJH5vcxYTBDAx51cqZiKdyTxlecdKNSjj8EcxGBxNf6Vg+945gw=="], "@neondatabase/serverless/@types/node/undici-types": ["undici-types@6.21.0", "", {}, "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ=="], @@ -7247,8 +7157,6 @@ "data-urls/whatwg-url/tr46": ["tr46@6.0.0", "", { "dependencies": { "punycode": "^2.3.1" } }, "sha512-bLVMLPtstlZ4iMQHpFHTR7GAGj2jxi8Dg0s2h2MafAE4uSWF98FC/3MomU51iQAMf8/qDUbKWf5GxuvvVcXEhw=="], - "data-urls/whatwg-url/webidl-conversions": ["webidl-conversions@8.0.1", "", {}, "sha512-BMhLD/Sw+GbJC21C/UgyaZX41nPt8bUTg+jWyDeg7e7YN4xOM05YPSIXceACnXVtqyEw/LMClUQMtMZ+PGGpqQ=="], - "degenerator/ast-types/tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], "elizaos/@clack/prompts/@clack/core": ["@clack/core@0.5.0", "", { "dependencies": { "picocolors": "^1.0.0", "sisteransi": "^1.0.5" } }, "sha512-p3y0FIOwaYRUPRcMO7+dlmLh8PSRcrjuTndsiA0WAFbWES0mLZlrjVoBRZ9DzkPFJZG6KGkJmoEAY0ZcVWTkow=="], @@ -7297,10 +7205,6 @@ "jayson/@types/ws/@types/node": ["@types/node@25.5.2", "", { "dependencies": { "undici-types": "~7.18.0" } }, "sha512-tO4ZIRKNC+MDWV4qKVZe3Ql/woTnmHDr5JD8UI5hn2pwBrHEwOEMZK7WlNb5RKB6EoJ02gwmQS9OrjuFnZYdpg=="], - "jsdom/parse5/entities": ["entities@6.0.1", "", {}, "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g=="], - - "jsdom/tough-cookie/tldts": ["tldts@7.0.28", "", { "dependencies": { "tldts-core": "^7.0.28" }, "bin": { "tldts": "bin/cli.js" } }, "sha512-+Zg3vWhRUv8B1maGSTFdev9mjoo8Etn2Ayfs4cnjlD3CsGkxXX4QyW3j2WJ0wdjYcYmy7Lx2RDsZMhgCWafKIw=="], - "jsdom/whatwg-url/tr46": ["tr46@6.0.0", "", { "dependencies": { "punycode": "^2.3.1" } }, "sha512-bLVMLPtstlZ4iMQHpFHTR7GAGj2jxi8Dg0s2h2MafAE4uSWF98FC/3MomU51iQAMf8/qDUbKWf5GxuvvVcXEhw=="], "jszip/readable-stream/string_decoder": ["string_decoder@1.1.1", "", { "dependencies": { "safe-buffer": "~5.1.0" } }, "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg=="], @@ -7409,6 +7313,8 @@ "@discordjs/node-pre-gyp/rimraf/glob/minimatch": ["minimatch@3.1.5", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w=="], + "@distube/ytdl-core/tough-cookie/tldts/tldts-core": ["tldts-core@6.1.86", "", {}, "sha512-Je6p7pkk+KMzMv2XXKmAE3McmolOQFdxkKw0R8EYNr7sELW46JqnNeTX8ybPiQgvg1ymCoF8LXs5fzFaZvJPTA=="], + "@elizaos-plugins/client-telegram-account/glob/jackspeak/@isaacs/cliui": ["@isaacs/cliui@9.0.0", "", {}, "sha512-AokJm4tuBHillT+FpMtxQ60n8ObyXBatq7jD2/JA9dxbDDokKQm8KMht5ibGzLVU9IJDIKK4TPKgMHEYMn3lMg=="], "@elizaos/plugin-agent-skills/@anthropic-ai/sdk/@types/node/undici-types": ["undici-types@5.26.5", "", {}, "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="], @@ -7551,16 +7457,8 @@ "@miladyai/capacitor-gateway/eslint/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], - "@miladyai/homepage/jsdom/parse5/entities": ["entities@6.0.1", "", {}, "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g=="], - - "@miladyai/homepage/jsdom/tough-cookie/tldts": ["tldts@7.0.28", "", { "dependencies": { "tldts-core": "^7.0.28" }, "bin": { "tldts": "bin/cli.js" } }, "sha512-+Zg3vWhRUv8B1maGSTFdev9mjoo8Etn2Ayfs4cnjlD3CsGkxXX4QyW3j2WJ0wdjYcYmy7Lx2RDsZMhgCWafKIw=="], - "@miladyai/homepage/jsdom/whatwg-url/tr46": ["tr46@6.0.0", "", { "dependencies": { "punycode": "^2.3.1" } }, "sha512-bLVMLPtstlZ4iMQHpFHTR7GAGj2jxi8Dg0s2h2MafAE4uSWF98FC/3MomU51iQAMf8/qDUbKWf5GxuvvVcXEhw=="], - "@miladyai/ui/jsdom/parse5/entities": ["entities@6.0.1", "", {}, "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g=="], - - "@miladyai/ui/jsdom/tough-cookie/tldts": ["tldts@7.0.28", "", { "dependencies": { "tldts-core": "^7.0.28" }, "bin": { "tldts": "bin/cli.js" } }, "sha512-+Zg3vWhRUv8B1maGSTFdev9mjoo8Etn2Ayfs4cnjlD3CsGkxXX4QyW3j2WJ0wdjYcYmy7Lx2RDsZMhgCWafKIw=="], - "@miladyai/ui/jsdom/whatwg-url/tr46": ["tr46@6.0.0", "", { "dependencies": { "punycode": "^2.3.1" } }, "sha512-bLVMLPtstlZ4iMQHpFHTR7GAGj2jxi8Dg0s2h2MafAE4uSWF98FC/3MomU51iQAMf8/qDUbKWf5GxuvvVcXEhw=="], "@puppeteer/browsers/yargs/cliui/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], @@ -7589,8 +7487,6 @@ "inquirer/cli-cursor/restore-cursor/onetime": ["onetime@1.1.0", "", {}, "sha512-GZ+g4jayMqzCRMgB2sol7GiCLjKfS1PINkjmx8spcKce1LiVqcbQreXwqs2YAFXC6R03VIG28ZS31t8M866v6A=="], - "jsdom/tough-cookie/tldts/tldts-core": ["tldts-core@7.0.28", "", {}, "sha512-7W5Efjhsc3chVdFhqtaU0KtK32J37Zcr9RKtID54nG+tIpcY79CQK/veYPODxtD/LJ4Lue66jvrQzIX2Z2/pUQ=="], - "node-edge-tts/yargs/cliui/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], "node-llama-cpp/yargs/cliui/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], @@ -7657,10 +7553,6 @@ "@miladyai/capacitor-gateway/eslint/minimatch/brace-expansion/balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], - "@miladyai/homepage/jsdom/tough-cookie/tldts/tldts-core": ["tldts-core@7.0.28", "", {}, "sha512-7W5Efjhsc3chVdFhqtaU0KtK32J37Zcr9RKtID54nG+tIpcY79CQK/veYPODxtD/LJ4Lue66jvrQzIX2Z2/pUQ=="], - - "@miladyai/ui/jsdom/tough-cookie/tldts/tldts-core": ["tldts-core@7.0.28", "", {}, "sha512-7W5Efjhsc3chVdFhqtaU0KtK32J37Zcr9RKtID54nG+tIpcY79CQK/veYPODxtD/LJ4Lue66jvrQzIX2Z2/pUQ=="], - "@puppeteer/browsers/yargs/cliui/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], "cmake-js/yargs/cliui/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], diff --git a/packages/agent/src/services/skill-marketplace.ts b/packages/agent/src/services/skill-marketplace.ts index d9a429f266..8b0fa293ba 100644 --- a/packages/agent/src/services/skill-marketplace.ts +++ b/packages/agent/src/services/skill-marketplace.ts @@ -87,10 +87,11 @@ async function runSkillSecurityScan( if (entry.name === "node_modules") continue; const fullPath = pathMod.join(dir, entry.name); const relPath = pathMod.relative(skillDir, fullPath); + const stats = await fsPromises.lstat(fullPath); - if (entry.isDirectory()) { + if (stats.isDirectory()) { await walk(fullPath); - } else if (entry.isFile()) { + } else if (stats.isFile()) { scannedFiles++; const ext = pathMod.extname(entry.name).toLowerCase(); if (BINARY_EXTENSIONS.has(ext)) { @@ -101,14 +102,16 @@ async function runSkillSecurityScan( message: `Binary executable file detected (${ext})`, }); } - } else if (entry.isSymbolicLink()) { - const resolved = await fsPromises.realpath(fullPath).catch(() => ""); - if (resolved && !resolved.startsWith(skillDir + pathMod.sep)) { + } else if (stats.isSymbolicLink()) { + const resolved = await fsPromises.realpath(fullPath).catch(() => null); + if (!resolved || !resolved.startsWith(skillDir + pathMod.sep)) { manifestFindings.push({ ruleId: "symlink-escape", severity: "critical", file: relPath, - message: `Symbolic link points outside skill directory`, + message: resolved + ? "Symbolic link points outside skill directory" + : "Symbolic link could not be resolved safely", }); } } @@ -205,7 +208,8 @@ export interface InstallSkillInput { } function stateDirBase(): string { - const base = process.env.ELIZA_STATE_DIR?.trim(); + const base = + process.env.MILADY_STATE_DIR?.trim() || process.env.ELIZA_STATE_DIR?.trim(); return base || path.join(os.homedir(), ".eliza"); } diff --git a/packages/agent/test/api-server.e2e.test.ts b/packages/agent/test/api-server.e2e.test.ts index 784c8be909..1853fb6070 100644 --- a/packages/agent/test/api-server.e2e.test.ts +++ b/packages/agent/test/api-server.e2e.test.ts @@ -789,11 +789,14 @@ function createRuntimeForProviderErrorTests(): AgentRuntime { let _e2eTempDir: string; let _origStateDirEnv: string | undefined; +let _origMiladyStateDirEnv: string | undefined; beforeAll(async () => { _origStateDirEnv = process.env.ELIZA_STATE_DIR; + _origMiladyStateDirEnv = process.env.MILADY_STATE_DIR; _e2eTempDir = await fs.mkdtemp(path.join(os.tmpdir(), "eliza-e2e-")); process.env.ELIZA_STATE_DIR = _e2eTempDir; + process.env.MILADY_STATE_DIR = _e2eTempDir; // Seed a minimal config so the server can start await fs.writeFile( @@ -820,6 +823,11 @@ afterAll(async () => { } else { delete process.env.ELIZA_STATE_DIR; } + if (_origMiladyStateDirEnv !== undefined) { + process.env.MILADY_STATE_DIR = _origMiladyStateDirEnv; + } else { + delete process.env.MILADY_STATE_DIR; + } if (_e2eTempDir) { await fs.rm(_e2eTempDir, { recursive: true, force: true }); } diff --git a/packages/agent/test/e2e-validation.e2e.test.ts b/packages/agent/test/e2e-validation.e2e.test.ts index 77dfc2d457..943166193a 100644 --- a/packages/agent/test/e2e-validation.e2e.test.ts +++ b/packages/agent/test/e2e-validation.e2e.test.ts @@ -71,10 +71,6 @@ function fileExistsAny(candidates: string[]): boolean { return candidates.some((candidate) => fs.existsSync(candidate)); } -function shellEscape(value: string): string { - return `'${value.replace(/'/g, `'\\''`)}'`; -} - function isRealNodeExecutable(candidate: string | undefined): boolean { if (!candidate || !fs.existsSync(candidate)) { return false; @@ -128,14 +124,7 @@ function runCliEntry( timeout: number = 90_000, ): string { const nodeExec = resolveNodeExec(); - const command = [ - shellEscape(nodeExec), - "--import", - "tsx", - shellEscape(cliEntryPath), - ...args.map(shellEscape), - ].join(" "); - return execFileSync("sh", ["-lc", command], { + return execFileSync(nodeExec, ["--import", "tsx", cliEntryPath, ...args], { cwd: repoRoot, timeout, encoding: "utf-8", diff --git a/packages/agent/test/lifeops-calendar.e2e.test.ts b/packages/agent/test/lifeops-calendar.e2e.test.ts index 6b59536bad..4b19b2d56e 100644 --- a/packages/agent/test/lifeops-calendar.e2e.test.ts +++ b/packages/agent/test/lifeops-calendar.e2e.test.ts @@ -111,6 +111,7 @@ describe("life-ops calendar sync", () => { beforeAll(async () => { envBackup = saveEnv( "ELIZA_STATE_DIR", + "MILADY_STATE_DIR", "MILADY_GOOGLE_OAUTH_DESKTOP_CLIENT_ID", "ELIZA_GOOGLE_OAUTH_DESKTOP_CLIENT_ID", "MILADY_GOOGLE_OAUTH_WEB_CLIENT_ID", @@ -122,6 +123,7 @@ describe("life-ops calendar sync", () => { ); stateDir = await fs.mkdtemp(path.join(os.tmpdir(), "lifeops-calendar-")); process.env.ELIZA_STATE_DIR = stateDir; + process.env.MILADY_STATE_DIR = stateDir; runtime = createRuntimeForCalendarTests(); const server = await startApiServer({ diff --git a/packages/agent/test/lifeops-gmail.e2e.test.ts b/packages/agent/test/lifeops-gmail.e2e.test.ts index fdd0bf3198..151f6cfa61 100644 --- a/packages/agent/test/lifeops-gmail.e2e.test.ts +++ b/packages/agent/test/lifeops-gmail.e2e.test.ts @@ -111,6 +111,7 @@ describe("life-ops gmail triage", () => { beforeAll(async () => { envBackup = saveEnv( "ELIZA_STATE_DIR", + "MILADY_STATE_DIR", "MILADY_GOOGLE_OAUTH_DESKTOP_CLIENT_ID", "ELIZA_GOOGLE_OAUTH_DESKTOP_CLIENT_ID", "MILADY_GOOGLE_OAUTH_WEB_CLIENT_ID", @@ -122,6 +123,7 @@ describe("life-ops gmail triage", () => { ); stateDir = await fs.mkdtemp(path.join(os.tmpdir(), "lifeops-gmail-")); process.env.ELIZA_STATE_DIR = stateDir; + process.env.MILADY_STATE_DIR = stateDir; runtime = createRuntimeForGmailTests(); const server = await startApiServer({ diff --git a/packages/agent/test/lifeops-google-oauth.e2e.test.ts b/packages/agent/test/lifeops-google-oauth.e2e.test.ts index 8c224236dc..1326a10165 100644 --- a/packages/agent/test/lifeops-google-oauth.e2e.test.ts +++ b/packages/agent/test/lifeops-google-oauth.e2e.test.ts @@ -14,6 +14,7 @@ import { vi, } from "vitest"; import { startApiServer } from "../src/api/server"; +import { resolveOAuthDir } from "../src/config/paths"; import { req } from "../../../test/helpers/http"; import { saveEnv } from "../../../test/helpers/test-utils"; import { DatabaseSync } from "../src/test-utils/sqlite-compat"; @@ -106,6 +107,7 @@ describe("life-ops Google OAuth foundation", () => { beforeAll(async () => { envBackup = saveEnv( "ELIZA_STATE_DIR", + "MILADY_STATE_DIR", "MILADY_GOOGLE_OAUTH_DESKTOP_CLIENT_ID", "ELIZA_GOOGLE_OAUTH_DESKTOP_CLIENT_ID", "MILADY_GOOGLE_OAUTH_WEB_CLIENT_ID", @@ -117,6 +119,7 @@ describe("life-ops Google OAuth foundation", () => { ); stateDir = await fs.mkdtemp(path.join(os.tmpdir(), "lifeops-google-oauth-")); process.env.ELIZA_STATE_DIR = stateDir; + process.env.MILADY_STATE_DIR = stateDir; const server = await startApiServer({ port: 0, @@ -273,7 +276,7 @@ describe("life-ops Google OAuth foundation", () => { const grant = statusRes.data.grant as Record; const tokenRef = String(grant.tokenRef); - const tokenPath = path.join(stateDir, "credentials", "lifeops", "google", tokenRef); + const tokenPath = path.join(resolveOAuthDir(process.env, stateDir), "lifeops", "google", tokenRef); const storedToken = JSON.parse(await fs.readFile(tokenPath, "utf-8")) as { refreshToken: string; accessToken: string; @@ -382,8 +385,7 @@ describe("life-ops Google OAuth foundation", () => { const grant = statusRes.data.grant as Record; const tokenPath = path.join( - stateDir, - "credentials", + resolveOAuthDir(process.env, stateDir), "lifeops", "google", String(grant.tokenRef), diff --git a/packages/agent/test/milaidy-life-ops-prd-validation.e2e.test.ts b/packages/agent/test/milaidy-life-ops-prd-validation.e2e.test.ts index e76c6ab20d..96a542e43c 100644 --- a/packages/agent/test/milaidy-life-ops-prd-validation.e2e.test.ts +++ b/packages/agent/test/milaidy-life-ops-prd-validation.e2e.test.ts @@ -14,6 +14,7 @@ import type { AgentRuntime, Task, UUID } from "@elizaos/core"; import { describe, expect, it, vi } from "vitest"; import { describeIf, itIf } from "../../../test/helpers/conditional-tests.ts"; import { startApiServer } from "../src/api/server"; +import { resolveOAuthDir } from "../src/config/paths"; import { LifeOpsRepository } from "../src/lifeops/repository"; import { LifeOpsService } from "../src/lifeops/service"; import { DatabaseSync } from "../src/test-utils/sqlite-compat"; @@ -439,6 +440,7 @@ async function withGoogleOAuthApiServer( ): Promise { const envBackup = saveEnv( "ELIZA_STATE_DIR", + "MILADY_STATE_DIR", "MILADY_GOOGLE_OAUTH_DESKTOP_CLIENT_ID", "ELIZA_GOOGLE_OAUTH_DESKTOP_CLIENT_ID", "MILADY_GOOGLE_OAUTH_WEB_CLIENT_ID", @@ -455,6 +457,7 @@ async function withGoogleOAuthApiServer( vi.stubGlobal("fetch", fetchMock as unknown as typeof fetch); process.env.ELIZA_STATE_DIR = stateDir; + process.env.MILADY_STATE_DIR = stateDir; for (const [key, value] of Object.entries(env)) { process.env[key] = value; } @@ -540,11 +543,12 @@ async function readJsonFile(filePath: string): Promise { async function withLiveLifeOpsApiServer( fn: (args: LiveServerContext) => Promise, ): Promise { - const envBackup = saveEnv("ELIZA_STATE_DIR"); + const envBackup = saveEnv("ELIZA_STATE_DIR", "MILADY_STATE_DIR"); const stateDir = await fs.mkdtemp( path.join(os.tmpdir(), "milaidy-prd-live-lifeops-"), ); process.env.ELIZA_STATE_DIR = stateDir; + process.env.MILADY_STATE_DIR = stateDir; const runtime = createApiRuntime( `milaidy-prd-live-${crypto.randomUUID().slice(0, 8)}`, @@ -700,8 +704,7 @@ async function connectLiveGoogle(args: { const grant = statusRes.data.grant as Record; const tokenPath = path.join( - args.stateDir, - "credentials", + resolveOAuthDir(process.env, args.stateDir), "lifeops", "google", String(grant.tokenRef ?? ""), diff --git a/packages/agent/test/skills-marketplace-services.e2e.test.ts b/packages/agent/test/skills-marketplace-services.e2e.test.ts index 6916f2570d..698bc65cab 100644 --- a/packages/agent/test/skills-marketplace-services.e2e.test.ts +++ b/packages/agent/test/skills-marketplace-services.e2e.test.ts @@ -121,12 +121,14 @@ beforeEach(async () => { savedEnv = { ELIZA_STATE_DIR: process.env.ELIZA_STATE_DIR, + MILADY_STATE_DIR: process.env.MILADY_STATE_DIR, SKILLS_MARKETPLACE_URL: process.env.SKILLS_MARKETPLACE_URL, SKILLS_REGISTRY: process.env.SKILLS_REGISTRY, CLAWHUB_REGISTRY: process.env.CLAWHUB_REGISTRY, SKILLSMP_API_KEY: process.env.SKILLSMP_API_KEY, }; process.env.ELIZA_STATE_DIR = tmpDir; + process.env.MILADY_STATE_DIR = tmpDir; delete process.env.SKILLS_REGISTRY; delete process.env.CLAWHUB_REGISTRY; delete process.env.SKILLS_MARKETPLACE_URL; diff --git a/packages/agent/test/subscription-auth.e2e.test.ts b/packages/agent/test/subscription-auth.e2e.test.ts index 6871f020c0..d9e965e72d 100644 --- a/packages/agent/test/subscription-auth.e2e.test.ts +++ b/packages/agent/test/subscription-auth.e2e.test.ts @@ -12,6 +12,7 @@ import { } from "vitest"; import { startApiServer } from "@miladyai/agent/api/server"; import type { OAuthCredentials } from "@miladyai/agent/auth"; +import { resolveConfigPath } from "../src/config/paths"; import { req } from "../../../test/helpers/http"; import { saveEnv } from "../../../test/helpers/test-utils"; @@ -67,6 +68,7 @@ describe("subscription auth routes (e2e contract)", () => { beforeAll(async () => { envBackup = saveEnv( "ELIZA_STATE_DIR", + "MILADY_STATE_DIR", "ELIZA_CONFIG_PATH", "ELIZA_API_TOKEN", "ELIZA_PAIRING_DISABLED", @@ -75,6 +77,7 @@ describe("subscription auth routes (e2e contract)", () => { stateDir = await fs.mkdtemp(path.join(os.tmpdir(), "eliza-subscription-")); process.env.ELIZA_STATE_DIR = stateDir; + process.env.MILADY_STATE_DIR = stateDir; delete process.env.ELIZA_CONFIG_PATH; delete process.env.ELIZA_API_TOKEN; delete process.env.ELIZA_PAIRING_DISABLED; @@ -177,7 +180,7 @@ describe("subscription auth routes (e2e contract)", () => { expect(setupRes.data.success).toBe(true); expect(process.env.ANTHROPIC_API_KEY).toBeUndefined(); - const configPath = path.join(stateDir, "eliza.json"); + const configPath = resolveConfigPath(process.env, stateDir); const rawConfig = await fs.readFile(configPath, "utf-8"); const parsed = JSON.parse(rawConfig) as { env?: Record }; expect(parsed.env?.__anthropicSubscriptionToken).toBe(token); @@ -206,7 +209,7 @@ describe("subscription auth routes (e2e contract)", () => { expect(res.data.success).toBe(true); expect(process.env.ANTHROPIC_API_KEY).toBeUndefined(); - const configPath = path.join(stateDir, "eliza.json"); + const configPath = resolveConfigPath(process.env, stateDir); const rawConfig = await fs.readFile(configPath, "utf-8"); const parsed = JSON.parse(rawConfig) as { env?: Record }; expect(parsed.env?.__anthropicSubscriptionToken).toBe( diff --git a/packages/app-core/src/api/__tests__/discord-managed-oauth.test.ts b/packages/app-core/src/api/__tests__/discord-managed-oauth.test.ts index 040fe413a4..aca3c9effd 100644 --- a/packages/app-core/src/api/__tests__/discord-managed-oauth.test.ts +++ b/packages/app-core/src/api/__tests__/discord-managed-oauth.test.ts @@ -169,7 +169,10 @@ describe("managed Discord OAuth init", () => { new Response( JSON.stringify({ success: true, - data: { authorizeUrl: "https://discord.com/oauth", applicationId: "app-1" }, + data: { + authorizeUrl: "https://discord.com/oauth", + applicationId: "app-1", + }, }), { status: 200, headers: { "Content-Type": "application/json" } }, ), @@ -191,7 +194,10 @@ describe("managed Discord OAuth init", () => { botNickname: "Chen", }); - const [, init] = fetchMock.mock.calls[0] as [RequestInfo | URL, RequestInit]; + const [, init] = fetchMock.mock.calls[0] as [ + RequestInfo | URL, + RequestInit, + ]; expect(init?.method).toBe("POST"); const body = JSON.parse(init?.body as string); @@ -207,7 +213,10 @@ describe("managed Discord OAuth init", () => { await client.createCloudCompatAgentManagedDiscordOauth("agent-1"); - const [, init] = fetchMock.mock.calls[0] as [RequestInfo | URL, RequestInit]; + const [, init] = fetchMock.mock.calls[0] as [ + RequestInfo | URL, + RequestInit, + ]; const body = JSON.parse(init?.body as string); expect(body).toEqual({}); }); diff --git a/packages/app-core/src/api/apps-hyperscape-e2e.test.ts b/packages/app-core/src/api/apps-hyperscape-e2e.test.ts index 1b571427ce..d9afb2e302 100644 --- a/packages/app-core/src/api/apps-hyperscape-e2e.test.ts +++ b/packages/app-core/src/api/apps-hyperscape-e2e.test.ts @@ -205,26 +205,26 @@ function clonePluginInfo(plugin: RegistryPluginInfo): RegistryPluginInfo { function createMockPluginManager( plugins: RegistryPluginInfo[] = [HYPERSCAPE_LOCAL_PLUGIN], ): PluginManagerLike { - const pluginEntries = plugins.map((plugin) => [ - plugin.name, - clonePluginInfo(plugin), - ] as const); + const pluginEntries = plugins.map( + (plugin) => [plugin.name, clonePluginInfo(plugin)] as const, + ); const pluginMap = new Map(pluginEntries); return { refreshRegistry: vi.fn( async () => new Map( - pluginEntries.map(([name, plugin]) => [name, clonePluginInfo(plugin)]), + pluginEntries.map(([name, plugin]) => [ + name, + clonePluginInfo(plugin), + ]), ), ), listInstalledPlugins: vi.fn(async () => []), - getRegistryPlugin: vi.fn( - async (name: string) => { - const plugin = pluginMap.get(name); - return plugin ? clonePluginInfo(plugin) : null; - }, - ), + getRegistryPlugin: vi.fn(async (name: string) => { + const plugin = pluginMap.get(name); + return plugin ? clonePluginInfo(plugin) : null; + }), searchRegistry: vi.fn(async (query: string) => { const lowerQuery = query.toLowerCase(); return plugins @@ -331,9 +331,9 @@ describeIf(hasLocalHyperscapePlugin)("Hyperscape E2E Integration", () => { const results = await appManager.search(pluginManager, "rpg"); expect(results.length).toBeGreaterThan(0); - expect(results.some((r) => r.name === "@hyperscape/plugin-hyperscape")).toBe( - true, - ); + expect( + results.some((r) => r.name === "@hyperscape/plugin-hyperscape"), + ).toBe(true); }); }); @@ -477,7 +477,9 @@ describeIf(hasLocalHyperscapePlugin)("Hyperscape E2E Integration", () => { test("complete discovery to launch flow", async () => { // Step 1: List apps const apps = await appManager.listAvailable(pluginManager); - expect(apps.some((a) => a.name === "@hyperscape/plugin-hyperscape")).toBe(true); + expect(apps.some((a) => a.name === "@hyperscape/plugin-hyperscape")).toBe( + true, + ); // Step 2: Get app info const info = await appManager.getInfo( diff --git a/packages/app-core/src/api/client-agent.ts b/packages/app-core/src/api/client-agent.ts index 6b9a4513b0..1cbc7108bc 100644 --- a/packages/app-core/src/api/client-agent.ts +++ b/packages/app-core/src/api/client-agent.ts @@ -349,7 +349,9 @@ declare module "./client-base" { fromSeq?: number; }): Promise; getExtensionStatus(): Promise; - getRelationshipsGraph(query?: RelationshipsGraphQuery): Promise; + getRelationshipsGraph( + query?: RelationshipsGraphQuery, + ): Promise; getRelationshipsPeople(query?: RelationshipsGraphQuery): Promise<{ people: RelationshipsPersonSummary[]; stats: RelationshipsGraphStats; diff --git a/packages/app-core/src/api/client-chat.ts b/packages/app-core/src/api/client-chat.ts index b5f2b43b95..5b20b0f86b 100644 --- a/packages/app-core/src/api/client-chat.ts +++ b/packages/app-core/src/api/client-chat.ts @@ -92,7 +92,11 @@ declare module "./client-base" { text: string, channelType?: ConversationChannelType, conversationMode?: ConversationMode, - ): Promise<{ text: string; agentName: string; noResponseReason?: "ignored" }>; + ): Promise<{ + text: string; + agentName: string; + noResponseReason?: "ignored"; + }>; sendChatStream( text: string, onToken: (token: string, accumulatedText?: string) => void, diff --git a/packages/app-core/src/api/client-relationships.test.ts b/packages/app-core/src/api/client-relationships.test.ts index 93ae131d3f..f5631de2ef 100644 --- a/packages/app-core/src/api/client-relationships.test.ts +++ b/packages/app-core/src/api/client-relationships.test.ts @@ -106,7 +106,9 @@ describe("MiladyClient relationships API", () => { const client = new MiladyClient("http://127.0.0.1:31337"); const person = await client.getRelationshipsPerson("person 1"); - expect(fetchSpy).toHaveBeenCalledWith("/api/relationships/people/person%201"); + expect(fetchSpy).toHaveBeenCalledWith( + "/api/relationships/people/person%201", + ); expect(person.displayName).toBe("Chris"); }); }); diff --git a/packages/app-core/src/api/database.readonly-query-guard.test.ts b/packages/app-core/src/api/database.readonly-query-guard.test.ts index f8739d625b..3986c76830 100644 --- a/packages/app-core/src/api/database.readonly-query-guard.test.ts +++ b/packages/app-core/src/api/database.readonly-query-guard.test.ts @@ -1,6 +1,14 @@ import type { AgentRuntime } from "@elizaos/core"; import { handleDatabaseRoute } from "@miladyai/agent/api/database"; -import { afterAll, afterEach, beforeAll, describe, expect, it, vi } from "vitest"; +import { + afterAll, + afterEach, + beforeAll, + describe, + expect, + it, + vi, +} from "vitest"; import { createTestRuntime } from "../../../../test/helpers/pglite-runtime"; import { createMockHttpResponse, diff --git a/packages/app-core/src/api/onboarding-compat-routes.ts b/packages/app-core/src/api/onboarding-compat-routes.ts index 278522cb35..f1efa128f3 100644 --- a/packages/app-core/src/api/onboarding-compat-routes.ts +++ b/packages/app-core/src/api/onboarding-compat-routes.ts @@ -175,7 +175,6 @@ export async function handleOnboardingCompatRoute( `[milady-api] Failed to persist onboarding state: ${err instanceof Error ? err.message : String(err)}`, ); } - } catch { // JSON parse failed — let upstream handle the error } diff --git a/packages/app-core/src/api/plugins-compat-routes.ts b/packages/app-core/src/api/plugins-compat-routes.ts index 4d70728d05..ccd3fa0a33 100644 --- a/packages/app-core/src/api/plugins-compat-routes.ts +++ b/packages/app-core/src/api/plugins-compat-routes.ts @@ -629,7 +629,9 @@ export function buildPluginListResponse(runtime: AgentRuntime | null): { const configRecord = config as Record; const loadedNames = resolveLoadedPluginNames(runtime); const manifestPath = resolvePluginManifestPath(); - const manifestRoot = manifestPath ? path.dirname(manifestPath) : process.cwd(); + const manifestRoot = manifestPath + ? path.dirname(manifestPath) + : process.cwd(); const manifest = manifestPath ? (JSON.parse(fs.readFileSync(manifestPath, "utf8")) as PluginManifestFile) : null; @@ -1044,7 +1046,8 @@ export async function handlePluginsCompatRoutes( } const refreshed = ( - buildPluginListResponse(state.current).plugins as unknown as CompatPluginRecord[] + buildPluginListResponse(state.current) + .plugins as unknown as CompatPluginRecord[] ).find((candidate) => candidate.id === pluginId); result.payload.plugin = refreshed ?? result.payload.plugin ?? plugin; diff --git a/packages/app-core/src/api/server.no-response-fallback.test.ts b/packages/app-core/src/api/server.no-response-fallback.test.ts index fa6af442fd..b20e5f2cc4 100644 --- a/packages/app-core/src/api/server.no-response-fallback.test.ts +++ b/packages/app-core/src/api/server.no-response-fallback.test.ts @@ -341,9 +341,14 @@ describe("conversation no-response fallback", () => { }), ); - const created = await req(isolatedServer.port, "POST", "/api/conversations", { - title: "Timed out fallback thread", - }); + const created = await req( + isolatedServer.port, + "POST", + "/api/conversations", + { + title: "Timed out fallback thread", + }, + ); expect(created.status).toBe(200); const conversationId = String( (created.data.conversation as { id?: string } | undefined)?.id ?? "", diff --git a/packages/app-core/src/api/stream-routes.test.ts b/packages/app-core/src/api/stream-routes.test.ts index c9e0b6cd5f..9d319e61f6 100644 --- a/packages/app-core/src/api/stream-routes.test.ts +++ b/packages/app-core/src/api/stream-routes.test.ts @@ -1003,164 +1003,155 @@ async function loadCustomRtmpPlugin(): Promise<{ // createTwitchDestination() — destination adapter unit tests // --------------------------------------------------------------------------- -describeIf(hasTwitchDestinationModule)( - "createTwitchDestination()", - () => { - it("returns a StreamingDestination with id and name", async () => { +describeIf(hasTwitchDestinationModule)("createTwitchDestination()", () => { + it("returns a StreamingDestination with id and name", async () => { + const { createTwitchDestination } = await loadTwitchDestinationModule(); + const dest = createTwitchDestination({ streamKey: "test-key" }); + expect(dest.id).toBe("twitch"); + expect(dest.name).toBe("Twitch"); + }); + + it("getCredentials throws when no stream key is configured", async () => { + const origKey = process.env.TWITCH_STREAM_KEY; + delete process.env.TWITCH_STREAM_KEY; + + try { const { createTwitchDestination } = await loadTwitchDestinationModule(); - const dest = createTwitchDestination({ streamKey: "test-key" }); - expect(dest.id).toBe("twitch"); - expect(dest.name).toBe("Twitch"); - }); + const dest = createTwitchDestination(); + await expect(dest.getCredentials()).rejects.toThrow("not configured"); + } finally { + if (origKey !== undefined) process.env.TWITCH_STREAM_KEY = origKey; + } + }); - it("getCredentials throws when no stream key is configured", async () => { - const origKey = process.env.TWITCH_STREAM_KEY; - delete process.env.TWITCH_STREAM_KEY; + it("getCredentials returns Twitch RTMP URL with config stream key", async () => { + const { createTwitchDestination } = await loadTwitchDestinationModule(); + const dest = createTwitchDestination({ streamKey: "my-stream-key" }); + const creds = await dest.getCredentials(); - try { - const { createTwitchDestination } = await loadTwitchDestinationModule(); - const dest = createTwitchDestination(); - await expect(dest.getCredentials()).rejects.toThrow("not configured"); - } finally { - if (origKey !== undefined) process.env.TWITCH_STREAM_KEY = origKey; - } - }); + expect(creds.rtmpUrl).toBe("rtmp://live.twitch.tv/app"); + expect(creds.rtmpKey).toBe("my-stream-key"); + }); + + it("prefers config.streamKey over TWITCH_STREAM_KEY env var", async () => { + const origKey = process.env.TWITCH_STREAM_KEY; + process.env.TWITCH_STREAM_KEY = "env-key"; - it("getCredentials returns Twitch RTMP URL with config stream key", async () => { + try { const { createTwitchDestination } = await loadTwitchDestinationModule(); - const dest = createTwitchDestination({ streamKey: "my-stream-key" }); + const dest = createTwitchDestination({ streamKey: "config-key" }); const creds = await dest.getCredentials(); - - expect(creds.rtmpUrl).toBe("rtmp://live.twitch.tv/app"); - expect(creds.rtmpKey).toBe("my-stream-key"); - }); - - it("prefers config.streamKey over TWITCH_STREAM_KEY env var", async () => { - const origKey = process.env.TWITCH_STREAM_KEY; - process.env.TWITCH_STREAM_KEY = "env-key"; - - try { - const { createTwitchDestination } = await loadTwitchDestinationModule(); - const dest = createTwitchDestination({ streamKey: "config-key" }); - const creds = await dest.getCredentials(); - expect(creds.rtmpKey).toBe("config-key"); - } finally { - if (origKey !== undefined) { - process.env.TWITCH_STREAM_KEY = origKey; - } else { - delete process.env.TWITCH_STREAM_KEY; - } + expect(creds.rtmpKey).toBe("config-key"); + } finally { + if (origKey !== undefined) { + process.env.TWITCH_STREAM_KEY = origKey; + } else { + delete process.env.TWITCH_STREAM_KEY; } - }); + } + }); - it("falls back to TWITCH_STREAM_KEY env var when no config", async () => { - const origKey = process.env.TWITCH_STREAM_KEY; - process.env.TWITCH_STREAM_KEY = "env-key"; - - try { - const { createTwitchDestination } = await loadTwitchDestinationModule(); - const dest = createTwitchDestination(); - const creds = await dest.getCredentials(); - expect(creds.rtmpKey).toBe("env-key"); - } finally { - if (origKey !== undefined) { - process.env.TWITCH_STREAM_KEY = origKey; - } else { - delete process.env.TWITCH_STREAM_KEY; - } + it("falls back to TWITCH_STREAM_KEY env var when no config", async () => { + const origKey = process.env.TWITCH_STREAM_KEY; + process.env.TWITCH_STREAM_KEY = "env-key"; + + try { + const { createTwitchDestination } = await loadTwitchDestinationModule(); + const dest = createTwitchDestination(); + const creds = await dest.getCredentials(); + expect(creds.rtmpKey).toBe("env-key"); + } finally { + if (origKey !== undefined) { + process.env.TWITCH_STREAM_KEY = origKey; + } else { + delete process.env.TWITCH_STREAM_KEY; } - }); - }, -); + } + }); +}); // --------------------------------------------------------------------------- // createYoutubeDestination() — destination adapter unit tests // --------------------------------------------------------------------------- -describeIf(hasYoutubeDestinationModule)( - "createYoutubeDestination()", - () => { - it("returns a StreamingDestination with id and name", async () => { - const { createYoutubeDestination } = await loadYoutubeDestinationModule(); - const dest = createYoutubeDestination({ streamKey: "test-key" }); - expect(dest.id).toBe("youtube"); - expect(dest.name).toBe("YouTube"); - }); +describeIf(hasYoutubeDestinationModule)("createYoutubeDestination()", () => { + it("returns a StreamingDestination with id and name", async () => { + const { createYoutubeDestination } = await loadYoutubeDestinationModule(); + const dest = createYoutubeDestination({ streamKey: "test-key" }); + expect(dest.id).toBe("youtube"); + expect(dest.name).toBe("YouTube"); + }); - it("getCredentials throws when no stream key is configured", async () => { - const origKey = process.env.YOUTUBE_STREAM_KEY; - delete process.env.YOUTUBE_STREAM_KEY; - - try { - const { createYoutubeDestination } = - await loadYoutubeDestinationModule(); - const dest = createYoutubeDestination(); - await expect(dest.getCredentials()).rejects.toThrow("not configured"); - } finally { - if (origKey !== undefined) process.env.YOUTUBE_STREAM_KEY = origKey; - } - }); + it("getCredentials throws when no stream key is configured", async () => { + const origKey = process.env.YOUTUBE_STREAM_KEY; + delete process.env.YOUTUBE_STREAM_KEY; - it("getCredentials returns default YouTube RTMP URL with config stream key", async () => { + try { const { createYoutubeDestination } = await loadYoutubeDestinationModule(); - const dest = createYoutubeDestination({ streamKey: "yt-key" }); - const creds = await dest.getCredentials(); + const dest = createYoutubeDestination(); + await expect(dest.getCredentials()).rejects.toThrow("not configured"); + } finally { + if (origKey !== undefined) process.env.YOUTUBE_STREAM_KEY = origKey; + } + }); - expect(creds.rtmpUrl).toBe("rtmp://a.rtmp.youtube.com/live2"); - expect(creds.rtmpKey).toBe("yt-key"); - }); + it("getCredentials returns default YouTube RTMP URL with config stream key", async () => { + const { createYoutubeDestination } = await loadYoutubeDestinationModule(); + const dest = createYoutubeDestination({ streamKey: "yt-key" }); + const creds = await dest.getCredentials(); - it("uses custom RTMP URL when provided in config", async () => { - const { createYoutubeDestination } = await loadYoutubeDestinationModule(); - const dest = createYoutubeDestination({ - streamKey: "yt-key", - rtmpUrl: "rtmp://custom.youtube.com/live", - }); - const creds = await dest.getCredentials(); + expect(creds.rtmpUrl).toBe("rtmp://a.rtmp.youtube.com/live2"); + expect(creds.rtmpKey).toBe("yt-key"); + }); - expect(creds.rtmpUrl).toBe("rtmp://custom.youtube.com/live"); - expect(creds.rtmpKey).toBe("yt-key"); + it("uses custom RTMP URL when provided in config", async () => { + const { createYoutubeDestination } = await loadYoutubeDestinationModule(); + const dest = createYoutubeDestination({ + streamKey: "yt-key", + rtmpUrl: "rtmp://custom.youtube.com/live", }); + const creds = await dest.getCredentials(); - it("prefers config.streamKey over YOUTUBE_STREAM_KEY env var", async () => { - const origKey = process.env.YOUTUBE_STREAM_KEY; - process.env.YOUTUBE_STREAM_KEY = "env-key"; - - try { - const { createYoutubeDestination } = - await loadYoutubeDestinationModule(); - const dest = createYoutubeDestination({ streamKey: "config-key" }); - const creds = await dest.getCredentials(); - expect(creds.rtmpKey).toBe("config-key"); - } finally { - if (origKey !== undefined) { - process.env.YOUTUBE_STREAM_KEY = origKey; - } else { - delete process.env.YOUTUBE_STREAM_KEY; - } + expect(creds.rtmpUrl).toBe("rtmp://custom.youtube.com/live"); + expect(creds.rtmpKey).toBe("yt-key"); + }); + + it("prefers config.streamKey over YOUTUBE_STREAM_KEY env var", async () => { + const origKey = process.env.YOUTUBE_STREAM_KEY; + process.env.YOUTUBE_STREAM_KEY = "env-key"; + + try { + const { createYoutubeDestination } = await loadYoutubeDestinationModule(); + const dest = createYoutubeDestination({ streamKey: "config-key" }); + const creds = await dest.getCredentials(); + expect(creds.rtmpKey).toBe("config-key"); + } finally { + if (origKey !== undefined) { + process.env.YOUTUBE_STREAM_KEY = origKey; + } else { + delete process.env.YOUTUBE_STREAM_KEY; } - }); + } + }); - it("falls back to YOUTUBE_STREAM_KEY env var when no config", async () => { - const origKey = process.env.YOUTUBE_STREAM_KEY; - process.env.YOUTUBE_STREAM_KEY = "env-key"; - - try { - const { createYoutubeDestination } = - await loadYoutubeDestinationModule(); - const dest = createYoutubeDestination(); - const creds = await dest.getCredentials(); - expect(creds.rtmpKey).toBe("env-key"); - } finally { - if (origKey !== undefined) { - process.env.YOUTUBE_STREAM_KEY = origKey; - } else { - delete process.env.YOUTUBE_STREAM_KEY; - } + it("falls back to YOUTUBE_STREAM_KEY env var when no config", async () => { + const origKey = process.env.YOUTUBE_STREAM_KEY; + process.env.YOUTUBE_STREAM_KEY = "env-key"; + + try { + const { createYoutubeDestination } = await loadYoutubeDestinationModule(); + const dest = createYoutubeDestination(); + const creds = await dest.getCredentials(); + expect(creds.rtmpKey).toBe("env-key"); + } finally { + if (origKey !== undefined) { + process.env.YOUTUBE_STREAM_KEY = origKey; + } else { + delete process.env.YOUTUBE_STREAM_KEY; } - }); - }, -); + } + }); +}); // --------------------------------------------------------------------------- // createCustomRtmpDestination() — destination adapter unit tests diff --git a/packages/app-core/src/api/training-routes.test.ts b/packages/app-core/src/api/training-routes.test.ts index db3e70e388..05bf56fbd1 100644 --- a/packages/app-core/src/api/training-routes.test.ts +++ b/packages/app-core/src/api/training-routes.test.ts @@ -666,7 +666,9 @@ describe("training routes", () => { pathname: "/api/training/trajectories/export", body: { splitByTask: true, - outputDir: await mkdtemp(join(tmpdir(), "training-route-trajectories-")), + outputDir: await mkdtemp( + join(tmpdir(), "training-route-trajectories-"), + ), }, }); @@ -738,7 +740,12 @@ describe("training routes", () => { const exportedLines = (await readFile(outputPath, "utf-8")) .trim() .split("\n") - .map((line) => JSON.parse(line) as { messages: Array<{ role: string; content: string }> }); + .map( + (line) => + JSON.parse(line) as { + messages: Array<{ role: string; content: string }>; + }, + ); expect(result.status).toBe(201); expect(result.payload).toMatchObject({ diff --git a/packages/app-core/src/components/apps/AppDetailPane.tsx b/packages/app-core/src/components/apps/AppDetailPane.tsx index 0512dba3d6..b5e1b9f569 100644 --- a/packages/app-core/src/components/apps/AppDetailPane.tsx +++ b/packages/app-core/src/components/apps/AppDetailPane.tsx @@ -40,10 +40,7 @@ export function AppDetailPane({ const backLabel = t("appsview.Back", { defaultValue: "Back" }); const sessionModeLabel = getAppSessionModeLabel(app); const sessionFeatures = getAppSessionFeatureLabels(app); - const allTags = [ - ...sessionFeatures, - ...(app.capabilities ?? []), - ]; + const allTags = [...sessionFeatures, ...(app.capabilities ?? [])]; const launchLabel = busy ? t("appsview.Launching", { defaultValue: "Launching..." }) : t("appsview.Launch", { defaultValue: "Launch" }); @@ -68,9 +65,7 @@ export function AppDetailPane({ {app.displayName ?? app.name}
- {isActive ? ( - Active - ) : null} + {isActive ? Active : null} {app.category ? ( {CATEGORY_LABELS[app.category] ?? app.category} ) : null} diff --git a/packages/app-core/src/components/apps/extensions/DefenseAgentsDetailExtension.tsx b/packages/app-core/src/components/apps/extensions/DefenseAgentsDetailExtension.tsx index c1b9db43d1..5d1af7eb06 100644 --- a/packages/app-core/src/components/apps/extensions/DefenseAgentsDetailExtension.tsx +++ b/packages/app-core/src/components/apps/extensions/DefenseAgentsDetailExtension.tsx @@ -1,8 +1,6 @@ import { DefenseAgentsOperatorSurface } from "../surfaces/DefenseAgentsOperatorSurface"; import type { AppDetailExtensionProps } from "./types"; -export function DefenseAgentsDetailExtension({ - app, -}: AppDetailExtensionProps) { +export function DefenseAgentsDetailExtension({ app }: AppDetailExtensionProps) { return ; } diff --git a/packages/app-core/src/components/apps/extensions/TwoThousandFourScapeDetailExtension.tsx b/packages/app-core/src/components/apps/extensions/TwoThousandFourScapeDetailExtension.tsx index eb9245a983..b12563aab8 100644 --- a/packages/app-core/src/components/apps/extensions/TwoThousandFourScapeDetailExtension.tsx +++ b/packages/app-core/src/components/apps/extensions/TwoThousandFourScapeDetailExtension.tsx @@ -5,9 +5,6 @@ export function TwoThousandFourScapeDetailExtension({ app, }: AppDetailExtensionProps) { return ( - + ); } diff --git a/packages/app-core/src/components/onboarding/connection/ConnectionProviderDetailScreen.test.tsx b/packages/app-core/src/components/onboarding/connection/ConnectionProviderDetailScreen.test.tsx index 95b99a14a5..94ff62b65d 100644 --- a/packages/app-core/src/components/onboarding/connection/ConnectionProviderDetailScreen.test.tsx +++ b/packages/app-core/src/components/onboarding/connection/ConnectionProviderDetailScreen.test.tsx @@ -83,9 +83,13 @@ vi.mock("@miladyai/ui", async (importOriginal) => { {children} ), - SelectTrigger: ({ children }: { children?: React.ReactNode }) => <>{children}, + SelectTrigger: ({ children }: { children?: React.ReactNode }) => ( + <>{children} + ), SelectValue: () => null, - SelectContent: ({ children }: { children?: React.ReactNode }) => <>{children}, + SelectContent: ({ children }: { children?: React.ReactNode }) => ( + <>{children} + ), SelectItem: ({ value, children, @@ -97,9 +101,10 @@ vi.mock("@miladyai/ui", async (importOriginal) => { }); vi.mock("../../../providers", async () => { - const actual = await vi.importActual( - "../../../providers", - ); + const actual = + await vi.importActual( + "../../../providers", + ); return { ...actual, getProviderLogo: (...args: unknown[]) => mockGetProviderLogo(...args), @@ -169,8 +174,7 @@ function t( "Powers task agents only (Claude Code CLI). For the main agent runtime, connect Eliza Cloud or a direct API key.", }; - const template = - translations[key] ?? String(params?.defaultValue ?? key); + const template = translations[key] ?? String(params?.defaultValue ?? key); if (!params) { return template; } @@ -340,7 +344,10 @@ describe("ConnectionProviderDetailScreen", () => { target: { value: "ec-test-key" }, }); - expect(setState).toHaveBeenCalledWith("onboardingCloudApiKey", "ec-test-key"); + expect(setState).toHaveBeenCalledWith( + "onboardingCloudApiKey", + "ec-test-key", + ); }); it("switches Eliza Cloud tabs and starts the login flow from the login tab", () => { @@ -438,7 +445,10 @@ describe("ConnectionProviderDetailScreen", () => { fireEvent.click(screen.getByRole("radio", { name: /Claude Sonnet/i })); - expect(setState).toHaveBeenCalledWith("onboardingOpenRouterModel", "sonnet"); + expect(setState).toHaveBeenCalledWith( + "onboardingOpenRouterModel", + "sonnet", + ); }); it("trims Claude tokens and lets the user continue with limited setup after saving", async () => { @@ -475,7 +485,9 @@ describe("ConnectionProviderDetailScreen", () => { "sk-ant-oat01-test-token", ); expect( - await screen.findByRole("button", { name: "Continue with limited setup" }), + await screen.findByRole("button", { + name: "Continue with limited setup", + }), ).toBeTruthy(); expect( screen.getByRole("button", { name: "Add another provider" }), @@ -520,7 +532,9 @@ describe("ConnectionProviderDetailScreen", () => { ); await screen.findByRole("button", { name: "Add another provider" }); - fireEvent.click(screen.getByRole("button", { name: "Add another provider" })); + fireEvent.click( + screen.getByRole("button", { name: "Add another provider" }), + ); expect(dispatch).toHaveBeenCalledWith({ type: "clearProvider" }); }); @@ -837,7 +851,9 @@ describe("ConnectionProviderDetailScreen", () => { fireEvent.click(screen.getByRole("button", { name: "Start over" })); - expect(screen.getByRole("button", { name: "Log in with OpenAI" })).toBeTruthy(); + expect( + screen.getByRole("button", { name: "Log in with OpenAI" }), + ).toBeTruthy(); expect(screen.queryByLabelText("Redirect URL")).toBeNull(); }); @@ -976,7 +992,10 @@ describe("ConnectionProviderDetailScreen", () => { target: { value: "pi/creative" }, }); - expect(setState).toHaveBeenCalledWith("onboardingPrimaryModel", "pi/creative"); + expect(setState).toHaveBeenCalledWith( + "onboardingPrimaryModel", + "pi/creative", + ); }); it("clears the pi.ai override when the user switches to a custom model", () => { diff --git a/packages/app-core/src/components/pages/AdvancedPageView.test.tsx b/packages/app-core/src/components/pages/AdvancedPageView.test.tsx index bfde8f82fa..76c3cd7383 100644 --- a/packages/app-core/src/components/pages/AdvancedPageView.test.tsx +++ b/packages/app-core/src/components/pages/AdvancedPageView.test.tsx @@ -206,9 +206,8 @@ describe("AdvancedPageView", () => { ).length, ).toBeGreaterThan(0); expect( - tree.root.findByProps({ "data-testid": "advanced-subtab-relationships" }).props[ - "aria-pressed" - ], + tree.root.findByProps({ "data-testid": "advanced-subtab-relationships" }) + .props["aria-pressed"], ).toBe(true); }); }); diff --git a/packages/app-core/src/components/pages/AppsView.tsx b/packages/app-core/src/components/pages/AppsView.tsx index d086ea10d8..242695bd03 100644 --- a/packages/app-core/src/components/pages/AppsView.tsx +++ b/packages/app-core/src/components/pages/AppsView.tsx @@ -12,10 +12,7 @@ import { useApp } from "../../state"; import { openExternalUrl } from "../../utils"; import { AppDetailPane } from "../apps/AppDetailPane"; import { AppsCatalogGrid } from "../apps/AppsCatalogGrid"; -import { - filterAppsForCatalog, - shouldShowAppInAppsView, -} from "../apps/helpers"; +import { filterAppsForCatalog, shouldShowAppInAppsView } from "../apps/helpers"; import { getRunAttentionReasons, RunningAppsPanel, diff --git a/packages/app-core/src/components/pages/PluginCard.tsx b/packages/app-core/src/components/pages/PluginCard.tsx index a59656d3cc..970acabd5d 100644 --- a/packages/app-core/src/components/pages/PluginCard.tsx +++ b/packages/app-core/src/components/pages/PluginCard.tsx @@ -362,23 +362,23 @@ export function PluginCard({ )}
{isStoreInstallMissing && !isShowcase && !p.loadError && ( - - )} + + )} {canUpdate && (
); @@ -117,7 +117,12 @@ export function RelationshipsGraphPanel({ aria-label="Relationships relationship graph" > - + diff --git a/packages/app-core/src/components/pages/RelationshipsIdentityCluster.tsx b/packages/app-core/src/components/pages/RelationshipsIdentityCluster.tsx index 5102127b32..7a56e1e7b5 100644 --- a/packages/app-core/src/components/pages/RelationshipsIdentityCluster.tsx +++ b/packages/app-core/src/components/pages/RelationshipsIdentityCluster.tsx @@ -9,7 +9,10 @@ function shortLabel(value: string, maxLength = 14): string { return value.length > maxLength ? `${value.slice(0, maxLength - 1)}…` : value; } -function identityLabel(person: RelationshipsPersonDetail, index: number): string { +function identityLabel( + person: RelationshipsPersonDetail, + index: number, +): string { const identity = person.identities[index]; if (!identity) { return `${index + 1}`; diff --git a/packages/app-core/src/components/pages/RelationshipsView.test.tsx b/packages/app-core/src/components/pages/RelationshipsView.test.tsx index ea147ca5b6..eeaa55a38a 100644 --- a/packages/app-core/src/components/pages/RelationshipsView.test.tsx +++ b/packages/app-core/src/components/pages/RelationshipsView.test.tsx @@ -4,13 +4,12 @@ import { fireEvent, render, screen, waitFor } from "@testing-library/react"; import type { ButtonHTMLAttributes, ReactNode } from "react"; import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; -const { mockUseApp, mockGetRelationshipsGraph, mockGetRelationshipsPerson } = vi.hoisted( - () => ({ +const { mockUseApp, mockGetRelationshipsGraph, mockGetRelationshipsPerson } = + vi.hoisted(() => ({ mockUseApp: vi.fn(), mockGetRelationshipsGraph: vi.fn(), mockGetRelationshipsPerson: vi.fn(), - }), -); + })); vi.mock("../../state", () => ({ useApp: () => mockUseApp(), @@ -18,8 +17,10 @@ vi.mock("../../state", () => ({ vi.mock("@miladyai/app-core/api", () => ({ client: { - getRelationshipsGraph: (...args: unknown[]) => mockGetRelationshipsGraph(...args), - getRelationshipsPerson: (...args: unknown[]) => mockGetRelationshipsPerson(...args), + getRelationshipsGraph: (...args: unknown[]) => + mockGetRelationshipsGraph(...args), + getRelationshipsPerson: (...args: unknown[]) => + mockGetRelationshipsPerson(...args), }, })); diff --git a/packages/app-core/src/components/pages/RelationshipsView.tsx b/packages/app-core/src/components/pages/RelationshipsView.tsx index 6a2c7e8519..fc83a9a30f 100644 --- a/packages/app-core/src/components/pages/RelationshipsView.tsx +++ b/packages/app-core/src/components/pages/RelationshipsView.tsx @@ -37,7 +37,9 @@ function toTimestamp(value?: string): number { return Number.isFinite(timestamp) ? timestamp : 0; } -function sortPeople(people: RelationshipsPersonSummary[]): RelationshipsPersonSummary[] { +function sortPeople( + people: RelationshipsPersonSummary[], +): RelationshipsPersonSummary[] { return [...people].sort((left, right) => { const timeDiff = toTimestamp(right.lastInteractionAt) - @@ -56,7 +58,9 @@ function summarizeHandles(person: RelationshipsPersonSummary): string { return handles.slice(0, 3).join(", "); } -function platformOptions(snapshot: RelationshipsGraphSnapshot | null): string[] { +function platformOptions( + snapshot: RelationshipsGraphSnapshot | null, +): string[] { if (!snapshot) return []; return [...new Set(snapshot.people.flatMap((person) => person.platforms))] .filter((platform) => platform.trim().length > 0) diff --git a/packages/app-core/src/components/pages/TrajectoriesView.actions.test.tsx b/packages/app-core/src/components/pages/TrajectoriesView.actions.test.tsx index 6a1193b23d..2178448053 100644 --- a/packages/app-core/src/components/pages/TrajectoriesView.actions.test.tsx +++ b/packages/app-core/src/components/pages/TrajectoriesView.actions.test.tsx @@ -382,7 +382,11 @@ describe("TrajectoriesView actions", () => { await waitFor(() => { expect(mockDeleteTrajectories).toHaveBeenCalledWith(["traj-1"]); - expect(setActionNotice).toHaveBeenCalledWith("delete failed", "error", 4200); + expect(setActionNotice).toHaveBeenCalledWith( + "delete failed", + "error", + 4200, + ); }); expect(onSelectTrajectory).not.toHaveBeenCalled(); }); @@ -460,7 +464,11 @@ describe("TrajectoriesView actions", () => { await waitFor(() => { expect(mockClearAllTrajectories).toHaveBeenCalledTimes(1); - expect(setActionNotice).toHaveBeenCalledWith("clear failed", "error", 4200); + expect(setActionNotice).toHaveBeenCalledWith( + "clear failed", + "error", + 4200, + ); }); expect(onSelectTrajectory).not.toHaveBeenCalled(); }); diff --git a/packages/app-core/src/components/pages/TrajectoriesView.tsx b/packages/app-core/src/components/pages/TrajectoriesView.tsx index ffe68f9637..7e0eb55019 100644 --- a/packages/app-core/src/components/pages/TrajectoriesView.tsx +++ b/packages/app-core/src/components/pages/TrajectoriesView.tsx @@ -341,7 +341,9 @@ export function TrajectoriesView({ disabled={loading} title={t("common.refresh")} > - + diff --git a/packages/app-core/src/components/pages/cloud-dashboard-panels.tsx b/packages/app-core/src/components/pages/cloud-dashboard-panels.tsx index 17e6166215..a9c372a1eb 100644 --- a/packages/app-core/src/components/pages/cloud-dashboard-panels.tsx +++ b/packages/app-core/src/components/pages/cloud-dashboard-panels.tsx @@ -585,9 +585,7 @@ function DiscordSettingsPanel({ - patchIntents({ guildMembers: v }) - } + onCheckedChange={(v) => patchIntents({ guildMembers: v })} className="scale-75" />
@@ -616,9 +614,7 @@ function DiscordSettingsPanel({ - patchFlagSetting("pluralkit", v) - } + onCheckedChange={(v) => patchFlagSetting("pluralkit", v)} className="scale-75" /> diff --git a/packages/app-core/src/components/pages/cloud-dashboard-utils.ts b/packages/app-core/src/components/pages/cloud-dashboard-utils.ts index 701ecc9941..1cc6cdd674 100644 --- a/packages/app-core/src/components/pages/cloud-dashboard-utils.ts +++ b/packages/app-core/src/components/pages/cloud-dashboard-utils.ts @@ -194,9 +194,7 @@ export function buildManagedDiscordSettingsReturnUrl( return url.toString(); } -export function resolveManagedDiscordAgentChoice( - agents: CloudCompatAgent[], -): +export function resolveManagedDiscordAgentChoice(agents: CloudCompatAgent[]): | { mode: "none"; agent: null; diff --git a/packages/app-core/src/components/pages/plugin-view-connectors.tsx b/packages/app-core/src/components/pages/plugin-view-connectors.tsx index 68e17dd84e..efc4c4a36e 100644 --- a/packages/app-core/src/components/pages/plugin-view-connectors.tsx +++ b/packages/app-core/src/components/pages/plugin-view-connectors.tsx @@ -155,17 +155,13 @@ function ConnectorPluginCard({ testResults, togglingPlugins, }: ConnectorPluginCardProps) { - const { - elizaCloudConnected, - setActionNotice, - setState, - setTab, - } = useApp(); + const { elizaCloudConnected, setActionNotice, setState, setTab } = useApp(); const [managedDiscordBusy, setManagedDiscordBusy] = useState(false); const [managedDiscordAgents, setManagedDiscordAgents] = useState< CloudCompatAgent[] >([]); - const [managedDiscordPickerOpen, setManagedDiscordPickerOpen] = useState(false); + const [managedDiscordPickerOpen, setManagedDiscordPickerOpen] = + useState(false); const [managedDiscordSelectedAgentId, setManagedDiscordSelectedAgentId] = useState(null); const hasParams = @@ -212,24 +208,21 @@ function ConnectorPluginCard({ setTab("settings"); }; const startManagedDiscordOauth = async (agent: CloudCompatAgent) => { - const oauthResponse = await client.createCloudCompatAgentManagedDiscordOauth( - agent.agent_id, - { + const oauthResponse = + await client.createCloudCompatAgentManagedDiscordOauth(agent.agent_id, { returnUrl: typeof window !== "undefined" - ? buildManagedDiscordSettingsReturnUrl(window.location.href) ?? - undefined + ? (buildManagedDiscordSettingsReturnUrl(window.location.href) ?? + undefined) : undefined, botNickname: agent.agent_name?.trim() || undefined, - }, - ); + }); await handleOpenPluginExternalUrl(oauthResponse.data.authorizeUrl); setManagedDiscordPickerOpen(false); setActionNotice( t("elizaclouddashboard.DiscordSetupContinuesInBrowser", { - defaultValue: - "Finish Discord setup in your browser, then return here.", + defaultValue: "Finish Discord setup in your browser, then return here.", }), "info", 5000, @@ -487,12 +480,12 @@ function ConnectorPluginCard({ {managedDiscordBusy ? "..." : elizaCloudConnected - ? t("pluginsview.UseManagedDiscord", { - defaultValue: "Use managed Discord", - }) - : t("pluginsview.OpenElizaCloud", { - defaultValue: "Open Eliza Cloud", - })} + ? t("pluginsview.UseManagedDiscord", { + defaultValue: "Use managed Discord", + }) + : t("pluginsview.OpenElizaCloud", { + defaultValue: "Open Eliza Cloud", + })} } > @@ -572,30 +565,30 @@ function ConnectorPluginCard({ )} {isStoreInstallMissing && !plugin.loadError && ( - - void handleInstallPlugin(plugin.id, plugin.npmName ?? "") - } - > - {installingPlugins.has(plugin.id) - ? installProgressLabel( - installProgress.get(plugin.npmName ?? "")?.message, - ) - : installPluginLabel} - - } - > - {connectorInstallPrompt} - - )} + + void handleInstallPlugin(plugin.id, plugin.npmName ?? "") + } + > + {installingPlugins.has(plugin.id) + ? installProgressLabel( + installProgress.get(plugin.npmName ?? "")?.message, + ) + : installPluginLabel} + + } + > + {connectorInstallPrompt} + + )} {hasParams ? (
diff --git a/packages/app-core/src/components/settings/ProviderSwitcher.test.tsx b/packages/app-core/src/components/settings/ProviderSwitcher.test.tsx index 5583cb3656..745a8f57c2 100644 --- a/packages/app-core/src/components/settings/ProviderSwitcher.test.tsx +++ b/packages/app-core/src/components/settings/ProviderSwitcher.test.tsx @@ -533,7 +533,11 @@ describe("ProviderSwitcher subscription selection behavior", () => { await Promise.resolve(); }); - expect(mockSwitchProvider).toHaveBeenCalledWith("pi-ai", undefined, undefined); + expect(mockSwitchProvider).toHaveBeenCalledWith( + "pi-ai", + undefined, + undefined, + ); expect(getSelectValue(tree)).toBe("openai-subscription"); expect(mockSetActionNotice).toHaveBeenCalledWith( "Failed to enable pi.ai: pi failed", @@ -696,7 +700,10 @@ describe("ProviderSwitcher subscription selection behavior", () => { }); await act(async () => { - getButtonByText(tree, "providerswitcher.reportIssueWithTemplate").props.onClick(); + getButtonByText( + tree, + "providerswitcher.reportIssueWithTemplate", + ).props.onClick(); await Promise.resolve(); }); @@ -705,7 +712,10 @@ describe("ProviderSwitcher subscription selection behavior", () => { ); await act(async () => { - getButtonByText(tree, "providerswitcher.logInToElizaCloud").props.onClick(); + getButtonByText( + tree, + "providerswitcher.logInToElizaCloud", + ).props.onClick(); await Promise.resolve(); }); diff --git a/packages/app-core/src/components/settings/ProviderSwitcher.tsx b/packages/app-core/src/components/settings/ProviderSwitcher.tsx index 8d5612f2ef..e95e96a0fe 100644 --- a/packages/app-core/src/components/settings/ProviderSwitcher.tsx +++ b/packages/app-core/src/components/settings/ProviderSwitcher.tsx @@ -190,8 +190,8 @@ export function ProviderSwitcher(props: ProviderSwitcherProps = {}) { (cfg.agents as { defaults?: { subscriptionProvider?: string } }) .defaults?.subscriptionProvider ?? "", ) - ? (cfg.agents as { defaults?: { subscriptionProvider?: string } }) - .defaults?.subscriptionProvider ?? null + ? ((cfg.agents as { defaults?: { subscriptionProvider?: string } }) + .defaults?.subscriptionProvider ?? null) : null; const nextSelectedId = llmText?.transport === "cloud-proxy" && providerId === "elizacloud" @@ -414,7 +414,12 @@ export function ProviderSwitcher(props: ProviderSwitcherProps = {}) { notifySelectionFailure("Failed to switch AI provider", err); } }, - [allAiProviders, notifySelectionFailure, resolvedSelectedId, restoreSelection], + [ + allAiProviders, + notifySelectionFailure, + resolvedSelectedId, + restoreSelection, + ], ); const handleSelectSubscription = useCallback( @@ -486,10 +491,9 @@ export function ProviderSwitcher(props: ProviderSwitcherProps = {}) { const hasKnownPiAiModel = (piAiModelOptions ?? []).some( (model) => model.id === normalizedPiAiModelSpec, ); - const piAiModelSelectValue = - piAiCustomMode - ? "__custom__" - : normalizedPiAiModelSpec.length === 0 + const piAiModelSelectValue = piAiCustomMode + ? "__custom__" + : normalizedPiAiModelSpec.length === 0 ? "__default__" : hasKnownPiAiModel ? normalizedPiAiModelSpec diff --git a/packages/app-core/src/components/settings/SubscriptionStatus.test.tsx b/packages/app-core/src/components/settings/SubscriptionStatus.test.tsx index 285a72aed5..047dd98340 100644 --- a/packages/app-core/src/components/settings/SubscriptionStatus.test.tsx +++ b/packages/app-core/src/components/settings/SubscriptionStatus.test.tsx @@ -1,14 +1,16 @@ // @vitest-environment jsdom import type React from "react"; -import { cleanup, fireEvent, render, screen, waitFor } from "@testing-library/react"; +import { + cleanup, + fireEvent, + render, + screen, + waitFor, +} from "@testing-library/react"; import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; -const { - mockClient, - mockUseApp, - mockOpenExternalUrl, -} = vi.hoisted(() => ({ +const { mockClient, mockUseApp, mockOpenExternalUrl } = vi.hoisted(() => ({ mockClient: { submitAnthropicSetupToken: vi.fn(async () => ({ success: true })), startAnthropicLogin: vi.fn(async () => ({ @@ -89,18 +91,19 @@ function t( "subscriptionstatus.ExpectedCallbackUrl": "Expected a localhost:1455/auth/callback URL.", "subscriptionstatus.ExchangeFailedError": "Exchange failed: {{message}}", - "subscriptionstatus.FailedToStartLogin": "Failed to start login: {{message}}", + "subscriptionstatus.FailedToStartLogin": + "Failed to start login: {{message}}", "subscriptionstatus.FailedToGetAuthUrl": "Failed to get auth URL", "subscriptionstatus.NoAuthUrlReturned": "No auth URL returned", - "subscriptionstatus.DisconnectFailedError": "Disconnect failed: {{message}}", + "subscriptionstatus.DisconnectFailedError": + "Disconnect failed: {{message}}", "subscriptionstatus.ExchangeFailed": "Exchange failed", "subscriptionstatus.SaveToken": "Save token", "subscriptionstatus.SavingAmpRestart": "Saving and restarting…", "subscriptionstatus.skAntOat01": "sk-ant-oat01-...", "subscriptionstatus.FailedToSaveTokenError": "Failed to save token: {{message}}", - "subscriptionstatus.FailedToSaveSetupToken": - "Failed to save setup token", + "subscriptionstatus.FailedToSaveSetupToken": "Failed to save setup token", "apikeyconfig.saved": "Saved", "apikeyconfig.saving": "Saving", "subscriptionstatus.ClaudeTosWarningShort": @@ -223,9 +226,7 @@ describe("SubscriptionStatus", () => { }); fireEvent.click(screen.getByRole("button", { name: "Save token" })); - expect( - await screen.findByText("Failed to save setup token"), - ).toBeTruthy(); + expect(await screen.findByText("Failed to save setup token")).toBeTruthy(); }); it("blocks invalid OpenAI callback URLs before calling exchange", async () => { @@ -310,9 +311,12 @@ describe("SubscriptionStatus", () => { fireEvent.click(screen.getByRole("button", { name: "OAuth login" })); fireEvent.click(screen.getByRole("button", { name: "Log in with Claude" })); await screen.findByPlaceholderText("Paste the authorization code"); - fireEvent.change(screen.getByPlaceholderText("Paste the authorization code"), { - target: { value: "anthro-code-123" }, - }); + fireEvent.change( + screen.getByPlaceholderText("Paste the authorization code"), + { + target: { value: "anthro-code-123" }, + }, + ); fireEvent.click(screen.getByRole("button", { name: "Connect" })); expect(await screen.findByText("Claude code rejected")).toBeTruthy(); @@ -347,9 +351,12 @@ describe("SubscriptionStatus", () => { fireEvent.click(screen.getByRole("button", { name: "OAuth login" })); fireEvent.click(screen.getByRole("button", { name: "Log in with Claude" })); await screen.findByPlaceholderText("Paste the authorization code"); - fireEvent.change(screen.getByPlaceholderText("Paste the authorization code"), { - target: { value: "anthro-success-code" }, - }); + fireEvent.change( + screen.getByPlaceholderText("Paste the authorization code"), + { + target: { value: "anthro-success-code" }, + }, + ); fireEvent.click(screen.getByRole("button", { name: "Connect" })); await waitFor(() => { @@ -377,9 +384,12 @@ describe("SubscriptionStatus", () => { fireEvent.click(screen.getByRole("button", { name: "OAuth login" })); fireEvent.click(screen.getByRole("button", { name: "Log in with Claude" })); await screen.findByPlaceholderText("Paste the authorization code"); - fireEvent.change(screen.getByPlaceholderText("Paste the authorization code"), { - target: { value: "anthro-code-123" }, - }); + fireEvent.change( + screen.getByPlaceholderText("Paste the authorization code"), + { + target: { value: "anthro-code-123" }, + }, + ); fireEvent.click(screen.getByRole("button", { name: "Connect" })); expect( @@ -388,7 +398,9 @@ describe("SubscriptionStatus", () => { fireEvent.click(screen.getByRole("button", { name: "Start over" })); - expect(screen.getByRole("button", { name: "Log in with Claude" })).toBeTruthy(); + expect( + screen.getByRole("button", { name: "Log in with Claude" }), + ).toBeTruthy(); expect(screen.queryByText("Exchange failed: bad claude code")).toBeNull(); }); @@ -436,7 +448,9 @@ describe("SubscriptionStatus", () => { ); }); expect(setOpenaiConnected).toHaveBeenCalledWith(true); - expect(handleSelectSubscription).toHaveBeenCalledWith("openai-subscription"); + expect(handleSelectSubscription).toHaveBeenCalledWith( + "openai-subscription", + ); expect(loadSubscriptionStatus).toHaveBeenCalledTimes(1); expect(mockClient.restartAgent).toHaveBeenCalledTimes(1); }); @@ -493,8 +507,12 @@ describe("SubscriptionStatus", () => { fireEvent.click(screen.getByRole("button", { name: "Start over" })); - expect(screen.getByRole("button", { name: "Log in with OpenAI" })).toBeTruthy(); - expect(screen.queryByText("Exchange failed: bad openai callback")).toBeNull(); + expect( + screen.getByRole("button", { name: "Log in with OpenAI" }), + ).toBeTruthy(); + expect( + screen.queryByText("Exchange failed: bad openai callback"), + ).toBeNull(); }); it("surfaces missing OpenAI auth URLs before opening the browser flow", async () => { @@ -602,6 +620,8 @@ describe("SubscriptionStatus", () => { ], }); - expect(screen.getByText("subscriptionstatus.ChatGPTSubscription")).toBeTruthy(); + expect( + screen.getByText("subscriptionstatus.ChatGPTSubscription"), + ).toBeTruthy(); }); }); diff --git a/packages/app-core/src/onboarding-config.ts b/packages/app-core/src/onboarding-config.ts index c63112f086..6c39637ab2 100644 --- a/packages/app-core/src/onboarding-config.ts +++ b/packages/app-core/src/onboarding-config.ts @@ -119,30 +119,33 @@ export function buildOnboardingRuntimeConfig( !args.omitRuntimeProvider && !requiresAdditionalRuntimeProvider(args.onboardingProvider); - if (args.onboardingProvider === "elizacloud" && shouldConfigureRuntimeProvider) { + if ( + args.onboardingProvider === "elizacloud" && + shouldConfigureRuntimeProvider + ) { llmTextRoute = buildElizaCloudServiceRoute({ smallModel, largeModel, }); } else if (shouldConfigureRuntimeProvider && localProviderId) { - const primaryModel = resolveOnboardingPrimaryModel({ - providerId: localProviderId, - onboardingPrimaryModel: args.onboardingPrimaryModel, - onboardingOpenRouterModel: args.onboardingOpenRouterModel, - }); - llmTextRoute = - serverTarget === "remote" - ? { - backend: localProviderId, - transport: "remote", - remoteApiBase: args.onboardingRemoteApiBase.trim(), - ...(primaryModel ? { primaryModel } : {}), - } - : { - backend: localProviderId, - transport: "direct", - ...(primaryModel ? { primaryModel } : {}), - }; + const primaryModel = resolveOnboardingPrimaryModel({ + providerId: localProviderId, + onboardingPrimaryModel: args.onboardingPrimaryModel, + onboardingOpenRouterModel: args.onboardingOpenRouterModel, + }); + llmTextRoute = + serverTarget === "remote" + ? { + backend: localProviderId, + transport: "remote", + remoteApiBase: args.onboardingRemoteApiBase.trim(), + ...(primaryModel ? { primaryModel } : {}), + } + : { + backend: localProviderId, + transport: "direct", + ...(primaryModel ? { primaryModel } : {}), + }; } if (llmTextRoute) { diff --git a/packages/app-core/src/providers/media-provider.real.test.ts b/packages/app-core/src/providers/media-provider.real.test.ts index 5b9fae02fd..19fd5fe0cb 100644 --- a/packages/app-core/src/providers/media-provider.real.test.ts +++ b/packages/app-core/src/providers/media-provider.real.test.ts @@ -13,7 +13,10 @@ */ import { afterAll, beforeAll, describe, expect, it } from "vitest"; -import { describeIf, itIf } from "../../../../test/helpers/conditional-tests.ts"; +import { + describeIf, + itIf, +} from "../../../../test/helpers/conditional-tests.ts"; import type { ImageConfig, VisionConfig } from "../config/types.eliza"; import { createImageProvider, @@ -273,34 +276,38 @@ describeFn("Ollama Local Vision Provider (Real API)", () => { } }, 60000); - itIf(REAL_API_MODE && process.env.MILADY_OLLAMA_DOWNLOAD_TEST === "1")("should auto-download vision model if not present (SLOW - downloads ~4GB model)", async () => { - if (!ollamaAvailable) { - console.log("[Ollama] Skipping - Ollama server not running"); - return; - } - - // This test verifies the auto-download feature - // The model should be downloaded on first use if autoDownload is true - // NOTE: Skipped by default because llava is ~4GB and takes a long time - console.log("[Ollama] Testing auto-download capability..."); - - const imageResponse = await fetch(TEST_IMAGE_URL); - const buffer = await imageResponse.arrayBuffer(); - const base64 = Buffer.from(buffer).toString("base64"); - - const result = await provider.analyze({ - imageBase64: base64, - prompt: "Describe this image in one sentence.", - }); - - // Either succeeds (model available/downloaded) or fails with clear error - if (result.success) { - expect(result.data?.description).toBeDefined(); - } else { - // If it fails, should be due to download failure or other clear reason - expect(result.error).toBeDefined(); - } - }, 600000); // 10 minute timeout for model download + itIf(REAL_API_MODE && process.env.MILADY_OLLAMA_DOWNLOAD_TEST === "1")( + "should auto-download vision model if not present (SLOW - downloads ~4GB model)", + async () => { + if (!ollamaAvailable) { + console.log("[Ollama] Skipping - Ollama server not running"); + return; + } + + // This test verifies the auto-download feature + // The model should be downloaded on first use if autoDownload is true + // NOTE: Skipped by default because llava is ~4GB and takes a long time + console.log("[Ollama] Testing auto-download capability..."); + + const imageResponse = await fetch(TEST_IMAGE_URL); + const buffer = await imageResponse.arrayBuffer(); + const base64 = Buffer.from(buffer).toString("base64"); + + const result = await provider.analyze({ + imageBase64: base64, + prompt: "Describe this image in one sentence.", + }); + + // Either succeeds (model available/downloaded) or fails with clear error + if (result.success) { + expect(result.data?.description).toBeDefined(); + } else { + // If it fails, should be due to download failure or other clear reason + expect(result.error).toBeDefined(); + } + }, + 600000, + ); // 10 minute timeout for model download }); // ============================================================================ diff --git a/packages/app-core/src/runtime/api-dev-settings-banner.ts b/packages/app-core/src/runtime/api-dev-settings-banner.ts index 9254689890..44444d21b2 100644 --- a/packages/app-core/src/runtime/api-dev-settings-banner.ts +++ b/packages/app-core/src/runtime/api-dev-settings-banner.ts @@ -132,9 +132,6 @@ export function formatApiDevSettingsBannerText( return prependDevSubsystemFigletHeading( "api", - formatDevSettingsTable( - "API — effective settings (after listen)", - rows, - ), + formatDevSettingsTable("API — effective settings (after listen)", rows), ); } diff --git a/packages/app-core/src/runtime/eliza.test.ts b/packages/app-core/src/runtime/eliza.test.ts index 4957d20ffa..e4ffe7967a 100644 --- a/packages/app-core/src/runtime/eliza.test.ts +++ b/packages/app-core/src/runtime/eliza.test.ts @@ -2518,50 +2518,47 @@ describe("mergeDropInPlugins", () => { // resolveElizaPluginImportSpecifier depending on the resolved source) // --------------------------------------------------------------------------- -describeIf(resolvePluginImportSpecifier)( - "resolvePluginImportSpecifier", - () => { - it("prefers a bundled local plugin wrapper when one exists", async () => { - const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "eliza-plugin-")); - const runtimeDir = path.join(tmpDir, "runtime"); - const pluginIndex = path.join(tmpDir, "plugins", "twitch", "index.js"); - - await fs.mkdir(runtimeDir, { recursive: true }); - await fs.mkdir(path.dirname(pluginIndex), { recursive: true }); - await fs.writeFile(pluginIndex, "export default {};\n"); - - const specifier = resolvePluginImportSpecifier?.( - "@elizaos/plugin-twitch", - pathToFileURL(path.join(runtimeDir, "eliza.ts")).href, - ); +describeIf(resolvePluginImportSpecifier)("resolvePluginImportSpecifier", () => { + it("prefers a bundled local plugin wrapper when one exists", async () => { + const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "eliza-plugin-")); + const runtimeDir = path.join(tmpDir, "runtime"); + const pluginIndex = path.join(tmpDir, "plugins", "twitch", "index.js"); + + await fs.mkdir(runtimeDir, { recursive: true }); + await fs.mkdir(path.dirname(pluginIndex), { recursive: true }); + await fs.writeFile(pluginIndex, "export default {};\n"); + + const specifier = resolvePluginImportSpecifier?.( + "@elizaos/plugin-twitch", + pathToFileURL(path.join(runtimeDir, "eliza.ts")).href, + ); - expect(specifier).toBe(pathToFileURL(pluginIndex).href); + expect(specifier).toBe(pathToFileURL(pluginIndex).href); - await fs.rm(tmpDir, { recursive: true, force: true }); - }); + await fs.rm(tmpDir, { recursive: true, force: true }); + }); - it("falls back to the bundled package when no local wrapper exists", async () => { - const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "eliza-plugin-")); - const runtimeDir = path.join(tmpDir, "runtime"); - await fs.mkdir(runtimeDir, { recursive: true }); + it("falls back to the bundled package when no local wrapper exists", async () => { + const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "eliza-plugin-")); + const runtimeDir = path.join(tmpDir, "runtime"); + await fs.mkdir(runtimeDir, { recursive: true }); - const specifier = resolvePluginImportSpecifier?.( - "@elizaos/plugin-x-streaming", - pathToFileURL(path.join(runtimeDir, "eliza.ts")).href, - ); + const specifier = resolvePluginImportSpecifier?.( + "@elizaos/plugin-x-streaming", + pathToFileURL(path.join(runtimeDir, "eliza.ts")).href, + ); - expect(specifier).toBe("@elizaos/plugin-x-streaming"); + expect(specifier).toBe("@elizaos/plugin-x-streaming"); - await fs.rm(tmpDir, { recursive: true, force: true }); - }); + await fs.rm(tmpDir, { recursive: true, force: true }); + }); - it("leaves non-project plugins unchanged", () => { - expect(resolvePluginImportSpecifier?.("@elizaos/plugin-discord")).toBe( - "@elizaos/plugin-discord", - ); - }); - }, -); + it("leaves non-project plugins unchanged", () => { + expect(resolvePluginImportSpecifier?.("@elizaos/plugin-discord")).toBe( + "@elizaos/plugin-discord", + ); + }); +}); describe("shouldIgnoreMissingPluginExport", () => { it("ignores helper-only streaming-base package exports", () => { diff --git a/packages/app-core/src/services/app-manager.test.ts b/packages/app-core/src/services/app-manager.test.ts index 3808377861..e297be1e09 100644 --- a/packages/app-core/src/services/app-manager.test.ts +++ b/packages/app-core/src/services/app-manager.test.ts @@ -460,7 +460,7 @@ describe("Hyperscape Auto-Provisioning", () => { let originalEnv: Record; const HYPERSCAPE_APP_NAME = "@hyperscape/plugin-hyperscape"; - const HYPERSCAPE_PLUGIN_NAME = "@elizaos/plugin-hyperscape"; + const HYPERSCAPE_PLUGIN_NAME = "@hyperscape/plugin-hyperscape"; beforeEach(async () => { // Flush any cached registry from prior test suites so fresh fetch mocks @@ -476,6 +476,7 @@ describe("Hyperscape Auto-Provisioning", () => { HYPERSCAPE_SERVER_URL: process.env.HYPERSCAPE_SERVER_URL, SOLANA_PRIVATE_KEY: process.env.SOLANA_PRIVATE_KEY, EVM_PRIVATE_KEY: process.env.EVM_PRIVATE_KEY, + MILADY_STATE_DIR: process.env.MILADY_STATE_DIR, ELIZA_STATE_DIR: process.env.ELIZA_STATE_DIR, }; @@ -496,6 +497,7 @@ describe("Hyperscape Auto-Provisioning", () => { pluginDirectory: pluginsDir, }); + process.env.MILADY_STATE_DIR = tempDir; process.env.ELIZA_STATE_DIR = tempDir; appManager = new AppManager(); }); @@ -546,9 +548,7 @@ describe("Hyperscape Auto-Provisioning", () => { "raw.githubusercontent.com/elizaos-plugins/registry/next/generated-registry.json", ) ) { - return Promise.resolve( - jsonResponse(createHyperscapeRegistryPayload()), - ); + return Promise.resolve(jsonResponse(createHyperscapeRegistryPayload())); } if ( url.includes( @@ -608,7 +608,9 @@ describe("Hyperscape Auto-Provisioning", () => { it("launches without Hyperscape iframe auth when no credentials or wallet are available", async () => { process.env.HYPERSCAPE_API_URL = "http://localhost:3333"; process.env.HYPERSCAPE_CLIENT_URL = "http://localhost:3333"; - const fetchMock = createHyperscapeLaunchFetchMock({ rejectWalletAuth: true }); + const fetchMock = createHyperscapeLaunchFetchMock({ + rejectWalletAuth: true, + }); global.fetch = fetchMock; // Mock listInstalledPlugins to report the plugin as already installed @@ -616,7 +618,12 @@ describe("Hyperscape Auto-Provisioning", () => { { name: HYPERSCAPE_PLUGIN_NAME, version: "1.0.0" }, ]); - const result = await appManager.launch(pluginManager, HYPERSCAPE_APP_NAME); + const result = await appManager.launch( + pluginManager, + HYPERSCAPE_APP_NAME, + undefined, + runtime, + ); expect(result.pluginInstalled).toBe(true); expect(result.viewer?.authMessage).toBeUndefined(); expect( @@ -631,7 +638,9 @@ describe("Hyperscape Auto-Provisioning", () => { process.env.HYPERSCAPE_CLIENT_URL = "http://localhost:3333"; process.env.HYPERSCAPE_CHARACTER_ID = "test-char-id"; process.env.HYPERSCAPE_AUTH_TOKEN = "test-auth-token"; - const fetchMock = createHyperscapeLaunchFetchMock({ rejectWalletAuth: true }); + const fetchMock = createHyperscapeLaunchFetchMock({ + rejectWalletAuth: true, + }); global.fetch = fetchMock; // Mock listInstalledPlugins to report the plugin as already installed @@ -639,14 +648,14 @@ describe("Hyperscape Auto-Provisioning", () => { { name: HYPERSCAPE_PLUGIN_NAME, version: "1.0.0" }, ]); - const result = await appManager.launch(pluginManager, HYPERSCAPE_APP_NAME); - expect(result.pluginInstalled).toBe(true); - expect(result.viewer?.authMessage).toEqual( - expect.objectContaining({ - authToken: "test-auth-token", - characterId: "test-char-id", - }), + const result = await appManager.launch( + pluginManager, + HYPERSCAPE_APP_NAME, + undefined, + runtime, ); + expect(result.pluginInstalled).toBe(true); + expect(result.viewer).toBeNull(); expect( fetchMock.mock.calls.some(([input]) => String(input).includes("wallet-auth"), @@ -659,7 +668,9 @@ describe("Hyperscape Auto-Provisioning", () => { process.env.HYPERSCAPE_CLIENT_URL = "http://localhost:3333"; process.env.HYPERSCAPE_CHARACTER_ID = "existing-char-id"; process.env.HYPERSCAPE_AUTH_TOKEN = "existing-auth-token"; - const fetchMock = createHyperscapeLaunchFetchMock({ rejectWalletAuth: true }); + const fetchMock = createHyperscapeLaunchFetchMock({ + rejectWalletAuth: true, + }); global.fetch = fetchMock; // Mock listInstalledPlugins to report the plugin as already installed @@ -977,7 +988,9 @@ describe("App session launch metadata", () => { ); } if ( - url.includes("/api/agents/11111111-1111-1111-1111-111111111111/thoughts") + url.includes( + "/api/agents/11111111-1111-1111-1111-111111111111/thoughts", + ) ) { return Promise.resolve( jsonResponse( @@ -1111,7 +1124,9 @@ describe("App session launch metadata", () => { ); } if ( - url.includes("/api/agents/22222222-2222-2222-2222-222222222222/thoughts") + url.includes( + "/api/agents/22222222-2222-2222-2222-222222222222/thoughts", + ) ) { return Promise.resolve( jsonResponse( diff --git a/packages/app-core/src/services/plugin-stability.test.ts b/packages/app-core/src/services/plugin-stability.test.ts index 957bd05e28..1cad18fb6d 100644 --- a/packages/app-core/src/services/plugin-stability.test.ts +++ b/packages/app-core/src/services/plugin-stability.test.ts @@ -12,11 +12,7 @@ * Issue: #3 — Plugin & Provider Stability */ -import type { - Plugin, - Provider, - ProviderResult, -} from "@elizaos/core"; +import type { Plugin, Provider, ProviderResult } from "@elizaos/core"; import { afterEach, beforeEach, describe, expect, it } from "vitest"; import { validateRuntimeContext } from "../api/plugin-validation"; import { CONNECTOR_PLUGINS } from "../config/plugin-auto-enable"; diff --git a/packages/app-core/src/services/registry-client.test.ts b/packages/app-core/src/services/registry-client.test.ts index 7edaaddfe3..b6b47e2129 100644 --- a/packages/app-core/src/services/registry-client.test.ts +++ b/packages/app-core/src/services/registry-client.test.ts @@ -299,15 +299,19 @@ beforeEach(async () => { tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "eliza-reg-test-")); savedEnv = { - // The upstream autonomous package uses ELIZA_* env vars + // The runtime now prefers MILADY_* and falls back to ELIZA_*. + MILADY_STATE_DIR: process.env.MILADY_STATE_DIR, + MILADY_WORKSPACE_ROOT: process.env.MILADY_WORKSPACE_ROOT, ELIZA_STATE_DIR: process.env.ELIZA_STATE_DIR, ELIZA_WORKSPACE_ROOT: process.env.ELIZA_WORKSPACE_ROOT, }; - // Point the file cache at our temp dir (set both eliza and eliza variants - // so tests pass regardless of which source is resolved via vitest aliases) + // Point cache/workspace discovery at an isolated temp root regardless of + // which namespace the resolved source prefers. + process.env.MILADY_STATE_DIR = tmpDir; process.env.ELIZA_STATE_DIR = tmpDir; const isolatedWorkspaceRoot = path.join(tmpDir, "workspace-empty"); await fs.mkdir(isolatedWorkspaceRoot, { recursive: true }); + process.env.MILADY_WORKSPACE_ROOT = isolatedWorkspaceRoot; process.env.ELIZA_WORKSPACE_ROOT = isolatedWorkspaceRoot; // Mock global fetch @@ -316,8 +320,8 @@ beforeEach(async () => { afterEach(async () => { vi.unstubAllGlobals(); - process.env.ELIZA_STATE_DIR = savedEnv.ELIZA_STATE_DIR; - process.env.ELIZA_WORKSPACE_ROOT = savedEnv.ELIZA_WORKSPACE_ROOT; + process.env.MILADY_STATE_DIR = savedEnv.MILADY_STATE_DIR; + process.env.MILADY_WORKSPACE_ROOT = savedEnv.MILADY_WORKSPACE_ROOT; process.env.ELIZA_STATE_DIR = savedEnv.ELIZA_STATE_DIR; process.env.ELIZA_WORKSPACE_ROOT = savedEnv.ELIZA_WORKSPACE_ROOT; await removeDirWithRetries(tmpDir); @@ -957,9 +961,9 @@ describe("registry-client", () => { const { listApps, getPluginInfo } = await loadModule(); const apps = await listApps(); - expect(apps.some((app) => app.name === "@hyperscape/plugin-hyperscape")).toBe( - true, - ); + expect( + apps.some((app) => app.name === "@hyperscape/plugin-hyperscape"), + ).toBe(true); const hyperscape = apps.find( (app) => app.name === "@hyperscape/plugin-hyperscape", diff --git a/packages/app-core/src/state/useOnboardingCallbacks.test.ts b/packages/app-core/src/state/useOnboardingCallbacks.test.ts index b7d1e01971..bb0531582c 100644 --- a/packages/app-core/src/state/useOnboardingCallbacks.test.ts +++ b/packages/app-core/src/state/useOnboardingCallbacks.test.ts @@ -1,9 +1,11 @@ // @vitest-environment jsdom -const { mockInvokeDesktopBridgeRequest, mockCapacitorAgentStart } = vi.hoisted(() => ({ - mockInvokeDesktopBridgeRequest: vi.fn(async () => undefined), - mockCapacitorAgentStart: vi.fn(async () => undefined), -})); +const { mockInvokeDesktopBridgeRequest, mockCapacitorAgentStart } = vi.hoisted( + () => ({ + mockInvokeDesktopBridgeRequest: vi.fn(async () => undefined), + mockCapacitorAgentStart: vi.fn(async () => undefined), + }), +); vi.mock("../bridge", () => ({ invokeDesktopBridgeRequest: (...args: unknown[]) => @@ -988,7 +990,10 @@ describe("useOnboardingCallbacks", () => { }); act(() => { - result.current.onboarding.setField("remoteApiBase", "ftp://ren.example.com"); + result.current.onboarding.setField( + "remoteApiBase", + "ftp://ren.example.com", + ); }); await act(async () => { @@ -1319,14 +1324,8 @@ describe("useOnboardingCallbacks", () => { }); result.current.onboarding.setField("name", "Chen"); result.current.onboarding.setField("serverTarget", "local"); - result.current.onboarding.setField( - "provider", - "anthropic-subscription", - ); - result.current.onboarding.setField( - "apiKey", - "sk-ant-oat01-test-token", - ); + result.current.onboarding.setField("provider", "anthropic-subscription"); + result.current.onboarding.setField("apiKey", "sk-ant-oat01-test-token"); }); await act(async () => { @@ -1528,7 +1527,9 @@ describe("useOnboardingCallbacks", () => { it("warns and still completes onboarding when voice preset persistence fails", async () => { const submitOnboarding = vi.fn().mockResolvedValue(undefined); - const updateConfig = vi.fn().mockRejectedValue(new Error("tts save failed")); + const updateConfig = vi + .fn() + .mockRejectedValue(new Error("tts save failed")); const setOnboardingComplete = vi.fn(); const setTab = vi.fn(); const warnSpy = vi.spyOn(console, "warn").mockImplementation(() => {}); diff --git a/plugins/plugin-groq b/plugins/plugin-groq deleted file mode 160000 index adb6e7573f..0000000000 --- a/plugins/plugin-groq +++ /dev/null @@ -1 +0,0 @@ -Subproject commit adb6e7573f4172a4b6572b389cb0754e17c76e73 diff --git a/scripts/ensure-bundled-workspaces.mjs b/scripts/ensure-bundled-workspaces.mjs index 2247dfe95f..836acc9828 100644 --- a/scripts/ensure-bundled-workspaces.mjs +++ b/scripts/ensure-bundled-workspaces.mjs @@ -22,6 +22,24 @@ export const BUNDLED_WORKSPACE_BUILDS = [ ), args: ["run", "build"], }, + { + label: "@elizaos/plugin-agent-skills", + cwd: path.join("plugins", "plugin-agent-skills", "typescript"), + manifest: path.join( + "plugins", + "plugin-agent-skills", + "typescript", + "package.json", + ), + artifact: path.join( + "plugins", + "plugin-agent-skills", + "typescript", + "dist", + "index.js", + ), + args: ["run", "build"], + }, ]; function runCommand(command, args, { cwd, env = process.env, label } = {}) { diff --git a/scripts/patch-workspace-plugins.mjs b/scripts/patch-workspace-plugins.mjs new file mode 100644 index 0000000000..f813da090e --- /dev/null +++ b/scripts/patch-workspace-plugins.mjs @@ -0,0 +1,156 @@ +#!/usr/bin/env node +/** + * Apply compatibility patches to workspace plugin submodules. + * + * These patches fix type errors introduced by @elizaos/core API changes that + * haven't been merged upstream yet. Each patch is stored under + * scripts/workspace-plugin-patches/ and applied idempotently via + * `git apply --check` / `git apply`. + * + * Patches are skipped gracefully when: + * - The submodule directory does not exist (not initialised yet) + * - The patch has already been applied (git apply --check fails with "already applied") + * - The upstream repo has fixed the issue (patch doesn't apply to current code) + * + * Remove a patch file once the corresponding elizaos-plugins PR is merged and + * the milady submodule pointer is bumped past it. + */ +import { execFileSync } from "node:child_process"; +import { existsSync, readdirSync } from "node:fs"; +import { dirname, resolve } from "node:path"; +import { fileURLToPath } from "node:url"; + +const __dirname = dirname(fileURLToPath(import.meta.url)); +const root = resolve(__dirname, ".."); +const patchDir = resolve(__dirname, "workspace-plugin-patches"); + +/** + * Mapping from patch filename prefix → plugin submodule path (relative to repo root). + * Convention: patch file is named `-.patch`. + */ +export const PLUGIN_PATCH_DIRS = { + "plugin-anthropic": "plugins/plugin-anthropic", + "plugin-google-genai": "plugins/plugin-google-genai", + "plugin-personality": "plugins/plugin-personality", + "plugin-agent-skills": "plugins/plugin-agent-skills", +}; + +export function resolvePluginDir(patchFile, { rootDir = root } = {}) { + for (const [prefix, submodulePath] of Object.entries(PLUGIN_PATCH_DIRS)) { + if (patchFile.startsWith(`${prefix}-`)) { + return resolve(rootDir, submodulePath); + } + } + return null; +} + +function exec(cmd, args, cwd) { + return execFileSync(cmd, args, { + cwd, + encoding: "utf8", + stdio: ["ignore", "pipe", "pipe"], + }); +} + +function applyPatch(patchPath, pluginDir) { + const patchName = patchPath.split(/[\\/]/).pop(); + + if (!existsSync(pluginDir)) { + console.log( + `[patch-workspace-plugins] Skipping ${patchName}: submodule not initialised`, + ); + return "skipped"; + } + + // Check if patch is already applied + try { + exec("git", ["apply", "--check", "--reverse", patchPath], pluginDir); + console.log( + `[patch-workspace-plugins] ${patchName}: already applied, skipping`, + ); + return "already-applied"; + } catch { + // Not yet applied — proceed + } + + // Check if patch applies cleanly + try { + exec("git", ["apply", "--check", patchPath], pluginDir); + } catch (checkErr) { + const msg = checkErr.stderr || checkErr.stdout || String(checkErr); + console.warn( + `[patch-workspace-plugins] ${patchName}: does not apply cleanly (upstream may have fixed it): ${msg.trim().slice(0, 200)}`, + ); + return "inapplicable"; + } + + // Apply the patch + try { + exec("git", ["apply", patchPath], pluginDir); + console.log(`[patch-workspace-plugins] ${patchName}: applied successfully`); + return "applied"; + } catch (applyErr) { + const msg = applyErr.stderr || applyErr.stdout || String(applyErr); + console.error( + `[patch-workspace-plugins] ERROR: failed to apply ${patchName}: ${msg.trim().slice(0, 400)}`, + ); + return "failed"; + } +} + +function run() { + if (!existsSync(patchDir)) { + console.log( + "[patch-workspace-plugins] No patches directory found, skipping", + ); + return; + } + + let patches; + try { + patches = readdirSync(patchDir) + .filter((f) => f.endsWith(".patch")) + .sort(); + } catch { + patches = []; + } + + if (patches.length === 0) { + console.log("[patch-workspace-plugins] No patch files found, skipping"); + return; + } + + let applied = 0; + let skipped = 0; + let failed = 0; + + for (const patchFile of patches) { + const pluginDir = resolvePluginDir(patchFile); + if (!pluginDir) { + console.warn( + `[patch-workspace-plugins] Cannot resolve plugin dir for ${patchFile}, skipping`, + ); + skipped++; + continue; + } + + const patchPath = resolve(patchDir, patchFile); + const result = applyPatch(patchPath, pluginDir); + if (result === "applied") applied++; + else if (result === "failed") failed++; + else skipped++; + } + + if (failed > 0) { + console.error( + `[patch-workspace-plugins] ${applied} applied, ${skipped} skipped, ${failed} FAILED`, + ); + process.exit(1); + } else { + console.log( + `[patch-workspace-plugins] ${applied} applied, ${skipped} skipped`, + ); + } +} + +run(); diff --git a/scripts/patch-workspace-plugins.test.ts b/scripts/patch-workspace-plugins.test.ts new file mode 100644 index 0000000000..1406be7831 --- /dev/null +++ b/scripts/patch-workspace-plugins.test.ts @@ -0,0 +1,70 @@ +import path from "node:path"; +import { describe, expect, it } from "vitest"; +import { + PLUGIN_PATCH_DIRS, + resolvePluginDir, +} from "./patch-workspace-plugins.mjs"; + +describe("PLUGIN_PATCH_DIRS", () => { + it("maps all expected plugin names to their submodule paths", () => { + expect(PLUGIN_PATCH_DIRS["plugin-anthropic"]).toBe( + "plugins/plugin-anthropic", + ); + expect(PLUGIN_PATCH_DIRS["plugin-google-genai"]).toBe( + "plugins/plugin-google-genai", + ); + expect(PLUGIN_PATCH_DIRS["plugin-personality"]).toBe( + "plugins/plugin-personality", + ); + expect(PLUGIN_PATCH_DIRS["plugin-agent-skills"]).toBe( + "plugins/plugin-agent-skills", + ); + }); +}); + +describe("resolvePluginDir", () => { + const root = path.resolve(process.cwd(), "test-repo-root"); + + it("resolves patch filenames to the correct plugin submodule directory", () => { + expect( + resolvePluginDir("plugin-anthropic-elizaos-core-api-compat.patch", { + rootDir: root, + }), + ).toBe(path.join(root, "plugins", "plugin-anthropic")); + + expect( + resolvePluginDir("plugin-google-genai-elizaos-core-api-compat.patch", { + rootDir: root, + }), + ).toBe(path.join(root, "plugins", "plugin-google-genai")); + + expect( + resolvePluginDir("plugin-personality-elizaos-core-api-compat.patch", { + rootDir: root, + }), + ).toBe(path.join(root, "plugins", "plugin-personality")); + + expect( + resolvePluginDir("plugin-agent-skills-crlf-fix.patch", { + rootDir: root, + }), + ).toBe(path.join(root, "plugins", "plugin-agent-skills")); + }); + + it("returns null for patch files with no matching prefix", () => { + expect( + resolvePluginDir("plugin-unknown-some-fix.patch", { rootDir: root }), + ).toBeNull(); + + expect( + resolvePluginDir("not-a-plugin-patch.patch", { rootDir: root }), + ).toBeNull(); + }); + + it("does not match partial prefix without trailing hyphen", () => { + // 'plugin-anthropicXYZ.patch' should not resolve to plugin-anthropic + expect( + resolvePluginDir("plugin-anthropicXYZ.patch", { rootDir: root }), + ).toBeNull(); + }); +}); diff --git a/scripts/run-repo-setup.mjs b/scripts/run-repo-setup.mjs index 14939383ff..66fc6b3a9b 100644 --- a/scripts/run-repo-setup.mjs +++ b/scripts/run-repo-setup.mjs @@ -12,6 +12,7 @@ const DEFAULT_REPO_ROOT = path.resolve(__dirname, ".."); export const repoSetupSteps = [ "scripts/init-submodules.mjs", + "scripts/patch-workspace-plugins.mjs", "scripts/patch-deps.mjs", "scripts/setup-upstreams.mjs", "scripts/ensure-bundled-workspaces.mjs", diff --git a/scripts/run-repo-setup.test.ts b/scripts/run-repo-setup.test.ts index 5362e3c067..2fb8d81be4 100644 --- a/scripts/run-repo-setup.test.ts +++ b/scripts/run-repo-setup.test.ts @@ -15,6 +15,7 @@ describe("repoSetupSteps", () => { it("keeps repo setup order explicit", () => { expect(repoSetupSteps).toEqual([ "scripts/init-submodules.mjs", + "scripts/patch-workspace-plugins.mjs", "scripts/patch-deps.mjs", "scripts/setup-upstreams.mjs", "scripts/ensure-bundled-workspaces.mjs", diff --git a/scripts/workspace-plugin-patches/plugin-anthropic-elizaos-core-api-compat.patch b/scripts/workspace-plugin-patches/plugin-anthropic-elizaos-core-api-compat.patch new file mode 100644 index 0000000000..8bf2d35101 --- /dev/null +++ b/scripts/workspace-plugin-patches/plugin-anthropic-elizaos-core-api-compat.patch @@ -0,0 +1,34 @@ +From 6711acc78e013c3ae6f7d0afc1dde9d165e4363d Mon Sep 17 00:00:00 2001 +From: dutch +Date: Thu, 9 Apr 2026 11:45:14 -0400 +Subject: [PATCH] fix: cast emitEvent payload for @elizaos/core EventPayloadMap + compat + +MODEL_USED is not in EventPayloadMap's known keys after the core API update. +Cast the payload to EventPayload to satisfy the generic overload. + +Co-Authored-By: Claude Sonnet 4.6 +--- + typescript/utils/events.ts | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/typescript/utils/events.ts b/typescript/utils/events.ts +index 361676b..b36a8ec 100644 +--- a/typescript/utils/events.ts ++++ b/typescript/utils/events.ts +@@ -1,4 +1,4 @@ +-import type { IAgentRuntime, ModelTypeName } from "@elizaos/core"; ++import type { EventPayload, IAgentRuntime, ModelTypeName } from "@elizaos/core"; + import { EventType } from "@elizaos/core"; + + type ModelUsage = { +@@ -34,5 +34,5 @@ export function emitModelUsageEvent( + ...(cacheRead !== undefined ? { cacheRead } : {}), + ...(cacheWrite !== undefined ? { cacheWrite } : {}), + }, +- }); ++ } as EventPayload); + } +-- +2.52.0.windows.1 + diff --git a/scripts/workspace-plugin-patches/plugin-google-genai-elizaos-core-api-compat.patch b/scripts/workspace-plugin-patches/plugin-google-genai-elizaos-core-api-compat.patch new file mode 100644 index 0000000000..3e81b8ef52 --- /dev/null +++ b/scripts/workspace-plugin-patches/plugin-google-genai-elizaos-core-api-compat.patch @@ -0,0 +1,104 @@ +From 659c87ce997d6f8b02e524ae4cb3072573c93bf2 Mon Sep 17 00:00:00 2001 +From: dutch +Date: Thu, 9 Apr 2026 13:10:07 -0400 +Subject: [PATCH] fix: use ModelType enum and cast EventPayload for + @elizaos/core API compat + +--- + typescript/index.ts | 24 ++++++++++++------------ + typescript/utils/events.ts | 4 ++-- + 2 files changed, 14 insertions(+), 14 deletions(-) + +diff --git a/typescript/index.ts b/typescript/index.ts +index 074eee5..dcde607 100644 +--- a/typescript/index.ts ++++ b/typescript/index.ts +@@ -9,7 +9,7 @@ import type { + TextEmbeddingParams, + } from "@elizaos/core"; + import * as ElizaCore from "@elizaos/core"; +-import { logger } from "@elizaos/core"; ++import { ModelType, logger } from "@elizaos/core"; + import { GoogleGenAI } from "@google/genai"; + import { initializeGoogleGenAI, type PluginConfig } from "./init"; + import { +@@ -70,7 +70,7 @@ const pluginTests = [ + name: "google_test_text_embedding", + fn: async (runtime: IAgentRuntime) => { + try { +- const embedding = await runtime.useModel(TEXT_EMBEDDING_MODEL_TYPE, { ++ const embedding = await runtime.useModel(ModelType.TEXT_EMBEDDING, { + text: "Hello, world!", + }); + logger.log(`Embedding dimension: ${embedding.length}`); +@@ -89,7 +89,7 @@ const pluginTests = [ + name: "google_test_text_small", + fn: async (runtime: IAgentRuntime) => { + try { +- const text = await runtime.useModel(TEXT_SMALL_MODEL_TYPE, { ++ const text = await runtime.useModel(ModelType.TEXT_SMALL, { + prompt: "What is the nature of reality in 10 words?", + }); + if (text.length === 0) { +@@ -108,7 +108,7 @@ const pluginTests = [ + name: "google_test_text_large", + fn: async (runtime: IAgentRuntime) => { + try { +- const text = await runtime.useModel(TEXT_LARGE_MODEL_TYPE, { ++ const text = await runtime.useModel(ModelType.TEXT_LARGE, { + prompt: "Explain quantum mechanics in simple terms.", + }); + if (text.length === 0) { +@@ -128,12 +128,12 @@ const pluginTests = [ + fn: async (runtime: IAgentRuntime) => { + try { + const result = await runtime.useModel( +- IMAGE_DESCRIPTION_MODEL_TYPE, ++ ModelType.IMAGE_DESCRIPTION, + "https://upload.wikimedia.org/wikipedia/commons/thumb/1/1c/Vitalik_Buterin_TechCrunch_London_2015_%28cropped%29.jpg/537px-Vitalik_Buterin_TechCrunch_London_2015_%28cropped%29.jpg" + ); + + if ( +- result && ++ result != null && + typeof result === "object" && + "title" in result && + "description" in result +@@ -164,14 +164,14 @@ const pluginTests = [ + required: ["name", "age", "hobbies"], + }; + +- const result = await runtime.useModel(OBJECT_SMALL_MODEL_TYPE, { ++ const result = await runtime.useModel(ModelType.OBJECT_SMALL, { + prompt: "Generate a person profile with name, age, and hobbies.", + schema, +- }); ++ }) as Record; + + logger.log("Generated object:", JSON.stringify(result)); + +- if (!result.name || !result.age || !result.hobbies) { ++ if (!result?.name || !result?.age || !result?.hobbies) { + throw new Error("Generated object missing required fields"); + } + } catch (error) { +diff --git a/typescript/utils/events.ts b/typescript/utils/events.ts +index eb19a83..c44864a 100644 +--- a/typescript/utils/events.ts ++++ b/typescript/utils/events.ts +@@ -1,4 +1,4 @@ +-import type { IAgentRuntime, ModelTypeName } from "@elizaos/core"; ++import type { EventPayload, IAgentRuntime, ModelTypeName } from "@elizaos/core"; + + const MODEL_USED_EVENT = "MODEL_USED"; + +@@ -22,5 +22,5 @@ export function emitModelUsageEvent( + completion: usage.completionTokens, + total: usage.totalTokens, + }, +- }); ++ } as EventPayload); + } +-- +2.52.0.windows.1 + diff --git a/scripts/workspace-plugin-patches/plugin-personality-elizaos-core-api-compat.patch b/scripts/workspace-plugin-patches/plugin-personality-elizaos-core-api-compat.patch new file mode 100644 index 0000000000..7f078da59a --- /dev/null +++ b/scripts/workspace-plugin-patches/plugin-personality-elizaos-core-api-compat.patch @@ -0,0 +1,69 @@ +From 389ad828117b9de97885bcf5471a2eff71bfcbff Mon Sep 17 00:00:00 2001 +From: dutch +Date: Thu, 9 Apr 2026 11:45:20 -0400 +Subject: [PATCH] fix: update zod records and metadata types for @elizaos/core + compat + +z.record() now requires explicit key schema as first argument (Zod v4 compat). +MetadataValue does not accept nested plain objects directly - stringify +evolutionData to store as a string value. CharacterSettings spread cast via +typeof to preserve the correct mapped type. + +Co-Authored-By: Claude Sonnet 4.6 +--- + typescript/src/evaluators/character-evolution.ts | 6 +++--- + typescript/src/services/character-file-manager.ts | 4 ++-- + 2 files changed, 5 insertions(+), 5 deletions(-) + +diff --git a/typescript/src/evaluators/character-evolution.ts b/typescript/src/evaluators/character-evolution.ts +index e40892a..1f46d6f 100644 +--- a/typescript/src/evaluators/character-evolution.ts ++++ b/typescript/src/evaluators/character-evolution.ts +@@ -42,7 +42,7 @@ const CharacterEvolutionSchema = z.object({ + .optional() + .describe("Updates to communication style"), + settings: z +- .record(z.union([z.string(), z.number(), z.boolean(), z.null()])) ++ .record(z.string(), z.union([z.string(), z.number(), z.boolean(), z.null()])) + .optional() + .describe("New setting values to add"), + }), +@@ -301,11 +301,11 @@ Return JSON analysis with specific, measurable reasoning for any suggested modif + evaluatorName: "character-evolution", + timestamp: Date.now(), + confidence: evolution.confidence, +- evolutionData: { ++ evolutionData: JSON.stringify({ + shouldModify: evolution.shouldModify, + gradualChange: evolution.gradualChange, + modifications: evolution.modifications, +- }, ++ }), + }, + }, + "character_evolution" +diff --git a/typescript/src/services/character-file-manager.ts b/typescript/src/services/character-file-manager.ts +index c182242..b2a488c 100644 +--- a/typescript/src/services/character-file-manager.ts ++++ b/typescript/src/services/character-file-manager.ts +@@ -40,7 +40,7 @@ const CharacterModificationSchema = z.object({ + post: z.array(z.string()).optional(), + }) + .optional(), +- settings: z.record(z.union([z.string(), z.number(), z.boolean(), z.null()])).optional(), ++ settings: z.record(z.string(), z.union([z.string(), z.number(), z.boolean(), z.null()])).optional(), + }); + + type CharacterModification = z.infer; +@@ -381,7 +381,7 @@ export class CharacterFileManager extends Service { + currentCharacter.settings = { + ...currentCharacter.settings, + ...modification.settings, +- }; ++ } as typeof currentCharacter.settings; + } + + // Update runtime character +-- +2.52.0.windows.1 + diff --git a/steward-fi b/steward-fi index c0883fd007..3a6b97b138 160000 --- a/steward-fi +++ b/steward-fi @@ -1 +1 @@ -Subproject commit c0883fd007ae834360d7ee183716ce59ed8ee849 +Subproject commit 3a6b97b138353d30860507fe5c66f058bd7d759a diff --git a/test/contracts/lib/openzeppelin-contracts b/test/contracts/lib/openzeppelin-contracts index 99a8f42977..9cfdccd353 160000 --- a/test/contracts/lib/openzeppelin-contracts +++ b/test/contracts/lib/openzeppelin-contracts @@ -1 +1 @@ -Subproject commit 99a8f429774cb8d47de3c9a4186463d829e92956 +Subproject commit 9cfdccd35350f7bcc585cf2ede08cd04e7f0ec10