Skip to main content

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}