@team-agent/installer 0.5.24 → 0.5.25
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/diagnose.rs +13 -0
- package/crates/team-agent/src/leader/lease.rs +32 -1
- package/crates/team-agent/src/mcp_server/normalize.rs +3 -0
- package/crates/team-agent/src/mcp_server/tools.rs +78 -28
- package/crates/team-agent/src/messaging/results.rs +17 -0
- package/crates/team-agent/src/state/paths.rs +30 -31
- package/package.json +4 -4
package/Cargo.lock
CHANGED
package/Cargo.toml
CHANGED
|
@@ -171,10 +171,23 @@ pub(crate) fn diagnose_runtime_for_workspace(
|
|
|
171
171
|
backend: &dyn Transport,
|
|
172
172
|
) -> (Value, Value) {
|
|
173
173
|
let (mut issues, mut repairs) = diagnose_runtime(state, backend);
|
|
174
|
+
append_legacy_snapshot_issue(workspace, state, &mut issues);
|
|
174
175
|
append_coordinator_health_issue(workspace, state, &mut issues, &mut repairs);
|
|
175
176
|
(issues, repairs)
|
|
176
177
|
}
|
|
177
178
|
|
|
179
|
+
fn append_legacy_snapshot_issue(workspace: &std::path::Path, state: &Value, issues: &mut Value) {
|
|
180
|
+
let Ok(Some(details)) = crate::leader::detect_dual_state_divergence(workspace, state) else {
|
|
181
|
+
return;
|
|
182
|
+
};
|
|
183
|
+
if let Some(items) = issues.as_array_mut() {
|
|
184
|
+
items.push(json!({
|
|
185
|
+
"id": "legacy_snapshot_stale",
|
|
186
|
+
"details": details,
|
|
187
|
+
}));
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
178
191
|
fn append_coordinator_health_issue(
|
|
179
192
|
workspace: &std::path::Path,
|
|
180
193
|
state: &Value,
|
|
@@ -1780,10 +1780,13 @@ pub fn detect_dual_state_divergence( // B0_DIAGNOSTIC_LEGACY_SNAPSHOT_READ: diag
|
|
|
1780
1780
|
.or_else(|| get_path_u64(state, &["leader_receiver", "owner_epoch"]));
|
|
1781
1781
|
let team_epoch = get_path_u64(&snap, &["team_owner", "owner_epoch"])
|
|
1782
1782
|
.or_else(|| get_path_u64(&snap, &["leader_receiver", "owner_epoch"]));
|
|
1783
|
+
let workspace_agent_bindings = agent_binding_summary(state);
|
|
1784
|
+
let team_agent_bindings = agent_binding_summary(&snap);
|
|
1783
1785
|
let diverged = workspace_owner_pane != team_owner_pane
|
|
1784
1786
|
|| workspace_owner_uuid != team_owner_uuid
|
|
1785
1787
|
|| workspace_receiver_pane != team_receiver_pane
|
|
1786
|
-
|| workspace_epoch != team_epoch
|
|
1788
|
+
|| workspace_epoch != team_epoch
|
|
1789
|
+
|| workspace_agent_bindings != team_agent_bindings;
|
|
1787
1790
|
if !diverged {
|
|
1788
1791
|
return Ok(None);
|
|
1789
1792
|
}
|
|
@@ -1796,10 +1799,38 @@ pub fn detect_dual_state_divergence( // B0_DIAGNOSTIC_LEGACY_SNAPSHOT_READ: diag
|
|
|
1796
1799
|
"team_receiver_pane": team_receiver_pane,
|
|
1797
1800
|
"workspace_owner_epoch": workspace_epoch,
|
|
1798
1801
|
"team_owner_epoch": team_epoch,
|
|
1802
|
+
"workspace_agent_bindings": workspace_agent_bindings,
|
|
1803
|
+
"team_agent_bindings": team_agent_bindings,
|
|
1799
1804
|
"_legacy_snapshot_stale": true,
|
|
1800
1805
|
})))
|
|
1801
1806
|
}
|
|
1802
1807
|
|
|
1808
|
+
fn agent_binding_summary(state: &Value) -> Value {
|
|
1809
|
+
let mut out = serde_json::Map::new();
|
|
1810
|
+
let Some(agents) = state.get("agents").and_then(Value::as_object) else {
|
|
1811
|
+
return Value::Object(out);
|
|
1812
|
+
};
|
|
1813
|
+
for (agent_id, agent) in agents {
|
|
1814
|
+
let mut binding = serde_json::Map::new();
|
|
1815
|
+
for key in [
|
|
1816
|
+
"pane_id",
|
|
1817
|
+
"pane_pid",
|
|
1818
|
+
"tmux_endpoint",
|
|
1819
|
+
"tmux_socket",
|
|
1820
|
+
"window",
|
|
1821
|
+
"window_name",
|
|
1822
|
+
] {
|
|
1823
|
+
if let Some(value) = agent.get(key) {
|
|
1824
|
+
binding.insert(key.to_string(), value.clone());
|
|
1825
|
+
}
|
|
1826
|
+
}
|
|
1827
|
+
if !binding.is_empty() {
|
|
1828
|
+
out.insert(agent_id.clone(), Value::Object(binding));
|
|
1829
|
+
}
|
|
1830
|
+
}
|
|
1831
|
+
Value::Object(out)
|
|
1832
|
+
}
|
|
1833
|
+
|
|
1803
1834
|
fn readable_team_snapshot_path(workspace: &Path, session_name: &str) -> PathBuf { // B0_DIAGNOSTIC_LEGACY_SNAPSHOT_READ: diagnostic-only path resolver.
|
|
1804
1835
|
let safe_path = crate::lifecycle::helpers::team_snapshot_path(workspace, session_name); // B0_DIAGNOSTIC_LEGACY_SNAPSHOT_READ: reuses helpers safe legacy path.
|
|
1805
1836
|
if safe_path.exists() {
|
|
@@ -20,10 +20,10 @@ use crate::state::persist::{
|
|
|
20
20
|
use crate::messaging::{self, MessageTarget, SendOptions};
|
|
21
21
|
|
|
22
22
|
use super::helpers::{
|
|
23
|
-
delivery_outcome_value, direct_message_attribution_for,
|
|
24
|
-
insert_array, is_worker_recipient, json_dumps_default,
|
|
25
|
-
non_empty_string, normalized_envelope_value, object_fields,
|
|
26
|
-
tool_runtime_error, DirectMessageAttribution,
|
|
23
|
+
current_reportable_message_for, delivery_outcome_value, direct_message_attribution_for,
|
|
24
|
+
ensure_object, enum_value, insert_array, is_worker_recipient, json_dumps_default,
|
|
25
|
+
latest_task_for_assignee, non_empty_string, normalized_envelope_value, object_fields,
|
|
26
|
+
requires_ack_for_target, tool_runtime_error, DirectMessageAttribution,
|
|
27
27
|
};
|
|
28
28
|
use super::normalize::{
|
|
29
29
|
compact_tool_result, normalize_report_envelope, normalize_result_status_observed,
|
|
@@ -341,45 +341,76 @@ impl TeamOrchestratorTools {
|
|
|
341
341
|
// only when no newer failed/refused/blocked direct turn blocks fallback
|
|
342
342
|
// 5. "manual" — truly uncorrelated; collect still rejects
|
|
343
343
|
let owner_team_id_str = self.owner_team_id.as_ref().map(|t| t.as_str().to_string());
|
|
344
|
+
let mut attributed_message_id = None;
|
|
345
|
+
let mut attribution_scope = None;
|
|
346
|
+
let mut task_id_source = None;
|
|
344
347
|
let resolved = if let Some(task_id) = task_id {
|
|
345
348
|
task_id.to_string()
|
|
346
349
|
} else if let Some(agent) = self.agent_id.as_ref() {
|
|
347
|
-
|
|
350
|
+
if let Some(message_id) = current_reportable_message_for(
|
|
348
351
|
&self.workspace,
|
|
349
352
|
agent.as_str(),
|
|
350
353
|
owner_team_id_str.as_deref(),
|
|
351
354
|
) {
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
push_report_warning(
|
|
359
|
-
obj,
|
|
360
|
-
serde_json::json!({
|
|
361
|
-
"code": "result_attribution_blocked_by_newer_direct_message",
|
|
362
|
-
"field": "task_id",
|
|
363
|
-
"severity": "warning",
|
|
364
|
-
"advisory": true,
|
|
365
|
-
"message_id": message_id,
|
|
366
|
-
"message_status": status,
|
|
367
|
-
"message_error": error,
|
|
368
|
-
}),
|
|
369
|
-
);
|
|
370
|
-
"manual".to_string()
|
|
371
|
-
}
|
|
372
|
-
DirectMessageAttribution::None => latest_task_for_assignee(
|
|
355
|
+
attributed_message_id = Some(message_id.clone());
|
|
356
|
+
attribution_scope = Some("message");
|
|
357
|
+
task_id_source = Some("current_turn_message");
|
|
358
|
+
message_id
|
|
359
|
+
} else {
|
|
360
|
+
match direct_message_attribution_for(
|
|
373
361
|
&self.workspace,
|
|
374
362
|
agent.as_str(),
|
|
375
363
|
owner_team_id_str.as_deref(),
|
|
376
|
-
)
|
|
377
|
-
|
|
364
|
+
) {
|
|
365
|
+
DirectMessageAttribution::Reportable(message_id) => {
|
|
366
|
+
attributed_message_id = Some(message_id.clone());
|
|
367
|
+
attribution_scope = Some("message");
|
|
368
|
+
task_id_source = Some("direct_message");
|
|
369
|
+
message_id
|
|
370
|
+
}
|
|
371
|
+
DirectMessageAttribution::BlockedByNewer {
|
|
372
|
+
message_id,
|
|
373
|
+
status,
|
|
374
|
+
error,
|
|
375
|
+
} => {
|
|
376
|
+
push_report_warning(
|
|
377
|
+
obj,
|
|
378
|
+
serde_json::json!({
|
|
379
|
+
"code": "result_attribution_blocked_by_newer_direct_message",
|
|
380
|
+
"field": "task_id",
|
|
381
|
+
"severity": "warning",
|
|
382
|
+
"advisory": true,
|
|
383
|
+
"message_id": message_id,
|
|
384
|
+
"message_status": status,
|
|
385
|
+
"message_error": error,
|
|
386
|
+
}),
|
|
387
|
+
);
|
|
388
|
+
"manual".to_string()
|
|
389
|
+
}
|
|
390
|
+
DirectMessageAttribution::None => latest_task_for_assignee(
|
|
391
|
+
&self.workspace,
|
|
392
|
+
agent.as_str(),
|
|
393
|
+
owner_team_id_str.as_deref(),
|
|
394
|
+
)
|
|
395
|
+
.unwrap_or_else(|| "manual".to_string()),
|
|
396
|
+
}
|
|
378
397
|
}
|
|
379
398
|
} else {
|
|
380
399
|
"manual".to_string()
|
|
381
400
|
};
|
|
382
401
|
obj.insert("task_id".to_string(), Value::String(resolved));
|
|
402
|
+
if let Some(message_id) = attributed_message_id {
|
|
403
|
+
obj.entry("attributed_message_id")
|
|
404
|
+
.or_insert(Value::String(message_id));
|
|
405
|
+
}
|
|
406
|
+
if let Some(scope) = attribution_scope {
|
|
407
|
+
obj.entry("attribution_scope")
|
|
408
|
+
.or_insert(Value::String(scope.to_string()));
|
|
409
|
+
}
|
|
410
|
+
if let Some(source) = task_id_source {
|
|
411
|
+
obj.entry("task_id_source")
|
|
412
|
+
.or_insert(Value::String(source.to_string()));
|
|
413
|
+
}
|
|
383
414
|
}
|
|
384
415
|
if !obj.contains_key("agent_id") {
|
|
385
416
|
let resolved = agent_id
|
|
@@ -419,6 +450,7 @@ impl TeamOrchestratorTools {
|
|
|
419
450
|
let normalized = normalize_report_envelope(&base);
|
|
420
451
|
let warnings = report_result_integrity_warnings(&base, &normalized);
|
|
421
452
|
let mut env_value = normalized_envelope_value(&normalized);
|
|
453
|
+
copy_report_attribution_fields(&base, &mut env_value);
|
|
422
454
|
if !warnings.is_empty() {
|
|
423
455
|
if let Some(obj) = env_value.as_object_mut() {
|
|
424
456
|
obj.insert("warnings".to_string(), Value::Array(warnings));
|
|
@@ -985,6 +1017,24 @@ fn merge_object_fields(existing: &mut Value, incoming: &Value) {
|
|
|
985
1017
|
}
|
|
986
1018
|
}
|
|
987
1019
|
|
|
1020
|
+
fn copy_report_attribution_fields(source: &Value, target: &mut Value) {
|
|
1021
|
+
let Some(src) = source.as_object() else {
|
|
1022
|
+
return;
|
|
1023
|
+
};
|
|
1024
|
+
let Some(dst) = target.as_object_mut() else {
|
|
1025
|
+
return;
|
|
1026
|
+
};
|
|
1027
|
+
for key in [
|
|
1028
|
+
"attributed_message_id",
|
|
1029
|
+
"attribution_scope",
|
|
1030
|
+
"task_id_source",
|
|
1031
|
+
] {
|
|
1032
|
+
if let Some(value) = src.get(key) {
|
|
1033
|
+
dst.entry(key.to_string()).or_insert(value.clone());
|
|
1034
|
+
}
|
|
1035
|
+
}
|
|
1036
|
+
}
|
|
1037
|
+
|
|
988
1038
|
fn push_report_warning(obj: &mut serde_json::Map<String, Value>, warning: Value) {
|
|
989
1039
|
let Some(code) = warning.get("code").and_then(Value::as_str) else {
|
|
990
1040
|
return;
|
|
@@ -697,6 +697,7 @@ fn report_result_for_owner_team_inner(
|
|
|
697
697
|
"task_id".to_string(),
|
|
698
698
|
serde_json::Value::String(task_id.to_string()),
|
|
699
699
|
);
|
|
700
|
+
copy_report_attribution_fields(envelope, &mut out);
|
|
700
701
|
out.insert(
|
|
701
702
|
"agent_id".to_string(),
|
|
702
703
|
serde_json::Value::String(agent_id.to_string()),
|
|
@@ -927,6 +928,7 @@ fn report_result_for_owner_team_inner(
|
|
|
927
928
|
"task_id".to_string(),
|
|
928
929
|
serde_json::Value::String(task_id.to_string()),
|
|
929
930
|
);
|
|
931
|
+
copy_report_attribution_fields(envelope, &mut out);
|
|
930
932
|
out.insert(
|
|
931
933
|
"agent_id".to_string(),
|
|
932
934
|
serde_json::Value::String(agent_id.to_string()),
|
|
@@ -968,6 +970,21 @@ fn report_result_for_owner_team_inner(
|
|
|
968
970
|
Ok(serde_json::Value::Object(out))
|
|
969
971
|
}
|
|
970
972
|
|
|
973
|
+
fn copy_report_attribution_fields(
|
|
974
|
+
envelope: &serde_json::Value,
|
|
975
|
+
out: &mut serde_json::Map<String, serde_json::Value>,
|
|
976
|
+
) {
|
|
977
|
+
for key in [
|
|
978
|
+
"attributed_message_id",
|
|
979
|
+
"attribution_scope",
|
|
980
|
+
"task_id_source",
|
|
981
|
+
] {
|
|
982
|
+
if let Some(value) = envelope.get(key) {
|
|
983
|
+
out.insert(key.to_string(), value.clone());
|
|
984
|
+
}
|
|
985
|
+
}
|
|
986
|
+
}
|
|
987
|
+
|
|
971
988
|
fn fallback_primary_error_text(cli_primary_error: Option<&str>, observed: String) -> String {
|
|
972
989
|
match cli_primary_error.filter(|error| !error.trim().is_empty()) {
|
|
973
990
|
Some(error) => format!("{error}; {observed}"),
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
//! paths or behaviour. It introduces a shared vocabulary that Stage 2 (owner
|
|
6
6
|
//! repository), Stage 5 (per-team runtime state), and Stage 6 (per-team
|
|
7
7
|
//! coordinator) will all consume, so that no later stage has to hand-build
|
|
8
|
-
//! `.team/runtime/<team_key>/...` paths or guess the canonical team_key from
|
|
8
|
+
//! `.team/runtime/teams/<team_key>/...` paths or guess the canonical team_key from
|
|
9
9
|
//! a display name.
|
|
10
10
|
//!
|
|
11
11
|
//! Canonical rules:
|
|
@@ -15,10 +15,10 @@
|
|
|
15
15
|
//! - For the foundation slice, `TeamScope::new(team_key)` accepts whatever
|
|
16
16
|
//! the caller already resolved (state/selector + state/persist already do
|
|
17
17
|
//! this work). Slug/hash promotion to global uniqueness lands in Stage 5.
|
|
18
|
-
//! - `TeamRuntimePaths` is the SINGLE place where the
|
|
19
|
-
//! `.team/runtime/<team_key>/` layout is constructed. Anywhere
|
|
20
|
-
//! code today hand-joins
|
|
21
|
-
//!
|
|
18
|
+
//! - `TeamRuntimePaths` is the SINGLE place where the future B3
|
|
19
|
+
//! `.team/runtime/teams/<team_key>/` layout is constructed. Anywhere
|
|
20
|
+
//! downstream code today hand-joins runtime team paths should migrate to
|
|
21
|
+
//! call a method on `TeamRuntimePaths` in a later stage.
|
|
22
22
|
//!
|
|
23
23
|
//! Single-team behaviour: unchanged. The foundation does not move data, does
|
|
24
24
|
//! not introduce new files, and is invoked by zero existing call sites yet.
|
|
@@ -72,15 +72,15 @@ impl TeamScope {
|
|
|
72
72
|
}
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
-
/// Single source of `.team/runtime/<team_key>/...` path construction.
|
|
75
|
+
/// Single source of future B3 `.team/runtime/teams/<team_key>/...` path construction.
|
|
76
76
|
///
|
|
77
77
|
/// Stage 2 (owner repository), Stage 5 (per-team state), Stage 6 (per-team
|
|
78
78
|
/// coordinator), and Stage 7 (per-team tmux socket) will all migrate from
|
|
79
79
|
/// hand-built paths to `TeamRuntimePaths`. Today nothing reads from these
|
|
80
80
|
/// methods yet — the foundation just owns the layout decision so when later
|
|
81
|
-
/// stages start writing `.team/runtime/<team_key>/state.json` (Stage 5)
|
|
82
|
-
/// `.team/runtime/<team_key>/coordinator.pid` (Stage 6), there is
|
|
83
|
-
/// one place to change the layout.
|
|
81
|
+
/// stages start writing `.team/runtime/teams/<team_key>/state.json` (Stage 5)
|
|
82
|
+
/// or `.team/runtime/teams/<team_key>/coordinator.pid` (Stage 6), there is
|
|
83
|
+
/// exactly one place to change the layout.
|
|
84
84
|
#[derive(Debug, Clone)]
|
|
85
85
|
pub struct TeamRuntimePaths {
|
|
86
86
|
workspace: PathBuf,
|
|
@@ -110,34 +110,36 @@ impl TeamRuntimePaths {
|
|
|
110
110
|
&self.team_key
|
|
111
111
|
}
|
|
112
112
|
|
|
113
|
-
/// `.team/runtime/<team_key>/` — the team's
|
|
114
|
-
///
|
|
115
|
-
///
|
|
113
|
+
/// `.team/runtime/teams/<team_key>/` — the team's future B3 runtime
|
|
114
|
+
/// directory. It is not used as product authority until the B3 migration;
|
|
115
|
+
/// current callers must keep using `runtime_state_path`.
|
|
116
116
|
pub fn team_dir(&self) -> PathBuf {
|
|
117
|
-
runtime_dir(&self.workspace)
|
|
117
|
+
runtime_dir(&self.workspace)
|
|
118
|
+
.join("teams")
|
|
119
|
+
.join(&self.team_key)
|
|
118
120
|
}
|
|
119
121
|
|
|
120
|
-
///
|
|
121
|
-
///
|
|
122
|
-
///
|
|
122
|
+
/// Transitional runtime spec path. Mirrors the existing
|
|
123
|
+
/// `runtime_spec_path` helper while specs remain at
|
|
124
|
+
/// `.team/runtime/<team_key>/team.spec.yaml`.
|
|
123
125
|
pub fn spec_path(&self) -> PathBuf {
|
|
124
126
|
runtime_spec_path(&self.workspace, &self.team_key)
|
|
125
127
|
}
|
|
126
128
|
|
|
127
|
-
/// `.team/runtime/<team_key>/state.json` — the canonical per-team
|
|
128
|
-
/// path that
|
|
129
|
-
/// code; callers must continue using `runtime_state_path` until
|
|
129
|
+
/// `.team/runtime/teams/<team_key>/state.json` — the canonical per-team
|
|
130
|
+
/// state path that B3 will start writing. Not used by current product
|
|
131
|
+
/// code; callers must continue using `runtime_state_path` until B3
|
|
130
132
|
/// migrates the truth source.
|
|
131
133
|
pub fn state_path(&self) -> PathBuf {
|
|
132
134
|
self.team_dir().join("state.json")
|
|
133
135
|
}
|
|
134
136
|
|
|
135
|
-
/// `.team/runtime/<team_key>/coordinator.pid` —
|
|
137
|
+
/// `.team/runtime/teams/<team_key>/coordinator.pid` — future sidecar location.
|
|
136
138
|
pub fn coordinator_pid_path(&self) -> PathBuf {
|
|
137
139
|
self.team_dir().join("coordinator.pid")
|
|
138
140
|
}
|
|
139
141
|
|
|
140
|
-
/// `.team/runtime/<team_key>/coordinator.log` —
|
|
142
|
+
/// `.team/runtime/teams/<team_key>/coordinator.log` — future sidecar location.
|
|
141
143
|
pub fn coordinator_log_path(&self) -> PathBuf {
|
|
142
144
|
self.team_dir().join("coordinator.log")
|
|
143
145
|
}
|
|
@@ -240,23 +242,20 @@ mod tests {
|
|
|
240
242
|
}
|
|
241
243
|
|
|
242
244
|
#[test]
|
|
243
|
-
fn
|
|
245
|
+
fn team_runtime_paths_layout_preannounces_b3_state_dir() {
|
|
244
246
|
let paths = TeamRuntimePaths::new(PathBuf::from("/ws/proj"), "alpha");
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
);
|
|
247
|
+
let b3_team_dir = PathBuf::from("/ws/proj/.team/runtime")
|
|
248
|
+
.join("teams")
|
|
249
|
+
.join("alpha");
|
|
250
|
+
assert_eq!(paths.team_dir(), b3_team_dir);
|
|
249
251
|
assert_eq!(
|
|
250
252
|
paths.spec_path(),
|
|
251
253
|
PathBuf::from("/ws/proj/.team/runtime/alpha/team.spec.yaml")
|
|
252
254
|
);
|
|
253
|
-
assert_eq!(
|
|
254
|
-
paths.state_path(),
|
|
255
|
-
PathBuf::from("/ws/proj/.team/runtime/alpha/state.json")
|
|
256
|
-
);
|
|
255
|
+
assert_eq!(paths.state_path(), b3_team_dir.join("state.json"));
|
|
257
256
|
assert_eq!(
|
|
258
257
|
paths.coordinator_pid_path(),
|
|
259
|
-
|
|
258
|
+
b3_team_dir.join("coordinator.pid")
|
|
260
259
|
);
|
|
261
260
|
}
|
|
262
261
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@team-agent/installer",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.25",
|
|
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.25",
|
|
24
|
+
"@team-agent/cli-darwin-x64": "0.5.25",
|
|
25
|
+
"@team-agent/cli-linux-x64": "0.5.25"
|
|
26
26
|
},
|
|
27
27
|
"scripts": {
|
|
28
28
|
"postinstall": "node npm/bincheck.mjs",
|