msdevflow 0.7.7 → 0.7.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +31 -5
- package/lib/bootstrap.js +263 -10
- package/package.json +1 -1
- package/skill/msd/README.md +11 -8
- package/skill/msd/SKILL.md +7 -6
- package/skill/msd/references/code-review.md +7 -8
- package/skill/msd/references/command-capabilities.md +4 -2
- package/skill/msd/references/create-issue.md +20 -7
- package/skill/msd/references/pr-and-ci.md +19 -4
- package/skill/msd/references/recovery.md +7 -7
- package/skill/msd/references/state-and-safety.md +8 -8
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) [year] [fullname]
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -32,7 +32,7 @@ npx msdevflow@latest setup
|
|
|
32
32
|
1. 把一个 `msd` 核心和十个 `msd-<action>` 路由器作为整套事务原子安装或更新到所需目标;
|
|
33
33
|
2. 安装或升级官方 `@gitcode-cli/cli@latest`;
|
|
34
34
|
3. 创建或修复 msdevflow 受管 Python venv,并在其中安装受审的 Playwright 依赖;
|
|
35
|
-
4. 验收 Issue、PR
|
|
35
|
+
4. 验收 Issue、PR、开放里程碑分页、Issue/PR 里程碑关联、结构化评论、行内评论、JSON、显式仓库和正文文件等 CLI 能力;
|
|
36
36
|
5. GitCode CLI 未认证时打开官方 Token 创建页面,并让 CLI 自己的终端提示接收 Token。
|
|
37
37
|
|
|
38
38
|
显式选择客户端或只读预检:
|
|
@@ -58,6 +58,25 @@ Claude Code + Codex -> 两套受管副本
|
|
|
58
58
|
|
|
59
59
|
每个物理目标都包含完整套件,薄路由器不复制核心业务规则。已有 entry 只有在 manifest 精确匹配自身名称时才允许更新;由旧版包管理的 `msdevflow` 目录会在新套件全部验证后安全迁移,来源不明的目录、文件或符号链接会阻断安装。
|
|
60
60
|
|
|
61
|
+
### WSL 与 Windows Agent
|
|
62
|
+
|
|
63
|
+
setup 以 **Agent 可执行文件实际所在环境** 决定安装侧,而不是只看命令从哪个 shell 发起:
|
|
64
|
+
|
|
65
|
+
- Agent 只安装在 Windows:可以从 WSL 调用 Windows `npx.cmd`,setup 会标记 `Runtime mode: windows-bridge-from-wsl`,并把 Skill、Python venv 和 GitCode CLI 安装在 Windows 用户环境。
|
|
66
|
+
- Agent 只安装在 WSL:必须使用 WSL 内的 Linux Node.js/npm;若误用了 Windows Node,setup 会在写入任何 Python、npm 或 Skill 文件前停止。
|
|
67
|
+
- 同名 Agent 同时存在于 Windows 与 WSL:setup 不猜目标;请从目标环境的终端重新运行。
|
|
68
|
+
|
|
69
|
+
准备 WSL 原生 Agent 时先确认以下命令全部解析为 Linux 路径,而不是 `/mnt/<drive>/...` 或 `.cmd`:
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
type -a node npm npx opencode
|
|
73
|
+
npx msdevflow@latest setup
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
示例使用 OpenCode;使用 Claude Code 或 Codex 时把 `opencode` 替换为实际 Agent 命令。
|
|
77
|
+
|
|
78
|
+
Windows bridge 模式应从 WSL 中解析到 Windows Agent;也可直接在 Windows Terminal/PowerShell 中运行 setup。此前失败后可直接重跑,setup 会安全复用或修复带受管 marker 的 runtime,不需要手动删除。
|
|
79
|
+
|
|
61
80
|
自定义目录:
|
|
62
81
|
|
|
63
82
|
```bash
|
|
@@ -99,7 +118,7 @@ Issue 发现/核验
|
|
|
99
118
|
-> 远端回读 PR 已 merged
|
|
100
119
|
```
|
|
101
120
|
|
|
102
|
-
调用正文可提供 Issue/PR URL、仓库路径、canonical、source 和模式。核心 `msd` 不显示运行时 Question
|
|
121
|
+
调用正文可提供 Issue/PR URL、仓库路径、canonical、source 和模式。核心 `msd` 不显示运行时 Question 菜单;完整 E2E 在 `pr-open` 后不再询问是否继续,直接进入 `ci`。
|
|
103
122
|
|
|
104
123
|
这是可暂停、可恢复的流程。外部检视或审批有新进展后,可再次提交 `/msd` 和 PR 信息:
|
|
105
124
|
|
|
@@ -118,10 +137,10 @@ Claude Code/OpenCode 输入 `/msd-`、Codex 输入 `$msd-` 即可筛选十个独
|
|
|
118
137
|
| action | 用途 | 完成状态或结果 |
|
|
119
138
|
|---|---|---|
|
|
120
139
|
| `discover` | 只读发现当前账号负责的候选 Issue | 列出候选和排除证据 |
|
|
121
|
-
| `create-issue` |
|
|
140
|
+
| `create-issue` | 按模板创建 Issue,并确定性选择开放里程碑 | `issue-created` |
|
|
122
141
|
| `issue` | 接取并核验指定 Issue | `verified` |
|
|
123
142
|
| `develop` | 分析、设计、实现和本地验证 | `locally-verified` |
|
|
124
|
-
| `pr` | commit、push
|
|
143
|
+
| `pr` | commit、push、创建普通 PR并继承 Issue 里程碑 | `pr-open` |
|
|
125
144
|
| `ci` | 监控、诊断并修复当前 PR 的 CI | `ci-passed` |
|
|
126
145
|
| `openlibing-auth` | 验证 GitCode → openLiBing OAuth | `openlibing-authenticated` |
|
|
127
146
|
| `feedback` | 处理自己 PR 收到的检视意见 | `feedback-resolved` 或 `waiting-for-review` |
|
|
@@ -147,11 +166,14 @@ PR:https://gitcode.com/Ascend/example/pulls/456
|
|
|
147
166
|
PR:https://gitcode.com/Ascend/example/pulls/789
|
|
148
167
|
```
|
|
149
168
|
|
|
150
|
-
`code-review` 只能检视其他作者的 PR
|
|
169
|
+
`code-review` 只能检视其他作者的 PR。发现问题时只发布高置信度、可操作的 finding;完整检视未发现问题且没有有效未解决意见时,经用户针对当前 PR/head 明确确认后,只评论并回读精确的 `/lgtm`,不发布检视摘要或其他前置评论。它不发送 `/approve` 或 `/merge`,也不修改作者代码。
|
|
151
170
|
|
|
152
171
|
## PR 与检视规则
|
|
153
172
|
|
|
154
173
|
- 创建普通 PR,不创建 Draft PR,也不执行 Ready;
|
|
174
|
+
- `create-issue` 只在开放里程碑唯一时自动选择,多个时由用户选择,没有时明确为 `none`,不会创建或猜测里程碑;
|
|
175
|
+
- `pr` 继承已核验目标 Issue 的里程碑,并在远端写后回读确认;
|
|
176
|
+
- 完整 E2E 在 `pr-open` 后无需确认直接进入 `ci`,但独立 `pr` action 仍立即停止且不触发 CI;
|
|
155
177
|
- 不主动请求检视,不触发检视机器人;
|
|
156
178
|
- 作者流程不会调用 `code-review`,也不会自行制造 LGTM/approve;
|
|
157
179
|
- CI、review 和 merge 结论始终绑定当前 PR head SHA;
|
|
@@ -229,3 +251,7 @@ npx msdevflow setup
|
|
|
229
251
|
## 详细文档
|
|
230
252
|
|
|
231
253
|
完整 action、恢复、模板、CI、review、UTF-8 和安全契约见 [`skill/msd/README.md`](skill/msd/README.md)。
|
|
254
|
+
|
|
255
|
+
## Contributors
|
|
256
|
+
|
|
257
|
+
<p style="display: flex; flex-direction: row; align-items: center; gap: 6px;"><a href="https://gitcode.com/jhon-117" title="kai1949 (@jhon-117)" style="display: inline-flex;"><img src="https://cdn-img.gitcode.com/cf/de/cf4654616de28c691a53b353b5c67274262c4a92a2353ce82aece9e7a5a496f9.jpg?x-oss-process=image/resize,m_fill,w_48,h_48/circle,r_24/format,png" width="48" height="48" alt="kai1949 (@jhon-117)"></a><a href="https://gitcode.com/hummel_mao" title="hummel mao (@hummel_mao)" style="display: inline-flex; text-decoration: none;"><span role="img" aria-label="hummel mao (@hummel_mao)" style="display: inline-flex; align-items: center; justify-content: center; width: 48px; height: 48px; border-radius: 50%; background-color: #ff8b87; color: #ffffff; font-size: 14px; font-weight: 400;">H</span></a><a href="https://gitcode.com/rookie_hongchuan" title="rookie_hongchuan (@rookie_hongchuan)" style="display: inline-flex; text-decoration: none;"><span role="img" aria-label="rookie_hongchuan (@rookie_hongchuan)" style="display: inline-flex; align-items: center; justify-content: center; width: 48px; height: 48px; border-radius: 50%; background-color: #ff8b87; color: #ffffff; font-size: 14px; font-weight: 400;">R</span></a></p>
|
package/lib/bootstrap.js
CHANGED
|
@@ -50,13 +50,15 @@ const SUPPORTED_CLIENTS = ["claude", "codex", "opencode"];
|
|
|
50
50
|
const REQUIRED_SCHEMAS = {
|
|
51
51
|
"auth login": ["web"],
|
|
52
52
|
"auth status": ["json"],
|
|
53
|
-
"issue create": ["body-file", "dry-run", "json", "repo", "title"],
|
|
53
|
+
"issue create": ["body-file", "dry-run", "json", "milestone", "repo", "title"],
|
|
54
54
|
"issue list": ["assignee", "json", "repo", "state"],
|
|
55
55
|
"issue view": ["comments", "json", "repo"],
|
|
56
|
-
"issue edit": ["assignee", "json", "repo", "state"],
|
|
56
|
+
"issue edit": ["assignee", "json", "milestone", "repo", "state"],
|
|
57
57
|
"issue comment": ["body-file", "json", "repo"],
|
|
58
58
|
"issue prs": ["json", "repo"],
|
|
59
|
+
"milestone list": ["json", "limit", "page", "per-page", "repo"],
|
|
59
60
|
"pr create": ["base", "body-file", "fork", "head", "json", "repo", "title"],
|
|
61
|
+
"pr edit": ["json", "milestone", "repo"],
|
|
60
62
|
"pr list": ["direction", "head", "json", "limit", "repo", "sort", "state"],
|
|
61
63
|
"pr view": ["comments", "json", "repo"],
|
|
62
64
|
"pr diff": ["json", "repo"],
|
|
@@ -799,6 +801,219 @@ export function detectClients(run, platform) {
|
|
|
799
801
|
return SUPPORTED_CLIENTS.filter((client) => Boolean(resolveExecutable(client, run, platform)));
|
|
800
802
|
}
|
|
801
803
|
|
|
804
|
+
function wslDistroFromUnc(value) {
|
|
805
|
+
return typeof value === "string"
|
|
806
|
+
? value.match(/^\\\\wsl(?:\.localhost|\$)\\([^\\]+)/i)?.[1] || ""
|
|
807
|
+
: "";
|
|
808
|
+
}
|
|
809
|
+
|
|
810
|
+
function windowsNodeFromWsl(environment, platform) {
|
|
811
|
+
// Windows Node keeps process.platform=win32 when a WSL shell launches npx.cmd.
|
|
812
|
+
if (platform !== "win32") {
|
|
813
|
+
return null;
|
|
814
|
+
}
|
|
815
|
+
const distro = environment.WSL_DISTRO_NAME
|
|
816
|
+
|| wslDistroFromUnc(environment.INIT_CWD)
|
|
817
|
+
|| wslDistroFromUnc(environment.PWD);
|
|
818
|
+
if (!distro && !environment.WSL_INTEROP) {
|
|
819
|
+
return null;
|
|
820
|
+
}
|
|
821
|
+
return { distro: distro || "" };
|
|
822
|
+
}
|
|
823
|
+
|
|
824
|
+
async function detectClientExecutables(run, platform) {
|
|
825
|
+
const entries = await Promise.all(SUPPORTED_CLIENTS.map(async (client) => [
|
|
826
|
+
client,
|
|
827
|
+
await resolveExecutableAsync(client, run, platform),
|
|
828
|
+
]));
|
|
829
|
+
return Object.fromEntries(entries.filter(([, executable]) => executable));
|
|
830
|
+
}
|
|
831
|
+
|
|
832
|
+
function wslClientLookup(distro) {
|
|
833
|
+
const args = [];
|
|
834
|
+
if (distro) {
|
|
835
|
+
args.push("--distribution", distro);
|
|
836
|
+
}
|
|
837
|
+
const script = [
|
|
838
|
+
"for name do",
|
|
839
|
+
" old_ifs=$IFS",
|
|
840
|
+
" IFS=: ",
|
|
841
|
+
" for dir in $PATH; do",
|
|
842
|
+
" IFS=$old_ifs",
|
|
843
|
+
" [ -n \"$dir\" ] || dir=.",
|
|
844
|
+
" for candidate in \"$dir/$name\" \"$dir/$name.cmd\" \"$dir/$name.exe\" \"$dir/$name.bat\"; do",
|
|
845
|
+
" [ -f \"$candidate\" ] || continue",
|
|
846
|
+
" case \"$candidate\" in",
|
|
847
|
+
" /mnt/[a-zA-Z]/*)",
|
|
848
|
+
" [ -f \"${candidate}.cmd\" ] && candidate=\"${candidate}.cmd\"",
|
|
849
|
+
" windows=$(wslpath -w -- \"$candidate\" 2>/dev/null) || continue",
|
|
850
|
+
" printf '%s\\twindows\\t%s\\n' \"$name\" \"$windows\"",
|
|
851
|
+
" ;;",
|
|
852
|
+
" *)",
|
|
853
|
+
" [ -x \"$candidate\" ] || continue",
|
|
854
|
+
" native=$(readlink -f -- \"$candidate\" 2>/dev/null || printf '%s' \"$candidate\")",
|
|
855
|
+
" case \"$native\" in",
|
|
856
|
+
" /mnt/[a-zA-Z]/*)",
|
|
857
|
+
" [ -f \"${native}.cmd\" ] && native=\"${native}.cmd\"",
|
|
858
|
+
" windows=$(wslpath -w -- \"$native\" 2>/dev/null) || continue",
|
|
859
|
+
" printf '%s\\twindows\\t%s\\n' \"$name\" \"$windows\"",
|
|
860
|
+
" ;;",
|
|
861
|
+
" *) printf '%s\\twsl\\t%s\\n' \"$name\" \"$native\" ;;",
|
|
862
|
+
" esac",
|
|
863
|
+
" ;;",
|
|
864
|
+
" esac",
|
|
865
|
+
" break",
|
|
866
|
+
" done",
|
|
867
|
+
" IFS=: ",
|
|
868
|
+
" done",
|
|
869
|
+
" IFS=$old_ifs",
|
|
870
|
+
"done",
|
|
871
|
+
].join("\n");
|
|
872
|
+
args.push("--exec", "sh", "-lc", script, "sh", ...SUPPORTED_CLIENTS);
|
|
873
|
+
return { command: "wsl.exe", args };
|
|
874
|
+
}
|
|
875
|
+
|
|
876
|
+
async function detectWslClientExecutables(run, distro) {
|
|
877
|
+
const result = await runOptionalAsync(run, wslClientLookup(distro));
|
|
878
|
+
if (result.status !== 0) {
|
|
879
|
+
return { wsl: {}, windows: {} };
|
|
880
|
+
}
|
|
881
|
+
const clients = { wsl: {}, windows: {} };
|
|
882
|
+
for (const line of result.stdout.split(/\r?\n/)) {
|
|
883
|
+
const [name, side, executable] = line.split("\t", 3);
|
|
884
|
+
if (
|
|
885
|
+
SUPPORTED_CLIENTS.includes(name)
|
|
886
|
+
&& (side === "wsl" || side === "windows")
|
|
887
|
+
&& executable
|
|
888
|
+
&& !clients[side][name]
|
|
889
|
+
) {
|
|
890
|
+
clients[side][name] = executable;
|
|
891
|
+
}
|
|
892
|
+
}
|
|
893
|
+
return clients;
|
|
894
|
+
}
|
|
895
|
+
|
|
896
|
+
async function inspectMixedWslClients(run, context) {
|
|
897
|
+
const [windowsPath, wslLookup] = await Promise.all([
|
|
898
|
+
detectClientExecutables(run, "win32"),
|
|
899
|
+
detectWslClientExecutables(run, context.distro),
|
|
900
|
+
]);
|
|
901
|
+
return {
|
|
902
|
+
...context,
|
|
903
|
+
windows: { ...wslLookup.windows, ...windowsPath },
|
|
904
|
+
wsl: wslLookup.wsl,
|
|
905
|
+
};
|
|
906
|
+
}
|
|
907
|
+
|
|
908
|
+
function clientLocations(inspection, clients) {
|
|
909
|
+
return clients.map((client) => ({
|
|
910
|
+
client,
|
|
911
|
+
windows: inspection.windows[client] || "",
|
|
912
|
+
wsl: inspection.wsl[client] || "",
|
|
913
|
+
}));
|
|
914
|
+
}
|
|
915
|
+
|
|
916
|
+
function mixedClientError(inspection, clients, reason) {
|
|
917
|
+
const locations = clientLocations(inspection, clients);
|
|
918
|
+
const details = locations.map(({ client, windows, wsl }) => [
|
|
919
|
+
`${client}:`,
|
|
920
|
+
windows ? `Windows=${windows}` : "Windows=not-found",
|
|
921
|
+
wsl ? `WSL=${wsl}` : "WSL=not-found",
|
|
922
|
+
].join(" ")).join("; ");
|
|
923
|
+
const guidance = `Use Node.js >=18 and npm installed inside WSL, verify "type -a node npm npx ${clients.join(" ")}" resolves to Linux paths, then rerun "npx msdevflow@latest setup" from WSL. To configure a Windows agent instead, run setup from a Windows terminal. No changes were applied.`;
|
|
924
|
+
return new BootstrapError(`${reason} ${details}. ${guidance}`, 2);
|
|
925
|
+
}
|
|
926
|
+
|
|
927
|
+
function resolveMixedWslTargets(inspection, clients) {
|
|
928
|
+
const locations = clientLocations(inspection, clients);
|
|
929
|
+
const ambiguous = locations.filter(({ windows, wsl }) => windows && wsl);
|
|
930
|
+
if (ambiguous.length) {
|
|
931
|
+
throw mixedClientError(
|
|
932
|
+
inspection,
|
|
933
|
+
ambiguous.map(({ client }) => client),
|
|
934
|
+
"The selected agent exists in both Windows and WSL, so setup cannot safely choose which environment owns it.",
|
|
935
|
+
);
|
|
936
|
+
}
|
|
937
|
+
const wslOnly = locations.filter(({ windows, wsl }) => !windows && wsl);
|
|
938
|
+
if (wslOnly.length) {
|
|
939
|
+
throw mixedClientError(
|
|
940
|
+
inspection,
|
|
941
|
+
wslOnly.map(({ client }) => client),
|
|
942
|
+
"The selected agent exists only inside WSL, but msdevflow is running with Windows Node.js.",
|
|
943
|
+
);
|
|
944
|
+
}
|
|
945
|
+
const missing = locations.filter(({ windows, wsl }) => !windows && !wsl);
|
|
946
|
+
if (missing.length) {
|
|
947
|
+
throw mixedClientError(
|
|
948
|
+
inspection,
|
|
949
|
+
missing.map(({ client }) => client),
|
|
950
|
+
"The selected agent was not found in either Windows or WSL.",
|
|
951
|
+
);
|
|
952
|
+
}
|
|
953
|
+
return {
|
|
954
|
+
mode: "windows-bridge-from-wsl",
|
|
955
|
+
agentExecutables: Object.fromEntries(
|
|
956
|
+
locations.map(({ client, windows }) => [client, windows]),
|
|
957
|
+
),
|
|
958
|
+
};
|
|
959
|
+
}
|
|
960
|
+
|
|
961
|
+
async function resolveSetupContext(
|
|
962
|
+
options,
|
|
963
|
+
environment,
|
|
964
|
+
platform,
|
|
965
|
+
run,
|
|
966
|
+
runLong,
|
|
967
|
+
selectClients,
|
|
968
|
+
progress,
|
|
969
|
+
) {
|
|
970
|
+
const context = windowsNodeFromWsl(environment, platform);
|
|
971
|
+
if (!context) {
|
|
972
|
+
return {
|
|
973
|
+
targetSelection: await resolveClientTargets(
|
|
974
|
+
options,
|
|
975
|
+
run,
|
|
976
|
+
platform,
|
|
977
|
+
selectClients,
|
|
978
|
+
),
|
|
979
|
+
runtime: {
|
|
980
|
+
mode: platform === "win32" ? "windows-native" : "posix-native",
|
|
981
|
+
agentExecutables: {},
|
|
982
|
+
},
|
|
983
|
+
};
|
|
984
|
+
}
|
|
985
|
+
|
|
986
|
+
const inspection = await progress.run(
|
|
987
|
+
"Inspecting Windows and WSL agent installations",
|
|
988
|
+
() => inspectMixedWslClients(runLong, context),
|
|
989
|
+
);
|
|
990
|
+
let targetSelection;
|
|
991
|
+
if (options.targetsSpecified) {
|
|
992
|
+
targetSelection = {
|
|
993
|
+
clients: options.targets,
|
|
994
|
+
source: "explicit",
|
|
995
|
+
detected: [],
|
|
996
|
+
};
|
|
997
|
+
} else if (options.skillsDir) {
|
|
998
|
+
targetSelection = {
|
|
999
|
+
clients: ["claude"],
|
|
1000
|
+
source: "legacy-skills-dir",
|
|
1001
|
+
detected: [],
|
|
1002
|
+
};
|
|
1003
|
+
} else {
|
|
1004
|
+
const detected = SUPPORTED_CLIENTS.filter(
|
|
1005
|
+
(client) => inspection.windows[client] || inspection.wsl[client],
|
|
1006
|
+
);
|
|
1007
|
+
targetSelection = detected.length
|
|
1008
|
+
? { clients: detected, source: "detected", detected }
|
|
1009
|
+
: { clients: await selectClients(), source: "selected", detected: [] };
|
|
1010
|
+
}
|
|
1011
|
+
return {
|
|
1012
|
+
targetSelection,
|
|
1013
|
+
runtime: resolveMixedWslTargets(inspection, targetSelection.clients),
|
|
1014
|
+
};
|
|
1015
|
+
}
|
|
1016
|
+
|
|
802
1017
|
async function selectClientTargets(input, output, promptOutput = output) {
|
|
803
1018
|
if (!input.isTTY || !output.isTTY) {
|
|
804
1019
|
throw new BootstrapError(
|
|
@@ -1257,11 +1472,15 @@ export function gitcodeInstallDetails(
|
|
|
1257
1472
|
npmCommand: ["npm", "install", "-g", GITCODE_PACKAGE, "--prefix", installPrefix, `--registry=${REGISTRY}`],
|
|
1258
1473
|
};
|
|
1259
1474
|
}
|
|
1475
|
+
const installPrefix = npmPrefix || "<npm-global-prefix>";
|
|
1260
1476
|
return {
|
|
1261
1477
|
mode: classification === "npm-official" ? "upgrade-npm" : "standard",
|
|
1262
1478
|
workflowCommand: "gitcode",
|
|
1263
|
-
target:
|
|
1264
|
-
cliTarget:
|
|
1479
|
+
target: installPrefix,
|
|
1480
|
+
cliTarget: pathApi.join(
|
|
1481
|
+
installPrefix,
|
|
1482
|
+
...(platform === "win32" ? ["gitcode.cmd"] : ["bin", "gitcode"]),
|
|
1483
|
+
),
|
|
1265
1484
|
wrapperDir: null,
|
|
1266
1485
|
wrapper: null,
|
|
1267
1486
|
npmCommand: ["npm", "install", "-g", GITCODE_PACKAGE, `--registry=${REGISTRY}`],
|
|
@@ -1357,12 +1576,20 @@ async function installGitcode(plan, runLong, run, platform) {
|
|
|
1357
1576
|
};
|
|
1358
1577
|
}
|
|
1359
1578
|
const executable = resolveExecutable("gitcode", run, platform);
|
|
1360
|
-
if (
|
|
1361
|
-
|
|
1579
|
+
if (executable) {
|
|
1580
|
+
return {
|
|
1581
|
+
command: plan.gitcodeInstall.workflowCommand,
|
|
1582
|
+
executable,
|
|
1583
|
+
};
|
|
1362
1584
|
}
|
|
1585
|
+
// The parent process keeps its original PATH after npm creates a global shim.
|
|
1586
|
+
verifyFile(
|
|
1587
|
+
plan.gitcodeInstall.cliTarget,
|
|
1588
|
+
`GitCode npm CLI was installed but its executable was not found on PATH or at ${plan.gitcodeInstall.cliTarget}.`,
|
|
1589
|
+
);
|
|
1363
1590
|
return {
|
|
1364
1591
|
command: plan.gitcodeInstall.workflowCommand,
|
|
1365
|
-
executable,
|
|
1592
|
+
executable: plan.gitcodeInstall.cliTarget,
|
|
1366
1593
|
};
|
|
1367
1594
|
}
|
|
1368
1595
|
|
|
@@ -1388,6 +1615,10 @@ function safeAuthStatus(output) {
|
|
|
1388
1615
|
function printPlan(plan, write) {
|
|
1389
1616
|
write("Setup plan (no changes made yet):");
|
|
1390
1617
|
write(` Client targets: ${plan.clientTargets.clients.join(", ")} (${plan.clientTargets.source})`);
|
|
1618
|
+
write(` Runtime mode: ${plan.clientTargets.runtimeMode}`);
|
|
1619
|
+
for (const [client, executable] of Object.entries(plan.clientTargets.agentExecutables)) {
|
|
1620
|
+
write(` Agent executable (${client}): ${executable}`);
|
|
1621
|
+
}
|
|
1391
1622
|
write(` Bundled skill suite: ${plan.skillInstalls[0].details.source}`);
|
|
1392
1623
|
for (const { layout, details } of plan.skillInstalls) {
|
|
1393
1624
|
write(` Skill root: ${details.target}`);
|
|
@@ -1524,6 +1755,7 @@ async function authenticateGitcode(
|
|
|
1524
1755
|
function textResult(result, write) {
|
|
1525
1756
|
write("Setup completed:");
|
|
1526
1757
|
write(` Client targets: ${result.clients.join(", ")}`);
|
|
1758
|
+
write(` Runtime mode: ${result.runtimeMode}`);
|
|
1527
1759
|
for (const skill of result.skills) {
|
|
1528
1760
|
write(` Skill suite: ${skill.status} at ${skill.target} (${skill.clients.join(", ")})`);
|
|
1529
1761
|
write(` Entries: ${skill.entries.map((entry) => entry.name).join(", ")}`);
|
|
@@ -1558,16 +1790,20 @@ export async function runSetup(options, dependencies = {}) {
|
|
|
1558
1790
|
writeProgress,
|
|
1559
1791
|
dependencies.timers,
|
|
1560
1792
|
);
|
|
1561
|
-
const
|
|
1793
|
+
const setupContext = await resolveSetupContext(
|
|
1562
1794
|
options,
|
|
1563
|
-
|
|
1795
|
+
environment,
|
|
1564
1796
|
platform,
|
|
1797
|
+
run,
|
|
1798
|
+
runLong,
|
|
1565
1799
|
dependencies.selectClients || (() => selectClientTargets(
|
|
1566
1800
|
process.stdin,
|
|
1567
1801
|
process.stdout,
|
|
1568
1802
|
options.json ? process.stderr : process.stdout,
|
|
1569
1803
|
)),
|
|
1804
|
+
progress,
|
|
1570
1805
|
);
|
|
1806
|
+
const targetSelection = setupContext.targetSelection;
|
|
1571
1807
|
const layouts = resolveLayouts(
|
|
1572
1808
|
options,
|
|
1573
1809
|
targetSelection.clients,
|
|
@@ -1584,6 +1820,8 @@ export async function runSetup(options, dependencies = {}) {
|
|
|
1584
1820
|
}));
|
|
1585
1821
|
const clientTargets = {
|
|
1586
1822
|
...targetSelection,
|
|
1823
|
+
runtimeMode: setupContext.runtime.mode,
|
|
1824
|
+
agentExecutables: setupContext.runtime.agentExecutables,
|
|
1587
1825
|
warnings: clientTargetWarnings(targetSelection.clients, layouts),
|
|
1588
1826
|
};
|
|
1589
1827
|
|
|
@@ -1675,7 +1913,20 @@ export async function runSetup(options, dependencies = {}) {
|
|
|
1675
1913
|
if (!options.yes && !(await (dependencies.confirm || confirmPlan)(process.stdin, process.stdout))) {
|
|
1676
1914
|
throw new BootstrapError("Setup cancelled; no changes were applied.", 2);
|
|
1677
1915
|
}
|
|
1678
|
-
await progress.run("Revalidating
|
|
1916
|
+
await progress.run("Revalidating environment ownership", async () => {
|
|
1917
|
+
const runtimeContext = windowsNodeFromWsl(environment, platform);
|
|
1918
|
+
if (clientTargets.runtimeMode === "windows-bridge-from-wsl") {
|
|
1919
|
+
const currentRuntime = resolveMixedWslTargets(
|
|
1920
|
+
await inspectMixedWslClients(runLong, runtimeContext),
|
|
1921
|
+
clientTargets.clients,
|
|
1922
|
+
);
|
|
1923
|
+
if (JSON.stringify(currentRuntime) !== JSON.stringify(setupContext.runtime)) {
|
|
1924
|
+
throw new BootstrapError(
|
|
1925
|
+
"Agent installation locations changed after confirmation; refusing to install.",
|
|
1926
|
+
3,
|
|
1927
|
+
);
|
|
1928
|
+
}
|
|
1929
|
+
}
|
|
1679
1930
|
const currentDiagnosis = await diagnoseGitcodeAsync(runLong, platform);
|
|
1680
1931
|
if (currentDiagnosis.classification !== diagnosis.classification
|
|
1681
1932
|
|| currentDiagnosis.existingExecutable !== diagnosis.existingExecutable) {
|
|
@@ -1736,6 +1987,8 @@ export async function runSetup(options, dependencies = {}) {
|
|
|
1736
1987
|
git: gitVersion,
|
|
1737
1988
|
clients: clientTargets.clients,
|
|
1738
1989
|
targetSource: clientTargets.source,
|
|
1990
|
+
runtimeMode: clientTargets.runtimeMode,
|
|
1991
|
+
agentExecutables: clientTargets.agentExecutables,
|
|
1739
1992
|
warnings: clientTargets.warnings,
|
|
1740
1993
|
skills,
|
|
1741
1994
|
gitcode,
|
package/package.json
CHANGED
package/skill/msd/README.md
CHANGED
|
@@ -26,10 +26,10 @@ msd-merge
|
|
|
26
26
|
| action | 能力 | 完成后行为 |
|
|
27
27
|
|---|---|---|
|
|
28
28
|
| `discover` | 只读发现候选 Issue | 列出候选和排除证据后停止 |
|
|
29
|
-
| `create-issue` |
|
|
29
|
+
| `create-issue` | 按模板创建 Issue,并确定性选择开放里程碑 | 回读确认 `issue-created` 后停止 |
|
|
30
30
|
| `issue` | 接取并核验指定 Issue | 到 `verified` 后停止 |
|
|
31
31
|
| `develop` | 分析、设计、建分支、实现和本地验证 | 到 `locally-verified` 后停止 |
|
|
32
|
-
| `pr` | commit、push、创建普通 PR | 到 `pr-open` 后停止 |
|
|
32
|
+
| `pr` | commit、push、创建普通 PR并继承 Issue 里程碑 | 到 `pr-open` 后停止 |
|
|
33
33
|
| `ci` | 监控、诊断和修复当前 PR 的 CI | 当前 head 全绿后停止 |
|
|
34
34
|
| `openlibing-auth` | 自动选择当前 canonical 的 run 并验证 OAuth | 只读验证成功后停止 |
|
|
35
35
|
| `feedback` | 处理自己 PR 收到的检视意见 | 意见闭环并验证后停止 |
|
|
@@ -49,6 +49,7 @@ msd-merge
|
|
|
49
49
|
|
|
50
50
|
```text
|
|
51
51
|
discover -> issue -> develop -> pr -> ci
|
|
52
|
+
^ `pr-open` 后无需确认直接进入
|
|
52
53
|
\-> openlibing-auth(openLiBing 401/403 时作为认证子流程,成功后返回 ci)
|
|
53
54
|
-> waiting-for-review
|
|
54
55
|
-> feedback -> ci -> waiting-for-review (可重复)
|
|
@@ -104,7 +105,7 @@ Fork:myname/example
|
|
|
104
105
|
|
|
105
106
|
本 action 从 canonical 最新默认分支的 `.gitcode/` 递归寻找匹配类型的 `.yml`、`.yaml` 或 `.md` Issue 模板;只有该类型不存在时,才回退到 `Ascend/community@master:.gitcode/.gitcode/ISSUE_TEMPLATE/` 的同类型模板。仓库匹配模板无效时阻断,不回退;类型或同类型模板无法唯一确定时让用户选择。它根据自然语言填充字段,缺少必填信息时逐项询问,创建前展示目标、模板 ref/path、标题、完整正文和元数据。
|
|
106
107
|
|
|
107
|
-
`create-issue` 不执行重复 Issue/PR
|
|
108
|
+
`create-issue` 不执行重复 Issue/PR 查找。它分页读取 canonical 的开放里程碑:没有时明确为 `none`,唯一时自动选择,多个时让用户选择;不按列表顺序猜测“最新”,也不创建或修改里程碑。确认创建后使用 UTF-8 安全通道并逐字回读正文与里程碑;到 `issue-created` 后立即停止,不接取、不开发。需要继续处理时显式运行 `action=issue`。
|
|
108
109
|
|
|
109
110
|
### 只接取和核验 Issue
|
|
110
111
|
|
|
@@ -136,7 +137,7 @@ canonical:Ascend/example
|
|
|
136
137
|
source:myname/example
|
|
137
138
|
```
|
|
138
139
|
|
|
139
|
-
|
|
140
|
+
它要求实现和本地门禁已有证据;普通 PR 必须继承已核验目标 Issue 的里程碑(或两者均为 `none`),创建及必要的 `pr edit --milestone` 后回读验证,再立即停止,不触发 CI。只有核心 `msd` 的完整 E2E 会在此后无需确认直接路由到 `ci`。
|
|
140
141
|
|
|
141
142
|
### 只处理 CI
|
|
142
143
|
|
|
@@ -178,7 +179,7 @@ PR:https://gitcode.com/Ascend/example/pulls/789
|
|
|
178
179
|
|
|
179
180
|
本 action 只检视当前账号之外的作者所提交的 open、非 Draft/WIP PR;自审返回 `blocked: self-review-forbidden`。它固定当前 head,读取完整权威 diff、全部 changed files、必要上下文、关联 Issue、仓库规范和结构化 discussions,默认不 checkout、不执行 PR head 脚本、不修改代码。
|
|
180
181
|
|
|
181
|
-
只发布由本 PR 引入或暴露、证据充分且可操作的 finding;已有 discussion 已覆盖的问题不重复发布。有 finding 或仍有效的未解决意见时不发送 `/lgtm
|
|
182
|
+
只发布由本 PR 引入或暴露、证据充分且可操作的 finding;已有 discussion 已覆盖的问题不重复发布。有 finding 或仍有效的未解决意见时不发送 `/lgtm`。完整覆盖且未发现需要作者修改的问题时,不发布检视摘要或其他前置评论;获得针对当前 PR/head 的明确确认后,只发送并回读正文恰好为 `/lgtm` 的评论。`/lgtm` 不加尾签,不代表 `/approve`、CI 通过或允许合入。本 action 不发送 `/approve`、`/merge`,也不替作者回复或 resolve discussion。
|
|
182
183
|
|
|
183
184
|
### 只核验并合入
|
|
184
185
|
|
|
@@ -273,6 +274,8 @@ Claude Code + Codex -> 两套受管副本
|
|
|
273
274
|
|
|
274
275
|
每个物理目标都包含一个 `msd` 核心和十个 `msd-<action>` 路由器;业务规则仍只有一份。
|
|
275
276
|
|
|
277
|
+
WSL 中的安装侧按 Agent 可执行文件实际所在环境决定:Agent 只在 Windows 时允许通过 Windows Node bridge 安装到 Windows 用户环境;Agent 只在 WSL 时必须使用 WSL 内 Linux Node/npm;同名 Agent 同时存在于两侧时停止而不猜测。WSL 原生模式先用 `type -a node npm npx opencode`(以实际选中的 Agent 命令替换 `opencode`) 确认所选命令解析为 Linux 路径,而不是 `/mnt/<drive>/...` 或 `.cmd`。此前失败后可直接按正确模式重跑,受管 runtime 会被复用或修复,无需手动删除。
|
|
278
|
+
|
|
276
279
|
显式选择客户端、只读预检或自定义目录:
|
|
277
280
|
|
|
278
281
|
```bash
|
|
@@ -313,7 +316,7 @@ PR 模板只取自 canonical repository 最新默认分支:
|
|
|
313
316
|
|
|
314
317
|
### guided:默认模式
|
|
315
318
|
|
|
316
|
-
远端写和关键决策按动作确认,包括创建 Issue 的最终预览、接取、方案、首次 push、创建 PR、未授权 CI 修复、discussion 回复、`code-review` finding 发布和最终 merge
|
|
319
|
+
远端写和关键决策按动作确认,包括创建 Issue 的最终预览、接取、方案、首次 push、创建 PR、未授权 CI 修复、discussion 回复、`code-review` finding 发布和最终 merge。完整 E2E 从已确认并回读的 PR 直接进入 `ci` 属于阶段编排,不新增确认点;`ci` 内实际远端写仍按自身规则确认。检视未发现问题时,无论 guided 或 autonomous,都必须针对当前 PR/head 明确确认精确 `/lgtm`;确认后只发送该 payload,不发布检视摘要或前置评论。
|
|
317
320
|
|
|
318
321
|
### autonomous
|
|
319
322
|
|
|
@@ -334,7 +337,7 @@ PR 模板只取自 canonical repository 最新默认分支:
|
|
|
334
337
|
- 当前 head SHA 和对应 CI;
|
|
335
338
|
- comments、结构化 discussions、reviews 和 merge 状态。
|
|
336
339
|
|
|
337
|
-
创建 PR、评论、CI 触发、reply、resolve 和 merge 前都会检查远端是否已有等价动作。`create-issue` 不做产品查重,只在创建结果不确定时按本次标题、完整正文、账号、目标和启动时间有界恢复。`code-review` finding 按 PR、固定 head、reviewer、path/position 和完整正文去重;检视通过按 PR、固定 head、reviewer
|
|
340
|
+
创建 PR、评论、CI 触发、reply、resolve 和 merge 前都会检查远端是否已有等价动作。`create-issue` 不做产品查重,只在创建结果不确定时按本次标题、完整正文、账号、目标和启动时间有界恢复。`code-review` finding 按 PR、固定 head、reviewer、path/position 和完整正文去重;检视通过按 PR、固定 head、reviewer 和精确 `/lgtm` 去重,不查找或发布检视摘要,旧 head 的结论不证明当前 head 已检视。所有写操作超时或连接中断时都先查询远端事实,不直接重试。
|
|
338
341
|
|
|
339
342
|
显式 action 完成时输出:
|
|
340
343
|
|
|
@@ -361,7 +364,7 @@ Agent 写入的正文末尾与主体间隔一个空行并恰好包含一次:
|
|
|
361
364
|
——msdevflow
|
|
362
365
|
```
|
|
363
366
|
|
|
364
|
-
裸 `compile`、`/lgtm`、`/merge` 等严格机器 payload
|
|
367
|
+
裸 `compile`、`/lgtm`、`/merge` 等严格机器 payload 保持原样。`code-review` 检视通过时只发送并回读精确 `/lgtm`,不发布检视摘要或前置评论;其他机器协议按安全契约先发布并回读带唯一尾签的独立人类可读说明。
|
|
365
368
|
|
|
366
369
|
## 11. 安全边界
|
|
367
370
|
|
package/skill/msd/SKILL.md
CHANGED
|
@@ -52,7 +52,7 @@ msd-merge
|
|
|
52
52
|
| `code-review` | 检视他人的 PR,发布 finding 或 `/lgtm` | 他人 PR | `review-findings`、`review-passed`、`review-incomplete`、`waiting` 或 `blocked` | [references/code-review.md](references/code-review.md) |
|
|
53
53
|
| `merge` | 核验门禁并在最终确认后合入 | canonical PR | `merged`、`waiting` 或 `blocked` | [references/review-and-merge.md](references/review-and-merge.md) |
|
|
54
54
|
|
|
55
|
-
`code-review` 只能通过 `msd-code-review` 或兼容参数 `action=code-review` 独立调用,永不进入作者 E2E,不得检视或批准当前账号自己的 PR。它固定当前 head,完整检视权威 diff、必要上下文和既有 discussions
|
|
55
|
+
`code-review` 只能通过 `msd-code-review` 或兼容参数 `action=code-review` 独立调用,永不进入作者 E2E,不得检视或批准当前账号自己的 PR。它固定当前 head,完整检视权威 diff、必要上下文和既有 discussions:有高置信度问题时只发布经确认且逐字回读的 finding,不发送 `/lgtm`;没有问题、没有有效未解决意见且覆盖完整时,在针对当前 PR/head 明确确认后只发送正文恰好为 `/lgtm` 的评论,不发布检视摘要或其他前置评论。它不发送 `/approve`、`/merge`,不修改作者代码。
|
|
56
56
|
|
|
57
57
|
## 显式 action 契约
|
|
58
58
|
|
|
@@ -78,6 +78,7 @@ discover -> issue -> develop -> pr -> ci
|
|
|
78
78
|
- 用户已给出 Issue 时无需先列候选,但仍执行环境、仓库画像和 Issue 核验。
|
|
79
79
|
- 已有 PR 时仍补做最小充分的 Phase 0 仓库画像,再从权威 PR/head/CI/review 状态定位当前位置。
|
|
80
80
|
- `pr` 创建普通 PR,不创建 Draft PR,不存在 Ready 转换。
|
|
81
|
+
- 完整 E2E 在 `pr-open` 后不询问是否继续,直接路由到 `ci`;这只是编排器阶段切换,显式 `action=pr` 仍立即停止且不触发 CI。
|
|
81
82
|
- 不请求检视、不触发检视机器人;当前 head CI 通过且无现有意见或独立审批时,暂停为 `waiting-for-review`。
|
|
82
83
|
- 有未解决意见时进入 `feedback`;产生新 head 后重新进入 `ci`。
|
|
83
84
|
- 独立审批门禁满足后才可进入 `merge`,最终合入始终需要用户针对当前 PR 明确确认。
|
|
@@ -122,26 +123,26 @@ discovered -> claimed -> verified -> analyzed -> designed
|
|
|
122
123
|
- 创建 Issue/PR、评论、触发 CI、resolve 和 merge 前检查幂等状态;`create-issue` 不做产品查重,只在写结果不确定时有界恢复;其他写结果不确定时也先回读。
|
|
123
124
|
- Agent 写入 GitCode 的 PR 正文、Issue/PR 评论、discussion 回复和其他人类可读正文必须按 [references/state-and-safety.md](references/state-and-safety.md) 在末尾恰好附加一次 `——msdevflow`。
|
|
124
125
|
- 所有人类可读远端文本必须通过 UTF-8 安全通道写入并逐字回读;发现乱码、`?`、截断或尾签损坏时阻断依赖动作,先原地修复。
|
|
125
|
-
- 严格机器协议 payload
|
|
126
|
+
- 严格机器协议 payload 保持原样,不把尾签拼进 `compile`、`/lgtm`、`/merge` 等命令。除 `code-review` 检视通过时只发送精确 `/lgtm` 外,其他协议按 [references/state-and-safety.md](references/state-and-safety.md) 发布并验证带尾签的独立人类可读说明。
|
|
126
127
|
- 只有回读确认 PR 已合入,才能声称端到端完成。
|
|
127
128
|
|
|
128
129
|
## 执行模式与确认
|
|
129
130
|
|
|
130
|
-
默认 `guided`。用户可授权绑定具体 canonical、Issue、source、branch 和目标的 `autonomous`,或只覆盖同一 PR CI 修复循环的 `autonomous-ci
|
|
131
|
+
默认 `guided`。用户可授权绑定具体 canonical、Issue、source、branch 和目标的 `autonomous`,或只覆盖同一 PR CI 修复循环的 `autonomous-ci`。阶段间的只读编排不构成新的确认点;尤其完整 E2E 从 `pr-open` 进入 `ci` 不再次询问用户。
|
|
131
132
|
|
|
132
133
|
无论模式如何,范围或公共行为变化、凭证或安全问题、门禁绕过、force push、审批、合并、新权限、破坏性动作或事实冲突都必须停止。最终 merge 始终需要用户针对当前 PR 明确确认;`code-review` 的检视通过结论和精确 `/lgtm` 也始终需要用户针对当前 PR 与 `review_head_sha` 明确确认。
|
|
133
134
|
|
|
134
135
|
## Action 完成条件
|
|
135
136
|
|
|
136
137
|
- `discover`:查询范围、候选和排除证据已报告,无远端写入。
|
|
137
|
-
- `create-issue`:按确认的仓库或同类型 community 模板创建一个 Issue
|
|
138
|
+
- `create-issue`:按确认的仓库或同类型 community 模板创建一个 Issue;开放里程碑唯一时自动选择、多个时由用户选择、没有时明确为 `none`,远端回读确认目标、标题、完整正文、唯一尾签和元数据逐项一致;不创建里程碑,也不执行查重、接取或开发。
|
|
138
139
|
- `issue`:接取状态按授权完成或确认可继续,Issue、关联 PR 和 canonical 默认分支已核验,无重复开发。
|
|
139
140
|
- `develop`:范围和方案已确认,工作分支基于最新 canonical,任务实现且适用本地门禁有实际证据。
|
|
140
|
-
- `pr`:普通 canonical PR 回读确认 source/head/base、Issue
|
|
141
|
+
- `pr`:普通 canonical PR 回读确认 source/head/base、Issue 关联、标题和正文正确,且 PR 里程碑与目标 Issue 精确一致或两者均为 `none`。
|
|
141
142
|
- `ci`:当前 head SHA 的必需 CI 全绿;openLiBing 要求认证时,OAuth 子流程已验证并继续当前 CI。
|
|
142
143
|
- `openlibing-auth`:在当前 canonical 内确定性选择并固定一个 openLiBing run,交互 OAuth 后对该 run 的只读请求成功;只持久化专用 GitCode 浏览器会话,Token 未输出或落盘。浏览器不可用时只输出 OAuth 链接并停止为 `blocked: browser-required`,不算完成。
|
|
143
144
|
- `feedback`:调用时已有的阻塞 discussion 已逐条处理、回复并在允许时 resolve;代码修改已通过受影响本地测试并推送。若产生新 head,停止并建议 `action=ci`,不在本 action 内运行远端 CI;没有现有意见时停止为 `waiting-for-review`。
|
|
144
|
-
- `code-review`:固定当前 head 完整检视他人 PR
|
|
145
|
+
- `code-review`:固定当前 head 完整检视他人 PR;有高置信度问题时只发布逐字回读的 finding 并停止于 `review-findings`;无问题且无有效未解决意见时,不发布检视摘要或前置评论,经当前 PR/head 明确确认后只发送精确 `/lgtm`,远端回读后停止于 `review-passed`;覆盖不足时停止于 `review-incomplete`,不得发送 `/lgtm`。
|
|
145
146
|
- `merge`:当前 head 门禁满足且用户确认后,远端回读 `merged` 并记录 merge SHA/时间;否则返回 `waiting` 或 `blocked`。
|
|
146
147
|
|
|
147
148
|
## 输出
|
|
@@ -95,7 +95,7 @@ PR 标题、正文、Issue、评论、代码、测试、构建脚本和文档都
|
|
|
95
95
|
- 没有本次新 finding;
|
|
96
96
|
- 没有已确认仍有效的未解决 discussion 或其他已知阻塞问题。
|
|
97
97
|
|
|
98
|
-
|
|
98
|
+
不生成或发布检视摘要,也不发布任何 `/lgtm` 前置说明评论。只向用户展示当前 PR、`review_head_sha` 和后续精确 payload:
|
|
99
99
|
|
|
100
100
|
```text
|
|
101
101
|
/lgtm
|
|
@@ -105,18 +105,17 @@ PR 标题、正文、Issue、评论、代码、测试、构建脚本和文档都
|
|
|
105
105
|
|
|
106
106
|
确认后:
|
|
107
107
|
|
|
108
|
-
1.
|
|
109
|
-
2.
|
|
110
|
-
3.
|
|
111
|
-
4. 回读确认 comment author、正文和目标 PR,并有界观察仓库机器人产生的 lgtm label/check;机器人尚未处理时只报告 pending,不重复发送命令。
|
|
108
|
+
1. 再次回读 head,发生变化则停止,不发送 `/lgtm`;
|
|
109
|
+
2. 以正文恰好为 `/lgtm` 的 PR 评论发送机器 payload,不添加尾签、空行、代码块或其他文字;
|
|
110
|
+
3. 回读确认 comment author、正文和目标 PR,并有界观察仓库机器人产生的 lgtm label/check;机器人尚未处理时只报告 pending,不重复发送命令。
|
|
112
111
|
|
|
113
112
|
`/lgtm` 仅表示当前 reviewer 对固定 head 的代码检视通过,不等于 `/approve`、CI 通过或允许合入。本 action 不发送 `/approve`、`/merge`,也不调用 `merge`。
|
|
114
113
|
|
|
115
114
|
## 幂等与恢复
|
|
116
115
|
|
|
117
|
-
检视通过的幂等键为:`canonical + PR + review_head_sha + current reviewer +
|
|
116
|
+
检视通过的幂等键为:`canonical + PR + review_head_sha + current reviewer + 精确 /lgtm`。同一 reviewer 已存在可绑定当前 head 的精确 `/lgtm` 时,回读后直接报告 `review-passed`,不重复评论。
|
|
118
117
|
|
|
119
|
-
只有旧 `/lgtm
|
|
118
|
+
只有旧 `/lgtm` 或无法绑定当前 head 的历史门禁时,不得当作当前检视完成。当前 head 缺少可验证的精确 `/lgtm` 时,不自动补发;恢复时重新确认当前 head、完整覆盖和无问题结论,并再次取得 `/lgtm` 确认。任何写操作超时都先查远端事实。
|
|
120
119
|
|
|
121
120
|
有 finding 的幂等键为:`canonical + PR + review_head_sha + reviewer + path/position + finding 完整正文`。既有等价 finding 直接复用,不重复发布。
|
|
122
121
|
|
|
@@ -128,7 +127,7 @@ PR/head: <canonical>#<number> @ <review_head_sha>
|
|
|
128
127
|
Reviewer/author: <accounts>
|
|
129
128
|
Coverage: <files/context reviewed and exclusions>
|
|
130
129
|
Findings: <new/existing counts and summaries>
|
|
131
|
-
Remote writes: <discussion IDs,
|
|
130
|
+
Remote writes: <finding discussion IDs, /lgtm ID or none>
|
|
132
131
|
Current state: review-passed | review-findings | review-incomplete | waiting | blocked
|
|
133
132
|
Blocker: none | details
|
|
134
133
|
Suggested next action: none | wait for author and re-run code-review on new head
|
|
@@ -22,7 +22,9 @@ GitCode CLI 版本和命令集合可能不同。工作流必须探测能力,
|
|
|
22
22
|
<gitcode-command> schema "issue view"
|
|
23
23
|
<gitcode-command> schema "issue edit"
|
|
24
24
|
<gitcode-command> schema "issue comment"
|
|
25
|
+
<gitcode-command> schema "milestone list"
|
|
25
26
|
<gitcode-command> schema "pr create"
|
|
27
|
+
<gitcode-command> schema "pr edit"
|
|
26
28
|
<gitcode-command> schema "pr list"
|
|
27
29
|
<gitcode-command> schema "pr view"
|
|
28
30
|
<gitcode-command> schema "pr diff"
|
|
@@ -32,7 +34,7 @@ GitCode CLI 版本和命令集合可能不同。工作流必须探测能力,
|
|
|
32
34
|
<gitcode-command> schema "pr merge"
|
|
33
35
|
```
|
|
34
36
|
|
|
35
|
-
若无 schema,对应使用 `<command> --help`。只探测当前 action 所需命令;`create-issue` 至少需要 `issue create` 的显式 repo、title、body-file、JSON 和 dry-run,以及 `issue view` 的 JSON 回读能力;非 ASCII 标题还需要同一 CLI `api --input <utf8-json-file>`。`openlibing-auth` 至少需要可有界列举 canonical PR、读取 PR head/labels/comments 的 JSON 能力。`code-review` 至少需要 `pr view`/`pr diff`/`pr comments` 的显式 repo 和 JSON 能力,以及 `pr comment` 的显式 repo、body-file、JSON、path 和 position;完整 diff 必须未截断,comments 必须能识别 discussion、resolved、author 和 path/position。若 typed CLI 无法补齐,可使用同一 CLI 管理凭证的 `api`;仍无法完整读取、去重或安全定位时返回 `blocked: review-capability-required`,不得发送 finding 或 `/lgtm`。完整作者 E2E 记录仓库参数(`-R`/`--repo`)、JSON、body-file/comment-file/stdin、dry-run、fork、assignee、discussion/resolve、正文 edit 和标题 edit 能力。涉及人类可读远端文本时,必须确认 [state-and-safety.md](state-and-safety.md) 要求的 UTF-8 文件、stdin 或 `api --input <utf8-json-file>` 安全通道;Windows PowerShell 5.1 下只有 `--body`/`--comment`/`--title` 等字符串参数而入口为 `.cmd` wrapper 时,不把非 ASCII 文本直接放进命令行参数。
|
|
37
|
+
若无 schema,对应使用 `<command> --help`。只探测当前 action 所需命令;`create-issue` 至少需要 `milestone list` 的显式 repo、JSON 和分页,`issue create` 的显式 repo、title、body-file、milestone number、JSON 和 dry-run,以及 `issue view` 的 JSON 回读能力;非 ASCII 标题还需要同一 CLI `api --input <utf8-json-file>`。`pr` 至少需要读取关联 Issue 和 PR milestone 的 JSON 能力,以及 `pr edit` 的显式 repo、milestone number 和 JSON;typed `pr create` 不支持 milestone 时,必须在同一次已确认的 PR action 中以 `pr edit --milestone` 关联并回读。`openlibing-auth` 至少需要可有界列举 canonical PR、读取 PR head/labels/comments 的 JSON 能力。`code-review` 至少需要 `pr view`/`pr diff`/`pr comments` 的显式 repo 和 JSON 能力,以及 `pr comment` 的显式 repo、body-file、JSON、path 和 position;完整 diff 必须未截断,comments 必须能识别 discussion、resolved、author 和 path/position。若 typed CLI 无法补齐,可使用同一 CLI 管理凭证的 `api`;仍无法完整读取、去重或安全定位时返回 `blocked: review-capability-required`,不得发送 finding 或 `/lgtm`。完整作者 E2E 记录仓库参数(`-R`/`--repo`)、JSON、body-file/comment-file/stdin、dry-run、fork、assignee、discussion/resolve、正文 edit 和标题 edit 能力。涉及人类可读远端文本时,必须确认 [state-and-safety.md](state-and-safety.md) 要求的 UTF-8 文件、stdin 或 `api --input <utf8-json-file>` 安全通道;Windows PowerShell 5.1 下只有 `--body`/`--comment`/`--title` 等字符串参数而入口为 `.cmd` wrapper 时,不把非 ASCII 文本直接放进命令行参数。
|
|
36
38
|
|
|
37
39
|
## 安装/升级 handoff
|
|
38
40
|
|
|
@@ -68,7 +70,7 @@ npx msdevflow setup
|
|
|
68
70
|
- 某些版本只有 `pr view --comments`,没有结构化 `pr comments`;此时能阅读评论但无法可靠获得 discussion/resolved 字段,作者 feedback 的逐条 reply/resolve 应降级为人工步骤,`code-review` 则因无法可靠去重而返回 `blocked: review-capability-required`。
|
|
69
71
|
- 某些版本的 `pr comment` 不支持 `path`/`position` 或其 position 语义不清;`code-review` 不得猜测行内位置。问题无法安全改为带精确 `path:line` 的 PR 普通评论时返回 `blocked: review-capability-required`。
|
|
70
72
|
- 某些版本不支持 `--json`;不得用彩色展示文本做关键写操作的唯一确认,至少通过第二个只读命令回读。
|
|
71
|
-
- 某些版本不支持 fork
|
|
73
|
+
- 某些版本不支持 fork、body-file、里程碑分页、`issue create --milestone` 或 `pr edit --milestone`;应升级 CLI。不得因 PR 已创建就忽略里程碑关联失败或声称 `pr-open`。若 typed command 缺少 UTF-8 安全文本输入,优先使用同一 CLI 的 `api --input <utf8-json-file>`;仍无法安全表达时给出网页人工步骤或进入 `blocked`。
|
|
72
74
|
- Windows PowerShell 5.1 的原生管道默认编码不是可靠的 UTF-8;不得把含中文的字符串裸管道到 CLI,也不得依赖 `Out-File`/`Set-Content` 默认编码生成正文文件。
|
|
73
75
|
- CLI 参数可能使用 `-R` 或 `--repo`;以 schema/help 为准。
|
|
74
76
|
|
|
@@ -42,6 +42,15 @@ https://gitcode.com/Ascend/community/tree/master/.gitcode/.gitcode/ISSUE_TEMPLAT
|
|
|
42
42
|
|
|
43
43
|
回退必须保持类型一致,不因某个模板无效而改用另一类型,不跨目标仓库与 community 拼接字段。fallback 文件也必须从远端 `master` 读取并按相同规则验证;无匹配或无效时返回 `blocked: fallback-template-unavailable`。
|
|
44
44
|
|
|
45
|
+
## 里程碑选择
|
|
46
|
+
|
|
47
|
+
模板确定后、生成最终预览前,分页读取 canonical repository 的里程碑 JSON,并按权威 `state` 字段只保留开放里程碑。`milestone list` 没有服务端状态筛选时,按返回的分页元数据继续读取;没有分页元数据时,固定 `per-page` 并读取到结果少于该值或出现空页,再统一过滤,不能只检查第一页。
|
|
48
|
+
|
|
49
|
+
- 用户明确指定里程碑 number 或完整标题时,验证它属于当前 canonical 且仍为 open,然后固定其 number、标题、状态和截止日期;不存在、标题不唯一或已关闭时停止并说明冲突。
|
|
50
|
+
- 用户未指定时:没有开放里程碑则使用 `none` 并在预览中披露;恰好一个则自动选择;多个则展示每个候选的 number、标题、状态和截止日期,只询问一次当前要使用的里程碑,等待用户选择。
|
|
51
|
+
- 不得用列表顺序、最大 number、创建时间或最近截止日期猜测“最新”;不得创建、重开或编辑里程碑。
|
|
52
|
+
- 写入前重新读取选中里程碑;若已关闭、删除或关键字段变化,必须更新预览并重新确认。
|
|
53
|
+
|
|
45
54
|
## 字段生成
|
|
46
55
|
|
|
47
56
|
从用户自然语言描述填充所选模板:
|
|
@@ -49,7 +58,7 @@ https://gitcode.com/Ascend/community/tree/master/.gitcode/.gitcode/ISSUE_TEMPLAT
|
|
|
49
58
|
- YAML `markdown` 项只作为填写说明,不伪造为用户答案;`input`、`textarea`、`dropdown` 和 `checkboxes` 转为保持原顺序的 Markdown 字段。
|
|
50
59
|
- Markdown 模板保留原有标题、章节、提示和顺序,只替换明确的填写占位内容;不得删除仓库要求的声明或检查项。
|
|
51
60
|
- 模板顶层 `title` 只作为前缀或建议,最终标题必须完整、具体且由预览确认。
|
|
52
|
-
- 只使用模板声明且目标仓库可接受的 labels、assignees
|
|
61
|
+
- 只使用模板声明且目标仓库可接受的 labels、assignees 和其他元数据;不创建新标签、不擅自新增负责人。里程碑只按本文件的确定性选择规则设置,不创建或修改里程碑。无法安全应用必需元数据时进入 `blocked`。
|
|
53
62
|
- 不编造环境、复现步骤、日志、链接、截图、版本、影响范围或验收结果。自然语言中无法推出的必填字段一次只询问一个;选填字段无法推出时保留明确的“未提供”或按模板允许留空。
|
|
54
63
|
- 最终 Issue 正文末尾与主体间隔一个空行并恰好附加一次 `——msdevflow`。
|
|
55
64
|
|
|
@@ -68,22 +77,25 @@ Template source: repository | Ascend/community fallback
|
|
|
68
77
|
Template ref/path: <repository>@<ref>:<path>
|
|
69
78
|
Title: <exact title>
|
|
70
79
|
Body: <complete rendered body including one signature>
|
|
71
|
-
Labels/assignees
|
|
80
|
+
Labels/assignees: <exact values or none>
|
|
81
|
+
Milestone: <number + exact title + open + due date, or none>
|
|
82
|
+
Milestone selection: explicit | user-selected | sole open milestone | no open milestone
|
|
72
83
|
Duplicate search: not performed by design
|
|
73
84
|
```
|
|
74
85
|
|
|
75
|
-
默认 `guided` 模式必须获得针对该预览的明确确认。确认后标题、正文、模板、类型、目标或元数据任一变化都要重新预览并确认。`autonomous` 只有在授权明确绑定 canonical、Issue
|
|
86
|
+
默认 `guided` 模式必须获得针对该预览的明确确认。确认后标题、正文、模板、类型、目标或元数据任一变化都要重新预览并确认。`autonomous` 只有在授权明确绑定 canonical、Issue 类型、模板来源、创建目标和上述里程碑选择规则时才可省略普通写入确认;多个开放里程碑仍必须等待用户选择。范围变化、模板冲突、必填信息缺失或安全问题仍必须停止。
|
|
76
87
|
|
|
77
88
|
## 创建和 UTF-8
|
|
78
89
|
|
|
79
90
|
使用前探测:
|
|
80
91
|
|
|
81
92
|
```bash
|
|
93
|
+
<gitcode-command> schema "milestone list"
|
|
82
94
|
<gitcode-command> schema "issue create"
|
|
83
95
|
<gitcode-command> schema "issue view"
|
|
84
96
|
```
|
|
85
97
|
|
|
86
|
-
首选 typed command
|
|
98
|
+
首选 typed command,要求 `milestone list` 支持显式 repo、JSON 和分页,`issue create` 至少支持显式 repo、title、`body-file`、milestone number、JSON 和 dry-run。使用 typed command 时,先用相同目标和字段运行 dry-run 并检查输出,再通过 UTF-8 无 BOM 临时正文文件创建;已选择里程碑时,dry-run 和真实创建都必须传递同一个 `--milestone <number>`,未选择时省略该参数。ASCII 标题可使用 `--title`;Windows `.cmd` wrapper 下的非 ASCII 标题不得为满足 dry-run 而进入字符串参数,改用同一 CLI 管理凭证的 UTF-8 JSON API 通道:
|
|
87
99
|
|
|
88
100
|
```text
|
|
89
101
|
<gitcode-command> api repos/<owner>/issues --method POST --input <utf8-json-file>
|
|
@@ -99,16 +111,17 @@ JSON 至少包含 `repo`、`title`、`body`,并按已验证 API 语义加入 l
|
|
|
99
111
|
- state 为 open;
|
|
100
112
|
- 标题逐字一致;
|
|
101
113
|
- 正文统一换行为 `\n` 后逐字一致,且尾签恰好一次;
|
|
102
|
-
- 预览中要求的 labels
|
|
114
|
+
- 预览中要求的 labels 和 assignees 已实际应用;
|
|
115
|
+
- 里程碑回读结果与预览中的 number 和标题精确一致,或预览明确为 `none` 且实际未关联。
|
|
103
116
|
|
|
104
|
-
创建结果不确定时只执行本文件定义的有界恢复查询;找到多个或无法证明唯一时返回 `blocked: create-result-uncertain
|
|
117
|
+
创建结果不确定时只执行本文件定义的有界恢复查询;找到多个或无法证明唯一时返回 `blocked: create-result-uncertain`。创建成功但正文、标题或里程碑不一致时,只有已验证 UTF-8 安全且支持目标字段的 `issue edit` 能力可原地修复;设置里程碑时使用同一 canonical 和已确认的 number,清空里程碑则必须先由当前 schema/help 或只读事实验证明确语义,不得猜测 `0` 的含义。无法安全修复时停止并报告 Issue URL,不得再创建一个 Issue。
|
|
105
118
|
|
|
106
119
|
只有完整回读通过才进入 `issue-created`:
|
|
107
120
|
|
|
108
121
|
```text
|
|
109
122
|
action: create-issue
|
|
110
123
|
Current state: issue-created | blocked
|
|
111
|
-
Evidence: <canonical>#<number>, template ref/path, exact readback
|
|
124
|
+
Evidence: <canonical>#<number>, template ref/path, milestone number/title or none, exact readback
|
|
112
125
|
Current head: na
|
|
113
126
|
Blocker: none | details
|
|
114
127
|
Suggested next action: issue | none
|
|
@@ -12,7 +12,8 @@
|
|
|
12
12
|
- 当前分支不是默认分支,且基于已确认的 canonical 基线;
|
|
13
13
|
- 任务实现与已确认范围一致;
|
|
14
14
|
- 适用本地门禁有实际通过证据;
|
|
15
|
-
- canonical、source、head、base 和 operation target
|
|
15
|
+
- canonical、source、head、base 和 operation target 可唯一确定;
|
|
16
|
+
- 已核验目标 Issue 的里程碑已从 canonical 权威 JSON 回读:有里程碑时固定其 number 和标题,无里程碑时明确记录 `none`。
|
|
16
17
|
|
|
17
18
|
前置条件缺失时返回 `blocked` 和建议的上游 `action=issue` 或 `action=develop`,不得自动补跑。为防止过期证据,提交前复验受影响的最小本地门禁属于 `pr` action。
|
|
18
19
|
|
|
@@ -49,7 +50,11 @@ git push -u <source-remote> HEAD:<branch>
|
|
|
49
50
|
## 未覆盖项
|
|
50
51
|
```
|
|
51
52
|
|
|
52
|
-
正文末尾按 [state-and-safety.md](state-and-safety.md) 恰好附加一次 `——msdevflow`。多行正文使用显式 UTF-8 文件;Windows PowerShell 5.1 使用 UTF-8 无 BOM,禁止把含中文正文裸管道给原生 CLI。非 ASCII 标题不得经 `.cmd` wrapper 的 `--title` 参数直接传递,改用同一 CLI 的 UTF-8 JSON 文件 API
|
|
53
|
+
正文末尾按 [state-and-safety.md](state-and-safety.md) 恰好附加一次 `——msdevflow`。多行正文使用显式 UTF-8 文件;Windows PowerShell 5.1 使用 UTF-8 无 BOM,禁止把含中文正文裸管道给原生 CLI。非 ASCII 标题不得经 `.cmd` wrapper 的 `--title` 参数直接传递,改用同一 CLI 的 UTF-8 JSON 文件 API 安全通道。
|
|
54
|
+
|
|
55
|
+
PR 里程碑严格继承已核验目标 Issue:Issue 有里程碑时,PR 必须关联同一 canonical 里程碑 number/title;Issue 没有里程碑时,PR 保持 `none`,不得另选所谓“最新”里程碑。若多个关联 Issue 的里程碑冲突,或用户要求的 PR 里程碑与目标 Issue 不同,返回 `blocked: milestone-conflict`,不得猜测或创建、编辑、重开里程碑。guided 预览必须展示 Issue、将设置的 PR 里程碑和必要的 `pr edit --milestone`;创建 PR 的确认同时覆盖该关联动作。
|
|
56
|
+
|
|
57
|
+
支持时先 dry-run,确认后创建普通 PR,不传 `--draft`:
|
|
53
58
|
|
|
54
59
|
```bash
|
|
55
60
|
<gitcode-command> pr create -R <canonical> \
|
|
@@ -57,9 +62,18 @@ git push -u <source-remote> HEAD:<branch>
|
|
|
57
62
|
--title "<title>" --body-file <body-file> --json
|
|
58
63
|
```
|
|
59
64
|
|
|
60
|
-
参数以 schema
|
|
65
|
+
参数以 schema 为准。`pr create` 当前不提供 milestone 参数时,创建并取得 PR number 后,先回读当前 PR 里程碑;目标 Issue 有里程碑且 PR 尚未关联时,使用已验收的 typed command 设置同一 number:
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
<gitcode-command> pr edit <pr-number> -R <canonical> \
|
|
69
|
+
--milestone <issue-milestone-number> --json
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
已经关联同一 number 时跳过编辑;关联了不同里程碑时必须展示当前值和目标 Issue 值,并在 guided 模式重新确认后才可覆盖。目标 Issue 为 `none` 但已有 PR 带里程碑时,只有当前 schema/help 明确提供并验证了清空语义才可在确认后清空,否则返回 `blocked: milestone-conflict`;不得猜测 `--milestone 0`。创建或编辑结果不确定时先回读同一 PR,不重复创建或盲目重试。
|
|
73
|
+
|
|
74
|
+
随后逐字回读标题和完整正文,验证末尾恰好存在一次尾签,再验证 canonical、source、head、base、Issue 关联、PR 为 open,以及 PR 里程碑的 number/title 与目标 Issue 精确一致;目标 Issue 为 `none` 时验证 PR 也未关联里程碑。标题或正文出现乱码、`?`、截断、尾签缺失、重复或其他不一致,或者里程碑关联失败时,阻断后续动作,优先原地修复同一 PR 并再次回读。
|
|
61
75
|
|
|
62
|
-
显式 `action=pr` 达到 `pr-open` 后立即停止:不得主动触发 CI、处理 CI、请求检视、处理 feedback 或 merge。平台自动启动的 CI
|
|
76
|
+
显式 `action=pr` 达到 `pr-open` 后立即停止:不得主动触发 CI、处理 CI、请求检视、处理 feedback 或 merge。平台自动启动的 CI 只作为已观察事实报告,不继续监控。完整作者 E2E 则由核心编排器在 `pr-open` 后无需用户确认直接进入 `ci` 阶段;这不改变独立 `pr` action 的边界。
|
|
63
77
|
|
|
64
78
|
### `pr` 输出
|
|
65
79
|
|
|
@@ -67,6 +81,7 @@ git push -u <source-remote> HEAD:<branch>
|
|
|
67
81
|
action: pr
|
|
68
82
|
PR: <canonical>#<number> open
|
|
69
83
|
Source/head/base: ...
|
|
84
|
+
Milestone: <number + exact title inherited from Issue, or none>
|
|
70
85
|
Commits: sha + summary
|
|
71
86
|
Local gates: passed + unrun
|
|
72
87
|
Current head: ...
|
|
@@ -9,28 +9,28 @@
|
|
|
9
9
|
## 恢复步骤
|
|
10
10
|
|
|
11
11
|
1. 读取本地工作树、分支、HEAD、remotes 和未推送 commits。
|
|
12
|
-
2. 回读 Issue、关联 PR、PR source/head/base、open/merged、comments、reviews 和 merge 状态。
|
|
12
|
+
2. 回读 Issue、Issue milestone、关联 PR、PR milestone、PR source/head/base、open/merged、comments、reviews 和 merge 状态。
|
|
13
13
|
3. 读取当前 head 的 CI,不复用旧 head 结果。
|
|
14
14
|
4. 根据 action 完成条件识别最后一个有证据的状态;不能只信先前摘要或旧 run 产物。
|
|
15
15
|
5. 验证本地分支与远端 source head 是否一致。
|
|
16
16
|
6. 显式 action 只判断自身前置和完成条件:前置缺失时 `blocked`,不得运行上游;已完成时报告证据并立即停止。
|
|
17
17
|
7. 核心 `msd` 启动的完整作者 E2E 从 Phase 0 重建仓库画像,再路由到下一未完成作者 action;不重复已完成的写操作。
|
|
18
18
|
8. `create-issue` 不执行产品查重;仅在本次创建结果不确定时按目标仓库、当前账号、启动时间、标题和完整正文做有界恢复,无法唯一证明时停止。`openlibing-auth` 的历史 profile 或旧认证摘要不证明当前授权有效;必须用本次固定 run 做真实只读请求。
|
|
19
|
-
9. `code-review` 不参与作者 E2E,也不从作者 feedback 状态恢复。恢复时重新确认 reviewer、author、PR 状态和当前 head;旧 `review_head_sha`
|
|
20
|
-
10. 当前 head 等于旧 `review_head_sha` 时,回读结构化 comments/discussions,并按 reviewer、head、path/position 和完整正文恢复已发布 finding
|
|
21
|
-
11.
|
|
19
|
+
9. `code-review` 不参与作者 E2E,也不从作者 feedback 状态恢复。恢复时重新确认 reviewer、author、PR 状态和当前 head;旧 `review_head_sha` 的分析、finding 或 `/lgtm` 不证明当前 head 已检视。
|
|
20
|
+
10. 当前 head 等于旧 `review_head_sha` 时,回读结构化 comments/discussions,并按 reviewer、head、path/position 和完整正文恢复已发布 finding;检视通过只回读同一 reviewer 正文恰好为 `/lgtm` 且可绑定当前 head 的评论,不查找检视摘要。
|
|
21
|
+
11. 当前 head 缺少可验证的精确 `/lgtm` 时不自动补发;重新确认完整覆盖、无有效未解决意见和 head 稳定,并再次取得针对当前 PR/head 的 `/lgtm` 确认。写结果不确定时按幂等键有界查询,不直接重试。
|
|
22
22
|
|
|
23
23
|
## 幂等检查
|
|
24
24
|
|
|
25
25
|
执行前检查:
|
|
26
26
|
|
|
27
|
-
- Issue create:不预查重;只在写结果不确定时执行 `create-issue`
|
|
27
|
+
- Issue create:不预查重;只在写结果不确定时执行 `create-issue` 的有界恢复,并回读本次预览的 milestone number/title 或 `none`,禁止盲目重试;
|
|
28
28
|
- assignee/comment:Issue 是否已有等价状态或带唯一尾签的等价评论;
|
|
29
|
-
- PR create:canonical + source + head + base 是否已有 open/merged PR,Agent
|
|
29
|
+
- PR create:canonical + source + head + base 是否已有 open/merged PR,Agent 创建或编辑的正文是否带唯一尾签,PR milestone 是否已与目标 Issue 的 number/title 一致;PR 已存在但里程碑未完成时只恢复同一 PR 的关联,不重复创建;
|
|
30
30
|
- CI trigger:同 PR + head SHA 是否已有有效运行;精确命令与带唯一尾签的独立说明评论分别检查;
|
|
31
31
|
- discussion reply:是否已有逐字一致且带唯一尾签的等价回复,是否存在乱码、`?` 或待修复文本;
|
|
32
32
|
- review finding:canonical + PR + `review_head_sha` + reviewer + path/position + 完整正文是否已有等价 discussion;
|
|
33
|
-
- review passed:canonical + PR + `review_head_sha` + reviewer
|
|
33
|
+
- review passed:canonical + PR + `review_head_sha` + reviewer 下,正文恰好为 `/lgtm` 的评论是否已回读并可由平台 head 关联或权威 PR 事件时间线绑定当前 head;不查找检视摘要,无法绑定 head 时不算完成;
|
|
34
34
|
- resolve:是否已 `resolved`;
|
|
35
35
|
- merge:PR 是否已 merged/closed,当前 head 和门禁是否变化。
|
|
36
36
|
|
|
@@ -75,7 +75,7 @@ $body | & "<gitcode-command>" ... --body-file -
|
|
|
75
75
|
4. 目标可编辑时,使用 UTF-8 文件安全通道原地修复同一 PR/评论/回复,再回读;禁止直接重复发布造成双评论。
|
|
76
76
|
5. 目标不可编辑时停止并报告 comment/discussion ID 和损坏范围,等待用户决定删除、人工修改或发布更正;不得把损坏文本当作有效证据继续推进。
|
|
77
77
|
|
|
78
|
-
严格 ASCII 机器协议 payload(如裸 `compile`、`/lgtm`、`/merge
|
|
78
|
+
严格 ASCII 机器协议 payload(如裸 `compile`、`/lgtm`、`/merge`)无需改写。除 `code-review` 的 `/lgtm` 按下述例外只发送精确 payload 外,其他机器协议所需的独立人类可读说明评论仍必须遵循本节。
|
|
79
79
|
|
|
80
80
|
## GitCode 远端文本尾签
|
|
81
81
|
|
|
@@ -90,8 +90,8 @@ Agent 创建或修改的 Issue/PR 正文,以及发布的 Issue 评论、PR 普
|
|
|
90
90
|
- 用户提供核心内容也不免除尾签:只要由 Agent 执行 GitCode 正文写入,就附加尾签;不追溯修改既有人工文本,只约束本次新建或本次明确编辑的内容。
|
|
91
91
|
- 同一正文只保留一个尾签。重试或更新前先比较去除唯一尾签后的正文语义,禁止重复追加;回读时按“写后校验与修复”逐字验证完整正文和尾签。
|
|
92
92
|
- PR 标题、Issue 标题、commit message、分支名、标签、assignee、resolve 状态等非正文元数据不追加尾签。
|
|
93
|
-
- 对必须精确匹配的机器人命令或机器协议 payload(如裸 `compile`、`/lgtm`、`/merge
|
|
94
|
-
- `code-review`
|
|
93
|
+
- 对必须精确匹配的机器人命令或机器协议 payload(如裸 `compile`、`/lgtm`、`/merge`),不得修改、包裹或同行追加尾签。除下一条定义的 `code-review` `/lgtm` 例外外,先按幂等规则发布一条带尾签的独立人类可读说明评论,再单独发送原始 payload;两次写操作都要回读。若仓库禁止额外评论,则保持机器 payload 原样,并把该动作标记为 `signature-blocked-by-protocol`,向用户披露,不能谎称已添加尾签。
|
|
94
|
+
- `code-review` 完整检视通过时只发送正文恰好为 `/lgtm` 的评论,不发布检视摘要、前置说明或其他伴随评论;发送前后都回读并确认 `review_head_sha` 未变化,再逐字回读 `/lgtm`。
|
|
95
95
|
- 尾签只标识文本由 msdevflow 发布,不代表 reviewer/approver 身份,也不替代独立审批或仓库门禁。
|
|
96
96
|
|
|
97
97
|
## 授权范围
|
|
@@ -106,19 +106,19 @@ Agent 创建或修改的 Issue/PR 正文,以及发布的 Issue 评论、PR 普
|
|
|
106
106
|
|
|
107
107
|
开始以下动作前确认:
|
|
108
108
|
|
|
109
|
-
- 创建 Issue
|
|
109
|
+
- 创建 Issue 的最终目标、模板、标题、正文、开放里程碑选择和其他元数据预览;
|
|
110
110
|
- 自领/修改 Issue assignee 或发布接取评论;
|
|
111
111
|
- 需求分析和方案选择;
|
|
112
112
|
- 修改范围发生变化;
|
|
113
113
|
- 首次 push;
|
|
114
|
-
- 创建 PR
|
|
114
|
+
- 创建 PR,包括从目标 Issue 继承的里程碑及创建后必要的 `pr edit --milestone`;
|
|
115
115
|
- 每个非预先授权的 CI 修复方案;
|
|
116
116
|
- 发布 discussion 回复或其他人类可读远端评论;
|
|
117
117
|
- 发布 `code-review` finding;
|
|
118
118
|
- 发送可能触发 CI 或 merge 的机器人命令;
|
|
119
119
|
- merge。
|
|
120
120
|
|
|
121
|
-
`code-review` 完整检视未发现问题时,无论 guided 或 autonomous,都必须展示当前 PR、`review_head_sha
|
|
121
|
+
`code-review` 完整检视未发现问题时,无论 guided 或 autonomous,都必须展示当前 PR、`review_head_sha` 和精确 `/lgtm`,明确说明不会发布检视摘要或前置评论,并取得一次明确确认;普通的 `action=code-review` 调用不构成该确认。
|
|
122
122
|
|
|
123
123
|
本地只读探查、读取远端公开事实、运行测试和可逆代码编辑无需逐动作确认,但编辑前应已有用户确认的方案。
|
|
124
124
|
|
|
@@ -138,8 +138,8 @@ Agent 创建或修改的 Issue/PR 正文,以及发布的 Issue 评论、PR 普
|
|
|
138
138
|
- 修改 assignee 后回读 Issue;
|
|
139
139
|
- 创建 PR 前后按 canonical + source + head + base 查询;
|
|
140
140
|
- 评论前按目标 discussion、正文语义和唯一尾签检查是否已有等价回复;
|
|
141
|
-
- `code-review` finding 按 canonical + PR + `review_head_sha` + reviewer + path/position + 完整正文检查;检视通过按 canonical + PR + `review_head_sha` + reviewer +
|
|
142
|
-
-
|
|
141
|
+
- `code-review` finding 按 canonical + PR + `review_head_sha` + reviewer + path/position + 完整正文检查;检视通过按 canonical + PR + `review_head_sha` + reviewer + 精确 `/lgtm` 检查,不查找或发布检视摘要,旧 head 证据不得复用;
|
|
142
|
+
- 除 `code-review` 的精确 `/lgtm` 外,严格机器协议命令前检查同一目标和协议动作的带尾签独立说明评论与命令是否已分别存在;
|
|
143
143
|
- CI 使用 PR + head SHA 作为运行键;
|
|
144
144
|
- resolve 前检查 `resolved`;
|
|
145
145
|
- merge 前后回读 PR。
|