@team-agent/installer 0.5.56 → 0.5.58
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Cargo.lock +1 -1
- package/Cargo.toml +1 -1
- package/crates/team-agent/src/cli/mod.rs +1 -0
- package/crates/team-agent/src/db/message_store.rs +284 -5
- package/crates/team-agent/src/leader/incident.rs +5 -0
- package/crates/team-agent/src/leader/mod.rs +2 -0
- package/crates/team-agent/src/lifecycle/launch/fork_agent.rs +89 -95
- package/crates/team-agent/src/lifecycle/launch/fork_finalize.rs +104 -0
- package/crates/team-agent/src/lifecycle/launch/fork_pending.rs +109 -0
- package/crates/team-agent/src/lifecycle/launch/fork_state.rs +49 -0
- package/crates/team-agent/src/lifecycle/launch.rs +1 -0
- package/crates/team-agent/src/lifecycle/types.rs +8 -0
- package/crates/team-agent/src/mcp_server/lifecycle_tools/agent_ops.rs +1 -0
- package/crates/team-agent/src/messaging/delivery.rs +7 -39
- package/crates/team-agent/src/messaging/tests/main_preserved.rs +1 -0
- package/crates/team-agent/src/messaging/watchers.rs +33 -16
- package/crates/team-agent/src/provider/session/capture.rs +37 -1
- package/crates/team-agent/src/provider/session/context_fork/claude.rs +85 -0
- package/crates/team-agent/src/provider/session/context_fork/codex.rs +65 -0
- package/crates/team-agent/src/provider/session/context_fork/outcome.rs +138 -0
- package/crates/team-agent/src/provider/session/context_fork.rs +30 -135
- package/crates/team-agent/src/provider/session/mod.rs +2 -1
- package/crates/team-agent/src/provider/session_scan/claude.rs +1 -1
- package/package.json +4 -4
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
use super::*;
|
|
2
|
+
|
|
3
|
+
pub(super) fn verify_codex_fork(
|
|
4
|
+
source_session_id: &SessionId,
|
|
5
|
+
plan: &CommandPlan,
|
|
6
|
+
before: &ContextBackingSnapshot,
|
|
7
|
+
agent_id: &str,
|
|
8
|
+
spawn_cwd: &Path,
|
|
9
|
+
spawned_at: &str,
|
|
10
|
+
deadline: Duration,
|
|
11
|
+
) -> Result<ContextForkProof, ContextForkTermination> {
|
|
12
|
+
let context = crate::provider::session_scan::CaptureSessionContext {
|
|
13
|
+
agent_id: agent_id.to_string(),
|
|
14
|
+
spawn_cwd: spawn_cwd.to_path_buf(),
|
|
15
|
+
pane_id: None,
|
|
16
|
+
pane_pid: None,
|
|
17
|
+
spawned_at: Some(spawned_at.to_string()),
|
|
18
|
+
expected_session_id: plan.expected_session_id.clone(),
|
|
19
|
+
provider_projects_root: plan.provider_projects_root.clone(),
|
|
20
|
+
};
|
|
21
|
+
let excluded = outcome::source_exclusions(before, source_session_id);
|
|
22
|
+
let started = std::time::Instant::now();
|
|
23
|
+
loop {
|
|
24
|
+
let current = jsonl_files(&before.root);
|
|
25
|
+
for candidate in
|
|
26
|
+
crate::provider::session_scan::scan_session_candidates_once(Provider::Codex, &context)?
|
|
27
|
+
{
|
|
28
|
+
let Some(path) = candidate.captured.rollout_path.as_ref() else {
|
|
29
|
+
continue;
|
|
30
|
+
};
|
|
31
|
+
let Some(stamp) = current.get(path.as_path()) else {
|
|
32
|
+
continue;
|
|
33
|
+
};
|
|
34
|
+
let snapshot_changed = before.files.get(path.as_path()) != Some(stamp);
|
|
35
|
+
if !snapshot_changed {
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
let Some(new_session_id) = candidate.captured.session_id else {
|
|
39
|
+
continue;
|
|
40
|
+
};
|
|
41
|
+
if excluded.contains(new_session_id.as_str())
|
|
42
|
+
|| excluded.contains(&path.as_path().to_string_lossy().to_string())
|
|
43
|
+
{
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
return Ok(ContextForkProof {
|
|
47
|
+
provider: Provider::Codex,
|
|
48
|
+
source_session_id: source_session_id.clone(),
|
|
49
|
+
new_session_id,
|
|
50
|
+
backing_path: path.as_path().to_path_buf(),
|
|
51
|
+
captured_via: "context_fork_verified".to_string(),
|
|
52
|
+
attribution_confidence: "high".to_string(),
|
|
53
|
+
managed_backing_root: None,
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
if started.elapsed() >= deadline {
|
|
57
|
+
break;
|
|
58
|
+
}
|
|
59
|
+
std::thread::sleep(Duration::from_millis(50));
|
|
60
|
+
}
|
|
61
|
+
Err(ContextForkTermination::Timeout {
|
|
62
|
+
provider: Provider::Codex,
|
|
63
|
+
deadline_ms: deadline.as_millis(),
|
|
64
|
+
})
|
|
65
|
+
}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
use super::*;
|
|
2
|
+
use std::collections::BTreeSet;
|
|
3
|
+
|
|
4
|
+
pub(super) fn source_exclusions(
|
|
5
|
+
before: &ContextBackingSnapshot,
|
|
6
|
+
source_session_id: &SessionId,
|
|
7
|
+
) -> BTreeSet<String> {
|
|
8
|
+
let mut excluded = BTreeSet::from([source_session_id.as_str().to_string()]);
|
|
9
|
+
for path in before.files.keys() {
|
|
10
|
+
if session_id_from_jsonl(path).as_deref() == Some(source_session_id.as_str()) {
|
|
11
|
+
excluded.insert(path.to_string_lossy().to_string());
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
excluded
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
#[derive(Debug, Clone)]
|
|
18
|
+
pub(crate) struct PendingContextFork {
|
|
19
|
+
pub source_session_id: SessionId,
|
|
20
|
+
pub target_agent: String,
|
|
21
|
+
pub spawned_at: String,
|
|
22
|
+
pub scanner_context: crate::provider::session_scan::CaptureSessionContext,
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
#[derive(Debug)]
|
|
26
|
+
pub(crate) enum ContextForkOutcome {
|
|
27
|
+
Verified(ContextForkProof),
|
|
28
|
+
Pending(PendingContextFork),
|
|
29
|
+
Rejected(ProviderError),
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
33
|
+
pub(crate) enum ContextForkPendingFailure {
|
|
34
|
+
TranscriptMissing,
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
pub(crate) fn transition_pending_context_fork(
|
|
38
|
+
triggered: bool,
|
|
39
|
+
grace_expired: bool,
|
|
40
|
+
) -> Option<ContextForkPendingFailure> {
|
|
41
|
+
(triggered && grace_expired).then_some(ContextForkPendingFailure::TranscriptMissing)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
pub(crate) fn observe_context_fork(
|
|
45
|
+
provider: Provider,
|
|
46
|
+
source_session_id: &SessionId,
|
|
47
|
+
plan: &CommandPlan,
|
|
48
|
+
before: &ContextBackingSnapshot,
|
|
49
|
+
expected_backing_path: Option<&Path>,
|
|
50
|
+
agent_id: &str,
|
|
51
|
+
spawn_cwd: &Path,
|
|
52
|
+
spawned_at: &str,
|
|
53
|
+
deadline: Duration,
|
|
54
|
+
) -> ContextForkOutcome {
|
|
55
|
+
match verify_context_fork(
|
|
56
|
+
provider,
|
|
57
|
+
source_session_id,
|
|
58
|
+
plan,
|
|
59
|
+
before,
|
|
60
|
+
expected_backing_path,
|
|
61
|
+
agent_id,
|
|
62
|
+
spawn_cwd,
|
|
63
|
+
spawned_at,
|
|
64
|
+
deadline,
|
|
65
|
+
) {
|
|
66
|
+
Ok(proof) => ContextForkOutcome::Verified(proof),
|
|
67
|
+
Err(ContextForkTermination::Timeout { .. }) => {
|
|
68
|
+
ContextForkOutcome::Pending(PendingContextFork {
|
|
69
|
+
source_session_id: source_session_id.clone(),
|
|
70
|
+
target_agent: agent_id.to_string(),
|
|
71
|
+
spawned_at: spawned_at.to_string(),
|
|
72
|
+
scanner_context: crate::provider::session_scan::CaptureSessionContext {
|
|
73
|
+
agent_id: agent_id.to_string(),
|
|
74
|
+
spawn_cwd: spawn_cwd.to_path_buf(),
|
|
75
|
+
pane_id: None,
|
|
76
|
+
pane_pid: None,
|
|
77
|
+
spawned_at: Some(spawned_at.to_string()),
|
|
78
|
+
expected_session_id: plan.expected_session_id.clone(),
|
|
79
|
+
provider_projects_root: plan.provider_projects_root.clone(),
|
|
80
|
+
},
|
|
81
|
+
})
|
|
82
|
+
}
|
|
83
|
+
Err(ContextForkTermination::Rejected(error)) => ContextForkOutcome::Rejected(error),
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
#[cfg(test)]
|
|
88
|
+
mod tests {
|
|
89
|
+
use super::*;
|
|
90
|
+
|
|
91
|
+
#[test]
|
|
92
|
+
fn convergence_deadlines_are_provider_specific() {
|
|
93
|
+
assert_eq!(
|
|
94
|
+
context_fork_convergence_deadline(Provider::Claude),
|
|
95
|
+
Duration::from_secs(45)
|
|
96
|
+
);
|
|
97
|
+
assert_eq!(
|
|
98
|
+
context_fork_convergence_deadline(Provider::Codex),
|
|
99
|
+
Duration::from_secs(10)
|
|
100
|
+
);
|
|
101
|
+
assert_eq!(
|
|
102
|
+
context_fork_convergence_deadline(Provider::Copilot),
|
|
103
|
+
Duration::from_secs(5)
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
#[test]
|
|
108
|
+
fn codex_without_new_backing_is_typed_pending() {
|
|
109
|
+
let root =
|
|
110
|
+
std::env::temp_dir().join(format!("ta-codex-fork-pending-{}", std::process::id()));
|
|
111
|
+
let _ = std::fs::remove_dir_all(&root);
|
|
112
|
+
std::fs::create_dir_all(&root).unwrap();
|
|
113
|
+
let plan = CommandPlan {
|
|
114
|
+
argv: Vec::new(),
|
|
115
|
+
expected_session_id: None,
|
|
116
|
+
provider_projects_root: Some(root.clone()),
|
|
117
|
+
managed_mcp_config: false,
|
|
118
|
+
};
|
|
119
|
+
let before = ContextBackingSnapshot::capture(Provider::Codex, &plan);
|
|
120
|
+
let outcome = observe_context_fork(
|
|
121
|
+
Provider::Codex,
|
|
122
|
+
&SessionId::new("source-session"),
|
|
123
|
+
&plan,
|
|
124
|
+
&before,
|
|
125
|
+
None,
|
|
126
|
+
"fork",
|
|
127
|
+
&root,
|
|
128
|
+
"2026-07-24T00:00:00Z",
|
|
129
|
+
Duration::ZERO,
|
|
130
|
+
);
|
|
131
|
+
let ContextForkOutcome::Pending(pending) = outcome else {
|
|
132
|
+
panic!("missing backing must remain a typed pending fork")
|
|
133
|
+
};
|
|
134
|
+
assert_eq!(pending.source_session_id.as_str(), "source-session");
|
|
135
|
+
assert_eq!(pending.target_agent, "fork");
|
|
136
|
+
let _ = std::fs::remove_dir_all(&root);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
@@ -5,7 +5,28 @@ use std::time::{Duration, SystemTime};
|
|
|
5
5
|
use crate::model::enums::Provider;
|
|
6
6
|
use crate::provider::{CommandPlan, ProviderError, SessionId};
|
|
7
7
|
|
|
8
|
+
#[derive(Debug, thiserror::Error)]
|
|
9
|
+
pub(crate) enum ContextForkTermination {
|
|
10
|
+
#[error(
|
|
11
|
+
"context_fork_unverified: {provider:?} produced no readable NEW session backing within {deadline_ms}ms"
|
|
12
|
+
)]
|
|
13
|
+
Timeout {
|
|
14
|
+
provider: Provider,
|
|
15
|
+
deadline_ms: u128,
|
|
16
|
+
},
|
|
17
|
+
#[error(transparent)]
|
|
18
|
+
Rejected(#[from] ProviderError),
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
mod claude;
|
|
22
|
+
mod codex;
|
|
23
|
+
mod outcome;
|
|
24
|
+
pub(crate) use outcome::{
|
|
25
|
+
observe_context_fork, transition_pending_context_fork, ContextForkOutcome, PendingContextFork,
|
|
26
|
+
};
|
|
27
|
+
|
|
8
28
|
pub(crate) fn context_fork_convergence_deadline(provider: Provider) -> Duration {
|
|
29
|
+
// Expiration is consumed by ContextForkOutcome::Pending(PendingContextFork).
|
|
9
30
|
match provider {
|
|
10
31
|
Provider::Claude | Provider::ClaudeCode => Duration::from_secs(45),
|
|
11
32
|
Provider::Codex => Duration::from_secs(10),
|
|
@@ -54,12 +75,12 @@ pub(crate) fn verify_context_fork(
|
|
|
54
75
|
spawn_cwd: &Path,
|
|
55
76
|
spawned_at: &str,
|
|
56
77
|
deadline: Duration,
|
|
57
|
-
) -> Result<ContextForkProof,
|
|
78
|
+
) -> Result<ContextForkProof, ContextForkTermination> {
|
|
58
79
|
if provider == Provider::Copilot {
|
|
59
|
-
return verify_copilot_fork(source_session_id, plan);
|
|
80
|
+
return verify_copilot_fork(source_session_id, plan).map_err(Into::into);
|
|
60
81
|
}
|
|
61
82
|
if provider == Provider::Codex {
|
|
62
|
-
return verify_codex_fork(
|
|
83
|
+
return codex::verify_codex_fork(
|
|
63
84
|
source_session_id,
|
|
64
85
|
plan,
|
|
65
86
|
before,
|
|
@@ -70,132 +91,20 @@ pub(crate) fn verify_context_fork(
|
|
|
70
91
|
);
|
|
71
92
|
}
|
|
72
93
|
if matches!(provider, Provider::Claude | Provider::ClaudeCode) {
|
|
73
|
-
return verify_claude_fork(
|
|
94
|
+
return claude::verify_claude_fork(
|
|
74
95
|
provider,
|
|
75
96
|
source_session_id,
|
|
76
97
|
plan,
|
|
77
98
|
before,
|
|
78
99
|
expected_backing_path,
|
|
100
|
+
spawn_cwd,
|
|
79
101
|
deadline,
|
|
80
102
|
);
|
|
81
103
|
}
|
|
82
104
|
Err(ProviderError::CaptureFailed(format!(
|
|
83
105
|
"context_fork_unverified: {provider:?} has no verifiable fork backing"
|
|
84
|
-
))
|
|
85
|
-
|
|
86
|
-
fn verify_claude_fork(
|
|
87
|
-
provider: Provider,
|
|
88
|
-
source_session_id: &SessionId,
|
|
89
|
-
plan: &CommandPlan,
|
|
90
|
-
before: &ContextBackingSnapshot,
|
|
91
|
-
expected_backing_path: Option<&Path>,
|
|
92
|
-
deadline: Duration,
|
|
93
|
-
) -> Result<ContextForkProof, ProviderError> {
|
|
94
|
-
let expected = plan.expected_session_id.as_ref().ok_or_else(|| {
|
|
95
|
-
ProviderError::CaptureFailed(
|
|
96
|
-
"context_fork_unverified: Claude plan has no expected session id".to_string(),
|
|
97
|
-
)
|
|
98
|
-
})?;
|
|
99
|
-
let path = expected_backing_path.ok_or_else(|| {
|
|
100
|
-
ProviderError::CaptureFailed(
|
|
101
|
-
"context_fork_unverified: Claude plan has no exact snapshot backing".to_string(),
|
|
102
|
-
)
|
|
103
|
-
})?;
|
|
104
|
-
let expected_name = format!("{}.jsonl", expected.as_str());
|
|
105
|
-
if path.file_name().and_then(|name| name.to_str()) != Some(expected_name.as_str()) {
|
|
106
|
-
return Err(ProviderError::CaptureFailed(format!(
|
|
107
|
-
"context_fork_unverified: Claude snapshot backing does not match expected session {}",
|
|
108
|
-
expected.as_str()
|
|
109
|
-
)));
|
|
110
|
-
}
|
|
111
|
-
let started = std::time::Instant::now();
|
|
112
|
-
loop {
|
|
113
|
-
if let Some(stamp) = file_stamp(path) {
|
|
114
|
-
let changed = before.files.get(path).is_none_or(|old| *old != stamp);
|
|
115
|
-
let observed_matches =
|
|
116
|
-
session_id_from_jsonl(path).is_none_or(|observed| observed == expected.as_str());
|
|
117
|
-
if changed && readable_jsonl(path) && observed_matches && expected != source_session_id
|
|
118
|
-
{
|
|
119
|
-
return Ok(ContextForkProof {
|
|
120
|
-
provider,
|
|
121
|
-
source_session_id: source_session_id.clone(),
|
|
122
|
-
new_session_id: expected.clone(),
|
|
123
|
-
backing_path: path.to_path_buf(),
|
|
124
|
-
captured_via: "context_fork_verified".to_string(),
|
|
125
|
-
attribution_confidence: "high".to_string(),
|
|
126
|
-
managed_backing_root: None,
|
|
127
|
-
});
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
if started.elapsed() >= deadline {
|
|
131
|
-
break;
|
|
132
|
-
}
|
|
133
|
-
std::thread::sleep(Duration::from_millis(50));
|
|
134
|
-
}
|
|
135
|
-
Err(ProviderError::CaptureFailed(format!(
|
|
136
|
-
"context_fork_unverified: {provider:?} produced no readable NEW session backing within {}ms",
|
|
137
|
-
deadline.as_millis()
|
|
138
|
-
)))
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
fn verify_codex_fork(
|
|
142
|
-
source_session_id: &SessionId,
|
|
143
|
-
plan: &CommandPlan,
|
|
144
|
-
before: &ContextBackingSnapshot,
|
|
145
|
-
agent_id: &str,
|
|
146
|
-
spawn_cwd: &Path,
|
|
147
|
-
spawned_at: &str,
|
|
148
|
-
deadline: Duration,
|
|
149
|
-
) -> Result<ContextForkProof, ProviderError> {
|
|
150
|
-
let context = crate::provider::session_scan::CaptureSessionContext {
|
|
151
|
-
agent_id: agent_id.to_string(),
|
|
152
|
-
spawn_cwd: spawn_cwd.to_path_buf(),
|
|
153
|
-
pane_id: None,
|
|
154
|
-
pane_pid: None,
|
|
155
|
-
spawned_at: Some(spawned_at.to_string()),
|
|
156
|
-
expected_session_id: plan.expected_session_id.clone(),
|
|
157
|
-
provider_projects_root: plan.provider_projects_root.clone(),
|
|
158
|
-
};
|
|
159
|
-
let started = std::time::Instant::now();
|
|
160
|
-
loop {
|
|
161
|
-
let current = jsonl_files(&before.root);
|
|
162
|
-
for candidate in
|
|
163
|
-
crate::provider::session_scan::scan_session_candidates_once(Provider::Codex, &context)?
|
|
164
|
-
{
|
|
165
|
-
let Some(path) = candidate.captured.rollout_path.as_ref() else {
|
|
166
|
-
continue;
|
|
167
|
-
};
|
|
168
|
-
let Some(stamp) = current.get(path.as_path()) else {
|
|
169
|
-
continue;
|
|
170
|
-
};
|
|
171
|
-
if before.files.get(path.as_path()) == Some(stamp) {
|
|
172
|
-
continue;
|
|
173
|
-
}
|
|
174
|
-
let Some(new_session_id) = candidate.captured.session_id else {
|
|
175
|
-
continue;
|
|
176
|
-
};
|
|
177
|
-
if new_session_id == *source_session_id {
|
|
178
|
-
continue;
|
|
179
|
-
}
|
|
180
|
-
return Ok(ContextForkProof {
|
|
181
|
-
provider: Provider::Codex,
|
|
182
|
-
source_session_id: source_session_id.clone(),
|
|
183
|
-
new_session_id,
|
|
184
|
-
backing_path: path.as_path().to_path_buf(),
|
|
185
|
-
captured_via: "context_fork_verified".to_string(),
|
|
186
|
-
attribution_confidence: "high".to_string(),
|
|
187
|
-
managed_backing_root: None,
|
|
188
|
-
});
|
|
189
|
-
}
|
|
190
|
-
if started.elapsed() >= deadline {
|
|
191
|
-
break;
|
|
192
|
-
}
|
|
193
|
-
std::thread::sleep(Duration::from_millis(50));
|
|
194
|
-
}
|
|
195
|
-
Err(ProviderError::CaptureFailed(format!(
|
|
196
|
-
"context_fork_unverified: Codex produced no readable NEW session backing within {}ms",
|
|
197
|
-
deadline.as_millis()
|
|
198
|
-
)))
|
|
106
|
+
))
|
|
107
|
+
.into())
|
|
199
108
|
}
|
|
200
109
|
|
|
201
110
|
fn verify_copilot_fork(
|
|
@@ -242,6 +151,8 @@ fn verify_copilot_fork(
|
|
|
242
151
|
"context_fork_unverified: copilot NEW session is absent from session-store".to_string(),
|
|
243
152
|
));
|
|
244
153
|
}
|
|
154
|
+
// Copilot's isolated database row is its synchronous fork proof; the
|
|
155
|
+
// pre-spawn materialization baseline is never accepted by transcript scan.
|
|
245
156
|
Ok(ContextForkProof {
|
|
246
157
|
provider: Provider::Copilot,
|
|
247
158
|
source_session_id: source_session_id.clone(),
|
|
@@ -335,22 +246,6 @@ mod tests {
|
|
|
335
246
|
use super::*;
|
|
336
247
|
use std::io::Write;
|
|
337
248
|
|
|
338
|
-
#[test]
|
|
339
|
-
fn context_fork_deadlines_are_provider_specific() {
|
|
340
|
-
assert_eq!(
|
|
341
|
-
context_fork_convergence_deadline(Provider::Claude),
|
|
342
|
-
Duration::from_secs(45)
|
|
343
|
-
);
|
|
344
|
-
assert_eq!(
|
|
345
|
-
context_fork_convergence_deadline(Provider::Codex),
|
|
346
|
-
Duration::from_secs(10)
|
|
347
|
-
);
|
|
348
|
-
assert_eq!(
|
|
349
|
-
context_fork_convergence_deadline(Provider::Copilot),
|
|
350
|
-
Duration::from_secs(5)
|
|
351
|
-
);
|
|
352
|
-
}
|
|
353
|
-
|
|
354
249
|
#[test]
|
|
355
250
|
fn codex_fork_proof_ignores_changed_stale_and_foreign_rollouts() {
|
|
356
251
|
let root =
|
|
@@ -10,7 +10,8 @@ pub mod resume;
|
|
|
10
10
|
|
|
11
11
|
pub use context_fork::ContextForkProof;
|
|
12
12
|
pub(crate) use context_fork::{
|
|
13
|
-
context_fork_convergence_deadline,
|
|
13
|
+
context_fork_convergence_deadline, observe_context_fork, transition_pending_context_fork,
|
|
14
|
+
ContextBackingSnapshot, ContextForkOutcome, PendingContextFork,
|
|
14
15
|
};
|
|
15
16
|
|
|
16
17
|
pub use resume::{
|
|
@@ -5,7 +5,7 @@ use crate::provider::Provider;
|
|
|
5
5
|
|
|
6
6
|
use super::{CaptureSessionContext, CapturedSessionCandidate};
|
|
7
7
|
|
|
8
|
-
pub(
|
|
8
|
+
pub(crate) fn projects_dir_for_cwd(home: &Path, spawn_cwd: &Path) -> Option<PathBuf> {
|
|
9
9
|
let canonical = std::fs::canonicalize(spawn_cwd).unwrap_or_else(|_| spawn_cwd.to_path_buf());
|
|
10
10
|
let encoded = encode_projects_dir(&canonical.to_string_lossy());
|
|
11
11
|
if encoded.is_empty() {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@team-agent/installer",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.58",
|
|
4
4
|
"description": "npx installer for Team Agent",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"codex",
|
|
@@ -20,9 +20,9 @@
|
|
|
20
20
|
"team-agent-installer": "npm/install.mjs"
|
|
21
21
|
},
|
|
22
22
|
"optionalDependencies": {
|
|
23
|
-
"@team-agent/cli-darwin-arm64": "0.5.
|
|
24
|
-
"@team-agent/cli-darwin-x64": "0.5.
|
|
25
|
-
"@team-agent/cli-linux-x64": "0.5.
|
|
23
|
+
"@team-agent/cli-darwin-arm64": "0.5.58",
|
|
24
|
+
"@team-agent/cli-darwin-x64": "0.5.58",
|
|
25
|
+
"@team-agent/cli-linux-x64": "0.5.58"
|
|
26
26
|
},
|
|
27
27
|
"scripts": {
|
|
28
28
|
"postinstall": "node npm/bincheck.mjs",
|