已合并
feat(cuda2ascend): support TraeCode as target tool #918
xutianze创建于 8月27日
feat(cuda2ascend): support TraeCode as target tool #918
已合并
共 20 个文件变更+293-40
| @@ -1,3 +1,6 @@ | |||
| 1 | .cannbot | 1 | .cannbot |
| 2 | .opencode | 2 | .opencode |
| 3 | .claude | 3 | .claude |
| 4 | +.trae | ||
| 5 | +.marscode | ||
| 6 | +.traecli | ||
| @@ -56,7 +56,7 @@ skills: | |||
| 56 | 注:若已安装部署级权限守卫(`hooks/dsh/install.sh`,挂 `$DSH_HOME/cordis.patch.yml`), | 56 | 注:若已安装部署级权限守卫(`hooks/dsh/install.sh`,挂 `$DSH_HOME/cordis.patch.yml`), |
| 57 | 按角色的写权限隔离与静默问卷拦截已由机制保证,本预检只需聚焦会话级审批/沙箱。 | 57 | 按角色的写权限隔离与静默问卷拦截已由机制保证,本预检只需聚焦会话级审批/沙箱。 |
| 58 | 58 | ||
| 59 | -3. **其余环境(claude / codex 等)**:无法从项目文件预检时跳过本项(不提示、不阻塞)。 | 59 | +3. **其余环境(claude / codex / trae 等)**:无法从项目文件预检时跳过本项(不提示、不阻塞)。trae(TraeCode)注意:角色写权限由 `.trae/agents/*.md` 的 frontmatter `tools` 静态限权(init 生成),目录级写权限靠本 PM 依 `workflow-agent-permissions` 判定避免无效派发;静默问卷拦截由 `.trae/hooks.json` 的 PreToolUse hook 机制保证。 |
| 60 | 60 | ||
| 61 | ## 身份 | 61 | ## 身份 |
| 62 | 62 | ||
| @@ -121,7 +121,7 @@ | |||
| 121 | 运行时配置统一由 `.cannbot/settings.json` 承载——**唯一配置文件与唯一权威**(工作流模式、插件注册信息与启用状态、询问状态全部聚合于此;init 生成、会话中可显式修改): | 121 | 运行时配置统一由 `.cannbot/settings.json` 承载——**唯一配置文件与唯一权威**(工作流模式、插件注册信息与启用状态、询问状态全部聚合于此;init 生成、会话中可显式修改): |
| 122 | 122 | ||
| 123 | - **生成**:`init.sh --mode interactive|silent` 与 `--plugin-enable <name> on|off`;未传 `--mode` 时保留现有配置(首次默认 `interactive`)。 | 123 | - **生成**:`init.sh --mode interactive|silent` 与 `--plugin-enable <name> on|off`;未传 `--mode` 时保留现有配置(首次默认 `interactive`)。 |
| 124 | -- **交互模式(默认)**:⛔ 用户确认点由 QA 用会话问卷工具(opencode `question` / claude `AskUserQuestion` / dsh `ask_user_question`)直接发送用户并收集结论,进度逐环节汇报。 | 124 | +- **交互模式(默认)**:⛔ 用户确认点由 QA 用会话问卷工具(opencode `question` / claude `AskUserQuestion` / dsh `ask_user_question` / trae `AskUserQuestion`)直接发送用户并收集结论,进度逐环节汇报。 |
| 125 | - **静默模式(`silent`,完全无人值守)**:不输出中间进度、不发问卷(确认点由 QA 按默认决策执行,架构选型固定采用 SIMD),失败自动回退至最大轮次;仅输出启动时的权限预检警告(opencode 检查 opencode.json 未全量授权、dsh 检查运行上下文声明的文件/审批策略未全量授权时提示一次)与任务完成总结(含阻断中止性总结)。启动静默工作流前 PM 执行权限预检,未全量授权时提示「运行期间权限确认可能打断自动流程」。 | 125 | - **静默模式(`silent`,完全无人值守)**:不输出中间进度、不发问卷(确认点由 QA 按默认决策执行,架构选型固定采用 SIMD),失败自动回退至最大轮次;仅输出启动时的权限预检警告(opencode 检查 opencode.json 未全量授权、dsh 检查运行上下文声明的文件/审批策略未全量授权时提示一次)与任务完成总结(含阻断中止性总结)。启动静默工作流前 PM 执行权限预检,未全量授权时提示「运行期间权限确认可能打断自动流程」。 |
| 126 | - **会话内切换**:直接对 PM 说「开启静默模式 / 关闭静默模式」,即修改配置并落盘,无需重跑 init。 | 126 | - **会话内切换**:直接对 PM 说「开启静默模式 / 关闭静默模式」,即修改配置并落盘,无需重跑 init。 |
| 127 | - **DSH 部署级权限守卫(可选)**:dsh 无项目级 hook(角色写隔离默认靠 prompt 约束);运行 `hooks/dsh/install.sh` 可安装部署级 Cordis 守卫插件(挂 `$DSH_HOME/cordis.patch.yml`,对所有 profile 生效),恢复按角色的写权限隔离与静默问卷拦截的机制保证(仅作用于 cuda2ascend 初始化的工作区)。 | 127 | - **DSH 部署级权限守卫(可选)**:dsh 无项目级 hook(角色写隔离默认靠 prompt 约束);运行 `hooks/dsh/install.sh` 可安装部署级 Cordis 守卫插件(挂 `$DSH_HOME/cordis.patch.yml`,对所有 profile 生效),恢复按角色的写权限隔离与静默问卷拦截的机制保证(仅作用于 cuda2ascend 初始化的工作区)。 |
| @@ -28,7 +28,7 @@ skills: | |||
| 28 | 28 | ||
| 29 | - **收到某 CP 点的验收任务时**:加载该 CP 点对应的 `workflow-cp*` Skill,按其规定的验收对象、通过指标与判定方式执行验收。 | 29 | - **收到某 CP 点的验收任务时**:加载该 CP 点对应的 `workflow-cp*` Skill,按其规定的验收对象、通过指标与判定方式执行验收。 |
| 30 | - **可机器判定的验收**(精度比对、用例执行、校验项核对等):按 Skill 指标客观裁定,产出验收报告。 | 30 | - **可机器判定的验收**(精度比对、用例执行、校验项核对等):按 Skill 指标客观裁定,产出验收报告。 |
| 31 | -- **需用户确认的验收**:按 Skill 给定的问卷模板生成问卷 json,用会话问卷工具(opencode `question` / claude `AskUserQuestion` / dsh `ask_user_question`)直接发送给用户并收集结论,用户结论作为验收结果。**原样发送、原样保存**:不得擅自改动问卷模板内容,问卷条目内容必须完全依据输入件(验收对象文档)填写,不得脱离输入件自行总结结论或另行采集信息;发出的问卷与用户回复成对落盘 `questionnaires/`(回复记为问卷同名 `.reply.json`)。 | 31 | +- **需用户确认的验收**:按 Skill 给定的问卷模板生成问卷 json,用会话问卷工具(opencode `question` / claude `AskUserQuestion` / dsh `ask_user_question` / trae `AskUserQuestion`)直接发送给用户并收集结论,用户结论作为验收结果。**原样发送、原样保存**:不得擅自改动问卷模板内容,问卷条目内容必须完全依据输入件(验收对象文档)填写,不得脱离输入件自行总结结论或另行采集信息;发出的问卷与用户回复成对落盘 `questionnaires/`(回复记为问卷同名 `.reply.json`)。 |
| 32 | - **插件流程内的验收**:按下发任务给定的验收对象与标准执行(如回归门禁复核、CI/检视状态核对)。 | 32 | - **插件流程内的验收**:按下发任务给定的验收对象与标准执行(如回归门禁复核、CI/检视状态核对)。 |
| 33 | - **验收不通过时**:产出结构化修改意见——问题定位 + 问题语义归属(归属于需求 / 开发方案 / 算子实现等),供上游按流程回退。 | 33 | - **验收不通过时**:产出结构化修改意见——问题定位 + 问题语义归属(归属于需求 / 开发方案 / 算子实现等),供上游按流程回退。 |
| 34 | 34 | ||
| @@ -19,7 +19,7 @@ set -e | |||
| 19 | # ============================================================ | 19 | # ============================================================ |
| 20 | # Quick Start content (shown after a successful install). | 20 | # Quick Start content (shown after a successful install). |
| 21 | # Customize this block for your repo. $CLI_NAME is resolved at | 21 | # Customize this block for your repo. $CLI_NAME is resolved at |
| 22 | -# runtime from the target tool (opencode/claude/codex/dsh). | 22 | +# runtime from the target tool chosen by the user (see --help). |
| 23 | # ============================================================ | 23 | # ============================================================ |
| 24 | show_quick_start() { | 24 | show_quick_start() { |
| 25 | echo "" | 25 | echo "" |
| @@ -101,9 +101,9 @@ Options: | |||
| 101 | - passed through to the base plugin | 101 | - passed through to the base plugin |
| 102 | 102 | ||
| 103 | Examples: | 103 | Examples: |
| 104 | - ./init.sh opencode --repo cannbot-skills:~/cannbot-skills | 104 | + ./init.sh <target> --repo cannbot-skills:~/cannbot-skills |
| 105 | - ./init.sh claude --repo cannbot-skills:~/cannbot-skills | 105 | + ./init.sh <target> --repo asc-devkit:~/asc-devkit --repo cann-samples:~/cann-samples |
| 106 | - ./init.sh opencode --repo asc-devkit:~/asc-devkit --repo cann-samples:~/cann-samples | 106 | + (target = any tool in the list above, e.g. opencode) |
| 107 | EOF | 107 | EOF |
| 108 | } | 108 | } |
| 109 | 109 | ||
| @@ -164,7 +164,7 @@ while [[ $# -gt 0 ]]; do | |||
| 164 | done | 164 | done |
| 165 | 165 | ||
| 166 | if [ "$HELP_REQUESTED" = false ] && [ -z "$TARGET_ENV" ]; then | 166 | if [ "$HELP_REQUESTED" = false ] && [ -z "$TARGET_ENV" ]; then |
| 167 | - err "Missing required argument: target (e.g. opencode)" | 167 | + err "Missing required argument: target (run ./init.sh --help to list supported tools)" |
| 168 | echo "" | 168 | echo "" |
| 169 | show_help | 169 | show_help |
| 170 | exit 1 | 170 | exit 1 |
| @@ -262,9 +262,6 @@ bash "$PLUGIN_INIT" "${PLUGIN_ARGS[@]}" || { | |||
| 262 | # ============================================================ | 262 | # ============================================================ |
| 263 | # Step 3: Quick Start (子仓定制;基类在 --override 时不输出) | 263 | # Step 3: Quick Start (子仓定制;基类在 --override 时不输出) |
| 264 | # ============================================================ | 264 | # ============================================================ |
| 265 | -CLI_NAME="opencode" | 265 | +CLI_NAME="$TARGET_ENV" |
| 266 | -[ "$TARGET_ENV" = "claude" ] && CLI_NAME="claude" | ||
| 267 | -[ "$TARGET_ENV" = "codex" ] && CLI_NAME="codex" | ||
| 268 | -[ "$TARGET_ENV" = "dsh" ] && CLI_NAME="dsh" | ||
| 269 | show_quick_start | 266 | show_quick_start |
| 270 | echo "" | 267 | echo "" |
| @@ -0,0 +1,97 @@ | |||
| 1 | +#!/usr/bin/env node | ||
| 2 | +// Copyright (c) 2025-2026 Huawei Technologies Co., Ltd. | ||
| 3 | +// This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | +// CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | +// Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | +// INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | +// See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + | ||
| 10 | +// --------------------------------------------------------------------------- | ||
| 11 | +// permission-guard —— TraeCode 侧静默问卷拦截 hook | ||
| 12 | +// | ||
| 13 | +// 机制(TraeCode PreToolUse hook): | ||
| 14 | +// hook 注册在 .trae/hooks.json(init Step 4+ 幂等写入),matcher 命中 | ||
| 15 | +// AskUserQuestion 问卷工具时本脚本被调用,事件 JSON 经 stdin 传入: | ||
| 16 | +// { session_id, cwd, hook_event_name: "PreToolUse", tool_use_id, | ||
| 17 | +// tool_name, llm_tool_name, tool_input } | ||
| 18 | +// Trae 的 PreToolUse stdin **没有 agent 角色字段**(与 opencode/claude 不同, | ||
| 19 | +// 无法按角色反查当前子 Agent),因此本 hook 只做**静默问卷拦截**兜底: | ||
| 20 | +// .cannbot/settings.json 的 mode=silent 时阻断任何问卷发送。 | ||
| 21 | +// | ||
| 22 | +// 角色写权限隔离由 .trae/agents/*.md 的 frontmatter tools 静态限权承担 | ||
| 23 | +// (Trae 原生机制,init Step 3 生成时按角色注入工具白名单);目录级写权限 | ||
| 24 | +// (.cannbot 等)Trae 不支持,由 AGENTS.md prompt 约束(同 codex 降级)。 | ||
| 25 | +// | ||
| 26 | +// 违规 → exit 2(阻断本次调用,stderr 原因回传模型);放行 → exit 0 且无输出。 | ||
| 27 | +// | ||
| 28 | +// ★ 静默语义与 hooks/opencode/permission-guard.js、hooks/claude/permission-guard.js | ||
| 29 | +// ★ 及 hooks/dsh/permission-guard.js 保持一致(SILENT_GUARDED_TOOLS 子串匹配 + | ||
| 30 | +// ★ readSilentMode 读 .cannbot/settings.json)。 | ||
| 31 | +// --------------------------------------------------------------------------- | ||
| 32 | + | ||
| 33 | +"use strict" | ||
| 34 | + | ||
| 35 | +const { readFileSync } = require("node:fs") | ||
| 36 | +const { join } = require("node:path") | ||
| 37 | + | ||
| 38 | +// 静默模式(.cannbot/settings.json 的 mode=silent)下拦截的询问类工具。 | ||
| 39 | +// 按**子串**匹配工具名(小写后),覆盖 AskUserQuestion 等带前后缀的命名。 | ||
| 40 | +const SILENT_GUARDED_TOOLS = ["question", "ask"] | ||
| 41 | + | ||
| 42 | +function deny(reason) { | ||
| 43 | + // exit 2:阻断本次工具调用,stderr 内容回传给模型 | ||
| 44 | + console.error(`[permission-guard] ${reason}`) | ||
| 45 | + process.exit(2) | ||
| 46 | +} | ||
| 47 | + | ||
| 48 | +// 读取 .cannbot/settings.json 的静默开关(hook 为一次性进程,天然实时; | ||
| 49 | +// 读失败按非静默处理,避免误伤) | ||
| 50 | +function readSilentMode(projectRoot) { | ||
| 51 | + try { | ||
| 52 | + const data = JSON.parse( | ||
| 53 | + readFileSync(join(projectRoot, ".cannbot", "settings.json"), "utf8"), | ||
| 54 | + ) | ||
| 55 | + return data && data.mode === "silent" | ||
| 56 | + } catch { | ||
| 57 | + return false | ||
| 58 | + } | ||
| 59 | +} | ||
| 60 | + | ||
| 61 | +function main() { | ||
| 62 | + const raw = readFileSync(0, "utf8") // stdin | ||
| 63 | + | ||
| 64 | + let input | ||
| 65 | + try { | ||
| 66 | + input = JSON.parse(raw) | ||
| 67 | + } catch { | ||
| 68 | + return // 输入异常不拦(避免误伤) | ||
| 69 | + } | ||
| 70 | + | ||
| 71 | + // 仅处理 PreToolUse(matcher 已限定,防御性判断) | ||
| 72 | + if (input.hook_event_name && input.hook_event_name !== "PreToolUse") return | ||
| 73 | + | ||
| 74 | + const tool = (input.tool_name || "").toLowerCase() | ||
| 75 | + | ||
| 76 | + // 静默模式:拦截问卷发送(任何角色都不得绕过) | ||
| 77 | + if (SILENT_GUARDED_TOOLS.some((t) => tool.includes(t))) { | ||
| 78 | + // Trae 注入 CLAUDE_PROJECT_DIR(兼容 Claude 环境变量)与 TRAE_PROJECT_DIR; | ||
| 79 | + // 项目级 hook 工作目录即项目根,cwd 兜底 | ||
| 80 | + const projectRoot = | ||
| 81 | + process.env.CLAUDE_PROJECT_DIR || | ||
| 82 | + process.env.TRAE_PROJECT_DIR || | ||
| 83 | + input.cwd || | ||
| 84 | + process.cwd() | ||
| 85 | + if (readSilentMode(projectRoot)) { | ||
| 86 | + deny( | ||
| 87 | + "静默模式已启用,问卷发送被拦截:请按静默默认决策执行——不发送问卷,落盘 " + | ||
| 88 | + '.reply.json({"mode":"silent","decision":"accepted"});如需恢复交互,请让用户关闭静默模式。', | ||
| 89 | + ) | ||
| 90 | + } | ||
| 91 | + return | ||
| 92 | + } | ||
| 93 | + | ||
| 94 | + // 非问卷工具:放行(角色写权限由 Subagent tools 静态限权,不在此拦截) | ||
| 95 | +} | ||
| 96 | + | ||
| 97 | +main() | ||
| @@ -112,7 +112,7 @@ BRAND="cannbot" | |||
| 112 | VERSION="1.0.0" | 112 | VERSION="1.0.0" |
| 113 | # Supported target tools — single source of truth (modify-init.md 红线 1). | 113 | # Supported target tools — single source of truth (modify-init.md 红线 1). |
| 114 | # Subclass init.sh queries this via `--list-tools` instead of hardcoding. | 114 | # Subclass init.sh queries this via `--list-tools` instead of hardcoding. |
| 115 | -SUPPORTED_TOOLS=("opencode" "claude" "codex" "dsh") | 115 | +SUPPORTED_TOOLS=("opencode" "claude" "codex" "dsh" "trae") |
| 116 | 116 | ||
| 117 | # ============================================================ | 117 | # ============================================================ |
| 118 | # Third-party repository registry | 118 | # Third-party repository registry |
| @@ -298,6 +298,11 @@ Installation paths: | |||
| 298 | agents are role reference only (DSH subagents are prompt-driven); | 298 | agents are role reference only (DSH subagents are prompt-driven); |
| 299 | no project-level permission hook — optional deployment-level guard: | 299 | no project-level permission hook — optional deployment-level guard: |
| 300 | hooks/dsh/install.sh (Cordis plugin via $DSH_HOME/cordis.patch.yml) | 300 | hooks/dsh/install.sh (Cordis plugin via $DSH_HOME/cordis.patch.yml) |
| 301 | + trae: .trae/skills/ + .trae/agents/ + AGENTS.md in project root | ||
| 302 | + skills discovered at <projectRoot>/.trae/skills (TraeCode project skills); | ||
| 303 | + agents generated as TraeCode Subagent .md (frontmatter tools = static per-role | ||
| 304 | + tool allowlist, native Trae mechanism; role dir-level writes rely on prompt); | ||
| 305 | + PreToolUse hook registered in .trae/hooks.json (silent-question interception) | ||
| 301 | 306 | ||
| 302 | Intermediate directory: | 307 | Intermediate directory: |
| 303 | .cannbot/ workflow intermediate files & state | 308 | .cannbot/ workflow intermediate files & state |
| @@ -406,6 +411,7 @@ while [ $# -gt 0 ]; do | |||
| 406 | claude) TOOL="$arg"; shift; continue ;; | 411 | claude) TOOL="$arg"; shift; continue ;; |
| 407 | codex) TOOL="$arg"; shift; continue ;; | 412 | codex) TOOL="$arg"; shift; continue ;; |
| 408 | dsh) TOOL="$arg"; shift; continue ;; | 413 | dsh) TOOL="$arg"; shift; continue ;; |
| 414 | + trae) TOOL="$arg"; shift; continue ;; | ||
| 409 | *) | 415 | *) |
| 410 | # 兜底:动态校验 SUPPORTED_TOOLS,支持未来新增工具 | 416 | # 兜底:动态校验 SUPPORTED_TOOLS,支持未来新增工具 |
| 411 | if is_supported_tool "$1"; then | 417 | if is_supported_tool "$1"; then |
| @@ -455,6 +461,9 @@ if [ "${LEVEL}" = "global" ]; then | |||
| 455 | # DSH(DeepSeek Harness)用户数据根:$DSH_HOME,默认 ~/.dsh | 461 | # DSH(DeepSeek Harness)用户数据根:$DSH_HOME,默认 ~/.dsh |
| 456 | # (对齐 dsh-home-paths 的 resolveDshHome 优先级:显式配置 > $DSH_HOME > ~/.dsh) | 462 | # (对齐 dsh-home-paths 的 resolveDshHome 优先级:显式配置 > $DSH_HOME > ~/.dsh) |
| 457 | CONFIG_ROOT="${DSH_HOME:-${HOME}/.dsh}" | 463 | CONFIG_ROOT="${DSH_HOME:-${HOME}/.dsh}" |
| 464 | + elif [ "${TOOL}" = "trae" ]; then | ||
| 465 | + # TraeCode 全局用户根:~/.trae-cn(含 user_rules / skills / agents / hooks.json) | ||
| 466 | + CONFIG_ROOT="${HOME}/.trae-cn" | ||
| 458 | fi | 467 | fi |
| 459 | INSTALL_BASE="${HOME}" | 468 | INSTALL_BASE="${HOME}" |
| 460 | else | 469 | else |
| @@ -475,6 +484,11 @@ else | |||
| 475 | # 其下的 skills/ 正是 DSH 的 project-dsh 发现根(<projectRoot>/.dsh/skills, | 484 | # 其下的 skills/ 正是 DSH 的 project-dsh 发现根(<projectRoot>/.dsh/skills, |
| 476 | # 最近 .git 祖先判定,rank 100),无需额外配置即可被扫描。 | 485 | # 最近 .git 祖先判定,rank 100),无需额外配置即可被扫描。 |
| 477 | CONFIG_ROOT="${INSTALL_BASE}/.dsh" | 486 | CONFIG_ROOT="${INSTALL_BASE}/.dsh" |
| 487 | + elif [ "${TOOL}" = "trae" ]; then | ||
| 488 | + # TraeCode 项目级配置根:<install>/.trae。 | ||
| 489 | + # 其下的 skills/ 是 TraeCode 项目技能目录(自动发现,无需额外配置); | ||
| 490 | + # agents/ 为 Subagent 定义目录;hooks.json 为 PreToolUse hook 注册。 | ||
| 491 | + CONFIG_ROOT="${INSTALL_BASE}/.trae" | ||
| 478 | fi | 492 | fi |
| 479 | fi | 493 | fi |
| 480 | 494 | ||
| @@ -715,6 +729,62 @@ if [ "${TOOL}" = "codex" ]; then | |||
| 715 | else | 729 | else |
| 716 | warn "No codex agent TOMLs found at ${CODEX_AGENT_ROOT}, skipping agents" | 730 | warn "No codex agent TOMLs found at ${CODEX_AGENT_ROOT}, skipping agents" |
| 717 | fi | 731 | fi |
| 732 | +elif [ "${TOOL}" = "trae" ]; then | ||
| 733 | + # TraeCode Subagent:Markdown 定义(frontmatter name/description/tools 等), | ||
| 734 | + # 仅内置 Agent 可调用。从 agents/*.md 生成 .trae/agents/{name}.md: | ||
| 735 | + # 保留 name/description 与正文,注入 tools(按角色静态限权,Trae 原生机制); | ||
| 736 | + # 目录级写权限(.cannbot 等)Trae 不支持,由 prompt 约束兜底(同 codex 降级)。 | ||
| 737 | + agent_count=$(TRAE_AGENT_OUT="${AGENTS_LINK_DIR}" python3 - "${AGENT_FILES[@]}" << 'TRAE_AGENT_PY' 2>/dev/null) | ||
| 738 | +import os, re, sys | ||
| 739 | + | ||
| 740 | +out_dir = os.environ["TRAE_AGENT_OUT"] | ||
| 741 | +os.makedirs(out_dir, exist_ok=True) | ||
| 742 | + | ||
| 743 | +# 角色 → Trae 工具白名单(与 workflow-agent-permissions 角色语义对齐)。 | ||
| 744 | +# Trae 工具名:Read/Write/Edit/Glob/Grep/LS/RunCommand/WebSearch/WebFetch/ | ||
| 745 | +# AskUserQuestion/Skill/TodoWrite/LSP/mcp__*。目录级限权 Trae 不支持。 | ||
| 746 | +ROLE_TOOLS = { | ||
| 747 | + "architect": "Read, Glob, Grep, LS, Write, Edit, Skill, TodoWrite", | ||
| 748 | + "developer": "Read, Glob, Grep, LS, Write, Edit, RunCommand, Skill, TodoWrite", | ||
| 749 | + "developer-code": "Read, Glob, Grep, LS, Write, Edit, RunCommand, Skill, TodoWrite", | ||
| 750 | + "developer-test": "Read, Glob, Grep, LS, Write, Edit, RunCommand, Skill, TodoWrite", | ||
| 751 | + "developer-doc": "Read, Glob, Grep, LS, Write, Edit, RunCommand, Skill, TodoWrite", | ||
| 752 | + "qa": "Read, Glob, Grep, LS, Write, Edit, RunCommand, Skill, TodoWrite, AskUserQuestion", | ||
| 753 | +} | ||
| 754 | +DEFAULT_TOOLS = "Read, Glob, Grep, LS, Write, Edit, Skill, TodoWrite" | ||
| 755 | + | ||
| 756 | + | ||
| 757 | +def parse_frontmatter(text): | ||
| 758 | + m = re.match(r"^---\n(.*?)\n---\n(.*)$", text, re.S) | ||
| 759 | + if not m: | ||
| 760 | + return {}, text | ||
| 761 | + fm, body = m.group(1), m.group(2) | ||
| 762 | + data = {} | ||
| 763 | + for line in fm.splitlines(): | ||
| 764 | + mm = re.match(r"^([A-Za-z0-9_-]+):\s*(.*)$", line) | ||
| 765 | + if mm: | ||
| 766 | + data[mm.group(1)] = mm.group(2).strip() | ||
| 767 | + return data, body | ||
| 768 | + | ||
| 769 | + | ||
| 770 | +count = 0 | ||
| 771 | +for f in sys.argv[1:]: | ||
| 772 | + try: | ||
| 773 | + with open(f, encoding="utf-8") as fh: | ||
| 774 | + text = fh.read() | ||
| 775 | + except OSError: | ||
| 776 | + continue | ||
| 777 | + fm, body = parse_frontmatter(text) | ||
| 778 | + name = fm.get("name") or os.path.splitext(os.path.basename(f))[0] | ||
| 779 | + desc = fm.get("description", "") | ||
| 780 | + tools = ROLE_TOOLS.get(name, DEFAULT_TOOLS) | ||
| 781 | + out = f"---\nname: {name}\ndescription: {desc}\ntools: {tools}\n---\n{body}" | ||
| 782 | + with open(os.path.join(out_dir, name + ".md"), "w", encoding="utf-8") as fh: | ||
| 783 | + fh.write(out) | ||
| 784 | + count += 1 | ||
| 785 | +print(count) | ||
| 786 | +TRAE_AGENT_PY | ||
| 787 | + ok "Agents: ${agent_count} trae Subagent files generated" | ||
| 718 | else | 788 | else |
| 719 | for f in "${AGENT_FILES[@]}"; do | 789 | for f in "${AGENT_FILES[@]}"; do |
| 720 | link_name="$(basename "${f}")" | 790 | link_name="$(basename "${f}")" |
| @@ -729,6 +799,9 @@ fi | |||
| 729 | if [ "${TOOL}" = "dsh" ]; then | 799 | if [ "${TOOL}" = "dsh" ]; then |
| 730 | info "dsh: agents linked to .dsh/agents/ as role reference (DSH subagents are prompt-driven, no native agent registration)" | 800 | info "dsh: agents linked to .dsh/agents/ as role reference (DSH subagents are prompt-driven, no native agent registration)" |
| 731 | fi | 801 | fi |
| 802 | +if [ "${TOOL}" = "trae" ]; then | ||
| 803 | + info "trae: agents generated as Subagent .md in .trae/agents/ (tools = static per-role allowlist, native Trae mechanism)" | ||
| 804 | +fi | ||
| 732 | echo "" | 805 | echo "" |
| 733 | 806 | ||
| 734 | # ============================================================ | 807 | # ============================================================ |
| @@ -913,6 +986,76 @@ elif [ "${TOOL}" = "dsh" ]; then | |||
| 913 | echo -e " ${DIM}可选机制升级: ${GREEN}hooks/dsh/install.sh${NC}${DIM} 安装部署级权限守卫${NC}" | 986 | echo -e " ${DIM}可选机制升级: ${GREEN}hooks/dsh/install.sh${NC}${DIM} 安装部署级权限守卫${NC}" |
| 914 | echo -e " ${DIM}(Cordis 插件 → ${DIM}\$DSH_HOME/cordis.patch.yml,恢复角色写权限隔离与静默问卷拦截)${NC}" | 987 | echo -e " ${DIM}(Cordis 插件 → ${DIM}\$DSH_HOME/cordis.patch.yml,恢复角色写权限隔离与静默问卷拦截)${NC}" |
| 915 | echo "" | 988 | echo "" |
| 989 | +elif [ "${TOOL}" = "trae" ]; then | ||
| 990 | + # TraeCode:PreToolUse hook 注册在 .trae/hooks.json。 | ||
| 991 | + # 角色写权限由 .trae/agents/*.md 的 frontmatter tools 静态限权(Trae 原生机制, | ||
| 992 | + # 见 Step 3 生成逻辑),本 hook 只做**静默问卷拦截**兜底——Trae 的 PreToolUse | ||
| 993 | + # stdin 无 agent 角色字段(与 opencode/claude 不同),无法做按角色目录限权, | ||
| 994 | + # 目录级写权限由 prompt 约束(同 codex 降级)。 | ||
| 995 | + TRAE_HOOK_SRC="${PLUGIN_ROOT}/hooks/trae/permission-guard.js" | ||
| 996 | + if [ -f "${TRAE_HOOK_SRC}" ]; then | ||
| 997 | + TRAE_HOOK_DIR="${CONFIG_ROOT}/hooks" | ||
| 998 | + mkdir -p "${TRAE_HOOK_DIR}" | ||
| 999 | + ln -sfn "$(realpath "${TRAE_HOOK_SRC}")" "${TRAE_HOOK_DIR}/permission-guard.js" | ||
| 1000 | + ok "trae hook: permission-guard.js linked" | ||
| 1001 | + | ||
| 1002 | + HOOKS_FILE="${CONFIG_ROOT}/hooks.json" | ||
| 1003 | + # 项目级用 ${CLAUDE_PROJECT_DIR} 占位符(Trae 兼容 Claude 环境变量,随项目迁移不失效); | ||
| 1004 | + # global 级项目目录不固定,用绝对路径 | ||
| 1005 | + HOOK_REF='${CLAUDE_PROJECT_DIR}/.trae/hooks/permission-guard.js' | ||
| 1006 | + [ "${LEVEL}" = "global" ] && HOOK_REF="${TRAE_HOOK_DIR}/permission-guard.js" | ||
| 1007 | + if command -v python3 > /dev/null 2>&1; then | ||
| 1008 | + python3 - "${HOOKS_FILE}" "${HOOK_REF}" << 'TRAE_HOOKS_PY' | ||
| 1009 | +import json, os, sys | ||
| 1010 | + | ||
| 1011 | +path, hook_ref = sys.argv[1], sys.argv[2] | ||
| 1012 | +data = {} | ||
| 1013 | +if os.path.exists(path): | ||
| 1014 | + try: | ||
| 1015 | + with open(path, encoding="utf-8") as f: | ||
| 1016 | + data = json.load(f) | ||
| 1017 | + if not isinstance(data, dict): | ||
| 1018 | + print(f" [warn] hooks.json 内容不是 JSON 对象,保留原文件未注册 hook: {path}", file=sys.stderr) | ||
| 1019 | + sys.exit(0) | ||
| 1020 | + except Exception: | ||
| 1021 | + print(f" [warn] hooks.json 解析失败,保留原文件未注册 hook: {path}", file=sys.stderr) | ||
| 1022 | + sys.exit(0) | ||
| 1023 | + | ||
| 1024 | +pre = data.setdefault("hooks", {}).setdefault("PreToolUse", []) | ||
| 1025 | +for group in pre: | ||
| 1026 | + matcher = group.get("matcher", "") | ||
| 1027 | + for h in group.get("hooks", []): | ||
| 1028 | + blob = h.get("command", "") + " " + " ".join(h.get("args", [])) | ||
| 1029 | + if "permission-guard.js" in blob: | ||
| 1030 | + if "Question" in matcher: | ||
| 1031 | + print(" [info] hooks.json 已注册 permission-guard hook,跳过") | ||
| 1032 | + else: | ||
| 1033 | + group["matcher"] = matcher + "|AskUserQuestion" | ||
| 1034 | + with open(path, "w", encoding="utf-8") as f: | ||
| 1035 | + json.dump(data, f, indent=2, ensure_ascii=False) | ||
| 1036 | + f.write("\n") | ||
| 1037 | + print(" [ok] hooks.json 已注册 permission-guard hook(matcher 补充 AskUserQuestion,静默问卷拦截生效)") | ||
| 1038 | + sys.exit(0) | ||
| 1039 | + | ||
| 1040 | +pre.append({ | ||
| 1041 | + "matcher": "AskUserQuestion", | ||
| 1042 | + "hooks": [{ | ||
| 1043 | + "type": "command", | ||
| 1044 | + "command": "node " + hook_ref, | ||
| 1045 | + }], | ||
| 1046 | +}) | ||
| 1047 | +with open(path, "w", encoding="utf-8") as f: | ||
| 1048 | + json.dump(data, f, indent=2, ensure_ascii=False) | ||
| 1049 | + f.write("\n") | ||
| 1050 | +print(" [ok] hooks.json 注册 permission-guard PreToolUse hook(静默问卷拦截)") | ||
| 1051 | +TRAE_HOOKS_PY | ||
| 1052 | + else | ||
| 1053 | + warn "python3 not found, 请手动在 ${HOOKS_FILE} 注册 PreToolUse hook(见 hooks/trae/permission-guard.js 注释)" | ||
| 1054 | + fi | ||
| 1055 | + else | ||
| 1056 | + warn "trae permission-guard.js not found, skipping" | ||
| 1057 | + fi | ||
| 1058 | + echo "" | ||
| 916 | else | 1059 | else |
| 917 | OC_PLUGIN_SRC="${PLUGIN_ROOT}/hooks/opencode/permission-guard.js" | 1060 | OC_PLUGIN_SRC="${PLUGIN_ROOT}/hooks/opencode/permission-guard.js" |
| 918 | if [ -f "${OC_PLUGIN_SRC}" ]; then | 1061 | if [ -f "${OC_PLUGIN_SRC}" ]; then |
| @@ -1237,6 +1380,15 @@ if [ "${TOOL}" = "claude" ]; then | |||
| 1237 | health_errors="${health_errors}\n ${YELLOW}⚠${NC} settings.json missing (hook 未注册)" | 1380 | health_errors="${health_errors}\n ${YELLOW}⚠${NC} settings.json missing (hook 未注册)" |
| 1238 | fi | 1381 | fi |
| 1239 | fi | 1382 | fi |
| 1383 | +if [ "${TOOL}" = "trae" ]; then | ||
| 1384 | + [ -e "${CONFIG_ROOT}/hooks/permission-guard.js" ] || { health_errors="${health_errors}\n ${RED}✗${NC} .trae/hooks/permission-guard.js missing"; health_ok=false; } | ||
| 1385 | + if [ -f "${CONFIG_ROOT}/hooks.json" ]; then | ||
| 1386 | + grep -q "permission-guard.js" "${CONFIG_ROOT}/hooks.json" \ | ||
| 1387 | + || health_errors="${health_errors}\n ${YELLOW}⚠${NC} hooks.json 未注册 permission-guard hook" | ||
| 1388 | + else | ||
| 1389 | + health_errors="${health_errors}\n ${YELLOW}⚠${NC} hooks.json missing (hook 未注册)" | ||
| 1390 | + fi | ||
| 1391 | +fi | ||
| 1240 | 1392 | ||
| 1241 | if [ "${health_ok}" = true ] && [ -z "${health_errors}" ]; then | 1393 | if [ "${health_ok}" = true ] && [ -z "${health_errors}" ]; then |
| 1242 | ok "All checks passed" | 1394 | ok "All checks passed" |
| @@ -1248,10 +1400,7 @@ fi | |||
| 1248 | # ============================================================ | 1400 | # ============================================================ |
| 1249 | # Summary | 1401 | # Summary |
| 1250 | # ============================================================ | 1402 | # ============================================================ |
| 1251 | -CLI_NAME="opencode" | 1403 | +CLI_NAME="${TOOL}" |
| 1252 | -[ "${TOOL}" = "claude" ] && CLI_NAME="claude" | ||
| 1253 | -[ "${TOOL}" = "codex" ] && CLI_NAME="codex" | ||
| 1254 | -[ "${TOOL}" = "dsh" ] && CLI_NAME="dsh" | ||
| 1255 | echo "" | 1404 | echo "" |
| 1256 | echo -e " ${GREEN}${BOLD}✓ ${TEAM_NAME} installed!${NC}" | 1405 | echo -e " ${GREEN}${BOLD}✓ ${TEAM_NAME} installed!${NC}" |
| 1257 | echo -e " ${DIM}Skills: ${skill_count} | Agents: ${agent_count}${NC}" | 1406 | echo -e " ${DIM}Skills: ${skill_count} | Agents: ${agent_count}${NC}" |
| @@ -16,6 +16,7 @@ cannbot-skills/plugins-community/cuda2ascend/ # 基类插件根 = PLUGIN_ROOT | |||
| 16 | ├── init.sh # 基类构造函数:搭建工作区 + 绑定 virtual 组件 | 16 | ├── init.sh # 基类构造函数:搭建工作区 + 绑定 virtual 组件 |
| 17 | ├── hooks/opencode/permission-guard.js # 动态权限插件(opencode 侧,按角色限写) | 17 | ├── hooks/opencode/permission-guard.js # 动态权限插件(opencode 侧,按角色限写) |
| 18 | ├── hooks/claude/permission-guard.js # 动态权限 hook(claude 侧,同一套规则语义) | 18 | ├── hooks/claude/permission-guard.js # 动态权限 hook(claude 侧,同一套规则语义) |
| 19 | +├── hooks/trae/permission-guard.js # 静默问卷拦截 hook(trae 侧,PreToolUse) | ||
| 19 | ├── agents/ # 三类子 Agent 源文件(final,init 扁平化链接) | 20 | ├── agents/ # 三类子 Agent 源文件(final,init 扁平化链接) |
| 20 | │ ├── architect.md # 方案设计 | 21 | │ ├── architect.md # 方案设计 |
| 21 | │ ├── developer*.md # 开发(含 -code/-test/-doc 按权限分的变体) | 22 | │ ├── developer*.md # 开发(含 -code/-test/-doc 按权限分的变体) |
| @@ -88,7 +89,7 @@ skills/ops-direct-invoke-workflow/ | |||
| 88 | 89 | ||
| 89 | ### 运行时目录(init 生成,勿手改,勿提交) | 90 | ### 运行时目录(init 生成,勿手改,勿提交) |
| 90 | 91 | ||
| 91 | -init 把源文件软链接到算子仓根的运行时目录(OpenCode 的 `.opencode/` 或 Claude Code 的 `.claude/`,由 init 的 tool 参数决定): | 92 | +init 把源文件软链接到算子仓根的运行时目录(OpenCode 的 `.opencode/`、Claude Code 的 `.claude/` 或 TraeCode 的 `.trae/`,由 init 的 tool 参数决定): |
| 92 | 93 | ||
| 93 | ``` | 94 | ``` |
| 94 | <算子仓>/ | 95 | <算子仓>/ |
| @@ -103,9 +104,12 @@ init 把源文件软链接到算子仓根的运行时目录(OpenCode 的 `.ope | |||
| 103 | │ (codex 为 .agents/skills/*/,非 .codex/skills/) | 104 | │ (codex 为 .agents/skills/*/,非 .codex/skills/) |
| 104 | │ (dsh 为 .dsh/skills/*/ —— 即 DSH 的 project-dsh 发现根 <projectRoot>/.dsh/skills, | 105 | │ (dsh 为 .dsh/skills/*/ —— 即 DSH 的 project-dsh 发现根 <projectRoot>/.dsh/skills, |
| 105 | │ rank 100 自动扫描,无需额外配置;global 为 $DSH_HOME/skills,rank 400) | 106 | │ rank 100 自动扫描,无需额外配置;global 为 $DSH_HOME/skills,rank 400) |
| 107 | +│ (trae 为 .trae/skills/*/ —— TraeCode 项目技能目录,自动发现) | ||
| 106 | ├── .opencode/plugin/ -> 权限插件 permission-guard.js | 108 | ├── .opencode/plugin/ -> 权限插件 permission-guard.js |
| 107 | │ (claude 为 .claude/hooks/permission-guard.js + .claude/settings.json 注册 PreToolUse) | 109 | │ (claude 为 .claude/hooks/permission-guard.js + .claude/settings.json 注册 PreToolUse) |
| 108 | │ (codex 无权限 hook,init 时输出 WARNING 告知降级) | 110 | │ (codex 无权限 hook,init 时输出 WARNING 告知降级) |
| 111 | +│ (trae 为 .trae/hooks/permission-guard.js + .trae/hooks.json 注册 PreToolUse | ||
| 112 | +│ 静默问卷拦截;角色写权限由 .trae/agents/*.md 的 tools 静态限权,目录级靠 prompt) | ||
| 109 | ├── .cannbot/ -> 中间文件 + asc-devkit + cann-samples + ops-tensor | 113 | ├── .cannbot/ -> 中间文件 + asc-devkit + cann-samples + ops-tensor |
| 110 | ├── .cannbot/permissions/*.js -> init Step 4.5 复制自 workflow-agent-permissions skill(角色配置文件) | 114 | ├── .cannbot/permissions/*.js -> init Step 4.5 复制自 workflow-agent-permissions skill(角色配置文件) |
| 111 | └── .cannbot/settings.json -> init Step 5.5 生成的工作流运行时配置(唯一文件:mode / surveyed / plugins / version / updated_at) | 115 | └── .cannbot/settings.json -> init Step 5.5 生成的工作流运行时配置(唯一文件:mode / surveyed / plugins / version / updated_at) |
| @@ -125,10 +129,10 @@ init 把源文件软链接到算子仓根的运行时目录(OpenCode 的 `.ope | |||
| 125 | |------|------|---------| | 129 | |------|------|---------| |
| 126 | | 1 | 建 `.cannbot/` 中间目录 | — | | 130 | | 1 | 建 `.cannbot/` 中间目录 | — | |
| 127 | | 2 | 链接配置文件 | `<install>/AGENTS.md` → `PLUGIN_ROOT/AGENTS.md`;`--override` 目录含 `AGENTS.md` 时 → `<override>/AGENTS.md`;claude 时额外 `<install>/CLAUDE.md` → 同源 | | 131 | | 2 | 链接配置文件 | `<install>/AGENTS.md` → `PLUGIN_ROOT/AGENTS.md`;`--override` 目录含 `AGENTS.md` 时 → `<override>/AGENTS.md`;claude 时额外 `<install>/CLAUDE.md` → 同源 | |
| 128 | -| 3 | **扁平化**链接 agents | 递归 `agents/`,按 basename 链接到运行时 `agents/*.md`(opencode `.opencode/agents/`、claude `.claude/agents/`);**codex** 从 `hooks/codex/*.toml` 生成 `.codex/agents/*.toml`(`__CANNBOT_AGENT_SOURCE__` 替换为 `agents/*.md` 绝对路径);**dsh** 链接到 `.dsh/agents/`——DSH 无原生 agent 注册(子 Agent 纯 prompt 驱动),仅作角色定义参考文件,init 输出说明 | | 132 | +| 3 | **扁平化**链接 agents | 递归 `agents/`,按 basename 链接到运行时 `agents/*.md`(opencode `.opencode/agents/`、claude `.claude/agents/`);**codex** 从 `hooks/codex/*.toml` 生成 `.codex/agents/*.toml`(`__CANNBOT_AGENT_SOURCE__` 替换为 `agents/*.md` 绝对路径);**dsh** 链接到 `.dsh/agents/`——DSH 无原生 agent 注册(子 Agent 纯 prompt 驱动),仅作角色定义参考文件,init 输出说明;**trae** 从 `agents/*.md` 生成 `.trae/agents/*.md`(TraeCode Subagent:frontmatter 注入 `tools` 按角色静态限权,保留 name/description 与正文;目录级写权限 Trae 不支持,由 prompt 约束) | |
| 129 | -| 4 | 链接 skills | 收集到的每个 skill 名 → 运行时 `skills/<name>`(opencode `.opencode/skills/`、claude `.claude/skills/`、**codex `.agents/skills/`**、**dsh `.dsh/skills/`**);`plugin-*/` 下含 SKILL.md 的嵌套子 skill 一并顶层链接;带 `--override <dir>` 时用 `<dir>/skills/` 同名替换、基类没有的新增(含嵌套子 skill) | | 133 | +| 4 | 链接 skills | 收集到的每个 skill 名 → 运行时 `skills/<name>`(opencode `.opencode/skills/`、claude `.claude/skills/`、**codex `.agents/skills/`**、**dsh `.dsh/skills/`**、**trae `.trae/skills/`**);`plugin-*/` 下含 SKILL.md 的嵌套子 skill 一并顶层链接;带 `--override <dir>` 时用 `<dir>/skills/` 同名替换、基类没有的新增(含嵌套子 skill) | |
| 130 | | 4.5 | 生成权限配置 | 从运行时 `skills/workflow-agent-permissions/hooks/` **复制**(非软链接)到 `.cannbot/permissions/`,**缺失才生成、已存在保留**(工作区配置优先) | | 134 | | 4.5 | 生成权限配置 | 从运行时 `skills/workflow-agent-permissions/hooks/` **复制**(非软链接)到 `.cannbot/permissions/`,**缺失才生成、已存在保留**(工作区配置优先) | |
| 131 | -| 4+ | 权限 hook | opencode:`hooks/opencode/permission-guard.js` → `<install>/.opencode/plugin/`;claude:`hooks/claude/permission-guard.js` → `<install>/.claude/hooks/`,并在 `.claude/settings.json` 幂等注册 PreToolUse hook(matcher `Write\|Edit\|MultiEdit\|NotebookEdit\|Question`,已注册而 matcher 缺 Question 时自动补充);**codex / dsh:无项目级 hook**,init 输出 WARNING 告知降级(角色隔离靠 prompt,非机制保证;dsh 的沙箱/审批策略在会话或部署层配置)。**dsh 可选机制升级**:部署级守卫 `hooks/dsh/permission-guard.js` 由 `hooks/dsh/install.sh` 安装到 `$DSH_HOME/cordis.patch.yml`(home 级 patch 层,对所有 profile 生效),监听 `tools/pre-execute` 恢复机制保证 | | 135 | +| 4+ | 权限 hook | opencode:`hooks/opencode/permission-guard.js` → `<install>/.opencode/plugin/`;claude:`hooks/claude/permission-guard.js` → `<install>/.claude/hooks/`,并在 `.claude/settings.json` 幂等注册 PreToolUse hook(matcher `Write\|Edit\|MultiEdit\|NotebookEdit\|Question`,已注册而 matcher 缺 Question 时自动补充);**codex / dsh:无项目级 hook**,init 输出 WARNING 告知降级(角色隔离靠 prompt,非机制保证;dsh 的沙箱/审批策略在会话或部署层配置)。**dsh 可选机制升级**:部署级守卫 `hooks/dsh/permission-guard.js` 由 `hooks/dsh/install.sh` 安装到 `$DSH_HOME/cordis.patch.yml`(home 级 patch 层,对所有 profile 生效),监听 `tools/pre-execute` 恢复机制保证。**trae**:`hooks/trae/permission-guard.js` → `<install>/.trae/hooks/`,并在 `.trae/hooks.json` 幂等注册 PreToolUse hook(matcher `AskUserQuestion`,静默问卷拦截);Trae PreToolUse stdin 无 agent 角色字段,**角色写权限由 .trae/agents/*.md 的 tools 静态限权**(Trae 原生机制),目录级靠 prompt(同 codex 降级) | |
| 132 | | 5.5 | 生成工作流配置(唯一配置) | 写 `.cannbot/settings.json`(version 2 / mode / surveyed / plugins / updated_at):**扫描 `skills/plugin-*/`(基类 + override,override 同名优先)frontmatter 生成 `plugins`(hook/stages/standalone/enabled)——重扫重写,保留各插件 `enabled`、并入新增(新增时 `surveyed` 复位)、剔除失效**;非法 hook / 缺 stages 仅 warn 不注册;`--mode` 写 `mode`(未传保留现有值);`--plugin-enable <name> on|off` 直接改 `enabled`;旧版 `plugin-registry.json` 一次性迁移并入后删除;生成失败仅 warn 不 fail | | 136 | | 5.5 | 生成工作流配置(唯一配置) | 写 `.cannbot/settings.json`(version 2 / mode / surveyed / plugins / updated_at):**扫描 `skills/plugin-*/`(基类 + override,override 同名优先)frontmatter 生成 `plugins`(hook/stages/standalone/enabled)——重扫重写,保留各插件 `enabled`、并入新增(新增时 `surveyed` 复位)、剔除失效**;非法 hook / 缺 stages 仅 warn 不注册;`--mode` 写 `mode`(未传保留现有值);`--plugin-enable <name> on|off` 直接改 `enabled`;旧版 `plugin-registry.json` 一次性迁移并入后删除;生成失败仅 warn 不 fail | |
| 133 | | 5/6 | clone asc-devkit / cann-samples / ops-tensor 到 `.cannbot/` | — | | 137 | | 5/6 | clone asc-devkit / cann-samples / ops-tensor 到 `.cannbot/` | — | |
| 134 | 138 | ||
| @@ -136,7 +140,7 @@ init 把源文件软链接到算子仓根的运行时目录(OpenCode 的 `.ope | |||
| 136 | 140 | ||
| 137 | **skill 源解析顺序**:本地 `skills/` → 本地 `plugin-*/` 嵌套子 skill → override `skills/` → override `plugin-*/` 嵌套子 skill → 共享 `../../ops/` → `../../infra/`。同名时靠前者优先。 | 141 | **skill 源解析顺序**:本地 `skills/` → 本地 `plugin-*/` 嵌套子 skill → override `skills/` → override `plugin-*/` 嵌套子 skill → 共享 `../../ops/` → `../../infra/`。同名时靠前者优先。 |
| 138 | 142 | ||
| 139 | -### 动态权限 hook(opencode / claude 项目级;dsh / codex 无项目级 hook——dsh 可选部署级守卫) | 143 | +### 动态权限 hook(opencode / claude / trae 项目级;dsh / codex 无项目级 hook——dsh 可选部署级守卫) |
| 140 | 144 | ||
| 141 | 按角色限制写权限——`.cannbot` 所有角色可写(任意类型)、项目外拒绝、code/test/doc 按角色限权: | 145 | 按角色限制写权限——`.cannbot` 所有角色可写(任意类型)、项目外拒绝、code/test/doc 按角色限权: |
| 142 | 146 | ||
| @@ -151,6 +155,9 @@ init 把源文件软链接到算子仓根的运行时目录(OpenCode 的 `.ope | |||
| 151 | - **codex 降级**:codex 无 PreToolUse / `tool.execute.before` 等拦截点,不部署权限 hook。角色写权限隔离由 AGENTS.md prompt 约束,非机制保证(违反 F2,已显式接受)。init 时输出 WARNING 告知用户。 | 155 | - **codex 降级**:codex 无 PreToolUse / `tool.execute.before` 等拦截点,不部署权限 hook。角色写权限隔离由 AGENTS.md prompt 约束,非机制保证(违反 F2,已显式接受)。init 时输出 WARNING 告知用户。 |
| 152 | - **dsh 降级**:dsh(DeepSeek Harness)无项目级拦截点(hook),init 不部署 permission-guard。角色写权限隔离默认由 prompt 约束;dsh 自身的文件沙箱(sandbox 模式)与审批策略(approval ask/never)在会话/部署层配置,不属于本项目文件机制。init 时输出 WARNING;`.cannbot/permissions/` 照常生成(PM 启动闸口与 workflow-agent-permissions 仍依赖)。 | 156 | - **dsh 降级**:dsh(DeepSeek Harness)无项目级拦截点(hook),init 不部署 permission-guard。角色写权限隔离默认由 prompt 约束;dsh 自身的文件沙箱(sandbox 模式)与审批策略(approval ask/never)在会话/部署层配置,不属于本项目文件机制。init 时输出 WARNING;`.cannbot/permissions/` 照常生成(PM 启动闸口与 workflow-agent-permissions 仍依赖)。 |
| 153 | - **dsh 可选机制升级**:dsh 有**部署级** Cordis 插件机制(非项目级)——`hooks/dsh/permission-guard.js`(监听 `tools/pre-execute` allow/deny 瀑布门,与 opencode/claude 同一套规则语义)由 `hooks/dsh/install.sh` 复制到 `$DSH_HOME/plugins/` 并在 `$DSH_HOME/cordis.patch.yml`(home 级 patch 层,对所有 profile 生效)幂等注册;`watchUserPatches` 支持热加载。安装后恢复按角色的写权限隔离与静默问卷拦截(仅作用于 cwd 下有 `.cannbot/permissions/` 的 cuda2ascend 工作区,其它项目放行)。角色识别:主 Agent(session header 无 `origin: "subagent"`)→ PM;子 Agent → 从持久 label(PM 派发 subagent 的 description,约定含角色名)经 `ctx.subagents.listChildren` 解析。未安装时按上条降级。 | 157 | - **dsh 可选机制升级**:dsh 有**部署级** Cordis 插件机制(非项目级)——`hooks/dsh/permission-guard.js`(监听 `tools/pre-execute` allow/deny 瀑布门,与 opencode/claude 同一套规则语义)由 `hooks/dsh/install.sh` 复制到 `$DSH_HOME/plugins/` 并在 `$DSH_HOME/cordis.patch.yml`(home 级 patch 层,对所有 profile 生效)幂等注册;`watchUserPatches` 支持热加载。安装后恢复按角色的写权限隔离与静默问卷拦截(仅作用于 cwd 下有 `.cannbot/permissions/` 的 cuda2ascend 工作区,其它项目放行)。角色识别:主 Agent(session header 无 `origin: "subagent"`)→ PM;子 Agent → 从持久 label(PM 派发 subagent 的 description,约定含角色名)经 `ctx.subagents.listChildren` 解析。未安装时按上条降级。 |
| 158 | +- **trae 实现**:trae 用 `hooks/trae/permission-guard.js`,作为 PreToolUse hook 读 stdin 事件 JSON,违规时 exit 2(stderr 回传模型)。**只做静默问卷拦截**——Trae PreToolUse stdin 无 agent 角色字段(与 opencode 的 session 反查、claude 的 `agent_type` 不同),无法按角色做目录级限权。 | ||
| 159 | +- **trae 角色写权限(静态)**:角色写权限隔离由 init Step 3 生成的 `.trae/agents/*.md` 的 frontmatter `tools` 承担——Trae Subagent 原生机制,按角色注入工具白名单(如 developer 系含 `RunCommand`,architect 不含)。目录级写权限(`.cannbot` 等)Trae 不支持,由 AGENTS.md prompt 约束(同 codex 降级,违反 F2 已显式接受)。init 时输出说明。 | ||
| 160 | +- **trae 加载**:init Step 4+ 链接到 `<install>/.trae/hooks/` 并在 `.trae/hooks.json` 幂等注册 PreToolUse hook(matcher `AskUserQuestion`,已注册而 matcher 缺 `Question` 时自动补充)。 | ||
| 154 | 161 | ||
| 155 | ### 子类 init(`<算子仓>/agent/init.sh`) | 162 | ### 子类 init(`<算子仓>/agent/init.sh`) |
| 156 | 163 | ||
Mplugins-community/cuda2ascend/skills/ops-direct-invoke-workflow-maintain/references/modify-skill.md+1-1
| @@ -1,7 +1,7 @@ | |||
| 1 | # 修改 virtual skill | 1 | # 修改 virtual skill |
| 2 | 2 | ||
| 3 | > 适用于:基类 `skills/repo-*/`、`skills/workflow-*/`(默认实现),子仓 `agent/skills/*`(override 实现)。 | 3 | > 适用于:基类 `skills/repo-*/`、`skills/workflow-*/`(默认实现),子仓 `agent/skills/*`(override 实现)。 |
| 4 | -> `<level>` 按当前运行环境确定(project/global)。目标工具支持 opencode / claude / codex / dsh。 | 4 | +> `<level>` 按当前运行环境确定(project/global)。目标工具支持 opencode / claude / codex / dsh / trae。 |
| 5 | 5 | ||
| 6 | ## 核心概念 | 6 | ## 核心概念 |
| 7 | 7 | ||
| @@ -51,12 +51,12 @@ | |||
| 51 | |------|--------| | 51 | |------|--------| |
| 52 | | L1 | 新增/删除 skill 后,是否重新运行了 init 使软链接生效? | | 52 | | L1 | 新增/删除 skill 后,是否重新运行了 init 使软链接生效? | |
| 53 | | L2 | 子仓 override 的逻辑名(skill 目录名 / SKILL.md 的 `name:`)是否与基类一致,能被正确匹配? | | 53 | | L2 | 子仓 override 的逻辑名(skill 目录名 / SKILL.md 的 `name:`)是否与基类一致,能被正确匹配? | |
| 54 | -| L3 | 是否只改了源文件,没有直接改运行时目录(`.opencode/` / `.claude/` / `.dsh/`)里的软链接目标? | | 54 | +| L3 | 是否只改了源文件,没有直接改运行时目录(`.opencode/` / `.claude/` / `.dsh/` / `.trae/`)里的软链接目标? | |
| 55 | | L4 | 新增 skill 若需被某 agent 或 PM 使用,是否已加入对应 `agents/<name>.md` 或 `AGENTS.md` 的 `skills:` frontmatter,否则 init 收集不到? | | 55 | | L4 | 新增 skill 若需被某 agent 或 PM 使用,是否已加入对应 `agents/<name>.md` 或 `AGENTS.md` 的 `skills:` frontmatter,否则 init 收集不到? | |
| 56 | | L5 | 改动了流程(阶段 / CP / 回退关系)后,插件根 `README.md` 的「开发流程概览」表是否仍与 `ops-direct-invoke-workflow/SKILL.md` 的统一流程表一致(阶段、CP 编号、回退指向)? | | 56 | | L5 | 改动了流程(阶段 / CP / 回退关系)后,插件根 `README.md` 的「开发流程概览」表是否仍与 `ops-direct-invoke-workflow/SKILL.md` 的统一流程表一致(阶段、CP 编号、回退指向)? | |
| 57 | | L6 | 改动了 `init.sh` 的 CLI 参数(新增 / 删除 / 重命名 / 语义变更)或 override 展开逻辑后,`example/init.sh` 是否仍然兼容?该文件已分发到各子仓,若不兼容必须发问卷知会用户决策是否迁移 | | 57 | | L6 | 改动了 `init.sh` 的 CLI 参数(新增 / 删除 / 重命名 / 语义变更)或 override 展开逻辑后,`example/init.sh` 是否仍然兼容?该文件已分发到各子仓,若不兼容必须发问卷知会用户决策是否迁移 | |
| 58 | | L7 | 改动 agent 文件后,检查其正文中是否有"用 `xxx` skill"、"加载 `xxx`"、"引用 `xxx`"等 skill 依赖声明——若有,该 skill 是否已全部列入 `skills:` frontmatter?漏掉的 skill 不会被 init 链接,运行时加载会失败 | | 58 | | L7 | 改动 agent 文件后,检查其正文中是否有"用 `xxx` skill"、"加载 `xxx`"、"引用 `xxx`"等 skill 依赖声明——若有,该 skill 是否已全部列入 `skills:` frontmatter?漏掉的 skill 不会被 init 链接,运行时加载会失败 | |
| 59 | -| L8 | 修改 `skills/workflow-agent-permissions/hooks/*.js`(新增/删除角色文件、调整 categories/exts)后,是否同步更新了**三侧**内置默认值 `DEFAULT_RULES`(`hooks/opencode/`、`hooks/claude/` 与 `hooks/dsh/permission-guard.js`)?三者互为兜底(skill 文件为真值源、hook 内置为防御兜底),不同步会导致「配置缺失时角色行为与预期不一致」 | | 59 | +| L8 | 修改 `skills/workflow-agent-permissions/hooks/*.js`(新增/删除角色文件、调整 categories/exts)后,是否同步更新了**各侧**内置默认值 `DEFAULT_RULES`(`hooks/opencode/`、`hooks/claude/`、`hooks/dsh/permission-guard.js`;trae 侧无 DEFAULT_RULES——角色写权限由 `.trae/agents/*.md` 的 `tools` 静态声明承担,改角色权限时需同步 init Step 3 的 `ROLE_TOOLS` 映射)?各侧互为兜底(skill 文件为真值源、hook 内置为防御兜底),不同步会导致「配置缺失时角色行为与预期不一致」 | |
| 60 | 60 | ||
| 61 | ## 六、插件约束(plugin-*) | 61 | ## 六、插件约束(plugin-*) |
| 62 | 62 | ||
| @@ -78,7 +78,7 @@ | |||
| 78 | | M3 | ⛔ 确认点(CP0/CP1/CP2.2)的静默默认决策是否落盘 `.reply.json`(`{"mode":"silent","decision":"accepted"}`),中断恢复表(task-prompts recovery)是否无需感知静默? | | 78 | | M3 | ⛔ 确认点(CP0/CP1/CP2.2)的静默默认决策是否落盘 `.reply.json`(`{"mode":"silent","decision":"accepted"}`),中断恢复表(task-prompts recovery)是否无需感知静默? | |
| 79 | | M4 | 静默例外清单是否完整且唯一(权限预检警告 / 任务完成总结),无其它隐含输出;插件内异步等待的告知是否归插件自身约定而非主工作流例外清单? | | 79 | | M4 | 静默例外清单是否完整且唯一(权限预检警告 / 任务完成总结),无其它隐含输出;插件内异步等待的告知是否归插件自身约定而非主工作流例外清单? | |
| 80 | | M5 | 修改 `--mode` 或 Step 5.5 后,`example/init.sh` 是否仍兼容(基类参数只增不破坏)? | | 80 | | M5 | 修改 `--mode` 或 Step 5.5 后,`example/init.sh` 是否仍兼容(基类参数只增不破坏)? | |
| 81 | -| M6 | 静默问卷拦截是否三侧同步(`hooks/opencode/permission-guard.js`、`hooks/claude/permission-guard.js` 与 `hooks/dsh/permission-guard.js` 的 `SILENT_GUARDED_TOOLS` / `readSilentMode` 语义一致)?claude 的 PreToolUse matcher 是否含 `Question`(init 注册与已注册补充)?**`SILENT_GUARDED_TOOLS` 的取值是否与各 harness 的问卷工具真实名对得上**(claude 侧为 `AskUserQuestion`、dsh 侧为 `ask_user_question`,hook 内按子串匹配;只对 matcher 不对工具名,拦截会静默空转) | | 81 | +| M6 | 静默问卷拦截是否各侧同步(`hooks/opencode/permission-guard.js`、`hooks/claude/permission-guard.js`、`hooks/dsh/permission-guard.js` 与 `hooks/trae/permission-guard.js` 的 `SILENT_GUARDED_TOOLS` / `readSilentMode` 语义一致)?claude 的 PreToolUse matcher 是否含 `Question`(init 注册与已注册补充)?trae 的 hooks.json matcher 是否命中 `AskUserQuestion`(init 注册与已注册补充)?**`SILENT_GUARDED_TOOLS` 的取值是否与各 harness 的问卷工具真实名对得上**(claude 侧为 `AskUserQuestion`、dsh 侧为 `ask_user_question`、trae 侧为 `AskUserQuestion`,hook 内按子串匹配;只对 matcher 不对工具名,拦截会静默空转) | |
| 82 | 82 | ||
| 83 | ## 八、子仓兼容性(`example/init.sh` 分发契约) | 83 | ## 八、子仓兼容性(`example/init.sh` 分发契约) |
| 84 | 84 | ||
| @@ -53,7 +53,7 @@ description: 直调算子开发工作流编排技能,承载从算子需求分 | |||
| 53 | | 7.1 | 开发报告 | developer-doc→PM | 全部交付物 | 开发报告 | developer-doc 整理开发过程与交付物清单,PM 落盘 `.cannbot/<算子名>/` | | | 53 | | 7.1 | 开发报告 | developer-doc→PM | 全部交付物 | 开发报告 | developer-doc 整理开发过程与交付物清单,PM 落盘 `.cannbot/<算子名>/` | | |
| 54 | | 7.2 | 经验总结 | developer-doc→PM | 开发过程记录 | 经验总结文档 | developer-doc 沉淀开发经验与踩坑记录,PM 落盘 `.cannbot/<算子名>/` | | | 54 | | 7.2 | 经验总结 | developer-doc→PM | 开发过程记录 | 经验总结文档 | developer-doc 沉淀开发经验与踩坑记录,PM 落盘 `.cannbot/<算子名>/` | | |
| 55 | 55 | ||
| 56 | -- ⛔ 标记的为**用户确认点**,QA 生成结构化问卷 json,用会话问卷工具(opencode `question` / claude `AskUserQuestion` / dsh `ask_user_question`)直接发送用户并收集结论;问卷与用户回复成对落盘 `.cannbot/<算子名>/questionnaires/`(回复记为问卷同名 `.reply.json`) | 56 | +- ⛔ 标记的为**用户确认点**,QA 生成结构化问卷 json,用会话问卷工具(opencode `question` / claude `AskUserQuestion` / dsh `ask_user_question` / trae `AskUserQuestion`)直接发送用户并收集结论;问卷与用户回复成对落盘 `.cannbot/<算子名>/questionnaires/`(回复记为问卷同名 `.reply.json`) |
| 57 | - 可插拔流程步骤(如提交 PR 到上库、性能迭代)由 PM 按 `.cannbot/settings.json` 的 plugins 中启用的插件在其挂载点触发,不在本表列出 | 57 | - 可插拔流程步骤(如提交 PR 到上库、性能迭代)由 PM 按 `.cannbot/settings.json` 的 plugins 中启用的插件在其挂载点触发,不在本表列出 |
| 58 | - 方案线与测试线在阶段 2、3 并行推进 | 58 | - 方案线与测试线在阶段 2、3 并行推进 |
| 59 | - CP3/CP4/CP5 任一不通过均回退到算子开发(3.1)后依次重走(重走路径经 3.4 联调) | 59 | - CP3/CP4/CP5 任一不通过均回退到算子开发(3.1)后依次重走(重走路径经 3.4 联调) |
| @@ -64,7 +64,7 @@ | |||
| 64 | 64 | ||
| 65 | 其余一切进度、结论、中间信息均不输出。 | 65 | 其余一切进度、结论、中间信息均不输出。 |
| 66 | 66 | ||
| 67 | -> **机制兜底**:`mode=silent` 时 permission-guard hook 在工具层拦截问卷发送(opencode `question`/`ask` / claude `AskUserQuestion`,按工具名子串匹配,任何角色都不得绕过)——「QA 不发送问卷」既是 prompt 约束,也有 hook 保证;`mode` 切回 `interactive` 后立即解除拦截(见 `workflow-agent-permissions` skill)。**dsh**:默认无项目级 hook、无机制兜底(仅 prompt 约束);安装部署级守卫(`hooks/dsh/install.sh`,挂 `$DSH_HOME/cordis.patch.yml`)后,`tools/pre-execute` 门按同一语义拦截 `ask_user_question` 等问卷工具。**codex**:无 hook,仅 prompt 约束。 | 67 | +> **机制兜底**:`mode=silent` 时 permission-guard hook 在工具层拦截问卷发送(opencode `question`/`ask` / claude `AskUserQuestion` / trae `AskUserQuestion`,按工具名子串匹配,任何角色都不得绕过)——「QA 不发送问卷」既是 prompt 约束,也有 hook 保证;`mode` 切回 `interactive` 后立即解除拦截(见 `workflow-agent-permissions` skill)。**dsh**:默认无项目级 hook、无机制兜底(仅 prompt 约束);安装部署级守卫(`hooks/dsh/install.sh`,挂 `$DSH_HOME/cordis.patch.yml`)后,`tools/pre-execute` 门按同一语义拦截 `ask_user_question` 等问卷工具。**codex**:无 hook,仅 prompt 约束。**trae**:`.trae/hooks.json` 注册 PreToolUse hook 拦截 `AskUserQuestion`(按子串匹配),恢复机制兜底。 |
| 68 | 68 | ||
| 69 | ### 静默默认决策表(用户确认点替代) | 69 | ### 静默默认决策表(用户确认点替代) |
| 70 | 70 | ||
| @@ -83,4 +83,4 @@ | |||
| 83 | 83 | ||
| 84 | ## 交互模式(mode=interactive,默认) | 84 | ## 交互模式(mode=interactive,默认) |
| 85 | 85 | ||
| 86 | -按工作流既有约定执行:⛔ 确认点由 QA 用会话问卷工具(opencode `question` / claude `AskUserQuestion` / dsh `ask_user_question`)直接发送用户并收集结论,PM 汇报中间进度。本模式为默认,settings.json 缺失时即此模式。 | 86 | +按工作流既有约定执行:⛔ 确认点由 QA 用会话问卷工具(opencode `question` / claude `AskUserQuestion` / dsh `ask_user_question` / trae `AskUserQuestion`)直接发送用户并收集结论,PM 汇报中间进度。本模式为默认,settings.json 缺失时即此模式。 |
| @@ -54,7 +54,7 @@ | |||
| 54 | | `completed_stages` | 已通过的阶段列表,恢复时跳过。可插拔流程插件的内部步骤编号亦记入本列表,编号含义见对应插件文档 | | 54 | | `completed_stages` | 已通过的阶段列表,恢复时跳过。可插拔流程插件的内部步骤编号亦记入本列表,编号含义见对应插件文档 | |
| 55 | | `blocked` | 暂停时填充;`at`=阻塞的环节(CP 或流程表步骤),`reason`=问题摘要,`round`=当前轮次,`loop`=所属循环(`design`/`joint_debug`/`acceptance` 对应 [error-handling.md](error-handling.md) 的轮次表;`ci` 属上库插件的轮次表,见对应插件文档) | | 55 | | `blocked` | 暂停时填充;`at`=阻塞的环节(CP 或流程表步骤),`reason`=问题摘要,`round`=当前轮次,`loop`=所属循环(`design`/`joint_debug`/`acceptance` 对应 [error-handling.md](error-handling.md) 的轮次表;`ci` 属上库插件的轮次表,见对应插件文档) | |
| 56 | | `rounds` | 各环节已用轮次,**按流程表编号分槽计数**(含 3.4 联调槽位);跨环节回退(如 CP2.2 因归属需求回退 1.1)不清零发起方槽位,避免往返途中计数丢失导致循环失去边界。`blocked.round` 取当前阻塞环节的槽值 | | 56 | | `rounds` | 各环节已用轮次,**按流程表编号分槽计数**(含 3.4 联调槽位);跨环节回退(如 CP2.2 因归属需求回退 1.1)不清零发起方槽位,避免往返途中计数丢失导致循环失去边界。`blocked.round` 取当前阻塞环节的槽值 | |
| 57 | -| `pending_questionnaire` | 有问卷待用户答复时填;`cp`=发出问卷的 CP,`path`=问卷 json 路径,`reply_path`=用户回复落盘路径(问卷同名加 `.reply` 后缀,如 `1.需求.json` → `1.需求.reply.json`),`status`=`sent`(PM 派出问卷类 CP 时预填,已发未回)/ `answered`(QA 结论已回传、未处理)。问卷由 QA 用会话问卷工具(opencode `question` / claude `AskUserQuestion` / dsh `ask_user_question`)直接发送用户:发出时落盘 `path`,收到回复后先落盘 `reply_path` 再回传,问卷与回复成对持久化。用户确认类 CP(CP0 / CP1 / CP2.2)中断恢复的依据,处理完毕后清空 | | 57 | +| `pending_questionnaire` | 有问卷待用户答复时填;`cp`=发出问卷的 CP,`path`=问卷 json 路径,`reply_path`=用户回复落盘路径(问卷同名加 `.reply` 后缀,如 `1.需求.json` → `1.需求.reply.json`),`status`=`sent`(PM 派出问卷类 CP 时预填,已发未回)/ `answered`(QA 结论已回传、未处理)。问卷由 QA 用会话问卷工具(opencode `question` / claude `AskUserQuestion` / dsh `ask_user_question` / trae `AskUserQuestion`)直接发送用户:发出时落盘 `path`,收到回复后先落盘 `reply_path` 再回传,问卷与回复成对持久化。用户确认类 CP(CP0 / CP1 / CP2.2)中断恢复的依据,处理完毕后清空 | |
| 58 | | `pending_user_review` | **待用户复核的需求级决策**列表(放宽需求文档声明的性能 / 精度硬门槛等)。每条:`at`=作出决策的环节,`decision`=决策内容,`scope`=涉及的具体项与量化差距,`evidence_path`=完整依据所在交付件,`decided_by`/`decided_at`=作出方与时间。**只增不自行清除**——须随任务完成总结逐条上报,由用户裁定后才可移除并记录裁定结果。无此类决策时省略该字段或置空数组 | | 58 | | `pending_user_review` | **待用户复核的需求级决策**列表(放宽需求文档声明的性能 / 精度硬门槛等)。每条:`at`=作出决策的环节,`decision`=决策内容,`scope`=涉及的具体项与量化差距,`evidence_path`=完整依据所在交付件,`decided_by`/`decided_at`=作出方与时间。**只增不自行清除**——须随任务完成总结逐条上报,由用户裁定后才可移除并记录裁定结果。无此类决策时省略该字段或置空数组 | |
| 59 | | `deliverables` | 已产出交付件路径(与 [data-flow.md](data-flow.md) 的落盘位置一致) | | 59 | | `deliverables` | 已产出交付件路径(与 [data-flow.md](data-flow.md) 的落盘位置一致) | |
| 60 | | `updated_at` | 最后更新时间(ISO8601) | | 60 | | `updated_at` | 最后更新时间(ISO8601) | |
| @@ -6,7 +6,7 @@ | |||
| 6 | > | 6 | > |
| 7 | > **工具差异(dsh)**:dsh(DeepSeek Harness)无命名 agent 注册(子 Agent 纯 prompt 驱动,角色定义文件位于 `.dsh/agents/<角色>.md`),PM 用 subagent 工具派发:**prompt = 对应角色定义全文(`.dsh/agents/<角色>.md` 正文)+ 本文档 prompt 原样 + 任务输入**,子 Agent 才能获得完整角色上下文;回退/续跑复用原子 Agent 会话(send_message 追加 prompt),不新建会话。**派发时 subagent 工具的 description 必须含角色名**(如「architect:需求分析」)——部署级权限守卫(`hooks/dsh/install.sh`)据此识别子 Agent 角色并按 `.cannbot/permissions/` 规则判权。 | 7 | > **工具差异(dsh)**:dsh(DeepSeek Harness)无命名 agent 注册(子 Agent 纯 prompt 驱动,角色定义文件位于 `.dsh/agents/<角色>.md`),PM 用 subagent 工具派发:**prompt = 对应角色定义全文(`.dsh/agents/<角色>.md` 正文)+ 本文档 prompt 原样 + 任务输入**,子 Agent 才能获得完整角色上下文;回退/续跑复用原子 Agent 会话(send_message 追加 prompt),不新建会话。**派发时 subagent 工具的 description 必须含角色名**(如「architect:需求分析」)——部署级权限守卫(`hooks/dsh/install.sh`)据此识别子 Agent 角色并按 `.cannbot/permissions/` 规则判权。 |
| 8 | > | 8 | > |
| 9 | -> **权限行的机制差异**:各 prompt 的【权限】行中「其它写入操作会被 hooks 拦截」在 opencode / claude 由 permission-guard hook 机制保证;在无项目级 hook 环境(dsh / codex)下降级为**提示性约束**——子 Agent 依据 `workflow-agent-permissions` 的规则自律,违规写入不会被拦截,PM 派发时仍须按该 skill 判定角色权限。**dsh 可选升级**:运行 `hooks/dsh/install.sh` 安装部署级守卫后,dsh 恢复机制保证(拦截语义与 opencode/claude 一致)。 | 9 | +> **权限行的机制差异**:各 prompt 的【权限】行中「其它写入操作会被 hooks 拦截」在 opencode / claude 由 permission-guard hook 机制保证;在无项目级 hook 环境(dsh / codex)下降级为**提示性约束**——子 Agent 依据 `workflow-agent-permissions` 的规则自律,违规写入不会被拦截,PM 派发时仍须按该 skill 判定角色权限。**dsh 可选升级**:运行 `hooks/dsh/install.sh` 安装部署级守卫后,dsh 恢复机制保证(拦截语义与 opencode/claude 一致)。**trae**:角色写权限由 `.trae/agents/*.md` 的 frontmatter `tools` 静态限权(Trae Subagent 原生机制,init 生成时按角色注入),目录级写权限(`.cannbot` 等)靠 prompt 自律——PM 派发时仍须按 `workflow-agent-permissions` 判定角色权限。 |
| 10 | 10 | ||
| 11 | # 阶段 0:开发准备 | 11 | # 阶段 0:开发准备 |
| 12 | 12 | ||
| @@ -25,7 +25,7 @@ disable-model-invocation: true | |||
| 25 | | 编号 | 流程 | 角色 | 输入 | 输出 | 说明 | 备注 | | 25 | | 编号 | 流程 | 角色 | 输入 | 输出 | 说明 | 备注 | |
| 26 | |------|------|------|------|------|------|------| | 26 | |------|------|------|------|------|------|------| |
| 27 | | plugin-experience-summary-1 | 开发回顾与踩坑总结 | developer-doc | 全部过程产物 | 踩坑回顾段落(暂存) | 回顾本次开发全过程;总结本仓开发容易踩坑、而本仓 skill 未说明确的点(对照各 skill 文档定位盲区) | **与 2/3 并行派发**;产出先落 `.cannbot/<算子名>/tmp/经验总结-1-踩坑回顾.md` | | 27 | | plugin-experience-summary-1 | 开发回顾与踩坑总结 | developer-doc | 全部过程产物 | 踩坑回顾段落(暂存) | 回顾本次开发全过程;总结本仓开发容易踩坑、而本仓 skill 未说明确的点(对照各 skill 文档定位盲区) | **与 2/3 并行派发**;产出先落 `.cannbot/<算子名>/tmp/经验总结-1-踩坑回顾.md` | |
| 28 | -| plugin-experience-summary-2 | hooks 异常拦截分析 | developer-doc | 拦截记录(state/LOG/tmp)+ 两侧 hook 源 | hooks 分析与修复建议段落(暂存) | 梳理本次会话中 permission-guard 与静默问卷拦截的实际拦截/漏拦/误拦记录,对照 `hooks/opencode/` 与 `hooks/claude/` 源给出建议修复点;**dsh(未安装部署级守卫时)/ codex 等无 hook 环境**:本步直接输出「该环境无 permission-guard 机制、无拦截记录」,并基于 `workflow-agent-permissions` 规则给静态建议;dsh 已安装部署级守卫(`hooks/dsh/permission-guard.js`)时按常规流程梳理,hook 源对照 `hooks/dsh/` | **与 1/3 并行派发**;产出落 `.cannbot/<算子名>/tmp/经验总结-2-hooks分析.md` | | 28 | +| plugin-experience-summary-2 | hooks 异常拦截分析 | developer-doc | 拦截记录(state/LOG/tmp)+ 两侧 hook 源 | hooks 分析与修复建议段落(暂存) | 梳理本次会话中 permission-guard 与静默问卷拦截的实际拦截/漏拦/误拦记录,对照 `hooks/opencode/` 与 `hooks/claude/` 源给出建议修复点(trae 侧源为 `hooks/trae/permission-guard.js`,仅静默问卷拦截);**dsh(未安装部署级守卫时)/ codex 等无 hook 环境**:本步直接输出「该环境无 permission-guard 机制、无拦截记录」,并基于 `workflow-agent-permissions` 规则给静态建议;dsh 已安装部署级守卫(`hooks/dsh/permission-guard.js`)时按常规流程梳理,hook 源对照 `hooks/dsh/` | **与 1/3 并行派发**;产出落 `.cannbot/<算子名>/tmp/经验总结-2-hooks分析.md` | |
| 29 | | plugin-experience-summary-3 | 耗时统计与重试定位 | developer-doc | state.json 时间戳、LOG.md、回退记录 | 耗时统计段落(暂存) | 统计本次工作流运行总时长(首步启动至收尾,按阶段/CP 分解),总结反复重试耗时的地方(回退轮次、CI 等待、性能迭代等) | **与 1/2 并行派发**;产出落 `.cannbot/<算子名>/tmp/经验总结-3-耗时统计.md` | | 29 | | plugin-experience-summary-3 | 耗时统计与重试定位 | developer-doc | state.json 时间戳、LOG.md、回退记录 | 耗时统计段落(暂存) | 统计本次工作流运行总时长(首步启动至收尾,按阶段/CP 分解),总结反复重试耗时的地方(回退轮次、CI 等待、性能迭代等) | **与 1/2 并行派发**;产出落 `.cannbot/<算子名>/tmp/经验总结-3-耗时统计.md` | |
| 30 | | plugin-experience-summary-4 | 汇总与 issue 征询 | PM | 前三段产物 + `.cannbot/环境信息.md` | `.cannbot/<算子名>/插件经验总结.md` + 征询结论 | 整合三段为完整经验总结并落盘;**检查环境信息文档的「环境补充记录」节——非空(曾被探索补充)时在总结中建议提 Issue 补充环境检查内容**;征询用户是否需要拟 issue 反馈到 cannbot-skills 仓——同意则加载 `gitcode-issue-gen` 拟 issue 草稿交用户确认后提交 | 三段缺失或不全时回退对应步骤补齐,往返不超过 2 轮 | | 30 | | plugin-experience-summary-4 | 汇总与 issue 征询 | PM | 前三段产物 + `.cannbot/环境信息.md` | `.cannbot/<算子名>/插件经验总结.md` + 征询结论 | 整合三段为完整经验总结并落盘;**检查环境信息文档的「环境补充记录」节——非空(曾被探索补充)时在总结中建议提 Issue 补充环境检查内容**;征询用户是否需要拟 issue 反馈到 cannbot-skills 仓——同意则加载 `gitcode-issue-gen` 拟 issue 草稿交用户确认后提交 | 三段缺失或不全时回退对应步骤补齐,往返不超过 2 轮 | |
| 31 | 31 | ||
| @@ -24,7 +24,7 @@ | |||
| 24 | 24 | ||
| 25 | ```md | 25 | ```md |
| 26 | - 【权限】你只可写 `.cannbot/<算子名>/tmp/`,其它写入操作会被 hooks 拦截。 | 26 | - 【权限】你只可写 `.cannbot/<算子名>/tmp/`,其它写入操作会被 hooks 拦截。 |
| 27 | -- 【输入】本次会话的拦截记录(从 state.json、LOG.md、Issue-问题记录、tmp/ 中寻找 permission-guard / 静默问卷拦截相关记录);hook 源文件:`hooks/opencode/permission-guard.js` 与 `hooks/claude/permission-guard.js`(只读,不修改;**dsh 未安装部署级守卫时 / codex 等无 hook 环境没有这些源文件**,见验收标准;dsh 已安装守卫时另可对照 `hooks/dsh/permission-guard.js`)。 | 27 | +- 【输入】本次会话的拦截记录(从 state.json、LOG.md、Issue-问题记录、tmp/ 中寻找 permission-guard / 静默问卷拦截相关记录);hook 源文件:`hooks/opencode/permission-guard.js` 与 `hooks/claude/permission-guard.js`(只读,不修改;trae 侧为 `hooks/trae/permission-guard.js`——仅静默问卷拦截,角色写权限靠 `.trae/agents/*.md` 的 `tools` 静态限权;**dsh 未安装部署级守卫时 / codex 等无 hook 环境没有这些源文件**,见验收标准;dsh 已安装守卫时另可对照 `hooks/dsh/permission-guard.js`)。 |
| 28 | - 【输出】hooks 分析与修复建议段落,写入 `.cannbot/<算子名>/tmp/经验总结-2-hooks分析.md`。 | 28 | - 【输出】hooks 分析与修复建议段落,写入 `.cannbot/<算子名>/tmp/经验总结-2-hooks分析.md`。 |
| 29 | - 【参考资料】读取 `workflow-agent-permissions` 的 SKILL.md **原文**作为权限范围与守卫边界的基准(该 skill 不经 skill 加载工具触发,直接读文件)。 | 29 | - 【参考资料】读取 `workflow-agent-permissions` 的 SKILL.md **原文**作为权限范围与守卫边界的基准(该 skill 不经 skill 加载工具触发,直接读文件)。 |
| 30 | - 【验收标准】逐条记录本次会话中的实际拦截/漏拦/误拦事件(含事件上下文、角色、工具、结果);对照两侧 hook 源给出建议修复点(如规则缺失、误伤、语义不一致、两侧语义不同步),每条标注严重度与修复位置;无拦截记录时明确写出「本次会话无 hooks 拦截记录」,并基于两侧 hook 源给静态建议。**误拦事件须追到规则层根因**(是路径分类规则不匹配,还是角色权限范围本身不含该目录)——绕开守卫落盘属绕行手段,不作为修复结论。**无 hook 环境(dsh 未安装部署级守卫时 / codex)**:直接输出「该环境无 permission-guard 机制、无拦截记录」,并基于 `workflow-agent-permissions` 的规则表(路径分类 / 角色可写范围 / 静默问卷约束)给静态建议,不引用不存在的 hook 源。 | 30 | - 【验收标准】逐条记录本次会话中的实际拦截/漏拦/误拦事件(含事件上下文、角色、工具、结果);对照两侧 hook 源给出建议修复点(如规则缺失、误伤、语义不一致、两侧语义不同步),每条标注严重度与修复位置;无拦截记录时明确写出「本次会话无 hooks 拦截记录」,并基于两侧 hook 源给静态建议。**误拦事件须追到规则层根因**(是路径分类规则不匹配,还是角色权限范围本身不含该目录)——绕开守卫落盘属绕行手段,不作为修复结论。**无 hook 环境(dsh 未安装部署级守卫时 / codex)**:直接输出「该环境无 permission-guard 机制、无拦截记录」,并基于 `workflow-agent-permissions` 的规则表(路径分类 / 角色可写范围 / 静默问卷约束)给静态建议,不引用不存在的 hook 源。 |
| @@ -50,6 +50,6 @@ | |||
| 50 | - 读取 `.cannbot/<算子名>/tmp/经验总结-{1,2,3}-*.md` 三段,整合为完整经验总结:① 踩坑回顾(仅本仓 skill 未说明确的点)② hooks 异常拦截分析与建议修复点 ③ 耗时统计与反复重试定位 ④ 汇总与后续建议;落盘 `.cannbot/<算子名>/插件经验总结.md`。 | 50 | - 读取 `.cannbot/<算子名>/tmp/经验总结-{1,2,3}-*.md` 三段,整合为完整经验总结:① 踩坑回顾(仅本仓 skill 未说明确的点)② hooks 异常拦截分析与建议修复点 ③ 耗时统计与反复重试定位 ④ 汇总与后续建议;落盘 `.cannbot/<算子名>/插件经验总结.md`。 |
| 51 | - **环境检查**:读取 `.cannbot/环境信息.md` 的「环境补充记录」节——若该节非空(本次开发中环境项曾被探索补充),说明初始环境检查(步骤 0)未覆盖到这些项,在总结中**建议提 Issue 补充环境检查内容**(列出被补充的环境项与缺失原因);该建议与其它建议一并纳入下方 issue 征询。 | 51 | - **环境检查**:读取 `.cannbot/环境信息.md` 的「环境补充记录」节——若该节非空(本次开发中环境项曾被探索补充),说明初始环境检查(步骤 0)未覆盖到这些项,在总结中**建议提 Issue 补充环境检查内容**(列出被补充的环境项与缺失原因);该建议与其它建议一并纳入下方 issue 征询。 |
| 52 | - 三段任一缺失或不全:回退对应步骤(plugin-experience-summary-1/2/3)补齐后重试,往返不超过 2 轮。 | 52 | - 三段任一缺失或不全:回退对应步骤(plugin-experience-summary-1/2/3)补齐后重试,往返不超过 2 轮。 |
| 53 | -- 落盘后征询用户:是否需要拟一条 issue 反馈到 cannbot-skills 仓(gitcode.com/cann/cannbot-skills)?——交互模式用会话问卷工具(opencode `question` / claude `AskUserQuestion` / dsh `ask_user_question`)直接发送用户;静默模式并入任务完成总结列出选项。 | 53 | +- 落盘后征询用户:是否需要拟一条 issue 反馈到 cannbot-skills 仓(gitcode.com/cann/cannbot-skills)?——交互模式用会话问卷工具(opencode `question` / claude `AskUserQuestion` / dsh `ask_user_question` / trae `AskUserQuestion`)直接发送用户;静默模式并入任务完成总结列出选项。 |
| 54 | - 用户同意:加载 `gitcode-issue-gen`,按模板拟 issue 草稿(标题、分类、现象、建议修复点、复现/证据),**先交用户确认后再提交**;用户不同意或暂缓:在插件经验总结.md 中记录征询结论。 | 54 | - 用户同意:加载 `gitcode-issue-gen`,按模板拟 issue 草稿(标题、分类、现象、建议修复点、复现/证据),**先交用户确认后再提交**;用户不同意或暂缓:在插件经验总结.md 中记录征询结论。 |
| 55 | ``` | 55 | ``` |
| @@ -16,7 +16,7 @@ disable-model-invocation: true | |||
| 16 | | developer-test | test | 任意 | 测试工程(评测集 cases 对齐、白盒补充、本地自测脚本) | | 16 | | developer-test | test | 任意 | 测试工程(评测集 cases 对齐、白盒补充、本地自测脚本) | |
| 17 | | developer-doc | 代码 + test + doc | 仅 `.md` | 文档产出 | | 17 | | developer-doc | 代码 + test + doc | 仅 `.md` | 文档产出 | |
| 18 | 18 | ||
| 19 | -派发非 `.cannbot` 目录的写任务时,必须选择对应可写范围的角色;权限不足会被 hook 拦截并提示上报主 Agent(**dsh / codex 无项目级权限 hook**:默认拦截缺失,规则降级为 prompt 约束——PM 依本 skill 判定避免无效派发,子 Agent 依 prompt 自律,违规写入无机制拦截。**dsh 可选机制升级**:运行 `hooks/dsh/install.sh` 安装部署级 Cordis 守卫插件(`$DSH_HOME/cordis.patch.yml`,对所有 profile 生效),即恢复与 opencode/claude 同语义的机制拦截,仅作用于 cuda2ascend 初始化的工作区)。 | 19 | +派发非 `.cannbot` 目录的写任务时,必须选择对应可写范围的角色;权限不足会被 hook 拦截并提示上报主 Agent(**dsh / codex 无项目级权限 hook**:默认拦截缺失,规则降级为 prompt 约束——PM 依本 skill 判定避免无效派发,子 Agent 依 prompt 自律,违规写入无机制拦截。**dsh 可选机制升级**:运行 `hooks/dsh/install.sh` 安装部署级 Cordis 守卫插件(`$DSH_HOME/cordis.patch.yml`,对所有 profile 生效),即恢复与 opencode/claude 同语义的机制拦截,仅作用于 cuda2ascend 初始化的工作区。**trae**:PreToolUse hook 只做静默问卷拦截,角色写权限由 `.trae/agents/*.md` 的 frontmatter `tools` 静态限权(Trae Subagent 原生机制,init 生成时注入),目录级写权限靠 prompt 约束)。 |
| 20 | 20 | ||
| 21 | ## 目录类别的判定方式 | 21 | ## 目录类别的判定方式 |
| 22 | 22 | ||
| @@ -41,7 +41,7 @@ disable-model-invocation: true | |||
| 41 | 41 | ||
| 42 | ## 静默模式问卷拦截 | 42 | ## 静默模式问卷拦截 |
| 43 | 43 | ||
| 44 | -静默模式(`.cannbot/settings.json` 的 `mode=silent`)启用时,permission-guard hook 在机制层拦截问卷工具(opencode 的 `question`/`ask`、claude 的 `AskUserQuestion`;按工具名子串匹配,覆盖带前后缀的同类命名)的发送:任何角色(含 QA)在静默下调用问卷工具都会被阻断并回传「按静默默认决策执行、落盘 `.reply.json`」的提示。这是 prompt 层约束(QA 不发送问卷)的机制兜底;settings.json 的 `mode` 切换为 `interactive` 后立即解除拦截(opencode 每次调用实时读配置,claude 天然每次调用独立进程)。**dsh**:默认无项目级 hook、无机制兜底,仅靠 prompt 约束(task-prompts 的「【静默模式】不发送问卷」追加指令 + QA 自律);安装部署级守卫(`hooks/dsh/install.sh`)后,`tools/pre-execute` 门会拦截 `ask_user_question` 等问卷工具(按子串匹配,dsh 侧含 `ask`),恢复机制兜底。**codex**:无任何 hook,仅 prompt 约束。 | 44 | +静默模式(`.cannbot/settings.json` 的 `mode=silent`)启用时,permission-guard hook 在机制层拦截问卷工具(opencode 的 `question`/`ask`、claude 的 `AskUserQuestion`;按工具名子串匹配,覆盖带前后缀的同类命名)的发送:任何角色(含 QA)在静默下调用问卷工具都会被阻断并回传「按静默默认决策执行、落盘 `.reply.json`」的提示。这是 prompt 层约束(QA 不发送问卷)的机制兜底;settings.json 的 `mode` 切换为 `interactive` 后立即解除拦截(opencode 每次调用实时读配置,claude 天然每次调用独立进程)。**dsh**:默认无项目级 hook、无机制兜底,仅靠 prompt 约束(task-prompts 的「【静默模式】不发送问卷」追加指令 + QA 自律);安装部署级守卫(`hooks/dsh/install.sh`)后,`tools/pre-execute` 门会拦截 `ask_user_question` 等问卷工具(按子串匹配,dsh 侧含 `ask`),恢复机制兜底。**codex**:无任何 hook,仅 prompt 约束。**trae**:`.trae/hooks.json` 注册 PreToolUse hook(matcher `AskUserQuestion`),拦截 `AskUserQuestion` 等问卷工具(按子串匹配),恢复机制兜底。 |
| 45 | 45 | ||
| 46 | ## 规格文件 | 46 | ## 规格文件 |
| 47 | 47 | ||
| @@ -6,7 +6,7 @@ disable-model-invocation: true | |||
| 6 | 6 | ||
| 7 | # 环境确认验收标准 | 7 | # 环境确认验收标准 |
| 8 | 8 | ||
| 9 | -获取到 `.cannbot/环境信息.md` 时,立即用会话问卷工具(opencode `question` / claude `AskUserQuestion` / dsh `ask_user_question`)按下列格式向用户发送问卷。每个标题对应问卷的一页(`questions` 数组的一项),`{...}` 为占位符,取值自环境信息文档的实测结果: | 9 | +获取到 `.cannbot/环境信息.md` 时,立即用会话问卷工具(opencode `question` / claude `AskUserQuestion` / dsh `ask_user_question` / trae `AskUserQuestion`)按下列格式向用户发送问卷。每个标题对应问卷的一页(`questions` 数组的一项),`{...}` 为占位符,取值自环境信息文档的实测结果: |
| 10 | 10 | ||
| 11 | ```json | 11 | ```json |
| 12 | { | 12 | { |
| @@ -65,12 +65,12 @@ disable-model-invocation: true | |||
| 65 | 4. 按明确性判据逐类核对取值可判定性;按一致性判据做接口 / 数学 / dtype 交叉核对。 | 65 | 4. 按明确性判据逐类核对取值可判定性;按一致性判据做接口 / 数学 / dtype 交叉核对。 |
| 66 | 5. 核对用户原始需求逐条落表,且各确认项与其可双向追溯、无遗漏、无越界新增。 | 66 | 5. 核对用户原始需求逐条落表,且各确认项与其可双向追溯、无遗漏、无越界新增。 |
| 67 | 6. 将问题按「硬伤 / 开放取舍」归类:存在硬伤直接判不通过,返回结构化修改意见,**不进入用户确认段**。 | 67 | 6. 将问题按「硬伤 / 开放取舍」归类:存在硬伤直接判不通过,返回结构化修改意见,**不进入用户确认段**。 |
| 68 | -7. 核对无硬伤后,按下方**问卷模板**生成问卷 json,用会话问卷工具(opencode `question` / claude `AskUserQuestion` / dsh `ask_user_question`)直接发送用户并收集结论;问卷与回复成对落盘 `.cannbot/<算子名>/questionnaires/`(回复记为问卷同名 `.reply.json`)。代码架构选型尚未拍板时,问卷须带上推荐项、推荐依据与各候选架构的可行性评估结论,使用户可依据决策而非盲选。 | 68 | +7. 核对无硬伤后,按下方**问卷模板**生成问卷 json,用会话问卷工具(opencode `question` / claude `AskUserQuestion` / dsh `ask_user_question` / trae `AskUserQuestion`)直接发送用户并收集结论;问卷与回复成对落盘 `.cannbot/<算子名>/questionnaires/`(回复记为问卷同名 `.reply.json`)。代码架构选型尚未拍板时,问卷须带上推荐项、推荐依据与各候选架构的可行性评估结论,使用户可依据决策而非盲选。 |
| 69 | 8. 汇总判定:需求总览无异议、待拍板页均已拍板、待补齐项已补齐,即为通过;用户异议按条目打回需求文档修订。 | 69 | 8. 汇总判定:需求总览无异议、待拍板页均已拍板、待补齐项已补齐,即为通过;用户异议按条目打回需求文档修订。 |
| 70 | 70 | ||
| 71 | ## 问卷模板 | 71 | ## 问卷模板 |
| 72 | 72 | ||
| 73 | -核对无硬伤后,按下列格式用会话问卷工具(opencode `question` / claude `AskUserQuestion` / dsh `ask_user_question`)发送问卷(落盘 `.cannbot/<算子名>/questionnaires/CP1-需求确认.json`)。`{...}` 为占位符,取值自需求文档。「需求总览」页固定发送;「评测来源」「代码架构选型」页仅在决策状态为「待用户确认」时发送;「待补齐项」页仅在存在缺项或我方补充项时发送: | 73 | +核对无硬伤后,按下列格式用会话问卷工具(opencode `question` / claude `AskUserQuestion` / dsh `ask_user_question` / trae `AskUserQuestion`)发送问卷(落盘 `.cannbot/<算子名>/questionnaires/CP1-需求确认.json`)。`{...}` 为占位符,取值自需求文档。「需求总览」页固定发送;「评测来源」「代码架构选型」页仅在决策状态为「待用户确认」时发送;「待补齐项」页仅在存在缺项或我方补充项时发送: |
| 74 | 74 | ||
| 75 | ```json | 75 | ```json |
| 76 | { | 76 | { |
| @@ -74,7 +74,7 @@ disable-model-invocation: true | |||
| 74 | 1. 读取开发方案文档,逐项核对架构承接、schema 对齐、关键设计、接口、承接需求、资源约束、能力边界、瓶颈预判、优化项全部检查项。 | 74 | 1. 读取开发方案文档,逐项核对架构承接、schema 对齐、关键设计、接口、承接需求、资源约束、能力边界、瓶颈预判、优化项全部检查项。 |
| 75 | 2. 对照需求文档(= proto.yaml)核实代码架构与拍板结果一致、schema 逐字对齐;对照 `repo-op-templates`、`repo-build-guide` 核实模板与架构匹配、接口可用性、真值一致性。 | 75 | 2. 对照需求文档(= proto.yaml)核实代码架构与拍板结果一致、schema 逐字对齐;对照 `repo-op-templates`、`repo-build-guide` 核实模板与架构匹配、接口可用性、真值一致性。 |
| 76 | 3. 检查项存在不通过项时,直接返回结构化修改意见,**不进入用户确认段**。 | 76 | 3. 检查项存在不通过项时,直接返回结构化修改意见,**不进入用户确认段**。 |
| 77 | -4. 检查项全过后,按抽取清单生成结构化问卷 json,每条带上述四要素;用会话问卷工具(opencode `question` / claude `AskUserQuestion` / dsh `ask_user_question`)直接发送用户;问卷与回复成对落盘 `.cannbot/<算子名>/questionnaires/`(回复记为问卷同名 `.reply.json`)。 | 77 | +4. 检查项全过后,按抽取清单生成结构化问卷 json,每条带上述四要素;用会话问卷工具(opencode `question` / claude `AskUserQuestion` / dsh `ask_user_question` / trae `AskUserQuestion`)直接发送用户;问卷与回复成对落盘 `.cannbot/<算子名>/questionnaires/`(回复记为问卷同名 `.reply.json`)。 |
| 78 | 5. 收集用户结论后汇总判定:全部条目确认无异议即通过;存在异议则按条目的语义归属标签返回修改意见。 | 78 | 5. 收集用户结论后汇总判定:全部条目确认无异议即通过;存在异议则按条目的语义归属标签返回修改意见。 |
| 79 | 79 | ||
| 80 | ## 输出 | 80 | ## 输出 |