@team-agent/installer 0.5.112 → 0.5.113

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.
Files changed (44) hide show
  1. package/Cargo.lock +1 -1
  2. package/Cargo.toml +1 -1
  3. package/crates/team-agent/src/cli/adapters.rs +100 -44
  4. package/crates/team-agent/src/cli/emit.rs +127 -98
  5. package/crates/team-agent/src/cli/leaders.rs +32 -32
  6. package/crates/team-agent/src/cli/mod.rs +6 -6
  7. package/crates/team-agent/src/cli/named_address.rs +17 -16
  8. package/crates/team-agent/src/cli/route.rs +4 -4
  9. package/crates/team-agent/src/cli/send/presentation.rs +19 -18
  10. package/crates/team-agent/src/cli/send/resolve.rs +11 -11
  11. package/crates/team-agent/src/cli/send.rs +4 -4
  12. package/crates/team-agent/src/cli/spec.rs +29 -29
  13. package/crates/team-agent/src/cli/status.rs +7 -7
  14. package/crates/team-agent/src/cli/tests/base.rs +6 -6
  15. package/crates/team-agent/src/cli/tests/divergence.rs +3 -2
  16. package/crates/team-agent/src/cli/tests/lane_c.rs +1 -1
  17. package/crates/team-agent/src/cli/tests/named_address.rs +3 -3
  18. package/crates/team-agent/src/cli/tests/status_send.rs +7 -7
  19. package/crates/team-agent/src/cli/triage.rs +53 -2
  20. package/crates/team-agent/src/cli/types.rs +8 -8
  21. package/crates/team-agent/src/compiler/tests.rs +12 -0
  22. package/crates/team-agent/src/compiler.rs +0 -9
  23. package/crates/team-agent/src/leader/start.rs +5 -0
  24. package/crates/team-agent/src/leader/tests/identity.rs +21 -0
  25. package/crates/team-agent/src/lifecycle/launch/identity.rs +172 -13
  26. package/crates/team-agent/src/lifecycle/launch/quick_start.rs +325 -14
  27. package/crates/team-agent/src/lifecycle/launch.rs +2 -2
  28. package/crates/team-agent/src/lifecycle/profile_launch.rs +58 -46
  29. package/crates/team-agent/src/lifecycle/restart/rebuild.rs +97 -52
  30. package/crates/team-agent/src/lifecycle/restart.rs +1 -1
  31. package/crates/team-agent/src/lifecycle/tests/stale_team_saveconflict_contract.rs +3 -2
  32. package/crates/team-agent/src/provider/adapter.rs +8 -59
  33. package/crates/team-agent/src/provider/adapters/claude.rs +6 -14
  34. package/crates/team-agent/src/provider/adapters/codex.rs +8 -18
  35. package/crates/team-agent/src/provider/adapters/copilot.rs +5 -22
  36. package/crates/team-agent/src/provider/adapters/cursor_agent.rs +8 -45
  37. package/crates/team-agent/src/provider/adapters/grok.rs +7 -31
  38. package/crates/team-agent/src/provider/adapters/pi.rs +7 -18
  39. package/crates/team-agent/src/provider/command_helpers.rs +45 -0
  40. package/crates/team-agent/src/provider/mod.rs +1 -0
  41. package/crates/team-agent/src/provider/model_catalog.rs +21 -28
  42. package/crates/team-agent/src/provider/tests/adapter.rs +70 -0
  43. package/crates/team-agent/src/provider/tests/command_helpers.rs +55 -0
  44. package/package.json +4 -4
@@ -3,7 +3,7 @@
3
3
  //! contract:
4
4
  //! provides:
5
5
  //! - name: cursor_agent_base_command
6
- //! what: 只组已实测文档化 flag;mcp_config 不入 argv,由 launch overlay 写盘
6
+ //! what: 只组已实测文档化 flag;MCP 由 launch overlay 写盘
7
7
  //! boundary:
8
8
  //! - 不调未文档化 flag(--system-prompt / --allowed-tools)
9
9
  //! - 不写 grok 那种 cwd 独占闸
@@ -22,60 +22,23 @@
22
22
  //! 随时可能消失。可以在注释里记录,代码里不许调。
23
23
  //! `--allowed-tools` 正反行为未验证,不写「支持工具白名单」。
24
24
 
25
- use crate::model::enums::AuthMode;
26
- use crate::provider::adapter::BasicProviderAdapter;
27
- use crate::provider::{McpConfig, ProviderError};
28
-
29
- pub(crate) fn cursor_agent_launch_command(
30
- adapter: &BasicProviderAdapter,
31
- auth_mode: AuthMode,
32
- mcp_config: Option<&McpConfig>,
33
- system_prompt: Option<&str>,
34
- model: Option<&str>,
35
- dangerously_skip_permissions: bool,
36
- ) -> Result<Vec<String>, ProviderError> {
37
- cursor_agent_base_command(
38
- adapter,
39
- auth_mode,
40
- mcp_config,
41
- system_prompt,
42
- model,
43
- dangerously_skip_permissions,
44
- false,
45
- None,
46
- )
47
- }
25
+ use crate::provider::ProviderError;
26
+ use crate::provider::command_helpers::{append_opt_pair, append_pair};
48
27
 
49
28
  pub(crate) fn cursor_agent_base_command(
50
- adapter: &BasicProviderAdapter,
51
- auth_mode: AuthMode,
52
- mcp_config: Option<&McpConfig>,
53
- system_prompt: Option<&str>,
54
29
  model: Option<&str>,
55
30
  dangerously_skip_permissions: bool,
56
- managed_mcp_config: bool,
57
- effort: Option<crate::model::enums::ProviderEffort>,
58
31
  ) -> Result<Vec<String>, ProviderError> {
59
32
  let mut argv = vec!["agent".to_string()];
60
33
  if dangerously_skip_permissions {
61
34
  // Explicit bypass also opts into Cursor's trusted, unsandboxed launch.
62
35
  argv.push("--trust".to_string());
63
- argv.push("--sandbox".to_string());
64
- argv.push("disabled".to_string());
36
+ append_pair(&mut argv, "--sandbox", "disabled");
65
37
  argv.push("--force".to_string());
66
38
  }
67
- if let Some(model) = model {
68
- argv.push("--model".to_string());
69
- argv.push(model.to_string());
70
- }
71
- // Cursor `--effort` flag 不存在;框架在调用方丢掉 effort。绝不发明 flag。
72
- let _ = effort;
73
- // system_prompt 不入 argv(help 无 --rules / --append-system-prompt)。
74
- // launch 写 `<workspace>/.cursor/rules/team-agent-role-<agent_id>.mdc`。
75
- // mcp_config 也不入 argv(无 --mcp-config)。launch 写 `.cursor/mcp.json`
76
- // 并 `agent mcp enable team_orchestrator`。这里收下以免静默丢弃。
77
- let _ = (adapter, auth_mode, mcp_config, managed_mcp_config, system_prompt);
78
- argv.push("--workspace".to_string());
79
- argv.push("{workspace}".to_string());
39
+ append_opt_pair(&mut argv, "--model", model);
40
+ // Cursor has no `--effort`, system-prompt, or MCP config flag.
41
+ // Launch materializes role rules and the `.cursor/mcp.json` overlay.
42
+ append_pair(&mut argv, "--workspace", "{workspace}");
80
43
  Ok(argv)
81
44
  }
@@ -30,62 +30,38 @@
30
30
  //! → `native_mcp_config: false`; MCP reaches the worker via launch-path
31
31
  //! `<cwd>/.grok/config.toml` (`apply_grok_mcp_overlay`).
32
32
 
33
- use crate::model::enums::AuthMode;
34
- use crate::provider::adapter::{next_session_token, BasicProviderAdapter};
35
- use crate::provider::{McpConfig, ProviderError};
33
+ use crate::provider::adapter::next_session_token;
34
+ use crate::provider::ProviderError;
35
+ use crate::provider::command_helpers::{append_opt_pair, append_pair};
36
36
 
37
37
  pub(crate) fn grok_launch_command(
38
- adapter: &BasicProviderAdapter,
39
- auth_mode: AuthMode,
40
- mcp_config: Option<&McpConfig>,
41
38
  system_prompt: Option<&str>,
42
39
  model: Option<&str>,
43
40
  dangerously_skip_permissions: bool,
44
41
  ) -> Result<Vec<String>, ProviderError> {
45
- let mut argv = grok_base_command(
46
- adapter,
47
- auth_mode,
48
- mcp_config,
49
- system_prompt,
50
- model,
51
- dangerously_skip_permissions,
52
- false,
53
- None,
54
- )?;
55
- argv.push("--session-id".to_string());
56
- argv.push(next_session_token());
42
+ let mut argv = grok_base_command(system_prompt, model, dangerously_skip_permissions, None)?;
43
+ append_pair(&mut argv, "--session-id", next_session_token());
57
44
  Ok(argv)
58
45
  }
59
46
 
60
47
  pub(crate) fn grok_base_command(
61
- adapter: &BasicProviderAdapter,
62
- auth_mode: AuthMode,
63
- mcp_config: Option<&McpConfig>,
64
48
  system_prompt: Option<&str>,
65
49
  model: Option<&str>,
66
50
  dangerously_skip_permissions: bool,
67
- managed_mcp_config: bool,
68
51
  effort: Option<crate::model::enums::ProviderEffort>,
69
52
  ) -> Result<Vec<String>, ProviderError> {
70
53
  let mut argv = vec!["grok".to_string()];
71
54
  if dangerously_skip_permissions {
72
55
  argv.push("--always-approve".to_string());
73
56
  }
74
- if let Some(model) = model.map(str::trim).filter(|value| !value.is_empty()) {
75
- argv.push("--model".to_string());
76
- argv.push(model.to_string());
77
- }
57
+ append_opt_pair(&mut argv, "--model", model.map(str::trim).filter(|value| !value.is_empty()));
78
58
  if let Some(effort) = effort {
79
59
  // Grok accepts `--effort` as alias for `--reasoning-effort`.
80
60
  argv.push("--effort".to_string());
81
61
  argv.push(effort.as_str().to_string());
82
62
  }
83
- if let Some(prompt) = system_prompt {
84
- argv.push("--rules".to_string());
85
- argv.push(prompt.to_string());
86
- }
63
+ append_opt_pair(&mut argv, "--rules", system_prompt);
87
64
  // Grok CLI has no `--mcp-config` flag — the claude inline-MCP block is
88
65
  // intentionally absent. Launch writes `<cwd>/.grok/config.toml`.
89
- let _ = (adapter, auth_mode, mcp_config, managed_mcp_config);
90
66
  Ok(argv)
91
67
  }
@@ -14,6 +14,7 @@ use std::path::Path;
14
14
 
15
15
  use crate::model::enums::ProviderEffort;
16
16
  use crate::provider::ProviderError;
17
+ use crate::provider::command_helpers::{append_opt_pair, append_pair};
17
18
 
18
19
  #[derive(Debug, Clone, Copy)]
19
20
  pub(crate) enum PiSessionSelector<'a> {
@@ -60,38 +61,27 @@ pub(crate) fn build_pi_command_argv(
60
61
  "-e".to_string(),
61
62
  request.extension.to_string_lossy().into_owned(),
62
63
  ];
63
- if let Some(model) = request.model {
64
- argv.push("--model".to_string());
65
- argv.push(model.to_string());
66
- }
64
+ append_opt_pair(&mut argv, "--model", request.model);
67
65
  if let Some(effort) = request.effort {
68
66
  argv.push("--thinking".to_string());
69
67
  argv.push(effort.as_str().to_string());
70
68
  }
71
- argv.extend([
72
- "--append-system-prompt".to_string(),
73
- request.system_prompt.to_string(),
74
- ]);
69
+ append_pair(&mut argv, "--append-system-prompt", request.system_prompt);
75
70
  if let Some(session_dir) = request.session_dir {
76
- argv.extend([
77
- "--session-dir".to_string(),
78
- session_dir.to_string_lossy().into_owned(),
79
- ]);
71
+ append_pair(&mut argv, "--session-dir", session_dir.to_string_lossy().into_owned());
80
72
  }
81
73
  // The shared lifecycle materializer always revalidates resume root/path/header.
82
74
  // Keep the pure argv builder usable before a fixture root is materialized, while
83
75
  // refusing a missing exact file once the recorded path's parent exists.
84
76
  match request.session {
85
77
  PiSessionSelector::Fresh { session_id } if !session_id.trim().is_empty() => {
86
- argv.push("--session-id".to_string());
87
- argv.push(session_id.to_string());
78
+ append_pair(&mut argv, "--session-id", session_id);
88
79
  }
89
80
  PiSessionSelector::Resume { path }
90
81
  if !path.as_os_str().is_empty()
91
82
  && (!path.parent().is_some_and(Path::is_dir) || path.is_file()) =>
92
83
  {
93
- argv.push("--session".to_string());
94
- argv.push(path.to_string_lossy().into_owned());
84
+ append_pair(&mut argv, "--session", path.to_string_lossy().into_owned());
95
85
  }
96
86
  PiSessionSelector::Resume { path } if !path.as_os_str().is_empty() => {
97
87
  return Err(ProviderError::ResumeUnavailable(format!(
@@ -105,7 +95,6 @@ pub(crate) fn build_pi_command_argv(
105
95
  ));
106
96
  }
107
97
  }
108
- argv.push("--name".to_string());
109
- argv.push(request.agent_id.to_string());
98
+ append_pair(&mut argv, "--name", request.agent_id);
110
99
  Ok(argv)
111
100
  }
@@ -0,0 +1,45 @@
1
+ //! Pure append operations. Callers own ordering, filtering, escaping and env-unset policy.
2
+ use std::collections::BTreeMap;
3
+
4
+ pub(crate) fn append_pair(argv: &mut Vec<String>, flag: &str, value: impl Into<String>) {
5
+ argv.push(flag.to_string());
6
+ argv.push(value.into());
7
+ }
8
+
9
+ pub(crate) fn append_opt_pair(argv: &mut Vec<String>, flag: &str, value: Option<&str>) {
10
+ if let Some(value) = value {
11
+ append_pair(argv, flag, value);
12
+ }
13
+ }
14
+
15
+ pub(crate) fn append_env_pair(env: &mut BTreeMap<String, String>, key: &str, value: Option<&str>) {
16
+ if let Some(value) = value {
17
+ env.insert(key.to_string(), value.to_string());
18
+ }
19
+ }
20
+
21
+ #[cfg(test)]
22
+ mod tests {
23
+ use super::*;
24
+
25
+ #[test]
26
+ fn append_preserves_order_and_raw_values() {
27
+ let mut argv = vec!["cli".to_string()];
28
+ append_opt_pair(&mut argv, "--absent", None);
29
+ append_opt_pair(&mut argv, "--empty", Some(""));
30
+ append_pair(&mut argv, "--raw", " \"'\\\n ".to_string());
31
+ append_pair(&mut argv, "--repeat", "first");
32
+ append_pair(&mut argv, "--repeat", "last");
33
+ assert_eq!(argv, ["cli", "--empty", "", "--raw", " \"'\\\n ", "--repeat", "first", "--repeat", "last"]);
34
+ }
35
+
36
+ #[test]
37
+ fn env_append_preserves_absence_empty_values_and_last_write() {
38
+ let mut env = BTreeMap::from([("Z".to_string(), "old".to_string())]);
39
+ append_env_pair(&mut env, "Z", None);
40
+ assert_eq!(env["Z"], "old");
41
+ append_env_pair(&mut env, "A", Some(""));
42
+ append_env_pair(&mut env, "Z", Some(" \"'\\\n "));
43
+ assert_eq!(env.into_iter().collect::<Vec<_>>(), vec![("A".to_string(), "".to_string()), ("Z".to_string(), " \"'\\\n ".to_string())]);
44
+ }
45
+ }
@@ -51,6 +51,7 @@ pub mod argv_route;
51
51
  /// 0.5.66 bypass 单源:provider → bypass argv flag 配置表(唯一权威)。
52
52
  pub(crate) mod bypass_flags;
53
53
  pub mod classify;
54
+ pub(crate) mod command_helpers;
54
55
  pub mod faults;
55
56
  pub mod model_catalog;
56
57
  pub mod session;
@@ -9,6 +9,7 @@ use std::sync::mpsc;
9
9
  use std::time::{Duration, Instant};
10
10
 
11
11
  use crate::model::enums::Provider;
12
+ use crate::provider::wire::{parse_canonical_provider, provider_wire};
12
13
 
13
14
  const CATALOG_TIMEOUT: Duration = Duration::from_secs(10);
14
15
  const MAX_CATALOG_BYTES: u64 = 1024 * 1024;
@@ -126,29 +127,7 @@ fn display_provider(provider: &str) -> &str {
126
127
 
127
128
  /// Only the documented catalog names are accepted; launch aliases stay unchanged.
128
129
  pub fn parse_catalog_provider(name: &str) -> Option<Provider> {
129
- match name {
130
- "pi" => Some(Provider::Pi),
131
- "cursor_agent" => Some(Provider::CursorAgent),
132
- "codex" => Some(Provider::Codex),
133
- "claude" => Some(Provider::Claude),
134
- "claude_code" => Some(Provider::ClaudeCode),
135
- "grok" => Some(Provider::Grok),
136
- _ => None,
137
- }
138
- }
139
-
140
- fn provider_wire_name(provider: Provider) -> &'static str {
141
- match provider {
142
- Provider::Pi => "pi",
143
- Provider::CursorAgent => "cursor_agent",
144
- Provider::Codex => "codex",
145
- Provider::Claude => "claude",
146
- Provider::ClaudeCode => "claude_code",
147
- Provider::Copilot => "copilot",
148
- Provider::GeminiCli => "gemini_cli",
149
- Provider::Grok => "grok",
150
- Provider::Fake => "fake",
151
- }
130
+ parse_canonical_provider(name).filter(|provider| catalog_source(*provider).is_some())
152
131
  }
153
132
 
154
133
  #[derive(Clone, Copy)]
@@ -175,7 +154,7 @@ fn catalog_source(provider: Provider) -> Option<CatalogSource> {
175
154
  pub fn discover_model_catalog(provider_name: &str) -> Result<Vec<ModelRecord>, CatalogError> {
176
155
  let provider = parse_catalog_provider(provider_name).ok_or(CatalogError::UnsupportedProvider)?;
177
156
  let source = catalog_source(provider).ok_or(CatalogError::UnsupportedProvider)?;
178
- let requested_provider = provider_wire_name(provider);
157
+ let requested_provider = provider_wire(provider);
179
158
  let records = match source {
180
159
  CatalogSource::Pi => {
181
160
  let bytes = run_native("pi", &["--list-models"], None, None, &[], CATALOG_TIMEOUT, MAX_CATALOG_BYTES, &mut NoopObserver)?;
@@ -881,10 +860,24 @@ mod tests {
881
860
 
882
861
  #[test]
883
862
  fn provider_capability_is_explicit_and_exact() {
884
- assert_eq!(parse_catalog_provider("claude_code"), Some(Provider::ClaudeCode));
885
- assert_eq!(parse_catalog_provider("cloud"), None);
886
- assert!(catalog_source(Provider::Codex).is_some());
887
- assert!(catalog_source(Provider::Fake).is_none());
863
+ for (name, provider) in [
864
+ ("pi", Provider::Pi),
865
+ ("cursor_agent", Provider::CursorAgent),
866
+ ("codex", Provider::Codex),
867
+ ("claude", Provider::Claude),
868
+ ("claude_code", Provider::ClaudeCode),
869
+ ("grok", Provider::Grok),
870
+ ] {
871
+ assert_eq!(parse_catalog_provider(name), Some(provider));
872
+ assert_eq!(provider_wire(provider), name);
873
+ assert!(catalog_source(provider).is_some());
874
+ }
875
+ for name in ["", "cloud", "cursor", "agent", "claude-code", "copilot", "gemini_cli", "fake", "Pi", "CODEX", " pi", "pi ", "pi/model", "codex:model", "claude_code_extra"] {
876
+ assert_eq!(parse_catalog_provider(name), None);
877
+ }
878
+ for provider in [Provider::Copilot, Provider::GeminiCli, Provider::Fake] {
879
+ assert!(catalog_source(provider).is_none());
880
+ }
888
881
  }
889
882
 
890
883
  #[test]
@@ -1,3 +1,73 @@
1
+ #[test]
2
+ fn trimmed_provider_builders_preserve_fresh_and_resume_argv() {
3
+ for (provider, base) in [
4
+ (
5
+ Provider::Grok,
6
+ vec!["grok", "--model", "test-model", "--rules", "role"],
7
+ ),
8
+ (
9
+ Provider::CursorAgent,
10
+ vec!["agent", "--model", "test-model", "--workspace", "{workspace}"],
11
+ ),
12
+ (
13
+ Provider::Copilot,
14
+ vec![
15
+ "copilot", "--no-color", "--no-auto-update", "--no-remote",
16
+ "--disable-builtin-mcps", "--allow-tool", "team_orchestrator",
17
+ "--model", "test-model",
18
+ ],
19
+ ),
20
+ ] {
21
+ let adapter = get_adapter(provider);
22
+ let ctx = ProviderCommandContext {
23
+ auth_mode: AuthMode::Subscription,
24
+ mcp_config: None,
25
+ system_prompt: Some("role"),
26
+ model: Some("test-model"),
27
+ dangerously_skip_permissions: false,
28
+ profile_launch: None,
29
+ agent_id_hint: Some("worker"),
30
+ effort: None,
31
+ };
32
+ let mut expected = base.iter().map(|s| s.to_string()).collect::<Vec<_>>();
33
+ let fresh = adapter.build_command_plan(ctx).expect("fresh plan");
34
+ if provider != Provider::CursorAgent {
35
+ expected.push("--session-id".to_string());
36
+ expected.push(
37
+ fresh.expected_session_id.as_ref().expect("session hint").as_str().to_string(),
38
+ );
39
+ } else {
40
+ assert!(fresh.expected_session_id.is_none());
41
+ }
42
+ assert_eq!(fresh.argv, expected, "{provider:?} fresh argv");
43
+ let session = SessionId::new("existing-session");
44
+ let mut expected = base.iter().map(|s| s.to_string()).collect::<Vec<_>>();
45
+ expected.extend(["--resume".to_string(), session.as_str().to_string()]);
46
+ assert_eq!(
47
+ adapter
48
+ .build_resume_command_plan(Some(&session), ctx)
49
+ .expect("resume plan")
50
+ .argv,
51
+ expected,
52
+ "{provider:?} resume argv"
53
+ );
54
+ if provider == Provider::CursorAgent {
55
+ let mut expected = base.iter().map(|s| s.to_string()).collect::<Vec<_>>();
56
+ expected.insert(1, "--resume".to_string());
57
+ expected.insert(2, session.as_str().to_string());
58
+ assert_eq!(
59
+ adapter
60
+ .build_resume_command_with_context(
61
+ Some(&session), ctx.auth_mode, None, ctx.system_prompt, ctx.model, false,
62
+ )
63
+ .expect("legacy resume"),
64
+ expected,
65
+ "legacy Cursor resume must retain its distinct flag order"
66
+ );
67
+ }
68
+ }
69
+ }
70
+
1
71
  #[test]
2
72
  fn abnormal_dedup_key_uses_signature_and_optional_turn_id() {
3
73
  // probe(/tmp/probe_idle.py read_fault_facts): the C8 dedup key is
@@ -0,0 +1,55 @@
1
+ //! Exact argv characterization: no helper may trim, escape or reorder caller values.
2
+ #![allow(clippy::unwrap_used, clippy::expect_used, clippy::panic)]
3
+ use super::*;
4
+ use crate::model::enums::ProviderEffort;
5
+ use crate::provider::adapters::{claude, codex, copilot, cursor_agent, grok, pi};
6
+ use crate::provider::ProviderCommandOverrides;
7
+
8
+ #[test]
9
+ fn command_helpers_keep_provider_argv_bytes_and_order() {
10
+ let raw = " \"'\\\n ";
11
+ let mcp = McpConfig { raw: serde_json::json!({}) };
12
+ assert_eq!(claude::claude_base_command(
13
+ &BasicProviderAdapter { provider: Provider::Claude }, AuthMode::Subscription,
14
+ Some(&mcp), Some(raw), Some(""), false, false, Some(ProviderEffort::High),
15
+ ).expect("claude"), ["claude", "--permission-mode", "default", "--model", "", "--effort", "high", "--append-system-prompt", raw, "--mcp-config", "{\"mcpServers\":{}}"]);
16
+
17
+ let overrides = ProviderCommandOverrides {
18
+ codex_profile: Some("".to_string()),
19
+ codex_config: vec!["model_reasoning_effort=low".to_string()],
20
+ ..Default::default()
21
+ };
22
+ assert_eq!(codex::codex_base_command(
23
+ Some("resume"), AuthMode::Subscription, Some(&mcp), Some(raw), Some(""),
24
+ true, Some(&overrides), Some(ProviderEffort::Max),
25
+ ), ["codex", "resume", "--no-alt-screen", "--disable", "shell_snapshot", "--disable", "apps", "--profile", "", "--dangerously-bypass-approvals-and-sandbox", "--model", "", "-c", "model_reasoning_effort=low", "-c", "model_reasoning_effort=max", "-c", "developer_instructions=\" \\\"'\\\\\\n \""]);
26
+
27
+ assert_eq!(copilot::copilot_base_command(
28
+ AuthMode::Subscription, Some(&mcp), Some(raw), Some(""), true,
29
+ ), ["copilot", "--no-color", "--no-auto-update", "--no-remote", "--disable-builtin-mcps", "--allow-all", "--allow-tool", "team_orchestrator", "--model", "", "--additional-mcp-config", "{}"]);
30
+ assert_eq!(cursor_agent::cursor_agent_base_command(Some(raw), true).expect("cursor"),
31
+ ["agent", "--trust", "--sandbox", "disabled", "--force", "--model", raw, "--workspace", "{workspace}"]);
32
+ assert_eq!(grok::grok_base_command(Some(raw), Some(" model-id "), true, Some(ProviderEffort::Medium)).expect("grok"),
33
+ ["grok", "--always-approve", "--model", "model-id", "--effort", "medium", "--rules", raw]);
34
+ assert_eq!(grok::grok_base_command(Some(""), Some(" "), false, None).expect("grok empty"), ["grok", "--rules", ""]);
35
+ assert_eq!(pi::build_pi_command_argv(pi::PiCommandRequest {
36
+ extension: std::path::Path::new("extension.ts"), model: Some("vendor/model"),
37
+ effort: Some(ProviderEffort::XHigh), system_prompt: raw,
38
+ session_dir: Some(std::path::Path::new("sessions")),
39
+ session: pi::PiSessionSelector::Fresh { session_id: "session-id" }, agent_id: "worker",
40
+ }).expect("pi"), ["pi", "-e", "extension.ts", "--model", "vendor/model", "--thinking", "xhigh", "--append-system-prompt", raw, "--session-dir", "sessions", "--session-id", "session-id", "--name", "worker"]);
41
+ }
42
+
43
+ #[test]
44
+ fn command_helpers_keep_absent_options_and_safe_defaults() {
45
+ assert_eq!(claude::claude_base_command(
46
+ &BasicProviderAdapter { provider: Provider::Claude }, AuthMode::Subscription,
47
+ None, None, None, false, false, None,
48
+ ).expect("claude"), ["claude", "--permission-mode", "default"]);
49
+ assert_eq!(codex::codex_base_command(None, AuthMode::Subscription, None, None, None, false, None, None),
50
+ ["codex", "--no-alt-screen", "--disable", "shell_snapshot", "--disable", "apps"]);
51
+ assert_eq!(copilot::copilot_base_command(AuthMode::Subscription, None, None, None, false),
52
+ ["copilot", "--no-color", "--no-auto-update", "--no-remote", "--disable-builtin-mcps", "--allow-tool", "team_orchestrator"]);
53
+ assert_eq!(cursor_agent::cursor_agent_base_command(None, false).expect("cursor"), ["agent", "--workspace", "{workspace}"]);
54
+ assert_eq!(grok::grok_base_command(None, None, false, None).expect("grok"), ["grok"]);
55
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@team-agent/installer",
3
- "version": "0.5.112",
3
+ "version": "0.5.113",
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.112",
24
- "@team-agent/cli-darwin-x64": "0.5.112",
25
- "@team-agent/cli-linux-x64": "0.5.112"
23
+ "@team-agent/cli-darwin-arm64": "0.5.113",
24
+ "@team-agent/cli-darwin-x64": "0.5.113",
25
+ "@team-agent/cli-linux-x64": "0.5.113"
26
26
  },
27
27
  "scripts": {
28
28
  "postinstall": "node npm/bincheck.mjs",