已合并
feat(cuda2ascend): support TraeCode as target tool #918
feat(cuda2ascend): support TraeCode as target tool #918
已合并
xutianze创建于 8月27日
共 20 个文件变更+293-40
@@ -1,3 +1,6 @@
1.cannbot1.cannbot
2.opencode2.opencode
3.claude3.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 at21# 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# ============================================================
24show_quick_start() {24show_quick_start() {
25 echo ""25 echo ""
@@ -101,9 +101,9 @@ Options:
101 - passed through to the base plugin101 - passed through to the base plugin
102 102 
103Examples:103Examples:
104- ./init.sh opencode --repo cannbot-skills:~/cannbot-skills104+ ./init.sh <target> --repo cannbot-skills:~/cannbot-skills
105- ./init.sh claude --repo cannbot-skills:~/cannbot-skills105+ ./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-samples106+ (target = any tool in the list above, e.g. opencode)
107EOF107EOF
108}108}
109 109 
@@ -164,7 +164,7 @@ while [[ $# -gt 0 ]]; do
164done164done
165 165 
166if [ "$HELP_REQUESTED" = false ] && [ -z "$TARGET_ENV" ]; then166if [ "$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_help169 show_help
170 exit 1170 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"
269show_quick_start266show_quick_start
270echo ""267echo ""
@@ -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"
112VERSION="1.0.0"112VERSION="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 registry118# 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 
302Intermediate directory:307Intermediate directory:
303 .cannbot/ workflow intermediate files & state308 .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"; then417 if is_supported_tool "$1"; then
@@ -455,6 +461,9 @@ if [ "${LEVEL}" = "global" ]; then
455 # DSH(DeepSeek Harness)用户数据根:$DSH_HOME,默认 ~/.dsh461 # 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 fi467 fi
459 INSTALL_BASE="${HOME}"468 INSTALL_BASE="${HOME}"
460else469else
@@ -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 fi492 fi
479fi493fi
480 494 
@@ -715,6 +729,62 @@ if [ "${TOOL}" = "codex" ]; then
715 else729 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 fi731 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"
718else788else
719 for f in "${AGENT_FILES[@]}"; do789 for f in "${AGENT_FILES[@]}"; do
720 link_name="$(basename "${f}")"790 link_name="$(basename "${f}")"
@@ -729,6 +799,9 @@ fi
729if [ "${TOOL}" = "dsh" ]; then799if [ "${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)"
731fi801fi
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
732echo ""805echo ""
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 ""
916else1059else
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}" ]; then1061 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 fi1381 fi
1239fi1382fi
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 
1241if [ "${health_ok}" = true ] && [ -z "${health_errors}" ]; then1393if [ "${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# Summary1401# 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"
1255echo ""1404echo ""
1256echo -e " ${GREEN}${BOLD}✓ ${TEAM_NAME} installed!${NC}"1405echo -e " ${GREEN}${BOLD}✓ ${TEAM_NAME} installed!${NC}"
1257echo -e " ${DIM}Skills: ${skill_count} | Agents: ${agent_count}${NC}"1406echo -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.js108├── .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-tensor113├── .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 
@@ -1,7 +1,7 @@
1# 修改 virtual skill1# 修改 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```md25```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```json11```json
12{12{
@@ -65,12 +65,12 @@ disable-model-invocation: true
654. 按明确性判据逐类核对取值可判定性;按一致性判据做接口 / 数学 / dtype 交叉核对。654. 按明确性判据逐类核对取值可判定性;按一致性判据做接口 / 数学 / dtype 交叉核对。
665. 核对用户原始需求逐条落表,且各确认项与其可双向追溯、无遗漏、无越界新增。665. 核对用户原始需求逐条落表,且各确认项与其可双向追溯、无遗漏、无越界新增。
676. 将问题按「硬伤 / 开放取舍」归类:存在硬伤直接判不通过,返回结构化修改意见,**不进入用户确认段**。676. 将问题按「硬伤 / 开放取舍」归类:存在硬伤直接判不通过,返回结构化修改意见,**不进入用户确认段**。
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`)。代码架构选型尚未拍板时,问卷须带上推荐项、推荐依据与各候选架构的可行性评估结论,使用户可依据决策而非盲选。
698. 汇总判定:需求总览无异议、待拍板页均已拍板、待补齐项已补齐,即为通过;用户异议按条目打回需求文档修订。698. 汇总判定:需求总览无异议、待拍板页均已拍板、待补齐项已补齐,即为通过;用户异议按条目打回需求文档修订。
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```json75```json
76{76{
@@ -74,7 +74,7 @@ disable-model-invocation: true
741. 读取开发方案文档,逐项核对架构承接、schema 对齐、关键设计、接口、承接需求、资源约束、能力边界、瓶颈预判、优化项全部检查项。741. 读取开发方案文档,逐项核对架构承接、schema 对齐、关键设计、接口、承接需求、资源约束、能力边界、瓶颈预判、优化项全部检查项。
752. 对照需求文档(= proto.yaml)核实代码架构与拍板结果一致、schema 逐字对齐;对照 `repo-op-templates`、`repo-build-guide` 核实模板与架构匹配、接口可用性、真值一致性。752. 对照需求文档(= proto.yaml)核实代码架构与拍板结果一致、schema 逐字对齐;对照 `repo-op-templates`、`repo-build-guide` 核实模板与架构匹配、接口可用性、真值一致性。
763. 检查项存在不通过项时,直接返回结构化修改意见,**不进入用户确认段**。763. 检查项存在不通过项时,直接返回结构化修改意见,**不进入用户确认段**。
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`)。
785. 收集用户结论后汇总判定:全部条目确认无异议即通过;存在异议则按条目的语义归属标签返回修改意见。785. 收集用户结论后汇总判定:全部条目确认无异议即通过;存在异议则按条目的语义归属标签返回修改意见。
79 79 
80## 输出80## 输出