feat(agent/access): 强化项目级运行态接入 #18
@ -126,8 +126,8 @@ Codex / Claude 项目
|
|||||||
- depends: A2. 分层 Agent runtime readiness 本体
|
- depends: A2. 分层 Agent runtime readiness 本体
|
||||||
- files: src-tauri/Cargo.toml, src-tauri/Cargo.lock, src-tauri/src/lib.rs, src-tauri/src/commands/settings.rs
|
- files: src-tauri/Cargo.toml, src-tauri/Cargo.lock, src-tauri/src/lib.rs, src-tauri/src/commands/settings.rs
|
||||||
- acceptance: "[Tauri command] set_agent_autostart(enabled) → 默认 false,可启用、查询并撤销;重复调用幂等;不启动第二个炼境实例,不修改项目文件或 pnpm-lock.yaml。"
|
- acceptance: "[Tauri command] set_agent_autostart(enabled) → 默认 false,可启用、查询并撤销;重复调用幂等;不启动第二个炼境实例,不修改项目文件或 pnpm-lock.yaml。"
|
||||||
- decision_note: "用户于 2026-09-23 明确恢复 A6,但限定正式安装版:默认关闭,debug/target 构建拒绝启用,查询/启停幂等,复用 single-instance;updater 单独建设。"
|
- decision_note: "用户于 2026-09-23 明确恢复 A6,但限定正式安装版:默认关闭,debug/target 构建拒绝启用,查询/启停幂等,复用 single-instance;开发前先退出正式版,不并行运行两个实例;updater 单独建设。"
|
||||||
- done_note: "接入官方 tauri-plugin-autostart,保留既有 single-instance;query/set command 对重复调用幂等,debug 与 target/release 路径拒绝启用,未改 pnpm-lock。路径 fixture、cargo test --lib 178/178 与 cargo check --release 通过;`mise exec -- pnpm build:local` 已生成 NSIS/MSI,NSIS SHA-256=82F05ECB0A68E5B87FCD5D50906A64A4CD07B6E9169A07CB2F20D6130FE36C12。正式安装后的注册表效果留待安装包 human_verify。"
|
- done_note: "接入官方 tauri-plugin-autostart,保留既有 single-instance;query/set command 通过纯状态机 fixture 证明重复调用幂等,debug 与 target/release 路径拒绝启用,未改 pnpm-lock。路径 fixture、cargo test --lib 179/179 与 cargo check --release 通过;`mise exec -- pnpm build:local` 已生成 NSIS/MSI,NSIS SHA-256=82F05ECB0A68E5B87FCD5D50906A64A4CD07B6E9169A07CB2F20D6130FE36C12。正式安装后的注册表效果留待安装包 human_verify。"
|
||||||
|
|
||||||
### ✅ A7. Agent 连接状态与自启动 UI 投影
|
### ✅ A7. Agent 连接状态与自启动 UI 投影
|
||||||
- status: done
|
- status: done
|
||||||
|
|||||||
@ -133,6 +133,7 @@ acceptance 是 agent 自验的唯一判断依据,必须是可执行断言:
|
|||||||
- readiness 分为 `configured → reachable → handshake → tools_ready → reload_required`。配置存在不等于当前任务已加载;停在哪层,就只修哪一层。
|
- readiness 分为 `configured → reachable → handshake → tools_ready → reload_required`。配置存在不等于当前任务已加载;停在哪层,就只修哪一层。
|
||||||
- `.lian-jing/context.json` 是项目身份唯一来源;Skill 和插件不复制项目身份、Gitea 凭证或 MCP 实现。
|
- `.lian-jing/context.json` 是项目身份唯一来源;Skill 和插件不复制项目身份、Gitea 凭证或 MCP 实现。
|
||||||
- Windows 登录自启动只服务正式安装版,默认关闭且由用户主动启用;debug 和 `target/release` 直接运行明确拒绝注册。single-instance 继续保证同一时间只有一个炼境实例。
|
- Windows 登录自启动只服务正式安装版,默认关闭且由用户主动启用;debug 和 `target/release` 直接运行明确拒绝注册。single-instance 继续保证同一时间只有一个炼境实例。
|
||||||
|
- 开发炼境前先从托盘完全退出正式安装版;不得把正式版与 `pnpm tauri dev` 并行运行。single-instance 是运行时兜底,不替代这一开发约定。
|
||||||
- updater 是独立的发布能力,不属于自启动或 readiness 的完成条件。
|
- updater 是独立的发布能力,不属于自启动或 readiness 的完成条件。
|
||||||
|
|
||||||
这套 scope 是单用户本机的误操作隔离,不是多租户认证。威胁模型变化前,不向项目配置写持久 token。
|
这套 scope 是单用户本机的误操作隔离,不是多租户认证。威胁模型变化前,不向项目配置写持久 token。
|
||||||
|
|||||||
@ -604,6 +604,28 @@ pub struct AgentAutostartStatus {
|
|||||||
pub detail: String,
|
pub detail: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
enum AutostartAction {
|
||||||
|
RefuseEnable,
|
||||||
|
Noop,
|
||||||
|
Enable,
|
||||||
|
Disable,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn plan_autostart_action(eligible: bool, current: bool, requested: bool) -> AutostartAction {
|
||||||
|
if !eligible && requested {
|
||||||
|
return AutostartAction::RefuseEnable;
|
||||||
|
}
|
||||||
|
if !eligible || current == requested {
|
||||||
|
return AutostartAction::Noop;
|
||||||
|
}
|
||||||
|
if requested {
|
||||||
|
AutostartAction::Enable
|
||||||
|
} else {
|
||||||
|
AutostartAction::Disable
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn autostart_eligibility(is_debug: bool, executable: &Path) -> (bool, String, String) {
|
fn autostart_eligibility(is_debug: bool, executable: &Path) -> (bool, String, String) {
|
||||||
let executable_text = executable.to_string_lossy().to_string();
|
let executable_text = executable.to_string_lossy().to_string();
|
||||||
if !cfg!(target_os = "windows") {
|
if !cfg!(target_os = "windows") {
|
||||||
@ -688,18 +710,15 @@ pub fn set_agent_autostart(
|
|||||||
enabled: bool,
|
enabled: bool,
|
||||||
) -> Result<AgentAutostartStatus, String> {
|
) -> Result<AgentAutostartStatus, String> {
|
||||||
let before = get_agent_autostart_status(app.clone())?;
|
let before = get_agent_autostart_status(app.clone())?;
|
||||||
if !before.eligible {
|
match plan_autostart_action(before.eligible, before.enabled, enabled) {
|
||||||
if enabled {
|
AutostartAction::RefuseEnable => return Err(before.detail),
|
||||||
return Err(before.detail);
|
AutostartAction::Noop => return Ok(before),
|
||||||
}
|
AutostartAction::Enable => {
|
||||||
return Ok(before);
|
|
||||||
}
|
|
||||||
if before.enabled != enabled {
|
|
||||||
if enabled {
|
|
||||||
app.autolaunch()
|
app.autolaunch()
|
||||||
.enable()
|
.enable()
|
||||||
.map_err(|error| error.to_string())?;
|
.map_err(|error| error.to_string())?;
|
||||||
} else {
|
}
|
||||||
|
AutostartAction::Disable => {
|
||||||
app.autolaunch()
|
app.autolaunch()
|
||||||
.disable()
|
.disable()
|
||||||
.map_err(|error| error.to_string())?;
|
.map_err(|error| error.to_string())?;
|
||||||
@ -1331,4 +1350,32 @@ mod tests {
|
|||||||
assert_eq!(kind, "installed_release");
|
assert_eq!(kind, "installed_release");
|
||||||
assert!(detail.contains("正式安装版"));
|
assert!(detail.contains("正式安装版"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn autostart_transition_is_idempotent_and_refuses_ineligible_enable() {
|
||||||
|
assert_eq!(
|
||||||
|
plan_autostart_action(false, false, true),
|
||||||
|
AutostartAction::RefuseEnable
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
plan_autostart_action(false, false, false),
|
||||||
|
AutostartAction::Noop
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
plan_autostart_action(true, false, false),
|
||||||
|
AutostartAction::Noop
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
plan_autostart_action(true, true, true),
|
||||||
|
AutostartAction::Noop
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
plan_autostart_action(true, false, true),
|
||||||
|
AutostartAction::Enable
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
plan_autostart_action(true, true, false),
|
||||||
|
AutostartAction::Disable
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user