feat(onboarding): lian-jing skill 双投影到 Claude,接入包升至 1.6.0
All checks were successful
Push & PR Check / check (push) Successful in 1m4s
All checks were successful
Push & PR Check / check (push) Successful in 1m4s
- 同一模板同时写 .agents/skills(Codex、DSH)与 .claude/skills(Claude Code) - verify_onboarding 新增「Claude 炼境技能已分发」检查 - skill 降级步骤改为三端通用,提示无开发变量工具即连的是全局地址 - capability-packs supported_clients 增加 dsh Feature-Confirmed: true Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
8babc545c3
commit
f4e75dc91f
@ -66,12 +66,13 @@ progress: 0
|
||||
- acceptance: "agent_verify: [三端无头探针] 在 enterprise 目录 Claude 与 DSH 的 C 项均看到开发变量工具(项目工具集),E 项成功;项目目录外的会话不获得他项目工具。"
|
||||
- 注:吸收原 project-dev-variables V17(Claude 以 local scope + headersHelper 取值)。
|
||||
|
||||
### 🔵 P2 — Claude skill 投影
|
||||
- status: in_progress
|
||||
### ✅ P2 — Claude skill 投影
|
||||
- status: done
|
||||
- complexity: S
|
||||
- files: src-tauri/src/commands/onboarding.rs, src-tauri/resources/onboarding/
|
||||
- depends: H3
|
||||
- acceptance: "agent_verify: [cargo test onboarding] 接入包同时写 .claude/skills/lian-jing/SKILL.md,内容与 .agents/skills 单一来源一致;[Claude 无头探针] B 项看到 lian-jing。"
|
||||
- verification: "2026-10-01:同一模板双投影到 .agents/skills 与 .claude/skills;verify_onboarding 新增「Claude 炼境技能已分发」(检查链 12 项);base-onboarding 升至 1.6.0,supported_clients 增 dsh;skill 降级步骤改为三端通用并提示「无开发变量工具即连的是全局地址」。新增测试 skill_is_projected_to_codex_and_claude_from_one_source;cargo test --locked 229 passed / 5 ignored。Enterprise 分发后 verify_onboarding 14/14,两份 skill 逐字节一致;Claude 无头会话 init 事件 skills 与 slash_commands 均含 lian-jing(基线探针时为不存在)。"
|
||||
|
||||
### 📋 P3 — 稳定 helper 入口,项目配置去本机路径
|
||||
- status: todo
|
||||
|
||||
@ -25,7 +25,7 @@ contracts:
|
||||
- ".lian-jing/context.json"
|
||||
- ".lian-jing/capability-packs.json"
|
||||
- ".claude/liangjing.json"
|
||||
doc: "`.lian-jing/context.json` 是 project_id 的工具无关单一事实来源;`.claude/liangjing.json` 仅为兼容投影;`.lian-jing/capability-packs.json` 是炼境分发基线的版本描述。迁移必须保留未知字段;验证必须返回显式状态与 upgrade_hint;升级仅覆盖炼境托管文件,绝不覆盖项目定制或手工 MCP 配置,且不得以客户端全局配置或项目 UI 身份替代项目根目录上下文。"
|
||||
doc: "`.lian-jing/context.json` 是 project_id 的工具无关单一事实来源;`.claude/liangjing.json` 仅为兼容投影;`.lian-jing/capability-packs.json` 是炼境分发基线的版本描述。lian-jing skill 以同一模板双投影:`.agents/skills/lian-jing/`(Codex、DSH 读取)与 `.claude/skills/lian-jing/`(Claude Code 不读 .agents/skills),两份内容必须一致。迁移必须保留未知字段;验证必须返回显式状态与 upgrade_hint;升级仅覆盖炼境托管文件,绝不覆盖项目定制或手工 MCP 配置,且不得以客户端全局配置或项目 UI 身份替代项目根目录上下文。"
|
||||
|
||||
- label: Tauri command 接口(前后端契约)
|
||||
paths:
|
||||
|
||||
@ -16,11 +16,11 @@ description: 读取炼境项目健康状态,并使用炼境 MCP 的项目管
|
||||
5. 交付、Gitea、CI、蓝图等平台状态优先通过 MCP 查询,不凭静态文档猜测。
|
||||
6. 合并 PR 前调用 `get_delivery_status(project_id)`,向用户展示 PR 编号、完整 head SHA、CI 与 review。只有当前用户明确确认该 PR 与 SHA 后,才调用 `merge_pull_request(project_id, pr_number, expected_head_sha, confirmed=true)`;合并后再次读取交付状态。不得自行推断确认。
|
||||
7. 生成 CI workflow 时先调用 `plan_cicd_workflow(project_id, workflow_type)`,向用户展示目标文件、变更类型、`content_digest`、工具链来源与所需 secret 名称;只有用户明确确认这份摘要后,才以同一 digest 调用 `apply_cicd_workflow(..., confirmed=true)`。该流程只写项目 workflow,不配置 secret、不触发 CI 或部署;不得通过 MCP 传服务器地址、命令、路径或 secret 值,部署类配置先由用户在炼境 UI 保存。
|
||||
8. 需要测试账号或开发变量(登录自验、沙箱 key 等)时,先调用 `list_project_dev_variables` 查找:已配置则用 `read_project_test_account` / `read_project_dev_variable` 单项读取;没有则用 `register_project_test_account` 登记名称、目标系统、非生产环境与用途,并请用户在炼境项目 UI「开发变量」中填写。不得在对话中向用户索要明文密码,不得登记生产账号,不得把读到的值写入受 Git 跟踪的文件。读取因缺少项目认证被拒时(当前仅 Codex 经 helper 验证可读),如实报告并改用项目原有配置方式,不得绕过认证。
|
||||
8. 需要测试账号或开发变量(登录自验、沙箱 key 等)时,先调用 `list_project_dev_variables` 查找:已配置则用 `read_project_test_account` / `read_project_dev_variable` 单项读取;没有则用 `register_project_test_account` 登记名称、目标系统、非生产环境与用途,并请用户在炼境项目 UI「开发变量」中填写。不得在对话中向用户索要明文密码,不得登记生产账号,不得把读到的值写入受 Git 跟踪的文件。读取因缺少项目认证被拒时,如实报告并改用项目原有配置方式,不得绕过认证。若 lian-jing 工具中根本没有 `list_project_dev_variables`,说明当前客户端连的是全局地址 `/mcp` 而非本项目地址,按下方 `configured` 一步处理。
|
||||
|
||||
如果 MCP 未出现,按以下顺序降级,不猜测状态:
|
||||
|
||||
1. `configured`:读取 `.codex/config.toml`,确认 `lian-jing` 指向 `http://127.0.0.1:<port>/mcp/projects/<canonical project_id>`;缺失或 legacy 时通过炼境重新 `inject_mcp`,手工同名 server 不覆盖。
|
||||
1. `configured`:确认当前客户端的 `lian-jing` 指向 `http://127.0.0.1:<port>/mcp/projects/<canonical project_id>`——Codex 看项目 `.codex/config.toml`,Claude Code 看 `~/.claude.json` 中本项目的 local 条目(优先于 user 级全局条目),DSH 看 `~/.dsh/cordis.patch.yml`。缺失或仍指向全局 `/mcp` 时通过炼境重新 `inject_mcp`,手工同名 server 不覆盖。
|
||||
2. `reachable`:配置正确后检查 loopback 服务;连接拒绝表示炼境未运行,先启动正式安装版并保持托盘进程。
|
||||
3. `reload`:服务可达但当前任务看不到工具时,新建 Codex 任务或重载客户端;不要反复改配置或复制凭证。
|
||||
3. `reload`:服务可达但当前会话看不到工具时,新建会话或重载客户端;不要反复改配置或复制凭证。
|
||||
4. 仍不可用时,明确报告停在哪一层,继续完成不依赖 MCP 的本地工作;不得伪造诊断、项目 ID、凭证或远端状态。
|
||||
|
||||
@ -3,11 +3,12 @@
|
||||
"packs": [
|
||||
{
|
||||
"pack_id": "base-onboarding",
|
||||
"version": "1.5.0",
|
||||
"supported_clients": ["codex", "claude"],
|
||||
"version": "1.6.0",
|
||||
"supported_clients": ["codex", "claude", "dsh"],
|
||||
"project_artifacts": [
|
||||
"AGENTS.md",
|
||||
".agents/skills/lian-jing/SKILL.md",
|
||||
".claude/skills/lian-jing/SKILL.md",
|
||||
".lian-jing/context.json"
|
||||
],
|
||||
"self_check": "verify_onboarding",
|
||||
|
||||
@ -26,7 +26,7 @@ const TMPL_CAPABILITY_PACKS: &str =
|
||||
const TMPL_MISE: &str = include_str!("../../resources/onboarding/mise.toml.tmpl");
|
||||
const PROJECT_CONTEXT_SCHEMA_VERSION: u64 = 1;
|
||||
const CAPABILITY_PACK_SCHEMA_VERSION: u64 = 1;
|
||||
const BASE_ONBOARDING_PACK_VERSION: &str = "1.5.0";
|
||||
const BASE_ONBOARDING_PACK_VERSION: &str = "1.6.0";
|
||||
const TOOLCHAIN_PACK_VERSION: &str = "1.0.0";
|
||||
|
||||
/// 单个模板的分发结果。
|
||||
@ -230,6 +230,12 @@ pub fn dispatch_templates(project_path: &str) -> Vec<TemplateResult> {
|
||||
".agents/skills/lian-jing/SKILL.md",
|
||||
TMPL_LIANJING_SKILL,
|
||||
),
|
||||
// Claude Code 不读 .agents/skills,同一模板投影一份(单一来源,双投影)。
|
||||
dispatch_fully_managed(
|
||||
root,
|
||||
".claude/skills/lian-jing/SKILL.md",
|
||||
TMPL_LIANJING_SKILL,
|
||||
),
|
||||
dispatch_fully_managed(
|
||||
root,
|
||||
".lian-jing/capability-packs.json",
|
||||
@ -885,6 +891,8 @@ pub fn verify_onboarding(
|
||||
|
||||
let (pass, detail) = check_skill(read(".agents/skills/lian-jing/SKILL.md").as_deref());
|
||||
checks.push(VerifyCheck::from_pass("Codex 炼境技能已分发", pass, detail));
|
||||
let (pass, detail) = check_skill(read(".claude/skills/lian-jing/SKILL.md").as_deref());
|
||||
checks.push(VerifyCheck::from_pass("Claude 炼境技能已分发", pass, detail));
|
||||
checks.push(check_codex_mcp(
|
||||
read(".codex/config.toml").as_deref(),
|
||||
project_id,
|
||||
@ -1310,7 +1318,7 @@ mod tests {
|
||||
|
||||
// 空目录:所有检查均不通过(真实反映"什么都没接")
|
||||
let checks = verify_onboarding(&conn, "p1", &base);
|
||||
assert_eq!(checks.len(), 11, "检查链应为十一项");
|
||||
assert_eq!(checks.len(), 12, "检查链应为十二项");
|
||||
assert!(checks.iter().all(|c| !c.pass), "空项目应全部不通过");
|
||||
|
||||
// 铺齐全部生效条件后:所有检查全通过
|
||||
@ -1407,6 +1415,25 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn skill_is_projected_to_codex_and_claude_from_one_source() {
|
||||
let base = std::env::temp_dir().join(format!(
|
||||
"lianjing_skill_projection_{}",
|
||||
std::process::id()
|
||||
));
|
||||
let _ = std::fs::remove_dir_all(&base);
|
||||
std::fs::create_dir_all(&base).unwrap();
|
||||
dispatch_templates(base.to_str().unwrap());
|
||||
let codex = std::fs::read_to_string(base.join(".agents/skills/lian-jing/SKILL.md")).unwrap();
|
||||
let claude = std::fs::read_to_string(base.join(".claude/skills/lian-jing/SKILL.md")).unwrap();
|
||||
assert_eq!(codex, claude, "两端 skill 必须来自同一模板");
|
||||
assert!(check_skill(Some(&claude)).0);
|
||||
let packs: serde_json::Value = serde_json::from_str(TMPL_CAPABILITY_PACKS).unwrap();
|
||||
let artifacts = packs["packs"][0]["project_artifacts"].to_string();
|
||||
assert!(artifacts.contains(".claude/skills/lian-jing/SKILL.md"), "能力包清单须登记 Claude 投影");
|
||||
let _ = std::fs::remove_dir_all(&base);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn skill_check_requires_canonical_context() {
|
||||
let legacy = "---\nname: lian-jing\n---\n读取 .claude/liangjing.json";
|
||||
|
||||
Loading…
Reference in New Issue
Block a user