|
|
|
|
@ -13,26 +13,25 @@ use std::sync::{Arc, Mutex};
|
|
|
|
|
|
|
|
|
|
use application::{
|
|
|
|
|
AgentResumer, AppError, AssignSkillToAgent, ChangeAgentProfile, CheckEmbedderSuggestion,
|
|
|
|
|
CloseProject, CloseTab,
|
|
|
|
|
CloseTerminal, ConfigureProfiles, ContextGuardUseCases, CreateAgentFromScratch,
|
|
|
|
|
CreateAgentFromTemplate,
|
|
|
|
|
CreateLayout, CreateMemory, CreateProject, CreateSkill, CreateTemplate, DeleteAgent,
|
|
|
|
|
LaunchAgentInput, ProposeContext, ReadContext, ReadMemory, SessionLimitService, WriteMemory,
|
|
|
|
|
DeleteEmbedderProfile, DeleteLayout, DeleteMemory, DeleteProfile, DeleteSkill, DeleteTemplate,
|
|
|
|
|
DescribeEmbedderEngines, DetectAgentDrift, DetectProfiles, DismissEmbedderSuggestion,
|
|
|
|
|
FirstRunState, GetMemory, GetProjectPermissions, GitBranches, GitCheckout, GitCommit, GitGraph,
|
|
|
|
|
GitInit, GitLog, GitStage, GitStatus, GitUnstage, HealthUseCase, InspectConversation,
|
|
|
|
|
LaunchAgent, ListAgents, ListAgentsInput, ListEmbedderProfiles, ListLayouts, ListMemories,
|
|
|
|
|
ListProfiles, ListProjects, ListResumableAgents, ListSkills, ListTemplates, LiveAgentRegistry,
|
|
|
|
|
LoadLayout, McpRuntime, MoveTabToNewWindow, MutateLayout, OnnxModelView, OpenProject,
|
|
|
|
|
PermissionProjectorRegistry,
|
|
|
|
|
OpenTerminal, OrchestratorService, ReadAgentContext, ReadMemoryIndex, ReadProjectContext,
|
|
|
|
|
RecallMemory, ReconcileLayouts, RecordTurn, RecordTurnProvider, ReferenceProfiles,
|
|
|
|
|
RenameLayout, ResizeTerminal, ResolveAgentPermissions, ResolveMemoryLinks, SaveEmbedderProfile,
|
|
|
|
|
SaveProfile, SetActiveLayout, SnapshotRunningAgents, StructuredSessions, SuggestedThisSession,
|
|
|
|
|
SyncAgentWithTemplate, TerminalSessions, UnassignSkillFromAgent, UpdateAgentContext,
|
|
|
|
|
UpdateAgentPermissions, UpdateMemory, UpdateProjectContext, UpdateProjectPermissions,
|
|
|
|
|
UpdateSkill, UpdateTemplate, WriteToTerminal, AGENT_MEMORY_RECALL_BUDGET,
|
|
|
|
|
CloseProject, CloseTab, CloseTerminal, ConfigureProfiles, ContextGuardUseCases,
|
|
|
|
|
CreateAgentFromScratch, CreateAgentFromTemplate, CreateLayout, CreateMemory, CreateProject,
|
|
|
|
|
CreateSkill, CreateTemplate, DeleteAgent, DeleteEmbedderProfile, DeleteLayout, DeleteMemory,
|
|
|
|
|
DeleteProfile, DeleteSkill, DeleteTemplate, DescribeEmbedderEngines, DetectAgentDrift,
|
|
|
|
|
DetectProfiles, DismissEmbedderSuggestion, FirstRunState, GetMemory, GetProjectPermissions,
|
|
|
|
|
GitBranches, GitCheckout, GitCommit, GitGraph, GitInit, GitLog, GitStage, GitStatus,
|
|
|
|
|
GitUnstage, HealthUseCase, InspectConversation, LaunchAgent, LaunchAgentInput, ListAgents,
|
|
|
|
|
ListAgentsInput, ListEmbedderProfiles, ListLayouts, ListMemories, ListProfiles, ListProjects,
|
|
|
|
|
ListResumableAgents, ListSkills, ListTemplates, LiveAgentRegistry, LoadLayout, McpRuntime,
|
|
|
|
|
MoveTabToNewWindow, MutateLayout, OnnxModelView, OpenProject, OpenTerminal,
|
|
|
|
|
OrchestratorService, PermissionProjectorRegistry, ProposeContext, ReadAgentContext,
|
|
|
|
|
ReadContext, ReadMemory, ReadMemoryIndex, ReadProjectContext, RecallMemory, ReconcileLayouts,
|
|
|
|
|
RecordTurn, RecordTurnProvider, ReferenceProfiles, RenameLayout, ResizeTerminal,
|
|
|
|
|
ResolveAgentPermissions, ResolveMemoryLinks, SaveEmbedderProfile, SaveProfile,
|
|
|
|
|
SessionLimitService, SetActiveLayout, SnapshotRunningAgents, StructuredSessions,
|
|
|
|
|
SuggestedThisSession, SyncAgentWithTemplate, TerminalSessions, UnassignSkillFromAgent,
|
|
|
|
|
UpdateAgentContext, UpdateAgentPermissions, UpdateMemory, UpdateProjectContext,
|
|
|
|
|
UpdateProjectPermissions, UpdateSkill, UpdateTemplate, WriteMemory, WriteToTerminal,
|
|
|
|
|
AGENT_MEMORY_RECALL_BUDGET,
|
|
|
|
|
};
|
|
|
|
|
use domain::ports::{
|
|
|
|
|
AgentContextStore, AgentRuntime, AgentSessionFactory, Clock, Embedder, EmbedderEnvInspector,
|
|
|
|
|
@ -50,16 +49,16 @@ use uuid::Uuid;
|
|
|
|
|
|
|
|
|
|
use infrastructure::{
|
|
|
|
|
embedder_from_profile, AdaptiveMemoryRecall, ClaudePermissionProjector,
|
|
|
|
|
ClaudeTranscriptInspector, CliAgentRuntime, CodexPermissionProjector,
|
|
|
|
|
EmbedderEnvProbe, FsConversationLog, FsEmbedderProfileStore, FsEmbedderPromptStore,
|
|
|
|
|
FsHandoffStore, FsMemoryStore, FsOrchestratorWatcher, FsPermissionStore, FsProfileStore,
|
|
|
|
|
FsProjectStore, FsProviderSessionStore, FsSkillStore, FsTemplateStore, Git2Repository,
|
|
|
|
|
ClaudeTranscriptInspector, CliAgentRuntime, CodexPermissionProjector, EmbedderEnvProbe,
|
|
|
|
|
FsConversationLog, FsEmbedderProfileStore, FsEmbedderPromptStore, FsHandoffStore,
|
|
|
|
|
FsMemoryStore, FsOrchestratorWatcher, FsPermissionStore, FsProfileStore, FsProjectStore,
|
|
|
|
|
FsProviderSessionStore, FsSkillStore, FsTemplateStore, Git2Repository,
|
|
|
|
|
HeuristicHandoffSummarizer, IdeaiContextStore, InMemoryConversationRegistry, InMemoryMailbox,
|
|
|
|
|
LocalFileSystem, LocalProcessSpawner, McpServer, MediatedInbox, NaiveMemoryRecall,
|
|
|
|
|
OrchestratorWatchHandle, PortablePtyAdapter, RwFileGuard, StructuredSessionFactory, SystemClock,
|
|
|
|
|
SystemMillisClock, TokioBroadcastEventBus, TokioScheduler, UuidGenerator, VectorMemoryRecall,
|
|
|
|
|
DEFAULT_OLLAMA_BASE_URL, ONNX_CACHE_SUBDIR, RECOMMENDED_ONNX_MODELS, VECTOR_HTTP_ENABLED,
|
|
|
|
|
VECTOR_ONNX_ENABLED,
|
|
|
|
|
OrchestratorWatchHandle, PortablePtyAdapter, RwFileGuard, StructuredSessionFactory,
|
|
|
|
|
SystemClock, SystemMillisClock, TokioBroadcastEventBus, TokioScheduler, UuidGenerator,
|
|
|
|
|
VectorMemoryRecall, DEFAULT_OLLAMA_BASE_URL, ONNX_CACHE_SUBDIR, RECOMMENDED_ONNX_MODELS,
|
|
|
|
|
VECTOR_HTTP_ENABLED, VECTOR_ONNX_ENABLED,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
use crate::chat::ChatBridge;
|
|
|
|
|
@ -773,10 +772,8 @@ impl AppState {
|
|
|
|
|
// l'infrastructure, keyés par leur `ProjectorKey` via `with(...)`.
|
|
|
|
|
let permission_projectors = Arc::new(
|
|
|
|
|
PermissionProjectorRegistry::new()
|
|
|
|
|
.with(Arc::new(ClaudePermissionProjector)
|
|
|
|
|
as Arc<dyn domain::PermissionProjector>)
|
|
|
|
|
.with(Arc::new(CodexPermissionProjector)
|
|
|
|
|
as Arc<dyn domain::PermissionProjector>),
|
|
|
|
|
.with(Arc::new(ClaudePermissionProjector) as Arc<dyn domain::PermissionProjector>)
|
|
|
|
|
.with(Arc::new(CodexPermissionProjector) as Arc<dyn domain::PermissionProjector>),
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
let launch_agent = Arc::new(
|
|
|
|
|
@ -1520,9 +1517,10 @@ fn claude_mcp_config_target(profile: &AgentProfile) -> Option<&str> {
|
|
|
|
|
/// Pendant Codex de [`migrate_claude_run_dir`] : répare le `config.toml` MCP isolé
|
|
|
|
|
/// du run dir (table `[mcp_servers.idea]`) pour que Codex, qui lit ses serveurs MCP
|
|
|
|
|
/// dans `$CODEX_HOME/config.toml`, voie les outils `idea_*` après un redémarrage.
|
|
|
|
|
/// `CODEX_HOME` est isolé au run dir au lancement (jamais le `~/.codex` global), donc
|
|
|
|
|
/// ce fichier appartient entièrement à IdeA : il est régénéré (clobber) dès qu'un
|
|
|
|
|
/// runtime réel est disponible. Best-effort, idempotent.
|
|
|
|
|
/// `CODEX_HOME` est isolé au run dir au lancement (jamais le `~/.codex` global).
|
|
|
|
|
/// Le fichier reste co-géré : la migration répare la partie MCP/trust sans effacer
|
|
|
|
|
/// les clés de permission (`approval_policy`, `sandbox_mode`) écrites par le
|
|
|
|
|
/// projecteur Codex. Best-effort, idempotent.
|
|
|
|
|
async fn migrate_codex_run_dir(
|
|
|
|
|
project: &Project,
|
|
|
|
|
agent_id: &AgentId,
|
|
|
|
|
@ -1547,11 +1545,18 @@ async fn migrate_codex_run_dir(
|
|
|
|
|
project_id: project.id.as_uuid().simple().to_string(),
|
|
|
|
|
requester: agent_id.to_string(),
|
|
|
|
|
});
|
|
|
|
|
migrate_codex_mcp_config(run_dir_path, profile, runtime.as_ref()).await
|
|
|
|
|
migrate_codex_mcp_config(
|
|
|
|
|
run_dir_path,
|
|
|
|
|
project.root.as_str(),
|
|
|
|
|
profile,
|
|
|
|
|
runtime.as_ref(),
|
|
|
|
|
)
|
|
|
|
|
.await
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async fn migrate_codex_mcp_config(
|
|
|
|
|
run_dir: &Path,
|
|
|
|
|
project_root: &str,
|
|
|
|
|
profile: &AgentProfile,
|
|
|
|
|
runtime: Option<&McpRuntime>,
|
|
|
|
|
) -> Result<(), std::io::Error> {
|
|
|
|
|
@ -1564,15 +1569,23 @@ async fn migrate_codex_mcp_config(
|
|
|
|
|
return Ok(());
|
|
|
|
|
};
|
|
|
|
|
let toml_path = run_dir.join(target);
|
|
|
|
|
let desired = mcp_server_entry_toml(profile, Some(runtime));
|
|
|
|
|
let declaration = mcp_server_entry_toml(profile, Some(runtime));
|
|
|
|
|
|
|
|
|
|
// `config.toml` isolé = entièrement géré par IdeA ⇒ régénération (clobber) ;
|
|
|
|
|
// idempotent (no-op si le contenu est déjà à jour).
|
|
|
|
|
match tokio::fs::read_to_string(&toml_path).await {
|
|
|
|
|
Ok(existing) if existing == desired => return Ok(()),
|
|
|
|
|
Ok(_) => {}
|
|
|
|
|
Err(err) if err.kind() == std::io::ErrorKind::NotFound => {}
|
|
|
|
|
// Ne jamais clobber le fichier complet ici : il porte aussi la projection de
|
|
|
|
|
// permissions Codex. On répare seulement la table MCP et les entrées trust.
|
|
|
|
|
let existing = match tokio::fs::read_to_string(&toml_path).await {
|
|
|
|
|
Ok(existing) => Some(existing),
|
|
|
|
|
Err(err) if err.kind() == std::io::ErrorKind::NotFound => None,
|
|
|
|
|
Err(err) => return Err(err),
|
|
|
|
|
};
|
|
|
|
|
let desired = codex_config_toml_for_migration(
|
|
|
|
|
existing.as_deref(),
|
|
|
|
|
&declaration,
|
|
|
|
|
run_dir.to_string_lossy().as_ref(),
|
|
|
|
|
project_root,
|
|
|
|
|
);
|
|
|
|
|
if existing.as_deref() == Some(desired.as_str()) {
|
|
|
|
|
return Ok(());
|
|
|
|
|
}
|
|
|
|
|
if let Some(parent) = toml_path.parent() {
|
|
|
|
|
tokio::fs::create_dir_all(parent).await?;
|
|
|
|
|
@ -1629,6 +1642,98 @@ fn mcp_server_entry_toml(profile: &AgentProfile, runtime: Option<&McpRuntime>) -
|
|
|
|
|
domain::McpServerWiring::new(command, args, transport).to_config_toml()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn codex_config_toml_for_migration(
|
|
|
|
|
existing: Option<&str>,
|
|
|
|
|
mcp_declaration: &str,
|
|
|
|
|
run_dir: &str,
|
|
|
|
|
project_root: &str,
|
|
|
|
|
) -> String {
|
|
|
|
|
let mut text = replace_toml_table_block(
|
|
|
|
|
existing.unwrap_or_default(),
|
|
|
|
|
"mcp_servers.idea",
|
|
|
|
|
mcp_declaration.trim_end(),
|
|
|
|
|
);
|
|
|
|
|
text = ensure_codex_project_trust(&text, run_dir);
|
|
|
|
|
text = ensure_codex_project_trust(&text, project_root);
|
|
|
|
|
if !text.ends_with('\n') {
|
|
|
|
|
text.push('\n');
|
|
|
|
|
}
|
|
|
|
|
text
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn replace_toml_table_block(existing: &str, table: &str, replacement: &str) -> String {
|
|
|
|
|
let header = format!("[{table}]");
|
|
|
|
|
let mut out = Vec::new();
|
|
|
|
|
let mut skipping = false;
|
|
|
|
|
let mut inserted = false;
|
|
|
|
|
|
|
|
|
|
for line in existing.lines() {
|
|
|
|
|
let trimmed = line.trim();
|
|
|
|
|
if trimmed == header {
|
|
|
|
|
if !inserted {
|
|
|
|
|
push_toml_block(&mut out, replacement);
|
|
|
|
|
inserted = true;
|
|
|
|
|
}
|
|
|
|
|
skipping = true;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if skipping && trimmed.starts_with('[') && trimmed.ends_with(']') {
|
|
|
|
|
skipping = false;
|
|
|
|
|
}
|
|
|
|
|
if !skipping {
|
|
|
|
|
out.push(line.to_owned());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if !inserted {
|
|
|
|
|
if !out.is_empty() && !out.last().is_some_and(|line| line.is_empty()) {
|
|
|
|
|
out.push(String::new());
|
|
|
|
|
}
|
|
|
|
|
push_toml_block(&mut out, replacement);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
out.join("\n")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn push_toml_block(out: &mut Vec<String>, block: &str) {
|
|
|
|
|
out.extend(block.lines().map(ToOwned::to_owned));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn ensure_codex_project_trust(existing: &str, path: &str) -> String {
|
|
|
|
|
if path.is_empty() {
|
|
|
|
|
return existing.to_owned();
|
|
|
|
|
}
|
|
|
|
|
let header = format!(r#"[projects.{}]"#, toml_quoted(path));
|
|
|
|
|
if existing.lines().any(|line| line.trim() == header) {
|
|
|
|
|
return existing.to_owned();
|
|
|
|
|
}
|
|
|
|
|
let mut text = existing.trim_end().to_owned();
|
|
|
|
|
if !text.is_empty() {
|
|
|
|
|
text.push_str("\n\n");
|
|
|
|
|
}
|
|
|
|
|
text.push_str(&header);
|
|
|
|
|
text.push_str("\ntrust_level = \"trusted\"\n");
|
|
|
|
|
text
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn toml_quoted(value: &str) -> String {
|
|
|
|
|
let mut out = String::with_capacity(value.len() + 2);
|
|
|
|
|
out.push('"');
|
|
|
|
|
for ch in value.chars() {
|
|
|
|
|
match ch {
|
|
|
|
|
'\\' => out.push_str("\\\\"),
|
|
|
|
|
'"' => out.push_str("\\\""),
|
|
|
|
|
'\n' => out.push_str("\\n"),
|
|
|
|
|
'\r' => out.push_str("\\r"),
|
|
|
|
|
'\t' => out.push_str("\\t"),
|
|
|
|
|
c if (c as u32) < 0x20 => out.push_str(&format!("\\u{:04x}", c as u32)),
|
|
|
|
|
c => out.push(c),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
out.push('"');
|
|
|
|
|
out
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn merge_claude_settings_json(existing: &str, project_root: &str) -> Option<Value> {
|
|
|
|
|
let mut doc = match serde_json::from_str::<Value>(existing) {
|
|
|
|
|
Ok(Value::Object(map)) => Value::Object(map),
|
|
|
|
|
@ -1846,7 +1951,7 @@ fn write_atomically(path: &Path, content: &str) -> std::io::Result<()> {
|
|
|
|
|
mod run_dir_migration_tests {
|
|
|
|
|
use super::{
|
|
|
|
|
claude_settings_seed_value, is_claude_mcp_profile, mcp_server_entry,
|
|
|
|
|
merge_claude_settings_json, merge_mcp_json, migrate_claude_run_dir,
|
|
|
|
|
merge_claude_settings_json, merge_mcp_json, migrate_claude_run_dir, migrate_codex_run_dir,
|
|
|
|
|
};
|
|
|
|
|
use application::McpRuntimeProvider;
|
|
|
|
|
use domain::ids::{AgentId, ProfileId, ProjectId};
|
|
|
|
|
@ -1876,6 +1981,25 @@ mod run_dir_migration_tests {
|
|
|
|
|
))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn codex_profile() -> AgentProfile {
|
|
|
|
|
AgentProfile::new(
|
|
|
|
|
ProfileId::from_uuid(Uuid::from_u128(10)),
|
|
|
|
|
"OpenAI Codex CLI",
|
|
|
|
|
"codex",
|
|
|
|
|
Vec::new(),
|
|
|
|
|
ContextInjection::convention_file("AGENTS.md").unwrap(),
|
|
|
|
|
None,
|
|
|
|
|
"{agentRunDir}",
|
|
|
|
|
None,
|
|
|
|
|
)
|
|
|
|
|
.unwrap()
|
|
|
|
|
.with_structured_adapter(StructuredAdapter::Codex)
|
|
|
|
|
.with_mcp(McpCapability::new(
|
|
|
|
|
McpConfigStrategy::toml_config_home(".codex/config.toml", "CODEX_HOME").unwrap(),
|
|
|
|
|
McpTransport::Stdio,
|
|
|
|
|
))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn runtime(agent_id: AgentId) -> application::McpRuntime {
|
|
|
|
|
application::McpRuntime {
|
|
|
|
|
exe: "/opt/IdeA.AppImage".to_owned(),
|
|
|
|
|
@ -2012,6 +2136,58 @@ mod run_dir_migration_tests {
|
|
|
|
|
let _ = std::fs::remove_dir_all(temp);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn reconcile_codex_run_dir_preserves_permissions_and_repairs_mcp_trust() {
|
|
|
|
|
let agent_id = AgentId::from_uuid(Uuid::from_u128(89));
|
|
|
|
|
let temp = std::env::temp_dir().join(format!("idea-codex-run-migrate-{}", Uuid::new_v4()));
|
|
|
|
|
let project_root = temp.join("project");
|
|
|
|
|
let run_dir = project_root.join(".ideai/run").join(agent_id.to_string());
|
|
|
|
|
std::fs::create_dir_all(run_dir.join(".codex")).unwrap();
|
|
|
|
|
std::fs::write(
|
|
|
|
|
run_dir.join(".codex/config.toml"),
|
|
|
|
|
r#"approval_policy = "never"
|
|
|
|
|
sandbox_mode = "workspace-write"
|
|
|
|
|
|
|
|
|
|
[mcp_servers.idea]
|
|
|
|
|
command = "stale"
|
|
|
|
|
args = ["mcp-server"]
|
|
|
|
|
transport = "stdio"
|
|
|
|
|
"#,
|
|
|
|
|
)
|
|
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
|
|
let project = domain::Project::new(
|
|
|
|
|
ProjectId::from_uuid(Uuid::from_u128(1234)),
|
|
|
|
|
"demo",
|
|
|
|
|
domain::project::ProjectPath::new(project_root.to_string_lossy().into_owned()).unwrap(),
|
|
|
|
|
domain::remote::RemoteRef::local(),
|
|
|
|
|
1,
|
|
|
|
|
)
|
|
|
|
|
.unwrap();
|
|
|
|
|
let profile = codex_profile();
|
|
|
|
|
tokio::runtime::Builder::new_current_thread()
|
|
|
|
|
.enable_all()
|
|
|
|
|
.build()
|
|
|
|
|
.unwrap()
|
|
|
|
|
.block_on(async {
|
|
|
|
|
migrate_codex_run_dir(&project, &agent_id, &profile)
|
|
|
|
|
.await
|
|
|
|
|
.unwrap();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
let config = std::fs::read_to_string(run_dir.join(".codex/config.toml")).unwrap();
|
|
|
|
|
assert!(config.contains(r#"approval_policy = "never""#));
|
|
|
|
|
assert!(config.contains(r#"sandbox_mode = "workspace-write""#));
|
|
|
|
|
assert!(config.contains("[mcp_servers.idea]"));
|
|
|
|
|
assert!(config.contains(r#"default_tools_approval_mode = "approve""#));
|
|
|
|
|
assert!(config.contains("tool_timeout_sec = 86400"));
|
|
|
|
|
assert!(!config.contains(r#"command = "stale""#));
|
|
|
|
|
assert!(config.contains(&format!(r#"[projects."{}"]"#, run_dir.to_string_lossy())));
|
|
|
|
|
assert!(config.contains(&format!(r#"[projects."{}"]"#, project.root.as_str())));
|
|
|
|
|
|
|
|
|
|
let _ = std::fs::remove_dir_all(temp);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn claude_profile_guard_matches_only_claude_mcp_profiles() {
|
|
|
|
|
assert!(is_claude_mcp_profile(&claude_profile()));
|
|
|
|
|
@ -2361,6 +2537,7 @@ mod mcp_serve_peer_tests {
|
|
|
|
|
manifest: AgentManifest {
|
|
|
|
|
version: 1,
|
|
|
|
|
entries: Vec::new(),
|
|
|
|
|
orchestrator: None,
|
|
|
|
|
},
|
|
|
|
|
contents: HashMap::new(),
|
|
|
|
|
})))
|
|
|
|
|
@ -3123,11 +3300,11 @@ mod mcp_serve_peer_tests {
|
|
|
|
|
// traite ces commandes sans cette erreur — et le réfute sans le câblage.
|
|
|
|
|
// -----------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
use application::{
|
|
|
|
|
ContextGuardUseCases, ProposeContext, ReadContext, ReadMemory, WriteMemory,
|
|
|
|
|
};
|
|
|
|
|
use application::{ContextGuardUseCases, ProposeContext, ReadContext, ReadMemory, WriteMemory};
|
|
|
|
|
use domain::conversation::ConversationParty;
|
|
|
|
|
use domain::memory::{Memory, MemoryFrontmatter, MemoryIndexEntry, MemoryLink, MemorySlug, MemoryType};
|
|
|
|
|
use domain::memory::{
|
|
|
|
|
Memory, MemoryFrontmatter, MemoryIndexEntry, MemoryLink, MemorySlug, MemoryType,
|
|
|
|
|
};
|
|
|
|
|
use domain::ports::{Clock, MemoryError, MemoryStore};
|
|
|
|
|
use domain::OrchestratorCommand;
|
|
|
|
|
use infrastructure::RwFileGuard;
|
|
|
|
|
@ -3204,8 +3381,7 @@ mod mcp_serve_peer_tests {
|
|
|
|
|
contexts: FakeContexts,
|
|
|
|
|
) -> (Arc<OrchestratorService>, Arc<FakeMemory>) {
|
|
|
|
|
let memory = Arc::new(FakeMemory::default());
|
|
|
|
|
let file_guard =
|
|
|
|
|
Arc::new(RwFileGuard::new()) as Arc<dyn domain::fileguard::FileGuard>;
|
|
|
|
|
let file_guard = Arc::new(RwFileGuard::new()) as Arc<dyn domain::fileguard::FileGuard>;
|
|
|
|
|
let context_guard = Arc::new(ContextGuardUseCases {
|
|
|
|
|
read_context: Arc::new(ReadContext::new(
|
|
|
|
|
Arc::clone(&file_guard),
|
|
|
|
|
@ -3571,6 +3747,7 @@ mod mcp_e2e_loopback_tests {
|
|
|
|
|
manifest: AgentManifest {
|
|
|
|
|
version: 1,
|
|
|
|
|
entries: Vec::new(),
|
|
|
|
|
orchestrator: None,
|
|
|
|
|
},
|
|
|
|
|
contents: HashMap::new(),
|
|
|
|
|
})))
|
|
|
|
|
|