From 3cc1baeb4b566eea3ab2db380539dd865e40a8b8 Mon Sep 17 00:00:00 2001 From: qyinm Date: Tue, 5 May 2026 15:45:59 +0900 Subject: [PATCH 1/4] feat: add local agent context server --- .gitignore | 1 + apps/desktop/main.cjs | 237 ++- apps/desktop/main/native-launch.node-test.cjs | 31 + docs/distribution.md | 5 +- docs/native-helper-boundaries.md | 20 +- native/agent-server-rust/Cargo.lock | 1844 +++++++++++++++++ native/agent-server-rust/Cargo.toml | 24 + native/agent-server-rust/src/main.rs | 367 ++++ native/native-host-rust/src/context_packet.rs | 5 + package.json | 5 +- scripts/build_and_run.sh | 2 + scripts/prepare_macos_release.sh | 4 +- scripts/smoke_notes_store.cjs | 12 +- 13 files changed, 2542 insertions(+), 15 deletions(-) create mode 100644 native/agent-server-rust/Cargo.lock create mode 100644 native/agent-server-rust/Cargo.toml create mode 100644 native/agent-server-rust/src/main.rs diff --git a/.gitignore b/.gitignore index 7148fc1..926805e 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,4 @@ native/stt-server-zig/zig-out/ .env.release.local native/stt-server-rust/target/ native/native-host-rust/target/ +native/agent-server-rust/target/ diff --git a/apps/desktop/main.cjs b/apps/desktop/main.cjs index 81ac92f..b76a252 100644 --- a/apps/desktop/main.cjs +++ b/apps/desktop/main.cjs @@ -5,6 +5,7 @@ const fs = require("node:fs/promises"); const fsSync = require("node:fs"); const http = require("node:http"); const https = require("node:https"); +const net = require("node:net"); const os = require("node:os"); const path = require("node:path"); const readline = require("node:readline"); @@ -43,6 +44,7 @@ const TRANSCRIPT_UPLOAD_EXTENSIONS = new Set([".json", ".jsonl", ".srt", ".txt"] const NOTE_UPLOAD_EXTENSIONS = new Set([".md"]); const SUMMARY_TEMPLATES = require("./summaryTemplates.json"); const DEFAULT_SUMMARY_TEMPLATE_ID = "general-meeting"; +const DEFAULT_AGENT_SERVER_PORT = 49731; const CUSTOM_SUMMARY_TEMPLATE_ID_PATTERN = /^custom:[A-Za-z0-9_-]{1,80}$/; const MAX_CUSTOM_SUMMARY_TEMPLATES = 30; const MAX_SUMMARY_TEMPLATE_SECTIONS = 12; @@ -1461,6 +1463,66 @@ function withDerivedSourceContextPaths(status, directoryPath, availablePaths = { }; } +function agentContextJobStatusPath(directoryPath) { + return path.join(contextPacketPaths(directoryPath).contextDirectoryPath, "agent-jobs", "generate-context.json"); +} + +function sourceContextStatusFromAgentJob(directoryPath) { + try { + const raw = fsSync.readFileSync(agentContextJobStatusPath(directoryPath), "utf8"); + const job = JSON.parse(raw); + const state = optionalNonEmptyString(job?.state); + if (state === "succeeded") { + return { + state: "ready", + detail: null, + retryable: false, + updatedAt: optionalNonEmptyString(job.updatedAt), + packetId: optionalNonEmptyString(job.packetId), + objectCount: Number.isFinite(Number(job.objectCount)) ? Number(job.objectCount) : 0, + relationCount: Number.isFinite(Number(job.relationCount)) ? Number(job.relationCount) : 0, + warningCount: Number.isFinite(Number(job.warningCount)) ? Number(job.warningCount) : 0, + agentBriefPath: null, + projectContextPath: null, + contextDirectoryPath: null, + }; + } + if (state === "failed") { + return { + state: "failed", + detail: optionalNonEmptyString(job.error) || "Source context generation failed.", + retryable: true, + updatedAt: optionalNonEmptyString(job.updatedAt), + packetId: null, + objectCount: 0, + relationCount: 0, + warningCount: 0, + agentBriefPath: null, + projectContextPath: null, + contextDirectoryPath: null, + }; + } + if (state === "queued" || state === "running") { + return { + state: "generating", + detail: null, + retryable: false, + updatedAt: optionalNonEmptyString(job.updatedAt), + packetId: null, + objectCount: 0, + relationCount: 0, + warningCount: 0, + agentBriefPath: null, + projectContextPath: null, + contextDirectoryPath: null, + }; + } + } catch { + return null; + } + return null; +} + function sourceContextStatusFromMetadata(metadata, directoryPath, options = {}) { const verifyFiles = options.verifyFiles !== false; const paths = contextPacketPaths(directoryPath); @@ -1503,6 +1565,10 @@ function sourceContextStatusFromMetadata(metadata, directoryPath, options = {}) } if (stored && stored.state !== "ready") { + const jobStatus = sourceContextStatusFromAgentJob(directoryPath); + if (jobStatus) { + return jobStatus.state === "ready" ? withDerivedSourceContextPaths(jobStatus, directoryPath) : jobStatus; + } return stored; } @@ -3201,7 +3267,7 @@ async function generateSourceContext(noteID) { const settings = await readElectronSettings(); const summarySettings = normalizeSummarySettings(settings.summary); try { - const payload = await nativeCaptureRequest("generateSourceContext", { + const payload = await agentServerRequest("generateContext", { targetDirectory: note.directoryPath, summarySettings, }); @@ -3240,6 +3306,17 @@ async function generateSourceContext(noteID) { } } +function scheduleAutomaticSourceContextGeneration(noteID) { + if (!noteID) { + return; + } + setTimeout(() => { + generateSourceContext(noteID).catch((error) => { + console.error(`Automatic source context generation failed for ${noteID}:`, error); + }); + }, 0); +} + async function openAgentBrief(noteID) { const directoryPath = resolveBundleDirectory(noteID); const paths = contextPacketPaths(directoryPath); @@ -3387,6 +3464,10 @@ function rustSTTServerPath() { return path.join(repoRoot(), "native", "stt-server-rust", "target", "release", "MirrorNoteSTTServer"); } +function rustAgentServerPath() { + return path.join(repoRoot(), "native", "agent-server-rust", "target", "release", "MirrorNoteAgentServer"); +} + function iconPath() { const candidates = [ path.join(repoRoot(), "branding", "app-icon-1024.png"), @@ -3537,6 +3618,32 @@ function resolveSTTServerLaunch() { throw new Error("MirrorNoteSTTServer was not found. Run npm run native:build."); } +function resolveAgentServerLaunch() { + if (process.env.MIRROR_NOTE_AGENT_SERVER_PATH) { + return { command: process.env.MIRROR_NOTE_AGENT_SERVER_PATH, args: [] }; + } + + const packaged = packagedHelperPath("MirrorNoteAgentServer"); + if (packaged) { + return { command: packaged, args: [] }; + } + + const rustServer = rustAgentServerPath(); + if (fsSync.existsSync(rustServer)) { + return { command: rustServer, args: [] }; + } + + throw new Error("MirrorNoteAgentServer was not found. Run npm run native:build."); +} + +function agentServerPort() { + const raw = Number(process.env.MIRROR_NOTE_AGENT_SERVER_PORT || DEFAULT_AGENT_SERVER_PORT); + if (Number.isInteger(raw) && raw > 0 && raw < 65536) { + return raw; + } + return DEFAULT_AGENT_SERVER_PORT; +} + function resolveNativeHostEnvironment() { const env = { ...process.env }; const packagedSTTServer = packagedHelperPath("MirrorNoteSTTServer"); @@ -3798,6 +3905,127 @@ let nativeCaptureRequest = function nativeCaptureRequest(command, payload = {}) return nativeCapture.request(command, payload); }; +class AgentServerBridge { + constructor() { + this.launching = null; + this.requestSequence = 0; + } + + async request(command, payload = {}) { + try { + return await this.send(command, payload); + } catch (error) { + if (!this.isConnectionError(error)) { + throw error; + } + await this.ensureStarted(); + return this.send(command, payload); + } + } + + isConnectionError(error) { + return ["ECONNREFUSED", "ECONNRESET", "EPIPE", "ETIMEDOUT"].includes(error?.code); + } + + async ensureStarted() { + if (this.launching) { + return this.launching; + } + this.launching = (async () => { + const launch = resolveAgentServerLaunch(); + const child = spawn(launch.command, launch.args, { + cwd: nativeHelperWorkingDirectory(), + env: resolveNativeHostEnvironment(), + detached: true, + stdio: "ignore", + }); + child.unref(); + await this.waitUntilReady(); + })(); + try { + await this.launching; + } finally { + this.launching = null; + } + } + + async waitUntilReady() { + const deadline = Date.now() + 5000; + let lastError = null; + while (Date.now() < deadline) { + try { + await this.send("capabilities", {}); + return; + } catch (error) { + lastError = error; + await new Promise((resolve) => setTimeout(resolve, 100)); + } + } + throw lastError || new Error("MirrorNoteAgentServer did not become ready."); + } + + send(command, payload = {}) { + const id = `agent-${Date.now()}-${++this.requestSequence}`; + const request = { + id, + command, + ...payload, + }; + const port = agentServerPort(); + + return new Promise((resolve, reject) => { + const socket = net.createConnection({ host: "127.0.0.1", port }); + let buffer = ""; + const timeout = setTimeout(() => { + const error = new Error("MirrorNoteAgentServer request timed out."); + error.code = "ETIMEDOUT"; + socket.destroy(error); + }, 120000); + + socket.setEncoding("utf8"); + socket.on("connect", () => { + socket.write(`${JSON.stringify(request)}\n`, "utf8"); + }); + socket.on("data", (chunk) => { + buffer += chunk; + const newlineIndex = buffer.indexOf("\n"); + if (newlineIndex === -1) { + return; + } + const line = buffer.slice(0, newlineIndex).trim(); + clearTimeout(timeout); + socket.end(); + if (!line) { + reject(new Error("MirrorNoteAgentServer returned an empty response.")); + return; + } + let message; + try { + message = JSON.parse(line); + } catch (error) { + reject(error); + return; + } + if (message.ok) { + resolve(message.payload || {}); + } else { + reject(new Error(message.error || "MirrorNoteAgentServer request failed.")); + } + }); + socket.on("error", (error) => { + clearTimeout(timeout); + reject(error); + }); + }); + } +} + +const agentServer = new AgentServerBridge(); + +let agentServerRequest = function agentServerRequest(command, payload = {}) { + return agentServer.request(command, payload); +}; + async function selectedTranscriptionConfiguration() { const settings = await readElectronSettings(); const selectedModel = await resolveSelectedInstalledModel(); @@ -4469,6 +4697,7 @@ async function handleStopCapture() { const payload = await nativeCapture.request("stopSession"); if (stoppingNoteId) { await enqueueListenerSessionStateWrite(stoppingNoteId, { state: "completed", detail: "" }, "completion").catch(() => {}); + scheduleAutomaticSourceContextGeneration(stoppingNoteId); activeListenerSessionNoteId = null; } setMenuBarCaptureState("completed", "", ""); @@ -4868,6 +5097,12 @@ if (process.env.MIRROR_NOTE_TEST_EXPORTS === "1") { set nativeCaptureRequest(value) { nativeCaptureRequest = value; }, + get agentServerRequest() { + return agentServerRequest; + }, + set agentServerRequest(value) { + agentServerRequest = value; + }, }, }; } else { diff --git a/apps/desktop/main/native-launch.node-test.cjs b/apps/desktop/main/native-launch.node-test.cjs index c4804bf..c0794d8 100644 --- a/apps/desktop/main/native-launch.node-test.cjs +++ b/apps/desktop/main/native-launch.node-test.cjs @@ -177,6 +177,37 @@ assert.deepEqual(sourceContextStatusFromMetadata({}, contextTempDirectory), { contextDirectoryPath: generatedContextPaths.contextDirectoryPath, }); +const failedJobContextDirectory = fs.mkdtempSync(path.join(os.tmpdir(), "mirrornote-source-context-job-")); +const failedJobPaths = contextPacketPaths(failedJobContextDirectory); +fs.mkdirSync(path.join(failedJobPaths.contextDirectoryPath, "agent-jobs"), { recursive: true }); +fs.writeFileSync(path.join(failedJobPaths.contextDirectoryPath, "agent-jobs", "generate-context.json"), JSON.stringify({ + jobId: "job-failed", + command: "generateContext", + state: "failed", + targetDirectory: failedJobContextDirectory, + queuedAt: "2026-05-04T00:00:00.000Z", + updatedAt: "2026-05-04T00:00:02.000Z", + error: "provider unavailable", +}, null, 2)); +assert.deepEqual(sourceContextStatusFromMetadata({ + sourceContext: { + state: "generating", + updatedAt: "2026-05-04T00:00:01.000Z", + }, +}, failedJobContextDirectory), { + state: "failed", + detail: "provider unavailable", + retryable: true, + updatedAt: "2026-05-04T00:00:02.000Z", + packetId: null, + objectCount: 0, + relationCount: 0, + warningCount: 0, + agentBriefPath: null, + projectContextPath: null, + contextDirectoryPath: null, +}); + const interruptedLedgerRecords = parseSTTChunkLedgerJSONL([ JSON.stringify({ sessionID: "session-a", diff --git a/docs/distribution.md b/docs/distribution.md index 3a4f142..02d565a 100644 --- a/docs/distribution.md +++ b/docs/distribution.md @@ -96,15 +96,16 @@ When an update downloads, the updater prompts the user to restart the app. ## What `release:prepare:mac` Does - builds the Vite renderer -- builds native helpers (`native-host-rust` + `stt-server-rust`) +- builds native helpers (`native-host-rust` + `stt-server-rust` + `agent-server-rust`) - prepares the Silero VAD model used by the embedded STT helper - generates `MirrorNote.icns` - stages release resources in `.build/release-macos/` The helper split is intentional: -- `MirrorNoteNativeHost` owns macOS capture, meeting bundles, artifact writes, and source context generation. +- `MirrorNoteNativeHost` owns macOS capture, meeting bundles, and artifact writes. - `MirrorNoteSTTServer` owns local STT runtime checks, embedded whisper.cpp model loading, Metal-backed macOS acceleration, and segment extraction. +- `MirrorNoteAgentServer` owns local agent jobs, starting with source context generation and persistent job status. See [native-helper-boundaries.md](native-helper-boundaries.md) for the process contract. diff --git a/docs/native-helper-boundaries.md b/docs/native-helper-boundaries.md index 9566530..1b916a0 100644 --- a/docs/native-helper-boundaries.md +++ b/docs/native-helper-boundaries.md @@ -1,6 +1,6 @@ # Native Helper Boundaries -MirrorNote ships two Rust helper binaries. They are separate processes because capture ownership and STT runtime ownership have different failure modes, permissions, and resource profiles. +MirrorNote ships three Rust helper binaries. They are separate processes because capture ownership, STT runtime ownership, and agent job ownership have different failure modes, permissions, and resource profiles. ## `native/native-host-rust` @@ -11,10 +11,9 @@ Owns macOS integration and meeting artifact orchestration. - Meeting bundle creation and final artifact writes. - Track mixing and `recording.mp3` export. - Source-only speaker labeling and transcript artifact assembly. -- Source context packet generation. - Launching `MirrorNoteSTTServer` through its framed protocol when captured audio needs transcription. -It must not call an external Whisper CLI directly or parse Whisper terminal output. STT runtime details belong to `stt-server-rust`. +It must not call an external Whisper CLI directly or parse Whisper terminal output. STT runtime details belong to `stt-server-rust`. It also must not own long-lived agent jobs; those belong to `agent-server-rust`. ## `native/stt-server-rust` @@ -31,12 +30,27 @@ Owns local speech-to-text runtime behavior. It must not create meeting bundles, write MirrorNote artifacts, manage CoreAudio capture, or know about note/source-context files. +## `native/agent-server-rust` + +Owns local agent job behavior. + +- Local daemon lifecycle independent of the desktop window. +- JSON-line TCP protocol on localhost. +- `generateContext` job execution. +- Persistent job status under the meeting bundle's `context/agent-jobs/` directory. +- Source context packet generation using the shared Rust context packet module. + +It must not capture audio, run STT, manage app windows, or introduce cloud-server assumptions. + ## Electron Boundary Electron resolves helper paths and sets environment variables for packaged and development runs: - `MIRROR_NOTE_NATIVE_HOST_PATH` selects `MirrorNoteNativeHost`. - `MIRROR_NOTE_STT_SERVER_PATH` selects `MirrorNoteSTTServer`. +- `MIRROR_NOTE_AGENT_SERVER_PATH` selects `MirrorNoteAgentServer`. +- `MIRROR_NOTE_AGENT_SERVER_PORT` selects the localhost agent daemon port. - `MIRROR_NOTE_SILERO_VAD_MODEL_PATH` optionally selects the Silero VAD model used by the STT server. Electron may call `MirrorNoteSTTServer` directly for explicit retry/retranscription flows, but live capture finalization goes through `MirrorNoteNativeHost`, which delegates transcription to `MirrorNoteSTTServer`. +Electron sends source context jobs to `MirrorNoteAgentServer`, and failures are persisted as retryable note metadata without blocking transcript or note review. diff --git a/native/agent-server-rust/Cargo.lock b/native/agent-server-rust/Cargo.lock new file mode 100644 index 0000000..037cf9a --- /dev/null +++ b/native/agent-server-rust/Cargo.lock @@ -0,0 +1,1844 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "adler2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" + +[[package]] +name = "agent-server-rust" +version = "0.1.0" +dependencies = [ + "anyhow", + "chrono", + "native-host-rust", + "serde", + "serde_json", + "tempfile", +] + +[[package]] +name = "aho-corasick" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" +dependencies = [ + "memchr", +] + +[[package]] +name = "alsa" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed7572b7ba83a31e20d1b48970ee402d2e3e0537dcfe0a3ff4d6eb7508617d43" +dependencies = [ + "alsa-sys", + "bitflags 2.11.1", + "cfg-if", + "libc", +] + +[[package]] +name = "alsa-sys" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db8fee663d06c4e303404ef5f40488a53e062f89ba8bfed81f42325aafad1527" +dependencies = [ + "libc", + "pkg-config", +] + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "anyhow" +version = "1.0.102" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" + +[[package]] +name = "autocfg" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "bindgen" +version = "0.72.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895" +dependencies = [ + "bitflags 2.11.1", + "cexpr", + "clang-sys", + "itertools", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", + "syn", +] + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3" + +[[package]] +name = "bumpalo" +version = "3.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" + +[[package]] +name = "bytes" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" + +[[package]] +name = "cc" +version = "1.2.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d16d90359e986641506914ba71350897565610e87ce0ad9e6f28569db3dd5c6d" +dependencies = [ + "find-msvc-tools", + "jobserver", + "libc", + "shlex", +] + +[[package]] +name = "cesu8" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" + +[[package]] +name = "cexpr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" +dependencies = [ + "nom", +] + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "chrono" +version = "0.4.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0" +dependencies = [ + "iana-time-zone", + "num-traits", + "windows-link", +] + +[[package]] +name = "clang-sys" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" +dependencies = [ + "glob", + "libc", + "libloading", +] + +[[package]] +name = "combine" +version = "4.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" +dependencies = [ + "bytes", + "memchr", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "coreaudio-rs" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "321077172d79c662f64f5071a03120748d5bb652f5231570141be24cfcd2bace" +dependencies = [ + "bitflags 1.3.2", + "core-foundation-sys", + "coreaudio-sys", +] + +[[package]] +name = "coreaudio-sys" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ceec7a6067e62d6f931a2baf6f3a751f4a892595bcec1461a3c94ef9949864b6" +dependencies = [ + "bindgen", +] + +[[package]] +name = "cpal" +version = "0.15.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "873dab07c8f743075e57f524c583985fbaf745602acbe916a01539364369a779" +dependencies = [ + "alsa", + "core-foundation-sys", + "coreaudio-rs", + "dasp_sample", + "jni", + "js-sys", + "libc", + "mach2", + "ndk", + "ndk-context", + "oboe", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "windows", +] + +[[package]] +name = "crc32fast" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "dasp_sample" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c87e182de0887fd5361989c677c4e8f5000cd9491d6d563161a8f3a5519fc7f" + +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "fastrand" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6" + +[[package]] +name = "find-msvc-tools" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" + +[[package]] +name = "flate2" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + +[[package]] +name = "form_urlencoded" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "futures-core" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" + +[[package]] +name = "futures-task" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" + +[[package]] +name = "futures-util" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" +dependencies = [ + "futures-core", + "futures-task", + "pin-project-lite", + "slab", +] + +[[package]] +name = "getrandom" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "getrandom" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "libc", + "r-efi 5.3.0", + "wasip2", +] + +[[package]] +name = "getrandom" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555" +dependencies = [ + "cfg-if", + "libc", + "r-efi 6.0.0", + "wasip2", + "wasip3", +] + +[[package]] +name = "glob" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" + +[[package]] +name = "hashbrown" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +dependencies = [ + "foldhash", +] + +[[package]] +name = "hashbrown" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f467dd6dccf739c208452f8014c75c18bb8301b050ad1cfb27153803edb0f51" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "iana-time-zone" +version = "0.1.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "log", + "wasm-bindgen", + "windows-core 0.62.2", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "icu_collections" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2984d1cd16c883d7935b9e07e44071dca8d917fd52ecc02c04d5fa0b5a3f191c" +dependencies = [ + "displaydoc", + "potential_utf", + "utf8_iter", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locale_core" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92219b62b3e2b4d88ac5119f8904c10f8f61bf7e95b640d25ba3075e6cac2c29" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_normalizer" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c56e5ee99d6e3d33bd91c5d85458b6005a22140021cc324cea84dd0e72cff3b4" +dependencies = [ + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da3be0ae77ea334f4da67c12f149704f19f81d1adf7c51cf482943e84a2bad38" + +[[package]] +name = "icu_properties" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bee3b67d0ea5c2cca5003417989af8996f8604e34fb9ddf96208a033901e70de" +dependencies = [ + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e2bbb201e0c04f7b4b3e14382af113e17ba4f63e2c9d2ee626b720cbce54a14" + +[[package]] +name = "icu_provider" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "139c4cf31c8b5f33d7e199446eff9c1e02decfc2f0eec2c8d71f65befa45b421" +dependencies = [ + "displaydoc", + "icu_locale_core", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", +] + +[[package]] +name = "id-arena" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" + +[[package]] +name = "idna" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb68373c0d6620ef8105e855e7745e18b0d00d3bdb07fb532e434244cdb9a714" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "indexmap" +version = "2.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" +dependencies = [ + "equivalent", + "hashbrown 0.17.0", + "serde", + "serde_core", +] + +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + +[[package]] +name = "jni" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97" +dependencies = [ + "cesu8", + "cfg-if", + "combine", + "jni-sys 0.3.1", + "log", + "thiserror", + "walkdir", + "windows-sys 0.45.0", +] + +[[package]] +name = "jni-sys" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41a652e1f9b6e0275df1f15b32661cf0d4b78d4d87ddec5e0c3c20f097433258" +dependencies = [ + "jni-sys 0.4.1", +] + +[[package]] +name = "jni-sys" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6377a88cb3910bee9b0fa88d4f42e1d2da8e79915598f65fb0c7ee14c878af2" +dependencies = [ + "jni-sys-macros", +] + +[[package]] +name = "jni-sys-macros" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38c0b942f458fe50cdac086d2f946512305e5631e720728f2a61aabcd47a6264" +dependencies = [ + "quote", + "syn", +] + +[[package]] +name = "jobserver" +version = "0.1.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" +dependencies = [ + "getrandom 0.3.4", + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.97" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1840c94c045fbcf8ba2812c95db44499f7c64910a912551aaaa541decebcacf" +dependencies = [ + "cfg-if", + "futures-util", + "once_cell", + "wasm-bindgen", +] + +[[package]] +name = "leb128fmt" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" + +[[package]] +name = "libc" +version = "0.2.186" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" + +[[package]] +name = "libloading" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55" +dependencies = [ + "cfg-if", + "windows-link", +] + +[[package]] +name = "linux-raw-sys" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" + +[[package]] +name = "litemap" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0" + +[[package]] +name = "log" +version = "0.4.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" + +[[package]] +name = "mach2" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d640282b302c0bb0a2a8e0233ead9035e3bed871f0b7e81fe4a1ec829765db44" +dependencies = [ + "libc", +] + +[[package]] +name = "memchr" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "miniz_oxide" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" +dependencies = [ + "adler2", + "simd-adler32", +] + +[[package]] +name = "native-host-rust" +version = "0.1.0" +dependencies = [ + "anyhow", + "cc", + "chrono", + "cpal", + "regex", + "serde", + "serde_json", + "ureq", +] + +[[package]] +name = "ndk" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2076a31b7010b17a38c01907c45b945e8f11495ee4dd588309718901b1f7a5b7" +dependencies = [ + "bitflags 2.11.1", + "jni-sys 0.3.1", + "log", + "ndk-sys", + "num_enum", + "thiserror", +] + +[[package]] +name = "ndk-context" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b" + +[[package]] +name = "ndk-sys" +version = "0.5.0+25.2.9519653" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c196769dd60fd4f363e11d948139556a344e79d451aeb2fa2fd040738ef7691" +dependencies = [ + "jni-sys 0.3.1", +] + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "num-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_enum" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d0bca838442ec211fa11de3a8b0e0e8f3a4522575b5c4c06ed722e005036f26" +dependencies = [ + "num_enum_derive", + "rustversion", +] + +[[package]] +name = "num_enum_derive" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "680998035259dcfcafe653688bf2aa6d3e2dc05e98be6ab46afb089dc84f1df8" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "oboe" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8b61bebd49e5d43f5f8cc7ee2891c16e0f41ec7954d36bcb6c14c5e0de867fb" +dependencies = [ + "jni", + "ndk", + "ndk-context", + "num-derive", + "num-traits", + "oboe-sys", +] + +[[package]] +name = "oboe-sys" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c8bb09a4a2b1d668170cfe0a7d5bc103f8999fb316c98099b6a9939c9f2e79d" +dependencies = [ + "cc", +] + +[[package]] +name = "once_cell" +version = "1.21.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" + +[[package]] +name = "percent-encoding" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" + +[[package]] +name = "pin-project-lite" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" + +[[package]] +name = "pkg-config" +version = "0.3.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19f132c84eca552bf34cab8ec81f1c1dcc229b811638f9d283dceabe58c5569e" + +[[package]] +name = "potential_utf" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0103b1cef7ec0cf76490e969665504990193874ea05c85ff9bab8b911d0a0564" +dependencies = [ + "zerovec", +] + +[[package]] +name = "prettyplease" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" +dependencies = [ + "proc-macro2", + "syn", +] + +[[package]] +name = "proc-macro-crate" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f" +dependencies = [ + "toml_edit", +] + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "r-efi" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" + +[[package]] +name = "regex" +version = "1.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" + +[[package]] +name = "ring" +version = "0.17.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" +dependencies = [ + "cc", + "cfg-if", + "getrandom 0.2.17", + "libc", + "untrusted", + "windows-sys 0.52.0", +] + +[[package]] +name = "rustc-hash" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94300abf3f1ae2e2b8ffb7b58043de3d399c73fa6f4b73826402a5c457614dbe" + +[[package]] +name = "rustix" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" +dependencies = [ + "bitflags 2.11.1", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.61.2", +] + +[[package]] +name = "rustls" +version = "0.23.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef86cd5876211988985292b91c96a8f2d298df24e75989a43a3c73f2d4d8168b" +dependencies = [ + "log", + "once_cell", + "ring", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-pki-types" +version = "1.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30a7197ae7eb376e574fe940d068c30fe0462554a3ddbe4eca7838e049c937a9" +dependencies = [ + "zeroize", +] + +[[package]] +name = "rustls-webpki" +version = "0.103.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61c429a8649f110dddef65e2a5ad240f747e85f7758a6bccc7e5777bd33f756e" +dependencies = [ + "ring", + "rustls-pki-types", + "untrusted", +] + +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "semver" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.149" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "simd-adler32" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "703d5c7ef118737c72f1af64ad2f6f8c5e1921f818cdcb97b8fe6fc69bf66214" + +[[package]] +name = "slab" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" + +[[package]] +name = "smallvec" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" + +[[package]] +name = "stable_deref_trait" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "syn" +version = "2.0.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "synstructure" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tempfile" +version = "3.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" +dependencies = [ + "fastrand", + "getrandom 0.4.2", + "once_cell", + "rustix", + "windows-sys 0.61.2", +] + +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tinystr" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8323304221c2a851516f22236c5722a72eaa19749016521d6dff0824447d96d" +dependencies = [ + "displaydoc", + "zerovec", +] + +[[package]] +name = "toml_datetime" +version = "1.1.1+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3165f65f62e28e0115a00b2ebdd37eb6f3b641855f9d636d3cd4103767159ad7" +dependencies = [ + "serde_core", +] + +[[package]] +name = "toml_edit" +version = "0.25.11+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b59c4d22ed448339746c59b905d24568fcbb3ab65a500494f7b8c3e97739f2b" +dependencies = [ + "indexmap", + "toml_datetime", + "toml_parser", + "winnow", +] + +[[package]] +name = "toml_parser" +version = "1.1.2+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2abe9b86193656635d2411dc43050282ca48aa31c2451210f4202550afb7526" +dependencies = [ + "winnow", +] + +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "ureq" +version = "2.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02d1a66277ed75f640d608235660df48c8e3c19f3b4edb6a263315626cc3c01d" +dependencies = [ + "base64", + "flate2", + "log", + "once_cell", + "rustls", + "rustls-pki-types", + "serde", + "serde_json", + "url", + "webpki-roots 0.26.11", +] + +[[package]] +name = "url" +version = "2.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", + "serde", +] + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "wasip2" +version = "1.0.3+wasi-0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20064672db26d7cdc89c7798c48a0fdfac8213434a1186e5ef29fd560ae223d6" +dependencies = [ + "wit-bindgen 0.57.1", +] + +[[package]] +name = "wasip3" +version = "0.4.0+wasi-0.3.0-rc-2026-01-06" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" +dependencies = [ + "wit-bindgen 0.51.0", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.120" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df52b6d9b87e0c74c9edfa1eb2d9bf85e5d63515474513aa50fa181b3c4f5db1" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.70" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af934872acec734c2d80e6617bbb5ff4f12b052dd8e6332b0817bce889516084" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.120" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78b1041f495fb322e64aca85f5756b2172e35cd459376e67f2a6c9dffcedb103" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.120" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dcd0ff20416988a18ac686d4d4d0f6aae9ebf08a389ff5d29012b05af2a1b41" +dependencies = [ + "bumpalo", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.120" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49757b3c82ebf16c57d69365a142940b384176c24df52a087fb748e2085359ea" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "wasm-encoder" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319" +dependencies = [ + "leb128fmt", + "wasmparser", +] + +[[package]] +name = "wasm-metadata" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" +dependencies = [ + "anyhow", + "indexmap", + "wasm-encoder", + "wasmparser", +] + +[[package]] +name = "wasmparser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" +dependencies = [ + "bitflags 2.11.1", + "hashbrown 0.15.5", + "indexmap", + "semver", +] + +[[package]] +name = "web-sys" +version = "0.3.97" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2eadbac71025cd7b0834f20d1fe8472e8495821b4e9801eb0a60bd1f19827602" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webpki-roots" +version = "0.26.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9" +dependencies = [ + "webpki-roots 1.0.7", +] + +[[package]] +name = "webpki-roots" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52f5ee44c96cf55f1b349600768e3ece3a8f26010c05265ab73f945bb1a2eb9d" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "winapi-util" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "windows" +version = "0.54.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9252e5725dbed82865af151df558e754e4a3c2c30818359eb17465f1346a1b49" +dependencies = [ + "windows-core 0.54.0", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-core" +version = "0.54.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12661b9c89351d684a50a8a643ce5f608e20243b9fb84687800163429f161d65" +dependencies = [ + "windows-result 0.1.2", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-core" +version = "0.62.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link", + "windows-result 0.4.1", + "windows-strings", +] + +[[package]] +name = "windows-implement" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-interface" +version = "0.59.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-result" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e383302e8ec8515204254685643de10811af0ed97ea37210dc26fb0032647f8" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-result" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-sys" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets 0.42.2", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-targets" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +dependencies = [ + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "winnow" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ee1708bef14716a11bae175f579062d4554d95be2c6829f518df847b7b3fdd0" +dependencies = [ + "memchr", +] + +[[package]] +name = "wit-bindgen" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" +dependencies = [ + "wit-bindgen-rust-macro", +] + +[[package]] +name = "wit-bindgen" +version = "0.57.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" + +[[package]] +name = "wit-bindgen-core" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" +dependencies = [ + "anyhow", + "heck", + "wit-parser", +] + +[[package]] +name = "wit-bindgen-rust" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" +dependencies = [ + "anyhow", + "heck", + "indexmap", + "prettyplease", + "syn", + "wasm-metadata", + "wit-bindgen-core", + "wit-component", +] + +[[package]] +name = "wit-bindgen-rust-macro" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a" +dependencies = [ + "anyhow", + "prettyplease", + "proc-macro2", + "quote", + "syn", + "wit-bindgen-core", + "wit-bindgen-rust", +] + +[[package]] +name = "wit-component" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" +dependencies = [ + "anyhow", + "bitflags 2.11.1", + "indexmap", + "log", + "serde", + "serde_derive", + "serde_json", + "wasm-encoder", + "wasm-metadata", + "wasmparser", + "wit-parser", +] + +[[package]] +name = "wit-parser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" +dependencies = [ + "anyhow", + "id-arena", + "indexmap", + "log", + "semver", + "serde", + "serde_derive", + "serde_json", + "unicode-xid", + "wasmparser", +] + +[[package]] +name = "writeable" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4" + +[[package]] +name = "yoke" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abe8c5fda708d9ca3df187cae8bfb9ceda00dd96231bed36e445a1a48e66f9ca" +dependencies = [ + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zerofrom" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69faa1f2a1ea75661980b013019ed6687ed0e83d069bc1114e2cc74c6c04c4df" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zeroize" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" + +[[package]] +name = "zerotrie" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f9152d31db0792fa83f70fb2f83148effb5c1f5b8c7686c3459e361d9bc20bf" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + +[[package]] +name = "zerovec" +version = "0.11.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90f911cbc359ab6af17377d242225f4d75119aec87ea711a880987b18cd7b239" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "zmij" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" diff --git a/native/agent-server-rust/Cargo.toml b/native/agent-server-rust/Cargo.toml new file mode 100644 index 0000000..906a25a --- /dev/null +++ b/native/agent-server-rust/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "agent-server-rust" +version = "0.1.0" +edition = "2021" +description = "MirrorNote local agent job daemon" + +[[bin]] +name = "MirrorNoteAgentServer" +path = "src/main.rs" + +[dependencies] +anyhow = "1" +chrono = { version = "0.4.44", default-features = false, features = ["clock", "std"] } +native-host-rust = { path = "../native-host-rust" } +serde = { version = "1", features = ["derive"] } +serde_json = "1" + +[dev-dependencies] +tempfile = "3" + +[profile.release] +opt-level = 2 +lto = true +strip = true diff --git a/native/agent-server-rust/src/main.rs b/native/agent-server-rust/src/main.rs new file mode 100644 index 0000000..e499969 --- /dev/null +++ b/native/agent-server-rust/src/main.rs @@ -0,0 +1,367 @@ +use anyhow::{Context, Result}; +use chrono::{SecondsFormat, Utc}; +use native_host_rust::context_packet::{context_packet_paths, generate_source_context}; +use native_host_rust::protocol::{SourceContextResult, SummaryProviderSettings}; +use serde::{Deserialize, Serialize}; +use std::fs; +use std::io::{BufRead, BufReader, Write}; +use std::net::{TcpListener, TcpStream}; +use std::path::{Path, PathBuf}; +use std::sync::{ + atomic::{AtomicBool, Ordering}, + Arc, +}; +use std::thread; +use std::time::Duration; + +const DEFAULT_AGENT_SERVER_PORT: u16 = 49731; +const AGENT_SERVER_PORT_ENV: &str = "MIRROR_NOTE_AGENT_SERVER_PORT"; +const JOB_DIRECTORY_NAME: &str = "agent-jobs"; +const GENERATE_CONTEXT_JOB_FILE_NAME: &str = "generate-context.json"; + +#[derive(Debug, Deserialize)] +#[serde(rename_all = "camelCase")] +struct AgentRequest { + id: String, + command: AgentCommand, + target_directory: Option, + summary_settings: Option, +} + +#[derive(Debug, Deserialize)] +#[serde(rename_all = "camelCase")] +enum AgentCommand { + Capabilities, + GenerateContext, + JobStatus, + Shutdown, +} + +#[derive(Debug, Serialize)] +struct AgentResponse { + #[serde(rename = "type")] + message_type: &'static str, + id: String, + ok: bool, + #[serde(skip_serializing_if = "Option::is_none")] + payload: Option, + #[serde(skip_serializing_if = "Option::is_none")] + error: Option, +} + +#[derive(Debug, Serialize)] +#[serde(rename_all = "camelCase")] +struct AgentPayload { + #[serde(skip_serializing_if = "Option::is_none")] + agent_version: Option<&'static str>, + #[serde(skip_serializing_if = "Option::is_none")] + job: Option, + #[serde(skip_serializing_if = "Option::is_none")] + source_context: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +struct JobStatus { + job_id: String, + command: String, + state: JobState, + target_directory: String, + queued_at: String, + updated_at: String, + #[serde(skip_serializing_if = "Option::is_none")] + started_at: Option, + #[serde(skip_serializing_if = "Option::is_none")] + completed_at: Option, + #[serde(skip_serializing_if = "Option::is_none")] + packet_id: Option, + #[serde(skip_serializing_if = "Option::is_none")] + object_count: Option, + #[serde(skip_serializing_if = "Option::is_none")] + relation_count: Option, + #[serde(skip_serializing_if = "Option::is_none")] + warning_count: Option, + #[serde(skip_serializing_if = "Option::is_none")] + error: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +enum JobState { + Queued, + Running, + Succeeded, + Failed, +} + +fn main() -> Result<()> { + let port = std::env::var(AGENT_SERVER_PORT_ENV) + .ok() + .and_then(|value| value.parse::().ok()) + .unwrap_or(DEFAULT_AGENT_SERVER_PORT); + run_server(port) +} + +fn run_server(port: u16) -> Result<()> { + let listener = TcpListener::bind(("127.0.0.1", port)) + .with_context(|| format!("MirrorNoteAgentServer could not bind 127.0.0.1:{port}"))?; + listener.set_nonblocking(true)?; + let running = Arc::new(AtomicBool::new(true)); + + while running.load(Ordering::SeqCst) { + match listener.accept() { + Ok((stream, _address)) => { + stream.set_nonblocking(false)?; + let running_for_client = Arc::clone(&running); + thread::spawn(move || { + if let Err(error) = handle_client(stream, running_for_client) { + eprintln!("{error:#}"); + } + }); + } + Err(error) if error.kind() == std::io::ErrorKind::WouldBlock => { + thread::sleep(Duration::from_millis(50)); + } + Err(error) => return Err(error.into()), + } + } + Ok(()) +} + +fn handle_client(mut stream: TcpStream, running: Arc) -> Result<()> { + let peer_reader = stream.try_clone()?; + let reader = BufReader::new(peer_reader); + for line in reader.lines() { + let line = line?; + if line.trim().is_empty() { + continue; + } + let response = match serde_json::from_str::(&line) { + Ok(request) => handle_request(request, &running), + Err(error) => failure_response( + "unknown".to_string(), + format!("MirrorNoteAgentServer could not decode the request: {error}"), + ), + }; + write_response(&mut stream, response)?; + } + Ok(()) +} + +fn handle_request(request: AgentRequest, running: &Arc) -> AgentResponse { + match request.command { + AgentCommand::Capabilities => success_response( + request.id, + Some(AgentPayload { + agent_version: Some(env!("CARGO_PKG_VERSION")), + job: None, + source_context: None, + }), + ), + AgentCommand::GenerateContext => match generate_context_job(&request) { + Ok((job, result)) => success_response( + request.id, + Some(AgentPayload { + agent_version: None, + job: Some(job), + source_context: Some(result), + }), + ), + Err(error) => failure_response(request.id, format!("{error:#}")), + }, + AgentCommand::JobStatus => match read_job_status_for_request(&request) { + Ok(job) => success_response( + request.id, + Some(AgentPayload { + agent_version: None, + job, + source_context: None, + }), + ), + Err(error) => failure_response(request.id, format!("{error:#}")), + }, + AgentCommand::Shutdown => { + running.store(false, Ordering::SeqCst); + success_response( + request.id, + Some(AgentPayload { + agent_version: Some(env!("CARGO_PKG_VERSION")), + job: None, + source_context: None, + }), + ) + } + } +} + +fn generate_context_job(request: &AgentRequest) -> Result<(JobStatus, SourceContextResult)> { + let target_directory = request + .target_directory + .as_deref() + .context("A target bundle directory is required.")?; + let summary_settings = request + .summary_settings + .as_ref() + .context("Summary provider settings are required.")?; + let bundle_directory = Path::new(target_directory); + let now = current_iso8601(); + let mut job = JobStatus { + job_id: format!("generate-context-{}", Utc::now().timestamp_millis()), + command: "generateContext".to_string(), + state: JobState::Queued, + target_directory: target_directory.to_string(), + queued_at: now.clone(), + updated_at: now, + started_at: None, + completed_at: None, + packet_id: None, + object_count: None, + relation_count: None, + warning_count: None, + error: None, + }; + write_job_status(bundle_directory, &job)?; + + job.state = JobState::Running; + job.started_at = Some(current_iso8601()); + job.updated_at = current_iso8601(); + write_job_status(bundle_directory, &job)?; + + match generate_source_context(bundle_directory, summary_settings) { + Ok(result) => { + job.state = JobState::Succeeded; + job.updated_at = current_iso8601(); + job.completed_at = Some(job.updated_at.clone()); + job.packet_id = Some(result.packet_id.clone()); + job.object_count = Some(result.object_count); + job.relation_count = Some(result.relation_count); + job.warning_count = Some(result.warning_count); + write_job_status(bundle_directory, &job)?; + Ok((job, result)) + } + Err(error) => { + job.state = JobState::Failed; + job.updated_at = current_iso8601(); + job.completed_at = Some(job.updated_at.clone()); + job.error = Some(format!("{error:#}")); + write_job_status(bundle_directory, &job)?; + Err(error) + } + } +} + +fn read_job_status_for_request(request: &AgentRequest) -> Result> { + let target_directory = request + .target_directory + .as_deref() + .context("A target bundle directory is required.")?; + read_job_status(Path::new(target_directory)) +} + +fn job_status_path(bundle_directory: &Path) -> PathBuf { + context_packet_paths(bundle_directory) + .context_directory + .join(JOB_DIRECTORY_NAME) + .join(GENERATE_CONTEXT_JOB_FILE_NAME) +} + +fn write_job_status(bundle_directory: &Path, job: &JobStatus) -> Result<()> { + let path = job_status_path(bundle_directory); + if let Some(parent) = path.parent() { + fs::create_dir_all(parent)?; + } + let bytes = serde_json::to_vec_pretty(job)?; + fs::write(path, bytes)?; + Ok(()) +} + +fn read_job_status(bundle_directory: &Path) -> Result> { + let path = job_status_path(bundle_directory); + if !path.exists() { + return Ok(None); + } + let bytes = fs::read(path)?; + let status = serde_json::from_slice(&bytes)?; + Ok(Some(status)) +} + +fn write_response(out: &mut impl Write, response: AgentResponse) -> Result<()> { + serde_json::to_writer(&mut *out, &response)?; + out.write_all(b"\n")?; + out.flush()?; + Ok(()) +} + +fn success_response(id: String, payload: Option) -> AgentResponse { + AgentResponse { + message_type: "response", + id, + ok: true, + payload, + error: None, + } +} + +fn failure_response(id: String, error: String) -> AgentResponse { + AgentResponse { + message_type: "response", + id, + ok: false, + payload: None, + error: Some(error), + } +} + +fn current_iso8601() -> String { + Utc::now().to_rfc3339_opts(SecondsFormat::Millis, true) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn persists_generate_context_job_status_under_bundle_context_directory() { + let temp = tempfile::tempdir().unwrap(); + let bundle = temp.path(); + let job = JobStatus { + job_id: "job-1".to_string(), + command: "generateContext".to_string(), + state: JobState::Running, + target_directory: bundle.to_string_lossy().into_owned(), + queued_at: "2026-05-04T00:00:00.000Z".to_string(), + updated_at: "2026-05-04T00:00:01.000Z".to_string(), + started_at: Some("2026-05-04T00:00:01.000Z".to_string()), + completed_at: None, + packet_id: None, + object_count: None, + relation_count: None, + warning_count: None, + error: None, + }; + + write_job_status(bundle, &job).unwrap(); + + let path = job_status_path(bundle); + assert_eq!( + path, + bundle + .join("context") + .join("agent-jobs") + .join("generate-context.json") + ); + let restored = read_job_status(bundle).unwrap().unwrap(); + assert_eq!(restored.job_id, "job-1"); + assert!(matches!(restored.state, JobState::Running)); + assert_eq!( + restored.started_at.as_deref(), + Some("2026-05-04T00:00:01.000Z") + ); + } + + #[test] + fn missing_job_status_restores_to_none() { + let temp = tempfile::tempdir().unwrap(); + assert!(read_job_status(temp.path()).unwrap().is_none()); + } +} diff --git a/native/native-host-rust/src/context_packet.rs b/native/native-host-rust/src/context_packet.rs index 6e55a58..9d76549 100644 --- a/native/native-host-rust/src/context_packet.rs +++ b/native/native-host-rust/src/context_packet.rs @@ -24,13 +24,18 @@ const SOURCE_RECORD_TYPES: &[&str] = &[ "metadata", "slack_thread", "slack_message", + "calendar_event", "github_pr", "github_issue", "github_commit", "github_comment", + "jira_issue", + "jira_comment", "linear_issue", "linear_comment", + "confluence_page", "doc", + "agent_session", "ai_session", ]; const MEMORY_OBJECT_TYPES: &[&str] = &[ diff --git a/package.json b/package.json index fa5ecdd..f0ad07e 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ }, "main": "apps/desktop/main.cjs", "scripts": { - "native:build": "cd native/native-host-rust && CARGO_TARGET_DIR=target cargo build --release 2>&1 && cd ../stt-server-rust && CARGO_TARGET_DIR=target cargo build --release 2>&1 && mkdir -p ../../.build/release-macos/Helpers && cp ../native-host-rust/target/release/MirrorNoteNativeHost ../../.build/release-macos/Helpers/MirrorNoteNativeHost && cp target/release/MirrorNoteSTTServer ../../.build/release-macos/Helpers/MirrorNoteSTTServer && cp models/silero-vad.onnx ../../.build/release-macos/Helpers/silero-vad.onnx && find target/release target/release/deps -maxdepth 1 -type f -name '*onnxruntime*.dylib' -exec cp {} ../../.build/release-macos/Helpers/ \\;", + "native:build": "cd native/native-host-rust && CARGO_TARGET_DIR=target cargo build --release 2>&1 && cd ../stt-server-rust && CARGO_TARGET_DIR=target cargo build --release 2>&1 && cd ../agent-server-rust && CARGO_TARGET_DIR=target cargo build --release 2>&1 && mkdir -p ../../.build/release-macos/Helpers && cp ../native-host-rust/target/release/MirrorNoteNativeHost ../../.build/release-macos/Helpers/MirrorNoteNativeHost && cp ../stt-server-rust/target/release/MirrorNoteSTTServer ../../.build/release-macos/Helpers/MirrorNoteSTTServer && cp target/release/MirrorNoteAgentServer ../../.build/release-macos/Helpers/MirrorNoteAgentServer && cp ../stt-server-rust/models/silero-vad.onnx ../../.build/release-macos/Helpers/silero-vad.onnx && find ../stt-server-rust/target/release ../stt-server-rust/target/release/deps -maxdepth 1 -type f -name '*onnxruntime*.dylib' -exec cp {} ../../.build/release-macos/Helpers/ \\;", "renderer:build": "vite build --config apps/desktop/vite.config.ts", "renderer:test": "vitest run --config apps/desktop/vite.config.ts", "renderer:check": "tsc --noEmit -p apps/desktop/tsconfig.json && npm run renderer:test && npm run renderer:build", @@ -97,7 +97,8 @@ "entitlementsInherit": "build/macos/entitlements.mac.inherit.plist", "binaries": [ "Contents/Resources/Helpers/MirrorNoteNativeHost", - "Contents/Resources/Helpers/MirrorNoteSTTServer" + "Contents/Resources/Helpers/MirrorNoteSTTServer", + "Contents/Resources/Helpers/MirrorNoteAgentServer" ], "target": [ { diff --git a/scripts/build_and_run.sh b/scripts/build_and_run.sh index 22fbec1..d6165de 100755 --- a/scripts/build_and_run.sh +++ b/scripts/build_and_run.sh @@ -6,6 +6,7 @@ MODE="${1:-run}" ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" RUST_NATIVE_HOST_PATH="$ROOT_DIR/native/native-host-rust/target/release/MirrorNoteNativeHost" RUST_STT_SERVER_PATH="$ROOT_DIR/native/stt-server-rust/target/release/MirrorNoteSTTServer" +RUST_AGENT_SERVER_PATH="$ROOT_DIR/native/agent-server-rust/target/release/MirrorNoteAgentServer" if [[ ! -f "$ROOT_DIR/package.json" ]]; then echo "error: package.json is missing." >&2 @@ -28,6 +29,7 @@ case "$MODE" in npm run native:build test -x "$RUST_NATIVE_HOST_PATH" test -x "$RUST_STT_SERVER_PATH" + test -x "$RUST_AGENT_SERVER_PATH" ;; *) echo "usage: $0 [run|--verify|verify]" >&2 diff --git a/scripts/prepare_macos_release.sh b/scripts/prepare_macos_release.sh index cebc1dc..a0527d3 100755 --- a/scripts/prepare_macos_release.sh +++ b/scripts/prepare_macos_release.sh @@ -13,6 +13,7 @@ SILERO_VAD_MODEL_SOURCE="$ROOT_DIR/native/stt-server-rust/models/silero-vad.onnx SILERO_VAD_MODEL_NAME="silero-vad.onnx" RUST_NATIVE_HOST_PATH="$ROOT_DIR/native/native-host-rust/target/release/MirrorNoteNativeHost" RUST_STT_SERVER_PATH="$ROOT_DIR/native/stt-server-rust/target/release/MirrorNoteSTTServer" +RUST_AGENT_SERVER_PATH="$ROOT_DIR/native/agent-server-rust/target/release/MirrorNoteAgentServer" ensure_silero_vad_model() { if [[ -f "$SILERO_VAD_MODEL_SOURCE" ]]; then @@ -61,8 +62,9 @@ stage_release_payload() { cp "$RUST_NATIVE_HOST_PATH" "$HELPERS_DIR/MirrorNoteNativeHost" cp "$RUST_STT_SERVER_PATH" "$HELPERS_DIR/MirrorNoteSTTServer" + cp "$RUST_AGENT_SERVER_PATH" "$HELPERS_DIR/MirrorNoteAgentServer" stage_whisper_runtime - chmod +x "$HELPERS_DIR/MirrorNoteNativeHost" "$HELPERS_DIR/MirrorNoteSTTServer" + chmod +x "$HELPERS_DIR/MirrorNoteNativeHost" "$HELPERS_DIR/MirrorNoteSTTServer" "$HELPERS_DIR/MirrorNoteAgentServer" } cd "$ROOT_DIR" diff --git a/scripts/smoke_notes_store.cjs b/scripts/smoke_notes_store.cjs index 23337e0..9c118a5 100644 --- a/scripts/smoke_notes_store.cjs +++ b/scripts/smoke_notes_store.cjs @@ -180,10 +180,10 @@ async function main() { assert.equal(switchedProviderSummary.provider, "ollama"); assert.equal(switchedProviderSummary.defaultTemplateId, "technical-review"); - const originalNativeCaptureRequest = notesStore.__testHooks.nativeCaptureRequest; + const originalAgentServerRequest = notesStore.__testHooks.agentServerRequest; try { - notesStore.__testHooks.nativeCaptureRequest = async (command, payload) => { - assert.equal(command, "generateSourceContext"); + notesStore.__testHooks.agentServerRequest = async (command, payload) => { + assert.equal(command, "generateContext"); assert.equal(payload.targetDirectory, created.directoryPath); assert.equal(payload.summarySettings.provider, "openai"); assert.equal(payload.summarySettings.model, "gpt-4o-mini"); @@ -227,7 +227,7 @@ async function main() { /Use source-neutral context packets/, ); } finally { - notesStore.__testHooks.nativeCaptureRequest = originalNativeCaptureRequest; + notesStore.__testHooks.agentServerRequest = originalAgentServerRequest; } const blockedContextNote = await notesStore.createNote("No Transcript Context"); @@ -271,7 +271,7 @@ async function main() { }, ]); try { - notesStore.__testHooks.nativeCaptureRequest = async () => { + notesStore.__testHooks.agentServerRequest = async () => { throw new Error("Add an OpenAI API key in Settings before generating source context."); }; await assert.rejects( @@ -283,7 +283,7 @@ async function main() { assert.equal(providerMissingDetail.sourceContextStatus.retryable, true); assert.match(providerMissingDetail.sourceContextStatus.detail, /OpenAI API key/); } finally { - notesStore.__testHooks.nativeCaptureRequest = originalNativeCaptureRequest; + notesStore.__testHooks.agentServerRequest = originalAgentServerRequest; } assert.equal(await notesStore.deleteNote(providerMissingNote.id), true); From 8c96de3e201da68149842f73ed409912ef2e22a5 Mon Sep 17 00:00:00 2001 From: qyinm Date: Tue, 5 May 2026 15:57:06 +0900 Subject: [PATCH 2/4] fix: avoid retrying timed-out agent jobs --- apps/desktop/main.cjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/desktop/main.cjs b/apps/desktop/main.cjs index b76a252..ff21228 100644 --- a/apps/desktop/main.cjs +++ b/apps/desktop/main.cjs @@ -3924,7 +3924,7 @@ class AgentServerBridge { } isConnectionError(error) { - return ["ECONNREFUSED", "ECONNRESET", "EPIPE", "ETIMEDOUT"].includes(error?.code); + return ["ECONNREFUSED", "ECONNRESET", "EPIPE"].includes(error?.code); } async ensureStarted() { From 987a45ba60d912777bbdcfd939ea53c10bf7fcd7 Mon Sep 17 00:00:00 2001 From: qyinm Date: Tue, 5 May 2026 15:57:25 +0900 Subject: [PATCH 3/4] refactor: simplify agent job count parsing --- apps/desktop/main.cjs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/desktop/main.cjs b/apps/desktop/main.cjs index ff21228..6f9aa6d 100644 --- a/apps/desktop/main.cjs +++ b/apps/desktop/main.cjs @@ -1479,9 +1479,9 @@ function sourceContextStatusFromAgentJob(directoryPath) { retryable: false, updatedAt: optionalNonEmptyString(job.updatedAt), packetId: optionalNonEmptyString(job.packetId), - objectCount: Number.isFinite(Number(job.objectCount)) ? Number(job.objectCount) : 0, - relationCount: Number.isFinite(Number(job.relationCount)) ? Number(job.relationCount) : 0, - warningCount: Number.isFinite(Number(job.warningCount)) ? Number(job.warningCount) : 0, + objectCount: parseInt(job.objectCount, 10) || 0, + relationCount: parseInt(job.relationCount, 10) || 0, + warningCount: parseInt(job.warningCount, 10) || 0, agentBriefPath: null, projectContextPath: null, contextDirectoryPath: null, From 2a0e66349ca3385edc3049eb31fcd3546a6c2c21 Mon Sep 17 00:00:00 2001 From: qyinm Date: Tue, 5 May 2026 15:59:11 +0900 Subject: [PATCH 4/4] chore: move native build into script --- package.json | 2 +- scripts/build_native.sh | 26 ++++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) create mode 100755 scripts/build_native.sh diff --git a/package.json b/package.json index f0ad07e..84b22af 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ }, "main": "apps/desktop/main.cjs", "scripts": { - "native:build": "cd native/native-host-rust && CARGO_TARGET_DIR=target cargo build --release 2>&1 && cd ../stt-server-rust && CARGO_TARGET_DIR=target cargo build --release 2>&1 && cd ../agent-server-rust && CARGO_TARGET_DIR=target cargo build --release 2>&1 && mkdir -p ../../.build/release-macos/Helpers && cp ../native-host-rust/target/release/MirrorNoteNativeHost ../../.build/release-macos/Helpers/MirrorNoteNativeHost && cp ../stt-server-rust/target/release/MirrorNoteSTTServer ../../.build/release-macos/Helpers/MirrorNoteSTTServer && cp target/release/MirrorNoteAgentServer ../../.build/release-macos/Helpers/MirrorNoteAgentServer && cp ../stt-server-rust/models/silero-vad.onnx ../../.build/release-macos/Helpers/silero-vad.onnx && find ../stt-server-rust/target/release ../stt-server-rust/target/release/deps -maxdepth 1 -type f -name '*onnxruntime*.dylib' -exec cp {} ../../.build/release-macos/Helpers/ \\;", + "native:build": "./scripts/build_native.sh", "renderer:build": "vite build --config apps/desktop/vite.config.ts", "renderer:test": "vitest run --config apps/desktop/vite.config.ts", "renderer:check": "tsc --noEmit -p apps/desktop/tsconfig.json && npm run renderer:test && npm run renderer:build", diff --git a/scripts/build_native.sh b/scripts/build_native.sh new file mode 100755 index 0000000..79516b2 --- /dev/null +++ b/scripts/build_native.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +HELPERS_DIR="$ROOT_DIR/.build/release-macos/Helpers" + +cd "$ROOT_DIR/native/native-host-rust" +CARGO_TARGET_DIR=target cargo build --release 2>&1 + +cd "$ROOT_DIR/native/stt-server-rust" +CARGO_TARGET_DIR=target cargo build --release 2>&1 + +cd "$ROOT_DIR/native/agent-server-rust" +CARGO_TARGET_DIR=target cargo build --release 2>&1 + +mkdir -p "$HELPERS_DIR" +cp "$ROOT_DIR/native/native-host-rust/target/release/MirrorNoteNativeHost" "$HELPERS_DIR/MirrorNoteNativeHost" +cp "$ROOT_DIR/native/stt-server-rust/target/release/MirrorNoteSTTServer" "$HELPERS_DIR/MirrorNoteSTTServer" +cp "$ROOT_DIR/native/agent-server-rust/target/release/MirrorNoteAgentServer" "$HELPERS_DIR/MirrorNoteAgentServer" +cp "$ROOT_DIR/native/stt-server-rust/models/silero-vad.onnx" "$HELPERS_DIR/silero-vad.onnx" + +find "$ROOT_DIR/native/stt-server-rust/target/release" "$ROOT_DIR/native/stt-server-rust/target/release/deps" \ + -maxdepth 1 \ + -type f \ + -name '*onnxruntime*.dylib' \ + -exec cp {} "$HELPERS_DIR/" \;