L'appairage ne survivait pas au redémarrage et son code, permanent, était imprimé sur la sortie standard. Un appareil appairé devient une entité persistante, nommée et révocable, derrière un code désormais éphémère. - B1 : port DeviceSessionStore et adapter FsDeviceSessionStore, entités de domaine (PairedDevice, DeviceId, SessionTokenHash, DeviceName). Les tokens sont hachés en SHA-256 et comparés en temps constant (subtle) : le store ne peut pas rejouer une session qu'il a servie. Cookie Max-Age 400 j à renouvellement glissant, lastSeenAtMs throttlé. - B2 : code éphémère en mémoire, TTL 10 min et usage unique, toute génération invalidant la précédente. POST /api/pairing-code authentifiée, flag --new-code. Le code est retiré du boot et l'eprintln! qui l'imprimait est supprimé. - B3 : endpoints devices (list/rename/revoke/revoke-all/logout), event DeviceRevoked et ActiveConnectionRegistry par device_id, fermant sans délai les WebSockets d'un appareil révoqué. - B4 : port PairAttemptLimiter et adapter mémoire, rate-limit par origine et global sur horloge injectée, donc testable sans attente réelle. La normalisation du code passe côté serveur : elle absorbe la dette #76, que la seule normalisation frontend de #75 ne faisait que masquer. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
215 lines
8.0 KiB
Rust
215 lines
8.0 KiB
Rust
//! # IdeA — Domain layer
|
|
//!
|
|
//! The **pure** hexagonal core (ARCHITECTURE.md §1.4, §3, §4, §7). It contains:
|
|
//!
|
|
//! - **Entities & value objects** with invariants enforced by validating
|
|
//! constructors (`new`/`try_new` returning `Result`),
|
|
//! - the **pure layout logic** (`split`/`merge`/`resize`/`move` as immutable
|
|
//! `&LayoutTree -> Result<LayoutTree, LayoutError>` functions),
|
|
//! - **ports** (traits) the infrastructure implements,
|
|
//! - **domain events** and **errors**.
|
|
//!
|
|
//! ## Dependency rule
|
|
//!
|
|
//! This crate depends on **no I/O**: no `tokio`, no `std::fs`, no
|
|
//! `std::process`, no `git2`/`portable-pty`/`russh`. The only third-party
|
|
//! dependencies are `uuid`, `serde` (allowed solely to derive (de)serialisation
|
|
//! of *persisted* domain types — a metier format constraint, not I/O),
|
|
//! `thiserror`, and `async-trait`.
|
|
//!
|
|
//! ## Async strategy for ports
|
|
//!
|
|
//! I/O-touching ports (`PtyPort`, `FileSystem`, `ProcessSpawner`, `RemoteHost`,
|
|
//! the stores, `GitPort`) are `#[async_trait]`. They are injected as
|
|
//! `Arc<dyn Port>` trait objects at the composition root, which native
|
|
//! `async fn`-in-trait does not yet support dyn-compatibly without boxing;
|
|
//! `async_trait` boxes the returned future and keeps the ports object-safe.
|
|
//! Non-blocking ports (`Clock`, `IdGenerator`, `EventBus`, `AgentRuntime`)
|
|
//! remain plain synchronous traits. See [`ports`] for details.
|
|
|
|
#![forbid(unsafe_code)]
|
|
#![warn(missing_docs)]
|
|
|
|
pub mod agent;
|
|
pub mod agent_tool_policy;
|
|
pub mod background_task;
|
|
pub mod conversation;
|
|
pub mod conversation_log;
|
|
pub mod device;
|
|
pub mod error;
|
|
pub mod events;
|
|
pub mod fileguard;
|
|
pub mod git;
|
|
pub mod ids;
|
|
pub mod inbox;
|
|
pub mod input;
|
|
pub mod issue;
|
|
pub mod layout;
|
|
pub mod live_state;
|
|
pub mod mailbox;
|
|
pub mod markdown;
|
|
pub mod memory;
|
|
pub mod memory_harvest;
|
|
pub mod model_server;
|
|
pub mod orchestrator;
|
|
pub mod permission;
|
|
pub mod ports;
|
|
pub mod profile;
|
|
pub mod project;
|
|
pub mod readiness;
|
|
pub mod remote;
|
|
pub mod sandbox;
|
|
pub mod session_limit;
|
|
pub mod skill;
|
|
pub mod sprint;
|
|
pub mod template;
|
|
pub mod terminal;
|
|
|
|
mod validation;
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Curated re-exports for ergonomic downstream use.
|
|
// ---------------------------------------------------------------------------
|
|
|
|
pub use error::DomainError;
|
|
|
|
pub use ids::{
|
|
AgentId, IssueId, LayoutId, LocalModelServerId, NodeId, ProfileId, ProjectId, ScheduleId,
|
|
SessionId, SkillId, SprintId, TabId, TaskId, TemplateId, WindowId,
|
|
};
|
|
|
|
pub use project::{Project, ProjectPath};
|
|
|
|
pub use agent::{Agent, AgentManifest, AgentOrigin, ManifestEntry};
|
|
|
|
pub use agent_tool_policy::AgentToolPolicy;
|
|
|
|
pub use background_task::{
|
|
BackgroundTask, BackgroundTaskError, BackgroundTaskKind, BackgroundTaskResult,
|
|
BackgroundTaskState, BackgroundTaskWakePolicy, BACKGROUND_TASK_LABEL_MAX_CHARS,
|
|
BACKGROUND_TASK_OUTPUT_TAIL_MAX_BYTES, BACKGROUND_TASK_TEXT_MAX_BYTES,
|
|
};
|
|
|
|
pub use skill::{Skill, SkillRef, SkillScope};
|
|
|
|
pub use template::{AgentTemplate, TemplateVersion};
|
|
|
|
pub use profile::{
|
|
AgentProfile, ContextInjection, EmbedderProfile, EmbedderStrategy, LivenessStrategy,
|
|
McpServerWiring, RateLimitPattern, SessionStrategy,
|
|
};
|
|
|
|
pub use mailbox::{
|
|
AgentMailbox, AgentQueueSnapshot, MailboxError, PendingReply, QueuedTicketSnapshot, Ticket,
|
|
TicketId,
|
|
};
|
|
|
|
pub use conversation::{
|
|
Conversation, ConversationError, ConversationId, ConversationParty, ConversationRegistry,
|
|
ConversationSession, SessionRef, WaitForGraph,
|
|
};
|
|
|
|
pub use input::{AgentBusyState, AgentLiveness, InputMediator, InputSource};
|
|
|
|
pub use inbox::{
|
|
AgentInbox, AgentInboxSnapshot, InboxError, InboxItem, InboxItemKind, InboxReceipt,
|
|
InboxReceiptStatus, InboxSource, DEFAULT_AGENT_INBOX_CAPACITY,
|
|
};
|
|
|
|
pub use issue::{
|
|
AgentIssueRef, AgentIssueRole, Issue, IssueActor, IssueCarnet, IssueError, IssueIndexEntry,
|
|
IssueLink, IssueLinkKind, IssueListFilter, IssueNumber, IssuePriority, IssueRef, IssueStatus,
|
|
IssueVersion,
|
|
};
|
|
|
|
pub use sprint::{
|
|
validate_sprint_ordering, Sprint, SprintError, SprintIndexEntry, SprintOrder, SprintStatus,
|
|
SprintVersion,
|
|
};
|
|
|
|
pub use live_state::{LiveEntry, LiveState, WorkStatus, FIELD_MAX_BYTES, FIELD_PREVIEW_MAX_CHARS};
|
|
|
|
pub use readiness::{ReadinessPolicy, ReadinessSignal};
|
|
|
|
pub use session_limit::{plan_resume, RateLimitSource, ResumePlan, SessionLimit};
|
|
|
|
pub use conversation_log::{
|
|
bound_handoff_summary, clamp_page_limit, rotation_plan, ConversationArchive, ConversationLog,
|
|
ConversationTurn, Handoff, HandoffStore, HandoffSummarizer, PageCursor, PageDirection,
|
|
ProviderSessionStore, RotationDecision, RotationThresholds, SegmentStats, TurnId, TurnRole,
|
|
TurnSlice, HANDOFF_SUMMARY_MAX_CHARS, MAX_ARCHIVE_SEGMENTS, PAGE_DEFAULT_LIMIT, PAGE_MAX_LIMIT,
|
|
ROTATE_AFTER_BYTES, ROTATE_AFTER_TURNS,
|
|
};
|
|
|
|
pub use device::{
|
|
AuthenticatedDevice, DeviceError, DeviceId, DeviceName, PairedDevice, SessionTokenHash,
|
|
};
|
|
|
|
pub use fileguard::{
|
|
is_orchestrator, may_write_directly, FileGuard, GuardError, GuardedResource,
|
|
OrchestratorDesignation, ReadLease, WriteLease,
|
|
};
|
|
|
|
pub use markdown::MarkdownDoc;
|
|
|
|
pub use memory::{Memory, MemoryFrontmatter, MemoryIndexEntry, MemoryLink, MemorySlug, MemoryType};
|
|
|
|
pub use memory_harvest::{
|
|
parse_memory_directives, MemoryHarvestDirective, MemoryHarvestReport, MAX_BLOCKS,
|
|
MAX_BLOCK_BYTES, MAX_DESCRIPTION_CHARS,
|
|
};
|
|
|
|
pub use model_server::{
|
|
validate_free_args, ExecutablePath, HfModelRef, LlamaCppOptions, LocalModelRef,
|
|
LocalModelServerConfig, LocalModelServerKind, ModelPath, ModelServerEndpoint,
|
|
ModelServerLifecycleStatus, ModelServerReady, ModelServerStatus, ModelSource, StopPolicy,
|
|
};
|
|
|
|
pub use remote::{RemoteKind, RemoteRef, SshAuth};
|
|
|
|
pub use terminal::{PtySize, SessionKind, SessionStatus, TerminalSession};
|
|
|
|
pub use git::GitRepository;
|
|
|
|
pub use layout::{
|
|
Direction, GridCell, GridContainer, LayoutError, LayoutNode, LayoutTree, LeafCell,
|
|
PersistedMonitorState, PersistedWindowKind, PersistedWindowPosition, PersistedWindowSize,
|
|
PersistedWindowState, SplitContainer, Tab, WeightedChild, Window, WindowStateSnapshot,
|
|
Workspace, WINDOW_STATE_SNAPSHOT_VERSION,
|
|
};
|
|
|
|
pub use events::{DomainEvent, OrchestrationSource};
|
|
|
|
pub use permission::{
|
|
render_permission_summary, resolve as resolve_permissions, AgentPermissionOverride, Capability,
|
|
CommandMatcher, CommandRule, Effect, EffectivePermissions, Glob, PathScope, PermissionError,
|
|
PermissionProjection, PermissionProjector, PermissionRule, PermissionSet, Posture,
|
|
ProjectPermissions, ProjectedFile, ProjectionContext, ProjectorKey, PERMISSIONS_VERSION,
|
|
};
|
|
|
|
pub use sandbox::{
|
|
compile_sandbox_plan, PathAccess, PathGrant, SandboxContext, SandboxEnforcer, SandboxError,
|
|
SandboxKind, SandboxPlan, SandboxStatus,
|
|
};
|
|
|
|
pub use orchestrator::{
|
|
OrchestratorCommand, OrchestratorError, OrchestratorRequest, OrchestratorVisibility,
|
|
};
|
|
|
|
pub use ports::{
|
|
AgentContextStore, AgentRuntime, AgentToolPolicyStore, AssistantContextError,
|
|
AssistantContextProvider, BackgroundCompletionStream, BackgroundTaskCompletion,
|
|
BackgroundTaskHandle, BackgroundTaskPortError, BackgroundTaskRunner, BackgroundTaskSpec,
|
|
BackgroundTaskStore, Clock, ContextInjectionPlan, DirEntry, Embedder, EmbedderEnvInspector,
|
|
EmbedderEnvReport, EmbedderError, EmbedderProfileStore, EmbedderPromptDismissal,
|
|
EmbedderPromptStore, EventBus, EventStream, ExitStatus, FileSystem, FsError, GitCommitInfo,
|
|
GitError, GitFileStatus, GitPort, GraphCommit, IdGenerator, IssueNumberAllocator, IssueStore,
|
|
IssueStoreError, LiveStateStore, MemoryError, MemoryQuery, MemoryRecall, MemoryStore,
|
|
ModelArtifactCancel, ModelArtifactDownloader, ModelArtifactProgress, ModelArtifactResolution,
|
|
Output, OutputStream, PermissionStore, PreparedContext, ProcessError, ProcessSpawner,
|
|
ProfileStore, ProjectStore, PtyError, PtyHandle, PtyPort, RemoteError, RemoteHost, RemotePath,
|
|
RuntimeError, ScheduledTask, Scheduler, SpawnSpec, SprintStore, SprintStoreError, StoreError,
|
|
StructuredSessionEnvironment, StructuredSessionEnvironmentPreparer, TemplateStore,
|
|
WindowStateStore,
|
|
};
|