msdevflow 0.7.4 → 0.7.5

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.
Files changed (28) hide show
  1. package/README.md +31 -41
  2. package/lib/bootstrap.js +262 -88
  3. package/package.json +2 -2
  4. package/skill/{msdevflow → msd}/README.md +38 -33
  5. package/skill/{msdevflow → msd}/SKILL.md +26 -35
  6. package/skill/{msdevflow → msd}/references/ci-and-review.md +1 -1
  7. package/skill/{msdevflow → msd}/references/create-issue.md +1 -1
  8. package/skill/{msdevflow → msd}/references/design-and-development.md +1 -1
  9. package/skill/{msdevflow → msd}/references/pr-and-ci.md +1 -1
  10. package/skill/{msdevflow → msd}/references/recovery.md +1 -1
  11. package/skill/{msdevflow → msd}/references/review-and-merge.md +2 -2
  12. package/skill/{msdevflow → msd}/references/setup-and-issue.md +2 -2
  13. package/skill/msd-ci/SKILL.md +15 -0
  14. package/skill/msd-code-review/SKILL.md +15 -0
  15. package/skill/msd-create-issue/SKILL.md +15 -0
  16. package/skill/msd-develop/SKILL.md +15 -0
  17. package/skill/msd-discover/SKILL.md +15 -0
  18. package/skill/msd-feedback/SKILL.md +15 -0
  19. package/skill/msd-issue/SKILL.md +15 -0
  20. package/skill/msd-merge/SKILL.md +15 -0
  21. package/skill/msd-openlibing-auth/SKILL.md +15 -0
  22. package/skill/msd-pr/SKILL.md +15 -0
  23. /package/skill/{msdevflow → msd}/references/code-review.md +0 -0
  24. /package/skill/{msdevflow → msd}/references/command-capabilities.md +0 -0
  25. /package/skill/{msdevflow → msd}/references/openlibing-ci.md +0 -0
  26. /package/skill/{msdevflow → msd}/references/state-and-safety.md +0 -0
  27. /package/skill/{msdevflow → msd}/scripts/openlibing_ci.py +0 -0
  28. /package/skill/{msdevflow → msd}/scripts/requirements.txt +0 -0
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # msdevflow
2
2
 
3
- `msdevflow` 是一个用于 GitCode Agent Skill,可以把已授权的 Issue 安全推进到代码实现、普通 PR、CI、检视意见闭环和最终合入,也可以通过显式 `action` 只执行其中一个能力。正式支持 Claude Code、Codex 和 OpenCode;Trae 的 Skills 安装与兼容机制尚未完成可靠验证,因此当前不宣称支持。
3
+ `msdevflow` npm 包提供一套 GitCode Agent Skills:`msd` 核心可以把已授权的 Issue 安全推进到代码实现、普通 PR、CI、检视意见闭环和最终合入,十个 `msd-<action>` 薄路由入口用于在输入阶段发现并运行单项能力。正式支持 Claude Code、Codex 和 OpenCode;Trae 的 Skills 安装与兼容机制尚未完成可靠验证,因此当前不宣称支持。
4
4
 
5
5
  ## 安装
6
6
 
@@ -29,7 +29,7 @@ npx msdevflow@latest setup
29
29
 
30
30
  `setup` 默认检测 PATH 中的 Claude Code、Codex 和 OpenCode,展示完整计划并在确认后:
31
31
 
32
- 1. 把同一份 `msdevflow` skill 原子安装或更新到所需目标;
32
+ 1. 把一个 `msd` 核心和十个 `msd-<action>` 路由器作为整套事务原子安装或更新到所需目标;
33
33
  2. 安装或升级官方 `@gitcode-cli/cli@latest`;
34
34
  3. 安装受审的 Python Playwright 依赖;
35
35
  4. 验收 Issue、PR、结构化评论、行内评论、JSON、显式仓库和正文文件等 CLI 能力;
@@ -47,15 +47,17 @@ npx msdevflow setup --dry-run --targets all
47
47
  安装目录映射:
48
48
 
49
49
  ```text
50
- Claude Code -> ~/.claude/skills/msdevflow
51
- Codex -> ~/.agents/skills/msdevflow
52
- 仅 OpenCode -> ~/.agents/skills/msdevflow
53
- OpenCode + Claude Code -> 复用 ~/.claude/skills/msdevflow
54
- OpenCode + Codex -> 复用 ~/.agents/skills/msdevflow
55
- Claude Code + Codex -> 两个受管副本
56
- 三者同时安装 -> 两个受管副本,并提示 OpenCode 可从两处发现同名 skill
50
+ Claude Code -> ~/.claude/skills/{msd,msd-*}
51
+ Codex -> ~/.agents/skills/{msd,msd-*}
52
+ 仅 OpenCode -> ~/.agents/skills/{msd,msd-*}
53
+ OpenCode + Claude Code -> 复用 Claude 目标
54
+ OpenCode + Codex -> 复用 Agent Skills 目标
55
+ Claude Code + Codex -> 两套受管副本
56
+ 三者同时安装 -> 两套受管副本,并提示 OpenCode 双路径发现
57
57
  ```
58
58
 
59
+ 每个物理目标都包含完整套件,薄路由器不复制核心业务规则。已有 entry 只有在 manifest 精确匹配自身名称时才允许更新;由旧版包管理的 `msdevflow` 目录会在新套件全部验证后安全迁移,来源不明的目录、文件或符号链接会阻断安装。
60
+
59
61
  自定义目录:
60
62
 
61
63
  ```bash
@@ -65,29 +67,15 @@ npx msdevflow setup --agents-skills-dir "<shared-agent-skills-directory>"
65
67
 
66
68
  `--skills-dir` 未配合 `--targets` 使用时保留旧语义,只安装 Claude Code 目标。没有检测到客户端时,交互运行会要求选择目标;非交互运行必须提供 `--targets`。安装完成后重启或重新加载对应客户端。如果机器已有 Python 版本的 `gitcode`,setup 会保留它,并为 npm CLI 创建 `gitcode-npm` 命令;否则使用 `gitcode`。
67
69
 
68
- ## 运行与 action 菜单
69
-
70
- 从目标仓库目录启动客户端并提交 `msdevflow`:
71
-
72
- - Claude Code:输入并提交 `/msdevflow`;
73
- - Codex:使用 `$msdevflow` 或从 `/skills` 选择后提交;
74
- - OpenCode:打开 `/skills`,选择 `msdevflow`,再提交插入的 `/msdevflow`。`@` 用于文件、reference 或 agent,不用于选择 Skill。
70
+ ## 运行与 action 补全
75
71
 
76
- 没有字面量 `action=<name>` 时,Agent 会先通过宿主原生单选工具显示分级菜单,选择前不会探测仓库或访问 GitCode
77
-
78
- ```text
79
- 选择运行方式
80
- ├─ 完整端到端流程
81
- ├─ 作者工作流
82
- │ ├─ Issue 管理 -> discover | create-issue | issue
83
- │ ├─ 开发与交付 -> develop | pr | ci
84
- │ └─ PR 后续 -> feedback | merge
85
- └─ 独立工具 -> openlibing-auth | code-review
86
- ```
72
+ 从目标仓库目录启动客户端。直接调用核心 `msd` 会运行完整作者 E2E
87
73
 
88
- Claude Code 使用 `AskUserQuestion`,Codex 使用 `request_user_input`,OpenCode 使用 `question`。每次只显示当前层且不超过 3 项;工具不可用或处于非交互模式时,Agent 只输出当前层编号选项并等待回复,不自行选择默认项。
74
+ - Claude Code:输入并提交 `/msd`;
75
+ - Codex:使用 `$msd` 或从 `/skills` 选择;
76
+ - OpenCode:打开 `/skills`,选择 `msd`,再提交插入的 `/msd`。`@` 用于文件、reference 或 agent,不用于选择 Skill。
89
77
 
90
- 选择“完整端到端流程”后,才会运行:
78
+ 核心流程为:
91
79
 
92
80
  ```text
93
81
  Issue 发现/核验
@@ -102,9 +90,9 @@ Issue 发现/核验
102
90
  -> 远端回读 PR 已 merged
103
91
  ```
104
92
 
105
- 调用正文可预先提供 Issue/PR URL、仓库路径、canonical、source 和模式;菜单选择后这些参数会保留。即使正文写明“运行完整 E2E”或某个具体任务,只要没有字面量 `action=<name>`,仍从顶层菜单开始。
93
+ 调用正文可提供 Issue/PR URL、仓库路径、canonical、source 和模式。核心 `msd` 不显示运行时 Question 菜单。
106
94
 
107
- 这是可暂停、可恢复的流程。外部检视或审批有新进展后,可再次提交 `/msdevflow` 和 PR 信息,并在菜单中选择“完整端到端流程”:
95
+ 这是可暂停、可恢复的流程。外部检视或审批有新进展后,可再次提交 `/msd` 和 PR 信息:
108
96
 
109
97
  ```text
110
98
  恢复 https://gitcode.com/<canonical-owner>/<repo>/pulls/<number> 的完整作者 E2E。
@@ -116,7 +104,7 @@ source:<your-account>/<repo>
116
104
 
117
105
  ## 独立 action
118
106
 
119
- 显式提供 `action=<name>` 时,只运行该 action,完成后立即停止;前置条件不足时不会隐式补跑上游流程。
107
+ Claude Code/OpenCode 输入 `/msd-`、Codex 输入 `$msd-` 即可筛选十个独立入口。每个入口只运行对应 action,完成后立即停止;前置条件不足时不会隐式补跑上游流程。`/msd action=<name>` `$msd action=<name>` 仍是兼容调用,但参数本身不提供跨客户端枚举补全。
120
108
 
121
109
  | action | 用途 | 完成状态或结果 |
122
110
  |---|---|---|
@@ -134,19 +122,19 @@ source:<your-account>/<repo>
134
122
  示例:
135
123
 
136
124
  ```text
137
- /msdevflow action=create-issue
125
+ /msd-create-issue
138
126
  在 Ascend/example 提一个 bug:升级后首次启动失败……
139
127
  使用 guided 模式,确认完整预览后再创建。
140
128
  ```
141
129
 
142
130
  ```text
143
- /msdevflow action=ci
131
+ /msd-ci
144
132
  PR:https://gitcode.com/Ascend/example/pulls/456
145
133
  本地仓库:D:\work\example
146
134
  ```
147
135
 
148
136
  ```text
149
- /msdevflow action=code-review
137
+ /msd-code-review
150
138
  PR:https://gitcode.com/Ascend/example/pulls/789
151
139
  ```
152
140
 
@@ -188,17 +176,19 @@ Agent 写入的 PR/Issue 正文、评论和 discussion 回复末尾会附加:
188
176
 
189
177
  ## 常见阻塞
190
178
 
191
- ### 客户端找不到 `msdevflow`
179
+ ### 客户端找不到 `msd` 或 `msd-<action>`
192
180
 
193
- 按目标确认至少一个受支持的 manifest 存在,然后重启或重新加载客户端:
181
+ 按目标确认核心和相应路由器的 manifest 都存在,然后重启或重新加载客户端:
194
182
 
195
183
  ```text
196
- Claude Code: ~/.claude/skills/msdevflow/SKILL.md
197
- Codex: ~/.agents/skills/msdevflow/SKILL.md
184
+ Claude Code: ~/.claude/skills/msd/SKILL.md
185
+ ~/.claude/skills/msd-<action>/SKILL.md
186
+ Codex: ~/.agents/skills/msd/SKILL.md
187
+ ~/.agents/skills/msd-<action>/SKILL.md
198
188
  OpenCode: 上述任一路径(按 setup 计划)
199
189
  ```
200
190
 
201
- 可运行 `npx msdevflow setup --dry-run --targets <clients>` 检查目标映射。
191
+ Claude Code/OpenCode 可输入 `/msd-` 筛选 action;Codex 使用 `$msd-`。可运行 `npx msdevflow setup --dry-run --targets <clients>` 检查目标映射。
202
192
 
203
193
  ### `blocked: bootstrap-required`
204
194
 
@@ -229,4 +219,4 @@ npx msdevflow setup
229
219
 
230
220
  ## 详细文档
231
221
 
232
- 完整 action、恢复、模板、CI、review、UTF-8 和安全契约见 [`skill/msdevflow/README.md`](skill/msdevflow/README.md)。
222
+ 完整 action、恢复、模板、CI、review、UTF-8 和安全契约见 [`skill/msd/README.md`](skill/msd/README.md)。
package/lib/bootstrap.js CHANGED
@@ -24,7 +24,25 @@ import { fileURLToPath } from "node:url";
24
24
  const REGISTRY = "https://registry.npmjs.org";
25
25
  const GITCODE_PACKAGE = "@gitcode-cli/cli@latest";
26
26
  const PACKAGE_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
27
- const BUNDLED_SKILL_DIR = path.join(PACKAGE_ROOT, "skill", "msdevflow");
27
+ const BUNDLED_SKILLS_DIR = path.join(PACKAGE_ROOT, "skill");
28
+ const CORE_SKILL_NAME = "msd";
29
+ const LEGACY_SKILL_NAME = "msdevflow";
30
+ export const ACTIONS = [
31
+ "discover",
32
+ "create-issue",
33
+ "issue",
34
+ "develop",
35
+ "pr",
36
+ "ci",
37
+ "openlibing-auth",
38
+ "feedback",
39
+ "code-review",
40
+ "merge",
41
+ ];
42
+ export const MANAGED_SKILL_NAMES = [
43
+ CORE_SKILL_NAME,
44
+ ...ACTIONS.map((action) => `${CORE_SKILL_NAME}-${action}`),
45
+ ];
28
46
  const SUPPORTED_CLIENTS = ["claude", "codex", "opencode"];
29
47
  const REQUIRED_SCHEMAS = {
30
48
  "auth login": ["web"],
@@ -70,8 +88,8 @@ client is detected, interactive setup asks which clients to install; non-interac
70
88
  setup requires --targets. OpenCode reuses a Claude or shared Agent Skills target
71
89
  instead of creating a third copy.
72
90
 
73
- The setup installs or updates the bundled msdevflow skill, installs or upgrades
74
- the official GitCode npm CLI, and installs all reviewed Python runtime
91
+ The setup installs or updates the bundled msd core and msd-<action> skills,
92
+ installs or upgrades the official GitCode npm CLI, and installs all reviewed Python runtime
75
93
  dependencies. It never downloads or launches Chromium. If GitCode is not
76
94
  authenticated, it starts the CLI's official browser login; setup never reads or
77
95
  prints a token.`;
@@ -167,29 +185,33 @@ function defaultAgentsSkillsDir(options, environment, platform) {
167
185
  || path.join(environmentHome(environment, platform), ".agents", "skills");
168
186
  }
169
187
 
170
- function createSkillLayout(kind, clients, skillsDir, bundledSkillDir) {
188
+ function createSkillLayout(kind, clients, skillsDir, bundledSkillsDir) {
171
189
  const resolvedSkillsDir = path.resolve(skillsDir);
172
- const workflowDir = path.join(resolvedSkillsDir, "msdevflow");
173
- const bundledWorkflowDir = path.resolve(bundledSkillDir);
190
+ const resolvedBundledSkillsDir = path.resolve(bundledSkillsDir);
191
+ const coreDir = path.join(resolvedSkillsDir, CORE_SKILL_NAME);
192
+ const bundledCoreDir = path.join(resolvedBundledSkillsDir, CORE_SKILL_NAME);
174
193
  return {
175
194
  kind,
176
195
  clients,
177
196
  skillsDir: resolvedSkillsDir,
178
- workflowDir,
179
- workflowManifest: path.join(workflowDir, "SKILL.md"),
180
- pythonRequirements: path.join(workflowDir, "scripts", "requirements.txt"),
181
- bundledSkillDir: bundledWorkflowDir,
182
- bundledManifest: path.join(bundledWorkflowDir, "SKILL.md"),
183
- bundledPythonRequirements: path.join(bundledWorkflowDir, "scripts", "requirements.txt"),
197
+ coreDir,
198
+ coreManifest: path.join(coreDir, "SKILL.md"),
199
+ pythonRequirements: path.join(coreDir, "scripts", "requirements.txt"),
200
+ legacyDir: path.join(resolvedSkillsDir, LEGACY_SKILL_NAME),
201
+ legacyManifest: path.join(resolvedSkillsDir, LEGACY_SKILL_NAME, "SKILL.md"),
202
+ bundledSkillsDir: resolvedBundledSkillsDir,
203
+ bundledCoreDir,
204
+ bundledCoreManifest: path.join(bundledCoreDir, "SKILL.md"),
205
+ bundledPythonRequirements: path.join(bundledCoreDir, "scripts", "requirements.txt"),
184
206
  };
185
207
  }
186
208
 
187
- export function resolveLayout(options, environment = process.env, bundledSkillDir = BUNDLED_SKILL_DIR) {
209
+ export function resolveLayout(options, environment = process.env, bundledSkillsDir = BUNDLED_SKILLS_DIR) {
188
210
  return createSkillLayout(
189
211
  "claude",
190
212
  ["claude"],
191
213
  defaultClaudeSkillsDir(options, environment, process.platform),
192
- bundledSkillDir,
214
+ bundledSkillsDir,
193
215
  );
194
216
  }
195
217
 
@@ -197,7 +219,7 @@ export function resolveLayouts(
197
219
  options,
198
220
  clients,
199
221
  environment = process.env,
200
- bundledSkillDir = BUNDLED_SKILL_DIR,
222
+ bundledSkillsDir = BUNDLED_SKILLS_DIR,
201
223
  platform = process.platform,
202
224
  ) {
203
225
  const layouts = [];
@@ -207,7 +229,7 @@ export function resolveLayouts(
207
229
  "claude",
208
230
  openCodeUsesClaude ? ["claude", "opencode"] : ["claude"],
209
231
  defaultClaudeSkillsDir(options, environment, platform),
210
- bundledSkillDir,
232
+ bundledSkillsDir,
211
233
  ));
212
234
  }
213
235
  if (clients.includes("codex") || (clients.includes("opencode") && !openCodeUsesClaude)) {
@@ -219,12 +241,12 @@ export function resolveLayouts(
219
241
  "agents",
220
242
  sharedClients,
221
243
  defaultAgentsSkillsDir(options, environment, platform),
222
- bundledSkillDir,
244
+ bundledSkillsDir,
223
245
  ));
224
246
  }
225
247
  const unique = new Map();
226
248
  for (const layout of layouts) {
227
- const key = normalizedPath(layout.workflowDir, platform);
249
+ const key = normalizedPath(layout.skillsDir, platform);
228
250
  const existing = unique.get(key);
229
251
  if (existing) {
230
252
  existing.clients = [...new Set([...existing.clients, ...layout.clients])];
@@ -440,7 +462,7 @@ function requireFile(file, description) {
440
462
  verifyFile(file, `${description} not found: ${file}. Reinstall the msdevflow npm package.`);
441
463
  }
442
464
 
443
- function skillManifestIsOwned(file) {
465
+ function skillManifestIsOwned(file, expectedName) {
444
466
  try {
445
467
  const metadata = lstatSync(file);
446
468
  if (metadata.isSymbolicLink() || !metadata.isFile()) {
@@ -451,7 +473,7 @@ function skillManifestIsOwned(file) {
451
473
  return false;
452
474
  }
453
475
  const names = [...frontmatter[1].matchAll(/^name:\s*([^\s#]+)\s*$/gm)];
454
- return names.length === 1 && names[0][1] === "msdevflow";
476
+ return names.length === 1 && names[0][1] === expectedName;
455
477
  } catch (error) {
456
478
  if (error?.code === "ENOENT") {
457
479
  return false;
@@ -491,26 +513,25 @@ function skillDigest(root) {
491
513
  return digest.digest("hex");
492
514
  }
493
515
 
494
- function skillInstallDetails(layout) {
495
- requireFile(layout.bundledManifest, "bundled msdevflow skill manifest");
496
- requireFile(layout.bundledPythonRequirements, "bundled workflow Python requirements file");
497
- if (!skillManifestIsOwned(layout.bundledManifest)) {
498
- throw new BootstrapError("Bundled skill manifest does not identify msdevflow.", 3);
516
+ function installedSkillDetails(source, target, name) {
517
+ const sourceManifest = path.join(source, "SKILL.md");
518
+ requireFile(sourceManifest, `bundled ${name} skill manifest`);
519
+ if (!skillManifestIsOwned(sourceManifest, name)) {
520
+ throw new BootstrapError(`Bundled skill manifest does not identify ${name}.`, 3);
499
521
  }
500
- validatePythonRequirements(layout.bundledPythonRequirements);
501
- const bundledDigest = skillDigest(layout.bundledSkillDir);
522
+ const bundledDigest = skillDigest(source);
502
523
  let status = "absent";
503
524
  let existingDigest = null;
504
525
  try {
505
- const metadata = lstatSync(layout.workflowDir);
526
+ const metadata = lstatSync(target);
506
527
  if (metadata.isSymbolicLink() || !metadata.isDirectory()
507
- || !skillManifestIsOwned(layout.workflowManifest)) {
528
+ || !skillManifestIsOwned(path.join(target, "SKILL.md"), name)) {
508
529
  throw new BootstrapError(
509
- `Refusing to overwrite a skills entry not owned by msdevflow: ${layout.workflowDir}`,
530
+ `Refusing to overwrite a skills entry not owned by ${name}: ${target}`,
510
531
  3,
511
532
  );
512
533
  }
513
- existingDigest = skillDigest(layout.workflowDir);
534
+ existingDigest = skillDigest(target);
514
535
  status = existingDigest === bundledDigest ? "current" : "update";
515
536
  } catch (error) {
516
537
  if (error?.code !== "ENOENT") {
@@ -518,70 +539,211 @@ function skillInstallDetails(layout) {
518
539
  }
519
540
  }
520
541
  return {
521
- source: layout.bundledSkillDir,
522
- target: layout.workflowDir,
542
+ name,
543
+ source,
544
+ target,
523
545
  status,
524
546
  bundledDigest,
525
547
  existingDigest,
526
548
  };
527
549
  }
528
550
 
529
- function installBundledSkill(details) {
530
- const parent = path.dirname(details.target);
531
- mkdirSync(parent, { recursive: true });
532
- const current = skillInstallDetails({
533
- bundledSkillDir: details.source,
534
- bundledManifest: path.join(details.source, "SKILL.md"),
535
- bundledPythonRequirements: path.join(details.source, "scripts", "requirements.txt"),
536
- workflowDir: details.target,
537
- workflowManifest: path.join(details.target, "SKILL.md"),
538
- });
539
- if (current.status !== details.status || current.existingDigest !== details.existingDigest) {
540
- throw new BootstrapError("msdevflow skill target changed after confirmation; refusing to overwrite it.", 3);
551
+ function legacySkillDetails(layout) {
552
+ try {
553
+ const metadata = lstatSync(layout.legacyDir);
554
+ if (metadata.isSymbolicLink() || !metadata.isDirectory()
555
+ || !skillManifestIsOwned(layout.legacyManifest, LEGACY_SKILL_NAME)) {
556
+ throw new BootstrapError(
557
+ `Refusing to migrate a legacy skills entry not owned by ${LEGACY_SKILL_NAME}: ${layout.legacyDir}`,
558
+ 3,
559
+ );
560
+ }
561
+ return {
562
+ target: layout.legacyDir,
563
+ status: "migrate",
564
+ existingDigest: skillDigest(layout.legacyDir),
565
+ };
566
+ } catch (error) {
567
+ if (error?.code === "ENOENT") {
568
+ return {
569
+ target: layout.legacyDir,
570
+ status: "absent",
571
+ existingDigest: null,
572
+ };
573
+ }
574
+ throw error;
575
+ }
576
+ }
577
+
578
+ function skillInstallDetails(layout) {
579
+ requireFile(layout.bundledPythonRequirements, "bundled workflow Python requirements file");
580
+ validatePythonRequirements(layout.bundledPythonRequirements);
581
+ const entries = MANAGED_SKILL_NAMES.map((name) => installedSkillDetails(
582
+ path.join(layout.bundledSkillsDir, name),
583
+ path.join(layout.skillsDir, name),
584
+ name,
585
+ ));
586
+ return {
587
+ source: layout.bundledSkillsDir,
588
+ target: layout.skillsDir,
589
+ entries,
590
+ legacy: legacySkillDetails(layout),
591
+ };
592
+ }
593
+
594
+ function assertSkillInstallUnchanged(details) {
595
+ const layout = {
596
+ skillsDir: details.target,
597
+ bundledSkillsDir: details.source,
598
+ bundledPythonRequirements: path.join(
599
+ details.source,
600
+ CORE_SKILL_NAME,
601
+ "scripts",
602
+ "requirements.txt",
603
+ ),
604
+ legacyDir: path.join(details.target, LEGACY_SKILL_NAME),
605
+ legacyManifest: path.join(details.target, LEGACY_SKILL_NAME, "SKILL.md"),
606
+ };
607
+ const current = skillInstallDetails(layout);
608
+ for (let index = 0; index < details.entries.length; index += 1) {
609
+ const expected = details.entries[index];
610
+ const actual = current.entries[index];
611
+ if (actual.name !== expected.name || actual.status !== expected.status
612
+ || actual.existingDigest !== expected.existingDigest
613
+ || actual.bundledDigest !== expected.bundledDigest) {
614
+ throw new BootstrapError(
615
+ `Skill target changed after confirmation; refusing to overwrite it: ${expected.target}`,
616
+ 3,
617
+ );
618
+ }
541
619
  }
542
- if (current.status === "current") {
543
- return "current";
620
+ if (current.legacy.status !== details.legacy.status
621
+ || current.legacy.existingDigest !== details.legacy.existingDigest) {
622
+ throw new BootstrapError(
623
+ `Legacy skill target changed after confirmation; refusing to migrate it: ${details.legacy.target}`,
624
+ 3,
625
+ );
544
626
  }
545
- const staging = path.join(parent, `.msdevflow-${randomUUID()}.tmp`);
546
- const backup = path.join(parent, `.msdevflow-${randomUUID()}.backup`);
547
- let movedExisting = false;
627
+ }
628
+
629
+ function installedSuiteResult(details) {
630
+ const entries = details.entries.map((entry) => ({
631
+ name: entry.name,
632
+ status: entry.status === "current"
633
+ ? "current"
634
+ : entry.status === "absent" ? "installed" : "updated",
635
+ target: entry.target,
636
+ }));
637
+ let status = "current";
638
+ if (details.legacy.status === "migrate") {
639
+ status = "migrated";
640
+ } else if (entries.some((entry) => entry.status === "updated")) {
641
+ status = "updated";
642
+ } else if (entries.some((entry) => entry.status === "installed")) {
643
+ status = "installed";
644
+ }
645
+ return { status, entries, legacy: details.legacy.status };
646
+ }
647
+
648
+ function suiteTransactionPath(details, name, extension) {
649
+ const skillsRootName = path.basename(details.target) || "skills";
650
+ return path.join(
651
+ path.dirname(details.target),
652
+ `.${skillsRootName}-msdevflow-${name}-${randomUUID()}.${extension}`,
653
+ );
654
+ }
655
+
656
+ function installBundledSkillSuites(suites) {
657
+ for (const details of suites) {
658
+ mkdirSync(details.target, { recursive: true });
659
+ assertSkillInstallUnchanged(details);
660
+ }
661
+ const staged = [];
662
+ const switched = [];
663
+ const migrated = [];
548
664
  try {
549
- cpSync(details.source, staging, { recursive: true, errorOnExist: true });
550
- if (skillDigest(staging) !== details.bundledDigest) {
551
- throw new BootstrapError("Bundled skill verification failed after staging.", 3);
665
+ for (const details of suites) {
666
+ for (const entry of details.entries.filter((item) => item.status !== "current")) {
667
+ const staging = suiteTransactionPath(details, entry.name, "tmp");
668
+ cpSync(entry.source, staging, { recursive: true, errorOnExist: true });
669
+ if (skillDigest(staging) !== entry.bundledDigest) {
670
+ throw new BootstrapError(`Bundled ${entry.name} verification failed after staging.`, 3);
671
+ }
672
+ staged.push({ details, entry, staging });
673
+ }
552
674
  }
553
- if (current.status === "update") {
554
- renameSync(details.target, backup);
555
- movedExisting = true;
675
+ for (const details of suites) {
676
+ assertSkillInstallUnchanged(details);
556
677
  }
557
- try {
558
- renameSync(staging, details.target);
559
- } catch (error) {
560
- if (movedExisting) {
561
- renameSync(backup, details.target);
562
- movedExisting = false;
678
+ for (const item of staged) {
679
+ const backup = suiteTransactionPath(item.details, item.entry.name, "backup");
680
+ if (item.entry.status === "update") {
681
+ renameSync(item.entry.target, backup);
563
682
  }
564
- throw error;
683
+ try {
684
+ renameSync(item.staging, item.entry.target);
685
+ } catch (error) {
686
+ if (item.entry.status === "update") {
687
+ renameSync(backup, item.entry.target);
688
+ }
689
+ throw error;
690
+ }
691
+ switched.push({ ...item, backup: item.entry.status === "update" ? backup : null });
565
692
  }
566
- if (movedExisting) {
567
- movedExisting = false;
693
+ for (const details of suites.filter((item) => item.legacy.status === "migrate")) {
694
+ const backup = suiteTransactionPath(details, LEGACY_SKILL_NAME, "backup");
695
+ renameSync(details.legacy.target, backup);
696
+ migrated.push({ details, backup });
697
+ }
698
+ } catch (error) {
699
+ const rollbackFailures = [];
700
+ for (const item of migrated.reverse()) {
568
701
  try {
569
- rmSync(backup, { recursive: true, force: true });
570
- } catch {
571
- // The verified target is already live; stale backup cleanup must not invalidate it.
702
+ renameSync(item.backup, item.details.legacy.target);
703
+ } catch (rollbackError) {
704
+ rollbackFailures.push(rollbackError);
572
705
  }
573
706
  }
574
- return current.status === "absent" ? "installed" : "updated";
707
+ for (const item of switched.reverse()) {
708
+ try {
709
+ rmSync(item.entry.target, { recursive: true, force: true });
710
+ if (item.backup !== null) {
711
+ renameSync(item.backup, item.entry.target);
712
+ }
713
+ } catch (rollbackError) {
714
+ rollbackFailures.push(rollbackError);
715
+ }
716
+ }
717
+ if (rollbackFailures.length) {
718
+ throw new BootstrapError(
719
+ `Skill suite installation failed and rollback was incomplete: ${error.message}; rollback: ${rollbackFailures.map((failure) => failure.message).join("; ")}`,
720
+ 3,
721
+ );
722
+ }
723
+ throw error;
575
724
  } finally {
576
- rmSync(staging, { recursive: true, force: true });
577
- if (movedExisting) {
725
+ for (const item of staged) {
726
+ rmSync(item.staging, { recursive: true, force: true });
727
+ }
728
+ }
729
+
730
+ for (const item of switched) {
731
+ if (item.backup !== null) {
578
732
  try {
579
- renameSync(backup, details.target);
733
+ rmSync(item.backup, { recursive: true, force: true });
580
734
  } catch {
581
- throw new BootstrapError(`Failed to restore previous msdevflow skill from ${backup}.`, 3);
735
+ // The verified replacement is live; stale backup cleanup can be retried manually.
582
736
  }
583
737
  }
584
738
  }
739
+ for (const item of migrated) {
740
+ try {
741
+ rmSync(item.backup, { recursive: true, force: true });
742
+ } catch {
743
+ // The legacy entry is no longer discoverable; stale backup cleanup is non-blocking.
744
+ }
745
+ }
746
+ return suites.map(installedSuiteResult);
585
747
  }
586
748
 
587
749
  function validatePythonRequirements(file) {
@@ -628,7 +790,7 @@ async function selectClientTargets(input, output, promptOutput = output) {
628
790
  promptOutput.write("No supported agent client was detected. Available targets: claude, codex, opencode, all.\n");
629
791
  const terminal = createInterface({ input, output: promptOutput });
630
792
  try {
631
- const answer = await terminal.question("Install msdevflow for: ");
793
+ const answer = await terminal.question("Install the msd skill suite for: ");
632
794
  return parseTargets(answer);
633
795
  } finally {
634
796
  terminal.close();
@@ -653,7 +815,7 @@ async function resolveClientTargets(options, run, platform, selectClients) {
653
815
  function clientTargetWarnings(clients, layouts) {
654
816
  if (clients.includes("opencode") && layouts.length > 1) {
655
817
  return [
656
- "OpenCode can discover msdevflow from both installed paths; keep both copies managed by this setup to prevent version drift.",
818
+ "OpenCode can discover the msd skill suite from both installed paths; keep both copies managed by this setup to prevent version drift.",
657
819
  ];
658
820
  }
659
821
  return [];
@@ -951,11 +1113,16 @@ function safeAuthStatus(output) {
951
1113
  function printPlan(plan, write) {
952
1114
  write("Setup plan (no changes made yet):");
953
1115
  write(` Client targets: ${plan.clientTargets.clients.join(", ")} (${plan.clientTargets.source})`);
954
- write(` Bundled skill: ${plan.skillInstalls[0].details.source}`);
1116
+ write(` Bundled skill suite: ${plan.skillInstalls[0].details.source}`);
955
1117
  for (const { layout, details } of plan.skillInstalls) {
956
- write(` Skill target: ${details.target}`);
1118
+ write(` Skill root: ${details.target}`);
957
1119
  write(` Clients: ${layout.clients.join(", ")}`);
958
- write(` Action: ${details.status}`);
1120
+ for (const entry of details.entries) {
1121
+ write(` ${entry.name}: ${entry.status}`);
1122
+ }
1123
+ if (details.legacy.status === "migrate") {
1124
+ write(` ${LEGACY_SKILL_NAME}: migrate after suite verification`);
1125
+ }
959
1126
  }
960
1127
  for (const warning of plan.clientTargets.warnings) {
961
1128
  write(` Warning: ${warning}`);
@@ -1079,7 +1246,8 @@ function textResult(result, write) {
1079
1246
  write("Setup completed:");
1080
1247
  write(` Client targets: ${result.clients.join(", ")}`);
1081
1248
  for (const skill of result.skills) {
1082
- write(` Skill: ${skill.status} at ${skill.target} (${skill.clients.join(", ")})`);
1249
+ write(` Skill suite: ${skill.status} at ${skill.target} (${skill.clients.join(", ")})`);
1250
+ write(` Entries: ${skill.entries.map((entry) => entry.name).join(", ")}`);
1083
1251
  }
1084
1252
  for (const warning of result.warnings) {
1085
1253
  write(` Warning: ${warning}`);
@@ -1124,7 +1292,10 @@ export async function runSetup(options, dependencies = {}) {
1124
1292
  options,
1125
1293
  targetSelection.clients,
1126
1294
  environment,
1127
- dependencies.bundledSkillDir,
1295
+ dependencies.bundledSkillsDir
1296
+ || (dependencies.bundledSkillDir
1297
+ ? path.dirname(dependencies.bundledSkillDir)
1298
+ : BUNDLED_SKILLS_DIR),
1128
1299
  platform,
1129
1300
  );
1130
1301
  const skillInstalls = layouts.map((layout) => ({
@@ -1220,14 +1391,17 @@ export async function runSetup(options, dependencies = {}) {
1220
1391
  progress,
1221
1392
  options.json,
1222
1393
  );
1223
- const skills = await progress.run("Installing msdevflow skill targets", async () => (
1224
- skillInstalls.map(({ layout, details }) => ({
1225
- kind: layout.kind,
1226
- clients: layout.clients,
1227
- status: installBundledSkill(details),
1228
- target: layout.workflowDir,
1229
- }))
1230
- ));
1394
+ const skills = await progress.run("Installing msd skill suites", async () => {
1395
+ const installedSuites = installBundledSkillSuites(
1396
+ skillInstalls.map(({ details }) => details),
1397
+ );
1398
+ return installedSuites.map((installedSuite, index) => ({
1399
+ kind: skillInstalls[index].layout.kind,
1400
+ clients: skillInstalls[index].layout.clients,
1401
+ target: skillInstalls[index].layout.skillsDir,
1402
+ ...installedSuite,
1403
+ }));
1404
+ });
1231
1405
  const result = {
1232
1406
  state: "ready",
1233
1407
  git: gitVersion,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "msdevflow",
3
- "version": "0.7.4",
3
+ "version": "0.7.5",
4
4
  "description": "Install the msdevflow GitCode skill and its runtime dependencies",
5
5
  "type": "module",
6
6
  "bin": {
@@ -10,7 +10,7 @@
10
10
  "bin/",
11
11
  "lib/",
12
12
  "skill/",
13
- "!skill/msdevflow/scripts/test_openlibing_ci.py",
13
+ "!skill/**/scripts/test_openlibing_ci.py",
14
14
  "!skill/**/__pycache__/**",
15
15
  "!skill/**/*.pyc"
16
16
  ],
@@ -1,22 +1,25 @@
1
- # msdevflow
1
+ # msd
2
2
 
3
- 通用 GitCode Issue 到 PR 合入 workflow skill。它保留一个统一 skill:显式 `action=<name>` 直接执行单项能力;未提供 action 时先通过客户端原生选择菜单路由,再读取仓库或访问 GitCode
3
+ 通用 GitCode Issue 到 PR 合入 workflow Skill 套件。业务规则只存在于核心 `msd`;十个 `msd-<action>` 薄路由 Skill Claude Code、Codex 和 OpenCode 在输入阶段展示并补全可用 action
4
4
 
5
5
  ## 1. Action 模型
6
6
 
7
- action 调用的菜单为:
7
+ 输入 `/msd-`(Claude Code/OpenCode)或 `$msd-`(Codex)即可筛选:
8
8
 
9
9
  ```text
10
- 选择运行方式
11
- ├─ 完整端到端流程
12
- ├─ 作者工作流
13
- │ ├─ Issue 管理 -> discover | create-issue | issue
14
- │ ├─ 开发与交付 -> develop | pr | ci
15
- │ └─ PR 后续 -> feedback | merge
16
- └─ 独立工具 -> openlibing-auth | code-review
10
+ msd-discover
11
+ msd-create-issue
12
+ msd-issue
13
+ msd-develop
14
+ msd-pr
15
+ msd-ci
16
+ msd-openlibing-auth
17
+ msd-feedback
18
+ msd-code-review
19
+ msd-merge
17
20
  ```
18
21
 
19
- Claude Code 使用 `AskUserQuestion`,Codex 使用 `request_user_input`,OpenCode 使用 `question`。每次只显示当前层且不超过 3 项;没有可用选择工具时只输出当前层编号选项并等待回复。菜单选择前不探测仓库、不调用 GitCode、不读写远端,也不加载 action reference。选中叶子后等同于显式 action,且保留原调用正文中的 URL、路径、仓库和模式。
22
+ 每个薄路由只固定唯一 action、保留调用正文,并从相对路径 `../msd/SKILL.md` 加载同一 skills 根目录中的核心,不复制业务规则;核心 references 继续以 `../msd/` 为基准。直接调用核心 `msd` 会运行完整作者 E2E,不会在提交后弹出 Question 菜单;`/msd action=<name>`、`$msd action=<name>` 仍作为兼容调用,但参数本身没有跨客户端枚举下拉。
20
23
 
21
24
  支持:
22
25
 
@@ -42,7 +45,7 @@ Claude Code 使用 `AskUserQuestion`,Codex 使用 `request_user_input`,OpenC
42
45
 
43
46
  ## 2. 完整作者 E2E
44
47
 
45
- action 菜单选中“完整端到端流程”后,从环境、CLI 能力和仓库画像开始运行完整流程:
48
+ 直接调用核心 `msd` 且不提供 `action=` 时,从环境、CLI 能力和仓库画像开始运行完整流程:
46
49
 
47
50
  ```text
48
51
  discover -> issue -> develop -> pr -> ci
@@ -69,12 +72,12 @@ discover -> issue -> develop -> pr -> ci
69
72
 
70
73
  ## 4. 调用示例
71
74
 
72
- 以下示例使用 Claude Code 的 `/msdevflow` 形式。Codex 使用 `$msdevflow` 或从 `/skills` 选择;OpenCode 使用 `/skills` 选择 `msdevflow`,不要用 `@` 查找 Skill。没有 `action=` 时,提交后先出现分级菜单;显式 `action=<name>` 则不显示菜单,直接路由。无论客户端入口如何,正文中的 action 和其余任务参数保持相同。
75
+ 以下示例使用 Claude Code 的 `/msd` 形式。Codex 使用 `$msd`,OpenCode 可从 `/skills` 选择 `msd`;OpenCode `@` 不用于 Skill。单项能力优先使用各客户端输入补全中的 `msd-<action>`,正文中的任务参数保持不变。
73
76
 
74
- ### 通过菜单选择完整 E2E
77
+ ### 运行完整 E2E
75
78
 
76
79
  ```text
77
- /msdevflow
80
+ /msd
78
81
  处理 https://gitcode.com/Ascend/example/issues/123。
79
82
  本地仓库:D:\work\example
80
83
  canonical:Ascend/example
@@ -85,7 +88,7 @@ Fork:myname/example
85
88
  ### 只发现候选 Issue
86
89
 
87
90
  ```text
88
- /msdevflow action=discover
91
+ /msd-discover
89
92
  查询 Ascend/example 中分配给当前账号的开放 Issue,列出仍需处理的候选。
90
93
  ```
91
94
 
@@ -94,7 +97,7 @@ Fork:myname/example
94
97
  ### 只创建 Issue
95
98
 
96
99
  ```text
97
- /msdevflow action=create-issue
100
+ /msd-create-issue
98
101
  在 Ascend/example 提一个 bug:升级后首次启动失败,错误信息和环境如下……
99
102
  使用 guided 模式,先给我完整预览,确认后再创建。
100
103
  ```
@@ -106,7 +109,7 @@ Fork:myname/example
106
109
  ### 只接取和核验 Issue
107
110
 
108
111
  ```text
109
- /msdevflow action=issue
112
+ /msd-issue
110
113
  处理 https://gitcode.com/Ascend/example/issues/123。
111
114
  本地仓库:D:\work\example
112
115
  ```
@@ -116,7 +119,7 @@ Fork:myname/example
116
119
  ### 只开发和本地验证
117
120
 
118
121
  ```text
119
- /msdevflow action=develop
122
+ /msd-develop
120
123
  Issue:https://gitcode.com/Ascend/example/issues/123
121
124
  本地仓库:D:\work\example
122
125
  ```
@@ -126,7 +129,7 @@ Issue:https://gitcode.com/Ascend/example/issues/123
126
129
  ### 只创建 PR
127
130
 
128
131
  ```text
129
- /msdevflow action=pr
132
+ /msd-pr
130
133
  Issue:https://gitcode.com/Ascend/example/issues/123
131
134
  本地仓库:D:\work\example
132
135
  canonical:Ascend/example
@@ -138,7 +141,7 @@ source:myname/example
138
141
  ### 只处理 CI
139
142
 
140
143
  ```text
141
- /msdevflow action=ci
144
+ /msd-ci
142
145
  PR:https://gitcode.com/Ascend/example/pulls/456
143
146
  本地仓库:D:\work\example
144
147
  ```
@@ -148,7 +151,7 @@ CI 通过后立即停止,不处理 feedback 或 merge。识别为 openLiBing
148
151
  ### 只验证 openLiBing OAuth
149
152
 
150
153
  ```text
151
- /msdevflow action=openlibing-auth
154
+ /msd-openlibing-auth
152
155
  本地仓库:D:\work\example
153
156
  ```
154
157
 
@@ -159,7 +162,7 @@ CI 通过后立即停止,不处理 feedback 或 merge。识别为 openLiBing
159
162
  ### 只处理自己 PR 的意见
160
163
 
161
164
  ```text
162
- /msdevflow action=feedback
165
+ /msd-feedback
163
166
  PR:https://gitcode.com/Ascend/example/pulls/456
164
167
  本地仓库:D:\work\example
165
168
  ```
@@ -169,7 +172,7 @@ PR:https://gitcode.com/Ascend/example/pulls/456
169
172
  ### 检视他人的 PR
170
173
 
171
174
  ```text
172
- /msdevflow action=code-review
175
+ /msd-code-review
173
176
  PR:https://gitcode.com/Ascend/example/pulls/789
174
177
  ```
175
178
 
@@ -180,7 +183,7 @@ PR:https://gitcode.com/Ascend/example/pulls/789
180
183
  ### 只核验并合入
181
184
 
182
185
  ```text
183
- /msdevflow action=merge
186
+ /msd-merge
184
187
  PR:https://gitcode.com/Ascend/example/pulls/456
185
188
  ```
186
189
 
@@ -224,7 +227,7 @@ GitCode CLI 会打开官方页面让用户创建 Token,再在 CLI 自己的终
224
227
 
225
228
  ## 6. 安装
226
229
 
227
- npm 包同时携带 `msdevflow` skill setup 程序。首次安装:
230
+ npm `msdevflow` 同时携带 `msd` Skill 套件和 setup 程序。首次安装:
228
231
 
229
232
  ```bash
230
233
  npx msdevflow setup
@@ -240,7 +243,7 @@ npx msdevflow@latest setup
240
243
 
241
244
  `setup` 默认检测 PATH 中的 Claude Code、Codex 和 OpenCode,先展示客户端、物理 skill 目标、安装或更新状态、GitCode CLI 归属、registry、安装模式、Python 依赖命令和认证方式;用户确认后,在同一次运行中:
242
245
 
243
- 1. 从 npm 包内唯一源码 `skill/msdevflow` 原子安装或更新所需受管副本;
246
+ 1. 从 npm 包内的 `skill/msd` 核心和十个 `skill/msd-<action>` 路由器原子安装或更新整套入口;
244
247
  2. 安装或升级官方 GitCode npm CLI;
245
248
  3. 安装内置 `scripts/requirements.txt` 中的 Python Playwright 包;
246
249
  4. 验收 workflow 所需 schema/API;
@@ -249,15 +252,17 @@ npx msdevflow@latest setup
249
252
  客户端到物理目录的映射:
250
253
 
251
254
  ```text
252
- Claude Code -> ~/.claude/skills/msdevflow
253
- Codex -> ~/.agents/skills/msdevflow
254
- 仅 OpenCode -> ~/.agents/skills/msdevflow
255
+ Claude Code -> ~/.claude/skills/{msd,msd-*}
256
+ Codex -> ~/.agents/skills/{msd,msd-*}
257
+ 仅 OpenCode -> ~/.agents/skills/{msd,msd-*}
255
258
  OpenCode + Claude Code -> 复用 Claude 目标
256
259
  OpenCode + Codex -> 复用 Agent Skills 目标
257
- Claude Code + Codex -> 两个受管副本
258
- 三者同时安装 -> 两个受管副本,并提示 OpenCode 双路径发现
260
+ Claude Code + Codex -> 两套受管副本
261
+ 三者同时安装 -> 两套受管副本,并提示 OpenCode 双路径发现
259
262
  ```
260
263
 
264
+ 每个物理目标都包含一个 `msd` 核心和十个 `msd-<action>` 路由器;业务规则仍只有一份。
265
+
261
266
  显式选择客户端、只读预检或自定义目录:
262
267
 
263
268
  ```bash
@@ -277,7 +282,7 @@ npm 包尚未发布时,可从当前源码/发布目录运行等价入口:
277
282
  node ./msdevflow/bin/msdevflow.js setup
278
283
  ```
279
284
 
280
- `setup` 不下载或启动 Chromium。GitCode Token 只由 GitCode CLI 自己的终端提示接收并验证;setup 父进程不读取、输出或转存 Token,也不要求用户把 Token 传给 Agent。每个已有 skill 目标只有 manifest 明确标识为 `msdevflow` 时才允许更新,来源不明的目录、文件或符号链接会被拒绝覆盖。安装后重启或重新加载对应客户端。
285
+ `setup` 不下载或启动 Chromium。GitCode Token 只由 GitCode CLI 自己的终端提示接收并验证;setup 父进程不读取、输出或转存 Token,也不要求用户把 Token 传给 Agent。每个已有 `msd` `msd-<action>` entry 的 manifest 都必须精确匹配自身名称才允许更新;来源不明的目录、文件或符号链接会阻断整套安装。旧 `msdevflow` 目录只有在 manifest 精确证明由本包管理时,才会在新套件全部切换并验证后安全迁移;失败时回滚整套变更。安装后重启或重新加载对应客户端。
281
286
 
282
287
  ## 7. 仓库画像和 PR 模板
283
288
 
@@ -1,52 +1,43 @@
1
1
  ---
2
- name: msdevflow
2
+ name: msd
3
3
  description: >
4
- 通用 GitCode Issue 到 PR 合入工作流。无 action 调用时通过宿主原生选择菜单路由到完整作者流程或独立能力;也支持通过 action=discover、create-issue、issue、develop、pr、ci、openlibing-auth、feedback、code-review 或 merge 直接执行单个能力。适用于发现、新建或接取 GitCode Issue、开发并创建 PR、处理 CI、验证 openLiBing OAuth、处理自己 PR 的检视意见、检视他人 PR,以及在独立审批和显式确认后合入。仅适用于已授权的 GitCode 仓库。
4
+ 通用 GitCode Issue 到 PR 合入工作流核心。直接调用 msd 时运行完整作者端到端流程;也接受 action=discover、create-issue、issue、develop、pr、ci、openlibing-auth、feedback、code-review 或 merge 兼容参数。推荐通过独立的 msd-<action> Skill 在输入时发现并选择单项能力。适用于发现、新建或接取 GitCode Issue、开发并创建 PR、处理 CI、验证 openLiBing OAuth、处理自己 PR 的检视意见、检视他人 PR,以及在独立审批和显式确认后合入。仅适用于已授权的 GitCode 仓库。
5
5
  compatibility: Requires Git, Node.js >=18, Python >=3.10, GitCode access, and the setup-installed GitCode CLI. Supports Claude Code, Codex, and OpenCode.
6
6
  metadata:
7
- version: 2.1.0
7
+ version: 3.0.0
8
8
  source: msdevflow
9
+ role: core
9
10
  ---
10
11
 
11
- # msdevflow:GitCode Issue 到 PR 合入
12
+ # msd:GitCode Issue 到 PR 合入
12
13
 
13
- 把 GitCode 工作拆成可显式调用的 action;无 action 调用先通过选择菜单路由到完整作者 E2E 或独立能力。选定流程后再探测仓库规范和 CLI 能力,不硬编码组织、默认分支、CI、分支命名、合并方式或机器人协议。
14
+ 把 GitCode 工作拆成可独立发现和调用的 action,不硬编码组织、默认分支、CI、分支命名、合并方式或机器人协议。安装套件同时提供核心 `msd` 和十个薄路由 Skill:Claude Code OpenCode 输入 `/msd-`、Codex 输入 `$msd-`,即可在客户端的 Skill 补全中查看 action。
14
15
 
15
16
  ## Action 路由
16
17
 
17
- 识别显式参数 `action=<name>`;显式 action 直接路由,不显示菜单。未知 action 停止并列出有效值,不做远端写入。仅当用户调用本 skill 且没有提供 `action=` 时,必须先执行下述菜单路由,不得在选择完成前探测仓库、调用 GitCode、读写远端或加载 action reference。
18
+ 推荐入口为 `msd-<action>`。薄路由 Skill 只固定一个 action、保留调用正文并加载本核心,不复制业务规则。核心也兼容字面量参数 `action=<name>`;显式 action 直接路由,未知 action 停止并列出有效值,不做远端写入。
18
19
 
19
- ### action 菜单路由
20
+ 直接调用核心 `msd` 且没有 `action=` 时,运行完整作者 E2E,不显示运行时 Question 菜单,也不根据自然语言改成某个独立 action。完整 E2E 内部按权威证据定位当前阶段并渐进加载规则。
20
21
 
21
- 优先使用当前宿主提供的原生单选工具:Claude Code 使用 `AskUserQuestion`,Codex 使用 `request_user_input`,OpenCode 使用 `question`;不要仅因工具名称不同而跳过菜单。每次只问一个问题,选项不超过 3 个,等待用户选择后再进入下一层:
22
+ 若薄路由 Skill 固定的 action 与调用正文中的 `action=` 冲突,停止为 `blocked: action-conflict`,不得猜测或执行远端写入。
23
+
24
+ 可发现入口:
22
25
 
23
26
  ```text
24
- 选择运行方式
25
- ├─ 完整端到端流程 -> full-e2e
26
- ├─ 作者工作流
27
- │ ├─ Issue 管理
28
- │ │ ├─ discover
29
- │ │ ├─ create-issue
30
- │ │ └─ issue
31
- │ ├─ 开发与交付
32
- │ │ ├─ develop
33
- │ │ ├─ pr
34
- │ │ └─ ci
35
- │ └─ PR 后续
36
- │ ├─ feedback
37
- │ └─ merge
38
- └─ 独立工具
39
- ├─ openlibing-auth
40
- └─ code-review
27
+ msd
28
+ msd-discover
29
+ msd-create-issue
30
+ msd-issue
31
+ msd-develop
32
+ msd-pr
33
+ msd-ci
34
+ msd-openlibing-auth
35
+ msd-feedback
36
+ msd-code-review
37
+ msd-merge
41
38
  ```
42
39
 
43
- 菜单规则:
44
-
45
- 1. 顶层“完整端到端流程”不是 action;选中后按“完整作者 E2E”执行,并在内部将本次路由记为 `full-e2e`。
46
- 2. 每级原生菜单都把推荐项放在首位,并按宿主约定标明推荐:顶层推荐“完整端到端流程”;作者工作流分类推荐“Issue 管理”;各叶子层分别推荐 `discover`、`develop`、`feedback` 和 `openlibing-auth`。不得为了改变推荐项而提前探测仓库或远端。
47
- 3. 选中叶子 action 后,等同于用户显式提供了对应 `action=<name>`,严格遵守显式 action 契约;保留调用正文中已经给出的 URL、路径、仓库和模式等参数。
48
- 4. 宿主没有可用选择工具、选择工具在当前模式被禁用,或处于非交互运行时,只输出当前层的编号文本选项并停止等待用户回复;不得自行选择默认项,也不得把多层菜单一次性展开。
49
- 5. 只要调用中没有字面量 `action=<name>`,即使自然语言看似指向某个流程,也必须从顶层菜单开始;不得根据意图猜测跳过菜单。菜单选择属于当前 skill 调用,选定后立即继续,不要求用户重新输入 `/msdevflow`。
40
+ 薄路由选定后,等同于向本核心显式提供对应 `action=<name>`,并严格遵守显式 action 契约。
50
41
 
51
42
  | action | 目标 | 主要输入 | 完成后立即停止于 | 必读文件 |
52
43
  |---|---|---|---|---|
@@ -61,7 +52,7 @@ metadata:
61
52
  | `code-review` | 检视他人的 PR,发布 finding 或 `/lgtm` | 他人 PR | `review-findings`、`review-passed`、`review-incomplete`、`waiting` 或 `blocked` | [references/code-review.md](references/code-review.md) |
62
53
  | `merge` | 核验门禁并在最终确认后合入 | canonical PR | `merged`、`waiting` 或 `blocked` | [references/review-and-merge.md](references/review-and-merge.md) |
63
54
 
64
- `code-review` 只能通过显式 `action=code-review` 或“独立工具”菜单叶子独立调用,永不进入作者 E2E,不得检视或批准当前账号自己的 PR。它固定当前 head,完整检视权威 diff、必要上下文和既有 discussions:有高置信度问题时发布经确认且逐字回读的 finding,不发送 `/lgtm`;没有问题、没有有效未解决意见且覆盖完整时,在针对当前 PR/head 明确确认后先发布带尾签摘要,再原样发送 `/lgtm`。它不发送 `/approve`、`/merge`,不修改作者代码。
55
+ `code-review` 只能通过 `msd-code-review` 或兼容参数 `action=code-review` 独立调用,永不进入作者 E2E,不得检视或批准当前账号自己的 PR。它固定当前 head,完整检视权威 diff、必要上下文和既有 discussions:有高置信度问题时发布经确认且逐字回读的 finding,不发送 `/lgtm`;没有问题、没有有效未解决意见且覆盖完整时,在针对当前 PR/head 明确确认后先发布带尾签摘要,再原样发送 `/lgtm`。它不发送 `/approve`、`/merge`,不修改作者代码。
65
56
 
66
57
  ## 显式 action 契约
67
58
 
@@ -75,7 +66,7 @@ metadata:
75
66
 
76
67
  ## 完整作者 E2E
77
68
 
78
- 只有无 action 菜单选中 `full-e2e` 后,才从 Phase 0 环境、CLI 能力和仓库画像开始运行完整流程;调用正文可以提供完整 E2E 所需的 URL、路径、仓库和模式,但不能替代菜单选择。“从头开始”只表示重新读取事实,不表示重复创建资源或重复评论。按证据幂等跳过已完成步骤:
69
+ 直接调用核心 `msd` 且未提供 `action=` 时,从 Phase 0 环境、CLI 能力和仓库画像开始运行完整流程;调用正文可以提供完整 E2E 所需的 URL、路径、仓库和模式。“从头开始”只表示重新读取事实,不表示重复创建资源或重复评论。按证据幂等跳过已完成步骤:
79
70
 
80
71
  ```text
81
72
  discover -> issue -> develop -> pr -> ci
@@ -97,7 +88,7 @@ discover -> issue -> develop -> pr -> ci
97
88
  1. 固定 `gitcode_command`:无 Python 同名工具时为 `gitcode`;有 Python `gitcode` 时保留它并使用 `gitcode-npm`。来源不明时停止,不覆盖。
98
89
  2. 检查当前目录;若不是 Git 仓库,自动探测直接子目录中的 Git 仓库及 remotes。
99
90
  3. 确认 canonical repository、source repository、operation target、当前账号和授权范围。
100
- 4. 除纯只读 `discover` 外,显式 action 先从 [references/setup-and-issue.md](references/setup-and-issue.md) 只读取公共环境、仓库上下文和最小充分仓库画像,不执行其中的 Issue 接取业务;随后只加载该 action 对应 reference 及实际触发的深层规则。`create-issue` 的模板选择和写入只按 [references/create-issue.md](references/create-issue.md),不执行候选发现或既有 Issue 核验。`code-review` 只使用公共只读画像和 [references/code-review.md](references/code-review.md),不加载作者 feedback/merge 规则。`full-e2e` 也只按当前位置渐进加载。
91
+ 4. 除纯只读 `discover` 外,显式 action 先从 [references/setup-and-issue.md](references/setup-and-issue.md) 只读取公共环境、仓库上下文和最小充分仓库画像,不执行其中的 Issue 接取业务;随后只加载该 action 对应 reference 及实际触发的深层规则。`create-issue` 的模板选择和写入只按 [references/create-issue.md](references/create-issue.md),不执行候选发现或既有 Issue 核验。`code-review` 只使用公共只读画像和 [references/code-review.md](references/code-review.md),不加载作者 feedback/merge 规则。完整作者 E2E 也只按当前位置渐进加载。
101
92
  5. CLI 缺失、命令不兼容或版本不足时读 [references/command-capabilities.md](references/command-capabilities.md),停止当前 action 并提示用户运行独立 setup;setup 成功后恢复原 action。
102
93
  6. 进入 autonomous、远端写、危险动作或恢复时读 [references/state-and-safety.md](references/state-and-safety.md)。
103
94
  7. 中断恢复、写结果不确定或最终报告时读 [references/recovery.md](references/recovery.md)。
@@ -107,7 +107,7 @@ commit/head SHA
107
107
  - 不采纳:spec/代码/测试依据;
108
108
  6. 统一换行为 `\n` 后逐字比较完整远端回复与预期正文,并验证末尾恰好存在一次尾签;发现 `?`、乱码、截断、尾签缺失、重复或其他不一致时先原地修复,未修复前不得 resolve;
109
109
  7. 正文回读通过后,仓库规则允许且权限具备时 resolve,再回读确认 `resolved=true`;
110
- 8. 产生新 head 时,显式 `action=feedback` 停止并建议 `action=ci`;菜单选中的完整作者 E2E(`full-e2e`) 由编排器随后路由到 `ci`。
110
+ 8. 产生新 head 时,显式 `action=feedback` 停止并建议 `action=ci`;核心 `msd` 启动的完整作者 E2E 由编排器随后路由到 `ci`。
111
111
 
112
112
  不要只发一条总体总结替代逐条回复。汇总应在逐条闭环后发布。
113
113
 
@@ -1,6 +1,6 @@
1
1
  # Action `create-issue`
2
2
 
3
- 显式 `action=create-issue` 用于在一个已授权的 canonical repository 中创建一个 GitCode Issue。它是独立 action:创建并回读确认后立即停止,不执行 `discover`、`issue`、接取、查重、代码核验、开发或 PR 流程,也不进入菜单选中的完整作者 E2E(`full-e2e`)。
3
+ 显式 `action=create-issue` 用于在一个已授权的 canonical repository 中创建一个 GitCode Issue。它是独立 action:创建并回读确认后立即停止,不执行 `discover`、`issue`、接取、查重、代码核验、开发或 PR 流程,也不进入核心 `msd` 启动的完整作者 E2E
4
4
 
5
5
  ## 输入和边界
6
6
 
@@ -1,6 +1,6 @@
1
1
  # Action `develop`:分析、设计与开发
2
2
 
3
- 只在显式 `action=develop`,或菜单选中的完整作者 E2E(`full-e2e`) 已达到 `verified` 时读取。显式 action 启动时先只读确认 Issue 已核验且没有重复实现;前置不足时返回 `blocked` 并建议 `action=issue`,不得自动接取或补跑核验。
3
+ 只在显式 `action=develop`,或核心 `msd` 启动的完整作者 E2E 已达到 `verified` 时读取。显式 action 启动时先只读确认 Issue 已核验且没有重复实现;前置不足时返回 `blocked` 并建议 `action=issue`,不得自动接取或补跑核验。
4
4
 
5
5
  ## Phase 3:需求分析与设计决策树
6
6
 
@@ -1,6 +1,6 @@
1
1
  # Action `pr` 与 `ci`
2
2
 
3
- 只在显式 `action=pr`、`action=ci`,或菜单选中的完整作者 E2E(`full-e2e`) 路由到对应位置时读取。任何远端写前同时读取 [state-and-safety.md](state-and-safety.md)。CI 触发或失败时再读取 [ci-and-review.md](ci-and-review.md),不要提前加载。
3
+ 只在显式 `action=pr`、`action=ci`,或核心 `msd` 启动的完整作者 E2E 路由到对应位置时读取。任何远端写前同时读取 [state-and-safety.md](state-and-safety.md)。CI 触发或失败时再读取 [ci-and-review.md](ci-and-review.md),不要提前加载。
4
4
 
5
5
  ## Action `pr`:Commit、Push、普通 PR
6
6
 
@@ -14,7 +14,7 @@
14
14
  4. 根据 action 完成条件识别最后一个有证据的状态;不能只信先前摘要或旧 run 产物。
15
15
  5. 验证本地分支与远端 source head 是否一致。
16
16
  6. 显式 action 只判断自身前置和完成条件:前置缺失时 `blocked`,不得运行上游;已完成时报告证据并立即停止。
17
- 7. 菜单选中的完整作者 E2E(`full-e2e`) 从 Phase 0 重建仓库画像,再路由到下一未完成作者 action;不重复已完成的写操作。
17
+ 7. 核心 `msd` 启动的完整作者 E2E 从 Phase 0 重建仓库画像,再路由到下一未完成作者 action;不重复已完成的写操作。
18
18
  8. `create-issue` 不执行产品查重;仅在本次创建结果不确定时按目标仓库、当前账号、启动时间、标题和完整正文做有界恢复,无法唯一证明时停止。`openlibing-auth` 的历史 profile 或旧认证摘要不证明当前授权有效;必须用本次固定 run 做真实只读请求。
19
19
  9. `code-review` 不参与作者 E2E,也不从作者 feedback 状态恢复。恢复时重新确认 reviewer、author、PR 状态和当前 head;旧 `review_head_sha` 的分析、摘要、finding 或 `/lgtm` 不证明当前 head 已检视。
20
20
  10. 当前 head 等于旧 `review_head_sha` 时,回读结构化 comments/discussions,并按 reviewer、head、path/position 和完整正文恢复已发布 finding;检视通过必须同时回读到绑定当前 head 的带尾签摘要和同一 reviewer 的精确 `/lgtm`。
@@ -1,6 +1,6 @@
1
1
  # Action `feedback` 与 `merge`
2
2
 
3
- 只在显式 `action=feedback`、`action=merge`,或菜单选中的完整作者 E2E(`full-e2e`) 路由到对应位置时读取。开始时同时读取 [state-and-safety.md](state-and-safety.md);处理结构化 discussion 或 CI 时按需读取 [ci-and-review.md](ci-and-review.md)。本文件不定义 `action=code-review`。
3
+ 只在显式 `action=feedback`、`action=merge`,或核心 `msd` 启动的完整作者 E2E 路由到对应位置时读取。开始时同时读取 [state-and-safety.md](state-and-safety.md);处理结构化 discussion 或 CI 时按需读取 [ci-and-review.md](ci-and-review.md)。本文件不定义 `action=code-review`。
4
4
 
5
5
  ## Action `feedback`:处理自己 PR 的检视意见
6
6
 
@@ -31,7 +31,7 @@ PR 不存在时返回 `blocked` 并建议 `action=pr`;source branch 不可写
31
31
  6. 创建新 commit 并 push,不 amend、不 force push;
32
32
  7. 每条 discussion 在线程内回复:已修复引用 commit;部分采纳、不采纳或延期说明依据;每条回复按 [state-and-safety.md](state-and-safety.md) 使用 UTF-8 安全通道并附加唯一尾签,逐字回读完整正文;
33
33
  8. 只有回复正文和尾签回读一致后,仓库规则和权限允许时才 resolve;乱码、`?`、截断或不一致时先原地修复;
34
- 9. 产生新 head 时记录旧 CI 结果已失效,停止后建议 `action=ci`;不得在显式 `feedback` 内触发或监控远端 CI。菜单选中的完整作者 E2E(`full-e2e`) 由编排器随后路由到 `ci`。
34
+ 9. 产生新 head 时记录旧 CI 结果已失效,停止后建议 `action=ci`;不得在显式 `feedback` 内触发或监控远端 CI。核心 `msd` 启动的完整作者 E2E 由编排器随后路由到 `ci`。
35
35
 
36
36
  不要以一条总体评论替代逐条回复。处理完成后不请求重新检视、不触发检视机器人;外部 reviewer 是否重新检视由仓库和人员流程决定。
37
37
 
@@ -1,6 +1,6 @@
1
1
  # Action `discover` 与 `issue`
2
2
 
3
- 在显式 `action=discover`、`action=issue`,或菜单选中的完整作者 E2E(`full-e2e`) 启动时读取;显式 `action=create-issue` 只读取本文件的公共环境、仓库上下文和最小充分画像,模板和写入业务转到 [create-issue.md](create-issue.md),不得执行本文件的发现、接取或重复实现核验。`discover` 全程只读并在候选报告后立即停止;`issue` 只接取和核验指定 Issue,达到 `verified` 后立即停止,不进入开发。
3
+ 在显式 `action=discover`、`action=issue`,或核心 `msd` 启动的完整作者 E2E 启动时读取;显式 `action=create-issue` 只读取本文件的公共环境、仓库上下文和最小充分画像,模板和写入业务转到 [create-issue.md](create-issue.md),不得执行本文件的发现、接取或重复实现核验。`discover` 全程只读并在候选报告后立即停止;`issue` 只接取和核验指定 Issue,达到 `verified` 后立即停止,不进入开发。
4
4
 
5
5
  显式 `action=issue` 必须提供 Issue URL 或编号。缺少目标时只做确认输入缺失所需的只读核验,随后返回 `blocked` 并建议先运行 `action=discover`;不得在本 action 内查询候选、让用户选择 Issue 或执行 `discover` 的业务。
6
6
 
@@ -98,7 +98,7 @@ pr_number(如已有)
98
98
 
99
99
  ## Phase 1:发现与接取
100
100
 
101
- 显式 `action=issue` 直接读取输入中的 Issue URL/编号;缺少目标时按本文件入口规则返回 `blocked`。显式 `action=discover` 或菜单选中的完整作者 E2E(`full-e2e`) 尚无目标时,才对“无目标发现”确认出的每个 canonical 查询当前用户负责的开放 Issue:
101
+ 显式 `action=issue` 直接读取输入中的 Issue URL/编号;缺少目标时按本文件入口规则返回 `blocked`。显式 `action=discover` 或核心 `msd` 启动的完整作者 E2E 尚无目标时,才对“无目标发现”确认出的每个 canonical 查询当前用户负责的开放 Issue:
102
102
 
103
103
  ```bash
104
104
  <gitcode-command> issue list -R <canonical> --state open --assignee <username> --json
@@ -0,0 +1,15 @@
1
+ ---
2
+ name: msd-ci
3
+ description: 监控、诊断并修复当前 GitCode PR 的 CI,结果严格绑定当前 head SHA。
4
+ compatibility: Requires the sibling msd core skill.
5
+ metadata:
6
+ source: msdevflow
7
+ role: action-router
8
+ action: ci
9
+ ---
10
+
11
+ # msd ci router
12
+
13
+ 先读取并完整遵循相对路径 `../msd/SKILL.md`(同一 skills 根目录中的 `msd` 核心),以固定参数 `action=ci` 执行;核心引用的相对路径均以 `../msd/` 为基准。原样保留本次调用正文中的 URL、路径、仓库、模式和其他参数;若正文包含不同的 `action=`,按核心规则停止为 `blocked: action-conflict`。无法读取核心时停止为 `blocked: core-skill-unavailable`。
14
+
15
+ 本路由只固定 action,不实现或复制业务规则。
@@ -0,0 +1,15 @@
1
+ ---
2
+ name: msd-code-review
3
+ description: 独立检视他人的 GitCode PR,发布高置信度 finding,或确认后评论精确的 /lgtm。
4
+ compatibility: Requires the sibling msd core skill.
5
+ metadata:
6
+ source: msdevflow
7
+ role: action-router
8
+ action: code-review
9
+ ---
10
+
11
+ # msd code-review router
12
+
13
+ 先读取并完整遵循相对路径 `../msd/SKILL.md`(同一 skills 根目录中的 `msd` 核心),以固定参数 `action=code-review` 执行;核心引用的相对路径均以 `../msd/` 为基准。原样保留本次调用正文中的 URL、路径、仓库、模式和其他参数;若正文包含不同的 `action=`,按核心规则停止为 `blocked: action-conflict`。无法读取核心时停止为 `blocked: core-skill-unavailable`。
14
+
15
+ 本路由只固定 action,不实现或复制业务规则。
@@ -0,0 +1,15 @@
1
+ ---
2
+ name: msd-create-issue
3
+ description: 按目标仓库或 Ascend community 的同类型模板创建一个 GitCode Issue,并回读验证。
4
+ compatibility: Requires the sibling msd core skill.
5
+ metadata:
6
+ source: msdevflow
7
+ role: action-router
8
+ action: create-issue
9
+ ---
10
+
11
+ # msd create-issue router
12
+
13
+ 先读取并完整遵循相对路径 `../msd/SKILL.md`(同一 skills 根目录中的 `msd` 核心),以固定参数 `action=create-issue` 执行;核心引用的相对路径均以 `../msd/` 为基准。原样保留本次调用正文中的 URL、路径、仓库、模式和其他参数;若正文包含不同的 `action=`,按核心规则停止为 `blocked: action-conflict`。无法读取核心时停止为 `blocked: core-skill-unavailable`。
14
+
15
+ 本路由只固定 action,不实现或复制业务规则。
@@ -0,0 +1,15 @@
1
+ ---
2
+ name: msd-develop
3
+ description: 分析并实现已核验的 GitCode Issue,从最新 canonical 基线建分支并完成本地验证。
4
+ compatibility: Requires the sibling msd core skill.
5
+ metadata:
6
+ source: msdevflow
7
+ role: action-router
8
+ action: develop
9
+ ---
10
+
11
+ # msd develop router
12
+
13
+ 先读取并完整遵循相对路径 `../msd/SKILL.md`(同一 skills 根目录中的 `msd` 核心),以固定参数 `action=develop` 执行;核心引用的相对路径均以 `../msd/` 为基准。原样保留本次调用正文中的 URL、路径、仓库、模式和其他参数;若正文包含不同的 `action=`,按核心规则停止为 `blocked: action-conflict`。无法读取核心时停止为 `blocked: core-skill-unavailable`。
14
+
15
+ 本路由只固定 action,不实现或复制业务规则。
@@ -0,0 +1,15 @@
1
+ ---
2
+ name: msd-discover
3
+ description: 只读发现当前 GitCode 账号负责且仍需处理的候选 Issue,并列出候选与排除证据。
4
+ compatibility: Requires the sibling msd core skill.
5
+ metadata:
6
+ source: msdevflow
7
+ role: action-router
8
+ action: discover
9
+ ---
10
+
11
+ # msd discover router
12
+
13
+ 先读取并完整遵循相对路径 `../msd/SKILL.md`(同一 skills 根目录中的 `msd` 核心),以固定参数 `action=discover` 执行;核心引用的相对路径均以 `../msd/` 为基准。原样保留本次调用正文中的 URL、路径、仓库、模式和其他参数;若正文包含不同的 `action=`,按核心规则停止为 `blocked: action-conflict`。无法读取核心时停止为 `blocked: core-skill-unavailable`。
14
+
15
+ 本路由只固定 action,不实现或复制业务规则。
@@ -0,0 +1,15 @@
1
+ ---
2
+ name: msd-feedback
3
+ description: 处理当前账号自己 GitCode PR 的检视意见,验证并推送修改,逐条回复 discussion。
4
+ compatibility: Requires the sibling msd core skill.
5
+ metadata:
6
+ source: msdevflow
7
+ role: action-router
8
+ action: feedback
9
+ ---
10
+
11
+ # msd feedback router
12
+
13
+ 先读取并完整遵循相对路径 `../msd/SKILL.md`(同一 skills 根目录中的 `msd` 核心),以固定参数 `action=feedback` 执行;核心引用的相对路径均以 `../msd/` 为基准。原样保留本次调用正文中的 URL、路径、仓库、模式和其他参数;若正文包含不同的 `action=`,按核心规则停止为 `blocked: action-conflict`。无法读取核心时停止为 `blocked: core-skill-unavailable`。
14
+
15
+ 本路由只固定 action,不实现或复制业务规则。
@@ -0,0 +1,15 @@
1
+ ---
2
+ name: msd-issue
3
+ description: 接取并核验指定 GitCode Issue,检查关联 PR、默认分支和重复实现证据。
4
+ compatibility: Requires the sibling msd core skill.
5
+ metadata:
6
+ source: msdevflow
7
+ role: action-router
8
+ action: issue
9
+ ---
10
+
11
+ # msd issue router
12
+
13
+ 先读取并完整遵循相对路径 `../msd/SKILL.md`(同一 skills 根目录中的 `msd` 核心),以固定参数 `action=issue` 执行;核心引用的相对路径均以 `../msd/` 为基准。原样保留本次调用正文中的 URL、路径、仓库、模式和其他参数;若正文包含不同的 `action=`,按核心规则停止为 `blocked: action-conflict`。无法读取核心时停止为 `blocked: core-skill-unavailable`。
14
+
15
+ 本路由只固定 action,不实现或复制业务规则。
@@ -0,0 +1,15 @@
1
+ ---
2
+ name: msd-merge
3
+ description: 核验当前 GitCode PR 的 CI、discussion 和独立审批门禁,并在最终确认后合入。
4
+ compatibility: Requires the sibling msd core skill.
5
+ metadata:
6
+ source: msdevflow
7
+ role: action-router
8
+ action: merge
9
+ ---
10
+
11
+ # msd merge router
12
+
13
+ 先读取并完整遵循相对路径 `../msd/SKILL.md`(同一 skills 根目录中的 `msd` 核心),以固定参数 `action=merge` 执行;核心引用的相对路径均以 `../msd/` 为基准。原样保留本次调用正文中的 URL、路径、仓库、模式和其他参数;若正文包含不同的 `action=`,按核心规则停止为 `blocked: action-conflict`。无法读取核心时停止为 `blocked: core-skill-unavailable`。
14
+
15
+ 本路由只固定 action,不实现或复制业务规则。
@@ -0,0 +1,15 @@
1
+ ---
2
+ name: msd-openlibing-auth
3
+ description: 在当前 canonical 仓库内固定一个 openLiBing run,并安全验证 GitCode OAuth 只读访问。
4
+ compatibility: Requires the sibling msd core skill.
5
+ metadata:
6
+ source: msdevflow
7
+ role: action-router
8
+ action: openlibing-auth
9
+ ---
10
+
11
+ # msd openlibing-auth router
12
+
13
+ 先读取并完整遵循相对路径 `../msd/SKILL.md`(同一 skills 根目录中的 `msd` 核心),以固定参数 `action=openlibing-auth` 执行;核心引用的相对路径均以 `../msd/` 为基准。原样保留本次调用正文中的 URL、路径、仓库、模式和其他参数;若正文包含不同的 `action=`,按核心规则停止为 `blocked: action-conflict`。无法读取核心时停止为 `blocked: core-skill-unavailable`。
14
+
15
+ 本路由只固定 action,不实现或复制业务规则。
@@ -0,0 +1,15 @@
1
+ ---
2
+ name: msd-pr
3
+ description: 复验本地实现后 commit、push,并创建和回读验证普通 GitCode PR。
4
+ compatibility: Requires the sibling msd core skill.
5
+ metadata:
6
+ source: msdevflow
7
+ role: action-router
8
+ action: pr
9
+ ---
10
+
11
+ # msd pr router
12
+
13
+ 先读取并完整遵循相对路径 `../msd/SKILL.md`(同一 skills 根目录中的 `msd` 核心),以固定参数 `action=pr` 执行;核心引用的相对路径均以 `../msd/` 为基准。原样保留本次调用正文中的 URL、路径、仓库、模式和其他参数;若正文包含不同的 `action=`,按核心规则停止为 `blocked: action-conflict`。无法读取核心时停止为 `blocked: core-skill-unavailable`。
14
+
15
+ 本路由只固定 action,不实现或复制业务规则。