refactor(rust): remove domain shim and enforce direct tt-domain imports

This commit is contained in:
Darkatse 2026-07-02 13:39:47 -04:00
parent 15b1aaf741
commit db52d807ae
47 changed files with 95 additions and 96 deletions

View file

@ -91,7 +91,7 @@ AgentTaskRecord {
Invocation 与 task 文件由 `AgentInvocationRepository` 管理,当前文件实现位于:
```text
src-tauri/src/domain/repositories/agent_invocation_repository.rs
src-tauri/crates/tt-ports/src/repositories/agent_invocation_repository.rs
src-tauri/src/infrastructure/repositories/file_agent_repository/invocation_store.rs
```
@ -277,7 +277,7 @@ src-tauri/src/infrastructure/repositories/file_agent_profile_repository/mod.rs
Persistence:
```text
src-tauri/src/domain/repositories/agent_invocation_repository.rs
src-tauri/crates/tt-ports/src/repositories/agent_invocation_repository.rs
src-tauri/src/infrastructure/repositories/file_agent_repository/invocation_store.rs
```

View file

@ -49,7 +49,7 @@ MCP / Tool Direct Call
- 应用服务由 `AppState` 管理并在 `composition::build_services()` 装配。见 `src-tauri/src/app.rs`、`src-tauri/src/app/composition.rs`。
- 当前 LLM 请求经过 `ChatCompletionService`,该服务负责 provider 解析、iOS policy、endpoint override policy、payload build、prompt caching 和取消注册。见 `src-tauri/src/application/services/chat_completion_service/mod.rs:32`、`src-tauri/src/application/services/chat_completion_service/mod.rs:302`、`src-tauri/src/application/services/chat_completion_service/mod.rs:358`。
- 当前 LLM API 日志依赖 composition root 中装配的 `LoggingChatCompletionRepository` wrapper;Agent 不得直接调用 `HttpChatCompletionRepository` 绕过日志、secret 或 policy。Responses WebSocket 建连已复用 `HttpClientPool` 的 ChatCompletion WebSocket profile,不应扩散成第二套 LLM 调用链。见 `src-tauri/src/app/composition/repositories.rs`。
- 当前 chat payload 分片读写由 `ChatService` 和 `ChatRepository` 承担,windowed save/patch 是正式契约。见 `src-tauri/src/application/services/chat_service.rs:495`、`src-tauri/src/application/services/chat_service.rs:563`、`src-tauri/src/domain/repositories/chat_repository.rs:145`、`src-tauri/src/domain/repositories/chat_repository.rs:162`。
- 当前 chat payload 分片读写由 `ChatService` 和 `ChatRepository` 承担,windowed save/patch 是正式契约。见 `src-tauri/crates/tt-application/src/services/chat_service.rs`、`src-tauri/crates/tt-ports/src/repositories/chat_repository.rs`。
- 前端 Public ABI 的统一入口是 `window.__TAURITAVERN__`,应保持小而稳定。见 `docs/FrontendHostContract.md` 第 3.6 节、`src/tauri/main/bootstrap.js:139`。
- 当前 `Generate()` 支持 dryRun,并在 `GENERATE_AFTER_DATA` 提供生成请求数据。见 `src/script.js:4660`、`src/script.js:5743`。
- 当前 SillyTavern 工具调用会递归回 `Generate()`,并把工具调用结果保存成 `is_system` chat message。这是 Agent 必须摆脱的旧结构。见 `src/script.js:5826`、`src/script.js:5847`、`src/script.js:5959`、`src/scripts/tool-calling.js:868`、`src/scripts/tool-calling.js:887`。

View file

@ -57,10 +57,11 @@ src-tauri/
│ │ ├── composition/ # 仓库/服务/适配器装配子模块
│ │ ├── host/ # Tauri host shell(插件、setup、窗口、资源、shutdown)
│ │ ├── startup_profile.rs # 启动期 settings / iOS policy 快照
│ ├── domain/ # 领域层
│ │ ├── models/ # 领域模型
│ │ ├── repositories/ # 仓库接口
│ │ └── errors.rs # 领域错误
│ ├── crates/
│ │ ├── tt-domain/ # 领域模型、领域错误与纯逻辑
│ │ ├── tt-ports/ # 仓库接口与出站端口
│ │ ├── tt-contracts/ # 跨 crate DTO / 事件契约
│ │ └── tt-application/ # 应用服务与用例编排
│ ├── application/ # 应用层
│ │ ├── services/ # 业务服务
│ │ └── dto/ # 数据传输对象
@ -438,7 +439,7 @@ tauri::Builder::default()
#### 3.5.2 分层职责
- `domain/repositories/chat_repository.rs`
- `crates/tt-ports/src/repositories/chat_repository.rs`
- 保留 typed API(`get_chat` / `save` / `search_chats` 等)用于领域操作。
- payload API:path/from-file(大文件,data plane)+ windowed(tail/before/windowed-save,小窗口,control plane)。
- windowed 数据结构:`ChatPayloadCursor` / `ChatPayloadTail` / `ChatPayloadChunk`。
@ -803,8 +804,8 @@ service
添加新模型时,应遵循以下步骤:
1. 在`domain/models`中定义模型结构
2. 在`domain/repositories`中定义仓库接口
1. 在`crates/tt-domain/src/models`中定义模型结构
2. 在`crates/tt-ports/src/repositories`中定义仓库接口
3. 在`infrastructure/repositories`中实现仓库接口
4. 在`application/services`中创建服务
5. 在`application/dto`中定义数据传输对象

View file

@ -37,7 +37,7 @@ windowed payload 的底层存储是 JSONL 文件:
Rust 侧定义:`ChatPayloadCursor { offset, size, modified_millis }`(序列化为 camelCase)。见:
- `src-tauri/src/domain/repositories/chat_repository.rs`
- `src-tauri/crates/tt-ports/src/repositories/chat_repository.rs`
含义:

View file

@ -355,6 +355,10 @@ const CRATES = [
];
const MAIN_CRATE_SOURCE_RULES = [
sourceRule('main crate domain shim', path.join(REPO_ROOT, 'src-tauri', 'src'), [
['domain module declaration', /^\s*(pub\s+)?mod\s+domain\s*;/],
['domain shim path', /\bcrate::domain::/],
]),
sourceRule('infrastructure', path.join(REPO_ROOT, 'src-tauri', 'src', 'infrastructure'), [
['application facade', /\bcrate::application::/],
['tt-application crate', /\btt_application::/],

View file

@ -6,8 +6,8 @@ use std::path::Path;
use tauri::AppHandle;
use crate::domain::errors::DomainError;
use tt_adapter_storage_core::file_system::DataDirectory;
use tt_domain::errors::DomainError;
use super::{AppServices, StartupProfile};

View file

@ -7,7 +7,7 @@ use crate::application::services::chat_service::ChatService;
use crate::application::services::group_chat_service::GroupChatService;
use crate::application::services::group_service::GroupService;
use crate::application::services::secret_service::SecretService;
use crate::domain::errors::DomainError;
use tt_domain::errors::DomainError;
use tt_ports::sync::DataChangeReconciler;
pub(in crate::app::composition) fn data_change_reconciler(

View file

@ -9,12 +9,12 @@ use ttsync_contract::sync::SyncMode;
use crate::application::services::lan_sync_service::LanSyncService;
use crate::application::services::tt_sync_service::TtSyncService;
use crate::domain::errors::DomainError;
use crate::domain::models::lan_sync::LanSyncPairRequestEvent;
use tt_contracts::sync::SyncJobEvent;
use tt_contracts::sync_automation::{
SyncAutomationStatus, SyncAutomationTarget, SyncAutomationToastEvent,
};
use tt_domain::errors::DomainError;
use tt_domain::models::lan_sync::LanSyncPairRequestEvent;
use tt_ports::lan_sync::{LanPairingApprovalRequest, LanServerErrorReporter, PairingApproval};
use tt_ports::sync::SyncJobEventPublisher;
use tt_ports::sync_automation::{

View file

@ -37,10 +37,10 @@ use crate::application::services::update_service::UpdateService;
use crate::application::services::user_directory_service::UserDirectoryService;
use crate::application::services::user_service::UserService;
use crate::application::services::world_info_service::WorldInfoService;
use crate::domain::errors::DomainError;
use crate::infrastructure::apis::http_external_import_downloader::HttpExternalImportDownloader;
use tt_adapter_http::HttpClientPool;
use tt_adapter_storage_core::file_system::DataDirectory;
use tt_domain::errors::DomainError;
use super::{adapters, repositories};

View file

@ -8,12 +8,12 @@ use crate::application::services::lan_sync_service::{
use crate::application::services::sync_automation_service::SyncAutomationService;
use crate::application::services::sync_job_coordinator::SyncJobCoordinator;
use crate::application::services::tt_sync_service::TtSyncService;
use crate::domain::ios_policy::IosPolicyActivationReport;
use tt_adapter_storage_core::file_system::DataDirectory;
use tt_adapter_sync::{
AxumLanServerControl, HttpLanPairingClient, HttpTtPairingClient, InfrastructureSyncJobExecutor,
LanPeerStore, LanSyncStore, LocalLanAddressDiscovery, SyncAutomationStore, TtSyncRuntime,
};
use tt_domain::ios_policy::IosPolicyActivationReport;
use tt_ports::lan_sync::{LanPeerRepository, LanServerControl, LanSyncSettingsRepository};
use tt_ports::sync::DataChangeReconciler;

View file

@ -38,13 +38,6 @@ use crate::application::services::agent_workspace_lifecycle_service::{
use crate::application::services::character_service::CharacterService;
use crate::application::services::llm_connection_service::LlmConnectionService;
use crate::application::services::skill_service::SkillService;
use crate::domain::errors::DomainError;
use crate::domain::models::agent::profile::{AgentDelegationPolicy, AgentProfileId};
use crate::domain::models::agent::{
AgentChatRef, AgentModelContentPart, AgentModelRequest, AgentRun, AgentRunEventLevel,
AgentRunPresentation, AgentRunStatus, WorkspacePath,
};
use crate::domain::models::preset::{DefaultPreset, Preset, PresetType};
use crate::infrastructure::persistence::png_utils::{
read_character_data_from_png, write_character_data_to_png,
};
@ -56,6 +49,13 @@ use crate::infrastructure::repositories::file_world_info_repository::FileWorldIn
use tt_adapter_storage_core::FileChatRepository;
use tt_adapter_storage_core::FileLlmConnectionRepository;
use tt_adapter_storage_core::chat_directory_identity::new_shared_chat_alias_store_for_user_dir;
use tt_domain::errors::DomainError;
use tt_domain::models::agent::profile::{AgentDelegationPolicy, AgentProfileId};
use tt_domain::models::agent::{
AgentChatRef, AgentModelContentPart, AgentModelRequest, AgentRun, AgentRunEventLevel,
AgentRunPresentation, AgentRunStatus, WorkspacePath,
};
use tt_domain::models::preset::{DefaultPreset, Preset, PresetType};
use tt_ports::repositories::agent_invocation_repository::AgentInvocationRepository;
use tt_ports::repositories::agent_profile_repository::AgentProfileRepository;
use tt_ports::repositories::agent_profile_storage_health_repository::AgentProfileStorageHealthRepository;
@ -250,7 +250,7 @@ fn default_agent_responses() -> Vec<Value> {
async fn resolve_contract_profile(
fixture: &AgentRuntimeFixture,
) -> crate::domain::models::agent::profile::ResolvedAgentProfile {
) -> tt_domain::models::agent::profile::ResolvedAgentProfile {
let registry = BuiltinAgentToolRegistry::phase2c();
fixture
.profile_service
@ -265,7 +265,7 @@ async fn resolve_contract_profile(
fn contract_run(
id: &str,
presentation: AgentRunPresentation,
profile: &crate::domain::models::agent::profile::ResolvedAgentProfile,
profile: &tt_domain::models::agent::profile::ResolvedAgentProfile,
) -> AgentRun {
AgentRun {
id: id.to_string(),
@ -417,7 +417,7 @@ async fn execute_agent_loop_with_host_resolver<R>(
run_id: String,
prompt_snapshot: Value,
request: ChatCompletionGenerateRequestDto,
profile: crate::domain::models::agent::profile::ResolvedAgentProfile,
profile: tt_domain::models::agent::profile::ResolvedAgentProfile,
cancel_receiver: &mut watch::Receiver<bool>,
resolver: R,
) -> Result<(), ApplicationError>
@ -502,7 +502,7 @@ async fn wait_for_event_field(
async fn read_agent_events(
repository: &FileAgentRepository,
run_id: &str,
) -> Vec<crate::domain::models::agent::AgentRunEvent> {
) -> Vec<tt_domain::models::agent::AgentRunEvent> {
repository
.read_events(
run_id,

View file

@ -9,13 +9,13 @@ use crate::application::dto::dev_observability_dto::{
BackendLogEntryDto, DevBundleVersionDto, FrontendLogEntrySnapshotDto, LlmApiLogIndexEntryDto,
LlmApiLogPreviewDto, LlmApiLogRawDto, LlmApiRawKindDto,
};
use crate::domain::errors::DomainError;
use crate::infrastructure::logging::dev_bundle::{DevLogBundleInput, export_dev_log_bundle};
use crate::infrastructure::logging::devtools::{BackendLogEntry, BackendLogStore};
use crate::infrastructure::logging::llm_api_logs::{
LlmApiLogEntryPreview, LlmApiLogEntryRaw, LlmApiLogIndexEntry, LlmApiLogStore, LlmApiRawKind,
};
use crate::infrastructure::paths::RuntimePaths;
use tt_domain::errors::DomainError;
pub struct DevObservabilityHub {
app_handle: AppHandle,

View file

@ -7,11 +7,11 @@
use std::sync::Arc;
use crate::app::{BackendReadiness, StartupProfile, spawn_initialization};
use crate::domain::errors::DomainError;
use crate::domain::ios_policy::IosPolicyScope;
use crate::infrastructure::logging::llm_api_logs::LlmApiLogStore;
use tauri::Manager;
use tt_adapter_http::HttpClientPool;
use tt_domain::errors::DomainError;
use tt_domain::ios_policy::IosPolicyScope;
pub(super) fn setup(app: &mut tauri::App) -> Result<(), Box<dyn std::error::Error>> {
let app_handle = app.handle().clone();

View file

@ -1,12 +1,12 @@
use std::path::Path;
use crate::domain::errors::DomainError;
use crate::domain::ios_policy::{
IosPolicyActivationReport, IosPolicyScope, resolve_ios_policy_activation_report,
};
use crate::domain::models::settings::TauriTavernSettings;
use crate::infrastructure::ios_policy_cache::resolve_effective_raw_policy_sync;
use tt_adapter_storage_core::FileSettingsRepository;
use tt_domain::errors::DomainError;
use tt_domain::ios_policy::{
IosPolicyActivationReport, IosPolicyScope, resolve_ios_policy_activation_report,
};
use tt_domain::models::settings::TauriTavernSettings;
#[derive(Debug, Clone)]
pub(crate) struct StartupProfile {

View file

@ -42,9 +42,9 @@ use crate::application::services::update_service::UpdateService;
use crate::application::services::user_directory_service::UserDirectoryService;
use crate::application::services::user_service::UserService;
use crate::application::services::world_info_service::WorldInfoService;
use crate::domain::errors::DomainError;
use crate::domain::ios_policy::IosPolicyActivationReport;
use crate::infrastructure::paths::RuntimePaths;
use tt_domain::errors::DomainError;
use tt_domain::ios_policy::IosPolicyActivationReport;
use super::{StartupProfile, composition};

View file

@ -1,4 +0,0 @@
pub(crate) use tt_domain::json_merge;
pub use tt_domain::{errors, ios_policy, text_metrics, text_search};
pub mod models;

View file

@ -1 +0,0 @@
pub use tt_domain::models::*;

View file

@ -5,11 +5,11 @@ use serde_json::Value;
use tokio::fs;
use tokio::io::{AsyncBufReadExt, BufReader};
use crate::domain::json_merge::merge_json_value;
use crate::infrastructure::persistence::png_utils::{
process_avatar_image, read_character_data_from_png, write_character_data_to_png,
};
use tt_domain::errors::DomainError;
use tt_domain::json_merge::merge_json_value;
use tt_domain::models::character::Character;
use tt_domain::models::chat::parse_message_timestamp_value;
use tt_ports::repositories::character_repository::{

View file

@ -4,13 +4,13 @@ use std::path::PathBuf;
use super::FileSkillRepository;
use super::package::{collect_skill_files, sha256_hex};
use super::paths::{normalize_skill_path, validate_skill_name};
use crate::domain::text_metrics::TextMetrics;
use crate::domain::text_search::PreparedTextSearch;
use tt_domain::errors::DomainError;
use tt_domain::models::skill::{
DEFAULT_SKILL_READ_FALLBACK_MAX_CHARS, SkillFileKind, SkillFileRef, SkillReadRequest,
SkillReadResult, SkillScope, SkillSearchHit, SkillSearchRequest, SkillSearchResult,
};
use tt_domain::text_metrics::TextMetrics;
use tt_domain::text_search::PreparedTextSearch;
struct SkillTextFile {
scope: SkillScope,

View file

@ -1,6 +1,5 @@
mod app;
mod application;
mod domain;
mod infrastructure;
mod observability_targets;
mod platform;

View file

@ -14,8 +14,8 @@ use objc2_uniform_type_identifiers::UTType;
use tauri::WebviewWindow;
use tokio::sync::oneshot;
use crate::domain::errors::DomainError;
use crate::platform::ios_ui::resolve_presenting_view_controller;
use tt_domain::errors::DomainError;
const DATA_ARCHIVE_CONTENT_TYPES: &[&str] = &[
"public.zip-archive",

View file

@ -9,8 +9,8 @@ use objc2_ui_kit::{UIActivityType, UIActivityViewController};
use tauri::WebviewWindow;
use tokio::sync::oneshot;
use crate::domain::errors::DomainError;
use crate::platform::ios_ui::resolve_presenting_view_controller;
use tt_domain::errors::DomainError;
#[derive(Debug, Clone)]
pub struct ShareResult {

View file

@ -7,7 +7,7 @@ use objc2::rc::Retained;
use objc2::runtime::{AnyClass, AnyObject};
use objc2_foundation::NSArray;
use crate::domain::errors::DomainError;
use tt_domain::errors::DomainError;
use objc2_ui_kit::{UIViewController, UIWindow};

View file

@ -25,10 +25,10 @@ use crate::application::dto::agent_dto::{
};
use crate::application::errors::ApplicationError;
use crate::application::services::agent_workspace_lifecycle_service::AgentChatWorkspaceTarget;
use crate::domain::models::agent::AgentChatRef;
use crate::domain::models::agent::profile_diagnostic::AgentProfileHealth;
use crate::presentation::commands::helpers::{log_command, map_command_error};
use crate::presentation::errors::CommandError;
use tt_domain::models::agent::AgentChatRef;
use tt_domain::models::agent::profile_diagnostic::AgentProfileHealth;
use tt_ports::repositories::agent_workspace_lifecycle_repository::AgentPersistentStatePruneRequest;
#[tauri::command]

View file

@ -4,11 +4,11 @@ use tauri::State;
use crate::app::AppState;
use crate::application::services::asset_service::AssetDownloadResult;
use crate::domain::models::asset::AssetCatalog;
use crate::presentation::commands::helpers::{
ensure_ios_policy_allows, log_command, map_command_error,
};
use crate::presentation::errors::CommandError;
use tt_domain::models::asset::AssetCatalog;
#[tauri::command]
pub async fn get_assets_library(

View file

@ -9,11 +9,11 @@ use tauri::State;
use tokio::fs;
use crate::app::AppState;
use crate::domain::models::avatar::{AvatarUploadResult, CropInfo};
use crate::presentation::commands::helpers::{
log_command, log_user_visible_error, map_command_error,
};
use crate::presentation::errors::CommandError;
use tt_domain::models::avatar::{AvatarUploadResult, CropInfo};
const MAX_MOBILE_INLINE_AVATAR_BYTES: u64 = 8 * 1024 * 1024;

View file

@ -8,10 +8,10 @@ use tauri::State;
use crate::app::AppState;
use crate::application::dto::background_dto::{DeleteBackgroundDto, RenameBackgroundDto};
use crate::application::services::host_resource_service::HostResourceService;
use crate::domain::models::background::BackgroundListEntry;
use crate::domain::models::image_metadata::ImageMetadataIndex;
use crate::presentation::commands::helpers::{log_command, map_command_error};
use crate::presentation::errors::CommandError;
use tt_domain::models::background::BackgroundListEntry;
use tt_domain::models::image_metadata::ImageMetadataIndex;
#[derive(Debug, Clone, Serialize)]
pub struct ThumbnailAssetPayload {

View file

@ -13,9 +13,9 @@ use crate::application::dto::character_dto::{
ResolveCharacterLorebookConflictResultDto, UpdateAvatarDto, UpdateCharacterCardDataDto,
UpdateCharacterDto,
};
use crate::domain::models::skill::{SkillScope, SkillScopeRetargetRequest};
use crate::presentation::commands::helpers::{log_command, map_command_error};
use crate::presentation::errors::CommandError;
use tt_domain::models::skill::{SkillScope, SkillScopeRetargetRequest};
const SKILL_SOURCE_KIND_CHARACTER: &str = "character";

View file

@ -9,9 +9,9 @@ use crate::application::dto::chat_completion_dto::{
ChatCompletionGenerateRequestDto, ChatCompletionStatusRequestDto,
};
use crate::application::services::chat_completion_service::ChatCompletionService;
use crate::domain::models::upstream_failure::UpstreamFailure;
use crate::presentation::commands::helpers::{log_command, map_command_error};
use crate::presentation::errors::CommandError;
use tt_domain::models::upstream_failure::UpstreamFailure;
#[tauri::command]
pub async fn get_chat_completions_status(

View file

@ -3,14 +3,14 @@ use std::sync::Arc;
use tauri::State;
use crate::app::AppState;
use crate::domain::ios_policy::IosPolicyScope;
use crate::domain::models::extension::{
Extension, ExtensionInstallResult, ExtensionUpdateResult, ExtensionVersion,
};
use crate::presentation::commands::helpers::{
ensure_ios_policy_allows, log_command, map_command_error,
};
use crate::presentation::errors::CommandError;
use tt_domain::ios_policy::IosPolicyScope;
use tt_domain::models::extension::{
Extension, ExtensionInstallResult, ExtensionUpdateResult, ExtensionVersion,
};
#[tauri::command]
pub async fn get_extensions(
@ -39,11 +39,11 @@ pub async fn get_extensions(
let before = extensions.len();
extensions.retain(|extension| match extension.extension_type {
crate::domain::models::extension::ExtensionType::System => {
tt_domain::models::extension::ExtensionType::System => {
system_allowlist.allows(&extension.name)
}
crate::domain::models::extension::ExtensionType::Local
| crate::domain::models::extension::ExtensionType::Global => allow_third_party,
tt_domain::models::extension::ExtensionType::Local
| tt_domain::models::extension::ExtensionType::Global => allow_third_party,
});
let filtered = before.saturating_sub(extensions.len());

View file

@ -10,9 +10,9 @@ use tokio::fs;
use url::Url;
use crate::app::AppState;
use crate::domain::models::filename::sanitize_filename as sanitize_filename_contract;
use crate::presentation::commands::helpers::log_command;
use crate::presentation::errors::CommandError;
use tt_domain::models::filename::sanitize_filename as sanitize_filename_contract;
const UNSAFE_EXTENSIONS: &[&str] = &[
".php",

View file

@ -3,11 +3,11 @@ use std::fmt::Display;
use crate::presentation::errors::CommandError;
pub fn ensure_ios_policy_allows(
ios_policy: &crate::domain::ios_policy::IosPolicyActivationReport,
ios_policy: &tt_domain::ios_policy::IosPolicyActivationReport,
allowed: bool,
capability: &'static str,
) -> Result<(), CommandError> {
if ios_policy.scope == crate::domain::ios_policy::IosPolicyScope::Ios && !allowed {
if ios_policy.scope == tt_domain::ios_policy::IosPolicyScope::Ios && !allowed {
return Err(CommandError::Unauthorized(format!(
"iOS policy disabled capability: {capability}"
)));
@ -67,7 +67,7 @@ pub fn log_user_visible_error(message: impl AsRef<str>) {
#[cfg(test)]
mod tests {
use crate::domain::errors::GENERATION_CANCELLED_BY_USER_MESSAGE;
use tt_domain::errors::GENERATION_CANCELLED_BY_USER_MESSAGE;
use super::*;

View file

@ -7,9 +7,9 @@ use crate::application::dto::image_metadata_dto::{
CreateImageMetadataFolderDto, DeleteImageMetadataFolderDto, ImageMetadataFolderAssignmentDto,
SetImageMetadataFolderThumbnailsDto, UpdateImageMetadataFolderDto,
};
use crate::domain::models::image_metadata::{BackgroundFoldersPayload, ImageMetadataFolder};
use crate::presentation::commands::helpers::{log_command, map_command_error};
use crate::presentation::errors::CommandError;
use tt_domain::models::image_metadata::{BackgroundFoldersPayload, ImageMetadataFolder};
#[tauri::command]
pub async fn get_background_folders(

View file

@ -9,13 +9,13 @@ use tauri::{AppHandle, Manager, State, WebviewWindow};
use crate::app::AppState;
use crate::application::host_contract::IOS_EXPORT_STAGING_ROOT_NAME;
use crate::domain::errors::DomainError;
use crate::platform::ios_document_picker::{
PickDocumentResult, copy_picked_url_to_path, pick_data_archive, pick_skill_import_archive,
};
use crate::platform::ios_share_sheet::share_file;
use crate::presentation::commands::helpers::{log_command, map_command_error};
use crate::presentation::errors::CommandError;
use tt_domain::errors::DomainError;
const IOS_SKILL_IMPORT_STAGING_ROOT_NAME: &str = "tauritavern-skill-import-staging";

View file

@ -6,12 +6,12 @@ use tauri::State;
use ttsync_contract::sync::SyncMode;
use crate::app::AppState;
use crate::domain::models::lan_sync::{LanSyncPairedDeviceSummary, LanSyncStatus};
use crate::presentation::commands::helpers::{
ensure_ios_policy_allows, log_command, map_command_error,
};
use crate::presentation::errors::CommandError;
use tt_contracts::sync::{SyncJobReport, SyncOperationOptions};
use tt_domain::models::lan_sync::{LanSyncPairedDeviceSummary, LanSyncStatus};
fn ensure_lan_sync_allowed(app_state: &AppState) -> Result<(), CommandError> {
ensure_ios_policy_allows(
@ -280,9 +280,9 @@ pub async fn lan_sync_clear_sync_mode_override(
Ok(())
}
fn generate_qr_svg(text: &str) -> Result<String, crate::domain::errors::DomainError> {
fn generate_qr_svg(text: &str) -> Result<String, tt_domain::errors::DomainError> {
let code = QrCode::new(text.as_bytes())
.map_err(|error| crate::domain::errors::DomainError::InternalError(error.to_string()))?;
.map_err(|error| tt_domain::errors::DomainError::InternalError(error.to_string()))?;
Ok(code
.render::<qrcode::render::svg::Color>()
.min_dimensions(200, 200)

View file

@ -7,11 +7,11 @@ use crate::application::dto::preset_dto::{
DeleteOpenAIPresetDto, DeleteOpenAIPresetResponseDto, DeletePresetDto, RestorePresetDto,
RestorePresetResponseDto, SaveOpenAIPresetDto, SavePresetDto, SavePresetResponseDto,
};
use crate::domain::models::preset::PresetType;
use crate::presentation::commands::helpers::{
log_command, log_user_visible_error, map_command_error,
};
use crate::presentation::errors::CommandError;
use tt_domain::models::preset::PresetType;
const SKILL_SOURCE_KIND_PRESET: &str = "preset";

View file

@ -64,7 +64,7 @@ fn runtime_paths_dto(info: RuntimePathsInfo) -> RuntimePathsDto {
}
}
fn map_set_data_root_error(error: crate::domain::errors::DomainError) -> CommandError {
fn map_set_data_root_error(error: tt_domain::errors::DomainError) -> CommandError {
let command_error = CommandError::from(error);
if matches!(&command_error, CommandError::InternalServerError(_)) {
map_command_error("Failed to set data root")(command_error)

View file

@ -6,16 +6,16 @@ use serde::Serialize;
use tauri::State;
use crate::app::AppState;
use crate::domain::models::skill::{
use crate::presentation::commands::helpers::{
ensure_ios_policy_allows, log_command, map_command_error,
};
use crate::presentation::errors::CommandError;
use tt_domain::models::skill::{
DEFAULT_SKILL_READ_FALLBACK_MAX_CHARS, SkillFileRef, SkillImportInput, SkillImportPreview,
SkillIndexEntry, SkillInstallRequest, SkillInstallResult, SkillMoveRequest, SkillReadRequest,
SkillReadResult, SkillScope, SkillScopeFilter, SkillScopeRetargetRequest,
SkillScopeRetargetResult, SkillWriteRequest,
};
use crate::presentation::commands::helpers::{
ensure_ios_policy_allows, log_command, map_command_error,
};
use crate::presentation::errors::CommandError;
#[derive(Debug, Serialize)]
#[serde(rename_all = "camelCase")]

View file

@ -5,10 +5,10 @@ use tauri::State;
use ttsync_contract::sync::SyncMode;
use crate::app::AppState;
use crate::domain::models::tt_sync::TtSyncPairedServer;
use crate::presentation::commands::helpers::{log_command, map_command_error};
use crate::presentation::errors::CommandError;
use tt_contracts::sync::{SyncJobReport, SyncOperationOptions};
use tt_domain::models::tt_sync::TtSyncPairedServer;
#[derive(Debug, Clone, Serialize)]
pub struct TtSyncPermissionsDto {

View file

@ -3,11 +3,11 @@ use std::sync::Arc;
use tauri::State;
use crate::app::AppState;
use crate::domain::models::update::UpdateCheckResult;
use crate::presentation::commands::helpers::{
ensure_ios_policy_allows, log_command, map_command_error,
};
use crate::presentation::errors::CommandError;
use tt_domain::models::update::UpdateCheckResult;
#[tauri::command]
pub async fn check_for_update(

View file

@ -1,8 +1,8 @@
use crate::application::errors::ApplicationError;
use crate::domain::errors::DomainError;
use crate::domain::models::upstream_failure::UpstreamFailure;
use serde::Serialize;
use thiserror::Error;
use tt_domain::errors::DomainError;
use tt_domain::models::upstream_failure::UpstreamFailure;
#[derive(Error, Debug, Serialize)]
pub enum CommandError {
@ -82,7 +82,7 @@ impl CommandError {
#[cfg(test)]
mod tests {
use crate::domain::errors::GENERATION_CANCELLED_BY_USER_MESSAGE;
use tt_domain::errors::GENERATION_CANCELLED_BY_USER_MESSAGE;
use super::*;

View file

@ -83,8 +83,8 @@ test('chat rename events use backend-committed normalized file names', async ()
readFile(path.join(REPO_ROOT, 'src/tauri/main/routes/chat-routes.js'), 'utf8'),
readFile(path.join(REPO_ROOT, 'src-tauri/src/presentation/commands/chat_commands.rs'), 'utf8'),
readFile(path.join(REPO_ROOT, 'src-tauri/src/presentation/commands/group_chat_commands.rs'), 'utf8'),
readFile(path.join(REPO_ROOT, 'src-tauri/src/application/services/chat_service.rs'), 'utf8'),
readFile(path.join(REPO_ROOT, 'src-tauri/src/application/services/group_chat_service.rs'), 'utf8'),
readFile(path.join(REPO_ROOT, 'src-tauri/crates/tt-application/src/services/chat_service.rs'), 'utf8'),
readFile(path.join(REPO_ROOT, 'src-tauri/crates/tt-application/src/services/group_chat_service.rs'), 'utf8'),
]);
assert.match(route, /const sanitizedFileName = await context\.safeInvoke\('rename_group_chat'/);

View file

@ -6,8 +6,8 @@ const openaiSource = await readFile(new URL('../src/scripts/openai.js', import.m
const secretsSource = await readFile(new URL('../src/scripts/secrets.js', import.meta.url), 'utf8');
const aiRoutesSource = await readFile(new URL('../src/tauri/main/routes/ai-routes.js', import.meta.url), 'utf8');
const rustSource = await readFile(new URL('../src-tauri/crates/tt-domain/src/models/chat_completion_source.rs', import.meta.url), 'utf8');
const rustConfigSource = await readFile(new URL('../src-tauri/src/application/services/chat_completion_service/config.rs', import.meta.url), 'utf8');
const rustPayloadSource = await readFile(new URL('../src-tauri/src/application/services/chat_completion_service/payload/minimax.rs', import.meta.url), 'utf8');
const rustConfigSource = await readFile(new URL('../src-tauri/crates/tt-application/src/services/chat_completion_service/config.rs', import.meta.url), 'utf8');
const rustPayloadSource = await readFile(new URL('../src-tauri/crates/tt-application/src/services/chat_completion_service/payload/minimax.rs', import.meta.url), 'utf8');
const rustRepositorySource = await readRustSources(new URL('../src-tauri/crates/tt-adapter-provider-http/src/http_chat_completion_repository/', import.meta.url));
const rossAscendsSource = await readFile(new URL('../src/scripts/RossAscends-mods.js', import.meta.url), 'utf8');

View file

@ -11,7 +11,7 @@ function readProjectFile(relativePath) {
}
test('connectionRef prompt assembly overlays model binding instead of validating preset source', async () => {
const source = await readProjectFile('src-tauri/src/application/services/prompt_assembly_service.rs');
const source = await readProjectFile('src-tauri/crates/tt-application/src/services/prompt_assembly_service.rs');
assert.match(source, /apply_model_binding_to_prompt_settings/);
assert.match(source, /"deepseek"\s*=>\s*Ok\("deepseek_model"\)/);
@ -20,7 +20,7 @@ test('connectionRef prompt assembly overlays model binding instead of validating
});
test('currentPromptSnapshot prompt assembly overlays frozen current model connection', async () => {
const source = await readProjectFile('src-tauri/src/application/services/prompt_assembly_service.rs');
const source = await readProjectFile('src-tauri/crates/tt-application/src/services/prompt_assembly_service.rs');
const frontendSource = await readProjectFile('src/scripts/tauritavern/agent/frozen-run-input-snapshot.js');
const agentApiSource = await readProjectFile('src/tauri/main/api/agent-prompt-assembly-run.js');
@ -35,7 +35,7 @@ test('currentPromptSnapshot prompt assembly overlays frozen current model connec
});
test('requiresConfiguration prompt assembly fails fast before frontend broker handoff', async () => {
const source = await readProjectFile('src-tauri/src/application/services/prompt_assembly_service.rs');
const source = await readProjectFile('src-tauri/crates/tt-application/src/services/prompt_assembly_service.rs');
const guardIndex = source.indexOf('ensure_profile_model_configured(&profile)?;');
const brokerIndex = source.indexOf('AgentPromptAssemblyModeDto::FrontendPromptAssembly');

View file

@ -16,7 +16,7 @@ test('native regex batching shares the same runnable-script gate as sync regex e
});
test('native regex DTO remains an execution payload, not SillyTavern extension state', async () => {
const source = await readFile(path.join(REPO_ROOT, 'src-tauri', 'src', 'application', 'dto', 'native_regex_dto.rs'), 'utf8');
const source = await readFile(path.join(REPO_ROOT, 'src-tauri', 'crates', 'tt-application', 'src', 'dto', 'native_regex_dto.rs'), 'utf8');
assert.doesNotMatch(source, /\bpub\s+disabled\b/);
});

View file

@ -49,7 +49,7 @@ test('Stable Diffusion backend request uses explicit credentials instead of prov
'utf8',
);
const serviceSource = await readFile(
path.join(REPO_ROOT, 'src-tauri', 'src', 'application', 'services', 'stable_diffusion_service.rs'),
path.join(REPO_ROOT, 'src-tauri', 'crates', 'tt-application', 'src', 'services', 'stable_diffusion_service.rs'),
'utf8',
);

View file

@ -255,7 +255,7 @@ test('TauriTavern Sync automation status events refresh status only while toasts
test('TauriTavern Sync automation success toasts include next run time', async () => {
const listeners = await readRepoFile('src/scripts/tauri/setting/setting-panel/sync-listeners.js');
const service = await readRepoFile('src-tauri/src/application/services/sync_automation_service.rs');
const service = await readRepoFile('src-tauri/crates/tt-application/src/services/sync_automation_service.rs');
const model = await readRepoFile('src-tauri/crates/tt-contracts/src/sync_automation.rs');
const zhCn = await readRepoFile('src/locales/zh-cn.json');
const zhTw = await readRepoFile('src/locales/zh-tw.json');