nyx_agent_core/run/workspace.rs
1//! Per-run ownership handle around an [`IngestedRepo`].
2//!
3//! Local-path snapshots install a drop hook on the [`IngestedRepo`]
4//! that removes the snapshot directory; the dispatcher and any
5//! downstream consumer (sandbox, chain reasoning) must keep the same
6//! handle alive so the snapshot survives until end-of-run rather than
7//! being re-snapshotted per stage. `WorkspaceHandle` is that owner.
8
9use std::path::Path;
10use std::sync::Arc;
11
12use crate::repo::{IngestedRepo, RepoSource, SnapshotBackend};
13
14/// Run-scoped, cheaply clonable handle to an ingested repo workspace.
15///
16/// The inner [`IngestedRepo`] is held inside an `Arc`; cloning the
17/// handle bumps the refcount and never re-snapshots. The original
18/// snapshot is removed only when the last handle drops.
19#[derive(Clone, Debug)]
20pub struct WorkspaceHandle {
21 inner: Arc<IngestedRepo>,
22}
23
24impl WorkspaceHandle {
25 pub fn new(ingested: IngestedRepo) -> Self {
26 Self { inner: Arc::new(ingested) }
27 }
28
29 /// Build a synthetic handle pointing at `path`, with no cleanup
30 /// hook attached. Intended for binary / integration tests that
31 /// need to fan out per-repo work without going through `ingest`.
32 /// Production code paths always go through [`crate::repo::ingest`] +
33 /// [`WorkspaceHandle::new`].
34 #[cfg(any(test, feature = "test-util"))]
35 pub fn for_local_path_test(
36 name: impl Into<String>,
37 path: impl Into<std::path::PathBuf>,
38 ) -> Self {
39 let path: std::path::PathBuf = path.into();
40 let ingested = IngestedRepo {
41 name: name.into(),
42 workspace: path.clone(),
43 source: RepoSource::LocalPath { path },
44 snapshot_backend: None,
45 on_disk_git_remote: None,
46 cleanup: None,
47 };
48 Self::new(ingested)
49 }
50
51 pub fn name(&self) -> &str {
52 &self.inner.name
53 }
54
55 pub fn workspace(&self) -> &Path {
56 &self.inner.workspace
57 }
58
59 pub fn source(&self) -> &RepoSource {
60 &self.inner.source
61 }
62
63 pub fn snapshot_backend(&self) -> Option<SnapshotBackend> {
64 self.inner.snapshot_backend
65 }
66
67 pub fn on_disk_git_remote(&self) -> Option<&str> {
68 self.inner.on_disk_git_remote.as_deref()
69 }
70}