@team-agent/installer 0.5.41 → 0.5.43
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/adapters.rs +129 -54
- package/crates/team-agent/src/cli/diagnose.rs +1 -2
- package/crates/team-agent/src/cli/emit.rs +1 -7
- package/crates/team-agent/src/cli/helpers.rs +3 -1
- package/crates/team-agent/src/cli/leader.rs +2 -1
- package/crates/team-agent/src/cli/mod.rs +27 -7
- package/crates/team-agent/src/cli/named_address.rs +14 -5
- package/crates/team-agent/src/cli/profile.rs +19 -7
- package/crates/team-agent/src/cli/send.rs +9 -3
- package/crates/team-agent/src/cli/status.rs +8 -30
- package/crates/team-agent/src/cli/status_port.rs +1341 -1272
- package/crates/team-agent/src/cli/tests/base.rs +738 -660
- package/crates/team-agent/src/cli/tests/compile.rs +45 -18
- package/crates/team-agent/src/cli/tests/divergence.rs +462 -444
- package/crates/team-agent/src/cli/tests/lane_c.rs +365 -282
- package/crates/team-agent/src/cli/tests/leader_watch.rs +356 -329
- package/crates/team-agent/src/cli/tests/main_preserved.rs +672 -564
- package/crates/team-agent/src/cli/tests/missing_subcommands.rs +284 -224
- package/crates/team-agent/src/cli/tests/mod.rs +17 -7
- package/crates/team-agent/src/cli/tests/named_address.rs +8 -2
- package/crates/team-agent/src/cli/tests/peer_allow.rs +10 -2
- package/crates/team-agent/src/cli/tests/run_delegation.rs +314 -273
- package/crates/team-agent/src/cli/tests/shutdown_kill_plan.rs +26 -15
- package/crates/team-agent/src/cli/tests/status_send.rs +707 -629
- package/crates/team-agent/src/cli/tests/verb_install_skill.rs +20 -4
- package/crates/team-agent/src/cli/tests/verb_profile.rs +46 -17
- package/crates/team-agent/src/cli/tests/verb_validate.rs +15 -3
- package/crates/team-agent/src/codex_app_server.rs +2 -5
- package/crates/team-agent/src/compiler/tests.rs +139 -33
- package/crates/team-agent/src/compiler.rs +55 -22
- package/crates/team-agent/src/conpty/backend.rs +23 -33
- package/crates/team-agent/src/coordinator/backoff.rs +2 -7
- package/crates/team-agent/src/coordinator/conpty_shim.rs +55 -67
- package/crates/team-agent/src/coordinator/health.rs +46 -31
- package/crates/team-agent/src/coordinator/mod.rs +3 -3
- package/crates/team-agent/src/coordinator/orphan.rs +22 -10
- package/crates/team-agent/src/coordinator/steps/abnormal.rs +47 -52
- package/crates/team-agent/src/coordinator/tests/abnormal.rs +55 -19
- package/crates/team-agent/src/coordinator/tests/basics.rs +179 -41
- package/crates/team-agent/src/coordinator/tests/daemon.rs +53 -13
- package/crates/team-agent/src/coordinator/tests/health_sync.rs +78 -19
- package/crates/team-agent/src/coordinator/tests/main_preserved.rs +61 -11
- package/crates/team-agent/src/coordinator/tests/mod.rs +33 -39
- package/crates/team-agent/src/coordinator/tests/spine.rs +52 -12
- package/crates/team-agent/src/coordinator/tests/takeover.rs +73 -15
- package/crates/team-agent/src/coordinator/tests/tick_core.rs +50 -15
- package/crates/team-agent/src/coordinator/tests/watch.rs +74 -20
- package/crates/team-agent/src/coordinator/tick.rs +19 -1
- package/crates/team-agent/src/db/message_store.rs +138 -30
- package/crates/team-agent/src/db/migration.rs +249 -61
- package/crates/team-agent/src/db/schema.rs +303 -82
- package/crates/team-agent/src/diagnose/comms.rs +9 -2
- package/crates/team-agent/src/diagnose/mod.rs +1 -3
- package/crates/team-agent/src/diagnose/orphans.rs +79 -61
- package/crates/team-agent/src/event_log.rs +70 -16
- package/crates/team-agent/src/layout/manager.rs +15 -4
- package/crates/team-agent/src/layout/mod.rs +4 -4
- package/crates/team-agent/src/layout/overlay.rs +10 -3
- package/crates/team-agent/src/layout/placement.rs +5 -1
- package/crates/team-agent/src/layout/recovery.rs +4 -2
- package/crates/team-agent/src/layout/runtime_sessions.rs +7 -7
- package/crates/team-agent/src/layout/sessions.rs +17 -9
- package/crates/team-agent/src/layout/tmux_endpoint.rs +1 -1
- package/crates/team-agent/src/layout/worker_env.rs +52 -19
- package/crates/team-agent/src/leader/helpers.rs +7 -1
- package/crates/team-agent/src/leader/lease.rs +195 -82
- package/crates/team-agent/src/leader/owner_bind.rs +55 -22
- package/crates/team-agent/src/leader/rediscover/tests.rs +88 -24
- package/crates/team-agent/src/leader/rediscover.rs +74 -25
- package/crates/team-agent/src/leader/start.rs +75 -54
- package/crates/team-agent/src/leader/takeover.rs +46 -11
- package/crates/team-agent/src/leader/tests/basics.rs +320 -167
- package/crates/team-agent/src/leader/tests/byte_findings.rs +361 -219
- package/crates/team-agent/src/leader/tests/identity.rs +428 -356
- package/crates/team-agent/src/leader/tests/idle.rs +285 -254
- package/crates/team-agent/src/leader/tests/lease_api.rs +338 -274
- package/crates/team-agent/src/leader/tests/lease_claim.rs +643 -593
- package/crates/team-agent/src/leader/tests/mod.rs +115 -99
- package/crates/team-agent/src/leader/tests/rediscover.rs +74 -22
- package/crates/team-agent/src/leader/tests/wake_start_owner.rs +237 -211
- package/crates/team-agent/src/lib.rs +4 -4
- package/crates/team-agent/src/lifecycle/display.rs +7 -3
- package/crates/team-agent/src/lifecycle/launch.rs +6 -1
- package/crates/team-agent/src/lifecycle/mod.rs +9 -1
- package/crates/team-agent/src/lifecycle/profile_launch.rs +77 -34
- package/crates/team-agent/src/lifecycle/profile_smoke.rs +3 -1
- package/crates/team-agent/src/lifecycle/restart/agent.rs +1 -6
- package/crates/team-agent/src/lifecycle/restart/orchestrator.rs +1 -4
- package/crates/team-agent/src/lifecycle/restart/preflight.rs +6 -5
- package/crates/team-agent/src/lifecycle/restart/rebuild.rs +26 -22
- package/crates/team-agent/src/lifecycle/restart/remove.rs +45 -35
- package/crates/team-agent/src/lifecycle/restart/team_state.rs +63 -17
- package/crates/team-agent/src/lifecycle/tests/agent_ops.rs +251 -84
- package/crates/team-agent/src/lifecycle/tests/lane_ops.rs +198 -48
- package/crates/team-agent/src/lifecycle/tests/launch_spawn.rs +2 -1
- package/crates/team-agent/src/lifecycle/tests/main_preserved.rs +152 -32
- package/crates/team-agent/src/lifecycle/tests/phase_b_contracts.rs +1 -5
- package/crates/team-agent/src/lifecycle/tests.rs +2 -2
- package/crates/team-agent/src/main.rs +4 -4
- package/crates/team-agent/src/mcp_server/lifecycle_tools/agent_ops.rs +47 -20
- package/crates/team-agent/src/mcp_server/mod.rs +11 -2
- package/crates/team-agent/src/mcp_server/types.rs +14 -3
- package/crates/team-agent/src/mcp_server/wire.rs +230 -68
- package/crates/team-agent/src/messaging/delivery.rs +20 -18
- package/crates/team-agent/src/messaging/helpers.rs +25 -4
- package/crates/team-agent/src/messaging/leader_receiver.rs +4 -5
- package/crates/team-agent/src/messaging/mod.rs +2 -3
- package/crates/team-agent/src/messaging/selftest.rs +46 -26
- package/crates/team-agent/src/messaging/tests/main_preserved.rs +47 -12
- package/crates/team-agent/src/messaging/tests/runtime.rs +57 -22
- package/crates/team-agent/src/messaging/tests/spine.rs +154 -40
- package/crates/team-agent/src/messaging/tests/wave2.rs +31 -32
- package/crates/team-agent/src/messaging/trust.rs +25 -2
- package/crates/team-agent/src/messaging/watchers.rs +37 -9
- package/crates/team-agent/src/model/enums.rs +65 -16
- package/crates/team-agent/src/model/ids.rs +12 -3
- package/crates/team-agent/src/model/paths.rs +28 -7
- package/crates/team-agent/src/model/permissions.rs +176 -33
- package/crates/team-agent/src/model/routing.rs +66 -20
- package/crates/team-agent/src/model/spec.rs +365 -69
- package/crates/team-agent/src/model/task_graph.rs +36 -9
- package/crates/team-agent/src/model/yaml/tests.rs +24 -6
- package/crates/team-agent/src/model/yaml.rs +7 -6
- package/crates/team-agent/src/packaging/install.rs +23 -9
- package/crates/team-agent/src/packaging/migrate.rs +5 -7
- package/crates/team-agent/src/packaging/mod.rs +9 -1
- package/crates/team-agent/src/packaging/repair.rs +13 -6
- package/crates/team-agent/src/packaging/tests.rs +63 -16
- package/crates/team-agent/src/packaging/types.rs +22 -7
- package/crates/team-agent/src/platform/argv.rs +4 -1
- package/crates/team-agent/src/platform/file_lock.rs +22 -8
- package/crates/team-agent/src/platform/process.rs +21 -22
- package/crates/team-agent/src/provider/adapters/claude.rs +1 -3
- package/crates/team-agent/src/provider/approvals/parsing.rs +134 -26
- package/crates/team-agent/src/provider/approvals/runtime_prompts.rs +13 -3
- package/crates/team-agent/src/provider/classify.rs +127 -42
- package/crates/team-agent/src/provider/faults.rs +17 -5
- package/crates/team-agent/src/provider/helpers.rs +6 -5
- package/crates/team-agent/src/provider/startup_prompt.rs +75 -27
- package/crates/team-agent/src/state/repository.rs +27 -14
- package/crates/team-agent/src/tmux_backend/tests.rs +1637 -1398
- package/crates/team-agent/src/tmux_backend.rs +80 -44
- package/crates/team-agent/src/topology.rs +27 -20
- package/crates/team-agent/src/transport/test_support.rs +20 -23
- package/crates/team-agent/src/transport/tests/behavior.rs +292 -293
- package/crates/team-agent/src/transport/tests/mod.rs +178 -187
- package/crates/team-agent/src/transport/tests/wire.rs +561 -525
- package/crates/team-agent/src/transport.rs +12 -17
- package/crates/team-agent/src/transport_factory.rs +29 -14
- package/package.json +4 -4
|
@@ -38,7 +38,9 @@ pub(crate) fn claude_explicit_error_fact(record: &serde_json::Value) -> Option<F
|
|
|
38
38
|
FactKind::Error,
|
|
39
39
|
)
|
|
40
40
|
.with_api_error_details(
|
|
41
|
-
record
|
|
41
|
+
record
|
|
42
|
+
.get("apiErrorStatus")
|
|
43
|
+
.and_then(serde_json::Value::as_i64),
|
|
42
44
|
non_empty_string_field(record, "error"),
|
|
43
45
|
non_empty_string_field(record, "requestId"),
|
|
44
46
|
non_empty_string_field(record, "uuid"),
|
|
@@ -58,7 +60,9 @@ fn codex_explicit_error_fact(record: &serde_json::Value) -> Option<FaultFact> {
|
|
|
58
60
|
}
|
|
59
61
|
Some(FaultFact::new(
|
|
60
62
|
Signature::new("turn_failed"),
|
|
61
|
-
turn.get("id")
|
|
63
|
+
turn.get("id")
|
|
64
|
+
.and_then(serde_json::Value::as_str)
|
|
65
|
+
.map(TurnId::new),
|
|
62
66
|
FactKind::Failed,
|
|
63
67
|
))
|
|
64
68
|
}
|
|
@@ -126,8 +130,14 @@ fn claude_record_is_assistant_api_error(record: &serde_json::Value) -> bool {
|
|
|
126
130
|
.and_then(|message| message.get("role"))
|
|
127
131
|
.and_then(serde_json::Value::as_str)
|
|
128
132
|
== Some("assistant")
|
|
129
|
-
&& record
|
|
130
|
-
|
|
133
|
+
&& record
|
|
134
|
+
.get("isApiErrorMessage")
|
|
135
|
+
.and_then(serde_json::Value::as_bool)
|
|
136
|
+
== Some(true)
|
|
137
|
+
&& (record
|
|
138
|
+
.get("apiErrorStatus")
|
|
139
|
+
.and_then(serde_json::Value::as_i64)
|
|
140
|
+
.is_some()
|
|
131
141
|
|| non_empty_string_field(record, "error").is_some()
|
|
132
142
|
|| non_empty_string_field(record, "requestId").is_some())
|
|
133
143
|
}
|
|
@@ -156,7 +166,9 @@ fn codex_fault_fact(record: &serde_json::Value) -> Option<FaultFact> {
|
|
|
156
166
|
if turn.get("status").and_then(serde_json::Value::as_str) == Some("failed") {
|
|
157
167
|
return Some(FaultFact::new(
|
|
158
168
|
Signature::new("turn_failed"),
|
|
159
|
-
turn.get("id")
|
|
169
|
+
turn.get("id")
|
|
170
|
+
.and_then(serde_json::Value::as_str)
|
|
171
|
+
.map(TurnId::new),
|
|
160
172
|
FactKind::Failed,
|
|
161
173
|
));
|
|
162
174
|
}
|
|
@@ -22,10 +22,7 @@ pub(crate) fn find_session_id(record: &serde_json::Value) -> Option<String> {
|
|
|
22
22
|
if let Some(s) = record.get("sessionId").and_then(serde_json::Value::as_str) {
|
|
23
23
|
return Some(s.to_string());
|
|
24
24
|
}
|
|
25
|
-
if let Some(s) = record
|
|
26
|
-
.get("session_id")
|
|
27
|
-
.and_then(serde_json::Value::as_str)
|
|
28
|
-
{
|
|
25
|
+
if let Some(s) = record.get("session_id").and_then(serde_json::Value::as_str) {
|
|
29
26
|
return Some(s.to_string());
|
|
30
27
|
}
|
|
31
28
|
record
|
|
@@ -37,7 +34,11 @@ pub(crate) fn find_session_id(record: &serde_json::Value) -> Option<String> {
|
|
|
37
34
|
.map(ToString::to_string)
|
|
38
35
|
}
|
|
39
36
|
|
|
40
|
-
pub(crate) fn patterns(
|
|
37
|
+
pub(crate) fn patterns(
|
|
38
|
+
idle: &str,
|
|
39
|
+
processing: &str,
|
|
40
|
+
error: &str,
|
|
41
|
+
) -> Result<StatusPatterns, ProviderError> {
|
|
41
42
|
Ok(StatusPatterns {
|
|
42
43
|
idle: compile_regex(idle)?,
|
|
43
44
|
processing: compile_regex(processing)?,
|
|
@@ -28,10 +28,8 @@ const CLAUDE_TRUST_MARKERS: &[&str] = &[
|
|
|
28
28
|
"Enter to confirm",
|
|
29
29
|
];
|
|
30
30
|
const CLAUDE_READY_MARKERS: &[&str] = &["Claude Code"];
|
|
31
|
-
pub const COPILOT_TRUST_PROMPT_MARKER: &str =
|
|
32
|
-
|
|
33
|
-
pub const COPILOT_READY_MARKER: &str =
|
|
34
|
-
include_str!("testdata/copilot-ready-marker.txt");
|
|
31
|
+
pub const COPILOT_TRUST_PROMPT_MARKER: &str = include_str!("testdata/copilot-trust-prompt.txt");
|
|
32
|
+
pub const COPILOT_READY_MARKER: &str = include_str!("testdata/copilot-ready-marker.txt");
|
|
35
33
|
const COPILOT_TRUST_MARKERS: &[&str] = &[COPILOT_TRUST_PROMPT_MARKER];
|
|
36
34
|
const COPILOT_READY_MARKERS: &[&str] = &[COPILOT_READY_MARKER];
|
|
37
35
|
const COPILOT_TRUST_TITLE: &str = "Confirm folder trust";
|
|
@@ -173,13 +171,9 @@ fn has_active_claude_yes_trust_shape(output: &str) -> bool {
|
|
|
173
171
|
{
|
|
174
172
|
return false;
|
|
175
173
|
}
|
|
176
|
-
output
|
|
177
|
-
.
|
|
178
|
-
|
|
179
|
-
.any(|line| {
|
|
180
|
-
line == "❯ 1. Yes, I trust this folder"
|
|
181
|
-
|| line == "> 1. Yes, I trust this folder"
|
|
182
|
-
})
|
|
174
|
+
output.lines().map(str::trim_start).any(|line| {
|
|
175
|
+
line == "❯ 1. Yes, I trust this folder" || line == "> 1. Yes, I trust this folder"
|
|
176
|
+
})
|
|
183
177
|
}
|
|
184
178
|
|
|
185
179
|
fn has_claude_ready_shape(output: &str) -> bool {
|
|
@@ -352,7 +346,10 @@ pub fn codex_handle_startup_prompts(
|
|
|
352
346
|
StartupScreenDecision::KeepPolling => sleep_between_polls(sleep_s),
|
|
353
347
|
}
|
|
354
348
|
}
|
|
355
|
-
StartupPromptOutcome {
|
|
349
|
+
StartupPromptOutcome {
|
|
350
|
+
handled,
|
|
351
|
+
capture_error,
|
|
352
|
+
}
|
|
356
353
|
}
|
|
357
354
|
|
|
358
355
|
pub fn claude_handle_startup_prompts(
|
|
@@ -386,7 +383,10 @@ pub fn claude_handle_startup_prompts(
|
|
|
386
383
|
}
|
|
387
384
|
}
|
|
388
385
|
}
|
|
389
|
-
StartupPromptOutcome {
|
|
386
|
+
StartupPromptOutcome {
|
|
387
|
+
handled,
|
|
388
|
+
capture_error,
|
|
389
|
+
}
|
|
390
390
|
}
|
|
391
391
|
|
|
392
392
|
pub fn copilot_handle_startup_prompts(
|
|
@@ -420,11 +420,17 @@ pub fn copilot_handle_startup_prompts(
|
|
|
420
420
|
}
|
|
421
421
|
}
|
|
422
422
|
}
|
|
423
|
-
StartupPromptOutcome {
|
|
423
|
+
StartupPromptOutcome {
|
|
424
|
+
handled,
|
|
425
|
+
capture_error,
|
|
426
|
+
}
|
|
424
427
|
}
|
|
425
428
|
|
|
426
429
|
fn max_rfind(output: &str, needles: &[&str]) -> Option<usize> {
|
|
427
|
-
needles
|
|
430
|
+
needles
|
|
431
|
+
.iter()
|
|
432
|
+
.filter_map(|needle| output.rfind(needle))
|
|
433
|
+
.max()
|
|
428
434
|
}
|
|
429
435
|
|
|
430
436
|
fn is_more_recent(prompt_pos: Option<usize>, ready_pos: Option<usize>) -> bool {
|
|
@@ -449,8 +455,8 @@ mod tests {
|
|
|
449
455
|
use crate::model::enums::PaneLiveness;
|
|
450
456
|
use crate::transport::{
|
|
451
457
|
AttachOutcome, BackendKind, CaptureRange, CapturedText, InjectPayload, InjectReport, Key,
|
|
452
|
-
PaneField, PaneId, PaneInfo, SessionName, SetEnvOutcome, SpawnResult, Target,
|
|
453
|
-
WindowName,
|
|
458
|
+
PaneField, PaneId, PaneInfo, SessionName, SetEnvOutcome, SpawnResult, Target,
|
|
459
|
+
TransportError, WindowName,
|
|
454
460
|
};
|
|
455
461
|
use std::collections::BTreeMap;
|
|
456
462
|
use std::path::Path;
|
|
@@ -483,7 +489,8 @@ mod tests {
|
|
|
483
489
|
fn stale_trust_above_ready_is_not_answered_ready_wins() {
|
|
484
490
|
// trust prompt FIRST, then a ready marker LATER => trust_pos < ready_pos => do NOT answer.
|
|
485
491
|
// This is the positional-recency命门 a naive substring port gets wrong (would re-send Enter).
|
|
486
|
-
let screen =
|
|
492
|
+
let screen =
|
|
493
|
+
format!("{TRUST_DIR}\n[trusted earlier]\n{READY_BANNER} ready\n{READY_PROMPT} ");
|
|
487
494
|
assert_eq!(
|
|
488
495
|
classify_codex_startup_screen(&screen),
|
|
489
496
|
StartupScreenDecision::Ready,
|
|
@@ -519,7 +526,10 @@ mod tests {
|
|
|
519
526
|
#[test]
|
|
520
527
|
fn stale_update_above_ready_is_not_skipped_ready_wins() {
|
|
521
528
|
let screen = format!("{UPDATE_AVAIL}\n{READY_BANNER}\n{READY_PROMPT} ");
|
|
522
|
-
assert_eq!(
|
|
529
|
+
assert_eq!(
|
|
530
|
+
classify_codex_startup_screen(&screen),
|
|
531
|
+
StartupScreenDecision::Ready
|
|
532
|
+
);
|
|
523
533
|
}
|
|
524
534
|
|
|
525
535
|
// ── golden ORDER — update is checked BEFORE trust (both more recent) -> SkipUpdatePrompt wins ─────
|
|
@@ -528,7 +538,10 @@ mod tests {
|
|
|
528
538
|
// both update + trust appear after the ready marker; golden runs maybe_skip_update_prompt
|
|
529
539
|
// FIRST each iteration -> the screen resolves to SkipUpdatePrompt, not AnswerWorkspaceTrust.
|
|
530
540
|
let screen = format!("{READY_BANNER}\n{TRUST_DIR}\n{UPDATE_AVAIL}\n");
|
|
531
|
-
assert_eq!(
|
|
541
|
+
assert_eq!(
|
|
542
|
+
classify_codex_startup_screen(&screen),
|
|
543
|
+
StartupScreenDecision::SkipUpdatePrompt
|
|
544
|
+
);
|
|
532
545
|
}
|
|
533
546
|
|
|
534
547
|
// ── ready-only / neither ─────────────────────────────────────────────────────────────────────────
|
|
@@ -601,22 +614,50 @@ mod tests {
|
|
|
601
614
|
fn kind(&self) -> BackendKind {
|
|
602
615
|
BackendKind::Tmux
|
|
603
616
|
}
|
|
604
|
-
fn spawn_first(
|
|
617
|
+
fn spawn_first(
|
|
618
|
+
&self,
|
|
619
|
+
_s: &SessionName,
|
|
620
|
+
_w: &WindowName,
|
|
621
|
+
_a: &[String],
|
|
622
|
+
_c: &Path,
|
|
623
|
+
_e: &BTreeMap<String, String>,
|
|
624
|
+
) -> Result<SpawnResult, TransportError> {
|
|
605
625
|
unimplemented!("not reached by startup-prompt loop")
|
|
606
626
|
}
|
|
607
|
-
fn spawn_into(
|
|
627
|
+
fn spawn_into(
|
|
628
|
+
&self,
|
|
629
|
+
_s: &SessionName,
|
|
630
|
+
_w: &WindowName,
|
|
631
|
+
_a: &[String],
|
|
632
|
+
_c: &Path,
|
|
633
|
+
_e: &BTreeMap<String, String>,
|
|
634
|
+
) -> Result<SpawnResult, TransportError> {
|
|
608
635
|
unimplemented!("not reached by startup-prompt loop")
|
|
609
636
|
}
|
|
610
|
-
fn inject(
|
|
637
|
+
fn inject(
|
|
638
|
+
&self,
|
|
639
|
+
_t: &Target,
|
|
640
|
+
_p: &InjectPayload,
|
|
641
|
+
_submit: Key,
|
|
642
|
+
_b: bool,
|
|
643
|
+
) -> Result<InjectReport, TransportError> {
|
|
611
644
|
unimplemented!("not reached")
|
|
612
645
|
}
|
|
613
646
|
fn send_keys(&self, _t: &Target, keys: &[Key]) -> Result<(), TransportError> {
|
|
614
647
|
self.sent.lock().unwrap().push(keys.to_vec());
|
|
615
648
|
Ok(())
|
|
616
649
|
}
|
|
617
|
-
fn capture(
|
|
650
|
+
fn capture(
|
|
651
|
+
&self,
|
|
652
|
+
_t: &Target,
|
|
653
|
+
range: CaptureRange,
|
|
654
|
+
) -> Result<CapturedText, TransportError> {
|
|
618
655
|
let mut q = self.screens.lock().unwrap();
|
|
619
|
-
let text = if q.is_empty() {
|
|
656
|
+
let text = if q.is_empty() {
|
|
657
|
+
String::new()
|
|
658
|
+
} else {
|
|
659
|
+
q.remove(0)
|
|
660
|
+
};
|
|
620
661
|
Ok(CapturedText { text, range })
|
|
621
662
|
}
|
|
622
663
|
fn query(&self, _t: &Target, _f: PaneField) -> Result<Option<String>, TransportError> {
|
|
@@ -634,7 +675,12 @@ mod tests {
|
|
|
634
675
|
fn list_windows(&self, _s: &SessionName) -> Result<Vec<WindowName>, TransportError> {
|
|
635
676
|
unimplemented!("not reached")
|
|
636
677
|
}
|
|
637
|
-
fn set_session_env(
|
|
678
|
+
fn set_session_env(
|
|
679
|
+
&self,
|
|
680
|
+
_s: &SessionName,
|
|
681
|
+
_k: &str,
|
|
682
|
+
_v: &str,
|
|
683
|
+
) -> Result<SetEnvOutcome, TransportError> {
|
|
638
684
|
unimplemented!("not reached")
|
|
639
685
|
}
|
|
640
686
|
fn kill_session(&self, _s: &SessionName) -> Result<(), TransportError> {
|
|
@@ -700,7 +746,9 @@ mod tests {
|
|
|
700
746
|
);
|
|
701
747
|
let sent = t.sent.lock().unwrap();
|
|
702
748
|
assert_eq!(
|
|
703
|
-
sent.iter()
|
|
749
|
+
sent.iter()
|
|
750
|
+
.filter(|keys| keys.as_slice() == [Key::Enter])
|
|
751
|
+
.count(),
|
|
704
752
|
1,
|
|
705
753
|
"copilot trust prompt must choose option 1 with one Enter; got {sent:?}"
|
|
706
754
|
);
|
|
@@ -1,17 +1,32 @@
|
|
|
1
|
-
//!
|
|
1
|
+
//! StateRepository facade.
|
|
2
2
|
//!
|
|
3
|
-
//! Ref:
|
|
3
|
+
//! Ref:
|
|
4
|
+
//! - `.team/artifacts/s1a-state-repository-design.md` (skeleton)
|
|
5
|
+
//! - `.team/artifacts/s1b-writer-cluster-locate.md` (0.5.42 first
|
|
6
|
+
//! writer-cluster migration: `CoordinatorTick` + `ClaimLeader`)
|
|
4
7
|
//!
|
|
5
|
-
//!
|
|
6
|
-
//!
|
|
7
|
-
//!
|
|
8
|
-
//!
|
|
9
|
-
//!
|
|
8
|
+
//! `StateRepository` is a thin write facade that dispatches every write
|
|
9
|
+
//! to the existing helper family without changing helper behavior,
|
|
10
|
+
//! merge policy, or on-disk layout. The value it adds is that every
|
|
11
|
+
//! write now carries a `StateWriteIntent`, so writer clusters migrate
|
|
12
|
+
//! one semantic at a time.
|
|
10
13
|
//!
|
|
11
|
-
//!
|
|
12
|
-
//!
|
|
13
|
-
//!
|
|
14
|
-
//!
|
|
14
|
+
//! 0.5.42 status: first real consumers are the daemon `Coordinator::
|
|
15
|
+
//! tick` production save (`CoordinatorTick`) and the lease/claim
|
|
16
|
+
//! writer cluster's two terminal saves (`ClaimLeader`) —
|
|
17
|
+
//! `write_lease_dual_state` + `save_claim_team_scoped_state`.
|
|
18
|
+
//! Post-S1b, the direct-save allowlist drops from 73 to 70; the three
|
|
19
|
+
//! migrated sites have no allowlist row and every future direct save
|
|
20
|
+
//! must either enter through `StateRepository` or claim an explicit
|
|
21
|
+
//! new allowlist row (fail-closed).
|
|
22
|
+
//!
|
|
23
|
+
//! Non-goals kept from S1a (design §11) + reasserted by
|
|
24
|
+
//! s1b-writer-cluster-locate.md §7: no schema rewrite, no path layout
|
|
25
|
+
//! change, no helper deletion, no epoch computation in the repository,
|
|
26
|
+
//! no retry / reload / event emission, no reinterpretation of
|
|
27
|
+
//! `owner_epoch` / `topology_convergence` / readback proof — the
|
|
28
|
+
//! caller still owns the whole `Value`, and repository dispatches to
|
|
29
|
+
//! the same existing persist helper the direct edge used to hit.
|
|
15
30
|
|
|
16
31
|
#![deny(clippy::unwrap_used, clippy::expect_used, clippy::panic)]
|
|
17
32
|
|
|
@@ -323,9 +338,7 @@ fn route_direct(
|
|
|
323
338
|
// intent lives under `coordinator.abnormal_api_error_recovery`, a
|
|
324
339
|
// root-scoped bookkeeping namespace that must survive across team
|
|
325
340
|
// boundaries; use the same helper family as CoordinatorConptyShim.
|
|
326
|
-
StateWriteIntent::CoordinatorApiErrorRecovery { .. } =>
|
|
327
|
-
helper_write_root(workspace, state)
|
|
328
|
-
}
|
|
341
|
+
StateWriteIntent::CoordinatorApiErrorRecovery { .. } => helper_write_root(workspace, state),
|
|
329
342
|
// McpAssignTask uses the reapply variant today; direct save routes
|
|
330
343
|
// to the root helper for parity.
|
|
331
344
|
StateWriteIntent::McpAssignTask { .. } => helper_write_root(workspace, state),
|