@team-agent/installer 0.5.65 → 0.5.68

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 (208) hide show
  1. package/Cargo.lock +8 -1
  2. package/Cargo.toml +1 -1
  3. package/crates/team-agent/Cargo.toml +6 -0
  4. package/crates/team-agent/src/cli/adapters.rs +6 -1
  5. package/crates/team-agent/src/cli/diagnose.rs +82 -0
  6. package/crates/team-agent/src/cli/emit.rs +3 -3
  7. package/crates/team-agent/src/cli/grok_slot.rs +299 -0
  8. package/crates/team-agent/src/cli/leader.rs +21 -7
  9. package/crates/team-agent/src/cli/leaders.rs +125 -1
  10. package/crates/team-agent/src/cli/mod.rs +20 -0
  11. package/crates/team-agent/src/cli/send/presentation.rs +7 -1
  12. package/crates/team-agent/src/cli/spec.rs +2 -0
  13. package/crates/team-agent/src/cli/status_port/compact.rs +28 -0
  14. package/crates/team-agent/src/cli/status_port/snapshot.rs +25 -1
  15. package/crates/team-agent/src/cli/tests/base.rs +26 -3
  16. package/crates/team-agent/src/cli/tests/compile.rs +1 -1
  17. package/crates/team-agent/src/cli/tests/missing_subcommands.rs +129 -19
  18. package/crates/team-agent/src/cli/tests/mod.rs +2 -2
  19. package/crates/team-agent/src/cli/tests/run_delegation.rs +1 -1
  20. package/crates/team-agent/src/cli/tests/shutdown_kill_plan.rs +387 -6
  21. package/crates/team-agent/src/cli/tests/status_send.rs +79 -10
  22. package/crates/team-agent/src/cli/tests/verb_validate.rs +1 -1
  23. package/crates/team-agent/src/communication_mode/mod.rs +6 -4
  24. package/crates/team-agent/src/compiler/tests.rs +23 -20
  25. package/crates/team-agent/src/compiler.rs +84 -5
  26. package/crates/team-agent/src/conpty/backend.rs +16 -0
  27. package/crates/team-agent/src/coordinator/backoff.rs +55 -0
  28. package/crates/team-agent/src/coordinator/conpty_shim.rs +82 -0
  29. package/crates/team-agent/src/coordinator/health.rs +173 -0
  30. package/crates/team-agent/src/coordinator/mod.rs +31 -0
  31. package/crates/team-agent/src/coordinator/orphan.rs +31 -0
  32. package/crates/team-agent/src/coordinator/runtime_detectors.rs +30 -0
  33. package/crates/team-agent/src/coordinator/runtime_observation.rs +25 -0
  34. package/crates/team-agent/src/coordinator/steps/abnormal.rs +59 -0
  35. package/crates/team-agent/src/coordinator/steps/delivery.rs +10 -0
  36. package/crates/team-agent/src/coordinator/steps/health_sync.rs +10 -0
  37. package/crates/team-agent/src/coordinator/steps/mod.rs +22 -0
  38. package/crates/team-agent/src/coordinator/steps/persist.rs +10 -0
  39. package/crates/team-agent/src/coordinator/steps/runtime_prompts.rs +10 -0
  40. package/crates/team-agent/src/coordinator/steps/session_gate.rs +10 -0
  41. package/crates/team-agent/src/coordinator/tick.rs +133 -22
  42. package/crates/team-agent/src/coordinator/types.rs +49 -0
  43. package/crates/team-agent/src/db/message_store.rs +39 -5
  44. package/crates/team-agent/src/layout/worker_env.rs +20 -3
  45. package/crates/team-agent/src/layout/worker_window_helpers.rs +2 -0
  46. package/crates/team-agent/src/leader/provider_attribution.rs +53 -0
  47. package/crates/team-agent/src/leader/registry.rs +65 -0
  48. package/crates/team-agent/src/leader/start.rs +1080 -58
  49. package/crates/team-agent/src/leader/tests/team_in_team_state_scope_red.rs +1 -1
  50. package/crates/team-agent/src/lifecycle/display.rs +56 -0
  51. package/crates/team-agent/src/lifecycle/helpers.rs +57 -0
  52. package/crates/team-agent/src/lifecycle/launch/add_agent.rs +332 -14
  53. package/crates/team-agent/src/lifecycle/launch/add_agent_state.rs +69 -2
  54. package/crates/team-agent/src/lifecycle/launch/agent_state.rs +196 -2
  55. package/crates/team-agent/src/lifecycle/launch/clone_agent.rs +101 -11
  56. package/crates/team-agent/src/lifecycle/launch/cursor_create_chat.rs +229 -0
  57. package/crates/team-agent/src/lifecycle/launch/cursor_mcp.rs +332 -0
  58. package/crates/team-agent/src/lifecycle/launch/fork_agent.rs +204 -457
  59. package/crates/team-agent/src/lifecycle/launch/fork_entry.rs +24 -0
  60. package/crates/team-agent/src/lifecycle/launch/grok_per_seat.rs +260 -0
  61. package/crates/team-agent/src/lifecycle/launch/identity.rs +146 -0
  62. package/crates/team-agent/src/lifecycle/launch/layout.rs +60 -0
  63. package/crates/team-agent/src/lifecycle/launch/leader_context.rs +112 -0
  64. package/crates/team-agent/src/lifecycle/launch/mcp_config.rs +530 -0
  65. package/crates/team-agent/src/lifecycle/launch/ownership.rs +40 -0
  66. package/crates/team-agent/src/lifecycle/launch/plan.rs +31 -0
  67. package/crates/team-agent/src/lifecycle/launch/quick_start.rs +66 -0
  68. package/crates/team-agent/src/lifecycle/launch/quick_start_transport.rs +78 -0
  69. package/crates/team-agent/src/lifecycle/launch/readiness.rs +85 -38
  70. package/crates/team-agent/src/lifecycle/launch/role_source.rs +44 -44
  71. package/crates/team-agent/src/lifecycle/launch/spawn.rs +101 -4
  72. package/crates/team-agent/src/lifecycle/launch/spec_state.rs +244 -48
  73. package/crates/team-agent/src/lifecycle/launch/state_projection.rs +109 -2
  74. package/crates/team-agent/src/lifecycle/launch/worker_env.rs +214 -1
  75. package/crates/team-agent/src/lifecycle/launch.rs +209 -43
  76. package/crates/team-agent/src/lifecycle/lock.rs +42 -1
  77. package/crates/team-agent/src/lifecycle/mod.rs +11 -0
  78. package/crates/team-agent/src/lifecycle/pane_input_lock.rs +161 -0
  79. package/crates/team-agent/src/lifecycle/profile_launch.rs +98 -0
  80. package/crates/team-agent/src/lifecycle/profile_smoke.rs +51 -1
  81. package/crates/team-agent/src/lifecycle/restart/agent.rs +213 -3
  82. package/crates/team-agent/src/lifecycle/restart/common.rs +373 -18
  83. package/crates/team-agent/src/lifecycle/restart/orchestrator.rs +27 -0
  84. package/crates/team-agent/src/lifecycle/restart/preflight.rs +25 -0
  85. package/crates/team-agent/src/lifecycle/restart/rebuild.rs +165 -15
  86. package/crates/team-agent/src/lifecycle/restart/remove.rs +196 -5
  87. package/crates/team-agent/src/lifecycle/restart/selection.rs +72 -0
  88. package/crates/team-agent/src/lifecycle/restart/team_state.rs +22 -0
  89. package/crates/team-agent/src/lifecycle/restart.rs +29 -0
  90. package/crates/team-agent/src/lifecycle/tests/acceptance_b_batch_red.rs +1 -1
  91. package/crates/team-agent/src/lifecycle/tests/agent_ops.rs +3 -4
  92. package/crates/team-agent/src/lifecycle/tests/behavioral_diff_264_red.rs +1 -1
  93. package/crates/team-agent/src/lifecycle/tests/claude_compatible_config_red.rs +2 -2
  94. package/crates/team-agent/src/lifecycle/tests/claude_profile_launch_red.rs +4 -4
  95. package/crates/team-agent/src/lifecycle/tests/clone_agent_preserves_source_tools.rs +309 -0
  96. package/crates/team-agent/src/lifecycle/tests/clone_fork_copilot_perms_red.rs +159 -174
  97. package/crates/team-agent/src/lifecycle/tests/communication_mode_runtime_contract_red.rs +2 -2
  98. package/crates/team-agent/src/lifecycle/tests/copilot_provider_red.rs +15 -13
  99. package/crates/team-agent/src/lifecycle/tests/core.rs +4 -18
  100. package/crates/team-agent/src/lifecycle/tests/core_034_real_red.rs +1 -1
  101. package/crates/team-agent/src/lifecycle/tests/cursor_mcp_overlay.rs +287 -0
  102. package/crates/team-agent/src/lifecycle/tests/cursor_require_explicit_model_red.rs +229 -0
  103. package/crates/team-agent/src/lifecycle/tests/cursor_restart_resume_red.rs +353 -0
  104. package/crates/team-agent/src/lifecycle/tests/display_adaptive_red.rs +1 -1
  105. package/crates/team-agent/src/lifecycle/tests/f032_startup_prompt_best_effort_red.rs +1 -1
  106. package/crates/team-agent/src/lifecycle/tests/g1_silent_faces.rs +784 -0
  107. package/crates/team-agent/src/lifecycle/tests/gate_fixtures.rs +562 -0
  108. package/crates/team-agent/src/lifecycle/tests/grok_effort_argv_red.rs +239 -0
  109. package/crates/team-agent/src/lifecycle/tests/grok_mcp_overlay_red.rs +498 -0
  110. package/crates/team-agent/src/lifecycle/tests/grok_require_explicit_model_red.rs +250 -0
  111. package/crates/team-agent/src/lifecycle/tests/grok_restart_resume_red.rs +293 -0
  112. package/crates/team-agent/src/lifecycle/tests/harvest2_a_batch_red.rs +3 -0
  113. package/crates/team-agent/src/lifecycle/tests/host_cotenant_death_p0_contract.rs +3 -3
  114. package/crates/team-agent/src/lifecycle/tests/lane_ops.rs +65 -40
  115. package/crates/team-agent/src/lifecycle/tests/launch_spawn.rs +20 -32
  116. package/crates/team-agent/src/lifecycle/tests/lifecycle_rollback_red.rs +17 -9
  117. package/crates/team-agent/src/lifecycle/tests/mcp_tool_name_format_red.rs +69 -0
  118. package/crates/team-agent/src/lifecycle/tests/phase_b_contracts.rs +24 -23
  119. package/crates/team-agent/src/lifecycle/tests/phase_golden.rs +98 -62
  120. package/crates/team-agent/src/lifecycle/tests/quick_start_worker_readiness_red.rs +2 -2
  121. package/crates/team-agent/src/lifecycle/tests/restart_build_before_destroy_0540_contract.rs +1 -1
  122. package/crates/team-agent/src/lifecycle/tests/restart_liveness_red.rs +1 -1
  123. package/crates/team-agent/src/lifecycle/tests/restart_rebind_hotfix_252_red.rs +3 -1
  124. package/crates/team-agent/src/lifecycle/tests/restart_session_capture_red.rs +2 -2
  125. package/crates/team-agent/src/lifecycle/tests/resume_recover_red.rs +1 -1
  126. package/crates/team-agent/src/lifecycle/tests/stale_team_saveconflict_contract.rs +1 -1
  127. package/crates/team-agent/src/lifecycle/tests/startup_latency_contract.rs +41 -8
  128. package/crates/team-agent/src/lifecycle/tests/status_credential_redaction_contract.rs +3 -3
  129. package/crates/team-agent/src/lifecycle/tests/subprep_codex_trust_roundtrip_red.rs +1 -1
  130. package/crates/team-agent/src/lifecycle/tests/swallow_batch4_semantics_red.rs +1 -1
  131. package/crates/team-agent/src/lifecycle/tests/team_in_team_identity_scope_red.rs +1 -1
  132. package/crates/team-agent/src/lifecycle/tests/team_in_team_sibling_quick_start_red.rs +1 -1
  133. package/crates/team-agent/src/lifecycle/tests/team_in_team_state_scope_red.rs +1 -1
  134. package/crates/team-agent/src/lifecycle/tests/team_key_retirement_txn_red.rs +1 -1
  135. package/crates/team-agent/src/lifecycle/tests/test_isolation_escape_contract.rs +60 -2
  136. package/crates/team-agent/src/lifecycle/tests/upgrade_compat_0211_red.rs +1 -1
  137. package/crates/team-agent/src/lifecycle/tests/verify_rs031_window_consistency_red.rs +2 -2
  138. package/crates/team-agent/src/lifecycle/tests/worker_spawn_env_red.rs +69 -26
  139. package/crates/team-agent/src/lifecycle/tests.rs +23 -15
  140. package/crates/team-agent/src/lifecycle/types.rs +61 -2
  141. package/crates/team-agent/src/lifecycle/worker_command_context.rs +200 -33
  142. package/crates/team-agent/src/mcp_server/tests/scoped.rs +100 -1
  143. package/crates/team-agent/src/mcp_server/tests.rs +196 -2
  144. package/crates/team-agent/src/messaging/delivery.rs +405 -40
  145. package/crates/team-agent/src/messaging/helpers.rs +2 -0
  146. package/crates/team-agent/src/messaging/leader_receiver.rs +53 -1
  147. package/crates/team-agent/src/messaging/results.rs +4 -0
  148. package/crates/team-agent/src/messaging/send.rs +34 -0
  149. package/crates/team-agent/src/messaging/tests/dup_inject.rs +406 -0
  150. package/crates/team-agent/src/messaging/tests/e23.rs +9 -0
  151. package/crates/team-agent/src/messaging/tests/leader_inject_acceptance.rs +66 -0
  152. package/crates/team-agent/src/messaging/tests/main_preserved.rs +1 -1
  153. package/crates/team-agent/src/messaging/tests/mod.rs +1 -0
  154. package/crates/team-agent/src/messaging/types.rs +4 -1
  155. package/crates/team-agent/src/model/enums.rs +14 -5
  156. package/crates/team-agent/src/model/permissions.rs +3 -0
  157. package/crates/team-agent/src/model/spec.rs +129 -6
  158. package/crates/team-agent/src/model/testdata/spec_invalid_a.yaml +3 -1
  159. package/crates/team-agent/src/model/testdata/team.spec.golden.yaml +3 -1
  160. package/crates/team-agent/src/model/testdata/team.spec.yaml +3 -1
  161. package/crates/team-agent/src/os_probe.rs +73 -2
  162. package/crates/team-agent/src/provider/adapter.rs +231 -4
  163. package/crates/team-agent/src/provider/adapters/claude.rs +5 -2
  164. package/crates/team-agent/src/provider/adapters/codex.rs +5 -2
  165. package/crates/team-agent/src/provider/adapters/copilot.rs +5 -2
  166. package/crates/team-agent/src/provider/adapters/cursor_agent.rs +86 -0
  167. package/crates/team-agent/src/provider/adapters/grok.rs +157 -0
  168. package/crates/team-agent/src/provider/adapters/mod.rs +2 -0
  169. package/crates/team-agent/src/provider/bypass_flags.rs +124 -0
  170. package/crates/team-agent/src/provider/classify.rs +4 -2
  171. package/crates/team-agent/src/provider/faults.rs +2 -1
  172. package/crates/team-agent/src/provider/mod.rs +13 -0
  173. package/crates/team-agent/src/provider/session/capture.rs +158 -20
  174. package/crates/team-agent/src/provider/session/context_fork/claude.rs +38 -1
  175. package/crates/team-agent/src/provider/session/context_fork/codex.rs +72 -1
  176. package/crates/team-agent/src/provider/session/context_fork/outcome.rs +57 -1
  177. package/crates/team-agent/src/provider/session/context_fork.rs +77 -3
  178. package/crates/team-agent/src/provider/session/mod.rs +18 -0
  179. package/crates/team-agent/src/provider/session/resume.rs +57 -0
  180. package/crates/team-agent/src/provider/session_scan/claude.rs +125 -1
  181. package/crates/team-agent/src/provider/session_scan/codex.rs +94 -1
  182. package/crates/team-agent/src/provider/session_scan/common.rs +204 -2
  183. package/crates/team-agent/src/provider/session_scan/copilot.rs +33 -1
  184. package/crates/team-agent/src/provider/session_scan/cursor.rs +538 -0
  185. package/crates/team-agent/src/provider/session_scan/grok.rs +288 -0
  186. package/crates/team-agent/src/provider/session_scan.rs +8 -0
  187. package/crates/team-agent/src/provider/submit_now.rs +94 -0
  188. package/crates/team-agent/src/provider/tests/adapter.rs +304 -0
  189. package/crates/team-agent/src/provider/types.rs +4 -2
  190. package/crates/team-agent/src/provider/wire.rs +23 -1
  191. package/crates/team-agent/src/state/persist.rs +301 -8
  192. package/crates/team-agent/src/state/repository.rs +5 -0
  193. package/crates/team-agent/src/tmux_backend/tests.rs +1737 -42
  194. package/crates/team-agent/src/tmux_backend.rs +1083 -75
  195. package/crates/team-agent/src/transport/test_support.rs +20 -0
  196. package/crates/team-agent/src/transport/tests/wire.rs +28 -2
  197. package/crates/team-agent/src/transport.rs +265 -1
  198. package/npm/install.mjs +129 -73
  199. package/package.json +4 -4
  200. package/skills/team-agent/SKILL.md +33 -238
  201. package/skills/team-agent/command-coverage.json +31 -0
  202. package/crates/team-agent/src/lifecycle/launch/approval.rs +0 -134
  203. package/crates/team-agent/src/lifecycle/launch/fork_agent/completion.rs +0 -59
  204. package/crates/team-agent/src/lifecycle/launch/fork_finalize.rs +0 -483
  205. package/crates/team-agent/src/lifecycle/launch/fork_pending.rs +0 -109
  206. package/crates/team-agent/src/lifecycle/launch/fork_state.rs +0 -447
  207. package/crates/team-agent/src/lifecycle/tests/codex_mcp_approval_inheritance_red.rs +0 -1187
  208. package/crates/team-agent/src/lifecycle/tests/worker_dangerous_bypass_argv_red.rs +0 -327
@@ -261,3 +261,307 @@ fn unsupported_provider_capability_error_message_shape() {
261
261
  // ═══════════════ P2 FIX-LOOP RED (复绿即对抗 cross-model findings) ═══════════════
262
262
  // Lock the CORRECT Python v0.2.11 behavior the strengthened contracts missed.
263
263
  // Golden re-probed via /tmp/probe_p2_provider.py vs team-agent-public @ 439bef8.
264
+
265
+ // ═══════════════ 0.5.67 provider-adapter (Grok + CursorAgent) ═══════════════
266
+ // 仿 claude build_command tests 结构 (见 build_command_includes_model_and_system_prompt)。
267
+ // 不跑 cargo (禁 cargo 红线), 静态编码 + leader verify 时执行。
268
+
269
+ #[test]
270
+ fn test_grok_build_command_includes_rules_flag_when_system_prompt_set() {
271
+ let adapter = get_adapter(Provider::Grok);
272
+ let argv = adapter
273
+ .build_command(AuthMode::Subscription, None, Some("be helpful"), Some("grok-4"))
274
+ .expect("build_command ok");
275
+ assert!(
276
+ argv_contains_adjacent(&argv, &["--model", "grok-4"]),
277
+ "argv must contain `--model grok-4` adjacency: {argv:?}"
278
+ );
279
+ assert!(
280
+ argv_contains_adjacent(&argv, &["--rules", "be helpful"]),
281
+ "grok append-system-prompt must be `--rules 'be helpful'`: {argv:?}"
282
+ );
283
+ }
284
+
285
+ #[test]
286
+ fn test_grok_build_command_bypass_flag_when_dangerous() {
287
+ let adapter = get_adapter(Provider::Grok);
288
+ let dangerous = adapter
289
+ .build_command_with_tools(
290
+ AuthMode::Subscription,
291
+ None,
292
+ None,
293
+ Some("grok-4"),
294
+ &["dangerous_auto_approve"],
295
+ )
296
+ .expect("dangerous build_command ok");
297
+ assert!(
298
+ argv_contains_adjacent(&dangerous, &["--always-approve"]),
299
+ "dangerous grok must include `--always-approve`: {dangerous:?}"
300
+ );
301
+ let safe = adapter
302
+ .build_command(AuthMode::Subscription, None, None, Some("grok-4"))
303
+ .expect("safe build_command ok");
304
+ assert!(
305
+ !safe.iter().any(|a| a == "--always-approve"),
306
+ "non-dangerous grok must not include --always-approve: {safe:?}"
307
+ );
308
+ }
309
+
310
+ #[test]
311
+ fn test_grok_build_command_refuses_missing_model() {
312
+ let adapter = get_adapter(Provider::Grok);
313
+ let err = adapter
314
+ .build_command(AuthMode::Subscription, None, None, None)
315
+ .expect_err("grok must refuse to build argv without an explicit model");
316
+ let text = err.to_string();
317
+ assert!(
318
+ text.to_ascii_lowercase().contains("model"),
319
+ "error must name model; got {text}"
320
+ );
321
+ assert!(
322
+ text.to_ascii_lowercase().contains("built-in")
323
+ || text.to_ascii_lowercase().contains("builtin")
324
+ || text.contains("内建"),
325
+ "error must name the built-in default the framework would fill; got {text}"
326
+ );
327
+ assert!(
328
+ argv_contains_adjacent(
329
+ &adapter
330
+ .build_command(AuthMode::Subscription, None, None, Some("grok-4.6"))
331
+ .expect("explicit model must build"),
332
+ &["--model", "grok-4.6"]
333
+ ),
334
+ "explicit model must still become adjacent `--model grok-4.6`"
335
+ );
336
+ }
337
+
338
+ #[test]
339
+ fn test_cursor_agent_build_command_includes_workspace_flag() {
340
+ let adapter = get_adapter(Provider::CursorAgent);
341
+ let argv = adapter
342
+ .build_command(AuthMode::Subscription, None, Some("be helpful"), Some("sonnet-4-thinking"))
343
+ .expect("build_command ok");
344
+ // system_prompt 不入 argv (方案 1 变体走 workspace rules 文件), argv 只带
345
+ // --workspace {workspace} placeholder (spawn 时 fill_spawn_placeholders 替换)。
346
+ assert!(
347
+ argv_contains_adjacent(&argv, &["--workspace", "{workspace}"]),
348
+ "cursor argv must carry `--workspace {{workspace}}`: {argv:?}"
349
+ );
350
+ assert!(
351
+ argv_contains_adjacent(&argv, &["--trust"]),
352
+ "cursor argv must carry documented --trust: {argv:?}"
353
+ );
354
+ assert!(
355
+ argv_contains_adjacent(&argv, &["--sandbox", "disabled"]),
356
+ "cursor argv must carry documented --sandbox disabled: {argv:?}"
357
+ );
358
+ assert!(
359
+ !argv.iter().any(|a| a == "--rules" || a == "--append-system-prompt"),
360
+ "cursor append-system-prompt must NOT go on argv (workspace rules file): {argv:?}"
361
+ );
362
+ assert!(
363
+ !argv.iter().any(|a| a == "--system-prompt" || a == "--allowed-tools"),
364
+ "undocumented flags must stay off the main path: {argv:?}"
365
+ );
366
+ }
367
+
368
+ #[test]
369
+ fn test_cursor_agent_build_command_bypass_flag_when_dangerous() {
370
+ let adapter = get_adapter(Provider::CursorAgent);
371
+ let dangerous = adapter
372
+ .build_command_with_tools(
373
+ AuthMode::Subscription,
374
+ None,
375
+ None,
376
+ None,
377
+ &["dangerous_auto_approve"],
378
+ )
379
+ .expect("dangerous build_command ok");
380
+ assert!(
381
+ argv_contains_adjacent(&dangerous, &["--force"]),
382
+ "dangerous cursor must include `--force`: {dangerous:?}"
383
+ );
384
+ let safe = adapter
385
+ .build_command(AuthMode::Subscription, None, None, None)
386
+ .expect("safe build_command ok");
387
+ assert!(
388
+ !safe.iter().any(|a| a == "--force"),
389
+ "non-dangerous cursor must not include --force: {safe:?}"
390
+ );
391
+ }
392
+
393
+ #[test]
394
+ fn test_cursor_agent_accepts_mcp_config_without_putting_it_on_argv() {
395
+ let adapter = get_adapter(Provider::CursorAgent);
396
+ let cfg = McpConfig {
397
+ raw: serde_json::json!({
398
+ "team_orchestrator": {
399
+ "command": "/bin/team-agent",
400
+ "args": ["mcp-server"]
401
+ }
402
+ }),
403
+ };
404
+ let argv = adapter
405
+ .build_command(AuthMode::Subscription, Some(&cfg), None, None)
406
+ .expect("cursor MCP is launch overlay, not an argv capability hole");
407
+ assert!(
408
+ !argv.iter().any(|a| a == "--mcp-config" || a.contains("mcp")),
409
+ "cursor has no --mcp-config flag; overlay writes .cursor/mcp.json: {argv:?}"
410
+ );
411
+ assert!(
412
+ argv_contains_adjacent(&argv, &["--workspace", "{workspace}"]),
413
+ "workspace flag must survive an mcp_config argument: {argv:?}"
414
+ );
415
+ }
416
+
417
+ #[test]
418
+ fn test_cursor_agent_refuses_mcp_config_loudly() {
419
+ // 已废除的行为:旧实现收到 mcp_config 就返回 CapabilityUnsupported
420
+ // (「MCP is not implemented」),此断言证明它确实没了。
421
+ let adapter = get_adapter(Provider::CursorAgent);
422
+ let cfg = McpConfig {
423
+ raw: serde_json::json!({
424
+ "team_orchestrator": {
425
+ "command": "/bin/team-agent",
426
+ "args": ["mcp-server"]
427
+ }
428
+ }),
429
+ };
430
+ let result = adapter.build_command(AuthMode::Subscription, Some(&cfg), None, None);
431
+ assert!(
432
+ !matches!(result, Err(ProviderError::CapabilityUnsupported(_))),
433
+ "feeding mcp_config must not return CapabilityUnsupported; got {result:?}"
434
+ );
435
+ }
436
+
437
+ #[test]
438
+ fn test_grok_build_command_plan_binds_expected_session_id_to_argv() {
439
+ let adapter = get_adapter(Provider::Grok);
440
+ let plan = adapter
441
+ .build_command_plan(ProviderCommandContext {
442
+ auth_mode: AuthMode::Subscription,
443
+ mcp_config: None,
444
+ system_prompt: None,
445
+ model: Some("grok-4.6"),
446
+ tools: &[],
447
+ profile_launch: None,
448
+ agent_id_hint: Some("w1"),
449
+ effort: None,
450
+ })
451
+ .expect("grok plan");
452
+ let sid = plan
453
+ .expected_session_id
454
+ .as_ref()
455
+ .map(|s| s.as_str())
456
+ .expect("grok fresh plan must carry expected_session_id");
457
+ assert!(
458
+ !sid.is_empty(),
459
+ "expected_session_id must be a non-empty uuid"
460
+ );
461
+ assert!(
462
+ argv_contains_adjacent(&plan.argv, &["--session-id", sid]),
463
+ "argv --session-id must match expected_session_id; argv={:?}",
464
+ plan.argv
465
+ );
466
+ assert!(
467
+ !plan.argv.iter().any(|a| a == "--resume"),
468
+ "fresh grok plan must not include --resume; argv={:?}",
469
+ plan.argv
470
+ );
471
+ }
472
+
473
+ #[test]
474
+ fn test_cursor_auth_hint_subscription_is_unknown_not_present() {
475
+ let adapter = get_adapter(Provider::CursorAgent);
476
+ let hint = adapter.auth_hint(AuthMode::Subscription);
477
+ assert_ne!(
478
+ hint,
479
+ crate::provider::types::AuthHintStatus::Present,
480
+ "U-17 前不得把未观测写成 Present"
481
+ );
482
+ assert_ne!(hint, crate::provider::types::AuthHintStatus::PresentWeak);
483
+ assert_eq!(hint, crate::provider::types::AuthHintStatus::Unknown);
484
+ }
485
+
486
+ #[test]
487
+ fn test_cursor_fresh_plan_has_no_session_id_and_no_resume() {
488
+ let adapter = get_adapter(Provider::CursorAgent);
489
+ let plan = adapter
490
+ .build_command_plan(ProviderCommandContext {
491
+ auth_mode: AuthMode::Subscription,
492
+ mcp_config: None,
493
+ system_prompt: None,
494
+ model: Some("sonnet-4-thinking"),
495
+ tools: &[],
496
+ profile_launch: None,
497
+ agent_id_hint: Some("w1"),
498
+ effort: None,
499
+ })
500
+ .expect("cursor plan");
501
+ assert!(
502
+ plan.expected_session_id.is_none(),
503
+ "U-01 未过不得造假 pending; got {:?}",
504
+ plan.expected_session_id
505
+ );
506
+ assert!(
507
+ !plan.argv.iter().any(|a| a == "--session-id" || a == "--resume" || a == "--continue"),
508
+ "fresh cursor argv must not invent session flags; argv={:?}",
509
+ plan.argv
510
+ );
511
+ assert!(
512
+ argv_contains_adjacent(&plan.argv, &["--trust"]),
513
+ "fresh cursor must keep --trust; argv={:?}",
514
+ plan.argv
515
+ );
516
+ }
517
+
518
+ #[test]
519
+ fn test_cursor_resume_plan_requires_chat_id_and_never_emits_empty_resume() {
520
+ let adapter = get_adapter(Provider::CursorAgent);
521
+ let ctx = ProviderCommandContext {
522
+ auth_mode: AuthMode::Subscription,
523
+ mcp_config: None,
524
+ system_prompt: None,
525
+ model: Some("sonnet-4-thinking"),
526
+ tools: &[],
527
+ profile_launch: None,
528
+ agent_id_hint: Some("w1"),
529
+ effort: None,
530
+ };
531
+ let missing = adapter.build_resume_command_plan(None, ctx);
532
+ assert!(
533
+ matches!(missing, Err(ProviderError::ResumeUnavailable(_))),
534
+ "no chatId must not emit empty --resume; got {missing:?}"
535
+ );
536
+ let sid = SessionId::new("502896a1-72ba-4c53-9a86-b2da28780806");
537
+ let plan = adapter
538
+ .build_resume_command_plan(Some(&sid), ctx)
539
+ .expect("resume plan");
540
+ assert!(
541
+ argv_contains_adjacent(&plan.argv, &["--resume", sid.as_str()]),
542
+ "resume plan must hit CursorAgent --resume arm; argv={:?}",
543
+ plan.argv
544
+ );
545
+ assert!(
546
+ !plan.argv.iter().any(|a| a == "--session-id" || a == "--continue"),
547
+ "resume must not mint --session-id/--continue; argv={:?}",
548
+ plan.argv
549
+ );
550
+ }
551
+
552
+ #[test]
553
+ fn test_grok_unknown_tool_mapping_is_explicitly_unsupported() {
554
+ use crate::provider::adapters::grok::{grok_tool_mapping, GrokToolMapping};
555
+ assert_eq!(
556
+ grok_tool_mapping("network"),
557
+ GrokToolMapping::Unsupported
558
+ );
559
+ assert_eq!(
560
+ grok_tool_mapping("not_a_real_tool"),
561
+ GrokToolMapping::Unsupported
562
+ );
563
+ assert!(
564
+ !matches!(grok_tool_mapping("execute_bash"), GrokToolMapping::Unsupported),
565
+ "known tools must stay mapped"
566
+ );
567
+ }
@@ -353,8 +353,10 @@ pub struct ProviderCommandContext<'a> {
353
353
  /// framework passes no effort flag (provider default).
354
354
  /// - Claude / ClaudeCode: low|medium|high|xhigh|max → `--effort <level>`
355
355
  /// - Codex: low|medium|high|xhigh → `-c model_reasoning_effort=<level>`
356
- /// - Copilot / Gemini / Fake: ignored, warning event emitted at the
357
- /// caller (lifecycle/launch.rs / lifecycle/restart) before construct.
356
+ /// - Grok: low|medium|high|xhigh (NOT max) `--effort <level>`
357
+ /// - Copilot / Gemini / CursorAgent / Fake: ignored, warning event
358
+ /// emitted at the caller (lifecycle/launch.rs / lifecycle/restart)
359
+ /// before construct.
358
360
  pub effort: Option<crate::model::enums::ProviderEffort>,
359
361
  }
360
362
 
@@ -34,6 +34,8 @@ pub(crate) fn provider_wire(provider: Provider) -> &'static str {
34
34
  Provider::Codex => "codex",
35
35
  Provider::Copilot => "copilot",
36
36
  Provider::GeminiCli => "gemini_cli",
37
+ Provider::Grok => "grok",
38
+ Provider::CursorAgent => "cursor_agent",
37
39
  Provider::Fake => "fake",
38
40
  }
39
41
  }
@@ -75,7 +77,12 @@ pub(crate) fn is_claude_family(provider: Provider) -> bool {
75
77
  pub(crate) fn requires_resume_backing(provider: Provider) -> bool {
76
78
  matches!(
77
79
  provider,
78
- Provider::Codex | Provider::Claude | Provider::ClaudeCode | Provider::Copilot
80
+ Provider::Codex
81
+ | Provider::Claude
82
+ | Provider::ClaudeCode
83
+ | Provider::Copilot
84
+ | Provider::Grok
85
+ | Provider::CursorAgent
79
86
  )
80
87
  }
81
88
 
@@ -86,6 +93,8 @@ pub(crate) fn provider_model_keys(provider: Provider) -> &'static [&'static str]
86
93
  Provider::Codex => &["codex"],
87
94
  Provider::Copilot => &["copilot"],
88
95
  Provider::GeminiCli => &["gemini_cli"],
96
+ Provider::Grok => &["grok"],
97
+ Provider::CursorAgent => &["cursor_agent"],
89
98
  Provider::Fake => &["fake"],
90
99
  }
91
100
  }
@@ -94,6 +103,10 @@ pub(crate) fn builtin_provider_model(provider: Provider) -> Option<&'static str>
94
103
  match provider {
95
104
  Provider::Claude | Provider::ClaudeCode => Some("claude-sonnet-4-6"),
96
105
  Provider::Codex => Some("gpt-5.5"),
106
+ // grok: compiler 另有缺 model 硬闸,这里的 builtin 不再被 grok 角色吃到。
107
+ // cursor_agent: 禁止隐式默认(本机 shim 会剥 sonnet-4-thinking);缺 model 编译失败。
108
+ Provider::Grok => Some("grok-4"),
109
+ Provider::CursorAgent => None,
97
110
  Provider::Copilot | Provider::GeminiCli | Provider::Fake => None,
98
111
  }
99
112
  }
@@ -112,6 +125,11 @@ pub(crate) fn aliases(provider: Provider) -> &'static [&'static str] {
112
125
  Provider::Codex => &["codex"],
113
126
  Provider::Copilot => &["copilot"],
114
127
  Provider::GeminiCli => &["gemini_cli"],
128
+ Provider::Grok => &["grok"],
129
+ // canonical wire form 恒为首项 (parse_provider round-trip 依赖); "agent"
130
+ // 是 exec 二进制名, 仅作 alias (不参与 command-text 子串匹配, 见
131
+ // leader/provider_attribution.rs TODO)。
132
+ Provider::CursorAgent => &["cursor_agent", "agent"],
115
133
  Provider::Fake => &["fake"],
116
134
  }
117
135
  }
@@ -126,6 +144,8 @@ pub(crate) fn command_name(provider: Provider) -> &'static str {
126
144
  Provider::Codex => "codex",
127
145
  Provider::Copilot => "copilot",
128
146
  Provider::GeminiCli => "gemini",
147
+ Provider::Grok => "grok",
148
+ Provider::CursorAgent => "agent",
129
149
  Provider::Fake => "team-agent",
130
150
  }
131
151
  }
@@ -136,6 +156,8 @@ const ALL_PROVIDERS: &[Provider] = &[
136
156
  Provider::Codex,
137
157
  Provider::Copilot,
138
158
  Provider::GeminiCli,
159
+ Provider::Grok,
160
+ Provider::CursorAgent,
139
161
  Provider::Fake,
140
162
  ];
141
163