diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6412501..64b3ef5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -27,6 +27,10 @@ jobs: uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2 with: bun-version: 1.3.14 + - name: Set up pinned pnpm + uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6.0.9 + with: + version: 10.33.0 - name: Build and validate plugins run: make test @@ -76,6 +80,46 @@ jobs: node -e 'import(process.argv[1]).then((m) => { if (typeof m.default !== "function") process.exit(1) })' \ "$PWD/install-test/node_modules/@braintrust/trace-opencode/dist/index.js" + resolve-pi-compatibility: + name: Resolve Pi compatibility window + runs-on: ubuntu-24.04 + timeout-minutes: 10 + outputs: + versions: ${{ steps.versions.outputs.versions }} + steps: + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 + - id: versions + name: Resolve latest patch from five Pi minor lines + env: + PI_VERSION_COUNT: 5 + run: node src/plugins/pi/content/scripts/resolve-pi-versions.mjs + + pi-compatibility: + name: Pi package (${{ matrix.pi-target.version }}) + needs: resolve-pi-compatibility + strategy: + fail-fast: false + matrix: + pi-target: ${{ fromJson(needs.resolve-pi-compatibility.outputs.versions) }} + runs-on: ubuntu-24.04 + timeout-minutes: 20 + steps: + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 + - name: Set up pinned pnpm + uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6.0.9 + with: + version: 10.33.0 + - name: Build validated Pi tarball + run: make validate-pi + - name: Test resolved Pi compatibility target + run: | + mkdir pi-install-test + pnpm --dir pi-install-test add --lockfile=false \ + "$PWD"/dist/pi/braintrust-pi-extension-*.tgz \ + '${{ matrix.pi-target.piCodingAgentSpec }}' + node -e 'import(process.argv[1]).then((m) => { if (typeof m.default !== "function") process.exit(1) })' \ + "$PWD/pi-install-test/node_modules/@braintrust/pi-extension/dist/index.mjs" + daemon: name: Daemon (${{ matrix.os }}) strategy: @@ -98,18 +142,27 @@ jobs: rustup default stable rustup component add clippy rustfmt - name: Install latest coding agents - run: npm install --prefix "${{ runner.temp }}/coding-agents" --no-save --no-package-lock --no-audit --no-fund --cache "${{ runner.temp }}/npm-cache" @openai/codex@latest @anthropic-ai/claude-code@latest opencode-ai@latest + run: npm install --prefix "${{ runner.temp }}/coding-agents" --no-save --no-package-lock --no-audit --no-fund --cache "${{ runner.temp }}/npm-cache" @openai/codex@latest @anthropic-ai/claude-code@latest opencode-ai@latest @earendil-works/pi-coding-agent@latest - name: Set up pinned Bun uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2 with: bun-version: 1.3.14 + - name: Set up pinned pnpm + uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6.0.9 + with: + version: 10.33.0 - name: Build OpenCode plugin for integration harness run: make build-opencode + - name: Build Pi extension for integration harness + run: make build-pi + - name: Install built Pi extension for integration harness + run: npm install --prefix "${{ runner.temp }}/pi-extension" --no-save --no-package-lock --no-audit --no-fund ./dist/pi/braintrust-pi-extension-*.tgz - name: Report coding-agent versions run: | npm exec --prefix "${{ runner.temp }}/coding-agents" -- codex --version npm exec --prefix "${{ runner.temp }}/coding-agents" -- claude --version npm exec --prefix "${{ runner.temp }}/coding-agents" -- opencode --version + npm exec --prefix "${{ runner.temp }}/coding-agents" -- pi --version - name: Check formatting if: runner.os == 'Linux' run: cargo fmt --manifest-path bt-daemon/Cargo.toml -- --check @@ -124,6 +177,8 @@ jobs: CODEX_BIN: ${{ runner.temp }}/coding-agents/node_modules/.bin/codex${{ matrix.agent_suffix }} CLAUDE_BIN: ${{ runner.temp }}/coding-agents/node_modules/.bin/claude${{ matrix.agent_suffix }} OPENCODE_BIN: ${{ runner.temp }}/coding-agents/node_modules/.bin/opencode${{ matrix.agent_suffix }} + PI_BIN: ${{ runner.temp }}/coding-agents/node_modules/.bin/pi${{ matrix.agent_suffix }} + PI_EXTENSION_PATH: ${{ runner.temp }}/pi-extension/node_modules/@braintrust/pi-extension/dist/index.mjs run: cargo test --manifest-path bt-daemon/Cargo.toml --all-features --locked --test agent_integration -- --ignored --nocapture --test-threads=1 - name: Lint daemon run: cargo clippy --manifest-path bt-daemon/Cargo.toml --all-targets --all-features --locked -- -D warnings diff --git a/README.md b/README.md index 0ac7496..aecd10e 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,7 @@ For further instructions, see the instructions for your desired coding agent | Claude Code | [braintrustdata/braintrust-claude-plugin](https://github.com/braintrustdata/braintrust-claude-plugin) | | Codex | [braintrustdata/braintrust-codex-plugin](https://github.com/braintrustdata/braintrust-codex-plugin) | | OpenCode | npm: [`@braintrust/trace-opencode`](https://www.npmjs.com/package/@braintrust/trace-opencode) | +| Pi | npm: [`@braintrust/pi-extension`](https://www.npmjs.com/package/@braintrust/pi-extension) | ## Development & releasing diff --git a/bt-daemon/docs/protocol.md b/bt-daemon/docs/protocol.md index 4ed3065..ab96622 100644 --- a/bt-daemon/docs/protocol.md +++ b/bt-daemon/docs/protocol.md @@ -92,7 +92,7 @@ Result: { "protocol_version": 1, "daemon_version": "0.1.0", - "capabilities": { "sources": ["codex", "claude-code", "opencode", "debug"] } + "capabilities": { "sources": ["codex", "claude-code", "opencode", "pi", "debug"] } } ``` If `protocol_version` is incompatible the daemon returns an application error; diff --git a/bt-daemon/src/translate/mod.rs b/bt-daemon/src/translate/mod.rs index 92d978e..d182161 100644 --- a/bt-daemon/src/translate/mod.rs +++ b/bt-daemon/src/translate/mod.rs @@ -12,11 +12,13 @@ mod codex; mod debug; mod git; mod opencode; +mod pi; pub use claude::ClaudeTranslatorFactory; pub use codex::CodexTranslatorFactory; pub use debug::DebugTranslatorFactory; pub use opencode::OpenCodeTranslatorFactory; +pub use pi::PiTranslatorFactory; use crate::wire::{Envelope, SessionConfig}; use serde::{Deserialize, Serialize}; @@ -125,7 +127,8 @@ impl Registry { let git = Arc::new(git::GitMetadataCache::default()); r.register(Box::new(ClaudeTranslatorFactory::new(git.clone()))); r.register(Box::new(CodexTranslatorFactory::new(git.clone()))); - r.register(Box::new(OpenCodeTranslatorFactory::new(git))); + r.register(Box::new(OpenCodeTranslatorFactory::new(git.clone()))); + r.register(Box::new(PiTranslatorFactory::new(git))); r } diff --git a/bt-daemon/src/translate/pi.rs b/bt-daemon/src/translate/pi.rs new file mode 100644 index 0000000..e7946aa --- /dev/null +++ b/bt-daemon/src/translate/pi.rs @@ -0,0 +1,543 @@ +//! Pi coding-agent translator. Pi forwards native extension callbacks and this +//! state machine owns all span construction and recovery. + +use super::git::GitMetadataCache; +use super::{AgentTranslator, SessionCtx, SpanOp, SpanRow, SpanType, TranslatorFactory}; +use crate::ids; +use crate::wire::Envelope; +use serde_json::{json, Map, Value}; +use std::collections::HashMap; +use std::sync::Arc; + +pub struct PiTranslatorFactory { + git: Arc, +} +impl PiTranslatorFactory { + pub(super) fn new(git: Arc) -> Self { + Self { git } + } +} +impl TranslatorFactory for PiTranslatorFactory { + fn source(&self) -> &str { + "pi" + } + fn create(&self, session_id: &str) -> Box { + Box::new(PiTranslator { + session_id: session_id.into(), + root_span_id: ids::span_id(session_id, "root"), + effective_root_span_id: String::new(), + external_parent: None, + opened: false, + turn: None, + turn_seq: 0, + llm_seq: 0, + total_tools: 0, + pending_llms: Vec::new(), + tools: HashMap::new(), + compaction: None, + branch_summary: None, + last_ts: 0, + thinking_level: None, + git: self.git.clone(), + }) + } +} + +struct PendingLlm { + start_ms: i64, + input: Value, + first_token_ms: Option, + provider: Option, +} +struct ToolStart { + start_ms: i64, + name: String, + args: Value, +} +struct PiTranslator { + session_id: String, + root_span_id: String, + effective_root_span_id: String, + external_parent: Option, + opened: bool, + turn: Option<(String, Value)>, + turn_seq: u32, + llm_seq: u32, + total_tools: u32, + pending_llms: Vec, + tools: HashMap, + compaction: Option<(String, i64, Value)>, + branch_summary: Option<(String, i64, Value)>, + last_ts: i64, + thinking_level: Option, + git: Arc, +} + +impl AgentTranslator for PiTranslator { + fn handle(&mut self, envelope: &Envelope, ctx: &SessionCtx) -> anyhow::Result> { + self.last_ts = self.last_ts.max(envelope.ts_ms); + let event = envelope.payload.get("event").unwrap_or(&envelope.payload); + let mut ops = self.ensure_root(envelope, ctx); + match envelope.event.as_str() { + "before_agent_start" => ops.extend(self.start_turn(event, envelope.ts_ms)), + "context" => self.capture_context(event, envelope.ts_ms), + "before_provider_request" => self.provider_request(event), + "message_update" => self.streaming_update(event, envelope.ts_ms), + "thinking_level_select" => { + self.thinking_level = event + .get("level") + .and_then(Value::as_str) + .map(str::to_owned) + } + "message_end" => ops.extend(self.message_end(event, envelope.ts_ms)), + "tool_execution_start" => self.tool_start(event, envelope.ts_ms), + "tool_execution_end" => ops.extend(self.tool_end(event, envelope.ts_ms)), + "agent_end" if event.get("willRetry").and_then(Value::as_bool) != Some(true) => { + ops.extend(self.close_turn(envelope.ts_ms, None)); + } + "session_before_compact" => { + self.compaction = Some(( + ids::span_id(&self.session_id, &format!("compaction:{}", envelope.ts_ms)), + envelope.ts_ms, + event.clone(), + )) + } + "session_compact" => { + ops.extend(self.finish_special("Compaction", true, event, envelope.ts_ms)) + } + "session_before_tree" + if event + .pointer("/preparation/userWantsSummary") + .and_then(Value::as_bool) + == Some(true) => + { + self.branch_summary = Some(( + ids::span_id( + &self.session_id, + &format!("branch-summary:{}", envelope.ts_ms), + ), + envelope.ts_ms, + event.clone(), + )) + } + "session_tree" + if event.get("summaryEntry").is_some() || self.branch_summary.is_some() => + { + ops.extend(self.finish_special("Branch Summary", false, event, envelope.ts_ms)) + } + "session_shutdown" => { + ops.extend(self.close_turn(envelope.ts_ms, None)); + ops.push(self.close_root(envelope.ts_ms)); + } + _ => {} + } + let cwd = envelope.payload.get("cwd").and_then(Value::as_str); + self.git.enrich_rows(cwd, &mut ops); + Ok(ops) + } + + fn flush(&mut self, _ctx: &SessionCtx) -> anyhow::Result> { + let mut ops = self.close_turn(self.last_ts, Some("Interrupted before completion".into())); + if self.opened { + ops.push(self.close_root(self.last_ts)); + } + Ok(ops) + } +} + +impl PiTranslator { + fn ensure_root(&mut self, envelope: &Envelope, ctx: &SessionCtx) -> Vec { + if self.opened { + return Vec::new(); + } + self.opened = true; + let attached = ctx + .config + .as_ref() + .map(|c| c.attached_span_ids()) + .unwrap_or_default(); + let settings = envelope.payload.get("trace_settings"); + self.external_parent = attached.0.or_else(|| { + settings + .and_then(|value| value.get("parent_span_id")) + .and_then(Value::as_str) + .map(str::to_owned) + }); + self.effective_root_span_id = attached + .1 + .or_else(|| { + settings + .and_then(|value| value.get("root_span_id")) + .and_then(Value::as_str) + .map(str::to_owned) + }) + .or_else(|| self.external_parent.clone()) + .unwrap_or_else(|| self.root_span_id.clone()); + let mut metadata = Map::new(); + metadata.insert("session_id".into(), json!(self.session_id)); + metadata.insert("source".into(), json!("pi")); + metadata.insert("pi_version".into(), json!(envelope.source_version)); + metadata.insert( + "extension_version".into(), + envelope + .payload + .get("extension_version") + .cloned() + .unwrap_or(Value::Null), + ); + metadata.insert( + "native_session_id".into(), + envelope + .payload + .get("native_session_id") + .cloned() + .unwrap_or(Value::Null), + ); + metadata.insert( + "session_file".into(), + envelope + .payload + .get("session_file") + .cloned() + .unwrap_or(Value::Null), + ); + if let Some(extra) = ctx + .config + .as_ref() + .and_then(|c| c.additional_metadata.as_ref()) + .and_then(Value::as_object) + { + metadata.extend(extra.clone()); + } + if let Some(extra) = settings + .and_then(|value| value.get("additional_metadata")) + .and_then(Value::as_object) + { + metadata.extend(extra.clone()); + } + vec![SpanOp::Insert(SpanRow { + span_id: self.root_span_id.clone(), + root_span_id: self.effective_root_span_id.clone(), + parent_span_ids: self.external_parent.clone().into_iter().collect(), + name: "Pi".into(), + span_type: SpanType::Task, + start_ms: Some(envelope.ts_ms), + metadata: Some(Value::Object(metadata)), + ..Default::default() + })] + } + + fn start_turn(&mut self, event: &Value, ts: i64) -> Vec { + let mut ops = self.close_turn(ts, None); + self.turn_seq += 1; + self.llm_seq = 0; + self.pending_llms.clear(); + self.tools.clear(); + let id = ids::span_id(&self.session_id, &format!("turn:{}", self.turn_seq)); + let input = event.get("prompt").cloned().unwrap_or(Value::Null); + let skills = event + .get("prompt") + .and_then(Value::as_str) + .map(explicit_skills) + .unwrap_or_default(); + self.turn = Some((id.clone(), input.clone())); + ops.push(SpanOp::Insert(SpanRow{span_id:id,root_span_id:self.effective_root_span_id.clone(),parent_span_ids:vec![self.root_span_id.clone()],name:format!("Turn {}",self.turn_seq),span_type:SpanType::Task,start_ms:Some(ts),input:Some(input),metadata:Some(json!({"turn_number":self.turn_seq,"loaded_skill_names":skills,"thinking_level":self.thinking_level})),..Default::default()})); + ops + } + fn capture_context(&mut self, event: &Value, ts: i64) { + let input = event.get("messages").cloned().unwrap_or_else(|| json!([])); + self.pending_llms.push(PendingLlm { + start_ms: ts, + input, + first_token_ms: None, + provider: None, + }); + } + fn provider_request(&mut self, event: &Value) { + if let Some(call) = self.pending_llms.last_mut() { + call.provider = Some(event.clone()) + } + } + fn streaming_update(&mut self, event: &Value, ts: i64) { + if let Some(call) = self.pending_llms.last_mut() { + let kind = event + .pointer("/assistantMessageEvent/type") + .or_else(|| event.get("type")) + .and_then(Value::as_str) + .unwrap_or(""); + if matches!(kind, "text_delta" | "thinking_delta" | "text" | "thinking") + && call.first_token_ms.is_none() + { + call.first_token_ms = Some(ts) + } + } + } + fn message_end(&mut self, event: &Value, ts: i64) -> Vec { + let message = event.get("message").unwrap_or(event); + if message.get("role").and_then(Value::as_str) != Some("assistant") { + return vec![]; + }; + let Some((turn, _)) = &self.turn else { + return vec![]; + }; + self.llm_seq += 1; + let pending = if self.pending_llms.is_empty() { + PendingLlm { + start_ms: ts, + input: json!([]), + first_token_ms: None, + provider: None, + } + } else { + self.pending_llms.remove(0) + }; + let model = response_model(message); + let usage = message.get("usage").cloned().unwrap_or_else(|| json!({})); + let prompt = num(&usage, "input") + + num(&usage, "cacheRead") + + num(&usage, "cacheWrite") + + num(&usage, "cacheWrite1h"); + let completion = num(&usage, "output"); + let reasoning = num(&usage, "reasoning"); + let total = usage + .get("totalTokens") + .and_then(Value::as_i64) + .unwrap_or(prompt + completion + reasoning); + let output = normalize_assistant(message); + let error = message + .get("errorMessage") + .and_then(Value::as_str) + .map(str::to_owned) + .filter(|_| { + matches!( + message.get("stopReason").and_then(Value::as_str), + Some("error" | "aborted") + ) + }); + let ttft = pending + .first_token_ms + .map(|first| (first - pending.start_ms) as f64 / 1000.0); + vec![SpanOp::Insert(SpanRow { + span_id: ids::span_id( + &self.session_id, + &format!("llm:{}:{}", self.turn_seq, self.llm_seq), + ), + root_span_id: self.effective_root_span_id.clone(), + parent_span_ids: vec![turn.clone()], + name: model.clone().unwrap_or_else(|| "llm".into()), + span_type: SpanType::Llm, + start_ms: Some(pending.start_ms), + end_ms: Some(ts), + input: Some(pending.input), + output: Some(json!([output])), + metadata: Some( + json!({"model":model,"provider":message.get("provider"),"api":message.get("api"),"stop_reason":message.get("stopReason"),"thinking_level":self.thinking_level,"provider_request":pending.provider,"response_id":message.get("responseId")}), + ), + metrics: Some( + json!({"prompt_tokens":prompt,"completion_tokens":completion,"reasoning_tokens":reasoning,"tokens":total,"prompt_cached_tokens":num(&usage,"cacheRead"),"prompt_cache_creation_tokens":num(&usage,"cacheWrite")+num(&usage,"cacheWrite1h"),"time_to_first_token":ttft,"cost":usage.get("cost")}), + ), + error, + ..Default::default() + })] + } + fn tool_start(&mut self, event: &Value, ts: i64) { + let Some(id) = event.get("toolCallId").and_then(Value::as_str) else { + return; + }; + self.tools.insert( + id.into(), + ToolStart { + start_ms: ts, + name: event + .get("toolName") + .and_then(Value::as_str) + .unwrap_or("tool") + .into(), + args: event.get("args").cloned().unwrap_or(Value::Null), + }, + ); + } + fn tool_end(&mut self, event: &Value, ts: i64) -> Vec { + let Some((turn, _)) = &self.turn else { + return vec![]; + }; + let call = event + .get("toolCallId") + .and_then(Value::as_str) + .unwrap_or(""); + let tracked = self.tools.remove(call).unwrap_or(ToolStart { + start_ms: ts, + name: event + .get("toolName") + .and_then(Value::as_str) + .unwrap_or("tool") + .into(), + args: Value::Null, + }); + self.total_tools += 1; + let failed = event.get("isError").and_then(Value::as_bool) == Some(true); + let skill = skill_from_read(&tracked.name, &tracked.args); + let name = skill + .as_ref() + .map(|s| format!("skill: {s}")) + .unwrap_or_else(|| tracked.name.clone()); + vec![SpanOp::Insert(SpanRow { + span_id: ids::span_id(&self.session_id, &format!("tool:{}:{call}", self.turn_seq)), + root_span_id: self.effective_root_span_id.clone(), + parent_span_ids: vec![turn.clone()], + name, + span_type: SpanType::Tool, + start_ms: Some(tracked.start_ms), + end_ms: Some(ts), + input: Some(tracked.args), + output: event.get("result").cloned(), + metadata: Some( + json!({"tool_name":if skill.is_some(){"skill"}else{&tracked.name},"original_tool_name":tracked.name,"tool_call_id":call,"tool_approval":"approved","tool_outcome":if failed{"error"}else{"success"},"skill_name":skill}), + ), + error: failed.then(|| format_error(event.get("result"))), + ..Default::default() + })] + } + fn finish_special( + &mut self, + name: &str, + compaction: bool, + event: &Value, + ts: i64, + ) -> Vec { + let active = if compaction { + self.compaction.take() + } else { + self.branch_summary.take() + }; + let (id, start, input) = active.unwrap_or_else(|| { + ( + ids::span_id(&self.session_id, &format!("special:{name}:{ts}")), + ts, + Value::Null, + ) + }); + vec![SpanOp::Insert(SpanRow { + span_id: id, + root_span_id: self.effective_root_span_id.clone(), + parent_span_ids: vec![self.root_span_id.clone()], + name: name.into(), + span_type: SpanType::Task, + start_ms: Some(start), + end_ms: Some(ts), + input: Some(input), + output: Some(event.clone()), + metadata: Some( + json!({"event_type":if compaction{"session_compact"}else{"session_tree"}}), + ), + tags: Some(vec![if compaction { + "compaction".into() + } else { + "branch-summary".into() + }]), + ..Default::default() + })] + } + fn close_turn(&mut self, ts: i64, error: Option) -> Vec { + let Some((id, _)) = self.turn.take() else { + return vec![]; + }; + vec![SpanOp::Merge(SpanRow { + span_id: id, + root_span_id: self.effective_root_span_id.clone(), + end_ms: Some(ts), + error, + ..Default::default() + })] + } + fn close_root(&mut self, ts: i64) -> SpanOp { + self.opened = false; + SpanOp::Merge(SpanRow { + span_id: self.root_span_id.clone(), + root_span_id: self.effective_root_span_id.clone(), + end_ms: Some(ts), + metadata: Some( + json!({"total_turns":self.turn_seq,"total_tool_calls":self.total_tools}), + ), + ..Default::default() + }) + } +} + +fn num(v: &Value, key: &str) -> i64 { + v.get(key).and_then(Value::as_i64).unwrap_or(0) +} +fn response_model(v: &Value) -> Option { + for key in [ + "responseModel", + "routedModel", + "resolvedModel", + "actualModel", + "concreteModel", + "outputModel", + "model", + ] { + if let Some(s) = v.get(key).and_then(Value::as_str) { + return Some(s.into()); + } + } + None +} +fn normalize_assistant(v: &Value) -> Value { + let mut text = String::new(); + let mut reasoning = String::new(); + let mut calls = Vec::new(); + for part in v + .get("content") + .and_then(Value::as_array) + .into_iter() + .flatten() + { + match part.get("type").and_then(Value::as_str){Some("text")=>if let Some(s)=part.get("text").and_then(Value::as_str){text.push_str(s)},Some("thinking")=>if let Some(s)=part.get("thinking").and_then(Value::as_str){reasoning.push_str(s)},Some("toolCall")=>calls.push(json!({"id":part.get("id"),"type":"function","function":{"name":part.get("name"),"arguments":serde_json::to_string(part.get("arguments").unwrap_or(&Value::Null)).unwrap_or_default()}})),_=>{}} + } + let mut out = json!({"role":"assistant","content":text}); + if !reasoning.is_empty() { + out["reasoning"] = json!([{"id":"reasoning","content":reasoning}]) + } + if !calls.is_empty() { + out["tool_calls"] = Value::Array(calls) + } + out +} +fn skill_from_read(tool: &str, args: &Value) -> Option { + if tool != "read" { + return None; + } + let path = args + .get("path") + .or_else(|| args.get("filePath")) + .or_else(|| args.get("file_path")) + .and_then(Value::as_str)?; + if !path.to_ascii_lowercase().ends_with("/skill.md") { + return None; + } + path.rsplit('/').nth(1).map(str::to_owned) +} +fn explicit_skills(input: &str) -> Vec { + input + .split_whitespace() + .filter_map(|s| s.strip_prefix("/skill:")) + .map(|s| { + s.trim_matches(|c: char| matches!(c, ',' | ')' | '.' | ';')) + .to_string() + }) + .filter(|s| !s.is_empty()) + .collect() +} +fn format_error(v: Option<&Value>) -> String { + match v { + Some(Value::String(s)) => s.lines().next().unwrap_or(s).into(), + Some(v) => v + .get("error") + .or_else(|| v.get("message")) + .and_then(Value::as_str) + .unwrap_or("Tool execution failed") + .into(), + None => "Tool execution failed".into(), + } +} diff --git a/bt-daemon/tests/agent_integration.rs b/bt-daemon/tests/agent_integration.rs index 5329ffa..1634713 100644 --- a/bt-daemon/tests/agent_integration.rs +++ b/bt-daemon/tests/agent_integration.rs @@ -3,7 +3,9 @@ mod support; use axum::http::StatusCode; use serde_json::{json, Value}; use support::agent_process::AgentTestWorld; -use support::agents::{ClaudeAgent, ClaudeRun, CodexAgent, CodexRun, OpenCodeAgent, OpenCodeRun}; +use support::agents::{ + ClaudeAgent, ClaudeRun, CodexAgent, CodexRun, OpenCodeAgent, OpenCodeRun, PiAgent, PiRun, +}; use support::inference::{ AnthropicMock, AnthropicRequest, AnthropicTurn, MockReply, OpenAiMock, OpenAiRequest, OpenAiTurn, @@ -276,6 +278,40 @@ async fn opencode_session_emits_traces() { } } +#[tokio::test(flavor = "multi_thread", worker_threads = 4)] +#[ignore = "requires the Pi CLI and built extension"] +async fn pi_session_emits_traces() { + let inference = OpenAiMock::new(|_context, request| { + assert!(request.model().is_some()); + MockReply::response(OpenAiTurn::text("PI_MOCK_OK")) + }); + let inference_server = TestServer::start(inference.router()).await; + let world = AgentTestWorld::start().await; + let pi = PiAgent::new(&world); + + let output = pi + .run( + &world, + PiRun::new("Reply with the exact text PI_MOCK_OK.") + .mock_inference(inference_server.uri()), + ) + .await; + output.assert_success(); + if world.uses_mock_inference() { + output.assert_contains("PI_MOCK_OK"); + assert!(!inference.requests().is_empty(), "{}", output.text()); + } + + let rows = world.wait_for_trace_delivery().await; + if world.uses_mock_ingest() { + assert!( + rows.iter() + .any(|row| row_contains(row, &["braintrust.plugin.pi", "test_harness"])), + "Pi trace origin metadata was not emitted" + ); + } +} + #[test] fn request_helpers_recognize_tool_results_and_advertised_tools() { let openai = OpenAiRequest { diff --git a/bt-daemon/tests/pi_translator.rs b/bt-daemon/tests/pi_translator.rs new file mode 100644 index 0000000..6864dd0 --- /dev/null +++ b/bt-daemon/tests/pi_translator.rs @@ -0,0 +1,126 @@ +use bt_daemon::wire::Envelope; +use bt_daemon::{Registry, SessionCtx, SpanOp, SpanRow, SpanType}; +use serde_json::json; +use std::collections::HashMap; + +fn event(name: &str, ts_ms: i64, native: serde_json::Value) -> Envelope { + Envelope { + source: "pi".into(), + source_version: Some("0.80.10".into()), + plugin_version: Some("0.10.0".into()), + session_id: "pi-session".into(), + event: name.into(), + ts_ms, + payload: json!({"event":native,"extension_version":"0.10.0","cwd":"."}), + route: None, + config: None, + } +} + +fn reduce(ops: Vec) -> HashMap { + let mut rows = HashMap::new(); + for op in ops { + match op { + SpanOp::Insert(row) => { + rows.insert(row.span_id.clone(), row); + } + SpanOp::Merge(update) => { + let row: &mut SpanRow = rows.entry(update.span_id.clone()).or_default(); + if update.end_ms.is_some() { + row.end_ms = update.end_ms; + } + if update.metadata.is_some() { + row.metadata = update.metadata; + } + if update.error.is_some() { + row.error = update.error; + } + } + } + } + rows +} + +#[test] +fn pi_builds_turn_llm_tool_compaction_and_shutdown_spans() { + let registry = Registry::default_agents(); + assert!(registry.sources().contains(&"pi".to_string())); + let mut translator = registry.create("pi", "pi-session"); + let ctx = SessionCtx { + session_id: "pi-session".into(), + config: None, + }; + let events = vec![ + event("session_start", 1, json!({"reason":"new"})), + event( + "before_agent_start", + 2, + json!({"prompt":"/skill:review inspect"}), + ), + event( + "context", + 3, + json!({"messages":[{"role":"user","content":"inspect"}]}), + ), + event( + "message_update", + 4, + json!({"assistantMessageEvent":{"type":"text_delta"}}), + ), + event( + "message_end", + 5, + json!({"message":{"role":"assistant","provider":"openai","model":"gpt-5","content":[{"type":"thinking","thinking":"reason"},{"type":"text","text":"done"}],"usage":{"input":5,"output":2,"cacheRead":3,"reasoning":1,"totalTokens":11}}}), + ), + event( + "tool_execution_start", + 6, + json!({"toolCallId":"call-1","toolName":"read","args":{"path":"skills/review/SKILL.md"}}), + ), + event( + "tool_execution_end", + 7, + json!({"toolCallId":"call-1","toolName":"read","result":"contents","isError":false}), + ), + event( + "session_before_compact", + 8, + json!({"preparation":{"tokensBefore":100}}), + ), + event( + "session_compact", + 9, + json!({"compactionEntry":{"summary":"short"}}), + ), + event("agent_end", 10, json!({"messages":[]})), + event("session_shutdown", 11, json!({"reason":"quit"})), + ]; + let mut ops = Vec::new(); + for event in events { + ops.extend(translator.handle(&event, &ctx).unwrap()); + } + let rows = reduce(ops); + assert_eq!( + rows.values() + .filter(|r| r.span_type == SpanType::Llm) + .count(), + 1 + ); + let llm = rows + .values() + .find(|r| r.span_type == SpanType::Llm) + .unwrap(); + assert_eq!(llm.metrics.as_ref().unwrap()["prompt_tokens"], 8); + assert_eq!(llm.metrics.as_ref().unwrap()["time_to_first_token"], 0.001); + let tool = rows + .values() + .find(|r| r.span_type == SpanType::Tool) + .unwrap(); + assert_eq!(tool.name, "skill: review"); + assert_eq!(tool.metadata.as_ref().unwrap()["tool_outcome"], "success"); + assert!(rows.values().any(|r| r.name == "Compaction")); + assert!(rows + .values() + .filter(|r| r.span_type == SpanType::Task) + .all(|r| r.end_ms.is_some())); +} diff --git a/bt-daemon/tests/support/agents/mod.rs b/bt-daemon/tests/support/agents/mod.rs index 9c2aae0..bc15c2c 100644 --- a/bt-daemon/tests/support/agents/mod.rs +++ b/bt-daemon/tests/support/agents/mod.rs @@ -1,6 +1,7 @@ mod claude; mod codex; mod opencode; +mod pi; mod test_plugin; #[allow(unused_imports)] @@ -9,6 +10,8 @@ pub use claude::{ClaudeAgent, ClaudeRun}; pub use codex::{CodexAgent, CodexRun}; #[allow(unused_imports)] pub use opencode::{OpenCodeAgent, OpenCodeRun}; +#[allow(unused_imports)] +pub use pi::{PiAgent, PiRun}; use std::ffi::OsString; use std::path::PathBuf; diff --git a/bt-daemon/tests/support/agents/pi.rs b/bt-daemon/tests/support/agents/pi.rs new file mode 100644 index 0000000..1fd2364 --- /dev/null +++ b/bt-daemon/tests/support/agents/pi.rs @@ -0,0 +1,124 @@ +use super::{command_from_env, AgentOutput, ProcessOptions}; +use crate::support::agent_process::AgentTestWorld; +use serde_json::json; +use std::ffi::OsString; +use std::path::{Path, PathBuf}; + +pub struct PiAgent { + config_dir: PathBuf, + session_dir: PathBuf, + extension: PathBuf, +} + +pub struct PiRun { + prompt: OsString, + mock_inference: Option, + options: ProcessOptions, +} + +impl PiRun { + pub fn new(prompt: impl Into) -> Self { + Self { + prompt: prompt.into(), + mock_inference: None, + options: ProcessOptions::default(), + } + } + + pub fn mock_inference(mut self, base_url: impl Into) -> Self { + self.mock_inference = Some(base_url.into()); + self + } + + pub fn arg(mut self, value: impl Into) -> Self { + self.options.arg(value); + self + } + + pub fn env(mut self, key: impl Into, value: impl Into) -> Self { + self.options.env(key, value); + self + } +} + +impl PiAgent { + pub fn new(world: &AgentTestWorld) -> Self { + let config_dir = world.temp_path("pi-config"); + let session_dir = world.temp_path("pi-sessions"); + for directory in [&config_dir, &session_dir] { + std::fs::create_dir_all(directory).expect("create Pi test directory"); + } + let extension = std::env::var_os("PI_EXTENSION_PATH") + .map(PathBuf::from) + .unwrap_or_else(|| { + Path::new(env!("CARGO_MANIFEST_DIR")) + .parent() + .expect("repository root") + .join("dist/pi/dist/index.mjs") + }); + assert!( + extension.is_file(), + "build the Pi extension before running integration tests: {}", + extension.display() + ); + Self { + config_dir, + session_dir, + extension, + } + } + + pub async fn run(&self, world: &AgentTestWorld, run: PiRun) -> AgentOutput { + let mut command = command_from_env("PI_BIN", "pi"); + if world.uses_mock_inference() { + let base_url = run + .mock_inference + .as_ref() + .expect("mock Pi runs require a mock inference endpoint"); + std::fs::write( + self.config_dir.join("models.json"), + serde_json::to_vec_pretty(&json!({ + "providers": { + "mock": { + "baseUrl": format!("{base_url}/v1"), + "api": "openai-responses", + "apiKey": "test-key", + "models": [{"id": "mock-model", "name": "Mock Model"}] + } + } + })) + .unwrap(), + ) + .expect("write Pi mock model config"); + } + command + .args([ + "--print", + "--mode", + "json", + "--provider", + "mock", + "--model", + "mock-model", + "--api-key", + "test-key", + "--no-extensions", + "--no-skills", + "--no-context-files", + "--no-tools", + "--extension", + ]) + .arg(&self.extension) + .arg("--session-dir") + .arg(&self.session_dir) + .current_dir(world.workspace()) + .env("PI_CODING_AGENT_DIR", &self.config_dir) + .env("TRACE_TO_BRAINTRUST", "true") + .env("BRAINTRUST_PROJECT", "agent-e2e") + .env("PI_OFFLINE", "true"); + world.configure(&mut command); + run.options.apply(&mut command); + command.arg(run.prompt); + world.output(&mut command).await.into() + } +} diff --git a/src/plugins/pi/build.sh b/src/plugins/pi/build.sh new file mode 100755 index 0000000..32fb239 --- /dev/null +++ b/src/plugins/pi/build.sh @@ -0,0 +1,22 @@ +#!/usr/bin/env bash +set -euo pipefail + +TARGET_DIR="${1:?usage: build.sh }" +PLUGIN_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +REPO_ROOT="$(cd "$PLUGIN_DIR/../../.." && pwd)" +STAGE="$(mktemp -d)" +trap 'rm -rf "$STAGE"' EXIT + +rm -rf "$TARGET_DIR" +mkdir -p "$TARGET_DIR" "$STAGE/src/runtime" +TARGET_DIR="$(cd "$TARGET_DIR" && pwd)" +tar --exclude=node_modules --exclude=dist -cf - -C "$PLUGIN_DIR/content" . \ + | tar -xf - -C "$STAGE" +cp "$REPO_ROOT/src/runtime/js-daemon-client/src/index.ts" "$STAGE/src/runtime/daemon-client.ts" + +(cd "$STAGE" && pnpm install --frozen-lockfile && pnpm exec vp fmt src/runtime/daemon-client.ts && pnpm run sync:version && pnpm run pack) +rm -rf "$STAGE/node_modules" +cp -R "$STAGE/." "$TARGET_DIR/" +(cd "$TARGET_DIR" && pnpm pack --pack-destination "$TARGET_DIR" >/dev/null) + +echo "Built Pi npm package and tarball in $TARGET_DIR" diff --git a/src/plugins/pi/content/.gitignore b/src/plugins/pi/content/.gitignore new file mode 100644 index 0000000..ef4592e --- /dev/null +++ b/src/plugins/pi/content/.gitignore @@ -0,0 +1,25 @@ +# Dependencies +node_modules/ + +# Local package artifacts +*.tgz + +# Logs +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* + +# Local environment overrides +.env +.env.* + +# Extension/project-local config with potential secrets +.pi/braintrust.json + +# Local cache/state +.cache/ +dist/ + +# OS files +.DS_Store diff --git a/src/plugins/pi/content/.npmrc b/src/plugins/pi/content/.npmrc new file mode 100644 index 0000000..b6f27f1 --- /dev/null +++ b/src/plugins/pi/content/.npmrc @@ -0,0 +1 @@ +engine-strict=true diff --git a/src/plugins/pi/content/.tool-versions b/src/plugins/pi/content/.tool-versions new file mode 100644 index 0000000..1dbe639 --- /dev/null +++ b/src/plugins/pi/content/.tool-versions @@ -0,0 +1,3 @@ +node 24 +pnpm 10.33.0 +npm:vite-plus 0.1.14 diff --git a/src/plugins/pi/content/CONTRIBUTING.md b/src/plugins/pi/content/CONTRIBUTING.md new file mode 100644 index 0000000..be83224 --- /dev/null +++ b/src/plugins/pi/content/CONTRIBUTING.md @@ -0,0 +1,28 @@ +# Contributing + +`@braintrust/pi-extension` is developed in the Braintrust coding-agent plugin +monorepo under `src/plugins/pi/content`. + +The JavaScript package is intentionally a thin adapter: it reads non-secret +routing and UI preferences, forwards native pi events through the shared daemon +client, and displays daemon status. It must not construct spans, persist tracing +state, resolve credentials, or call the Braintrust API. + +Run the package checks from this directory with: + +```bash +pnpm install --frozen-lockfile +pnpm run check +pnpm test +pnpm run smoke +pnpm run pack +``` + +From the monorepo root, `make validate-pi` performs the complete package and +tarball validation. The Rust translator and real-agent harness live under +`bt-daemon/` and are exercised by the root CI workflow. + +Configuration precedence remains defaults, the global pi extension config, +project-local pi extension config, then environment variables. Configuration +may select a `bt` profile, organization, project, metadata, and UI behavior, but +must never contain credentials. diff --git a/src/plugins/pi/content/LICENSE b/src/plugins/pi/content/LICENSE new file mode 100644 index 0000000..893ee37 --- /dev/null +++ b/src/plugins/pi/content/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 Braintrust + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/src/plugins/pi/content/README.md b/src/plugins/pi/content/README.md new file mode 100644 index 0000000..ad7a1a7 --- /dev/null +++ b/src/plugins/pi/content/README.md @@ -0,0 +1,132 @@ +# @braintrust/pi-extension + +[![npm version](https://img.shields.io/npm/v/%40braintrust%2Fpi-extension)](https://www.npmjs.com/package/@braintrust/pi-extension) + +Braintrust extension for [pi](https://github.com/earendil-works/pi-coding-agent). + +Today this extension automatically traces pi sessions, turns, model calls, and tool executions to Braintrust. +The extension forwards native pi events to the installed `bt` tracing daemon; +all span construction, authentication, recovery, and Braintrust delivery happen +inside the daemon. + +## What gets traced + +- **Session spans**: one root span per pi session that actually produces at least one turn +- **Turn spans**: one span per user prompt / agent run +- **LLM spans**: one span per model response inside a turn, including canonical token, cache, reasoning, estimated-cost, and time-to-first-token metrics +- **Tool spans**: one span per tool execution, including tools activated through pi's dynamic/deferred tool-loading flow +- **Compaction spans**: one span per session compaction, including trigger/retry metadata when available +- **Branch summary spans**: one span per summarized `/tree` navigation branch + +Trace shape: + +```text +Session (task) +├── Turn 1 (task) +│ ├── anthropic/claude-sonnet-4 (llm) +│ │ ├── read: package.json (tool) +│ │ └── bash: pnpm test (tool) +│ └── anthropic/claude-sonnet-4 (llm) +├── Compaction (task) +├── Branch Summary (task) +└── Turn 2 (task) +``` + +## Install + +### From npm + +```bash +pi install npm:@braintrust/pi-extension +``` + +### From this repo + +```bash +pi install . +``` + +Or load it just for one run: + +```bash +pi -e . +``` + +## Compatibility + +This package supports the **latest patch release from each of the last five stable pi minor versions**, currently excluding pi versions before `0.65.0`. + +Our GitHub Actions compatibility job automatically resolves and tests that compatibility window, so new pi releases are picked up without manually updating the matrix. + +## Quick start + +Tracing is disabled by default. + +Set these environment variables: + +```bash +export TRACE_TO_BRAINTRUST=true +bt auth login +export BRAINTRUST_PROJECT=pi +``` + +Then start pi normally. + +In interactive mode, the footer shows a `Braintrust` status indicator while tracing is active, and a widget below the editor shows a shortened clickable trace link when available. + +## Configuration + +You can configure the extension with environment variables or JSON config files. + +Config precedence is: + +1. defaults +2. `~/.pi/agent/braintrust.json` +3. `.pi/braintrust.json` +4. environment variables + +### Config file locations + +- Global: `~/.pi/agent/braintrust.json` +- Project: `.pi/braintrust.json` + +Example: + +```json +{ + "trace_to_braintrust": true, + "profile": "work", + "project": "pi", + "additional_metadata": { + "team": "platform" + } +} +``` + +## Supported settings + +| Config key | Env var | Default | +|---|---|---| +| `trace_to_braintrust` | `TRACE_TO_BRAINTRUST` | `false` | +| `org_name` | `BRAINTRUST_ORG_NAME` | unset | +| `profile` | `BRAINTRUST_PROFILE` | default `bt` profile | +| `project` | `BRAINTRUST_PROJECT` | `pi` | +| `additional_metadata` | `BRAINTRUST_ADDITIONAL_METADATA` | `{}` | +| `show_ui` | `BRAINTRUST_SHOW_UI` | `true` | +| `show_trace_link` | `BRAINTRUST_SHOW_TRACE_LINK` | `true` | + +## Notes + +- Project config overrides global config. +- Environment variables override both config files. +- Project config follows pi's configured project config directory, which defaults to `.pi`. +- The extension does not persist local span state; recovery and incomplete-operation cleanup are owned by the daemon journal. +- Span construction and Braintrust delivery run in the installed `bt` tracing daemon. +- The extension never reads or stores Braintrust credentials. Profile selection is + non-secret, optional, and resolved by the daemon through `bt` authentication. +- Provider request tracing is allowlisted to effective model, thinking, output-limit, and tool-count settings; full provider payloads and thinking signatures are never logged. +- If Braintrust is unavailable, pi should continue working normally. + +## Contributing + +See [CONTRIBUTING.md](./CONTRIBUTING.md) for development setup, validation, and repository conventions. diff --git a/src/plugins/pi/content/docs/PUBLISHING.md b/src/plugins/pi/content/docs/PUBLISHING.md new file mode 100644 index 0000000..567fd5e --- /dev/null +++ b/src/plugins/pi/content/docs/PUBLISHING.md @@ -0,0 +1,17 @@ +# Publishing + +This package is built and validated from the Braintrust coding-agent plugin +monorepo. The source manifest owns the committed package version, and +`src/plugins/pi/build.sh` creates the npm tarball from a clean staging tree. + +Local release preflight from the monorepo root: + +```bash +make validate-pi +DRY_RUN=1 NPM_TAG=next src/plugins/pi/publish.sh dist/pi/braintrust-pi-extension-*.tgz +``` + +The publisher accepts only a previously built tarball and rejects an existing +npm version. A real publish requires the release-only confirmation documented +by `publish.sh`. Normal development and CI use only the dry-run path; they do +not publish, tag, or create a GitHub release. diff --git a/src/plugins/pi/content/package.json b/src/plugins/pi/content/package.json new file mode 100644 index 0000000..4584119 --- /dev/null +++ b/src/plugins/pi/content/package.json @@ -0,0 +1,71 @@ +{ + "name": "@braintrust/pi-extension", + "version": "0.10.0", + "description": "Braintrust extension for pi. Includes automatic tracing for pi sessions, turns, LLM calls, and tool executions to Braintrust.", + "keywords": [ + "braintrust", + "llm", + "observability", + "pi", + "pi-package", + "tracing" + ], + "license": "MIT", + "repository": { + "type": "git", + "url": "https://github.com/braintrustdata/plugin-monorepo.git", + "directory": "src/plugins/pi/content" + }, + "files": [ + "dist", + "README.md", + "LICENSE" + ], + "type": "module", + "main": "dist/index.mjs", + "types": "dist/index.d.mts", + "publishConfig": { + "access": "public" + }, + "scripts": { + "preinstall": "node -e \"const userAgent = process.env.npm_config_user_agent || ''; if (process.env.INIT_CWD === process.cwd() && !userAgent.includes('pnpm/')) { console.error('Use pnpm in this repo.'); process.exit(1); }\"", + "check": "node scripts/sync-version.mjs --check && vp check", + "fmt": "vp fmt", + "lint": "vp lint", + "prepack": "node scripts/sync-version.mjs", + "pack": "vp pack", + "sync:version": "node scripts/sync-version.mjs", + "test": "vitest run", + "test:watch": "vitest", + "typecheck": "vp check", + "smoke": "vp exec node -e \"import('./src/index.ts')\"" + }, + "devDependencies": { + "@earendil-works/pi-coding-agent": "^0.80.2", + "@types/node": "^26.0.0", + "typescript": "^6.0.2", + "vite-plus": "^0.2.1", + "vitest": "^4.1.4" + }, + "peerDependencies": { + "@earendil-works/pi-coding-agent": "*" + }, + "devEngines": { + "packageManager": { + "name": "pnpm", + "version": ">=10.33.0", + "onFail": "error" + } + }, + "engines": { + "npm": "please-use-pnpm", + "pnpm": ">=10.33.0", + "yarn": "please-use-pnpm" + }, + "packageManager": "pnpm@10.33.0", + "pi": { + "extensions": [ + "./dist/index.mjs" + ] + } +} diff --git a/src/plugins/pi/content/pnpm-lock.yaml b/src/plugins/pi/content/pnpm-lock.yaml new file mode 100644 index 0000000..1864205 --- /dev/null +++ b/src/plugins/pi/content/pnpm-lock.yaml @@ -0,0 +1,3475 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + devDependencies: + '@earendil-works/pi-coding-agent': + specifier: ^0.80.2 + version: 0.80.10(ws@8.21.1)(zod@4.4.3) + '@types/node': + specifier: ^26.0.0 + version: 26.1.1 + typescript: + specifier: ^6.0.2 + version: 6.0.3 + vite-plus: + specifier: ^0.2.1 + version: 0.2.5(@opentelemetry/api@1.9.0)(@types/node@26.1.1)(esbuild@0.27.7)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(vite@8.0.3(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@26.1.1)(esbuild@0.27.7)(jiti@2.7.0)(tsx@4.21.0)(yaml@2.9.0))(yaml@2.9.0) + vitest: + specifier: ^4.1.4 + version: 4.1.10(@opentelemetry/api@1.9.0)(@types/node@26.1.1)(@vitest/browser-preview@4.1.10)(vite@8.0.3(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@26.1.1)(esbuild@0.27.7)(jiti@2.7.0)(tsx@4.21.0)(yaml@2.9.0)) + +packages: + + '@anthropic-ai/sdk@0.91.1': + resolution: {integrity: sha512-LAmu761tSN9r66ixvmciswUj/ZC+1Q4iAfpedTfSVLeswRwnY3n2Nb6Tsk+cLPP28aLOPWeMgIuTuCcMC6W/iw==} + hasBin: true + peerDependencies: + zod: ^3.25.0 || ^4.0.0 + peerDependenciesMeta: + zod: + optional: true + + '@aws-crypto/sha256-browser@5.2.0': + resolution: {integrity: sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw==} + + '@aws-crypto/sha256-js@5.2.0': + resolution: {integrity: sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA==} + engines: {node: '>=16.0.0'} + + '@aws-crypto/supports-web-crypto@5.2.0': + resolution: {integrity: sha512-iAvUotm021kM33eCdNfwIN//F77/IADDSs58i+MDaOqFrVjZo9bAal0NK7HurRuWLLpF1iLX7gbWrjHjeo+YFg==} + + '@aws-crypto/util@5.2.0': + resolution: {integrity: sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==} + + '@aws-sdk/client-bedrock-runtime@3.1048.0': + resolution: {integrity: sha512-u+NT61JZEkRFtpL0CAw1N1dwxnaLgwVXQl/zjJxTGgLyS/jTIdg2SdoEoCTHxgDyCnqa1HEi9QOoE9/pYRNpOQ==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/core@3.975.3': + resolution: {integrity: sha512-7ur3kCKuvPLqlsZ2XlvnNBVQ7KkpSu6Y6dOTwSPHLrFpTEfZM8isLBJc4cgv96WB7GifeVM436mpycwxBd2vEA==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-env@3.972.59': + resolution: {integrity: sha512-Ny5e4Mfh3QPmiAc0AiUe+cbTXDlxkU3Rc+EpWOfyWeWEy6yp7Fa1KmfNeCc+1a8by9zQ9gtohmiQUkMPScF3ng==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-http@3.972.61': + resolution: {integrity: sha512-8jAjgStl5Ytq4+HF3X/9f+EmRinaRbGRRtQGktlPfBRVx73H+R1y48vIeXerQtYGFaUqkEp3fT6jP854rVO2yQ==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-ini@3.973.4': + resolution: {integrity: sha512-e6ZvVsj90aRALf1kHP+J4iqC1496ZpVgqI/+u0LJ5HL7q7ATauGy4gdDvRCP13L1pN/fMiZLah162PGIYkbUVQ==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-login@3.972.66': + resolution: {integrity: sha512-g2fsqm87r/nKthLZ0VkkDBElkGg0PvSa8d97HQ6EilMbJTZ6hxa8FxkSZyJfgPfFdZn0TTmkOffQmTSUcAHIng==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-node@3.972.70': + resolution: {integrity: sha512-3xzvkGdykBunxqh8WudmUpSyLWvIhfI6aBQo1b5rb3mDO5mNLadK+0hiI0qBQBMVynJbfLO+Ajy9dztMwy9O8w==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-process@3.972.59': + resolution: {integrity: sha512-DlZF2/MhLlatDdlrIy3CUCpfdbLrKx+3SMjVo+WyHnPpwzkc/M3vwAHw4OVJf7DMvO+4vfRqSCMc/E9I1auN0g==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-sso@3.973.3': + resolution: {integrity: sha512-hmdDHoy2G5Es2e8IgelNMYUuSQI6uCIAKZMJ2u2PdKDhxvbk1uWD/g4+R7R5c/tJfKEB1+KjjWiaoCr/S+ZTiQ==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-web-identity@3.972.65': + resolution: {integrity: sha512-gHQb/Kt0chjk/JQDa/GJDqmAvEuVn8n7z10wK2h0LFM9TUDRkohgOO4aEF+s2sBLM0br7Cl5W6P7phgjrrJvLQ==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/eventstream-handler-node@3.972.29': + resolution: {integrity: sha512-t3tKQRTVXsI2QNPE3CaNjHl0wRO9Xi3acZkAyti2RQsiFmZ9Gi0kArX2ighlRJ1BtDVuul413gThAgzyTfgmWA==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/middleware-eventstream@3.972.24': + resolution: {integrity: sha512-oykin4mDWxNOuYQ7SF1cHzgYeuFEkF4cdRwgvjFFbIklkx09qIFBiOgsORafG9sXZFO3TayMmQuAQYgADXhI8w==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/middleware-websocket@3.972.41': + resolution: {integrity: sha512-LSbGvvYmjc4Br9BPYI2dTLnIclmrSiQbahkP4D6nRGVEv4qsCZ8csVuKBPVEEFCVD+EEngGh8ROls6XpumtwMg==} + engines: {node: '>= 14.0.0'} + + '@aws-sdk/nested-clients@3.997.33': + resolution: {integrity: sha512-dVZOroI/r3/ENvqNGgjMPul+jjlz9GddfVusgTXlVjfZj5isibOxecLkGQbRPp8XOuX+RAfjXLFgPkD1JS5xrw==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/signature-v4-multi-region@3.996.41': + resolution: {integrity: sha512-QMUytg+FQMGouc8gHS00KoYih3+N6cqmVI/pQGOIo7Nr7OpQaiXjSYOuL+vsPZ1tymY4LAQ8MYcHJmws5LRxng==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/token-providers@3.1048.0': + resolution: {integrity: sha512-k0y/GcuesuSfWyUM0WamrGyeZmltRYaPbHO82UDA6mZ/doB+FOHKutikPAtSXMn/hDz970cF+iRuuiYO9VEbAA==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/token-providers@3.1088.0': + resolution: {integrity: sha512-4ObatWt2qpJg5FBk4LOOKrTQYzaqeewAtdO3r9ZO8lH9YqLtpTzLyIdy0mJ+nVdfYOnqISkKNfmzP22bNDhwyw==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/types@3.974.2': + resolution: {integrity: sha512-3W6IUtSxFbH6X7Wb7DzGCV5QiFQsd0g8bOfntpmDxQlzBoKWUMBu/JPQR0DwkE+Hpnxd6db1tXbOwdeHddG6cA==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/util-locate-window@3.965.8': + resolution: {integrity: sha512-uUbMs1cBZPafD0ohUj6EwNf0fPZ534NvBxHox4hjX+0Rxq5paSYUem7+hi833pYrzrcnBATKIYpR02MDXT5M9g==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/xml-builder@3.972.36': + resolution: {integrity: sha512-RdGmS1GLrtaTOLE1ElSluMldNrpk9Emq6uYs8SS8iHlu5xTAmM9rRkM91o48+rIRryBtyO9t+uLYCoMG6jVMVA==} + engines: {node: '>=20.0.0'} + + '@aws/lambda-invoke-store@0.3.0': + resolution: {integrity: sha512-sl4Bm6yiMNYrZKkqqDFWN0UfnWhlS8ivKxrYl+6t0gCLrqr8y3B2IqZZbFRkfaVVp7C/baApyh71P+LeE1A2sQ==} + engines: {node: '>=18.0.0'} + + '@babel/code-frame@7.29.7': + resolution: {integrity: sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@7.29.7': + resolution: {integrity: sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==} + engines: {node: '>=6.9.0'} + + '@babel/runtime@7.29.7': + resolution: {integrity: sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==} + engines: {node: '>=6.9.0'} + + '@blazediff/core@1.9.1': + resolution: {integrity: sha512-ehg3jIkYKulZh+8om/O25vkvSsXXwC+skXmyA87FFx6A/45eqOkZsBltMw/TVteb0mloiGT8oGRTcjRAz66zaA==} + + '@earendil-works/pi-agent-core@0.80.10': + resolution: {integrity: sha512-nwnOR3SuLYGRFfyQm8ri4Nj5VGVAvAM9GuqQd3u7BUQj0d6hmD2F8w7OHAAjThE3CuySIdM+v8E22QJG6/RfCg==} + engines: {node: '>=22.19.0'} + + '@earendil-works/pi-ai@0.80.10': + resolution: {integrity: sha512-Moe/H8c87yacDGK9dPbWphZNjVsrb3nTrIHycOQJAkFEnY9PYxOOd74+ny44kATfPU9Dm7aTHefar3pZF+UKUA==} + engines: {node: '>=22.19.0'} + hasBin: true + + '@earendil-works/pi-coding-agent@0.80.10': + resolution: {integrity: sha512-aL4apbupCHiVLSXASXvRzH4Q2vmtfrDa+0s909CJuVu/GgGylbDzr7oyF1mPmip5E+VxYYxKWmph4hV04wUcQg==} + engines: {node: '>=22.19.0'} + hasBin: true + + '@earendil-works/pi-tui@0.80.10': + resolution: {integrity: sha512-c2JO29PbhKPEQ6fgHQKAl0WhwuFqzWfzspMmP+8B5tpDuP+0mvarRbKKg8gq4b+pQx/QX+6aVS4ko7deoyjQjg==} + engines: {node: '>=22.19.0'} + + '@emnapi/core@1.9.1': + resolution: {integrity: sha512-mukuNALVsoix/w1BJwFzwXBN/dHeejQtuVzcDsfOEsdpCumXb/E9j8w11h5S54tT1xhifGfbbSm/ICrObRb3KA==} + + '@emnapi/runtime@1.9.1': + resolution: {integrity: sha512-VYi5+ZVLhpgK4hQ0TAjiQiZ6ol0oe4mBx7mVv7IflsiEp0OWoVsp/+f9Vc1hOhE0TtkORVrI1GvzyreqpgWtkA==} + + '@emnapi/wasi-threads@1.2.0': + resolution: {integrity: sha512-N10dEJNSsUx41Z6pZsXU8FjPjpBEplgH24sfkmITrBED1/U2Esum9F3lfLrMjKHHjmi557zQn7kR9R+XWXu5Rg==} + + '@esbuild/aix-ppc64@0.27.7': + resolution: {integrity: sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + + '@esbuild/android-arm64@0.27.7': + resolution: {integrity: sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.27.7': + resolution: {integrity: sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.27.7': + resolution: {integrity: sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.27.7': + resolution: {integrity: sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-x64@0.27.7': + resolution: {integrity: sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + + '@esbuild/freebsd-arm64@0.27.7': + resolution: {integrity: sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.27.7': + resolution: {integrity: sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.27.7': + resolution: {integrity: sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.27.7': + resolution: {integrity: sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.27.7': + resolution: {integrity: sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-loong64@0.27.7': + resolution: {integrity: sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.27.7': + resolution: {integrity: sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.27.7': + resolution: {integrity: sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.27.7': + resolution: {integrity: sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.27.7': + resolution: {integrity: sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-x64@0.27.7': + resolution: {integrity: sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + + '@esbuild/netbsd-arm64@0.27.7': + resolution: {integrity: sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.27.7': + resolution: {integrity: sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-arm64@0.27.7': + resolution: {integrity: sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.27.7': + resolution: {integrity: sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + + '@esbuild/openharmony-arm64@0.27.7': + resolution: {integrity: sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + + '@esbuild/sunos-x64@0.27.7': + resolution: {integrity: sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.27.7': + resolution: {integrity: sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-ia32@0.27.7': + resolution: {integrity: sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-x64@0.27.7': + resolution: {integrity: sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + + '@google/genai@1.52.0': + resolution: {integrity: sha512-gwSvbpiN/17O9TbsqSsE/OzZcpv5Fo4RQjdngGgogtuB9RsyJ8ZHhX5KjHj1bp5N9snN2eK8LDGXSaWW2hof8Q==} + engines: {node: '>=20.0.0'} + peerDependencies: + '@modelcontextprotocol/sdk': ^1.25.2 + peerDependenciesMeta: + '@modelcontextprotocol/sdk': + optional: true + + '@jridgewell/sourcemap-codec@1.5.5': + resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} + + '@mariozechner/clipboard-darwin-arm64@0.3.9': + resolution: {integrity: sha512-BfgV7vCEWZwJwZJw03r6bP5+tf0iI/ANuQYCxi9RNn7FrWB3yzGuMKCrNLRl6V761vXRdL8+OqZ0wd4TqlsNOQ==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [darwin] + + '@mariozechner/clipboard-darwin-universal@0.3.9': + resolution: {integrity: sha512-BGGR4iA9Z2shAjI65eI5xtyb3LYNlDW9X3gxKxDbqtbnREohsrqznov6zpKoIrsRWpzlYVEdKphS7ksJ0/ndSQ==} + engines: {node: '>= 10'} + os: [darwin] + + '@mariozechner/clipboard-darwin-x64@0.3.9': + resolution: {integrity: sha512-4kURmCbS6nt8uYhtmWpUcJWyPHfmAr5dTpXD1nO3pIfa+TSQ9DbrGOYCKH+aEFW47XhQ4Vp8ZTszie+wfFvDKg==} + engines: {node: '>= 10'} + cpu: [x64] + os: [darwin] + + '@mariozechner/clipboard-linux-arm64-gnu@0.3.9': + resolution: {integrity: sha512-g59OkUGP2DDfCOIKypHeYgv2M55u/cKvXa5dSxFbEJ34XvIQMdcVmpKCkGUro3ZgefXiGVdwguvTMQGpHWzIXw==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@mariozechner/clipboard-linux-arm64-musl@0.3.9': + resolution: {integrity: sha512-AGuJdgKsmJdm4Pych7kv3sqe591ERRaAHW3xjLooiFzn8J+PxUyof++7YZrB5Y5tpnTO+K18Og3taj2NpluCRQ==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@mariozechner/clipboard-linux-riscv64-gnu@0.3.9': + resolution: {integrity: sha512-DXBEAiuMpk7dhS1a9NzNxVAFi1vaKoPu7rQNgY8LIDLGrK3lnIp3nT10DUum+PKVJoJppIP+NAA8IZe4DMNDPw==} + engines: {node: '>= 10'} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@mariozechner/clipboard-linux-x64-gnu@0.3.9': + resolution: {integrity: sha512-WORrMLd6EpElEME7JRKfSaY34nW1P5LbdgK5YNCS1ncG2LqmITsSMEJ8nh2mpvxb3TxqbOOKgY7k9eMJYlW9Mw==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@mariozechner/clipboard-linux-x64-musl@0.3.9': + resolution: {integrity: sha512-/DHn+1DrfL6oRaPPWXaOKvonFFrni666fxd+zFqiQEfvBH0tsHVWjq9iqBk0oDp0qaPA72lIMy5BptxISBEhZQ==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + libc: [musl] + + '@mariozechner/clipboard-win32-arm64-msvc@0.3.9': + resolution: {integrity: sha512-O5FHD3ErkMwMhNzAfu3ggy0ug4z7btZuoQgwwxlzPrwV2bxlD6WDpqBY4NCgICAgZdDKdp+loUEKVAVt8aYnhQ==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [win32] + + '@mariozechner/clipboard-win32-x64-msvc@0.3.9': + resolution: {integrity: sha512-ihQC3EufqEY81vhXBgVBtK4prL+wc62zJsSvxrgz7K1hsdt6OObz6v9p3Rn1OG3GJksTTKMJF0u/guMISHPhSA==} + engines: {node: '>= 10'} + cpu: [x64] + os: [win32] + + '@mariozechner/clipboard@0.3.9': + resolution: {integrity: sha512-ABnA53mdfkGZwOFUdZNv2S0CWGO/EIuPj8Vv9xmBFmSYg/qFc7ihO6q5FcQjvoE67kZpWkEc4AhD6B/os04yuA==} + engines: {node: '>= 10'} + + '@mistralai/mistralai@2.2.6': + resolution: {integrity: sha512-W8pX7zHxjJvMIpw8JMxeJEleapXX0Q9NPszdNzqkM3MIEoIGPObdodujj+WHteXEvGfaP/AMwlNyRfEzSY6dQQ==} + peerDependencies: + '@opentelemetry/api': ^1.9.0 + peerDependenciesMeta: + '@opentelemetry/api': + optional: true + + '@napi-rs/wasm-runtime@1.1.6': + resolution: {integrity: sha512-ZLv/JdUfkvOy9eCnnBaGfiO+XimbjebAeO+MRQqD/B+FR1tnRN0tpKSJHRbE8sFfS6aqsXZ67TQjfwfsxULVbg==} + peerDependencies: + '@emnapi/core': ^1.7.1 + '@emnapi/runtime': ^1.7.1 + + '@opentelemetry/api@1.9.0': + resolution: {integrity: sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==} + engines: {node: '>=8.0.0'} + + '@opentelemetry/semantic-conventions@1.43.0': + resolution: {integrity: sha512-eSYWTm620tTk45EKSedaUL8MFYI8hW164hIXsgIHyxu3VobUB3fFCu5t0hQby6OoWRPsG1KkKUG2M5UadiLiVg==} + engines: {node: '>=14'} + + '@oxc-project/runtime@0.139.0': + resolution: {integrity: sha512-WnuGdceWtRdqD7f3alOIDXN6bnGuGtFjtQf/dHjzgn2im7eKaYRJTEl2T1kFEWPhBWCDk+UDYgsTLUE5L6jc0w==} + engines: {node: ^20.19.0 || >=22.12.0} + + '@oxc-project/types@0.122.0': + resolution: {integrity: sha512-oLAl5kBpV4w69UtFZ9xqcmTi+GENWOcPF7FCrczTiBbmC0ibXxCwyvZGbO39rCVEuLGAZM84DH0pUIyyv/YJzA==} + + '@oxc-project/types@0.139.0': + resolution: {integrity: sha512-r9gHphtCs+1M7J0pw6Sn/hh/Wpa/iQrOOkrNAlVLF/gHq+/CJmHIWKKUUhdWjcD6CIa8idarspCsASiXCXvFUw==} + + '@oxfmt/binding-android-arm-eabi@0.58.0': + resolution: {integrity: sha512-Uz62sHduGGPftXtILGyxdSW4PX82rUg+rfdNqhsgxe881g4rIoXlIqmZQ6HVKcF4f+F8qMhdD03Bx5u7gmeTdg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [android] + + '@oxfmt/binding-android-arm64@0.58.0': + resolution: {integrity: sha512-rD0lRaJp1b+9vw6X4A2dJWKukd6X8yxiicN4JxXcXayolmUypRZxk+lKR+fVOu5q/iYc0fh5fR4bgmfOfVlbaA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [android] + + '@oxfmt/binding-darwin-arm64@0.58.0': + resolution: {integrity: sha512-uzbPPk7O6M+w2K65vcQ1woga3wgP8zghjL1KOG5b6qJ8dvYHZJ1VShaslg2KOK6yQIwCQtcMCXqLBM6sqXUNTg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [darwin] + + '@oxfmt/binding-darwin-x64@0.58.0': + resolution: {integrity: sha512-L0nKYDxU32oxeQqJj21W9SlIMnf81VZEhyah6iDvFhf5q0oynq498Fopth7blErUJVBpVtxQ98RMCfMPqpJX6w==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [darwin] + + '@oxfmt/binding-freebsd-x64@0.58.0': + resolution: {integrity: sha512-woNwfD58dC5PGS9LSLSD5JYfo/EFK5iG9vhDWkcCg3q78ag7KC8bpDqgvPHrMoXpx83OLXxoSOhu6z8FsVTHlg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [freebsd] + + '@oxfmt/binding-linux-arm-gnueabihf@0.58.0': + resolution: {integrity: sha512-Sqs8nMLxuQpY21NKJ1u4stPDmO5hskBCNNh2E3AdCfI1QqWtf4m+Qn4mGEIUO4KGmuq3SWc/SZ80uy5IiwTCDw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] + + '@oxfmt/binding-linux-arm-musleabihf@0.58.0': + resolution: {integrity: sha512-Vd4exzBI5B5hB9m22JiTQzIL23WvHo/Pe+sNXPNeBLXSP9swCBPKCEBRwKpmpQzYhlgYaCgfPcGXPKAJBRIiZQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] + + '@oxfmt/binding-linux-arm64-gnu@0.58.0': + resolution: {integrity: sha512-bUWi5mHV+4Vi56RLHE1h6q/HHfwAIT3XoB9vJAVeRzfu5NriXM8y6eeJu0vlKa0C9kq2rq1sOWRClhdLHPocrg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@oxfmt/binding-linux-arm64-musl@0.58.0': + resolution: {integrity: sha512-2ZHxemzgHcjtktAuVUwSoyXmGo/t+aF5tS1ciPpPei4rhSyrz3JOqDosXXrmhN/yLUSzJjtuW7ToTWqfQpCj2w==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@oxfmt/binding-linux-ppc64-gnu@0.58.0': + resolution: {integrity: sha512-AwKkVwjVmFQ3bcO7j0McGYAqCKH2a326fswfofng/E8VewCT/raeeGQr4huVhY704deK8AWASSTlxzMj0eZc6Q==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@oxfmt/binding-linux-riscv64-gnu@0.58.0': + resolution: {integrity: sha512-xsRpTxfUnJF8D3AUKko/qyWdjw4GZVHlCVFuGlzSCTeewLmykKINW8em1+wx+axsDVtJJcMtvsiaXggXxrlHgw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@oxfmt/binding-linux-riscv64-musl@0.58.0': + resolution: {integrity: sha512-Z4AYOTcy7nYEIiXwD62PlerimyYRcfJOgUbQAEBjXz098kxKuERBlRntofGy69HHhe9E0TLVNMl1yspVNu+efw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [riscv64] + os: [linux] + libc: [musl] + + '@oxfmt/binding-linux-s390x-gnu@0.58.0': + resolution: {integrity: sha512-A3nhhtZPC/TKVWOPj9q/H3p2znJDCcHWYlJBhWL8hGq/bFmBaNBHC8Np6E581yVq1w9Mi3rMDNzDalWvtUfJtQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@oxfmt/binding-linux-x64-gnu@0.58.0': + resolution: {integrity: sha512-2g+tVkgwqphw8R4hgo+kF4oz8+P5RwVOtr9+irsC7uwEp0e9j7Crw8kDGKL20uYlLPD7g02DqA61mC/UNYx98A==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@oxfmt/binding-linux-x64-musl@0.58.0': + resolution: {integrity: sha512-rc15P6AbyyB7426aN8AakLd02Trb3a6ML/mmfAQeVHJEfVofWLcWIrBdy6zDEY+DIaL/s8E4GGPboVw+oP3+EA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [musl] + + '@oxfmt/binding-openharmony-arm64@0.58.0': + resolution: {integrity: sha512-ZWoTM27/HYPOh9iq86DAbhPu9nXb8qKvvGU/h8OfliyVUFAMMNTLDkGsWDKKnDqIkqvZ9+dXlgUOsH1LYO3O7g==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [openharmony] + + '@oxfmt/binding-win32-arm64-msvc@0.58.0': + resolution: {integrity: sha512-LHZnqFXe2dEfkRI4XdZS/57nEOT/I4UCRX5IyM9v4GYW9XwQCjGe1IUK59SuKw3POwvcgWQ4pme2cYXmNqTNPg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [win32] + + '@oxfmt/binding-win32-ia32-msvc@0.58.0': + resolution: {integrity: sha512-mZKpg20TpheCJym1rarcZCUJeW1sSruw8zAAaCYWvuVfwIUDN1CXdrPU/JgCWReXTCTrEfCB8Wyo3hh9jSZ2EA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [ia32] + os: [win32] + + '@oxfmt/binding-win32-x64-msvc@0.58.0': + resolution: {integrity: sha512-N/wUU4N5PZ2orBtI+Ko7MnMfYLfE7K91UrGMY/c/pYyHR3lA9kwst1XugkZx+92YcRh/Eo+iv2eTESSWXfiZPA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [win32] + + '@oxlint-tsgolint/darwin-arm64@0.24.0': + resolution: {integrity: sha512-C2uMmwK5Bc4ri4ysZ6sA8Rcu+A5zBQTp6ml2u0CLLbRZp4kMFPV3yWk8B5DK9Aw7y9bbjogIm75tUwGLFzlsYQ==} + cpu: [arm64] + os: [darwin] + + '@oxlint-tsgolint/darwin-x64@0.24.0': + resolution: {integrity: sha512-Wgvt/1lRbDxmoNqWQKKcL+UIiqLmdJ+EWLpQa1qzoNVAfNB0PJpa82/8dH1twT/3rSs4zrP5TXPWl4juB71WuQ==} + cpu: [x64] + os: [darwin] + + '@oxlint-tsgolint/linux-arm64@0.24.0': + resolution: {integrity: sha512-PB1rxII7KV83+ASY4sSkXtqvpij6ME66+QCRL49uksi/ofs2Rf/UVboYr095n0Rkbl2wgvlsHGl6DHC361jQUQ==} + cpu: [arm64] + os: [linux] + + '@oxlint-tsgolint/linux-x64@0.24.0': + resolution: {integrity: sha512-xcz3CxKmjTQLREtE/UShh+ruWmm9nAb7UM9zKcD65BStiuYgOakAKkPHl4YS5DztpVcDrE0+HqbOolTlRKYWmw==} + cpu: [x64] + os: [linux] + + '@oxlint-tsgolint/win32-arm64@0.24.0': + resolution: {integrity: sha512-A2i6ZGBec3i20S7RaxkgHc6r3HYtD5Mn7j/mb22NkTz14u0JuudvTu6JggAnbGMcv8+dBKQI//EasxSPJLD8pw==} + cpu: [arm64] + os: [win32] + + '@oxlint-tsgolint/win32-x64@0.24.0': + resolution: {integrity: sha512-0ZbGd9qRB6zs82moekaKdEvncRANq49EAwfNX62JpTS46feXUhKAuoyVDvZMj6Rywejylrmmu79Wo6faYCo4Ew==} + cpu: [x64] + os: [win32] + + '@oxlint/binding-android-arm-eabi@1.73.0': + resolution: {integrity: sha512-HZQRN/UMBu+Ut+/9MiAChkbP4qZqrNOWBcNI45vOT40GVhbGR0JgHB87L48D4iAqFQIdVmeQYtV9RF89AjTKkg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [android] + + '@oxlint/binding-android-arm64@1.73.0': + resolution: {integrity: sha512-Gp+KJRylv2aW7thRpG5p1KTxZq4ZJFbWowrKzufNq9d3ssl3r3JviYV45/+p+7CN1Nv0zDd1e8Ex0b/HUDq4TQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [android] + + '@oxlint/binding-darwin-arm64@1.73.0': + resolution: {integrity: sha512-3de96NdtXhxERMjIz7wsp2HYMY6pMQycGxFWac2mFecAx6VeARF/IqFb1QIaqiCRIdfzBwzTed+pCTCoiS+CYA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [darwin] + + '@oxlint/binding-darwin-x64@1.73.0': + resolution: {integrity: sha512-5zx/uPW32TiaOeVY1dQ/H5iOf0K1HOdFKOJhLqGl4o63+i1fpzoqqu/mKtd7OFgFjNCdhlyTGgjVkQTZm1ELcg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [darwin] + + '@oxlint/binding-freebsd-x64@1.73.0': + resolution: {integrity: sha512-qNe4gKHaGnLuZJ8toUg90JAa0S2vTVvDw+0bRi3q1avXZXDT4u5mMeECf3nD4HYrbdn1O7dXqWut4onY/yx/Xg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [freebsd] + + '@oxlint/binding-linux-arm-gnueabihf@1.73.0': + resolution: {integrity: sha512-cCehYh5hTbfShm/fxTD6wwrGUWIpvX+N5OxmAMhFhDeTGXvw+BeNj889tpxsFQ9ZLatQ6wImuY8tsKLZ+FMz7w==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] + + '@oxlint/binding-linux-arm-musleabihf@1.73.0': + resolution: {integrity: sha512-d5j5GDU/2dMgjVhw7TQT9ITrsIr1Y02KEXKyVGIXUkD+KiaxE9TP65FS2ZdgTBemQvoRL+gSBdbrIm3cQIeacg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] + + '@oxlint/binding-linux-arm64-gnu@1.73.0': + resolution: {integrity: sha512-Eyf1SrP3+yR1DI3OJgOY2Pvrr9dWP9TK37xPaDYycwTtlGlI45erJAVIfH5/m/xosDt6BupJYEFi47bvbTuuyw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@oxlint/binding-linux-arm64-musl@1.73.0': + resolution: {integrity: sha512-IlT/OJApEDKaMmCooHuncgJZbbCe7T5QIWmTZBEtYscWvzPQuuEinVcid6kwQRVQOUdb7PUCz4jQHnaYXdfJXw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@oxlint/binding-linux-ppc64-gnu@1.73.0': + resolution: {integrity: sha512-L+JYcb/vdg5fmcH08V6o0YYLU28cTH1SPNulwJdvK9NK49aXSkYy6oNpKBmddArVOXYqNepriDGiZ04G54kh1Q==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@oxlint/binding-linux-riscv64-gnu@1.73.0': + resolution: {integrity: sha512-Qtk0g3bKV6OwWjIm7R8kQN1uOZRKQt/MODK2a8QfkwhTpXBD53ozx5XLVWLGDQAVyp2otLW4D2wB98XfAfMPGA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@oxlint/binding-linux-riscv64-musl@1.73.0': + resolution: {integrity: sha512-wX0NQKZVxltkAOVmzFcpOaMpdaUvsq1Eqpx9tkAfl71UdkTlSo1R4AdAnGccR1Fm2+TzFgZ22CyyGuZ41RDr/A==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [riscv64] + os: [linux] + libc: [musl] + + '@oxlint/binding-linux-s390x-gnu@1.73.0': + resolution: {integrity: sha512-vPe7UGBMWyiLTtnqS4xxgMQFSFGmtQwhwCxuiw6lXygaO6bVt0D8dFVg8Xv05eaiN3ybC0HXXHUAohFMFvqoCQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@oxlint/binding-linux-x64-gnu@1.73.0': + resolution: {integrity: sha512-2CwIWr9cemFC/CbRBWZvuk5mffz6ObmfFkfcC/9rTQ7f+icNhYr2kOjf9Rt8lLvugvkdGDOmkoVoFFHh6ClCTw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@oxlint/binding-linux-x64-musl@1.73.0': + resolution: {integrity: sha512-nDadfJgg7NBBxG0N560wOe7LLX5QiYp6qBaI7viuk5EUORFBktU/NfV0MbTqU3gTqQDCh4VyxKdo5VADxk9w8Q==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [musl] + + '@oxlint/binding-openharmony-arm64@1.73.0': + resolution: {integrity: sha512-wGjJC+NLH9xP+IKGn9RDW94ojJR/wPbg5WCnQjj/oReaOtCQthr8ws1zICe77JFmo4ouUdeTHHZL/ESGiF6Pmw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [openharmony] + + '@oxlint/binding-win32-arm64-msvc@1.73.0': + resolution: {integrity: sha512-I7X47GPGljw225YUQ5SbC/rb1Kkdrd0yQf0x+hYxeKS6DpfjMbo9ccQPQ6LNY6BoJQ1sHhgDUGuMn5Vg5gHT6w==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [win32] + + '@oxlint/binding-win32-ia32-msvc@1.73.0': + resolution: {integrity: sha512-5lWj+3h+74Fm1jYOO9qkJA4xkAlZA099DkXppuXsk7UpnpZLttsefrZU469vChGaG6hcSqrkKXQOvMTZtbjeNg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [ia32] + os: [win32] + + '@oxlint/binding-win32-x64-msvc@1.73.0': + resolution: {integrity: sha512-WaNRvh4f6zY9CvUQk2YoA1O90ieWrIklI84+HXFr9Isjz9CSESrdqo/RtIYt4Dll/cAchqGDMehfaZd0vqEFZw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [win32] + + '@oxlint/plugins@1.73.0': + resolution: {integrity: sha512-OhgMQeMmZA0dcFcX4/priaJZWdFECxiClgq6mRX6aatZEcV9PbKC3P3/v8U1hVjviT1i5U+vR8lAtBV6m4FXAA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + '@polka/url@1.0.0-next.29': + resolution: {integrity: sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==} + + '@protobufjs/aspromise@1.1.2': + resolution: {integrity: sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==} + + '@protobufjs/base64@1.1.2': + resolution: {integrity: sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==} + + '@protobufjs/codegen@2.0.5': + resolution: {integrity: sha512-zgXFLzW3Ap33e6d0Wlj4MGIm6Ce8O89n/apUaGNB/jx+hw+ruWEp7EwGUshdLKVRCxZW12fp9r40E1mQrf/34g==} + + '@protobufjs/eventemitter@1.1.1': + resolution: {integrity: sha512-vW1GmwMZNnL+gMRaovlh9yZX74kc+TTU3FObkkurpMaRtBfLP3ldjS9KQWlwZgraRE0+dheEEoAxdzcJQ8eXZg==} + + '@protobufjs/fetch@1.1.1': + resolution: {integrity: sha512-GpptLrs57adMSuHi3VNj0mAF8dwh36LMaYF6XyJ6JMWlVsc+t42tm1HSEDmOs3A8fC9yyeisgLhsTVQokOZ0zw==} + + '@protobufjs/float@1.0.2': + resolution: {integrity: sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==} + + '@protobufjs/path@1.1.2': + resolution: {integrity: sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==} + + '@protobufjs/pool@1.1.0': + resolution: {integrity: sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==} + + '@protobufjs/utf8@1.1.2': + resolution: {integrity: sha512-b1UQwcEZ4yCnMCD8DAL1VlbvBJE9/IX4FTIp7BG1xYpf29SLazLSrqUkj4w7Y5y7cCVP6E5tcqqcI0xemPkHug==} + + '@rolldown/binding-android-arm64@1.0.0-rc.12': + resolution: {integrity: sha512-pv1y2Fv0JybcykuiiD3qBOBdz6RteYojRFY1d+b95WVuzx211CRh+ytI/+9iVyWQ6koTh5dawe4S/yRfOFjgaA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [android] + + '@rolldown/binding-darwin-arm64@1.0.0-rc.12': + resolution: {integrity: sha512-cFYr6zTG/3PXXF3pUO+umXxt1wkRK/0AYT8lDwuqvRC+LuKYWSAQAQZjCWDQpAH172ZV6ieYrNnFzVVcnSflAg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [darwin] + + '@rolldown/binding-darwin-x64@1.0.0-rc.12': + resolution: {integrity: sha512-ZCsYknnHzeXYps0lGBz8JrF37GpE9bFVefrlmDrAQhOEi4IOIlcoU1+FwHEtyXGx2VkYAvhu7dyBf75EJQffBw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [darwin] + + '@rolldown/binding-freebsd-x64@1.0.0-rc.12': + resolution: {integrity: sha512-dMLeprcVsyJsKolRXyoTH3NL6qtsT0Y2xeuEA8WQJquWFXkEC4bcu1rLZZSnZRMtAqwtrF/Ib9Ddtpa/Gkge9Q==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [freebsd] + + '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.12': + resolution: {integrity: sha512-YqWjAgGC/9M1lz3GR1r1rP79nMgo3mQiiA+Hfo+pvKFK1fAJ1bCi0ZQVh8noOqNacuY1qIcfyVfP6HoyBRZ85Q==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] + + '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.12': + resolution: {integrity: sha512-/I5AS4cIroLpslsmzXfwbe5OmWvSsrFuEw3mwvbQ1kDxJ822hFHIx+vsN/TAzNVyepI/j/GSzrtCIwQPeKCLIg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-arm64-musl@1.0.0-rc.12': + resolution: {integrity: sha512-V6/wZztnBqlx5hJQqNWwFdxIKN0m38p8Jas+VoSfgH54HSj9tKTt1dZvG6JRHcjh6D7TvrJPWFGaY9UBVOaWPw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.12': + resolution: {integrity: sha512-AP3E9BpcUYliZCxa3w5Kwj9OtEVDYK6sVoUzy4vTOJsjPOgdaJZKFmN4oOlX0Wp0RPV2ETfmIra9x1xuayFB7g==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-s390x-gnu@1.0.0-rc.12': + resolution: {integrity: sha512-nWwpvUSPkoFmZo0kQazZYOrT7J5DGOJ/+QHHzjvNlooDZED8oH82Yg67HvehPPLAg5fUff7TfWFHQS8IV1n3og==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-x64-gnu@1.0.0-rc.12': + resolution: {integrity: sha512-RNrafz5bcwRy+O9e6P8Z/OCAJW/A+qtBczIqVYwTs14pf4iV1/+eKEjdOUta93q2TsT/FI0XYDP3TCky38LMAg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-x64-musl@1.0.0-rc.12': + resolution: {integrity: sha512-Jpw/0iwoKWx3LJ2rc1yjFrj+T7iHZn2JDg1Yny1ma0luviFS4mhAIcd1LFNxK3EYu3DHWCps0ydXQ5i/rrJ2ig==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [musl] + + '@rolldown/binding-openharmony-arm64@1.0.0-rc.12': + resolution: {integrity: sha512-vRugONE4yMfVn0+7lUKdKvN4D5YusEiPilaoO2sgUWpCvrncvWgPMzK00ZFFJuiPgLwgFNP5eSiUlv2tfc+lpA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [openharmony] + + '@rolldown/binding-wasm32-wasi@1.0.0-rc.12': + resolution: {integrity: sha512-ykGiLr/6kkiHc0XnBfmFJuCjr5ZYKKofkx+chJWDjitX+KsJuAmrzWhwyOMSHzPhzOHOy7u9HlFoa5MoAOJ/Zg==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + + '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.12': + resolution: {integrity: sha512-5eOND4duWkwx1AzCxadcOrNeighiLwMInEADT0YM7xeEOOFcovWZCq8dadXgcRHSf3Ulh1kFo/qvzoFiCLOL1Q==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [win32] + + '@rolldown/binding-win32-x64-msvc@1.0.0-rc.12': + resolution: {integrity: sha512-PyqoipaswDLAZtot351MLhrlrh6lcZPo2LSYE+VDxbVk24LVKAGOuE4hb8xZQmrPAuEtTZW8E6D2zc5EUZX4Lw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [win32] + + '@rolldown/pluginutils@1.0.0-rc.12': + resolution: {integrity: sha512-HHMwmarRKvoFsJorqYlFeFRzXZqCt2ETQlEDOb9aqssrnVBB1/+xgTGtuTrIk5vzLNX1MjMtTf7W9z3tsSbrxw==} + + '@silvia-odwyer/photon-node@0.3.4': + resolution: {integrity: sha512-bnly4BKB3KDTFxrUIcgCLbaeVVS8lrAkri1pEzskpmxu9MdfGQTy8b8EgcD83ywD3RPMsIulY8xJH5Awa+t9fA==} + + '@smithy/core@3.29.5': + resolution: {integrity: sha512-i0dk2t5B+CwV/dcJdUHILYkOQF5lof8f44dFCfDWToGCxjT9YQ+CgHqTAvJxzc3+zqQwm2QtVoJ5IqiNar/CnQ==} + engines: {node: '>=18.0.0'} + + '@smithy/credential-provider-imds@4.4.10': + resolution: {integrity: sha512-MJenAe4OKRZUo1LdYYFDCsSHxaHvInIU/z52GsheO9vl1/VSySVCr0zkyKD6TFiGkSUaWGxvKZ/70OvgUZR5HQ==} + engines: {node: '>=18.0.0'} + + '@smithy/fetch-http-handler@5.6.7': + resolution: {integrity: sha512-3zpg8yqqyXzoK2TsRDdkqVOj2RDBFfLXwCczOZ5c7TWB4eiaebfSCsbMjDPYB3PJ9ihV62QaeadZ+wLadZtNGA==} + engines: {node: '>=18.0.0'} + + '@smithy/is-array-buffer@2.2.0': + resolution: {integrity: sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==} + engines: {node: '>=14.0.0'} + + '@smithy/node-http-handler@4.7.3': + resolution: {integrity: sha512-/jPhevcTFPMVl6KNjbaI47iOg1zxC7IsnX4PQDGVZKMFceOXtB8IEYaB7a9VvkP/3oC60WzTeKocvSI7vLT0vA==} + engines: {node: '>=18.0.0'} + + '@smithy/node-http-handler@4.9.7': + resolution: {integrity: sha512-wCU8HCLjAtAVqxxe0j2xff9LcEPw3yjBbg5IdQDIYFnxnPxbxcSLc7rgex7kqm9L/WYOnJEgaWQlfDkZleozMA==} + engines: {node: '>=18.0.0'} + + '@smithy/signature-v4@5.6.6': + resolution: {integrity: sha512-efP6DN3UTFrzIsGO42/xcabv8jU7+9nwEdphFUH7yL0k010ERyAWaO41KFQIDLcFZLZ8xzIQr4wplFxNzslSGQ==} + engines: {node: '>=18.0.0'} + + '@smithy/types@4.16.1': + resolution: {integrity: sha512-0JFs3V2y2M9tKW5na/qxe69Zv+uxLMO7QBbhxF/FHu/Gp2NFZAAL9tWl9PU02xxo07pb3G9FTyjNc6D5uZrJIg==} + engines: {node: '>=18.0.0'} + + '@smithy/util-buffer-from@2.2.0': + resolution: {integrity: sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==} + engines: {node: '>=14.0.0'} + + '@smithy/util-utf8@2.3.0': + resolution: {integrity: sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==} + engines: {node: '>=14.0.0'} + + '@standard-schema/spec@1.1.0': + resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} + + '@testing-library/dom@10.4.1': + resolution: {integrity: sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==} + engines: {node: '>=18'} + + '@testing-library/user-event@14.6.1': + resolution: {integrity: sha512-vq7fv0rnt+QTXgPxr5Hjc210p6YKq2kmdziLgnsZGgLJ9e6VAShx1pACLuRjd/AS/sr7phAR58OIIpf0LlmQNw==} + engines: {node: '>=12', npm: '>=6'} + peerDependencies: + '@testing-library/dom': '>=7.21.4' + + '@tybys/wasm-util@0.10.3': + resolution: {integrity: sha512-F3fo1MYrRJYL3zER0OUOmkutjr1Vp23m7OsSgp7nq4SP6OqX6C/56XFIPAl5bt3zaBRjmW7SGz3u/6LwFpYcOg==} + + '@types/aria-query@5.0.4': + resolution: {integrity: sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==} + + '@types/chai@5.2.3': + resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==} + + '@types/deep-eql@4.0.2': + resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} + + '@types/estree@1.0.9': + resolution: {integrity: sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==} + + '@types/node@26.1.1': + resolution: {integrity: sha512-nxAkRSVkN1Y0JC1W8ky/fTfkGsMmcrRsbx+3XoZE+rMOX71kLYTV7fLXpqud1GpbpP5TuffXFqfX7fH2GgZREw==} + + '@types/retry@0.12.0': + resolution: {integrity: sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==} + + '@vitest/browser-preview@4.1.10': + resolution: {integrity: sha512-14MJrL59ZFkqXLjwfSk6RzTDy5Czf9UG4+8q8L6Gxjs2aPjEce/cVNYV14bXAc2BvMjUNu904+ZEZA1Xc1wtvQ==} + peerDependencies: + vitest: 4.1.10 + + '@vitest/browser@4.1.10': + resolution: {integrity: sha512-UDwuWGwXj646CBx/bQHOaJSX7np0I8JL/UKQYa1e4QrVHH8VdWtx8eaOuf8sy0ShwDgR6NjJAsp5eF6vjF6qng==} + peerDependencies: + vitest: 4.1.10 + + '@vitest/expect@4.1.10': + resolution: {integrity: sha512-YsCn+qAk1GWjQOWFEsEcL2gNQ0zmVmQu3T03qP6UyjhtmdtwtbuI+DASn/7iQB3HGTXkdBwGddzxPlmiql5vlA==} + + '@vitest/mocker@4.1.10': + resolution: {integrity: sha512-v0xaezt+DKEmKfaxg133ldzADrwLGd7Ze1MfQQTYfvs8OqZIwbxyxaYURivwV7sWy5fqn3rH5uOrSp07bp44Ow==} + peerDependencies: + msw: ^2.4.9 + vite: ^6.0.0 || ^7.0.0 || ^8.0.0 + peerDependenciesMeta: + msw: + optional: true + vite: + optional: true + + '@vitest/pretty-format@4.1.10': + resolution: {integrity: sha512-W1HsjSH4MXQ9YfmmhLAoIYf1HRfekQCGngeIgcei6MP5QQGWUe0gkopdZQaVCFO+JDJMrAJGwa5pRpNpvy4P8Q==} + + '@vitest/runner@4.1.10': + resolution: {integrity: sha512-IKI6kpIH+LmpROplyLwBBaCfMgOZOMsygVa6BARD6ahA04VRuJSa6OaVG7kRvSEMD870Vd91rSSw0eegtWyLGg==} + + '@vitest/snapshot@4.1.10': + resolution: {integrity: sha512-xRkfOT1qpTAi/Ti4Y1LtfRc3kEuqxGw59eN2jN9pRWMtS/XDevekhcFSqvQqjUNGksfjMJu3Y+oJ+4Ypn2OaJw==} + + '@vitest/spy@4.1.10': + resolution: {integrity: sha512-PLf/Ugvoq5wO/b4rwYCR1h2PSIdXz7wnkQFMiUpLdtM7l6pqVFcQIBEHyT1+l+cj7mNwAfZHzqXqDyjvOuwbDw==} + + '@vitest/utils@4.1.10': + resolution: {integrity: sha512-fy9am/HWxbaGt/Sawrp90vt6Y6jQwf1RX77cz3uwoJwJVMli/e1IEwRPnMNJ7vKfPTwo0diXifkpPvwH9v7nGA==} + + '@voidzero-dev/vite-plus-core@0.2.5': + resolution: {integrity: sha512-fxMGImIOyOipwCX6udOD1S9Q1xXfaimv6kcRgLWBxLsy7oryAyXqVfoYr7bmmAdSDlIutHRgvA6eiqfJjARTHA==} + engines: {node: ^20.19.0 || ^22.18.0 || >=24.11.0} + peerDependencies: + '@arethetypeswrong/core': ^0.18.1 + '@types/node': ^20.19.0 || >=22.12.0 + '@vitejs/devtools': ^0.3.0 + esbuild: ^0.27.0 || ^0.28.0 + jiti: '>=1.21.0' + less: ^4.0.0 + publint: ^0.3.8 + sass: ^1.70.0 + sass-embedded: ^1.70.0 + stylus: '>=0.54.8' + sugarss: ^5.0.0 + terser: ^5.16.0 + tsx: ^4.8.1 + typescript: ^5.0.0 || ^6.0.0 || ^7.0.0 + unplugin-unused: ^0.5.0 + unrun: '*' + yaml: ^2.4.2 + peerDependenciesMeta: + '@arethetypeswrong/core': + optional: true + '@types/node': + optional: true + '@vitejs/devtools': + optional: true + esbuild: + optional: true + jiti: + optional: true + less: + optional: true + publint: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + typescript: + optional: true + unplugin-unused: + optional: true + unrun: + optional: true + yaml: + optional: true + + '@voidzero-dev/vite-plus-darwin-arm64@0.2.5': + resolution: {integrity: sha512-M62R3gmoHZbhL+UHHTevJi9a3aJyY+Eid8GAOtxEsRMkHmJ8IwOSOBERXM3C4CULvEa/ORYKiUQnqo5ewF44Fw==} + engines: {node: '>=20.0.0'} + cpu: [arm64] + os: [darwin] + + '@voidzero-dev/vite-plus-darwin-x64@0.2.5': + resolution: {integrity: sha512-a1h1dv/7QcnlqlN6yZBIPjgHSxbeyY/IcTxepTAOpPB7eAi1RPb1+cCkwo7c3MnDPJb3iZzwD0rm2+fOUoZp0w==} + engines: {node: '>=20.0.0'} + cpu: [x64] + os: [darwin] + + '@voidzero-dev/vite-plus-linux-arm64-gnu@0.2.5': + resolution: {integrity: sha512-t8bS8fA2a3OSAEaHdgJFmzd0TkWh9yAxIoKAprsOleIcUEmzDxhH8drTj9TPyTrChKpv0aJTsK5ZK3RzcCUkdg==} + engines: {node: '>=20.0.0'} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@voidzero-dev/vite-plus-linux-arm64-musl@0.2.5': + resolution: {integrity: sha512-vnsjQI3LEUYFMR3LCMqtAxaZav8BNypSAf8YzcFu9+Qtd1dcCrAUz9RrEBCIIqEiw0p0O+SrX2CcMHSSnzWbKA==} + engines: {node: '>=20.0.0'} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@voidzero-dev/vite-plus-linux-x64-gnu@0.2.5': + resolution: {integrity: sha512-3xlXrxIz8UKGcGefifkhoMpsTIMdgqikwQuDUqgG5O7/b2tetpK9aoT4C9b2fQGkhYUpCJwdD83AtywQ4EhoWA==} + engines: {node: '>=20.0.0'} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@voidzero-dev/vite-plus-linux-x64-musl@0.2.5': + resolution: {integrity: sha512-XylGiayBoD7vt1/SKfmh5FoBNdKI5EWlIb5Sd9A1oTQW8DLi97VcEgVZ7vh/8kG1OEe+9z1lyRis6RDql2KDUw==} + engines: {node: '>=20.0.0'} + cpu: [x64] + os: [linux] + libc: [musl] + + '@voidzero-dev/vite-plus-win32-arm64-msvc@0.2.5': + resolution: {integrity: sha512-eN1zvUAqXVXOC72WOVu9gz/jxr9tBrga/5lCsDjHeZDJ/bzhDVJ4eYZUDZzasPE1QCbAhmuIJsv0WzEUxdGAzA==} + engines: {node: '>=20.0.0'} + cpu: [arm64] + os: [win32] + + '@voidzero-dev/vite-plus-win32-x64-msvc@0.2.5': + resolution: {integrity: sha512-jgXVYK8crlR5cQ07vX5Qw2K+boNLKMxarPgE3/AyPPRUtGC8iCpZz0RCPoJHDmTh7848Ra5Fnt4LEfbcUv1ByQ==} + engines: {node: '>=20.0.0'} + cpu: [x64] + os: [win32] + + '@yuku-codegen/binding-darwin-arm64@0.5.48': + resolution: {integrity: sha512-yo96Oef12WzqnphInfz/eexVse3+kWgfGS5g2S3rFS3dcGn1ENW9xLFDZUP9rh+yP76DOq38wBoFi1+I9+6qBg==} + cpu: [arm64] + os: [darwin] + + '@yuku-codegen/binding-darwin-x64@0.5.48': + resolution: {integrity: sha512-aRCTw0EZC4bVosmw//0OMYP5tGWFE0Cu5yUBFkUbhXx/iBzvORcJ2xPNlOp/vtCCo9Ys4vp8b0DigJV6uOVb2g==} + cpu: [x64] + os: [darwin] + + '@yuku-codegen/binding-freebsd-x64@0.5.48': + resolution: {integrity: sha512-CA0AQAEApDkbw51PdLWMtKPJ41/7rvXsS3SJs+phG7fHJI+MuFzWuLbkucZfZoEOiDscmcsfYIdgL8BsfuyKKQ==} + cpu: [x64] + os: [freebsd] + + '@yuku-codegen/binding-linux-arm-gnu@0.5.48': + resolution: {integrity: sha512-DuSQlk8bH4gpmW3/00P0NLagAcMv8jOxjT40cQmxKRkktr+SUOALCfkT89tdDq3qtY95NR2GXOZ7AjNh7KKqCw==} + cpu: [arm] + os: [linux] + libc: [glibc] + + '@yuku-codegen/binding-linux-arm-musl@0.5.48': + resolution: {integrity: sha512-bxj4Ee+wlaJcWJwft2ReJXWw5sfl1qavDz6+dlRdU1xfTEtjPSNiAWhiCHnJR0R4Ygd57DnzSQmAVGvFv6RcGw==} + cpu: [arm] + os: [linux] + libc: [musl] + + '@yuku-codegen/binding-linux-arm64-gnu@0.5.48': + resolution: {integrity: sha512-mk5JVWh+0JOe5ue8k17kbYX8uGBoKt3ZqoCyxNh4nYAAcX7+X1tFUiU7jbjctu4vHeejCBFSTdQ021+V31cUCQ==} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@yuku-codegen/binding-linux-arm64-musl@0.5.48': + resolution: {integrity: sha512-4q3vkrNghbllyxOm2KesFLxCPKHF7r3JyQ7BWZccY1j2Y05yKoIFhoWCqIuQ2W/dpte9RI0+OVfwyxnrKg6fkA==} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@yuku-codegen/binding-linux-x64-gnu@0.5.48': + resolution: {integrity: sha512-csd4M1EVrGaohM8acM6gq1zpUA/Rwe2ulUMBKUcwQXm/k6n7cq1A++qdew78SOVb4do3JH1WE+WFwoGQAcWc1w==} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@yuku-codegen/binding-linux-x64-musl@0.5.48': + resolution: {integrity: sha512-KcDuEOT+GFoVKdvAWOv1v9iYjwnmvMZlO+j1Rw+5PYdeFLGWGzv/DD11y4SAAdwXIFcil4T0hibeIaF82WStMg==} + cpu: [x64] + os: [linux] + libc: [musl] + + '@yuku-codegen/binding-win32-arm64@0.5.48': + resolution: {integrity: sha512-HI8qNrI8dWM5BuqIMKsqornRvTNFrE6sm5zToIJ9YIa9zt5+29P7fJ7Nr39EVf6dAWSb6q7JSpScJnRsQ+FgZA==} + cpu: [arm64] + os: [win32] + + '@yuku-codegen/binding-win32-x64@0.5.48': + resolution: {integrity: sha512-X5YWJLO6EfBZpeBqO0AYESnUizbpFDWArcvVD61w0PEWQ3CaFRLnbQXs+kpM4ZZfGMfIE22zfA08QSY67q7TNQ==} + cpu: [x64] + os: [win32] + + '@yuku-parser/binding-darwin-arm64@0.5.48': + resolution: {integrity: sha512-If8mb7HH3vqghJ2NNZ8SuHfhsnjVzOxJpB8xcNOXS5WjYrs2mUhHIh5KOIvK13hDOzh0htGeGK3A6MsiEqE7HQ==} + cpu: [arm64] + os: [darwin] + + '@yuku-parser/binding-darwin-x64@0.5.48': + resolution: {integrity: sha512-EimvPXfspzxf1K11eB6tCW5oiQEXB8g84T2wP1TwzQagdDKo33bkmmVF0B32vTIpXnk/Ifu5IB61izZ1MylljA==} + cpu: [x64] + os: [darwin] + + '@yuku-parser/binding-freebsd-x64@0.5.48': + resolution: {integrity: sha512-0GcUMrumLHheThY9r5Tp46gaZYzn0irWPS1Zba6WY+vVQfhUtzGiWgXxI6tuXX0N32kEaaEVRpkKctvo6Kx3aQ==} + cpu: [x64] + os: [freebsd] + + '@yuku-parser/binding-linux-arm-gnu@0.5.48': + resolution: {integrity: sha512-8S5T5wjCC73dmmpQeZ49aYsSunIUM3D4Fc6rdK96c+Ayg/p3FmeSPF3xuLZHejcTmqJIIvnbfPlUF+rB6DITjQ==} + cpu: [arm] + os: [linux] + libc: [glibc] + + '@yuku-parser/binding-linux-arm-musl@0.5.48': + resolution: {integrity: sha512-tTmbxvnUHcK2/crS9547vk2SMmsajH1yqJ8ltXhIuHJgqR1v+d9n9KT+kSayo/5CS76LegeYxhMFjEivBH2hFA==} + cpu: [arm] + os: [linux] + libc: [musl] + + '@yuku-parser/binding-linux-arm64-gnu@0.5.48': + resolution: {integrity: sha512-KGYCBMqI2zfwyhgq5tpPVNe7jpUeYTBm8DhjdS+zqWNumde/PEC170QE5RHxcOAlsirIDeIUk0jqx+r/axoFSw==} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@yuku-parser/binding-linux-arm64-musl@0.5.48': + resolution: {integrity: sha512-2wTSMsCSXLTc2lZUjMAuU5X4cje55u205WJqfV5NWNF6j9pW/tXyxr15dJeekj8ziLqBXzIsj4DbRh4sY/WcjA==} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@yuku-parser/binding-linux-x64-gnu@0.5.48': + resolution: {integrity: sha512-d/6v9UnGglVu1WC2JQyv/5aWSi5fXZeGSlidCfmHp4+N65N1GDKUnFtys5MK5eAPeAjTgSHGGtOc/yCcKTlv3A==} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@yuku-parser/binding-linux-x64-musl@0.5.48': + resolution: {integrity: sha512-gX19gw6u4ApPy7SYMPKfFlEkrtj6WlORvrTKK3sBQqjyV+8+mUAkQgxXNjHw4RnOiAmVYg7TOlZcg8d+Qqod9A==} + cpu: [x64] + os: [linux] + libc: [musl] + + '@yuku-parser/binding-win32-arm64@0.5.48': + resolution: {integrity: sha512-w6cQQLbqj3Jcom5Q7ifm103NUOQ9d+Cb4VU5lkrZDjMnwVJ9Hzzg1vCQR7miJuF44vhCXldbme5UryE3giEKlA==} + cpu: [arm64] + os: [win32] + + '@yuku-parser/binding-win32-x64@0.5.48': + resolution: {integrity: sha512-4gO0HmG7fzFxrw1rs0dUdnnaY9YgennjETqDWrTSp7x9fmTUOAoN4VsMfP7YyliQeG1WJJHc55O+rOhmsLppow==} + cpu: [x64] + os: [win32] + + '@yuku-toolchain/types@0.5.43': + resolution: {integrity: sha512-kSpvPntnXw5+lYjO71ffBEnQ5ycQ74KGIYknh0TS4xeyCuBkOqxyJumxZkMhLBBUCLjDAbx2+Icnr3Zh4ftjpQ==} + + agent-base@7.1.4: + resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} + engines: {node: '>= 14'} + + ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + + ansi-styles@5.2.0: + resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} + engines: {node: '>=10'} + + aria-query@5.3.0: + resolution: {integrity: sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==} + + assertion-error@2.0.1: + resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} + engines: {node: '>=12'} + + balanced-match@4.0.4: + resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==} + engines: {node: 18 || 20 || >=22} + + base64-js@1.5.1: + resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + + bignumber.js@9.3.1: + resolution: {integrity: sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ==} + + bowser@2.14.1: + resolution: {integrity: sha512-tzPjzCxygAKWFOJP011oxFHs57HzIhOEracIgAePE4pqB3LikALKnSzUyU4MGs9/iCEUuHlAJTjTc5M+u7YEGg==} + + brace-expansion@5.0.7: + resolution: {integrity: sha512-7oFy703dxfY3/NLxC1fh2SUCQ0H9rmAY+5EpDVfXjUTTs+HEwR2nYaqLv+GWcTsumwxPfiz6CzCNkwXwBUwqCA==} + engines: {node: 18 || 20 || >=22} + + buffer-equal-constant-time@1.0.1: + resolution: {integrity: sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==} + + chai@6.2.2: + resolution: {integrity: sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==} + engines: {node: '>=18'} + + chalk@5.6.2: + resolution: {integrity: sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==} + engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} + + convert-source-map@2.0.0: + resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + + cross-spawn@7.0.6: + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} + engines: {node: '>= 8'} + + data-uri-to-buffer@4.0.1: + resolution: {integrity: sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==} + engines: {node: '>= 12'} + + debug@4.4.3: + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + dequal@2.0.3: + resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} + engines: {node: '>=6'} + + detect-libc@2.1.2: + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} + engines: {node: '>=8'} + + diff@8.0.4: + resolution: {integrity: sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw==} + engines: {node: '>=0.3.1'} + + dom-accessibility-api@0.5.16: + resolution: {integrity: sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==} + + ecdsa-sig-formatter@1.0.11: + resolution: {integrity: sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==} + + es-module-lexer@2.3.0: + resolution: {integrity: sha512-KLdwQm2NvGLDkQDCGvmiQrhkd0JbMzXthwQAUgWjQuQdBLFa3eiBP5arXZyA+f8x+x7OXgud6bq2rxjGtHV2tw==} + + esbuild@0.27.7: + resolution: {integrity: sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==} + engines: {node: '>=18'} + hasBin: true + + estree-walker@3.0.3: + resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} + + expect-type@1.4.0: + resolution: {integrity: sha512-KfYbmpRm0VbLjEvVa9yGwCi9GI34xvi7A/HXYWQO65CSD2u3MczUJSuwXKFIxlGsgBQizV9q5J9NHj4VG0n+pA==} + engines: {node: '>=12.0.0'} + + extend@3.0.2: + resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} + + fdir@6.5.0: + resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} + engines: {node: '>=12.0.0'} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + + fetch-blob@3.2.0: + resolution: {integrity: sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==} + engines: {node: ^12.20 || >= 14.13} + + formdata-polyfill@4.0.10: + resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==} + engines: {node: '>=12.20.0'} + + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + gaxios@7.2.0: + resolution: {integrity: sha512-CUVb4wcYe+771XevyH6HtGmXFAGGKkIC3kswAP8Z1JCe0j80JMaTPZH930DWFrvo0atjh18Arc0pEyUCWa5bfg==} + engines: {node: '>=18'} + + gcp-metadata@8.1.2: + resolution: {integrity: sha512-zV/5HKTfCeKWnxG0Dmrw51hEWFGfcF2xiXqcA3+J90WDuP0SvoiSO5ORvcBsifmx/FoIjgQN3oNOGaQ5PhLFkg==} + engines: {node: '>=18'} + + get-east-asian-width@1.6.0: + resolution: {integrity: sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA==} + engines: {node: '>=18'} + + get-tsconfig@4.14.0: + resolution: {integrity: sha512-yTb+8DXzDREzgvYmh6s9vHsSVCHeC0G3PI5bEXNBHtmshPnO+S5O7qgLEOn0I5QvMy6kpZN8K1NKGyilLb93wA==} + + glob@13.0.6: + resolution: {integrity: sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==} + engines: {node: 18 || 20 || >=22} + + google-auth-library@10.9.0: + resolution: {integrity: sha512-xtvUqvINPhTaBm7nXqlYPcrMHJPm1lCNdSovxnKKhTm+4JsvQ+KGVYJViLoH9Yxu8w+T0Qv5HubzYT9BLrppJg==} + engines: {node: '>=18'} + + google-logging-utils@1.1.3: + resolution: {integrity: sha512-eAmLkjDjAFCVXg7A1unxHsLf961m6y17QFqXqAXGj/gVkKFrEICfStRfwUlGNfeCEjNRa32JEWOUTlYXPyyKvA==} + engines: {node: '>=14'} + + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + + highlight.js@10.7.3: + resolution: {integrity: sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==} + + hosted-git-info@9.0.3: + resolution: {integrity: sha512-Hc+ghLoSt6QaYZUv0WBiIvmMDZuZZ7oaDvdH8MbfOO4lOsxdXLEvuC6ePoGs9H1X9oCLyq6+NVN0MKqD+ydxyg==} + engines: {node: ^20.17.0 || >=22.9.0} + + http-proxy-agent@7.0.2: + resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==} + engines: {node: '>= 14'} + + https-proxy-agent@7.0.6: + resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} + engines: {node: '>= 14'} + + ignore@7.0.5: + resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==} + engines: {node: '>= 4'} + + isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + + jiti@2.7.0: + resolution: {integrity: sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==} + hasBin: true + + js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + + json-bigint@1.0.0: + resolution: {integrity: sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==} + + json-schema-to-ts@3.1.1: + resolution: {integrity: sha512-+DWg8jCJG2TEnpy7kOm/7/AxaYoaRbjVB4LFZLySZlWn8exGs3A4OLJR966cVvU26N7X9TWxl+Jsw7dzAqKT6g==} + engines: {node: '>=16'} + + jwa@2.0.1: + resolution: {integrity: sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==} + + jws@4.0.1: + resolution: {integrity: sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==} + + lightningcss-android-arm64@1.32.0: + resolution: {integrity: sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [android] + + lightningcss-darwin-arm64@1.32.0: + resolution: {integrity: sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [darwin] + + lightningcss-darwin-x64@1.32.0: + resolution: {integrity: sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [darwin] + + lightningcss-freebsd-x64@1.32.0: + resolution: {integrity: sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [freebsd] + + lightningcss-linux-arm-gnueabihf@1.32.0: + resolution: {integrity: sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==} + engines: {node: '>= 12.0.0'} + cpu: [arm] + os: [linux] + + lightningcss-linux-arm64-gnu@1.32.0: + resolution: {integrity: sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + libc: [glibc] + + lightningcss-linux-arm64-musl@1.32.0: + resolution: {integrity: sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + libc: [musl] + + lightningcss-linux-x64-gnu@1.32.0: + resolution: {integrity: sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + libc: [glibc] + + lightningcss-linux-x64-musl@1.32.0: + resolution: {integrity: sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + libc: [musl] + + lightningcss-win32-arm64-msvc@1.32.0: + resolution: {integrity: sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [win32] + + lightningcss-win32-x64-msvc@1.32.0: + resolution: {integrity: sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [win32] + + lightningcss@1.32.0: + resolution: {integrity: sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==} + engines: {node: '>= 12.0.0'} + + long@5.3.2: + resolution: {integrity: sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==} + + lru-cache@11.5.2: + resolution: {integrity: sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g==} + engines: {node: 20 || >=22} + + lz-string@1.5.0: + resolution: {integrity: sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==} + hasBin: true + + magic-string@0.30.21: + resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} + + marked@18.0.5: + resolution: {integrity: sha512-S6GcvALHg6K4ohtu4E7x0a1AqhAjp6cV8KhLSyN9qVapnzJkusVBxZRcIU9AeYsbe6P1hKDusSbEOzGyyuce6w==} + engines: {node: '>= 20'} + hasBin: true + + minimatch@10.2.5: + resolution: {integrity: sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==} + engines: {node: 18 || 20 || >=22} + + minipass@7.1.3: + resolution: {integrity: sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==} + engines: {node: '>=16 || 14 >=14.17'} + + mrmime@2.0.1: + resolution: {integrity: sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==} + engines: {node: '>=10'} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + nanoid@3.3.16: + resolution: {integrity: sha512-bzlKTyNJ7+LdGIIwy8ijFpIqEQIvafahV7eYykJ8Cvh42EdJeODoJ6gUJXpQJvej1BddH8OqTXZNE/KfbWAu8Q==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + node-domexception@1.0.0: + resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==} + engines: {node: '>=10.5.0'} + deprecated: Use your platform's native DOMException instead + + node-fetch@3.3.2: + resolution: {integrity: sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + obug@2.1.3: + resolution: {integrity: sha512-9miFgM2OFba7hB+pRgvtV84pYTBaoTHohvmIgiRt6dRIzbwEOIaNaP+dIlGs2fNFoB0SeISs0Jz5WFVRid6Xyg==} + engines: {node: '>=12.20.0'} + + openai@6.26.0: + resolution: {integrity: sha512-zd23dbWTjiJ6sSAX6s0HrCZi41JwTA1bQVs0wLQPZ2/5o2gxOJA5wh7yOAUgwYybfhDXyhwlpeQf7Mlgx8EOCA==} + hasBin: true + peerDependencies: + ws: ^8.18.0 + zod: ^3.25 || ^4.0 + peerDependenciesMeta: + ws: + optional: true + zod: + optional: true + + oxfmt@0.58.0: + resolution: {integrity: sha512-8feG/7NVEHDVwc1OUpP6Pks+TnaDFUw2jLLFIMi5bcmmwxAX2wBQvjSzj62RRTYBf2Op1Wt8xbkmagmPTR5ETg==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + peerDependencies: + svelte: ^5.0.0 + vite-plus: '*' + peerDependenciesMeta: + svelte: + optional: true + vite-plus: + optional: true + + oxlint-tsgolint@0.24.0: + resolution: {integrity: sha512-giCk5sEvG02d5tzPmFMX3hem8ndzEEu1xvGYS5OwNfO2WGl6ZVxt5LjE0yiMDoz94INI7XkXwgFAQiydPvVHDw==} + hasBin: true + + oxlint@1.73.0: + resolution: {integrity: sha512-u91G9TJzU6yqKWNZUYprQB07W7YvntZXaRxQ6CkoytepYhLWUXWsr1M8zUJ34VatNPuUAr3Z8GH+O2A331CluQ==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + peerDependencies: + oxlint-tsgolint: '>=0.24.0' + vite-plus: '*' + peerDependenciesMeta: + oxlint-tsgolint: + optional: true + vite-plus: + optional: true + + p-retry@4.6.2: + resolution: {integrity: sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==} + engines: {node: '>=8'} + + partial-json@0.1.7: + resolution: {integrity: sha512-Njv/59hHaokb/hRUjce3Hdv12wd60MtM9Z5Olmn+nehe0QDAsRtRbJPvJ0Z91TusF0SuZRIvnM+S4l6EIP8leA==} + + path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + + path-scurry@2.0.2: + resolution: {integrity: sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==} + engines: {node: 18 || 20 || >=22} + + pathe@2.0.3: + resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + picomatch@4.0.5: + resolution: {integrity: sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==} + engines: {node: '>=12'} + + pngjs@7.0.0: + resolution: {integrity: sha512-LKWqWJRhstyYo9pGvgor/ivk2w94eSjE3RGVuzLGlr3NmD8bf7RcYGze1mNdEHRP6TRP6rMuDHk5t44hnTRyow==} + engines: {node: '>=14.19.0'} + + postcss@8.5.19: + resolution: {integrity: sha512-Mz8SaolMd8nB+G13WkORcxQKHZ/NE4xXevtkJHVuG+guo9/wYKlIMTKAqGdEmYOXR2ijPjTYNHssizdaVSUNdQ==} + engines: {node: ^10 || ^12 || >=14} + + pretty-format@27.5.1: + resolution: {integrity: sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + + proper-lockfile@4.1.2: + resolution: {integrity: sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA==} + + protobufjs@7.6.5: + resolution: {integrity: sha512-/FPD0nUc9jH6rfFjji9IBqOz4pcSE3CsT1m7Ep6Mdb0LxSUMj8hgl6GomOvZzpNpAqqGaXA0P3VSrZLFzIhQrw==} + engines: {node: '>=12.0.0'} + + react-is@17.0.2: + resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==} + + resolve-pkg-maps@1.0.0: + resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} + + retry@0.12.0: + resolution: {integrity: sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==} + engines: {node: '>= 4'} + + retry@0.13.1: + resolution: {integrity: sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==} + engines: {node: '>= 4'} + + rolldown@1.0.0-rc.12: + resolution: {integrity: sha512-yP4USLIMYrwpPHEFB5JGH1uxhcslv6/hL0OyvTuY+3qlOSJvZ7ntYnoWpehBxufkgN0cvXxppuTu5hHa/zPh+A==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + + safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + + semver@7.8.0: + resolution: {integrity: sha512-AcM7dV/5ul4EekoQ29Agm5vri8JNqRyj39o0qpX6vDF2GZrtutZl5RwgD1XnZjiTAfncsJhMI48QQH3sN87YNA==} + engines: {node: '>=10'} + hasBin: true + + shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + + shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + + siginfo@2.0.0: + resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} + + signal-exit@3.0.7: + resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} + + sirv@3.0.2: + resolution: {integrity: sha512-2wcC/oGxHis/BoHkkPwldgiPSYcpZK3JU28WoMVv55yHJgcZ8rlXvuG9iZggz+sU1d4bRgIGASwyWqjxu3FM0g==} + engines: {node: '>=18'} + + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} + + stackback@0.0.2: + resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} + + std-env@4.2.0: + resolution: {integrity: sha512-oCUKSupKTHX53EyjDtuZQ64pjLJ6yYCtpmEw0goYxtjG9KpbRe8KAsl2tBUGU9DyMcJ0RwJ8GqJAFzMXcXW1Rw==} + + tinybench@2.9.0: + resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} + + tinyexec@1.2.4: + resolution: {integrity: sha512-SHf/r48b7vOrjve9PxJo3MN5v5yuyjHvdUcrQffT3WXMUfnGmHDVbC4k3sHJaJTgZCwpUplIaAo5ANtMyp3YHg==} + engines: {node: '>=18'} + + tinyglobby@0.2.17: + resolution: {integrity: sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==} + engines: {node: '>=12.0.0'} + + tinypool@2.1.0: + resolution: {integrity: sha512-Pugqs6M0m7Lv1I7FtxN4aoyToKg1C4tu+/381vH35y8oENM/Ai7f7C4StcoK4/+BSw9ebcS8jRiVrORFKCALLw==} + engines: {node: ^20.0.0 || >=22.0.0} + + tinyrainbow@3.1.0: + resolution: {integrity: sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==} + engines: {node: '>=14.0.0'} + + totalist@3.0.1: + resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==} + engines: {node: '>=6'} + + ts-algebra@2.0.0: + resolution: {integrity: sha512-FPAhNPFMrkwz76P7cdjdmiShwMynZYN6SgOujD1urY4oNm80Ou9oMdmbR45LotcKOXoy7wSmHkRFE6Mxbrhefw==} + + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + + tsx@4.21.0: + resolution: {integrity: sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==} + engines: {node: '>=18.0.0'} + hasBin: true + + typebox@1.1.38: + resolution: {integrity: sha512-pZ0aQPmMmXoUvSbeuWf/Hzsc+avNw/Zd6VeE8CFgkVGWyuHPJvqeJJDeJqLve+K70LvjYIoleGcoJHPT17cWoA==} + + typescript@6.0.3: + resolution: {integrity: sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==} + engines: {node: '>=14.17'} + hasBin: true + + undici-types@8.3.0: + resolution: {integrity: sha512-j375ScV60dom+YkPFIfTLcOiPxkN/buHz5GobjLhixFuANaNs3C9l4GmrWqejgXWJ7BbJcFYpTEUkS1Ge8bpZQ==} + + undici@8.5.0: + resolution: {integrity: sha512-xamtWoB1EshgjpmlXd7GGm2VfdDtw1+rD8uhry8pSNW3If6S8E0m2T2+orSKeZXEn/aPJMviCpDBA65WJt8zhg==} + engines: {node: '>=22.19.0'} + + vite-plus@0.2.5: + resolution: {integrity: sha512-QNJ0FnN8rfs5u8lZKZ1uR2Tegjg3VkT0AGTxSLGHg4fYmGxRNfAV0YX1parZrVa4VybSI56SWCoo7wQ6D7pMew==} + engines: {node: ^20.19.0 || ^22.18.0 || >=24.11.0} + hasBin: true + peerDependencies: + '@vitest/browser-playwright': 4.1.10 + '@vitest/browser-webdriverio': 4.1.10 + peerDependenciesMeta: + '@vitest/browser-playwright': + optional: true + '@vitest/browser-webdriverio': + optional: true + + vite@8.0.3: + resolution: {integrity: sha512-B9ifbFudT1TFhfltfaIPgjo9Z3mDynBTJSUYxTjOQruf/zHH+ezCQKcoqO+h7a9Pw9Nm/OtlXAiGT1axBgwqrQ==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + peerDependencies: + '@types/node': ^20.19.0 || >=22.12.0 + '@vitejs/devtools': ^0.1.0 + esbuild: ^0.27.0 + jiti: '>=1.21.0' + less: ^4.0.0 + sass: ^1.70.0 + sass-embedded: ^1.70.0 + stylus: '>=0.54.8' + sugarss: ^5.0.0 + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + '@types/node': + optional: true + '@vitejs/devtools': + optional: true + esbuild: + optional: true + jiti: + optional: true + less: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true + + vitest@4.1.10: + resolution: {integrity: sha512-R9jUTe5S4Qb0HCd4TNqpC7oGcrMssMRGXLW80ubjWsW9VH5GF8y1Y0SFLY9AbqSk6nt0PnOx4H4WNJYZ13GUPw==} + engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0} + hasBin: true + peerDependencies: + '@edge-runtime/vm': '*' + '@opentelemetry/api': ^1.9.0 + '@types/node': ^20.0.0 || ^22.0.0 || >=24.0.0 + '@vitest/browser-playwright': 4.1.10 + '@vitest/browser-preview': 4.1.10 + '@vitest/browser-webdriverio': 4.1.10 + '@vitest/coverage-istanbul': 4.1.10 + '@vitest/coverage-v8': 4.1.10 + '@vitest/ui': 4.1.10 + happy-dom: '*' + jsdom: '*' + vite: ^6.0.0 || ^7.0.0 || ^8.0.0 + peerDependenciesMeta: + '@edge-runtime/vm': + optional: true + '@opentelemetry/api': + optional: true + '@types/node': + optional: true + '@vitest/browser-playwright': + optional: true + '@vitest/browser-preview': + optional: true + '@vitest/browser-webdriverio': + optional: true + '@vitest/coverage-istanbul': + optional: true + '@vitest/coverage-v8': + optional: true + '@vitest/ui': + optional: true + happy-dom: + optional: true + jsdom: + optional: true + + web-streams-polyfill@3.3.3: + resolution: {integrity: sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==} + engines: {node: '>= 8'} + + which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + + why-is-node-running@2.3.0: + resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} + engines: {node: '>=8'} + hasBin: true + + ws@8.21.1: + resolution: {integrity: sha512-+0NTnW77fFN/DjQi6k/Sq/Yvk4Sgajw7urW8V+asjXnRgDs9gyGkdb7EzgfhA4goXsRIZKE28fzIXBHEzhuiWw==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + + yaml@2.9.0: + resolution: {integrity: sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==} + engines: {node: '>= 14.6'} + hasBin: true + + yuku-codegen@0.5.48: + resolution: {integrity: sha512-p7HxD5Xl4jzDzqMrGePAOeSHmRY4g58h4HuGq15weQFPxuPWd/W6e7nqp/+Lea6JfpOdBwJOAyXFqIZ/J9Zfnw==} + + yuku-parser@0.5.48: + resolution: {integrity: sha512-OWBfhrpgK9+/4+IXG9oT8Bao4AhViQA7vdyNNH7EUg8dQYgwa70XtIBWTpCEme1P1ECyoDNYkn0wT63f8XRcVA==} + + zod-to-json-schema@3.25.2: + resolution: {integrity: sha512-O/PgfnpT1xKSDeQYSCfRI5Gy3hPf91mKVDuYLUHZJMiDFptvP41MSnWofm8dnCm0256ZNfZIM7DSzuSMAFnjHA==} + peerDependencies: + zod: ^3.25.28 || ^4 + + zod@4.4.3: + resolution: {integrity: sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==} + +snapshots: + + '@anthropic-ai/sdk@0.91.1(zod@4.4.3)': + dependencies: + json-schema-to-ts: 3.1.1 + optionalDependencies: + zod: 4.4.3 + + '@aws-crypto/sha256-browser@5.2.0': + dependencies: + '@aws-crypto/sha256-js': 5.2.0 + '@aws-crypto/supports-web-crypto': 5.2.0 + '@aws-crypto/util': 5.2.0 + '@aws-sdk/types': 3.974.2 + '@aws-sdk/util-locate-window': 3.965.8 + '@smithy/util-utf8': 2.3.0 + tslib: 2.8.1 + + '@aws-crypto/sha256-js@5.2.0': + dependencies: + '@aws-crypto/util': 5.2.0 + '@aws-sdk/types': 3.974.2 + tslib: 2.8.1 + + '@aws-crypto/supports-web-crypto@5.2.0': + dependencies: + tslib: 2.8.1 + + '@aws-crypto/util@5.2.0': + dependencies: + '@aws-sdk/types': 3.974.2 + '@smithy/util-utf8': 2.3.0 + tslib: 2.8.1 + + '@aws-sdk/client-bedrock-runtime@3.1048.0': + dependencies: + '@aws-crypto/sha256-browser': 5.2.0 + '@aws-crypto/sha256-js': 5.2.0 + '@aws-sdk/core': 3.975.3 + '@aws-sdk/credential-provider-node': 3.972.70 + '@aws-sdk/eventstream-handler-node': 3.972.29 + '@aws-sdk/middleware-eventstream': 3.972.24 + '@aws-sdk/middleware-websocket': 3.972.41 + '@aws-sdk/token-providers': 3.1048.0 + '@aws-sdk/types': 3.974.2 + '@smithy/core': 3.29.5 + '@smithy/fetch-http-handler': 5.6.7 + '@smithy/node-http-handler': 4.9.7 + '@smithy/types': 4.16.1 + tslib: 2.8.1 + + '@aws-sdk/core@3.975.3': + dependencies: + '@aws-sdk/types': 3.974.2 + '@aws-sdk/xml-builder': 3.972.36 + '@aws/lambda-invoke-store': 0.3.0 + '@smithy/core': 3.29.5 + '@smithy/signature-v4': 5.6.6 + '@smithy/types': 4.16.1 + bowser: 2.14.1 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-env@3.972.59': + dependencies: + '@aws-sdk/core': 3.975.3 + '@aws-sdk/types': 3.974.2 + '@smithy/core': 3.29.5 + '@smithy/types': 4.16.1 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-http@3.972.61': + dependencies: + '@aws-sdk/core': 3.975.3 + '@aws-sdk/types': 3.974.2 + '@smithy/core': 3.29.5 + '@smithy/fetch-http-handler': 5.6.7 + '@smithy/node-http-handler': 4.9.7 + '@smithy/types': 4.16.1 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-ini@3.973.4': + dependencies: + '@aws-sdk/core': 3.975.3 + '@aws-sdk/credential-provider-env': 3.972.59 + '@aws-sdk/credential-provider-http': 3.972.61 + '@aws-sdk/credential-provider-login': 3.972.66 + '@aws-sdk/credential-provider-process': 3.972.59 + '@aws-sdk/credential-provider-sso': 3.973.3 + '@aws-sdk/credential-provider-web-identity': 3.972.65 + '@aws-sdk/nested-clients': 3.997.33 + '@aws-sdk/types': 3.974.2 + '@smithy/core': 3.29.5 + '@smithy/credential-provider-imds': 4.4.10 + '@smithy/types': 4.16.1 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-login@3.972.66': + dependencies: + '@aws-sdk/core': 3.975.3 + '@aws-sdk/nested-clients': 3.997.33 + '@aws-sdk/types': 3.974.2 + '@smithy/core': 3.29.5 + '@smithy/types': 4.16.1 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-node@3.972.70': + dependencies: + '@aws-sdk/credential-provider-env': 3.972.59 + '@aws-sdk/credential-provider-http': 3.972.61 + '@aws-sdk/credential-provider-ini': 3.973.4 + '@aws-sdk/credential-provider-process': 3.972.59 + '@aws-sdk/credential-provider-sso': 3.973.3 + '@aws-sdk/credential-provider-web-identity': 3.972.65 + '@aws-sdk/types': 3.974.2 + '@smithy/core': 3.29.5 + '@smithy/credential-provider-imds': 4.4.10 + '@smithy/types': 4.16.1 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-process@3.972.59': + dependencies: + '@aws-sdk/core': 3.975.3 + '@aws-sdk/types': 3.974.2 + '@smithy/core': 3.29.5 + '@smithy/types': 4.16.1 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-sso@3.973.3': + dependencies: + '@aws-sdk/core': 3.975.3 + '@aws-sdk/nested-clients': 3.997.33 + '@aws-sdk/token-providers': 3.1088.0 + '@aws-sdk/types': 3.974.2 + '@smithy/core': 3.29.5 + '@smithy/types': 4.16.1 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-web-identity@3.972.65': + dependencies: + '@aws-sdk/core': 3.975.3 + '@aws-sdk/nested-clients': 3.997.33 + '@aws-sdk/types': 3.974.2 + '@smithy/core': 3.29.5 + '@smithy/types': 4.16.1 + tslib: 2.8.1 + + '@aws-sdk/eventstream-handler-node@3.972.29': + dependencies: + '@aws-sdk/types': 3.974.2 + '@smithy/core': 3.29.5 + '@smithy/types': 4.16.1 + tslib: 2.8.1 + + '@aws-sdk/middleware-eventstream@3.972.24': + dependencies: + '@aws-sdk/types': 3.974.2 + '@smithy/core': 3.29.5 + '@smithy/types': 4.16.1 + tslib: 2.8.1 + + '@aws-sdk/middleware-websocket@3.972.41': + dependencies: + '@aws-sdk/core': 3.975.3 + '@aws-sdk/types': 3.974.2 + '@smithy/core': 3.29.5 + '@smithy/fetch-http-handler': 5.6.7 + '@smithy/signature-v4': 5.6.6 + '@smithy/types': 4.16.1 + tslib: 2.8.1 + + '@aws-sdk/nested-clients@3.997.33': + dependencies: + '@aws-sdk/core': 3.975.3 + '@aws-sdk/signature-v4-multi-region': 3.996.41 + '@aws-sdk/types': 3.974.2 + '@smithy/core': 3.29.5 + '@smithy/fetch-http-handler': 5.6.7 + '@smithy/node-http-handler': 4.9.7 + '@smithy/types': 4.16.1 + tslib: 2.8.1 + + '@aws-sdk/signature-v4-multi-region@3.996.41': + dependencies: + '@aws-sdk/types': 3.974.2 + '@smithy/signature-v4': 5.6.6 + '@smithy/types': 4.16.1 + tslib: 2.8.1 + + '@aws-sdk/token-providers@3.1048.0': + dependencies: + '@aws-sdk/core': 3.975.3 + '@aws-sdk/nested-clients': 3.997.33 + '@aws-sdk/types': 3.974.2 + '@smithy/core': 3.29.5 + '@smithy/types': 4.16.1 + tslib: 2.8.1 + + '@aws-sdk/token-providers@3.1088.0': + dependencies: + '@aws-sdk/core': 3.975.3 + '@aws-sdk/nested-clients': 3.997.33 + '@aws-sdk/types': 3.974.2 + '@smithy/core': 3.29.5 + '@smithy/types': 4.16.1 + tslib: 2.8.1 + + '@aws-sdk/types@3.974.2': + dependencies: + '@smithy/types': 4.16.1 + tslib: 2.8.1 + + '@aws-sdk/util-locate-window@3.965.8': + dependencies: + tslib: 2.8.1 + + '@aws-sdk/xml-builder@3.972.36': + dependencies: + '@smithy/types': 4.16.1 + tslib: 2.8.1 + + '@aws/lambda-invoke-store@0.3.0': {} + + '@babel/code-frame@7.29.7': + dependencies: + '@babel/helper-validator-identifier': 7.29.7 + js-tokens: 4.0.0 + picocolors: 1.1.1 + + '@babel/helper-validator-identifier@7.29.7': {} + + '@babel/runtime@7.29.7': {} + + '@blazediff/core@1.9.1': {} + + '@earendil-works/pi-agent-core@0.80.10(ws@8.21.1)(zod@4.4.3)': + dependencies: + '@earendil-works/pi-ai': 0.80.10(ws@8.21.1)(zod@4.4.3) + ignore: 7.0.5 + typebox: 1.1.38 + yaml: 2.9.0 + transitivePeerDependencies: + - '@modelcontextprotocol/sdk' + - bufferutil + - supports-color + - utf-8-validate + - ws + - zod + + '@earendil-works/pi-ai@0.80.10(ws@8.21.1)(zod@4.4.3)': + dependencies: + '@anthropic-ai/sdk': 0.91.1(zod@4.4.3) + '@aws-sdk/client-bedrock-runtime': 3.1048.0 + '@google/genai': 1.52.0 + '@mistralai/mistralai': 2.2.6(@opentelemetry/api@1.9.0) + '@opentelemetry/api': 1.9.0 + '@smithy/node-http-handler': 4.7.3 + http-proxy-agent: 7.0.2 + https-proxy-agent: 7.0.6 + openai: 6.26.0(ws@8.21.1)(zod@4.4.3) + partial-json: 0.1.7 + typebox: 1.1.38 + transitivePeerDependencies: + - '@modelcontextprotocol/sdk' + - bufferutil + - supports-color + - utf-8-validate + - ws + - zod + + '@earendil-works/pi-coding-agent@0.80.10(ws@8.21.1)(zod@4.4.3)': + dependencies: + '@earendil-works/pi-agent-core': 0.80.10(ws@8.21.1)(zod@4.4.3) + '@earendil-works/pi-ai': 0.80.10(ws@8.21.1)(zod@4.4.3) + '@earendil-works/pi-tui': 0.80.10 + '@silvia-odwyer/photon-node': 0.3.4 + chalk: 5.6.2 + cross-spawn: 7.0.6 + diff: 8.0.4 + glob: 13.0.6 + highlight.js: 10.7.3 + hosted-git-info: 9.0.3 + ignore: 7.0.5 + jiti: 2.7.0 + minimatch: 10.2.5 + proper-lockfile: 4.1.2 + semver: 7.8.0 + typebox: 1.1.38 + undici: 8.5.0 + yaml: 2.9.0 + optionalDependencies: + '@mariozechner/clipboard': 0.3.9 + transitivePeerDependencies: + - '@modelcontextprotocol/sdk' + - bufferutil + - supports-color + - utf-8-validate + - ws + - zod + + '@earendil-works/pi-tui@0.80.10': + dependencies: + get-east-asian-width: 1.6.0 + marked: 18.0.5 + + '@emnapi/core@1.9.1': + dependencies: + '@emnapi/wasi-threads': 1.2.0 + tslib: 2.8.1 + optional: true + + '@emnapi/runtime@1.9.1': + dependencies: + tslib: 2.8.1 + optional: true + + '@emnapi/wasi-threads@1.2.0': + dependencies: + tslib: 2.8.1 + optional: true + + '@esbuild/aix-ppc64@0.27.7': + optional: true + + '@esbuild/android-arm64@0.27.7': + optional: true + + '@esbuild/android-arm@0.27.7': + optional: true + + '@esbuild/android-x64@0.27.7': + optional: true + + '@esbuild/darwin-arm64@0.27.7': + optional: true + + '@esbuild/darwin-x64@0.27.7': + optional: true + + '@esbuild/freebsd-arm64@0.27.7': + optional: true + + '@esbuild/freebsd-x64@0.27.7': + optional: true + + '@esbuild/linux-arm64@0.27.7': + optional: true + + '@esbuild/linux-arm@0.27.7': + optional: true + + '@esbuild/linux-ia32@0.27.7': + optional: true + + '@esbuild/linux-loong64@0.27.7': + optional: true + + '@esbuild/linux-mips64el@0.27.7': + optional: true + + '@esbuild/linux-ppc64@0.27.7': + optional: true + + '@esbuild/linux-riscv64@0.27.7': + optional: true + + '@esbuild/linux-s390x@0.27.7': + optional: true + + '@esbuild/linux-x64@0.27.7': + optional: true + + '@esbuild/netbsd-arm64@0.27.7': + optional: true + + '@esbuild/netbsd-x64@0.27.7': + optional: true + + '@esbuild/openbsd-arm64@0.27.7': + optional: true + + '@esbuild/openbsd-x64@0.27.7': + optional: true + + '@esbuild/openharmony-arm64@0.27.7': + optional: true + + '@esbuild/sunos-x64@0.27.7': + optional: true + + '@esbuild/win32-arm64@0.27.7': + optional: true + + '@esbuild/win32-ia32@0.27.7': + optional: true + + '@esbuild/win32-x64@0.27.7': + optional: true + + '@google/genai@1.52.0': + dependencies: + google-auth-library: 10.9.0 + p-retry: 4.6.2 + protobufjs: 7.6.5 + ws: 8.21.1 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + + '@jridgewell/sourcemap-codec@1.5.5': {} + + '@mariozechner/clipboard-darwin-arm64@0.3.9': + optional: true + + '@mariozechner/clipboard-darwin-universal@0.3.9': + optional: true + + '@mariozechner/clipboard-darwin-x64@0.3.9': + optional: true + + '@mariozechner/clipboard-linux-arm64-gnu@0.3.9': + optional: true + + '@mariozechner/clipboard-linux-arm64-musl@0.3.9': + optional: true + + '@mariozechner/clipboard-linux-riscv64-gnu@0.3.9': + optional: true + + '@mariozechner/clipboard-linux-x64-gnu@0.3.9': + optional: true + + '@mariozechner/clipboard-linux-x64-musl@0.3.9': + optional: true + + '@mariozechner/clipboard-win32-arm64-msvc@0.3.9': + optional: true + + '@mariozechner/clipboard-win32-x64-msvc@0.3.9': + optional: true + + '@mariozechner/clipboard@0.3.9': + optionalDependencies: + '@mariozechner/clipboard-darwin-arm64': 0.3.9 + '@mariozechner/clipboard-darwin-universal': 0.3.9 + '@mariozechner/clipboard-darwin-x64': 0.3.9 + '@mariozechner/clipboard-linux-arm64-gnu': 0.3.9 + '@mariozechner/clipboard-linux-arm64-musl': 0.3.9 + '@mariozechner/clipboard-linux-riscv64-gnu': 0.3.9 + '@mariozechner/clipboard-linux-x64-gnu': 0.3.9 + '@mariozechner/clipboard-linux-x64-musl': 0.3.9 + '@mariozechner/clipboard-win32-arm64-msvc': 0.3.9 + '@mariozechner/clipboard-win32-x64-msvc': 0.3.9 + optional: true + + '@mistralai/mistralai@2.2.6(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/semantic-conventions': 1.43.0 + ws: 8.21.1 + zod: 4.4.3 + zod-to-json-schema: 3.25.2(zod@4.4.3) + optionalDependencies: + '@opentelemetry/api': 1.9.0 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + + '@napi-rs/wasm-runtime@1.1.6(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)': + dependencies: + '@emnapi/core': 1.9.1 + '@emnapi/runtime': 1.9.1 + '@tybys/wasm-util': 0.10.3 + optional: true + + '@opentelemetry/api@1.9.0': {} + + '@opentelemetry/semantic-conventions@1.43.0': {} + + '@oxc-project/runtime@0.139.0': {} + + '@oxc-project/types@0.122.0': {} + + '@oxc-project/types@0.139.0': {} + + '@oxfmt/binding-android-arm-eabi@0.58.0': + optional: true + + '@oxfmt/binding-android-arm64@0.58.0': + optional: true + + '@oxfmt/binding-darwin-arm64@0.58.0': + optional: true + + '@oxfmt/binding-darwin-x64@0.58.0': + optional: true + + '@oxfmt/binding-freebsd-x64@0.58.0': + optional: true + + '@oxfmt/binding-linux-arm-gnueabihf@0.58.0': + optional: true + + '@oxfmt/binding-linux-arm-musleabihf@0.58.0': + optional: true + + '@oxfmt/binding-linux-arm64-gnu@0.58.0': + optional: true + + '@oxfmt/binding-linux-arm64-musl@0.58.0': + optional: true + + '@oxfmt/binding-linux-ppc64-gnu@0.58.0': + optional: true + + '@oxfmt/binding-linux-riscv64-gnu@0.58.0': + optional: true + + '@oxfmt/binding-linux-riscv64-musl@0.58.0': + optional: true + + '@oxfmt/binding-linux-s390x-gnu@0.58.0': + optional: true + + '@oxfmt/binding-linux-x64-gnu@0.58.0': + optional: true + + '@oxfmt/binding-linux-x64-musl@0.58.0': + optional: true + + '@oxfmt/binding-openharmony-arm64@0.58.0': + optional: true + + '@oxfmt/binding-win32-arm64-msvc@0.58.0': + optional: true + + '@oxfmt/binding-win32-ia32-msvc@0.58.0': + optional: true + + '@oxfmt/binding-win32-x64-msvc@0.58.0': + optional: true + + '@oxlint-tsgolint/darwin-arm64@0.24.0': + optional: true + + '@oxlint-tsgolint/darwin-x64@0.24.0': + optional: true + + '@oxlint-tsgolint/linux-arm64@0.24.0': + optional: true + + '@oxlint-tsgolint/linux-x64@0.24.0': + optional: true + + '@oxlint-tsgolint/win32-arm64@0.24.0': + optional: true + + '@oxlint-tsgolint/win32-x64@0.24.0': + optional: true + + '@oxlint/binding-android-arm-eabi@1.73.0': + optional: true + + '@oxlint/binding-android-arm64@1.73.0': + optional: true + + '@oxlint/binding-darwin-arm64@1.73.0': + optional: true + + '@oxlint/binding-darwin-x64@1.73.0': + optional: true + + '@oxlint/binding-freebsd-x64@1.73.0': + optional: true + + '@oxlint/binding-linux-arm-gnueabihf@1.73.0': + optional: true + + '@oxlint/binding-linux-arm-musleabihf@1.73.0': + optional: true + + '@oxlint/binding-linux-arm64-gnu@1.73.0': + optional: true + + '@oxlint/binding-linux-arm64-musl@1.73.0': + optional: true + + '@oxlint/binding-linux-ppc64-gnu@1.73.0': + optional: true + + '@oxlint/binding-linux-riscv64-gnu@1.73.0': + optional: true + + '@oxlint/binding-linux-riscv64-musl@1.73.0': + optional: true + + '@oxlint/binding-linux-s390x-gnu@1.73.0': + optional: true + + '@oxlint/binding-linux-x64-gnu@1.73.0': + optional: true + + '@oxlint/binding-linux-x64-musl@1.73.0': + optional: true + + '@oxlint/binding-openharmony-arm64@1.73.0': + optional: true + + '@oxlint/binding-win32-arm64-msvc@1.73.0': + optional: true + + '@oxlint/binding-win32-ia32-msvc@1.73.0': + optional: true + + '@oxlint/binding-win32-x64-msvc@1.73.0': + optional: true + + '@oxlint/plugins@1.73.0': {} + + '@polka/url@1.0.0-next.29': {} + + '@protobufjs/aspromise@1.1.2': {} + + '@protobufjs/base64@1.1.2': {} + + '@protobufjs/codegen@2.0.5': {} + + '@protobufjs/eventemitter@1.1.1': {} + + '@protobufjs/fetch@1.1.1': + dependencies: + '@protobufjs/aspromise': 1.1.2 + + '@protobufjs/float@1.0.2': {} + + '@protobufjs/path@1.1.2': {} + + '@protobufjs/pool@1.1.0': {} + + '@protobufjs/utf8@1.1.2': {} + + '@rolldown/binding-android-arm64@1.0.0-rc.12': + optional: true + + '@rolldown/binding-darwin-arm64@1.0.0-rc.12': + optional: true + + '@rolldown/binding-darwin-x64@1.0.0-rc.12': + optional: true + + '@rolldown/binding-freebsd-x64@1.0.0-rc.12': + optional: true + + '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.12': + optional: true + + '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.12': + optional: true + + '@rolldown/binding-linux-arm64-musl@1.0.0-rc.12': + optional: true + + '@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.12': + optional: true + + '@rolldown/binding-linux-s390x-gnu@1.0.0-rc.12': + optional: true + + '@rolldown/binding-linux-x64-gnu@1.0.0-rc.12': + optional: true + + '@rolldown/binding-linux-x64-musl@1.0.0-rc.12': + optional: true + + '@rolldown/binding-openharmony-arm64@1.0.0-rc.12': + optional: true + + '@rolldown/binding-wasm32-wasi@1.0.0-rc.12(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)': + dependencies: + '@napi-rs/wasm-runtime': 1.1.6(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1) + transitivePeerDependencies: + - '@emnapi/core' + - '@emnapi/runtime' + optional: true + + '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.12': + optional: true + + '@rolldown/binding-win32-x64-msvc@1.0.0-rc.12': + optional: true + + '@rolldown/pluginutils@1.0.0-rc.12': {} + + '@silvia-odwyer/photon-node@0.3.4': {} + + '@smithy/core@3.29.5': + dependencies: + '@smithy/types': 4.16.1 + tslib: 2.8.1 + + '@smithy/credential-provider-imds@4.4.10': + dependencies: + '@smithy/core': 3.29.5 + '@smithy/types': 4.16.1 + tslib: 2.8.1 + + '@smithy/fetch-http-handler@5.6.7': + dependencies: + '@smithy/core': 3.29.5 + '@smithy/types': 4.16.1 + tslib: 2.8.1 + + '@smithy/is-array-buffer@2.2.0': + dependencies: + tslib: 2.8.1 + + '@smithy/node-http-handler@4.7.3': + dependencies: + '@smithy/core': 3.29.5 + '@smithy/types': 4.16.1 + tslib: 2.8.1 + + '@smithy/node-http-handler@4.9.7': + dependencies: + '@smithy/core': 3.29.5 + '@smithy/types': 4.16.1 + tslib: 2.8.1 + + '@smithy/signature-v4@5.6.6': + dependencies: + '@smithy/core': 3.29.5 + '@smithy/types': 4.16.1 + tslib: 2.8.1 + + '@smithy/types@4.16.1': + dependencies: + tslib: 2.8.1 + + '@smithy/util-buffer-from@2.2.0': + dependencies: + '@smithy/is-array-buffer': 2.2.0 + tslib: 2.8.1 + + '@smithy/util-utf8@2.3.0': + dependencies: + '@smithy/util-buffer-from': 2.2.0 + tslib: 2.8.1 + + '@standard-schema/spec@1.1.0': {} + + '@testing-library/dom@10.4.1': + dependencies: + '@babel/code-frame': 7.29.7 + '@babel/runtime': 7.29.7 + '@types/aria-query': 5.0.4 + aria-query: 5.3.0 + dom-accessibility-api: 0.5.16 + lz-string: 1.5.0 + picocolors: 1.1.1 + pretty-format: 27.5.1 + + '@testing-library/user-event@14.6.1(@testing-library/dom@10.4.1)': + dependencies: + '@testing-library/dom': 10.4.1 + + '@tybys/wasm-util@0.10.3': + dependencies: + tslib: 2.8.1 + optional: true + + '@types/aria-query@5.0.4': {} + + '@types/chai@5.2.3': + dependencies: + '@types/deep-eql': 4.0.2 + assertion-error: 2.0.1 + + '@types/deep-eql@4.0.2': {} + + '@types/estree@1.0.9': {} + + '@types/node@26.1.1': + dependencies: + undici-types: 8.3.0 + + '@types/retry@0.12.0': {} + + '@vitest/browser-preview@4.1.10(vite@8.0.3(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@26.1.1)(esbuild@0.27.7)(jiti@2.7.0)(tsx@4.21.0)(yaml@2.9.0))(vitest@4.1.10)': + dependencies: + '@testing-library/dom': 10.4.1 + '@testing-library/user-event': 14.6.1(@testing-library/dom@10.4.1) + '@vitest/browser': 4.1.10(vite@8.0.3(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@26.1.1)(esbuild@0.27.7)(jiti@2.7.0)(tsx@4.21.0)(yaml@2.9.0))(vitest@4.1.10) + vitest: 4.1.10(@opentelemetry/api@1.9.0)(@types/node@26.1.1)(@vitest/browser-preview@4.1.10)(vite@8.0.3(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@26.1.1)(esbuild@0.27.7)(jiti@2.7.0)(tsx@4.21.0)(yaml@2.9.0)) + transitivePeerDependencies: + - bufferutil + - msw + - utf-8-validate + - vite + + '@vitest/browser@4.1.10(vite@8.0.3(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@26.1.1)(esbuild@0.27.7)(jiti@2.7.0)(tsx@4.21.0)(yaml@2.9.0))(vitest@4.1.10)': + dependencies: + '@blazediff/core': 1.9.1 + '@vitest/mocker': 4.1.10(vite@8.0.3(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@26.1.1)(esbuild@0.27.7)(jiti@2.7.0)(tsx@4.21.0)(yaml@2.9.0)) + '@vitest/utils': 4.1.10 + magic-string: 0.30.21 + pngjs: 7.0.0 + sirv: 3.0.2 + tinyrainbow: 3.1.0 + vitest: 4.1.10(@opentelemetry/api@1.9.0)(@types/node@26.1.1)(@vitest/browser-preview@4.1.10)(vite@8.0.3(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@26.1.1)(esbuild@0.27.7)(jiti@2.7.0)(tsx@4.21.0)(yaml@2.9.0)) + ws: 8.21.1 + transitivePeerDependencies: + - bufferutil + - msw + - utf-8-validate + - vite + + '@vitest/expect@4.1.10': + dependencies: + '@standard-schema/spec': 1.1.0 + '@types/chai': 5.2.3 + '@vitest/spy': 4.1.10 + '@vitest/utils': 4.1.10 + chai: 6.2.2 + tinyrainbow: 3.1.0 + + '@vitest/mocker@4.1.10(vite@8.0.3(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@26.1.1)(esbuild@0.27.7)(jiti@2.7.0)(tsx@4.21.0)(yaml@2.9.0))': + dependencies: + '@vitest/spy': 4.1.10 + estree-walker: 3.0.3 + magic-string: 0.30.21 + optionalDependencies: + vite: 8.0.3(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@26.1.1)(esbuild@0.27.7)(jiti@2.7.0)(tsx@4.21.0)(yaml@2.9.0) + + '@vitest/pretty-format@4.1.10': + dependencies: + tinyrainbow: 3.1.0 + + '@vitest/runner@4.1.10': + dependencies: + '@vitest/utils': 4.1.10 + pathe: 2.0.3 + + '@vitest/snapshot@4.1.10': + dependencies: + '@vitest/pretty-format': 4.1.10 + '@vitest/utils': 4.1.10 + magic-string: 0.30.21 + pathe: 2.0.3 + + '@vitest/spy@4.1.10': {} + + '@vitest/utils@4.1.10': + dependencies: + '@vitest/pretty-format': 4.1.10 + convert-source-map: 2.0.0 + tinyrainbow: 3.1.0 + + '@voidzero-dev/vite-plus-core@0.2.5(@types/node@26.1.1)(esbuild@0.27.7)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.9.0)': + dependencies: + '@oxc-project/runtime': 0.139.0 + '@oxc-project/types': 0.139.0 + lightningcss: 1.32.0 + postcss: 8.5.19 + yuku-codegen: 0.5.48 + yuku-parser: 0.5.48 + optionalDependencies: + '@types/node': 26.1.1 + esbuild: 0.27.7 + fsevents: 2.3.3 + jiti: 2.7.0 + tsx: 4.21.0 + typescript: 6.0.3 + yaml: 2.9.0 + + '@voidzero-dev/vite-plus-darwin-arm64@0.2.5': + optional: true + + '@voidzero-dev/vite-plus-darwin-x64@0.2.5': + optional: true + + '@voidzero-dev/vite-plus-linux-arm64-gnu@0.2.5': + optional: true + + '@voidzero-dev/vite-plus-linux-arm64-musl@0.2.5': + optional: true + + '@voidzero-dev/vite-plus-linux-x64-gnu@0.2.5': + optional: true + + '@voidzero-dev/vite-plus-linux-x64-musl@0.2.5': + optional: true + + '@voidzero-dev/vite-plus-win32-arm64-msvc@0.2.5': + optional: true + + '@voidzero-dev/vite-plus-win32-x64-msvc@0.2.5': + optional: true + + '@yuku-codegen/binding-darwin-arm64@0.5.48': + optional: true + + '@yuku-codegen/binding-darwin-x64@0.5.48': + optional: true + + '@yuku-codegen/binding-freebsd-x64@0.5.48': + optional: true + + '@yuku-codegen/binding-linux-arm-gnu@0.5.48': + optional: true + + '@yuku-codegen/binding-linux-arm-musl@0.5.48': + optional: true + + '@yuku-codegen/binding-linux-arm64-gnu@0.5.48': + optional: true + + '@yuku-codegen/binding-linux-arm64-musl@0.5.48': + optional: true + + '@yuku-codegen/binding-linux-x64-gnu@0.5.48': + optional: true + + '@yuku-codegen/binding-linux-x64-musl@0.5.48': + optional: true + + '@yuku-codegen/binding-win32-arm64@0.5.48': + optional: true + + '@yuku-codegen/binding-win32-x64@0.5.48': + optional: true + + '@yuku-parser/binding-darwin-arm64@0.5.48': + optional: true + + '@yuku-parser/binding-darwin-x64@0.5.48': + optional: true + + '@yuku-parser/binding-freebsd-x64@0.5.48': + optional: true + + '@yuku-parser/binding-linux-arm-gnu@0.5.48': + optional: true + + '@yuku-parser/binding-linux-arm-musl@0.5.48': + optional: true + + '@yuku-parser/binding-linux-arm64-gnu@0.5.48': + optional: true + + '@yuku-parser/binding-linux-arm64-musl@0.5.48': + optional: true + + '@yuku-parser/binding-linux-x64-gnu@0.5.48': + optional: true + + '@yuku-parser/binding-linux-x64-musl@0.5.48': + optional: true + + '@yuku-parser/binding-win32-arm64@0.5.48': + optional: true + + '@yuku-parser/binding-win32-x64@0.5.48': + optional: true + + '@yuku-toolchain/types@0.5.43': {} + + agent-base@7.1.4: {} + + ansi-regex@5.0.1: {} + + ansi-styles@5.2.0: {} + + aria-query@5.3.0: + dependencies: + dequal: 2.0.3 + + assertion-error@2.0.1: {} + + balanced-match@4.0.4: {} + + base64-js@1.5.1: {} + + bignumber.js@9.3.1: {} + + bowser@2.14.1: {} + + brace-expansion@5.0.7: + dependencies: + balanced-match: 4.0.4 + + buffer-equal-constant-time@1.0.1: {} + + chai@6.2.2: {} + + chalk@5.6.2: {} + + convert-source-map@2.0.0: {} + + cross-spawn@7.0.6: + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + + data-uri-to-buffer@4.0.1: {} + + debug@4.4.3: + dependencies: + ms: 2.1.3 + + dequal@2.0.3: {} + + detect-libc@2.1.2: {} + + diff@8.0.4: {} + + dom-accessibility-api@0.5.16: {} + + ecdsa-sig-formatter@1.0.11: + dependencies: + safe-buffer: 5.2.1 + + es-module-lexer@2.3.0: {} + + esbuild@0.27.7: + optionalDependencies: + '@esbuild/aix-ppc64': 0.27.7 + '@esbuild/android-arm': 0.27.7 + '@esbuild/android-arm64': 0.27.7 + '@esbuild/android-x64': 0.27.7 + '@esbuild/darwin-arm64': 0.27.7 + '@esbuild/darwin-x64': 0.27.7 + '@esbuild/freebsd-arm64': 0.27.7 + '@esbuild/freebsd-x64': 0.27.7 + '@esbuild/linux-arm': 0.27.7 + '@esbuild/linux-arm64': 0.27.7 + '@esbuild/linux-ia32': 0.27.7 + '@esbuild/linux-loong64': 0.27.7 + '@esbuild/linux-mips64el': 0.27.7 + '@esbuild/linux-ppc64': 0.27.7 + '@esbuild/linux-riscv64': 0.27.7 + '@esbuild/linux-s390x': 0.27.7 + '@esbuild/linux-x64': 0.27.7 + '@esbuild/netbsd-arm64': 0.27.7 + '@esbuild/netbsd-x64': 0.27.7 + '@esbuild/openbsd-arm64': 0.27.7 + '@esbuild/openbsd-x64': 0.27.7 + '@esbuild/openharmony-arm64': 0.27.7 + '@esbuild/sunos-x64': 0.27.7 + '@esbuild/win32-arm64': 0.27.7 + '@esbuild/win32-ia32': 0.27.7 + '@esbuild/win32-x64': 0.27.7 + optional: true + + estree-walker@3.0.3: + dependencies: + '@types/estree': 1.0.9 + + expect-type@1.4.0: {} + + extend@3.0.2: {} + + fdir@6.5.0(picomatch@4.0.5): + optionalDependencies: + picomatch: 4.0.5 + + fetch-blob@3.2.0: + dependencies: + node-domexception: 1.0.0 + web-streams-polyfill: 3.3.3 + + formdata-polyfill@4.0.10: + dependencies: + fetch-blob: 3.2.0 + + fsevents@2.3.3: + optional: true + + gaxios@7.2.0: + dependencies: + extend: 3.0.2 + https-proxy-agent: 7.0.6 + node-fetch: 3.3.2 + transitivePeerDependencies: + - supports-color + + gcp-metadata@8.1.2: + dependencies: + gaxios: 7.2.0 + google-logging-utils: 1.1.3 + json-bigint: 1.0.0 + transitivePeerDependencies: + - supports-color + + get-east-asian-width@1.6.0: {} + + get-tsconfig@4.14.0: + dependencies: + resolve-pkg-maps: 1.0.0 + optional: true + + glob@13.0.6: + dependencies: + minimatch: 10.2.5 + minipass: 7.1.3 + path-scurry: 2.0.2 + + google-auth-library@10.9.0: + dependencies: + base64-js: 1.5.1 + ecdsa-sig-formatter: 1.0.11 + gaxios: 7.2.0 + gcp-metadata: 8.1.2 + google-logging-utils: 1.1.3 + jws: 4.0.1 + transitivePeerDependencies: + - supports-color + + google-logging-utils@1.1.3: {} + + graceful-fs@4.2.11: {} + + highlight.js@10.7.3: {} + + hosted-git-info@9.0.3: + dependencies: + lru-cache: 11.5.2 + + http-proxy-agent@7.0.2: + dependencies: + agent-base: 7.1.4 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + https-proxy-agent@7.0.6: + dependencies: + agent-base: 7.1.4 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + ignore@7.0.5: {} + + isexe@2.0.0: {} + + jiti@2.7.0: {} + + js-tokens@4.0.0: {} + + json-bigint@1.0.0: + dependencies: + bignumber.js: 9.3.1 + + json-schema-to-ts@3.1.1: + dependencies: + '@babel/runtime': 7.29.7 + ts-algebra: 2.0.0 + + jwa@2.0.1: + dependencies: + buffer-equal-constant-time: 1.0.1 + ecdsa-sig-formatter: 1.0.11 + safe-buffer: 5.2.1 + + jws@4.0.1: + dependencies: + jwa: 2.0.1 + safe-buffer: 5.2.1 + + lightningcss-android-arm64@1.32.0: + optional: true + + lightningcss-darwin-arm64@1.32.0: + optional: true + + lightningcss-darwin-x64@1.32.0: + optional: true + + lightningcss-freebsd-x64@1.32.0: + optional: true + + lightningcss-linux-arm-gnueabihf@1.32.0: + optional: true + + lightningcss-linux-arm64-gnu@1.32.0: + optional: true + + lightningcss-linux-arm64-musl@1.32.0: + optional: true + + lightningcss-linux-x64-gnu@1.32.0: + optional: true + + lightningcss-linux-x64-musl@1.32.0: + optional: true + + lightningcss-win32-arm64-msvc@1.32.0: + optional: true + + lightningcss-win32-x64-msvc@1.32.0: + optional: true + + lightningcss@1.32.0: + dependencies: + detect-libc: 2.1.2 + optionalDependencies: + lightningcss-android-arm64: 1.32.0 + lightningcss-darwin-arm64: 1.32.0 + lightningcss-darwin-x64: 1.32.0 + lightningcss-freebsd-x64: 1.32.0 + lightningcss-linux-arm-gnueabihf: 1.32.0 + lightningcss-linux-arm64-gnu: 1.32.0 + lightningcss-linux-arm64-musl: 1.32.0 + lightningcss-linux-x64-gnu: 1.32.0 + lightningcss-linux-x64-musl: 1.32.0 + lightningcss-win32-arm64-msvc: 1.32.0 + lightningcss-win32-x64-msvc: 1.32.0 + + long@5.3.2: {} + + lru-cache@11.5.2: {} + + lz-string@1.5.0: {} + + magic-string@0.30.21: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + + marked@18.0.5: {} + + minimatch@10.2.5: + dependencies: + brace-expansion: 5.0.7 + + minipass@7.1.3: {} + + mrmime@2.0.1: {} + + ms@2.1.3: {} + + nanoid@3.3.16: {} + + node-domexception@1.0.0: {} + + node-fetch@3.3.2: + dependencies: + data-uri-to-buffer: 4.0.1 + fetch-blob: 3.2.0 + formdata-polyfill: 4.0.10 + + obug@2.1.3: {} + + openai@6.26.0(ws@8.21.1)(zod@4.4.3): + optionalDependencies: + ws: 8.21.1 + zod: 4.4.3 + + oxfmt@0.58.0(vite-plus@0.2.5(@opentelemetry/api@1.9.0)(@types/node@26.1.1)(esbuild@0.27.7)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(vite@8.0.3(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@26.1.1)(esbuild@0.27.7)(jiti@2.7.0)(tsx@4.21.0)(yaml@2.9.0))(yaml@2.9.0)): + dependencies: + tinypool: 2.1.0 + optionalDependencies: + '@oxfmt/binding-android-arm-eabi': 0.58.0 + '@oxfmt/binding-android-arm64': 0.58.0 + '@oxfmt/binding-darwin-arm64': 0.58.0 + '@oxfmt/binding-darwin-x64': 0.58.0 + '@oxfmt/binding-freebsd-x64': 0.58.0 + '@oxfmt/binding-linux-arm-gnueabihf': 0.58.0 + '@oxfmt/binding-linux-arm-musleabihf': 0.58.0 + '@oxfmt/binding-linux-arm64-gnu': 0.58.0 + '@oxfmt/binding-linux-arm64-musl': 0.58.0 + '@oxfmt/binding-linux-ppc64-gnu': 0.58.0 + '@oxfmt/binding-linux-riscv64-gnu': 0.58.0 + '@oxfmt/binding-linux-riscv64-musl': 0.58.0 + '@oxfmt/binding-linux-s390x-gnu': 0.58.0 + '@oxfmt/binding-linux-x64-gnu': 0.58.0 + '@oxfmt/binding-linux-x64-musl': 0.58.0 + '@oxfmt/binding-openharmony-arm64': 0.58.0 + '@oxfmt/binding-win32-arm64-msvc': 0.58.0 + '@oxfmt/binding-win32-ia32-msvc': 0.58.0 + '@oxfmt/binding-win32-x64-msvc': 0.58.0 + vite-plus: 0.2.5(@opentelemetry/api@1.9.0)(@types/node@26.1.1)(esbuild@0.27.7)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(vite@8.0.3(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@26.1.1)(esbuild@0.27.7)(jiti@2.7.0)(tsx@4.21.0)(yaml@2.9.0))(yaml@2.9.0) + + oxlint-tsgolint@0.24.0: + optionalDependencies: + '@oxlint-tsgolint/darwin-arm64': 0.24.0 + '@oxlint-tsgolint/darwin-x64': 0.24.0 + '@oxlint-tsgolint/linux-arm64': 0.24.0 + '@oxlint-tsgolint/linux-x64': 0.24.0 + '@oxlint-tsgolint/win32-arm64': 0.24.0 + '@oxlint-tsgolint/win32-x64': 0.24.0 + + oxlint@1.73.0(oxlint-tsgolint@0.24.0)(vite-plus@0.2.5(@opentelemetry/api@1.9.0)(@types/node@26.1.1)(esbuild@0.27.7)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(vite@8.0.3(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@26.1.1)(esbuild@0.27.7)(jiti@2.7.0)(tsx@4.21.0)(yaml@2.9.0))(yaml@2.9.0)): + optionalDependencies: + '@oxlint/binding-android-arm-eabi': 1.73.0 + '@oxlint/binding-android-arm64': 1.73.0 + '@oxlint/binding-darwin-arm64': 1.73.0 + '@oxlint/binding-darwin-x64': 1.73.0 + '@oxlint/binding-freebsd-x64': 1.73.0 + '@oxlint/binding-linux-arm-gnueabihf': 1.73.0 + '@oxlint/binding-linux-arm-musleabihf': 1.73.0 + '@oxlint/binding-linux-arm64-gnu': 1.73.0 + '@oxlint/binding-linux-arm64-musl': 1.73.0 + '@oxlint/binding-linux-ppc64-gnu': 1.73.0 + '@oxlint/binding-linux-riscv64-gnu': 1.73.0 + '@oxlint/binding-linux-riscv64-musl': 1.73.0 + '@oxlint/binding-linux-s390x-gnu': 1.73.0 + '@oxlint/binding-linux-x64-gnu': 1.73.0 + '@oxlint/binding-linux-x64-musl': 1.73.0 + '@oxlint/binding-openharmony-arm64': 1.73.0 + '@oxlint/binding-win32-arm64-msvc': 1.73.0 + '@oxlint/binding-win32-ia32-msvc': 1.73.0 + '@oxlint/binding-win32-x64-msvc': 1.73.0 + oxlint-tsgolint: 0.24.0 + vite-plus: 0.2.5(@opentelemetry/api@1.9.0)(@types/node@26.1.1)(esbuild@0.27.7)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(vite@8.0.3(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@26.1.1)(esbuild@0.27.7)(jiti@2.7.0)(tsx@4.21.0)(yaml@2.9.0))(yaml@2.9.0) + + p-retry@4.6.2: + dependencies: + '@types/retry': 0.12.0 + retry: 0.13.1 + + partial-json@0.1.7: {} + + path-key@3.1.1: {} + + path-scurry@2.0.2: + dependencies: + lru-cache: 11.5.2 + minipass: 7.1.3 + + pathe@2.0.3: {} + + picocolors@1.1.1: {} + + picomatch@4.0.5: {} + + pngjs@7.0.0: {} + + postcss@8.5.19: + dependencies: + nanoid: 3.3.16 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + pretty-format@27.5.1: + dependencies: + ansi-regex: 5.0.1 + ansi-styles: 5.2.0 + react-is: 17.0.2 + + proper-lockfile@4.1.2: + dependencies: + graceful-fs: 4.2.11 + retry: 0.12.0 + signal-exit: 3.0.7 + + protobufjs@7.6.5: + dependencies: + '@protobufjs/aspromise': 1.1.2 + '@protobufjs/base64': 1.1.2 + '@protobufjs/codegen': 2.0.5 + '@protobufjs/eventemitter': 1.1.1 + '@protobufjs/fetch': 1.1.1 + '@protobufjs/float': 1.0.2 + '@protobufjs/path': 1.1.2 + '@protobufjs/pool': 1.1.0 + '@protobufjs/utf8': 1.1.2 + '@types/node': 26.1.1 + long: 5.3.2 + + react-is@17.0.2: {} + + resolve-pkg-maps@1.0.0: + optional: true + + retry@0.12.0: {} + + retry@0.13.1: {} + + rolldown@1.0.0-rc.12(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1): + dependencies: + '@oxc-project/types': 0.122.0 + '@rolldown/pluginutils': 1.0.0-rc.12 + optionalDependencies: + '@rolldown/binding-android-arm64': 1.0.0-rc.12 + '@rolldown/binding-darwin-arm64': 1.0.0-rc.12 + '@rolldown/binding-darwin-x64': 1.0.0-rc.12 + '@rolldown/binding-freebsd-x64': 1.0.0-rc.12 + '@rolldown/binding-linux-arm-gnueabihf': 1.0.0-rc.12 + '@rolldown/binding-linux-arm64-gnu': 1.0.0-rc.12 + '@rolldown/binding-linux-arm64-musl': 1.0.0-rc.12 + '@rolldown/binding-linux-ppc64-gnu': 1.0.0-rc.12 + '@rolldown/binding-linux-s390x-gnu': 1.0.0-rc.12 + '@rolldown/binding-linux-x64-gnu': 1.0.0-rc.12 + '@rolldown/binding-linux-x64-musl': 1.0.0-rc.12 + '@rolldown/binding-openharmony-arm64': 1.0.0-rc.12 + '@rolldown/binding-wasm32-wasi': 1.0.0-rc.12(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1) + '@rolldown/binding-win32-arm64-msvc': 1.0.0-rc.12 + '@rolldown/binding-win32-x64-msvc': 1.0.0-rc.12 + transitivePeerDependencies: + - '@emnapi/core' + - '@emnapi/runtime' + + safe-buffer@5.2.1: {} + + semver@7.8.0: {} + + shebang-command@2.0.0: + dependencies: + shebang-regex: 3.0.0 + + shebang-regex@3.0.0: {} + + siginfo@2.0.0: {} + + signal-exit@3.0.7: {} + + sirv@3.0.2: + dependencies: + '@polka/url': 1.0.0-next.29 + mrmime: 2.0.1 + totalist: 3.0.1 + + source-map-js@1.2.1: {} + + stackback@0.0.2: {} + + std-env@4.2.0: {} + + tinybench@2.9.0: {} + + tinyexec@1.2.4: {} + + tinyglobby@0.2.17: + dependencies: + fdir: 6.5.0(picomatch@4.0.5) + picomatch: 4.0.5 + + tinypool@2.1.0: {} + + tinyrainbow@3.1.0: {} + + totalist@3.0.1: {} + + ts-algebra@2.0.0: {} + + tslib@2.8.1: {} + + tsx@4.21.0: + dependencies: + esbuild: 0.27.7 + get-tsconfig: 4.14.0 + optionalDependencies: + fsevents: 2.3.3 + optional: true + + typebox@1.1.38: {} + + typescript@6.0.3: {} + + undici-types@8.3.0: {} + + undici@8.5.0: {} + + vite-plus@0.2.5(@opentelemetry/api@1.9.0)(@types/node@26.1.1)(esbuild@0.27.7)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(vite@8.0.3(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@26.1.1)(esbuild@0.27.7)(jiti@2.7.0)(tsx@4.21.0)(yaml@2.9.0))(yaml@2.9.0): + dependencies: + '@oxc-project/types': 0.139.0 + '@oxlint/plugins': 1.73.0 + '@vitest/browser': 4.1.10(vite@8.0.3(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@26.1.1)(esbuild@0.27.7)(jiti@2.7.0)(tsx@4.21.0)(yaml@2.9.0))(vitest@4.1.10) + '@vitest/browser-preview': 4.1.10(vite@8.0.3(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@26.1.1)(esbuild@0.27.7)(jiti@2.7.0)(tsx@4.21.0)(yaml@2.9.0))(vitest@4.1.10) + '@vitest/expect': 4.1.10 + '@vitest/mocker': 4.1.10(vite@8.0.3(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@26.1.1)(esbuild@0.27.7)(jiti@2.7.0)(tsx@4.21.0)(yaml@2.9.0)) + '@vitest/pretty-format': 4.1.10 + '@vitest/runner': 4.1.10 + '@vitest/snapshot': 4.1.10 + '@vitest/spy': 4.1.10 + '@vitest/utils': 4.1.10 + '@voidzero-dev/vite-plus-core': 0.2.5(@types/node@26.1.1)(esbuild@0.27.7)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.9.0) + oxfmt: 0.58.0(vite-plus@0.2.5(@opentelemetry/api@1.9.0)(@types/node@26.1.1)(esbuild@0.27.7)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(vite@8.0.3(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@26.1.1)(esbuild@0.27.7)(jiti@2.7.0)(tsx@4.21.0)(yaml@2.9.0))(yaml@2.9.0)) + oxlint: 1.73.0(oxlint-tsgolint@0.24.0)(vite-plus@0.2.5(@opentelemetry/api@1.9.0)(@types/node@26.1.1)(esbuild@0.27.7)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(vite@8.0.3(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@26.1.1)(esbuild@0.27.7)(jiti@2.7.0)(tsx@4.21.0)(yaml@2.9.0))(yaml@2.9.0)) + oxlint-tsgolint: 0.24.0 + vitest: 4.1.10(@opentelemetry/api@1.9.0)(@types/node@26.1.1)(@vitest/browser-preview@4.1.10)(vite@8.0.3(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@26.1.1)(esbuild@0.27.7)(jiti@2.7.0)(tsx@4.21.0)(yaml@2.9.0)) + optionalDependencies: + '@voidzero-dev/vite-plus-darwin-arm64': 0.2.5 + '@voidzero-dev/vite-plus-darwin-x64': 0.2.5 + '@voidzero-dev/vite-plus-linux-arm64-gnu': 0.2.5 + '@voidzero-dev/vite-plus-linux-arm64-musl': 0.2.5 + '@voidzero-dev/vite-plus-linux-x64-gnu': 0.2.5 + '@voidzero-dev/vite-plus-linux-x64-musl': 0.2.5 + '@voidzero-dev/vite-plus-win32-arm64-msvc': 0.2.5 + '@voidzero-dev/vite-plus-win32-x64-msvc': 0.2.5 + transitivePeerDependencies: + - '@arethetypeswrong/core' + - '@edge-runtime/vm' + - '@opentelemetry/api' + - '@types/node' + - '@vitejs/devtools' + - '@vitest/coverage-istanbul' + - '@vitest/coverage-v8' + - '@vitest/ui' + - bufferutil + - esbuild + - happy-dom + - jiti + - jsdom + - less + - msw + - publint + - sass + - sass-embedded + - stylus + - sugarss + - svelte + - terser + - tsx + - typescript + - unplugin-unused + - unrun + - utf-8-validate + - vite + - yaml + + vite@8.0.3(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@26.1.1)(esbuild@0.27.7)(jiti@2.7.0)(tsx@4.21.0)(yaml@2.9.0): + dependencies: + lightningcss: 1.32.0 + picomatch: 4.0.5 + postcss: 8.5.19 + rolldown: 1.0.0-rc.12(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1) + tinyglobby: 0.2.17 + optionalDependencies: + '@types/node': 26.1.1 + esbuild: 0.27.7 + fsevents: 2.3.3 + jiti: 2.7.0 + tsx: 4.21.0 + yaml: 2.9.0 + transitivePeerDependencies: + - '@emnapi/core' + - '@emnapi/runtime' + + vitest@4.1.10(@opentelemetry/api@1.9.0)(@types/node@26.1.1)(@vitest/browser-preview@4.1.10)(vite@8.0.3(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@26.1.1)(esbuild@0.27.7)(jiti@2.7.0)(tsx@4.21.0)(yaml@2.9.0)): + dependencies: + '@vitest/expect': 4.1.10 + '@vitest/mocker': 4.1.10(vite@8.0.3(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@26.1.1)(esbuild@0.27.7)(jiti@2.7.0)(tsx@4.21.0)(yaml@2.9.0)) + '@vitest/pretty-format': 4.1.10 + '@vitest/runner': 4.1.10 + '@vitest/snapshot': 4.1.10 + '@vitest/spy': 4.1.10 + '@vitest/utils': 4.1.10 + es-module-lexer: 2.3.0 + expect-type: 1.4.0 + magic-string: 0.30.21 + obug: 2.1.3 + pathe: 2.0.3 + picomatch: 4.0.5 + std-env: 4.2.0 + tinybench: 2.9.0 + tinyexec: 1.2.4 + tinyglobby: 0.2.17 + tinyrainbow: 3.1.0 + vite: 8.0.3(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@26.1.1)(esbuild@0.27.7)(jiti@2.7.0)(tsx@4.21.0)(yaml@2.9.0) + why-is-node-running: 2.3.0 + optionalDependencies: + '@opentelemetry/api': 1.9.0 + '@types/node': 26.1.1 + '@vitest/browser-preview': 4.1.10(vite@8.0.3(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@26.1.1)(esbuild@0.27.7)(jiti@2.7.0)(tsx@4.21.0)(yaml@2.9.0))(vitest@4.1.10) + transitivePeerDependencies: + - msw + + web-streams-polyfill@3.3.3: {} + + which@2.0.2: + dependencies: + isexe: 2.0.0 + + why-is-node-running@2.3.0: + dependencies: + siginfo: 2.0.0 + stackback: 0.0.2 + + ws@8.21.1: {} + + yaml@2.9.0: {} + + yuku-codegen@0.5.48: + dependencies: + '@yuku-toolchain/types': 0.5.43 + optionalDependencies: + '@yuku-codegen/binding-darwin-arm64': 0.5.48 + '@yuku-codegen/binding-darwin-x64': 0.5.48 + '@yuku-codegen/binding-freebsd-x64': 0.5.48 + '@yuku-codegen/binding-linux-arm-gnu': 0.5.48 + '@yuku-codegen/binding-linux-arm-musl': 0.5.48 + '@yuku-codegen/binding-linux-arm64-gnu': 0.5.48 + '@yuku-codegen/binding-linux-arm64-musl': 0.5.48 + '@yuku-codegen/binding-linux-x64-gnu': 0.5.48 + '@yuku-codegen/binding-linux-x64-musl': 0.5.48 + '@yuku-codegen/binding-win32-arm64': 0.5.48 + '@yuku-codegen/binding-win32-x64': 0.5.48 + + yuku-parser@0.5.48: + dependencies: + '@yuku-toolchain/types': 0.5.43 + optionalDependencies: + '@yuku-parser/binding-darwin-arm64': 0.5.48 + '@yuku-parser/binding-darwin-x64': 0.5.48 + '@yuku-parser/binding-freebsd-x64': 0.5.48 + '@yuku-parser/binding-linux-arm-gnu': 0.5.48 + '@yuku-parser/binding-linux-arm-musl': 0.5.48 + '@yuku-parser/binding-linux-arm64-gnu': 0.5.48 + '@yuku-parser/binding-linux-arm64-musl': 0.5.48 + '@yuku-parser/binding-linux-x64-gnu': 0.5.48 + '@yuku-parser/binding-linux-x64-musl': 0.5.48 + '@yuku-parser/binding-win32-arm64': 0.5.48 + '@yuku-parser/binding-win32-x64': 0.5.48 + + zod-to-json-schema@3.25.2(zod@4.4.3): + dependencies: + zod: 4.4.3 + + zod@4.4.3: {} diff --git a/src/plugins/pi/content/pnpm-workspace.yaml b/src/plugins/pi/content/pnpm-workspace.yaml new file mode 100644 index 0000000..f66b35b --- /dev/null +++ b/src/plugins/pi/content/pnpm-workspace.yaml @@ -0,0 +1,6 @@ +allowBuilds: + "@google/genai": false + braintrust: false + esbuild: true + koffi: true + protobufjs: true diff --git a/src/plugins/pi/content/scripts/resolve-pi-versions.mjs b/src/plugins/pi/content/scripts/resolve-pi-versions.mjs new file mode 100644 index 0000000..8871e46 --- /dev/null +++ b/src/plugins/pi/content/scripts/resolve-pi-versions.mjs @@ -0,0 +1,121 @@ +#!/usr/bin/env node + +import { appendFileSync, mkdtempSync } from "node:fs"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; +import { execFileSync } from "node:child_process"; + +const packageFamily = { + alias: "@earendil-works/pi-coding-agent", + sources: ["@earendil-works/pi-coding-agent", "@mariozechner/pi-coding-agent"], +}; +const count = Number(process.env.PI_VERSION_COUNT ?? "5"); +const stableVersionPattern = /^\d+\.\d+\.\d+$/; + +if (!Number.isInteger(count) || count <= 0) { + throw new Error( + `PI_VERSION_COUNT must be a positive integer, got: ${process.env.PI_VERSION_COUNT ?? "undefined"}`, + ); +} + +const npmQueryDirectory = mkdtempSync(join(tmpdir(), "pi-version-query-")); + +function npmViewVersions(packageName) { + const output = execFileSync("npm", ["view", packageName, "versions", "--json"], { + cwd: npmQueryDirectory, + encoding: "utf8", + stdio: ["ignore", "pipe", "inherit"], + }).trim(); + + const parsed = JSON.parse(output); + const versions = Array.isArray(parsed) ? parsed : [parsed]; + return versions.filter((version) => stableVersionPattern.test(version)); +} + +function compareVersions(a, b) { + const aParts = a.split(".").map(Number); + const bParts = b.split(".").map(Number); + + for (let index = 0; index < 3; index += 1) { + const delta = aParts[index] - bParts[index]; + if (delta !== 0) { + return delta; + } + } + + return 0; +} + +const versionsBySource = packageFamily.sources.map((packageName) => ({ + packageName, + versions: npmViewVersions(packageName), +})); +const availableVersions = [...new Set(versionsBySource.flatMap(({ versions }) => versions))].sort( + compareVersions, +); + +const releaseLines = []; + +for (const version of availableVersions) { + const [major, minor] = version.split("."); + const line = `${major}.${minor}`; + const previousReleaseLine = releaseLines.at(-1); + + if (previousReleaseLine?.line === line) { + previousReleaseLine.version = version; + continue; + } + + releaseLines.push({ line, version }); +} + +const selectedVersions = releaseLines.map(({ version }) => version).slice(-count); + +if (selectedVersions.length < count) { + throw new Error( + `Expected at least ${count} stable pi release lines across ${packageFamily.sources.join( + "/", + )}, found ${selectedVersions.length}`, + ); +} + +function installSpecFor(version) { + const source = versionsBySource.find(({ versions }) => versions.includes(version))?.packageName; + if (!source) { + throw new Error(`No source package found for pi-coding-agent@${version}`); + } + return source === packageFamily.alias + ? `${packageFamily.alias}@${version}` + : `${packageFamily.alias}@npm:${source}@${version}`; +} + +const selectedTargets = selectedVersions.map((version) => ({ + version, + piCodingAgentSpec: installSpecFor(version), +})); + +const outputs = { + versions: JSON.stringify(selectedTargets), + latest: selectedVersions[selectedVersions.length - 1], + oldest: selectedVersions[0], +}; + +if (process.env.GITHUB_OUTPUT) { + for (const [key, value] of Object.entries(outputs)) { + appendFileSync(process.env.GITHUB_OUTPUT, `${key}=${value}\n`); + } +} + +if (process.env.GITHUB_STEP_SUMMARY) { + appendFileSync( + process.env.GITHUB_STEP_SUMMARY, + [ + "## Supported pi compatibility versions", + "", + `Testing the latest ${count} stable pi release lines: ${selectedVersions.join(", ")}`, + "", + ].join("\n"), + ); +} + +console.log(`Resolved pi compatibility versions: ${selectedVersions.join(", ")}`); diff --git a/src/plugins/pi/content/scripts/sync-version.mjs b/src/plugins/pi/content/scripts/sync-version.mjs new file mode 100644 index 0000000..b664cb6 --- /dev/null +++ b/src/plugins/pi/content/scripts/sync-version.mjs @@ -0,0 +1,23 @@ +#!/usr/bin/env node +import { readFileSync, writeFileSync } from "node:fs"; + +const check = process.argv.includes("--check"); +const packageJson = JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf8")); +const version = packageJson.version; + +if (typeof version !== "string" || version.length === 0) { + throw new Error("package.json version must be a non-empty string"); +} + +const target = new URL("../src/version.ts", import.meta.url); +const content = `// This file is generated by scripts/sync-version.mjs. Do not edit by hand.\nexport const EXTENSION_VERSION = ${JSON.stringify(version)};\n`; + +if (check) { + const current = readFileSync(target, "utf8"); + if (current !== content) { + console.error("src/version.ts is out of sync with package.json. Run `pnpm run sync:version`."); + process.exit(1); + } +} else { + writeFileSync(target, content); +} diff --git a/src/plugins/pi/content/src/config.test.ts b/src/plugins/pi/content/src/config.test.ts new file mode 100644 index 0000000..3730c94 --- /dev/null +++ b/src/plugins/pi/content/src/config.test.ts @@ -0,0 +1,116 @@ +import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs"; +import { tmpdir } from "node:os"; +import { dirname, join } from "node:path"; +import { afterEach, beforeEach, describe, expect, it } from "vitest"; +import { loadConfig } from "./config.ts"; + +const ENVIRONMENT_KEYS = [ + "BRAINTRUST_PROFILE", + "BRAINTRUST_ORG_NAME", + "BRAINTRUST_PROJECT", + "BRAINTRUST_ADDITIONAL_METADATA", + "BRAINTRUST_SHOW_UI", + "BRAINTRUST_SHOW_TRACE_LINK", + "TRACE_TO_BRAINTRUST", +] as const; + +const originalEnvironment = new Map(); +const originalHome = process.env.HOME; +let home: string; +let cwd: string; + +function writeJson(path: string, value: unknown): void { + mkdirSync(dirname(path), { recursive: true }); + writeFileSync(path, JSON.stringify(value)); +} + +beforeEach(() => { + home = mkdtempSync(join(tmpdir(), "pi-config-home-")); + cwd = mkdtempSync(join(tmpdir(), "pi-config-project-")); + process.env.HOME = home; + for (const key of ENVIRONMENT_KEYS) { + originalEnvironment.set(key, process.env[key]); + delete process.env[key]; + } +}); + +afterEach(() => { + rmSync(home, { recursive: true, force: true }); + rmSync(cwd, { recursive: true, force: true }); + for (const key of ENVIRONMENT_KEYS) { + const value = originalEnvironment.get(key); + if (value === undefined) delete process.env[key]; + else process.env[key] = value; + } + if (originalHome === undefined) delete process.env.HOME; + else process.env.HOME = originalHome; +}); + +describe("loadConfig", () => { + it("defaults to disabled tracing with the daemon default profile", () => { + expect(loadConfig(cwd)).toEqual({ + enabled: false, + projectName: "pi", + showUi: true, + showTraceLink: true, + }); + }); + + it("layers global, project, and invocation selection", () => { + writeJson(join(home, ".pi", "agent", "braintrust.json"), { + trace_to_braintrust: true, + profile: "global", + org_name: "global-org", + project: "global-project", + additional_metadata: { source: "global" }, + }); + writeJson(join(cwd, ".pi", "braintrust.json"), { + profile: "project", + project: "project-project", + show_trace_link: false, + }); + process.env.BRAINTRUST_PROFILE = "run"; + process.env.BRAINTRUST_ORG_NAME = "run-org"; + process.env.BRAINTRUST_PROJECT = "run-project"; + process.env.BRAINTRUST_ADDITIONAL_METADATA = '{"source":"run"}'; + + expect(loadConfig(cwd)).toEqual({ + enabled: true, + profile: "run", + orgName: "run-org", + projectName: "run-project", + additionalMetadata: { source: "run" }, + showUi: true, + showTraceLink: false, + }); + }); + + it("accepts invocation-local enablement and UI overrides", () => { + process.env.TRACE_TO_BRAINTRUST = "true"; + process.env.BRAINTRUST_SHOW_UI = "0"; + process.env.BRAINTRUST_SHOW_TRACE_LINK = "no"; + + expect(loadConfig(cwd)).toMatchObject({ + enabled: true, + showUi: false, + showTraceLink: false, + }); + }); + + it("ignores malformed files, values, and metadata", () => { + writeJson(join(home, ".pi", "agent", "braintrust.json"), { + trace_to_braintrust: "sometimes", + project: [], + additional_metadata: [], + }); + writeFileSync(join(cwd, ".pi-invalid"), "ignored"); + process.env.BRAINTRUST_ADDITIONAL_METADATA = "not-json"; + + expect(loadConfig(cwd)).toEqual({ + enabled: false, + projectName: "pi", + showUi: true, + showTraceLink: true, + }); + }); +}); diff --git a/src/plugins/pi/content/src/config.ts b/src/plugins/pi/content/src/config.ts new file mode 100644 index 0000000..51d318a --- /dev/null +++ b/src/plugins/pi/content/src/config.ts @@ -0,0 +1,102 @@ +import { existsSync, readFileSync } from "node:fs"; +import { homedir } from "node:os"; +import { join } from "node:path"; +import * as piCodingAgent from "@earendil-works/pi-coding-agent"; + +export interface PiConfig { + enabled: boolean; + profile?: string; + orgName?: string; + projectName: string; + additionalMetadata?: Record; + showUi: boolean; + showTraceLink: boolean; +} + +type ConfigRecord = Record; + +const PROJECT_CONFIG_DIR_NAME = + typeof (piCodingAgent as { CONFIG_DIR_NAME?: unknown }).CONFIG_DIR_NAME === "string" + ? (piCodingAgent as { CONFIG_DIR_NAME: string }).CONFIG_DIR_NAME + : ".pi"; + +function record(value: unknown): ConfigRecord | undefined { + return value !== null && typeof value === "object" && !Array.isArray(value) + ? (value as ConfigRecord) + : undefined; +} + +function nonEmptyString(value: unknown): string | undefined { + return typeof value === "string" && value.trim() ? value : undefined; +} + +function boolean(value: unknown): boolean | undefined { + if (typeof value === "boolean") return value; + if (typeof value !== "string" && typeof value !== "number") return undefined; + switch (String(value).trim().toLowerCase()) { + case "1": + case "true": + case "yes": + case "on": + return true; + case "0": + case "false": + case "no": + case "off": + return false; + default: + return undefined; + } +} + +function readConfig(path: string): ConfigRecord | undefined { + if (!existsSync(path)) return undefined; + try { + return record(JSON.parse(readFileSync(path, "utf8"))); + } catch { + return undefined; + } +} + +function applyConfig(config: PiConfig, source: ConfigRecord | undefined): void { + if (!source) return; + config.profile = nonEmptyString(source.profile) ?? config.profile; + config.orgName = nonEmptyString(source.org_name) ?? config.orgName; + config.projectName = nonEmptyString(source.project) ?? config.projectName; + config.enabled = boolean(source.trace_to_braintrust) ?? config.enabled; + config.additionalMetadata = record(source.additional_metadata) ?? config.additionalMetadata; + config.showUi = boolean(source.show_ui) ?? config.showUi; + config.showTraceLink = boolean(source.show_trace_link) ?? config.showTraceLink; +} + +function environmentMetadata(value: string | undefined): ConfigRecord | undefined { + if (!value) return undefined; + try { + return record(JSON.parse(value)); + } catch { + return undefined; + } +} + +export function loadConfig(cwd = process.cwd()): PiConfig { + const config: PiConfig = { + enabled: false, + projectName: "pi", + showUi: true, + showTraceLink: true, + }; + + applyConfig(config, readConfig(join(homedir(), ".pi", "agent", "braintrust.json"))); + applyConfig(config, readConfig(join(cwd, PROJECT_CONFIG_DIR_NAME, "braintrust.json"))); + + config.profile = nonEmptyString(process.env.BRAINTRUST_PROFILE) ?? config.profile; + config.orgName = nonEmptyString(process.env.BRAINTRUST_ORG_NAME) ?? config.orgName; + config.projectName = nonEmptyString(process.env.BRAINTRUST_PROJECT) ?? config.projectName; + config.enabled = boolean(process.env.TRACE_TO_BRAINTRUST) ?? config.enabled; + config.additionalMetadata = + environmentMetadata(process.env.BRAINTRUST_ADDITIONAL_METADATA) ?? config.additionalMetadata; + config.showUi = boolean(process.env.BRAINTRUST_SHOW_UI) ?? config.showUi; + config.showTraceLink = boolean(process.env.BRAINTRUST_SHOW_TRACE_LINK) ?? config.showTraceLink; + + return config; +} diff --git a/src/plugins/pi/content/src/daemon-adapter.test.ts b/src/plugins/pi/content/src/daemon-adapter.test.ts new file mode 100644 index 0000000..7e6b4d1 --- /dev/null +++ b/src/plugins/pi/content/src/daemon-adapter.test.ts @@ -0,0 +1,138 @@ +import { beforeEach, describe, expect, it, vi } from "vitest"; + +const mockState = vi.hoisted(() => ({ + logs: [] as Array>, + flushes: [] as string[], + closed: 0, +})); + +vi.mock("./runtime/daemon-client.ts", () => ({ + DaemonClient: class { + async log(envelope: Record): Promise { + mockState.logs.push(envelope); + return true; + } + async flush(sessionId: string): Promise { + mockState.flushes.push(sessionId); + return true; + } + async status(sessionId: string): Promise> { + return { + daemon_version: "test", + uptime_ms: 1, + sessions: [ + { + session_id: sessionId, + source: "pi", + queued: 0, + spans_emitted: 1, + permalink: "https://www.braintrust.dev/trace/1", + }, + ], + }; + } + async close(): Promise { + mockState.closed += 1; + } + }, +})); + +vi.mock("./config.ts", () => ({ + loadConfig: () => ({ + enabled: true, + profile: "work", + orgName: "acme", + projectName: "agents", + additionalMetadata: { team: "platform" }, + showUi: true, + showTraceLink: true, + }), +})); + +describe("Pi daemon adapter", () => { + beforeEach(() => { + mockState.logs.length = 0; + mockState.flushes.length = 0; + mockState.closed = 0; + }); + + it("forwards native events and keeps the trace-link UI", async () => { + const handlers = new Map Promise>(); + const statuses: unknown[] = []; + const widgets: unknown[] = []; + const pi = { + on: (name: string, handler: (...args: unknown[]) => Promise) => + handlers.set(name, handler), + }; + const ctx = { + cwd: "/tmp/project", + model: { provider: "openai", id: "gpt-5" }, + hasUI: true, + ui: { + setStatus: (...args: unknown[]) => statuses.push(args), + setWidget: (...args: unknown[]) => widgets.push(args), + }, + sessionManager: { + getSessionFile: () => "/tmp/session.jsonl", + getSessionId: () => "native-session", + }, + }; + const { default: extension } = await import("./index.ts"); + extension(pi as never); + + expect([...handlers.keys()]).toEqual([ + "session_start", + "input", + "before_agent_start", + "context", + "before_provider_request", + "after_provider_response", + "message_update", + "thinking_level_select", + "message_end", + "tool_execution_start", + "tool_execution_end", + "session_before_compact", + "session_compact", + "session_before_tree", + "session_tree", + "agent_end", + "session_shutdown", + ]); + + await handlers.get("session_start")?.({ reason: "new" }, ctx); + await handlers.get("before_agent_start")?.({ prompt: "hello" }, ctx); + await handlers.get("agent_end")?.({ messages: [] }); + await handlers.get("session_shutdown")?.({ reason: "quit" }, ctx); + + expect(mockState.logs.map((log) => log.event)).toEqual([ + "session_start", + "before_agent_start", + "agent_end", + "session_shutdown", + ]); + expect( + mockState.logs.every((log) => log.source === "pi" && typeof log.ts_ms === "number"), + ).toBe(true); + expect(mockState.logs[0]?.route).toEqual({ + auth: { profile: "work", org_name: "acme" }, + destination: { type: "project_logs", project_name: "agents" }, + flush_mode: "flush_on_turn_end", + additional_metadata: { team: "platform" }, + }); + expect(mockState.logs[0]?.payload).toMatchObject({ + event: { reason: "new" }, + extension_version: expect.any(String), + session_file: "/tmp/session.jsonl", + native_session_id: "native-session", + cwd: "/tmp/project", + model: { provider: "openai", id: "gpt-5" }, + }); + expect(mockState.flushes).toHaveLength(2); + expect( + widgets.some((args) => JSON.stringify(args).includes("https://www.braintrust.dev/trace/1")), + ).toBe(true); + expect(statuses.length).toBeGreaterThan(0); + expect(mockState.closed).toBe(1); + }); +}); diff --git a/src/plugins/pi/content/src/index.ts b/src/plugins/pi/content/src/index.ts new file mode 100644 index 0000000..1a0ffd7 --- /dev/null +++ b/src/plugins/pi/content/src/index.ts @@ -0,0 +1,157 @@ +import { createHash, randomUUID } from "node:crypto"; +import { resolve } from "node:path"; +import { + VERSION as PI_VERSION, + type ExtensionAPI, + type ExtensionContext, +} from "@earendil-works/pi-coding-agent"; +import { loadConfig } from "./config.ts"; +import { DaemonClient } from "./runtime/daemon-client.ts"; +import { EXTENSION_VERSION } from "./version.ts"; + +const STATUS_KEY = "braintrust-tracing"; +const WIDGET_KEY = "braintrust-trace-link"; + +function sessionKeyFor( + sessionFile: string | undefined, + sessionId: string | undefined, + cwd: string, +): string { + if (sessionFile) return `file:${sessionFile}`; + const projectKey = createHash("sha256").update(resolve(cwd)).digest("hex").slice(0, 12); + return `ephemeral:${projectKey}:${sessionId ?? randomUUID()}`; +} + +function nativePayload(value: unknown): unknown { + try { + return JSON.parse(JSON.stringify(value)); + } catch { + return { serialization_error: "Pi event payload was not JSON serializable" }; + } +} + +function sessionDescriptor(ctx: ExtensionContext): { + sessionId: string; + sessionFile?: string; + nativeSessionId?: string; +} { + const sessionFile = ctx.sessionManager.getSessionFile(); + const nativeSessionId = ctx.sessionManager.getSessionId(); + return { + sessionId: sessionKeyFor(sessionFile, nativeSessionId, ctx.cwd), + sessionFile, + nativeSessionId, + }; +} + +export default function braintrustPiExtension(pi: ExtensionAPI): void { + const config = loadConfig(process.cwd()); + if (!config.enabled) return; + + let sessionId: string | undefined; + let lastContext: ExtensionContext | undefined; + const client = new DaemonClient({ + source: "pi", + pluginVersion: EXTENSION_VERSION, + warn: (message) => { + if (lastContext?.hasUI && config.showUi) { + lastContext.ui.setStatus(STATUS_KEY, `Braintrust tracing unavailable: ${message}`); + } + }, + }); + + const remember = (ctx: ExtensionContext): ReturnType => { + lastContext = ctx; + const descriptor = sessionDescriptor(ctx); + sessionId = descriptor.sessionId; + return descriptor; + }; + + const refreshUi = async (ctx: ExtensionContext): Promise => { + if (!ctx.hasUI || !config.showUi || !sessionId) return; + const status = await client.status(sessionId); + const daemonSession = status?.sessions.find((session) => session.session_id === sessionId); + if (daemonSession?.last_error) { + ctx.ui.setStatus(STATUS_KEY, `Braintrust: ${daemonSession.last_error}`); + } else { + ctx.ui.setStatus(STATUS_KEY, "Braintrust: tracing"); + } + ctx.ui.setWidget( + WIDGET_KEY, + config.showTraceLink && daemonSession?.permalink + ? ["Braintrust trace", daemonSession.permalink] + : undefined, + { placement: "belowEditor" }, + ); + }; + + const forward = async ( + name: string, + event: unknown, + ctx?: ExtensionContext, + flush = false, + ): Promise => { + const descriptor = ctx ? remember(ctx) : undefined; + if (!sessionId) return; + await client.log({ + source: "pi", + source_version: PI_VERSION, + session_id: sessionId, + event: name, + ts_ms: Date.now(), + payload: { + event: nativePayload(event), + extension_version: EXTENSION_VERSION, + session_file: descriptor?.sessionFile, + native_session_id: descriptor?.nativeSessionId, + cwd: ctx?.cwd, + model: nativePayload(ctx?.model), + }, + route: { + auth: { + ...(config.profile ? { profile: config.profile } : {}), + ...(config.orgName ? { org_name: config.orgName } : {}), + }, + destination: { type: "project_logs", project_name: config.projectName }, + flush_mode: "flush_on_turn_end", + additional_metadata: config.additionalMetadata, + }, + }); + if (flush) { + await client.flush(sessionId); + if (ctx) await refreshUi(ctx); + } + }; + + pi.on("session_start", async (event, ctx) => { + await forward("session_start", event, ctx); + await refreshUi(ctx); + }); + pi.on("input", async (event) => forward("input", event)); + pi.on("before_agent_start", async (event, ctx) => forward("before_agent_start", event, ctx)); + pi.on("context", async (event, ctx) => forward("context", event, ctx)); + pi.on("before_provider_request", async (event) => forward("before_provider_request", event)); + pi.on("after_provider_response", async (event) => forward("after_provider_response", event)); + pi.on("message_update", async (event) => forward("message_update", event)); + pi.on("thinking_level_select", async (event) => forward("thinking_level_select", event)); + pi.on("message_end", async (event) => forward("message_end", event)); + pi.on("tool_execution_start", async (event) => forward("tool_execution_start", event)); + pi.on("tool_execution_end", async (event, ctx) => forward("tool_execution_end", event, ctx)); + pi.on("session_before_compact", async (event, ctx) => + forward("session_before_compact", event, ctx), + ); + pi.on("session_compact", async (event, ctx) => forward("session_compact", event, ctx, true)); + pi.on("session_before_tree", async (event, ctx) => forward("session_before_tree", event, ctx)); + pi.on("session_tree", async (event, ctx) => forward("session_tree", event, ctx, true)); + pi.on("agent_end", async (event) => forward("agent_end", event, undefined, true)); + pi.on("session_shutdown", async (event, ctx) => { + await forward("session_shutdown", event, ctx, true); + if (ctx.hasUI) { + ctx.ui.setStatus(STATUS_KEY, undefined); + ctx.ui.setWidget(WIDGET_KEY, undefined); + } + await client.close(); + sessionId = undefined; + lastContext = undefined; + }); +} diff --git a/src/plugins/pi/content/src/version.ts b/src/plugins/pi/content/src/version.ts new file mode 100644 index 0000000..6b442c4 --- /dev/null +++ b/src/plugins/pi/content/src/version.ts @@ -0,0 +1,2 @@ +// This file is generated by scripts/sync-version.mjs. Do not edit by hand. +export const EXTENSION_VERSION = "0.10.0"; diff --git a/src/plugins/pi/content/tsconfig.json b/src/plugins/pi/content/tsconfig.json new file mode 100644 index 0000000..8aa6f8e --- /dev/null +++ b/src/plugins/pi/content/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2023", + "module": "NodeNext", + "moduleResolution": "NodeNext", + "allowImportingTsExtensions": true, + "noEmit": true, + "strict": true, + "verbatimModuleSyntax": true, + "skipLibCheck": true, + "types": ["node"], + "lib": ["ES2023", "DOM"] + }, + "include": ["src/**/*.ts"] +} diff --git a/src/plugins/pi/content/vite.config.ts b/src/plugins/pi/content/vite.config.ts new file mode 100644 index 0000000..7852e3c --- /dev/null +++ b/src/plugins/pi/content/vite.config.ts @@ -0,0 +1,23 @@ +import { defineConfig } from "vite-plus"; + +export default defineConfig({ + fmt: { + ignorePatterns: ["AGENTS.md", "README.md", "dist/**"], + }, + lint: { + ignorePatterns: ["dist/**"], + options: { + typeAware: true, + typeCheck: true, + }, + }, + test: { + include: ["src/**/*.test.ts"], + }, + pack: { + entry: ["src/index.ts"], + dts: true, + format: ["esm"], + sourcemap: true, + }, +}); diff --git a/src/plugins/pi/publish.sh b/src/plugins/pi/publish.sh new file mode 100755 index 0000000..26a4c24 --- /dev/null +++ b/src/plugins/pi/publish.sh @@ -0,0 +1,18 @@ +#!/usr/bin/env bash +set -euo pipefail + +PLUGIN_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +BUILD_DIR="${BUILD_DIR:-$PLUGIN_DIR/../../../dist/pi}" +NPM_TAG="${NPM_TAG:-latest}" +case "$NPM_TAG" in latest|rc|next|beta) ;; *) echo "unsupported NPM_TAG: $NPM_TAG" >&2; exit 1;; esac +tarball="$(find "$BUILD_DIR" -maxdepth 1 -name 'braintrust-pi-extension-*.tgz' -print -quit)" +[[ -n "$tarball" ]] || { echo "build Pi before publishing" >&2; exit 1; } +version="$(node -p "require('$BUILD_DIR/package.json').version")" +if npm view "@braintrust/pi-extension@$version" version >/dev/null 2>&1; then + echo "@braintrust/pi-extension@$version is already published" >&2; exit 1 +fi +if [[ "${DRY_RUN:-}" == "1" ]]; then npm publish "$tarball" --tag "$NPM_TAG" --dry-run; exit 0; fi +[[ "${RELEASE_CONFIRM:-}" == "publish-@braintrust/pi-extension@$version" ]] || { + echo "set RELEASE_CONFIRM=publish-@braintrust/pi-extension@$version for a release-approved publish" >&2; exit 1; +} +npm publish "$tarball" --tag "$NPM_TAG" diff --git a/src/plugins/pi/validate.sh b/src/plugins/pi/validate.sh new file mode 100755 index 0000000..e74677b --- /dev/null +++ b/src/plugins/pi/validate.sh @@ -0,0 +1,40 @@ +#!/usr/bin/env bash +set -euo pipefail + +TARGET_DIR="${1:?usage: validate.sh }" +fail() { echo "validate: $*" >&2; exit 1; } +TARGET_DIR="$(cd "$TARGET_DIR" && pwd)" + +[[ -f "$TARGET_DIR/package.json" ]] || fail "missing package.json" +[[ -f "$TARGET_DIR/dist/index.mjs" ]] || fail "missing production entrypoint" +tarball="$(find "$TARGET_DIR" -maxdepth 1 -name 'braintrust-pi-extension-*.tgz' -print -quit)" +[[ -n "$tarball" ]] || fail "missing npm tarball" + +(cd "$TARGET_DIR" && pnpm install --frozen-lockfile && pnpm run check && pnpm test && pnpm run smoke && pnpm run pack) +pack_check_dir="$(mktemp -d)" +(cd "$TARGET_DIR" && pnpm pack --pack-destination "$pack_check_dir" >/dev/null) + +contents="$(tar -tzf "$tarball")" +for required in package/dist/index.mjs package/dist/index.d.mts package/README.md package/LICENSE; do + grep -q "^${required}$" <<<"$contents" || fail "tarball omits $required" +done +if grep -q '^package/src/' <<<"$contents"; then fail "tarball contains local tracing source"; fi +node -e ' + const p = require(process.argv[1]); + for (const field of ["dependencies", "devDependencies", "peerDependencies", "optionalDependencies"]) { + if (p[field]?.braintrust) process.exit(1); + } +' "$TARGET_DIR/package.json" || fail "Braintrust SDK remains in Pi package dependencies" +for removed in client.ts legacy-processor.ts state.ts types.ts utils.ts; do + [[ ! -e "$TARGET_DIR/src/$removed" ]] || fail "legacy tracing source remains: src/$removed" +done +if grep -RInE \ + "from [\"']braintrust[\"']|initLogger|startSpan|updateSpan|BRAINTRUST_API_KEY|api_key|state_dir|parent_span_id|root_span_id" \ + "$TARGET_DIR/src"; then + fail "Pi source still contains local tracing, credential, or span-management logic" +fi +if grep -Eq '(^|[ /])braintrust@|^[[:space:]]+braintrust:' "$TARGET_DIR/pnpm-lock.yaml"; then + fail "Braintrust SDK remains in the Pi lockfile" +fi + +echo "validate: Pi npm package OK ($TARGET_DIR)" diff --git a/src/runtime/js-daemon-client/src/index.ts b/src/runtime/js-daemon-client/src/index.ts index 6aef0bc..64b139f 100644 --- a/src/runtime/js-daemon-client/src/index.ts +++ b/src/runtime/js-daemon-client/src/index.ts @@ -148,9 +148,10 @@ export class DaemonClient { async status(sessionId?: string): Promise { return this.serial(async () => { try { - return (await this.request("status.get", { - ...(sessionId ? { session_id: sessionId } : {}), - })) as DaemonStatus + return (await this.request( + "status.get", + sessionId ? { session_id: sessionId } : {}, + )) as DaemonStatus } catch (error) { this.warnOnce(`status:${String(error)}`) return undefined