Refactor testing scripts in package.json and update dependencies

- Simplified test scripts in package.json by removing specific config references for vitest.
- Updated @tauri-apps/api dependency version to 2.10.1.
- Removed unused dependencies from yarn.lock and updated Cargo.toml and Cargo.lock for tinyhumansai to version 0.1.4.
- Enhanced memory management in Conversations and Login components by ensuring async token synchronization.
- Introduced recall_memory command in Tauri for improved context retrieval from memory.
This commit is contained in:
M3gA-Mind
2026-03-21 08:54:57 +05:30
parent d51f67445c
commit fa03a0b919
12 changed files with 248 additions and 134 deletions
+6 -8
View File
@@ -21,11 +21,11 @@
"macos:dev": "yarn macos:build:debug && open 'src-tauri/target/debug/bundle/macos/AlphaHuman.app'",
"android:dev": "tauri android dev",
"android:build": "tauri android build",
"test": "vitest run --config test/vitest.config.ts",
"test:unit": "vitest run --config test/vitest.config.ts",
"test:unit:watch": "vitest --config test/vitest.config.ts --watch",
"test:watch": "vitest --config test/vitest.config.ts --watch",
"test:coverage": "vitest run --config test/vitest.config.ts --coverage",
"test": "vitest run",
"test:unit": "vitest run",
"test:unit:watch": "vitest",
"test:watch": "vitest",
"test:coverage": "vitest run --coverage",
"test:rust": "source $HOME/.cargo/env 2>/dev/null; cargo test --manifest-path src-tauri/Cargo.toml",
"test:e2e:build": "bash scripts/e2e-build.sh",
"test:e2e:login": "bash scripts/e2e-login.sh",
@@ -48,13 +48,12 @@
"@scure/bip32": "^2.0.1",
"@scure/bip39": "^2.0.1",
"@sentry/react": "^10.38.0",
"@tauri-apps/api": "^2",
"@tauri-apps/api": "2.10.1",
"@tauri-apps/plugin-deep-link": "^2",
"@tauri-apps/plugin-opener": "^2",
"@tauri-apps/plugin-os": "^2.3.2",
"@tauri-apps/plugin-shell": "~2",
"@types/react-router-dom": "^5.3.3",
"@types/three": "^0.183.1",
"buffer": "^6.0.3",
"debug": "^4.4.3",
"immer": "^11.1.3",
@@ -71,7 +70,6 @@
"redux-persist": "^6.0.0",
"socket.io-client": "^4.8.3",
"telegram": "^2.26.22",
"three": "^0.183.2",
"util": "^0.12.5",
"zustand": "^5.0.10"
},
+2 -2
View File
@@ -8405,9 +8405,9 @@ dependencies = [
[[package]]
name = "tinyhumansai"
version = "0.1.2"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85a17392a3521fbef245da18fcef9e37bca8d97d9795da973a398e5d64d1b8af"
checksum = "f7a88dba7fe194a507d0351c5f8b5cd8518fb30f8307dd788333f9715f51c44e"
dependencies = [
"reqwest",
"serde",
+1 -1
View File
@@ -131,7 +131,7 @@ opentelemetry_sdk = { version = "0.31", default-features = false, features = ["t
opentelemetry-otlp = { version = "0.31", default-features = false, features = ["trace", "metrics", "http-proto", "reqwest-client", "reqwest-rustls-webpki-roots"] }
tokio-stream = { version = "0.1.18", features = ["full"] }
url = "2"
tinyhumansai = "0.1"
tinyhumansai = "0.1.4"
# Optional integrations
matrix-sdk = { version = "0.16", optional = true, default-features = false, features = ["e2e-encryption", "rustls-tls", "markdown"] }
+34
View File
@@ -27,6 +27,40 @@ pub async fn init_memory_client(
Ok(())
}
/// Recall context from the TinyHumans Master memory node for a skill integration.
/// Returns the recalled context string (or null if the server had nothing to return).
#[tauri::command]
pub async fn recall_memory(
skill_id: String,
integration_id: String,
max_chunks: Option<u32>,
state: tauri::State<'_, MemoryState>,
) -> Result<Option<String>, String> {
log::info!(
"[memory] recall_memory: entry (skill_id={skill_id}, integration_id={integration_id}, max_chunks={max_chunks:?})"
);
let client = state.0.lock().map_err(|e| e.to_string())?.clone();
match client {
Some(c) => {
let result = c
.recall_skill_context(&skill_id, &integration_id, max_chunks.unwrap_or(10))
.await;
match &result {
Ok(ctx) => log::info!(
"[memory] recall_memory: exit — ok (has_context={})",
ctx.is_some()
),
Err(e) => log::warn!("[memory] recall_memory: exit — error: {e}"),
}
result
}
None => {
log::warn!("[memory] recall_memory: exit — client not initialised (no JWT set)");
Err("Memory layer not configured — JWT token not yet set".into())
}
}
}
/// Query the TinyHumans memory for a skill integration.
/// Returns the RAG context string to inject into AI prompts.
#[tauri::command]
+2
View File
@@ -797,6 +797,7 @@ pub fn run() {
// Memory commands (TinyHumans Neocortex)
init_memory_client,
memory_query,
recall_memory,
]
}
#[cfg(not(desktop))]
@@ -916,6 +917,7 @@ pub fn run() {
// Memory commands (TinyHumans Neocortex)
init_memory_client,
memory_query,
recall_memory,
]
}
})
+72 -10
View File
@@ -6,8 +6,8 @@
use std::sync::Arc;
use tinyhumansai::{
DeleteMemoryParams, InsertMemoryParams, QueryMemoryParams, TinyHumanConfig,
TinyHumanMemoryClient,
DeleteMemoryParams, InsertMemoryParams, QueryMemoryParams, RecallMemoryParams,
TinyHumanConfig, TinyHumanMemoryClient,
};
/// Shared, cloneable handle to the memory client.
@@ -21,15 +21,23 @@ impl MemoryClient {
/// Construct from a JWT token (sourced from `authSlice.token` in the Redux store).
/// Returns `None` if the token is empty or client construction fails.
pub fn from_token(jwt_token: String) -> Option<Self> {
log::debug!("[memory] from_token: entry (token_len={})", jwt_token.trim().len());
log::info!("[memory] from_token: entry (token_len={})", jwt_token.trim().len());
if jwt_token.trim().is_empty() {
log::warn!("[memory] from_token: exit — token is empty, returning None");
return None;
}
let base_url = std::env::var("TINYHUMANS_BASE_URL")
.unwrap_or_else(|_| "https://api.tinyhumans.ai".to_string());
log::debug!("[memory] from_token: constructing client (base_url={base_url})");
let config = TinyHumanConfig::new(jwt_token).with_base_url(base_url);
let config = match std::env::var("ALPHAHUMAN_BASE_URL")
.or_else(|_| std::env::var("TINYHUMANS_BASE_URL"))
{
Ok(base_url) => {
log::info!("[memory] from_token: constructing client (base_url={base_url})");
TinyHumanConfig::new(jwt_token).with_base_url(base_url)
}
Err(_) => {
log::warn!("[memory] from_token: constructing client (base_url=<sdk default>)");
TinyHumanConfig::new(jwt_token)
}
};
match TinyHumanMemoryClient::new(config) {
Ok(inner) => {
log::info!("[memory] from_token: exit — client created successfully");
@@ -58,6 +66,7 @@ impl MemoryClient {
"[memory] store_skill_sync: payload → namespace={namespace} | title={title} | content={}",
content
);
log::info!("[memory] insert_memory: calling SDK (namespace={namespace}, title={title:?})");
let result = self.inner
.insert_memory(InsertMemoryParams {
title: title.to_string(),
@@ -66,8 +75,13 @@ impl MemoryClient {
..Default::default()
})
.await
.map(|_| ())
.map_err(|e| format!("Memory insert failed: {e}"));
.map(|_| {
log::info!("[memory] insert_memory: success (namespace={namespace}, title={title:?})");
})
.map_err(|e| {
log::warn!("[memory] insert_memory: SDK error — kind={:?} msg={e}", classify_insert_error(&e));
format!("Memory insert failed: {e}")
});
match &result {
Ok(()) => log::info!("[memory] store_skill_sync: exit — ok (namespace={namespace})"),
Err(e) => log::warn!("[memory] store_skill_sync: exit — error (namespace={namespace}): {e}"),
@@ -93,7 +107,7 @@ impl MemoryClient {
.query_memory(QueryMemoryParams {
query: query.to_string(),
namespace: Some(namespace.clone()),
max_chunks: Some(max_chunks),
max_chunks: Some(f64::from(max_chunks)),
..Default::default()
})
.await
@@ -106,6 +120,37 @@ impl MemoryClient {
Ok(response)
}
/// Recall context from the Master memory node for a given namespace.
/// Returns the synthesised `response` string, or `None` if the server returned nothing.
pub async fn recall_skill_context(
&self,
skill_id: &str,
integration_id: &str,
max_chunks: u32,
) -> Result<Option<String>, String> {
let namespace = format!("skill:{skill_id}:{integration_id}");
log::info!(
"[memory] recall_skill_context: entry (namespace={namespace}, max_chunks={max_chunks})"
);
let res = self
.inner
.recall_memory(RecallMemoryParams {
namespace: Some(namespace.clone()),
max_chunks: Some(f64::from(max_chunks)),
})
.await
.map_err(|e| {
log::warn!("[memory] recall_skill_context: exit — error (namespace={namespace}): {e}");
format!("Memory recall failed: {e}")
})?;
let response = res.data.response;
log::info!(
"[memory] recall_skill_context: exit — ok (namespace={namespace}, has_response={})",
response.is_some()
);
Ok(response)
}
/// Delete all memories for a skill integration (e.g. on OAuth revoke).
pub async fn clear_skill_memory(
&self,
@@ -130,6 +175,23 @@ impl MemoryClient {
}
}
fn classify_insert_error(e: &tinyhumansai::TinyHumanError) -> &'static str {
let msg = e.to_string();
if msg.contains("dns") || msg.contains("resolve") || msg.contains("lookup") {
"dns_failure"
} else if msg.contains("tls") || msg.contains("certificate") || msg.contains("ssl") {
"tls_failure"
} else if msg.contains("Connection refused") || msg.contains("connection refused") {
"connection_refused"
} else if msg.contains("timed out") || msg.contains("deadline") {
"timeout"
} else if msg.contains("error sending request") {
"transport_error"
} else {
"other"
}
}
#[cfg(test)]
mod tests {
use super::*;
+31 -16
View File
@@ -330,7 +330,7 @@ async fn run_event_loop(
// messages (events, pings, etc.) but queue any new CallTool.
match rx.try_recv() {
Ok(msg) => {
let should_stop = handle_message(rt, ctx, msg, state, skill_id, &mut pending_tool, app_handle).await;
let should_stop = handle_message(rt, ctx, msg, state, skill_id, &mut pending_tool, app_handle, ops_state).await;
if should_stop {
break;
}
@@ -447,6 +447,7 @@ async fn handle_message(
skill_id: &str,
pending_tool: &mut Option<PendingToolCall>,
app_handle: Option<&tauri::AppHandle>,
ops_state: &Arc<RwLock<qjs_ops::SkillState>>,
) -> bool {
match msg {
SkillMessage::CallTool { tool_name, arguments, reply } => {
@@ -553,12 +554,13 @@ async fn handle_message(
}
}
SkillMessage::Rpc { method, params, reply } => {
// Resolve the optional memory client once for this RPC call
let memory_client_opt: Option<crate::memory::MemoryClientRef> =
app_handle.and_then(|ah| {
ah.try_state::<Option<crate::memory::MemoryClientRef>>()
.and_then(|s: tauri::State<'_, Option<crate::memory::MemoryClientRef>>| s.inner().clone())
});
// Resolve the optional memory client once for this RPC call.
// State is registered as MemoryState(Mutex<Option<MemoryClientRef>>), not
// Option<MemoryClientRef> directly, so we must use the newtype wrapper.
let memory_client_opt = app_handle.and_then(|ah| {
ah.try_state::<crate::commands::memory::MemoryState>()
.and_then(|s| s.0.lock().ok().and_then(|g| g.clone()))
});
let result = match method.as_str() {
"oauth/complete" => {
@@ -582,8 +584,11 @@ async fn handle_message(
let params_str = serde_json::to_string(&params).unwrap_or_else(|_| "{}".to_string());
let result = handle_js_call(rt, ctx, "onOAuthComplete", &params_str).await;
// Fire-and-forget: persist returned payload to TinyHumans memory
if let Ok(ref payload) = result {
// Fire-and-forget: persist published ops state to TinyHumans memory.
// Skills publish data via state.set()/setPartial() into ops_state.data,
// not as the return value of onOAuthComplete() (which is typically undefined).
let state_snapshot = ops_state.read().data.clone();
if !state_snapshot.is_empty() {
if let Some(client) = memory_client_opt.clone() {
let skill = skill_id.to_string();
let integration_id = params
@@ -591,8 +596,10 @@ async fn handle_message(
.and_then(|v| v.as_str())
.unwrap_or("unknown")
.to_string();
let content = serde_json::to_string_pretty(payload)
.unwrap_or_else(|_| payload.to_string());
let content = serde_json::to_string_pretty(
&serde_json::Value::Object(state_snapshot),
)
.unwrap_or_else(|_| "{}".to_string());
let title = format!("{} OAuth sync — {}", skill, integration_id);
tokio::spawn(async move {
if let Err(e) = client
@@ -614,13 +621,21 @@ async fn handle_message(
}
"skill/sync" => {
let result = handle_js_call(rt, ctx, "onSync", "{}").await;
// Fire-and-forget: persist sync payload to TinyHumans memory
if let Ok(ref payload) = result {
// Fire-and-forget: persist published ops state to TinyHumans memory.
// Skills publish data via state.set()/setPartial() into ops_state.data,
// not as the return value of onSync() (which is typically undefined).
let state_snapshot = ops_state.read().data.clone();
log::info!(
"[memory] store_skill_sync: payload → state_snapshot={:?}",
state_snapshot
);
if !state_snapshot.is_empty() {
if let Some(client) = memory_client_opt.clone() {
let skill = skill_id.to_string();
let content = serde_json::to_string_pretty(payload)
.unwrap_or_else(|_| payload.to_string());
let content = serde_json::to_string_pretty(
&serde_json::Value::Object(state_snapshot),
)
.unwrap_or_else(|_| "{}".to_string());
let title = format!("{} periodic sync", skill);
tokio::spawn(async move {
if let Err(e) = client
+2 -2
View File
@@ -27,10 +27,10 @@ function App() {
<PersistGate
loading={null}
persistor={persistor}
onBeforeLift={() => {
onBeforeLift={async () => {
const token = store.getState().auth.token;
console.info('[memory] PersistGate onBeforeLift: token_present=%s', !!token);
if (token) void syncMemoryClientToken(token);
if (token) await syncMemoryClientToken(token);
}}>
<UserProvider>
<SocketProvider>
+82 -38
View File
@@ -12,13 +12,13 @@ import { useNavigate, useParams } from 'react-router-dom';
import { injectAll } from '../lib/ai/injector';
import type { Message } from '../lib/ai/providers/interface';
import { skillManager } from '../lib/skills/manager';
import { creditsApi, type TeamUsage } from '../services/api/creditsApi';
import {
type ChatMessage,
inferenceApi,
type ModelInfo,
type Tool,
} from '../services/api/inferenceApi';
import { type TeamUsage, creditsApi } from '../services/api/creditsApi';
import { useAppDispatch, useAppSelector } from '../store/hooks';
import type { NotionPageSummary, NotionSummary, NotionUserProfile } from '../store/notionSlice';
import {
@@ -388,6 +388,23 @@ const Conversations = () => {
// Continue with original message
}
// Prepend recalled memory context from TinyHumans Master node
try {
const { invoke } = await import('@tauri-apps/api/core');
const recalledContext = await invoke<string | null>('recall_memory', {
skillId: 'conversations',
integrationId: selectedThreadId,
maxChunks: 10,
});
if (recalledContext) {
processedUserContent = `[MEMORY_CONTEXT]\n${recalledContext}\n[/MEMORY_CONTEXT]\n\n${processedUserContent}`;
console.log('✅ Memory recall injected into prompt');
}
} catch (recallError) {
console.warn('⚠️ Memory recall skipped:', recallError);
// Non-fatal — continue without recalled context
}
// Prepend Notion workspace context if connected
const notionContext = buildNotionContext(
notionProfile,
@@ -1077,46 +1094,73 @@ const Conversations = () => {
)}
<div className="flex-1" />
{/* Budget indicator — circular */}
{(isLoadingBudget || teamUsage) && (() => {
const size = 22;
const r = 9;
const circ = 2 * Math.PI * r;
const pct = teamUsage
? Math.min(1, teamUsage.remainingUsd / teamUsage.cycleBudgetUsd)
: 0;
const dash = pct * circ;
return (
<div className="flex items-center gap-1.5" title={teamUsage ? `$${teamUsage.remainingUsd.toFixed(2)} of $${teamUsage.cycleBudgetUsd.toFixed(2)} remaining` : 'Loading budget…'}>
<svg width={size} height={size} viewBox={`0 0 ${size} ${size}`} className="-rotate-90">
<circle cx={size / 2} cy={size / 2} r={r} fill="none" stroke="currentColor" strokeWidth="2.5" className="text-white/10" />
{teamUsage ? (
{(isLoadingBudget || teamUsage) &&
(() => {
const size = 22;
const r = 9;
const circ = 2 * Math.PI * r;
const pct = teamUsage
? Math.min(1, teamUsage.remainingUsd / teamUsage.cycleBudgetUsd)
: 0;
const dash = pct * circ;
return (
<div
className="flex items-center gap-1.5"
title={
teamUsage
? `$${teamUsage.remainingUsd.toFixed(2)} of $${teamUsage.cycleBudgetUsd.toFixed(2)} remaining`
: 'Loading budget…'
}>
<svg
width={size}
height={size}
viewBox={`0 0 ${size} ${size}`}
className="-rotate-90">
<circle
cx={size / 2} cy={size / 2} r={r}
fill="none" stroke="currentColor" strokeWidth="2.5"
strokeDasharray={`${dash} ${circ}`}
strokeLinecap="round"
className={pct < 0.2 ? 'text-amber-500' : 'text-primary-500'}
style={{ transition: 'stroke-dasharray 0.3s ease' }}
/>
) : (
<circle
cx={size / 2} cy={size / 2} r={r}
fill="none" stroke="currentColor" strokeWidth="2.5"
strokeDasharray={`${circ * 0.25} ${circ}`}
strokeLinecap="round"
className="text-stone-600 animate-spin origin-center"
style={{ transformOrigin: `${size / 2}px ${size / 2}px` }}
cx={size / 2}
cy={size / 2}
r={r}
fill="none"
stroke="currentColor"
strokeWidth="2.5"
className="text-white/10"
/>
{teamUsage ? (
<circle
cx={size / 2}
cy={size / 2}
r={r}
fill="none"
stroke="currentColor"
strokeWidth="2.5"
strokeDasharray={`${dash} ${circ}`}
strokeLinecap="round"
className={pct < 0.2 ? 'text-amber-500' : 'text-primary-500'}
style={{ transition: 'stroke-dasharray 0.3s ease' }}
/>
) : (
<circle
cx={size / 2}
cy={size / 2}
r={r}
fill="none"
stroke="currentColor"
strokeWidth="2.5"
strokeDasharray={`${circ * 0.25} ${circ}`}
strokeLinecap="round"
className="text-stone-600 animate-spin origin-center"
style={{ transformOrigin: `${size / 2}px ${size / 2}px` }}
/>
)}
</svg>
{teamUsage && (
<span className="text-[10px] text-stone-500">
${teamUsage.remainingUsd.toFixed(2)}
</span>
)}
</svg>
{teamUsage && (
<span className="text-[10px] text-stone-500">
${teamUsage.remainingUsd.toFixed(2)}
</span>
)}
</div>
);
})()}
</div>
);
})()}
</div>
{sendError && (
<div className="flex items-center justify-between mb-2">
+1 -1
View File
@@ -28,7 +28,7 @@ const Login = () => {
dispatch(setToken(jwtToken));
console.info('[memory] Login: dispatching syncMemoryClientToken after setToken');
void syncMemoryClientToken(jwtToken);
await syncMemoryClientToken(jwtToken);
navigate('/onboarding/', { replace: true });
} catch (err) {
if (!cancelled) {
+9 -2
View File
@@ -169,13 +169,20 @@ export async function setWindowTitle(title: string): Promise<void> {
* Redux Persist rehydration.
*/
export async function syncMemoryClientToken(token: string): Promise<void> {
console.debug('[memory] syncMemoryClientToken: entry (token_present=%s, is_tauri=%s)', !!token, isTauri());
console.debug(
'[memory] syncMemoryClientToken: entry (token_present=%s, is_tauri=%s)',
!!token,
isTauri()
);
if (!isTauri() || !token) {
console.debug('[memory] syncMemoryClientToken: exit — skipped (not Tauri or empty token)');
return;
}
try {
console.debug('[memory] syncMemoryClientToken: payload → init_memory_client { jwtToken: <redacted, len=%d> }', token.length);
console.debug(
'[memory] syncMemoryClientToken: payload → init_memory_client { jwtToken: <redacted, len=%d> }',
token.length
);
await invoke('init_memory_client', { jwtToken: token });
console.info('[memory] syncMemoryClientToken: exit — ok');
} catch (err) {
+6 -54
View File
@@ -319,11 +319,6 @@
resolved "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-4.0.0.tgz"
integrity sha512-QxULHAm7cNu72w97JUNCBFODFaXpbDg+dP8b/oWFAZ2MTRppA3U00Y2L1HqaS4J6yBqxwa/Y3nMBaxVKbB/NsA==
"@dimforge/rapier3d-compat@~0.12.0":
version "0.12.0"
resolved "https://registry.yarnpkg.com/@dimforge/rapier3d-compat/-/rapier3d-compat-0.12.0.tgz#7b3365e1dfdc5cd957b45afe920b4ac06c7cd389"
integrity sha512-uekIGetywIgopfD97oDL5PfeezkFpNhwlzlaEYNOA0N6ghdsOvh/HYjSMek5Q2O1PYvRSDFcqFVJl4r4ZBwOow==
"@esbuild/aix-ppc64@0.27.2":
version "0.27.2"
resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.27.2.tgz#521cbd968dcf362094034947f76fa1b18d2d403c"
@@ -1299,7 +1294,12 @@
dependencies:
postcss-selector-parser "6.0.10"
"@tauri-apps/api@^2", "@tauri-apps/api@^2.8.0":
"@tauri-apps/api@2.10.1":
version "2.10.1"
resolved "https://registry.yarnpkg.com/@tauri-apps/api/-/api-2.10.1.tgz#57c1bae6114ec33d977eb2b50dfefc25fa84fc93"
integrity sha512-hKL/jWf293UDSUN09rR69hrToyIXBb8CjGaWC7gfinvnQrBVvnLr08FeFi38gxtugAVyVcTa5/FD/Xnkb1siBw==
"@tauri-apps/api@^2.8.0":
version "2.9.1"
resolved "https://registry.npmjs.org/@tauri-apps/api/-/api-2.9.1.tgz"
integrity sha512-IGlhP6EivjXHepbBic618GOmiWe4URJiIeZFlB7x3czM0yDHHYviH1Xvoiv4FefdkQtn6v7TuwWCRfOGdnVUGw==
@@ -1461,11 +1461,6 @@
minimatch "^9.0.0"
parse-imports-exports "^0.2.4"
"@tweenjs/tween.js@~23.1.3":
version "23.1.3"
resolved "https://registry.yarnpkg.com/@tweenjs/tween.js/-/tween.js-23.1.3.tgz#eff0245735c04a928bb19c026b58c2a56460539d"
integrity sha512-vJmvvwFxYuGnF2axRtPYocag6Clbb5YS7kLL+SO/TeVFzHqDIWrNKYtcsPMibjDx9O+bu+psAy9NKfWklassUA==
"@types/aria-query@^5.0.1":
version "5.0.4"
resolved "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz"
@@ -1666,29 +1661,11 @@
resolved "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz"
integrity sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==
"@types/stats.js@*":
version "0.17.4"
resolved "https://registry.yarnpkg.com/@types/stats.js/-/stats.js-0.17.4.tgz#1933e5ff153a23c7664487833198d685c22e791e"
integrity sha512-jIBvWWShCvlBqBNIZt0KAshWpvSjhkwkEu4ZUcASoAvhmrgAUI2t1dXrjSL4xXVLB4FznPrIsX3nKXFl/Dt4vA==
"@types/statuses@^2.0.6":
version "2.0.6"
resolved "https://registry.npmjs.org/@types/statuses/-/statuses-2.0.6.tgz"
integrity sha512-xMAgYwceFhRA2zY+XbEA7mxYbA093wdiW8Vu6gZPGWy9cmOyU9XesH1tNcEWsKFd5Vzrqx5T3D38PWx1FIIXkA==
"@types/three@^0.183.1":
version "0.183.1"
resolved "https://registry.yarnpkg.com/@types/three/-/three-0.183.1.tgz#d812d028b38ad68843725e3e7bd3268607cef150"
integrity sha512-f2Pu5Hrepfgavttdye3PsH5RWyY/AvdZQwIVhrc4uNtvF7nOWJacQKcoVJn0S4f0yYbmAE6AR+ve7xDcuYtMGw==
dependencies:
"@dimforge/rapier3d-compat" "~0.12.0"
"@tweenjs/tween.js" "~23.1.3"
"@types/stats.js" "*"
"@types/webxr" ">=0.5.17"
"@webgpu/types" "*"
fflate "~0.8.2"
meshoptimizer "~1.0.1"
"@types/unist@*", "@types/unist@^3.0.0":
version "3.0.3"
resolved "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz"
@@ -1704,11 +1681,6 @@
resolved "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.6.tgz"
integrity sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg==
"@types/webxr@>=0.5.17":
version "0.5.24"
resolved "https://registry.yarnpkg.com/@types/webxr/-/webxr-0.5.24.tgz#734d5d90dadc5809a53e422726c60337fa2f4a44"
integrity sha512-h8fgEd/DpoS9CBrjEQXR+dIDraopAEfu4wYVNY2tEPwk60stPWhvZMf4Foo5FakuQ7HFZoa8WceaWFervK2Ovg==
"@types/which@^2.0.1":
version "2.0.2"
resolved "https://registry.npmjs.org/@types/which/-/which-2.0.2.tgz"
@@ -2137,11 +2109,6 @@
dependencies:
"@wdio/logger" "9.18.0"
"@webgpu/types@*":
version "0.1.69"
resolved "https://registry.yarnpkg.com/@webgpu/types/-/types-0.1.69.tgz#6b849bf370a1f29c78bd3aeba8e84c1150b237f2"
integrity sha512-RPmm6kgRbI8e98zSD3RVACvnuktIja5+yLgDAkTmxLr90BEwdTXRQWNLF3ETTTyH/8mKhznZuN5AveXYFEsMGQ==
"@xmldom/xmldom@^0.9.5":
version "0.9.8"
resolved "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.9.8.tgz"
@@ -4160,11 +4127,6 @@ fdir@^6.5.0:
resolved "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz"
integrity sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==
fflate@~0.8.2:
version "0.8.2"
resolved "https://registry.yarnpkg.com/fflate/-/fflate-0.8.2.tgz#fc8631f5347812ad6028bbe4a2308b2792aa1dea"
integrity sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==
figures@^6.1.0:
version "6.1.0"
resolved "https://registry.npmjs.org/figures/-/figures-6.1.0.tgz"
@@ -5632,11 +5594,6 @@ merge2@^1.3.0:
resolved "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz"
integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==
meshoptimizer@~1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/meshoptimizer/-/meshoptimizer-1.0.1.tgz#c3ef0d509a8b84ac562493dba5a108fd67fa76dc"
integrity sha512-Vix+QlA1YYT3FwmBBZ+49cE5y/b+pRrcXKqGpS5ouh33d3lSp2PoTpCw19E0cKDFWalembrHnIaZetf27a+W2g==
micromark-core-commonmark@^2.0.0:
version "2.0.3"
resolved "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.3.tgz"
@@ -7732,11 +7689,6 @@ thenify-all@^1.0.0:
dependencies:
any-promise "^1.0.0"
three@^0.183.2:
version "0.183.2"
resolved "https://registry.yarnpkg.com/three/-/three-0.183.2.tgz#606e3195bf210ef8d1eaaca2ab8c59d92d2bbc18"
integrity sha512-di3BsL2FEQ1PA7Hcvn4fyJOlxRRgFYBpMTcyOgkwJIaDOdJMebEFPA+t98EvjuljDx4hNulAGwF6KIjtwI5jgQ==
timers-browserify@^2.0.4:
version "2.0.12"
resolved "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.12.tgz"