@team-agent/installer 0.5.66 → 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.
- package/Cargo.lock +8 -1
- package/Cargo.toml +1 -1
- package/crates/team-agent/Cargo.toml +1 -0
- package/crates/team-agent/src/cli/adapters.rs +5 -0
- package/crates/team-agent/src/cli/diagnose.rs +82 -0
- package/crates/team-agent/src/cli/emit.rs +3 -3
- package/crates/team-agent/src/cli/grok_slot.rs +299 -0
- package/crates/team-agent/src/cli/leader.rs +21 -7
- package/crates/team-agent/src/cli/leaders.rs +125 -1
- package/crates/team-agent/src/cli/mod.rs +20 -0
- package/crates/team-agent/src/cli/send/presentation.rs +7 -1
- package/crates/team-agent/src/cli/spec.rs +2 -0
- package/crates/team-agent/src/cli/status_port/compact.rs +28 -0
- package/crates/team-agent/src/cli/status_port/snapshot.rs +25 -1
- package/crates/team-agent/src/cli/tests/base.rs +26 -3
- package/crates/team-agent/src/cli/tests/missing_subcommands.rs +129 -19
- package/crates/team-agent/src/cli/tests/shutdown_kill_plan.rs +387 -6
- package/crates/team-agent/src/cli/tests/status_send.rs +79 -10
- package/crates/team-agent/src/communication_mode/mod.rs +6 -4
- package/crates/team-agent/src/compiler.rs +59 -0
- package/crates/team-agent/src/coordinator/backoff.rs +55 -0
- package/crates/team-agent/src/coordinator/conpty_shim.rs +82 -0
- package/crates/team-agent/src/coordinator/health.rs +173 -0
- package/crates/team-agent/src/coordinator/mod.rs +31 -0
- package/crates/team-agent/src/coordinator/orphan.rs +31 -0
- package/crates/team-agent/src/coordinator/runtime_detectors.rs +30 -0
- package/crates/team-agent/src/coordinator/runtime_observation.rs +25 -0
- package/crates/team-agent/src/coordinator/steps/abnormal.rs +59 -0
- package/crates/team-agent/src/coordinator/steps/delivery.rs +10 -0
- package/crates/team-agent/src/coordinator/steps/health_sync.rs +10 -0
- package/crates/team-agent/src/coordinator/steps/mod.rs +22 -0
- package/crates/team-agent/src/coordinator/steps/persist.rs +10 -0
- package/crates/team-agent/src/coordinator/steps/runtime_prompts.rs +10 -0
- package/crates/team-agent/src/coordinator/steps/session_gate.rs +10 -0
- package/crates/team-agent/src/coordinator/tick.rs +133 -22
- package/crates/team-agent/src/coordinator/types.rs +49 -0
- package/crates/team-agent/src/db/message_store.rs +39 -5
- package/crates/team-agent/src/layout/worker_env.rs +20 -3
- package/crates/team-agent/src/layout/worker_window_helpers.rs +2 -0
- package/crates/team-agent/src/leader/provider_attribution.rs +53 -0
- package/crates/team-agent/src/leader/registry.rs +65 -0
- package/crates/team-agent/src/leader/start.rs +920 -63
- package/crates/team-agent/src/lifecycle/display.rs +56 -0
- package/crates/team-agent/src/lifecycle/helpers.rs +57 -0
- package/crates/team-agent/src/lifecycle/launch/add_agent.rs +332 -12
- package/crates/team-agent/src/lifecycle/launch/add_agent_state.rs +62 -0
- package/crates/team-agent/src/lifecycle/launch/agent_state.rs +59 -0
- package/crates/team-agent/src/lifecycle/launch/clone_agent.rs +101 -11
- package/crates/team-agent/src/lifecycle/launch/cursor_create_chat.rs +229 -0
- package/crates/team-agent/src/lifecycle/launch/cursor_mcp.rs +332 -0
- package/crates/team-agent/src/lifecycle/launch/fork_agent.rs +204 -456
- package/crates/team-agent/src/lifecycle/launch/fork_entry.rs +24 -0
- package/crates/team-agent/src/lifecycle/launch/grok_per_seat.rs +260 -0
- package/crates/team-agent/src/lifecycle/launch/identity.rs +146 -0
- package/crates/team-agent/src/lifecycle/launch/layout.rs +60 -0
- package/crates/team-agent/src/lifecycle/launch/leader_context.rs +112 -0
- package/crates/team-agent/src/lifecycle/launch/mcp_config.rs +530 -0
- package/crates/team-agent/src/lifecycle/launch/ownership.rs +40 -0
- package/crates/team-agent/src/lifecycle/launch/plan.rs +31 -0
- package/crates/team-agent/src/lifecycle/launch/quick_start.rs +66 -0
- package/crates/team-agent/src/lifecycle/launch/quick_start_transport.rs +78 -0
- package/crates/team-agent/src/lifecycle/launch/readiness.rs +85 -38
- package/crates/team-agent/src/lifecycle/launch/role_source.rs +44 -44
- package/crates/team-agent/src/lifecycle/launch/spawn.rs +62 -2
- package/crates/team-agent/src/lifecycle/launch/spec_state.rs +139 -0
- package/crates/team-agent/src/lifecycle/launch/state_projection.rs +109 -0
- package/crates/team-agent/src/lifecycle/launch/worker_env.rs +214 -1
- package/crates/team-agent/src/lifecycle/launch.rs +99 -29
- package/crates/team-agent/src/lifecycle/lock.rs +42 -1
- package/crates/team-agent/src/lifecycle/mod.rs +11 -0
- package/crates/team-agent/src/lifecycle/pane_input_lock.rs +161 -0
- package/crates/team-agent/src/lifecycle/profile_launch.rs +98 -0
- package/crates/team-agent/src/lifecycle/profile_smoke.rs +51 -1
- package/crates/team-agent/src/lifecycle/restart/agent.rs +124 -0
- package/crates/team-agent/src/lifecycle/restart/common.rs +369 -11
- package/crates/team-agent/src/lifecycle/restart/orchestrator.rs +27 -0
- package/crates/team-agent/src/lifecycle/restart/preflight.rs +25 -0
- package/crates/team-agent/src/lifecycle/restart/rebuild.rs +106 -0
- package/crates/team-agent/src/lifecycle/restart/remove.rs +196 -5
- package/crates/team-agent/src/lifecycle/restart/selection.rs +72 -0
- package/crates/team-agent/src/lifecycle/restart/team_state.rs +22 -0
- package/crates/team-agent/src/lifecycle/restart.rs +29 -0
- package/crates/team-agent/src/lifecycle/tests/agent_ops.rs +2 -3
- package/crates/team-agent/src/lifecycle/tests/clone_agent_preserves_source_tools.rs +309 -0
- package/crates/team-agent/src/lifecycle/tests/clone_fork_copilot_perms_red.rs +150 -157
- package/crates/team-agent/src/lifecycle/tests/copilot_provider_red.rs +2 -2
- package/crates/team-agent/src/lifecycle/tests/core.rs +4 -0
- package/crates/team-agent/src/lifecycle/tests/cursor_mcp_overlay.rs +287 -0
- package/crates/team-agent/src/lifecycle/tests/cursor_require_explicit_model_red.rs +229 -0
- package/crates/team-agent/src/lifecycle/tests/cursor_restart_resume_red.rs +353 -0
- package/crates/team-agent/src/lifecycle/tests/g1_silent_faces.rs +784 -0
- package/crates/team-agent/src/lifecycle/tests/gate_fixtures.rs +562 -0
- package/crates/team-agent/src/lifecycle/tests/grok_effort_argv_red.rs +239 -0
- package/crates/team-agent/src/lifecycle/tests/grok_mcp_overlay_red.rs +498 -0
- package/crates/team-agent/src/lifecycle/tests/grok_require_explicit_model_red.rs +250 -0
- package/crates/team-agent/src/lifecycle/tests/grok_restart_resume_red.rs +293 -0
- package/crates/team-agent/src/lifecycle/tests/lane_ops.rs +63 -38
- package/crates/team-agent/src/lifecycle/tests/launch_spawn.rs +3 -2
- package/crates/team-agent/src/lifecycle/tests/lifecycle_rollback_red.rs +16 -8
- package/crates/team-agent/src/lifecycle/tests/mcp_tool_name_format_red.rs +69 -0
- package/crates/team-agent/src/lifecycle/tests/phase_b_contracts.rs +20 -19
- package/crates/team-agent/src/lifecycle/tests/phase_golden.rs +97 -61
- package/crates/team-agent/src/lifecycle/tests/restart_rebind_hotfix_252_red.rs +2 -0
- package/crates/team-agent/src/lifecycle/tests/startup_latency_contract.rs +40 -7
- package/crates/team-agent/src/lifecycle/tests/test_isolation_escape_contract.rs +59 -1
- package/crates/team-agent/src/lifecycle/tests/worker_spawn_env_red.rs +69 -26
- package/crates/team-agent/src/lifecycle/tests.rs +23 -13
- package/crates/team-agent/src/lifecycle/types.rs +61 -0
- package/crates/team-agent/src/lifecycle/worker_command_context.rs +85 -11
- package/crates/team-agent/src/mcp_server/tests/scoped.rs +100 -1
- package/crates/team-agent/src/mcp_server/tests.rs +196 -2
- package/crates/team-agent/src/messaging/delivery.rs +405 -40
- package/crates/team-agent/src/messaging/helpers.rs +2 -0
- package/crates/team-agent/src/messaging/leader_receiver.rs +53 -1
- package/crates/team-agent/src/messaging/results.rs +4 -0
- package/crates/team-agent/src/messaging/send.rs +34 -0
- package/crates/team-agent/src/messaging/tests/dup_inject.rs +406 -0
- package/crates/team-agent/src/messaging/tests/e23.rs +9 -0
- package/crates/team-agent/src/messaging/tests/leader_inject_acceptance.rs +66 -0
- package/crates/team-agent/src/messaging/tests/mod.rs +1 -0
- package/crates/team-agent/src/messaging/types.rs +4 -1
- package/crates/team-agent/src/model/enums.rs +14 -5
- package/crates/team-agent/src/model/permissions.rs +3 -0
- package/crates/team-agent/src/os_probe.rs +73 -2
- package/crates/team-agent/src/provider/adapter.rs +231 -4
- package/crates/team-agent/src/provider/adapters/cursor_agent.rs +86 -0
- package/crates/team-agent/src/provider/adapters/grok.rs +157 -0
- package/crates/team-agent/src/provider/adapters/mod.rs +2 -0
- package/crates/team-agent/src/provider/bypass_flags.rs +46 -2
- package/crates/team-agent/src/provider/classify.rs +4 -2
- package/crates/team-agent/src/provider/faults.rs +2 -1
- package/crates/team-agent/src/provider/mod.rs +11 -0
- package/crates/team-agent/src/provider/session/capture.rs +158 -20
- package/crates/team-agent/src/provider/session/context_fork/claude.rs +38 -1
- package/crates/team-agent/src/provider/session/context_fork/codex.rs +72 -1
- package/crates/team-agent/src/provider/session/context_fork/outcome.rs +57 -1
- package/crates/team-agent/src/provider/session/context_fork.rs +77 -3
- package/crates/team-agent/src/provider/session/mod.rs +18 -0
- package/crates/team-agent/src/provider/session/resume.rs +57 -0
- package/crates/team-agent/src/provider/session_scan/claude.rs +125 -1
- package/crates/team-agent/src/provider/session_scan/codex.rs +94 -1
- package/crates/team-agent/src/provider/session_scan/common.rs +204 -2
- package/crates/team-agent/src/provider/session_scan/copilot.rs +33 -1
- package/crates/team-agent/src/provider/session_scan/cursor.rs +538 -0
- package/crates/team-agent/src/provider/session_scan/grok.rs +288 -0
- package/crates/team-agent/src/provider/session_scan.rs +8 -0
- package/crates/team-agent/src/provider/submit_now.rs +94 -0
- package/crates/team-agent/src/provider/tests/adapter.rs +304 -0
- package/crates/team-agent/src/provider/types.rs +4 -2
- package/crates/team-agent/src/provider/wire.rs +23 -1
- package/crates/team-agent/src/state/persist.rs +301 -8
- package/crates/team-agent/src/state/repository.rs +5 -0
- package/crates/team-agent/src/tmux_backend/tests.rs +1737 -42
- package/crates/team-agent/src/tmux_backend.rs +1064 -75
- package/crates/team-agent/src/transport/tests/wire.rs +28 -2
- package/crates/team-agent/src/transport.rs +248 -1
- package/npm/install.mjs +129 -73
- package/package.json +4 -4
- package/skills/team-agent/SKILL.md +33 -238
- package/skills/team-agent/command-coverage.json +31 -0
- package/crates/team-agent/src/lifecycle/launch/fork_agent/completion.rs +0 -59
- package/crates/team-agent/src/lifecycle/launch/fork_finalize.rs +0 -488
- package/crates/team-agent/src/lifecycle/launch/fork_pending.rs +0 -109
- package/crates/team-agent/src/lifecycle/launch/fork_state.rs +0 -447
|
@@ -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
|
-
/// -
|
|
357
|
-
///
|
|
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
|
|
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
|
|