msdevflow 0.7.3 → 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 +35 -40
  2. package/lib/bootstrap.js +262 -88
  3. package/package.json +4 -2
  4. package/skill/{msdevflow → msd}/README.md +44 -25
  5. package/skill/{msdevflow → msd}/SKILL.md +33 -10
  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,11 +29,11 @@ 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 能力;
36
- 5. GitCode CLI 未认证时打开官方浏览器登录。
36
+ 5. GitCode CLI 未认证时打开官方 Token 创建页面,并让 CLI 自己的终端提示接收 Token。
37
37
 
38
38
  显式选择客户端或只读预检:
39
39
 
@@ -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,25 +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
- ## 完整端到端流程
70
+ ## 运行与 action 补全
69
71
 
70
- 从目标仓库目录启动已安装目标中的任一客户端,然后调用 skill
72
+ 从目标仓库目录启动客户端。直接调用核心 `msd` 会运行完整作者 E2E
71
73
 
72
- - Claude Code:输入 `/msdevflow`;
73
- - Codex:使用 `$msdevflow`、`/skills` 选择,或让 Codex 按描述隐式匹配;
74
- - OpenCode:通过其 skill 工具选择,或让 OpenCode 按描述隐式匹配。
74
+ - Claude Code:输入并提交 `/msd`;
75
+ - Codex:使用 `$msd` 或从 `/skills` 选择;
76
+ - OpenCode:打开 `/skills`,选择 `msd`,再提交插入的 `/msd`。`@` 用于文件、reference 或 agent,不用于选择 Skill。
75
77
 
76
- 客户端 UI 和命令入口可能随版本变化,但传给 skill 的任务正文相同:
77
-
78
- ```text
79
- 处理 https://gitcode.com/<canonical-owner>/<repo>/issues/<number>。
80
- 本地仓库:<local-repository-absolute-path>
81
- canonical:<canonical-owner>/<repo>
82
- source:<your-account>/<repo>
83
- 使用 guided 模式,按权威远端和本地证据推进完整作者 E2E。
84
- ```
85
-
86
- 未指定 `action` 时,流程为:
78
+ 核心流程为:
87
79
 
88
80
  ```text
89
81
  Issue 发现/核验
@@ -98,10 +90,11 @@ Issue 发现/核验
98
90
  -> 远端回读 PR 已 merged
99
91
  ```
100
92
 
101
- 这是可暂停、可恢复的流程。外部检视或审批有新进展后,可再次运行:
93
+ 调用正文可提供 Issue/PR URL、仓库路径、canonical、source 和模式。核心 `msd` 不显示运行时 Question 菜单。
94
+
95
+ 这是可暂停、可恢复的流程。外部检视或审批有新进展后,可再次提交 `/msd` 和 PR 信息:
102
96
 
103
97
  ```text
104
- /msdevflow
105
98
  恢复 https://gitcode.com/<canonical-owner>/<repo>/pulls/<number> 的完整作者 E2E。
106
99
  本地仓库:<local-repository-absolute-path>
107
100
  canonical:<canonical-owner>/<repo>
@@ -111,7 +104,7 @@ source:<your-account>/<repo>
111
104
 
112
105
  ## 独立 action
113
106
 
114
- 显式提供 `action=<name>` 时,只运行该 action,完成后立即停止;前置条件不足时不会隐式补跑上游流程。
107
+ Claude Code/OpenCode 输入 `/msd-`、Codex 输入 `$msd-` 即可筛选十个独立入口。每个入口只运行对应 action,完成后立即停止;前置条件不足时不会隐式补跑上游流程。`/msd action=<name>` `$msd action=<name>` 仍是兼容调用,但参数本身不提供跨客户端枚举补全。
115
108
 
116
109
  | action | 用途 | 完成状态或结果 |
117
110
  |---|---|---|
@@ -129,19 +122,19 @@ source:<your-account>/<repo>
129
122
  示例:
130
123
 
131
124
  ```text
132
- /msdevflow action=create-issue
125
+ /msd-create-issue
133
126
  在 Ascend/example 提一个 bug:升级后首次启动失败……
134
127
  使用 guided 模式,确认完整预览后再创建。
135
128
  ```
136
129
 
137
130
  ```text
138
- /msdevflow action=ci
131
+ /msd-ci
139
132
  PR:https://gitcode.com/Ascend/example/pulls/456
140
133
  本地仓库:D:\work\example
141
134
  ```
142
135
 
143
136
  ```text
144
- /msdevflow action=code-review
137
+ /msd-code-review
145
138
  PR:https://gitcode.com/Ascend/example/pulls/789
146
139
  ```
147
140
 
@@ -172,7 +165,7 @@ Agent 写入的 PR/Issue 正文、评论和 discussion 回复末尾会附加:
172
165
  `msdevflow`:
173
166
 
174
167
  - 不读取、打印或转存 GitCode Token;
175
- - 不要求用户把 Token 粘贴到终端、对话或项目文件;
168
+ - Token 只粘贴到 GitCode CLI 自己的终端提示,不放入 Agent 对话、命令参数、项目文件、URL 或日志;
176
169
  - openLiBing Token 只在当前 Python 认证进程内短暂使用,不输出、不落盘;
177
170
  - 永远不会自动下载 Playwright Chromium;
178
171
  - 优先使用系统 Chrome/Edge,其次使用已经安装的 Playwright Chromium;
@@ -183,17 +176,19 @@ Agent 写入的 PR/Issue 正文、评论和 discussion 回复末尾会附加:
183
176
 
184
177
  ## 常见阻塞
185
178
 
186
- ### 客户端找不到 `msdevflow`
179
+ ### 客户端找不到 `msd` 或 `msd-<action>`
187
180
 
188
- 按目标确认至少一个受支持的 manifest 存在,然后重启或重新加载客户端:
181
+ 按目标确认核心和相应路由器的 manifest 都存在,然后重启或重新加载客户端:
189
182
 
190
183
  ```text
191
- Claude Code: ~/.claude/skills/msdevflow/SKILL.md
192
- 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
193
188
  OpenCode: 上述任一路径(按 setup 计划)
194
189
  ```
195
190
 
196
- 可运行 `npx msdevflow setup --dry-run --targets <clients>` 检查目标映射。
191
+ Claude Code/OpenCode 可输入 `/msd-` 筛选 action;Codex 使用 `$msd-`。可运行 `npx msdevflow setup --dry-run --targets <clients>` 检查目标映射。
197
192
 
198
193
  ### `blocked: bootstrap-required`
199
194
 
@@ -212,7 +207,7 @@ npx msdevflow setup
212
207
  <gitcode-command> auth status --json
213
208
  ```
214
209
 
215
- 用户只在官方浏览器页面输入凭证。
210
+ 用户在官方页面创建 Token,并只粘贴到 GitCode CLI 自己的终端提示;不要把 Token 交给 Agent 或放入命令参数、项目文件、URL 或日志。
216
211
 
217
212
  ### `blocked: browser-required`
218
213
 
@@ -224,4 +219,4 @@ npx msdevflow setup
224
219
 
225
220
  ## 详细文档
226
221
 
227
- 完整 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.3",
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,9 @@
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
+ "!skill/**/__pycache__/**",
15
+ "!skill/**/*.pyc"
14
16
  ],
15
17
  "scripts": {
16
18
  "check": "node --check bin/msdevflow.js && node --check lib/bootstrap.js",
@@ -1,9 +1,26 @@
1
- # msdevflow
1
+ # msd
2
2
 
3
- 通用 GitCode Issue 到 PR 合入 workflow skill。它保留一个统一 skill,通过显式 `action` 单独执行某一部分;未指定 `action` 时,按远端和本地证据运行完整作者端到端流程。
3
+ 通用 GitCode Issue 到 PR 合入 workflow Skill 套件。业务规则只存在于核心 `msd`;十个 `msd-<action>` 薄路由 Skill 让 Claude Code、Codex 和 OpenCode 在输入阶段展示并补全可用 action
4
4
 
5
5
  ## 1. Action 模型
6
6
 
7
+ 输入 `/msd-`(Claude Code/OpenCode)或 `$msd-`(Codex)即可筛选:
8
+
9
+ ```text
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
20
+ ```
21
+
22
+ 每个薄路由只固定唯一 action、保留调用正文,并从相对路径 `../msd/SKILL.md` 加载同一 skills 根目录中的核心,不复制业务规则;核心 references 继续以 `../msd/` 为基准。直接调用核心 `msd` 会运行完整作者 E2E,不会在提交后弹出 Question 菜单;`/msd action=<name>`、`$msd action=<name>` 仍作为兼容调用,但参数本身没有跨客户端枚举下拉。
23
+
7
24
  支持:
8
25
 
9
26
  | action | 能力 | 完成后行为 |
@@ -28,7 +45,7 @@
28
45
 
29
46
  ## 2. 完整作者 E2E
30
47
 
31
- 未指定 `action` 时,从环境、CLI 能力和仓库画像开始运行完整流程:
48
+ 直接调用核心 `msd` 且不提供 `action=` 时,从环境、CLI 能力和仓库画像开始运行完整流程:
32
49
 
33
50
  ```text
34
51
  discover -> issue -> develop -> pr -> ci
@@ -55,12 +72,12 @@ discover -> issue -> develop -> pr -> ci
55
72
 
56
73
  ## 4. 调用示例
57
74
 
58
- 以下示例使用 Claude Code 的 `/msdevflow` 形式。Codex 使用 `$msdevflow`、`/skills` 或隐式匹配;OpenCode 使用 skill 工具或隐式匹配。无论客户端入口如何,正文中的 `action=<name>` 和其余任务参数保持相同。
75
+ 以下示例使用 Claude Code 的 `/msd` 形式。Codex 使用 `$msd`,OpenCode 可从 `/skills` 选择 `msd`;OpenCode `@` 不用于 Skill。单项能力优先使用各客户端输入补全中的 `msd-<action>`,正文中的任务参数保持不变。
59
76
 
60
- ### 未指定 action:完整 E2E
77
+ ### 运行完整 E2E
61
78
 
62
79
  ```text
63
- /msdevflow
80
+ /msd
64
81
  处理 https://gitcode.com/Ascend/example/issues/123。
65
82
  本地仓库:D:\work\example
66
83
  canonical:Ascend/example
@@ -71,7 +88,7 @@ Fork:myname/example
71
88
  ### 只发现候选 Issue
72
89
 
73
90
  ```text
74
- /msdevflow action=discover
91
+ /msd-discover
75
92
  查询 Ascend/example 中分配给当前账号的开放 Issue,列出仍需处理的候选。
76
93
  ```
77
94
 
@@ -80,7 +97,7 @@ Fork:myname/example
80
97
  ### 只创建 Issue
81
98
 
82
99
  ```text
83
- /msdevflow action=create-issue
100
+ /msd-create-issue
84
101
  在 Ascend/example 提一个 bug:升级后首次启动失败,错误信息和环境如下……
85
102
  使用 guided 模式,先给我完整预览,确认后再创建。
86
103
  ```
@@ -92,7 +109,7 @@ Fork:myname/example
92
109
  ### 只接取和核验 Issue
93
110
 
94
111
  ```text
95
- /msdevflow action=issue
112
+ /msd-issue
96
113
  处理 https://gitcode.com/Ascend/example/issues/123。
97
114
  本地仓库:D:\work\example
98
115
  ```
@@ -102,7 +119,7 @@ Fork:myname/example
102
119
  ### 只开发和本地验证
103
120
 
104
121
  ```text
105
- /msdevflow action=develop
122
+ /msd-develop
106
123
  Issue:https://gitcode.com/Ascend/example/issues/123
107
124
  本地仓库:D:\work\example
108
125
  ```
@@ -112,7 +129,7 @@ Issue:https://gitcode.com/Ascend/example/issues/123
112
129
  ### 只创建 PR
113
130
 
114
131
  ```text
115
- /msdevflow action=pr
132
+ /msd-pr
116
133
  Issue:https://gitcode.com/Ascend/example/issues/123
117
134
  本地仓库:D:\work\example
118
135
  canonical:Ascend/example
@@ -124,7 +141,7 @@ source:myname/example
124
141
  ### 只处理 CI
125
142
 
126
143
  ```text
127
- /msdevflow action=ci
144
+ /msd-ci
128
145
  PR:https://gitcode.com/Ascend/example/pulls/456
129
146
  本地仓库:D:\work\example
130
147
  ```
@@ -134,7 +151,7 @@ CI 通过后立即停止,不处理 feedback 或 merge。识别为 openLiBing
134
151
  ### 只验证 openLiBing OAuth
135
152
 
136
153
  ```text
137
- /msdevflow action=openlibing-auth
154
+ /msd-openlibing-auth
138
155
  本地仓库:D:\work\example
139
156
  ```
140
157
 
@@ -145,7 +162,7 @@ CI 通过后立即停止,不处理 feedback 或 merge。识别为 openLiBing
145
162
  ### 只处理自己 PR 的意见
146
163
 
147
164
  ```text
148
- /msdevflow action=feedback
165
+ /msd-feedback
149
166
  PR:https://gitcode.com/Ascend/example/pulls/456
150
167
  本地仓库:D:\work\example
151
168
  ```
@@ -155,7 +172,7 @@ PR:https://gitcode.com/Ascend/example/pulls/456
155
172
  ### 检视他人的 PR
156
173
 
157
174
  ```text
158
- /msdevflow action=code-review
175
+ /msd-code-review
159
176
  PR:https://gitcode.com/Ascend/example/pulls/789
160
177
  ```
161
178
 
@@ -166,7 +183,7 @@ PR:https://gitcode.com/Ascend/example/pulls/789
166
183
  ### 只核验并合入
167
184
 
168
185
  ```text
169
- /msdevflow action=merge
186
+ /msd-merge
170
187
  PR:https://gitcode.com/Ascend/example/pulls/456
171
188
  ```
172
189
 
@@ -206,11 +223,11 @@ git --version
206
223
  <gitcode-command> auth login --web
207
224
  ```
208
225
 
209
- 用户只在 GitCode CLI 打开的官方浏览器页面完成登录。不要把 Token 粘贴到对话、setupREADME、项目文件或命令 URL 中;如需手动恢复认证,也优先在自己的终端运行同一 `--web` 命令。
226
+ GitCode CLI 会打开官方页面让用户创建 Token,再在 CLI 自己的终端提示中接收粘贴内容并验证。Token 只能粘贴到该 CLI 提示;不要放入 Agent 对话、命令参数、项目文件、README、URL 或日志。`msdevflow` 父进程不读取或输出 Token;如需手动恢复认证,在自己的终端运行同一 `--web` 命令。
210
227
 
211
228
  ## 6. 安装
212
229
 
213
- npm 包同时携带 `msdevflow` skill setup 程序。首次安装:
230
+ npm `msdevflow` 同时携带 `msd` Skill 套件和 setup 程序。首次安装:
214
231
 
215
232
  ```bash
216
233
  npx msdevflow setup
@@ -226,7 +243,7 @@ npx msdevflow@latest setup
226
243
 
227
244
  `setup` 默认检测 PATH 中的 Claude Code、Codex 和 OpenCode,先展示客户端、物理 skill 目标、安装或更新状态、GitCode CLI 归属、registry、安装模式、Python 依赖命令和认证方式;用户确认后,在同一次运行中:
228
245
 
229
- 1. 从 npm 包内唯一源码 `skill/msdevflow` 原子安装或更新所需受管副本;
246
+ 1. 从 npm 包内的 `skill/msd` 核心和十个 `skill/msd-<action>` 路由器原子安装或更新整套入口;
230
247
  2. 安装或升级官方 GitCode npm CLI;
231
248
  3. 安装内置 `scripts/requirements.txt` 中的 Python Playwright 包;
232
249
  4. 验收 workflow 所需 schema/API;
@@ -235,15 +252,17 @@ npx msdevflow@latest setup
235
252
  客户端到物理目录的映射:
236
253
 
237
254
  ```text
238
- Claude Code -> ~/.claude/skills/msdevflow
239
- Codex -> ~/.agents/skills/msdevflow
240
- 仅 OpenCode -> ~/.agents/skills/msdevflow
255
+ Claude Code -> ~/.claude/skills/{msd,msd-*}
256
+ Codex -> ~/.agents/skills/{msd,msd-*}
257
+ 仅 OpenCode -> ~/.agents/skills/{msd,msd-*}
241
258
  OpenCode + Claude Code -> 复用 Claude 目标
242
259
  OpenCode + Codex -> 复用 Agent Skills 目标
243
- Claude Code + Codex -> 两个受管副本
244
- 三者同时安装 -> 两个受管副本,并提示 OpenCode 双路径发现
260
+ Claude Code + Codex -> 两套受管副本
261
+ 三者同时安装 -> 两套受管副本,并提示 OpenCode 双路径发现
245
262
  ```
246
263
 
264
+ 每个物理目标都包含一个 `msd` 核心和十个 `msd-<action>` 路由器;业务规则仍只有一份。
265
+
247
266
  显式选择客户端、只读预检或自定义目录:
248
267
 
249
268
  ```bash
@@ -263,7 +282,7 @@ npm 包尚未发布时,可从当前源码/发布目录运行等价入口:
263
282
  node ./msdevflow/bin/msdevflow.js setup
264
283
  ```
265
284
 
266
- `setup` 不下载或启动 Chromium。凭证只由 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 精确证明由本包管理时,才会在新套件全部切换并验证后安全迁移;失败时回滚整套变更。安装后重启或重新加载对应客户端。
267
286
 
268
287
  ## 7. 仓库画像和 PR 模板
269
288
 
@@ -1,20 +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.0.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 停止并列出有效值,不做远端写入。
18
+ 推荐入口为 `msd-<action>`。薄路由 Skill 只固定一个 action、保留调用正文并加载本核心,不复制业务规则。核心也兼容字面量参数 `action=<name>`;显式 action 直接路由,未知 action 停止并列出有效值,不做远端写入。
19
+
20
+ 直接调用核心 `msd` 且没有 `action=` 时,运行完整作者 E2E,不显示运行时 Question 菜单,也不根据自然语言改成某个独立 action。完整 E2E 内部按权威证据定位当前阶段并渐进加载规则。
21
+
22
+ 若薄路由 Skill 固定的 action 与调用正文中的 `action=` 冲突,停止为 `blocked: action-conflict`,不得猜测或执行远端写入。
23
+
24
+ 可发现入口:
25
+
26
+ ```text
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
38
+ ```
39
+
40
+ 薄路由选定后,等同于向本核心显式提供对应 `action=<name>`,并严格遵守显式 action 契约。
18
41
 
19
42
  | action | 目标 | 主要输入 | 完成后立即停止于 | 必读文件 |
20
43
  |---|---|---|---|---|
@@ -29,7 +52,7 @@ metadata:
29
52
  | `code-review` | 检视他人的 PR,发布 finding 或 `/lgtm` | 他人 PR | `review-findings`、`review-passed`、`review-incomplete`、`waiting` 或 `blocked` | [references/code-review.md](references/code-review.md) |
30
53
  | `merge` | 核验门禁并在最终确认后合入 | canonical PR | `merged`、`waiting` 或 `blocked` | [references/review-and-merge.md](references/review-and-merge.md) |
31
54
 
32
- `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`,不修改作者代码。
33
56
 
34
57
  ## 显式 action 契约
35
58
 
@@ -41,9 +64,9 @@ metadata:
41
64
  6. `ci` 和完整 E2E 在 openLiBing 只读接口返回 401/403 时可运行 OAuth 认证子流程并恢复原流程;这是读取当前 CI 证据的必要步骤,不视为越界执行显式 `openlibing-auth` action。
42
65
  7. 所有远端写仍遵循 guided/autonomous 授权、UTF-8、尾签、幂等和最终 merge 确认规则。
43
66
 
44
- ## 未指定 action:完整作者 E2E
67
+ ## 完整作者 E2E
45
68
 
46
- 未提供 `action` 时,从 Phase 0 环境、CLI 能力和仓库画像开始运行完整流程;“从头开始”只表示重新读取事实,不表示重复创建资源或重复评论。按证据幂等跳过已完成步骤:
69
+ 直接调用核心 `msd` 且未提供 `action=` 时,从 Phase 0 环境、CLI 能力和仓库画像开始运行完整流程;调用正文可以提供完整 E2E 所需的 URL、路径、仓库和模式。“从头开始”只表示重新读取事实,不表示重复创建资源或重复评论。按证据幂等跳过已完成步骤:
47
70
 
48
71
  ```text
49
72
  discover -> issue -> develop -> pr -> ci
@@ -65,7 +88,7 @@ discover -> issue -> develop -> pr -> ci
65
88
  1. 固定 `gitcode_command`:无 Python 同名工具时为 `gitcode`;有 Python `gitcode` 时保留它并使用 `gitcode-npm`。来源不明时停止,不覆盖。
66
89
  2. 检查当前目录;若不是 Git 仓库,自动探测直接子目录中的 Git 仓库及 remotes。
67
90
  3. 确认 canonical repository、source repository、operation target、当前账号和授权范围。
68
- 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 规则。未指定 action 也只按当前位置渐进加载。
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 也只按当前位置渐进加载。
69
92
  5. CLI 缺失、命令不兼容或版本不足时读 [references/command-capabilities.md](references/command-capabilities.md),停止当前 action 并提示用户运行独立 setup;setup 成功后恢复原 action。
70
93
  6. 进入 autonomous、远端写、危险动作或恢复时读 [references/state-and-safety.md](references/state-and-safety.md)。
71
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`;未指定 action 的完整作者 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 流程,也不进入未指定 action 的完整作者 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`,或未指定 action 的完整作者 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`,或未指定 action 的完整作者 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. 未指定 action 的完整 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`,或未指定 action 的完整作者 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。未指定 action 的完整 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`,或未指定 action 的完整作者 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` 或未指定 action 的完整作者 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,不实现或复制业务规则。