@team-agent/installer 0.5.66 → 0.5.69
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 +156 -0
- package/crates/team-agent/src/cli/emit.rs +6 -5
- package/crates/team-agent/src/cli/grok_slot.rs +299 -0
- package/crates/team-agent/src/cli/leader.rs +22 -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 +3 -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 +121 -5
- 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 +31 -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 +3 -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 +973 -75
- 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 +398 -26
- package/crates/team-agent/src/lifecycle/launch/add_agent_state.rs +80 -0
- package/crates/team-agent/src/lifecycle/launch/agent_state.rs +60 -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 +548 -0
- package/crates/team-agent/src/lifecycle/launch/cursor_mcp_iso.rs +120 -0
- package/crates/team-agent/src/lifecycle/launch/fork_agent.rs +208 -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 +482 -1
- package/crates/team-agent/src/lifecycle/launch/ownership.rs +40 -0
- package/crates/team-agent/src/lifecycle/launch/pi_mcp.rs +830 -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 +87 -3
- 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 +127 -25
- package/crates/team-agent/src/lifecycle/launch/spec_state.rs +140 -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 +107 -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 +99 -0
- package/crates/team-agent/src/lifecycle/profile_smoke.rs +52 -1
- package/crates/team-agent/src/lifecycle/restart/agent.rs +214 -160
- package/crates/team-agent/src/lifecycle/restart/common.rs +513 -37
- 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 +233 -6
- 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/claude_profile_launch_red.rs +24 -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 +464 -0
- package/crates/team-agent/src/lifecycle/tests/cursor_require_explicit_model_red.rs +247 -0
- package/crates/team-agent/src/lifecycle/tests/cursor_restart_resume_red.rs +353 -0
- package/crates/team-agent/src/lifecycle/tests/fixtures/pi_list_models_g0.stdout.txt +222 -0
- package/crates/team-agent/src/lifecycle/tests/g1_silent_faces.rs +787 -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 +485 -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/harvest2_a_batch_red.rs +1 -1
- 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/pi_catalog_red.rs +97 -0
- package/crates/team-agent/src/lifecycle/tests/pi_command_red.rs +128 -0
- package/crates/team-agent/src/lifecycle/tests/pi_compiler_red.rs +207 -0
- package/crates/team-agent/src/lifecycle/tests/pi_dual_entry_red.rs +838 -0
- package/crates/team-agent/src/lifecycle/tests/pi_executable_mcp_red.rs +320 -0
- package/crates/team-agent/src/lifecycle/tests/pi_lifecycle_doctor_red.rs +98 -0
- package/crates/team-agent/src/lifecycle/tests/pi_session_delivery_red.rs +216 -0
- package/crates/team-agent/src/lifecycle/tests/restart_rebind_hotfix_252_red.rs +3 -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 +30 -13
- package/crates/team-agent/src/lifecycle/types.rs +61 -0
- package/crates/team-agent/src/lifecycle/worker_command_context.rs +143 -12
- 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 +430 -41
- 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 +17 -6
- 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 +259 -6
- package/crates/team-agent/src/provider/adapters/cursor_agent.rs +89 -0
- package/crates/team-agent/src/provider/adapters/grok.rs +157 -0
- package/crates/team-agent/src/provider/adapters/mod.rs +3 -0
- package/crates/team-agent/src/provider/adapters/pi.rs +152 -0
- package/crates/team-agent/src/provider/bypass_flags.rs +47 -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 +78 -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 +205 -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/pi.rs +172 -0
- package/crates/team-agent/src/provider/session_scan.rs +12 -0
- package/crates/team-agent/src/provider/submit_now.rs +94 -0
- package/crates/team-agent/src/provider/tests/adapter.rs +384 -0
- package/crates/team-agent/src/provider/types.rs +4 -2
- package/crates/team-agent/src/provider/wire.rs +29 -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 +1116 -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 +32 -239
- 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
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
//! ---
|
|
2
|
+
//! purpose: Cursor agent CLI argv;role 走 .cursor/rules,MCP 走 mcp.json overlay
|
|
3
|
+
//! contract:
|
|
4
|
+
//! provides:
|
|
5
|
+
//! - name: cursor_agent_base_command
|
|
6
|
+
//! what: 只组已实测文档化 flag;mcp_config 不入 argv,由 launch overlay 写盘
|
|
7
|
+
//! boundary:
|
|
8
|
+
//! - 不调未文档化 flag(--system-prompt / --allowed-tools)
|
|
9
|
+
//! - 不写 grok 那种 cwd 独占闸
|
|
10
|
+
//! - 不打印代理值
|
|
11
|
+
//! maturity: wired
|
|
12
|
+
//! ---
|
|
13
|
+
//!
|
|
14
|
+
//! Cursor `agent` CLI(与 `cursor-agent` 同二进制)。主路径与
|
|
15
|
+
//! `.team/scripts/cursor_seat.sh` 实测一致:
|
|
16
|
+
//! `--trust --sandbox disabled --workspace <物理路径> [--force] [--model]`
|
|
17
|
+
//! Role 不入 argv,写 `<workspace>/.cursor/rules/*.mdc` + `alwaysApply: true`。
|
|
18
|
+
//! MCP 无 `--mcp-config`;身份必须写进 per-seat
|
|
19
|
+
//! `provider-config/<id>/cursor/.cursor/mcp.json` 的 env 表
|
|
20
|
+
//! (cursor 不把父进程 TEAM_AGENT_* 传给 MCP 子进程)。
|
|
21
|
+
//! spawn 把 `--workspace` 指到该工程根,并用 `--add-dir` 挂上真 workspace。
|
|
22
|
+
//!
|
|
23
|
+
//! 隐藏 flag `--system-prompt` / `--allowed-tools` 实测存在但 help 未列,
|
|
24
|
+
//! 随时可能消失。可以在注释里记录,代码里不许调。
|
|
25
|
+
//! `--allowed-tools` 正反行为未验证,不写「支持工具白名单」。
|
|
26
|
+
|
|
27
|
+
use crate::model::enums::AuthMode;
|
|
28
|
+
use crate::provider::adapter::BasicProviderAdapter;
|
|
29
|
+
use crate::provider::{McpConfig, ProviderError};
|
|
30
|
+
|
|
31
|
+
pub(crate) fn cursor_agent_launch_command(
|
|
32
|
+
adapter: &BasicProviderAdapter,
|
|
33
|
+
auth_mode: AuthMode,
|
|
34
|
+
mcp_config: Option<&McpConfig>,
|
|
35
|
+
system_prompt: Option<&str>,
|
|
36
|
+
model: Option<&str>,
|
|
37
|
+
tools: &[&str],
|
|
38
|
+
) -> Result<Vec<String>, ProviderError> {
|
|
39
|
+
cursor_agent_base_command(
|
|
40
|
+
adapter,
|
|
41
|
+
auth_mode,
|
|
42
|
+
mcp_config,
|
|
43
|
+
system_prompt,
|
|
44
|
+
model,
|
|
45
|
+
tools,
|
|
46
|
+
false,
|
|
47
|
+
None,
|
|
48
|
+
)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
pub(crate) fn cursor_agent_base_command(
|
|
52
|
+
adapter: &BasicProviderAdapter,
|
|
53
|
+
auth_mode: AuthMode,
|
|
54
|
+
mcp_config: Option<&McpConfig>,
|
|
55
|
+
system_prompt: Option<&str>,
|
|
56
|
+
model: Option<&str>,
|
|
57
|
+
tools: &[&str],
|
|
58
|
+
managed_mcp_config: bool,
|
|
59
|
+
effort: Option<crate::model::enums::ProviderEffort>,
|
|
60
|
+
) -> Result<Vec<String>, ProviderError> {
|
|
61
|
+
let mut argv = vec!["agent".to_string()];
|
|
62
|
+
// --trust 跳过 Workspace Trust 闸(已实测)。无此 flag 会停在 Do you trust。
|
|
63
|
+
argv.push("--trust".to_string());
|
|
64
|
+
if cursor_agent_dangerous_auto_approve(tools) {
|
|
65
|
+
argv.push("--force".to_string());
|
|
66
|
+
}
|
|
67
|
+
// 与 cursor_seat.sh 主路径一致。沙箱实际隔离面未再拆,但 flag 本身已实测。
|
|
68
|
+
argv.push("--sandbox".to_string());
|
|
69
|
+
argv.push("disabled".to_string());
|
|
70
|
+
if let Some(model) = model {
|
|
71
|
+
argv.push("--model".to_string());
|
|
72
|
+
argv.push(model.to_string());
|
|
73
|
+
}
|
|
74
|
+
// Cursor `--effort` flag 不存在;框架在调用方丢掉 effort。绝不发明 flag。
|
|
75
|
+
let _ = effort;
|
|
76
|
+
// system_prompt 不入 argv(help 无 --rules / --append-system-prompt)。
|
|
77
|
+
// launch 写 `<workspace>/.cursor/rules/team-agent-role-<agent_id>.mdc`。
|
|
78
|
+
// mcp_config 也不入 argv(无 --mcp-config)。launch 写
|
|
79
|
+
// `.team/runtime/provider-config/<id>/cursor/.cursor/mcp.json`
|
|
80
|
+
// 并 `agent mcp enable team_orchestrator`。这里收下以免静默丢弃。
|
|
81
|
+
let _ = (adapter, auth_mode, mcp_config, managed_mcp_config, system_prompt);
|
|
82
|
+
argv.push("--workspace".to_string());
|
|
83
|
+
argv.push("{workspace}".to_string());
|
|
84
|
+
Ok(argv)
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
pub(crate) fn cursor_agent_dangerous_auto_approve(tools: &[&str]) -> bool {
|
|
88
|
+
tools.contains(&"dangerous_auto_approve")
|
|
89
|
+
}
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
//!
|
|
2
|
+
//! purpose: Grok CLI argv + permission deny 映射;MCP 不走 CLI flag
|
|
3
|
+
//! contract: launch 写 `<cwd>/.grok/config.toml`;未登录 / 目录未信任必须拒绝启动。
|
|
4
|
+
//! 角色缺 model 必须拒绝启动(禁止内建 / team / CLI 任何隐式默认)。
|
|
5
|
+
//! 未知工具映射记成 Unsupported,不发明 deny 名
|
|
6
|
+
//! mcp_injection: dir_scoped —— 每席必须独立工作目录;同 cwd 多席会静默串台,故拒绝。
|
|
7
|
+
//! 对照 claude/codex 是 argv 作用域(`--mcp-config`),同目录多席没有这个问题。
|
|
8
|
+
//! 本版 exclusive 检查不读 per-agent cwd,一个 workspace 只支持一个 grok 席。
|
|
9
|
+
//! 这是 Provider::Grok 的能力边界,不是框架对所有 provider 的限制。
|
|
10
|
+
//! boundary: 只服务 Provider::Grok。不改 claude/codex/copilot 路径
|
|
11
|
+
//!
|
|
12
|
+
//! Grok CLI provider-local command builders + permission helpers.
|
|
13
|
+
//!
|
|
14
|
+
//! Mirrors `adapters/claude.rs` (0.5.67 provider-adapter step). Pure
|
|
15
|
+
//! flag-name adaptation over the claude skeleton — no new abstraction
|
|
16
|
+
//! layers, no public-API changes outside the provider dispatch.
|
|
17
|
+
//!
|
|
18
|
+
//! Grok CLI flag map (亲核 attest 0.5.67 + grok-full-help.txt):
|
|
19
|
+
//! bypass → `--always-approve` ("Auto-approve all tool executions")
|
|
20
|
+
//! system → `--rules <RULES>` ("Extra rules to append to the system prompt")
|
|
21
|
+
//! model → `-m, --model <MODEL>`
|
|
22
|
+
//! session → `-s, --session-id <SESSION_ID>` (fresh spawn)
|
|
23
|
+
//! resume → `-r, --resume [<ID_OR_TITLE>]` / `-c, --continue`
|
|
24
|
+
//! fork → `--fork-session` (with --resume)
|
|
25
|
+
//! effort → `--effort <level>` (alias of `--reasoning-effort`)
|
|
26
|
+
//! grok accepts low|medium|high|xhigh; CLI rejects `max`
|
|
27
|
+
//! deny → `--disallowed-tools` (compat alias `--disallowedTools`)
|
|
28
|
+
//! cwd → `--cwd <CWD>` / `-w, --worktree [<WORKTREE>]`
|
|
29
|
+
//!
|
|
30
|
+
//! No native `--mcp-config` flag on the Grok CLI (`grok mcp` is a subcommand)
|
|
31
|
+
//! → `native_mcp_config: false`; MCP reaches the worker via launch-path
|
|
32
|
+
//! `<cwd>/.grok/config.toml` (`apply_grok_mcp_overlay`).
|
|
33
|
+
|
|
34
|
+
use crate::model::enums::AuthMode;
|
|
35
|
+
use crate::provider::adapter::{next_session_token, BasicProviderAdapter};
|
|
36
|
+
use crate::provider::{McpConfig, ProviderError};
|
|
37
|
+
|
|
38
|
+
pub(crate) fn grok_launch_command(
|
|
39
|
+
adapter: &BasicProviderAdapter,
|
|
40
|
+
auth_mode: AuthMode,
|
|
41
|
+
mcp_config: Option<&McpConfig>,
|
|
42
|
+
system_prompt: Option<&str>,
|
|
43
|
+
model: Option<&str>,
|
|
44
|
+
tools: &[&str],
|
|
45
|
+
) -> Result<Vec<String>, ProviderError> {
|
|
46
|
+
let mut argv = grok_base_command(
|
|
47
|
+
adapter,
|
|
48
|
+
auth_mode,
|
|
49
|
+
mcp_config,
|
|
50
|
+
system_prompt,
|
|
51
|
+
model,
|
|
52
|
+
tools,
|
|
53
|
+
false,
|
|
54
|
+
None,
|
|
55
|
+
)?;
|
|
56
|
+
argv.push("--session-id".to_string());
|
|
57
|
+
argv.push(next_session_token());
|
|
58
|
+
Ok(argv)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
pub(crate) fn grok_base_command(
|
|
62
|
+
adapter: &BasicProviderAdapter,
|
|
63
|
+
auth_mode: AuthMode,
|
|
64
|
+
mcp_config: Option<&McpConfig>,
|
|
65
|
+
system_prompt: Option<&str>,
|
|
66
|
+
model: Option<&str>,
|
|
67
|
+
tools: &[&str],
|
|
68
|
+
managed_mcp_config: bool,
|
|
69
|
+
effort: Option<crate::model::enums::ProviderEffort>,
|
|
70
|
+
) -> Result<Vec<String>, ProviderError> {
|
|
71
|
+
let mut argv = vec!["grok".to_string()];
|
|
72
|
+
if grok_dangerous_auto_approve(tools) {
|
|
73
|
+
argv.push("--always-approve".to_string());
|
|
74
|
+
}
|
|
75
|
+
let model = match model.map(str::trim).filter(|value| !value.is_empty()) {
|
|
76
|
+
Some(model) => model,
|
|
77
|
+
None => {
|
|
78
|
+
return Err(ProviderError::Command(
|
|
79
|
+
"grok launch requires an explicit model. \
|
|
80
|
+
Without an explicit model the framework fills a built-in default (grok-4 for grok), \
|
|
81
|
+
so the seat silently gets a model and context window that are not in the role file, \
|
|
82
|
+
while argv still looks normal. The role file must name the model itself; \
|
|
83
|
+
built-in defaults, team-level defaults, and the Grok CLI global default are all implicit sources. \
|
|
84
|
+
Set the role front-matter field, for example:\n\
|
|
85
|
+
model: grok-4.6"
|
|
86
|
+
.to_string(),
|
|
87
|
+
));
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
argv.push("--model".to_string());
|
|
91
|
+
argv.push(model.to_string());
|
|
92
|
+
if let Some(effort) = effort {
|
|
93
|
+
// Grok accepts `--effort` as alias for `--reasoning-effort`.
|
|
94
|
+
argv.push("--effort".to_string());
|
|
95
|
+
argv.push(effort.as_str().to_string());
|
|
96
|
+
}
|
|
97
|
+
if let Some(prompt) = system_prompt {
|
|
98
|
+
argv.push("--rules".to_string());
|
|
99
|
+
argv.push(prompt.to_string());
|
|
100
|
+
}
|
|
101
|
+
// Grok CLI has no `--mcp-config` flag — the claude inline-MCP block is
|
|
102
|
+
// intentionally absent. Launch writes `<cwd>/.grok/config.toml`.
|
|
103
|
+
let _ = (adapter, auth_mode, mcp_config, managed_mcp_config);
|
|
104
|
+
for tool in grok_disallowed_tools(tools) {
|
|
105
|
+
argv.push("--disallowedTools".to_string());
|
|
106
|
+
argv.push(tool.to_string());
|
|
107
|
+
}
|
|
108
|
+
Ok(argv)
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
pub(crate) fn grok_dangerous_auto_approve(tools: &[&str]) -> bool {
|
|
112
|
+
tools.contains(&"dangerous_auto_approve")
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
pub(crate) fn grok_disallowed_tools(tools: &[&str]) -> Vec<&'static str> {
|
|
116
|
+
let mut disallowed = Vec::new();
|
|
117
|
+
for tool in [
|
|
118
|
+
"execute_bash",
|
|
119
|
+
"fs_read",
|
|
120
|
+
"fs_write",
|
|
121
|
+
"fs_list",
|
|
122
|
+
"network",
|
|
123
|
+
"git_diff",
|
|
124
|
+
"mcp_team",
|
|
125
|
+
"provider_builtin",
|
|
126
|
+
] {
|
|
127
|
+
if tools.contains(&tool) {
|
|
128
|
+
continue;
|
|
129
|
+
}
|
|
130
|
+
match grok_tool_mapping(tool) {
|
|
131
|
+
GrokToolMapping::Deny(names) => disallowed.extend(names),
|
|
132
|
+
GrokToolMapping::Unsupported | GrokToolMapping::Bypass => {}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
disallowed
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/// Canonical tool → grok CLI deny names. Unknown tools stay Unsupported
|
|
139
|
+
/// (no invented `--disallowedTools` token).
|
|
140
|
+
pub(crate) fn grok_tool_mapping(tool: &str) -> GrokToolMapping {
|
|
141
|
+
match tool {
|
|
142
|
+
"execute_bash" => GrokToolMapping::Deny(&["Bash"]),
|
|
143
|
+
"fs_read" => GrokToolMapping::Deny(&["Read"]),
|
|
144
|
+
"fs_write" => GrokToolMapping::Deny(&["Edit", "Write", "MultiEdit", "NotebookEdit"]),
|
|
145
|
+
"fs_list" => GrokToolMapping::Deny(&["Glob", "Grep"]),
|
|
146
|
+
"dangerous_auto_approve" => GrokToolMapping::Bypass,
|
|
147
|
+
"network" | "git_diff" | "mcp_team" | "provider_builtin" => GrokToolMapping::Unsupported,
|
|
148
|
+
_ => GrokToolMapping::Unsupported,
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
153
|
+
pub(crate) enum GrokToolMapping {
|
|
154
|
+
Deny(&'static [&'static str]),
|
|
155
|
+
Bypass,
|
|
156
|
+
Unsupported,
|
|
157
|
+
}
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
//! ---
|
|
2
|
+
//! purpose: Pi CLI 的纯工具映射与 fresh/resume argv 构造
|
|
3
|
+
//! contract:
|
|
4
|
+
//! provides:
|
|
5
|
+
//! - name: build_pi_command_argv
|
|
6
|
+
//! what: 仅从已验证输入构造隔离的 regular-TUI Pi argv
|
|
7
|
+
//! boundary:
|
|
8
|
+
//! - 不发现 executable、catalog、adapter 或 MCP 配置
|
|
9
|
+
//! - 除 resume exact backing 存在性外不读文件;不写文件、不启动进程
|
|
10
|
+
//! maturity: wired
|
|
11
|
+
//! ---
|
|
12
|
+
|
|
13
|
+
use std::collections::BTreeSet;
|
|
14
|
+
use std::path::Path;
|
|
15
|
+
|
|
16
|
+
use crate::model::enums::ProviderEffort;
|
|
17
|
+
use crate::provider::ProviderError;
|
|
18
|
+
|
|
19
|
+
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
20
|
+
pub(crate) enum PiToolMapping {
|
|
21
|
+
Mcp,
|
|
22
|
+
Builtin(&'static [&'static str]),
|
|
23
|
+
Unsupported,
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/// ---
|
|
27
|
+
/// purpose: 把 Team tool category 映射为 exact Pi builtin/proxy names
|
|
28
|
+
/// returns: 单个或多个 builtin、MCP proxy 或 Unsupported
|
|
29
|
+
/// ---
|
|
30
|
+
pub(crate) fn pi_tool_mapping(category: &str) -> PiToolMapping {
|
|
31
|
+
match category {
|
|
32
|
+
"mcp_team" => PiToolMapping::Mcp,
|
|
33
|
+
"fs_read" => PiToolMapping::Builtin(&["read"]),
|
|
34
|
+
"fs_list" => PiToolMapping::Builtin(&["grep", "find", "ls"]),
|
|
35
|
+
"fs_write" => PiToolMapping::Builtin(&["edit", "write"]),
|
|
36
|
+
"execute_bash" => PiToolMapping::Builtin(&["bash"]),
|
|
37
|
+
_ => PiToolMapping::Unsupported,
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
#[derive(Debug, Clone, Copy)]
|
|
42
|
+
pub(crate) enum PiSessionSelector<'a> {
|
|
43
|
+
Fresh { session_id: &'a str },
|
|
44
|
+
Resume { path: &'a Path },
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
pub(crate) struct PiCommandRequest<'a> {
|
|
48
|
+
pub executable: &'a Path,
|
|
49
|
+
pub extension: &'a Path,
|
|
50
|
+
pub model: &'a str,
|
|
51
|
+
pub effort: ProviderEffort,
|
|
52
|
+
pub system_prompt: &'a str,
|
|
53
|
+
pub tool_categories: &'a [&'a str],
|
|
54
|
+
pub session_dir: &'a Path,
|
|
55
|
+
pub session: PiSessionSelector<'a>,
|
|
56
|
+
pub agent_id: &'a str,
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/// ---
|
|
60
|
+
/// purpose: 从已验证 semantic request 构造无 ambient flag 的 Pi argv
|
|
61
|
+
/// returns: exact ordered fresh/resume argv
|
|
62
|
+
/// errors: 必需字段、mcp_team 或工具 category 非法时返回 ProviderError
|
|
63
|
+
/// ---
|
|
64
|
+
pub(crate) fn build_pi_command_argv(
|
|
65
|
+
request: PiCommandRequest<'_>,
|
|
66
|
+
) -> Result<Vec<String>, ProviderError> {
|
|
67
|
+
if request.executable.as_os_str().is_empty()
|
|
68
|
+
|| request.extension.as_os_str().is_empty()
|
|
69
|
+
|| request.session_dir.as_os_str().is_empty()
|
|
70
|
+
|| request.model.trim().is_empty()
|
|
71
|
+
|| request.system_prompt.trim().is_empty()
|
|
72
|
+
|| request.agent_id.trim().is_empty()
|
|
73
|
+
{
|
|
74
|
+
return Err(ProviderError::Command(
|
|
75
|
+
"Pi command requires executable, extension, model, prompt, session directory, and agent id"
|
|
76
|
+
.to_string(),
|
|
77
|
+
));
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
let mut tools = BTreeSet::new();
|
|
81
|
+
for category in request.tool_categories {
|
|
82
|
+
match pi_tool_mapping(category) {
|
|
83
|
+
PiToolMapping::Mcp => {
|
|
84
|
+
tools.insert("mcp");
|
|
85
|
+
}
|
|
86
|
+
PiToolMapping::Builtin(names) => tools.extend(names.iter().copied()),
|
|
87
|
+
PiToolMapping::Unsupported => {
|
|
88
|
+
return Err(ProviderError::Command(format!(
|
|
89
|
+
"Pi does not support Team Agent tool category {category:?}"
|
|
90
|
+
)));
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
if !tools.contains("mcp") {
|
|
95
|
+
return Err(ProviderError::Command(
|
|
96
|
+
"Pi command requires mcp_team".to_string(),
|
|
97
|
+
));
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
let mut argv = vec![
|
|
101
|
+
request.executable.to_string_lossy().into_owned(),
|
|
102
|
+
"--no-extensions".to_string(),
|
|
103
|
+
"-e".to_string(),
|
|
104
|
+
request.extension.to_string_lossy().into_owned(),
|
|
105
|
+
"--no-approve".to_string(),
|
|
106
|
+
"--no-context-files".to_string(),
|
|
107
|
+
"--no-skills".to_string(),
|
|
108
|
+
"--no-prompt-templates".to_string(),
|
|
109
|
+
"--tui-mode".to_string(),
|
|
110
|
+
"regular".to_string(),
|
|
111
|
+
"--model".to_string(),
|
|
112
|
+
request.model.to_string(),
|
|
113
|
+
"--thinking".to_string(),
|
|
114
|
+
request.effort.as_str().to_string(),
|
|
115
|
+
"--system-prompt".to_string(),
|
|
116
|
+
request.system_prompt.to_string(),
|
|
117
|
+
"--tools".to_string(),
|
|
118
|
+
tools.into_iter().collect::<Vec<_>>().join(","),
|
|
119
|
+
"--session-dir".to_string(),
|
|
120
|
+
request.session_dir.to_string_lossy().into_owned(),
|
|
121
|
+
];
|
|
122
|
+
// The shared lifecycle materializer always revalidates resume root/path/header.
|
|
123
|
+
// Keep the pure argv builder usable before a fixture root is materialized, while
|
|
124
|
+
// refusing a missing exact file once the recorded path's parent exists.
|
|
125
|
+
match request.session {
|
|
126
|
+
PiSessionSelector::Fresh { session_id } if !session_id.trim().is_empty() => {
|
|
127
|
+
argv.push("--session-id".to_string());
|
|
128
|
+
argv.push(session_id.to_string());
|
|
129
|
+
}
|
|
130
|
+
PiSessionSelector::Resume { path }
|
|
131
|
+
if !path.as_os_str().is_empty()
|
|
132
|
+
&& (!path.parent().is_some_and(Path::is_dir) || path.is_file()) =>
|
|
133
|
+
{
|
|
134
|
+
argv.push("--session".to_string());
|
|
135
|
+
argv.push(path.to_string_lossy().into_owned());
|
|
136
|
+
}
|
|
137
|
+
PiSessionSelector::Resume { path } if !path.as_os_str().is_empty() => {
|
|
138
|
+
return Err(ProviderError::ResumeUnavailable(format!(
|
|
139
|
+
"Pi exact session backing is missing: {}",
|
|
140
|
+
path.display()
|
|
141
|
+
)));
|
|
142
|
+
}
|
|
143
|
+
_ => {
|
|
144
|
+
return Err(ProviderError::Command(
|
|
145
|
+
"Pi command requires a non-empty session selector".to_string(),
|
|
146
|
+
));
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
argv.push("--name".to_string());
|
|
150
|
+
argv.push(request.agent_id.to_string());
|
|
151
|
+
Ok(argv)
|
|
152
|
+
}
|
|
@@ -8,6 +8,8 @@
|
|
|
8
8
|
//! - claude/claude_code → `--dangerously-skip-permissions`
|
|
9
9
|
//! - codex → `--dangerously-bypass-approvals-and-sandbox`
|
|
10
10
|
//! - copilot → `--allow-all`(0.3.27 P1 E54 symptom 2 起)
|
|
11
|
+
//! - grok → `--always-approve`
|
|
12
|
+
//! - cursor_agent → `--force`
|
|
11
13
|
//!
|
|
12
14
|
//! 未定义(返回 None)的 provider:调用侧必须 fail-loud(见
|
|
13
15
|
//! `resolved_tool_strings_for_command`),不得静默 fallback。
|
|
@@ -20,14 +22,24 @@ pub(crate) fn provider_bypass_flag(provider: Provider) -> Option<&'static str> {
|
|
|
20
22
|
Provider::Claude | Provider::ClaudeCode => Some("--dangerously-skip-permissions"),
|
|
21
23
|
Provider::Codex => Some("--dangerously-bypass-approvals-and-sandbox"),
|
|
22
24
|
Provider::Copilot => Some("--allow-all"),
|
|
25
|
+
Provider::Grok => Some("--always-approve"),
|
|
26
|
+
Provider::CursorAgent => Some("--force"),
|
|
27
|
+
Provider::Pi => None,
|
|
23
28
|
// TODO: 查 gemini_cli 的等价 bypass 参数;未定义前 fail-loud。
|
|
24
29
|
Provider::GeminiCli => None,
|
|
25
30
|
Provider::Fake => None,
|
|
26
31
|
}
|
|
27
32
|
}
|
|
28
33
|
|
|
29
|
-
/// 0.5.66 §3.2 跨 workspace 兼容警示用:扫 argv tokens
|
|
30
|
-
///
|
|
34
|
+
/// 0.5.66 §3.2 跨 workspace 兼容警示用:扫 **team-agent 进程自己的** argv tokens
|
|
35
|
+
/// 找已知 bypass flag。**只做检测,不做行为决策**(0.6.0 删)。
|
|
36
|
+
///
|
|
37
|
+
/// 不认 `--force`:那是 team-agent 自己的 CLI 旗(`init --force` /
|
|
38
|
+
/// `remove-agent --confirm --force` / `restart --force`),与 cursor worker
|
|
39
|
+
/// 的 `--force` 撞名。本函数看不到「当前在看哪个 provider 的 argv」,
|
|
40
|
+
/// 认 `--force` 会把既有非 grok/cursor 路径误判成 bypass。
|
|
41
|
+
/// cursor worker 的 bypass 仍走 [`provider_bypass_flag`],不走这条检测面。
|
|
42
|
+
/// `--always-approve` 可以认:team-agent 自己没有这个旗。
|
|
31
43
|
///
|
|
32
44
|
/// TODO(0.6.0): remove
|
|
33
45
|
pub(crate) fn detect_bypass_flag_in_argv(argv_tokens: &[String]) -> Option<&'static str> {
|
|
@@ -43,6 +55,9 @@ pub(crate) fn detect_bypass_flag_in_argv(argv_tokens: &[String]) -> Option<&'sta
|
|
|
43
55
|
if token == "--allow-all" || token == "--yolo" {
|
|
44
56
|
return Some("--allow-all");
|
|
45
57
|
}
|
|
58
|
+
if token == "--always-approve" {
|
|
59
|
+
return Some("--always-approve");
|
|
60
|
+
}
|
|
46
61
|
}
|
|
47
62
|
None
|
|
48
63
|
}
|
|
@@ -77,4 +92,34 @@ mod tests {
|
|
|
77
92
|
assert_eq!(provider_bypass_flag(Provider::GeminiCli), None);
|
|
78
93
|
assert_eq!(provider_bypass_flag(Provider::Fake), None);
|
|
79
94
|
}
|
|
95
|
+
|
|
96
|
+
#[test]
|
|
97
|
+
fn grok_and_cursor_bypass_flags() {
|
|
98
|
+
assert_eq!(
|
|
99
|
+
provider_bypass_flag(Provider::Grok),
|
|
100
|
+
Some("--always-approve")
|
|
101
|
+
);
|
|
102
|
+
assert_eq!(
|
|
103
|
+
provider_bypass_flag(Provider::CursorAgent),
|
|
104
|
+
Some("--force")
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
#[test]
|
|
109
|
+
fn detect_bypass_flag_ignores_team_agent_force() {
|
|
110
|
+
let argv = [
|
|
111
|
+
"team-agent".to_string(),
|
|
112
|
+
"remove-agent".to_string(),
|
|
113
|
+
"x".to_string(),
|
|
114
|
+
"--confirm".to_string(),
|
|
115
|
+
"--force".to_string(),
|
|
116
|
+
];
|
|
117
|
+
assert_eq!(
|
|
118
|
+
detect_bypass_flag_in_argv(&argv),
|
|
119
|
+
None,
|
|
120
|
+
"detect_bypass_flag_in_argv scans team-agent process argv, not worker argv; \
|
|
121
|
+
`remove-agent --force` must not look like a provider bypass flag; got {:?}",
|
|
122
|
+
detect_bypass_flag_in_argv(&argv)
|
|
123
|
+
);
|
|
124
|
+
}
|
|
80
125
|
}
|
|
@@ -215,7 +215,8 @@ fn latest_explicit_error_fact_for_record(
|
|
|
215
215
|
Provider::Claude | Provider::ClaudeCode => claude_latest_explicit_error_fact(record),
|
|
216
216
|
// C-3-5 cr verdict: copilot N35 通知不依赖 turn-state 分类;一期 Unknown,
|
|
217
217
|
// 与 GeminiCli/Fake 同精神。二期接 sqlite turns 表后再回填。
|
|
218
|
-
Provider::Copilot | Provider::
|
|
218
|
+
Provider::Copilot | Provider::Grok | Provider::CursorAgent | Provider::Pi | Provider::GeminiCli
|
|
219
|
+
| Provider::Fake => None,
|
|
219
220
|
}
|
|
220
221
|
}
|
|
221
222
|
|
|
@@ -378,7 +379,8 @@ fn extract_lifecycle_facts(
|
|
|
378
379
|
Provider::Codex => codex_lifecycle_fact(record),
|
|
379
380
|
// C-3-1 cr verdict: copilot lifecycle facts 一期不导出(classify→None,
|
|
380
381
|
// Unknown);二期读 sqlite turns 表(turn_index/assistant_response)。
|
|
381
|
-
Provider::Copilot | Provider::
|
|
382
|
+
Provider::Copilot | Provider::Grok | Provider::CursorAgent | Provider::Pi | Provider::GeminiCli
|
|
383
|
+
| Provider::Fake => None,
|
|
382
384
|
})
|
|
383
385
|
.collect()
|
|
384
386
|
}
|
|
@@ -46,7 +46,8 @@ fn fault_fact(provider: Provider, record: &serde_json::Value) -> Option<FaultFac
|
|
|
46
46
|
match provider {
|
|
47
47
|
Provider::Claude | Provider::ClaudeCode => claude_fault_fact(record),
|
|
48
48
|
Provider::Codex => codex_fault_fact(record),
|
|
49
|
-
Provider::Copilot | Provider::
|
|
49
|
+
Provider::Copilot | Provider::Grok | Provider::CursorAgent | Provider::Pi | Provider::GeminiCli
|
|
50
|
+
| Provider::Fake => None,
|
|
50
51
|
}
|
|
51
52
|
}
|
|
52
53
|
|
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
//! ---
|
|
2
|
+
//! purpose: provider 命令构造与会话观察入口
|
|
3
|
+
//! contract:
|
|
4
|
+
//! provides:
|
|
5
|
+
//! - name: adapter
|
|
6
|
+
//! what: 按 Provider 分发 launch/capability
|
|
7
|
+
//! boundary:
|
|
8
|
+
//! - 不把 observation 写成 ownership
|
|
9
|
+
//! maturity: wired
|
|
10
|
+
//! ---
|
|
1
11
|
//!
|
|
2
12
|
//! step 8 · provider — type + trait SKELETON (ROUND-0).
|
|
3
13
|
//!
|
|
@@ -44,6 +54,7 @@ pub mod faults;
|
|
|
44
54
|
pub mod session;
|
|
45
55
|
pub mod session_scan;
|
|
46
56
|
pub mod startup_prompt;
|
|
57
|
+
pub mod submit_now;
|
|
47
58
|
pub mod types;
|
|
48
59
|
/// 0.4.x: provider wire-format helpers — single source of truth for
|
|
49
60
|
/// `Provider` ↔ string conversions (replaces 7 hand-rolled match copies).
|