dependfix 0.3.2 → 0.5.0

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.
@@ -0,0 +1,100 @@
1
+ <p align="center">
2
+ <img alt="dependfix" src="../../assets/brand/png/banner.png">
3
+ </p>
4
+
5
+ <!-- i18n: switch -->
6
+ [简体中文](./README.md) | [English](./README.en-US.md)
7
+
8
+ # dependfix
9
+
10
+ > CLI tool for automated handling of GitHub Dependabot / Code Scanning security alerts.
11
+
12
+ ## Installation
13
+
14
+ ```bash
15
+ # Global install
16
+ pnpm add -g dependfix
17
+
18
+ # Or run directly (no install required)
19
+ npx dependfix report-only --repo owner/repo --github-token $GITHUB_TOKEN
20
+ ```
21
+
22
+ ## Commands
23
+
24
+ ### `report-only` — View alerts (default)
25
+
26
+ Fetch alerts and generate Markdown + JSON dual-format reports, without modifying any files.
27
+
28
+ ```bash
29
+ dependfix report-only --repo owner/repo --github-token $GITHUB_TOKEN
30
+ ```
31
+
32
+ ### `fix` — Fix alerts
33
+
34
+ Execute dependency upgrade, lockfile fix and verification (lint / build), modifications limited to local files, no branch or PR creation.
35
+
36
+ ```bash
37
+ dependfix fix --repo owner/repo --github-token $GITHUB_TOKEN --severity-threshold high
38
+ ```
39
+
40
+ ### `fix-and-pr` — Fix and create PR
41
+
42
+ After executing the full fix flow, automatically create fix branch, commit, push and create Pull Request.
43
+
44
+ ```bash
45
+ dependfix fix-and-pr --repo owner/repo --github-token $GITHUB_TOKEN
46
+ ```
47
+
48
+ > Requires `GITHUB_TOKEN` with `contents: write` and `pull-requests: write` permissions.
49
+
50
+ ## CLI flags
51
+
52
+ | Flag | Alias | Description | Default |
53
+ |:-----|:------|:------------|:--------|
54
+ | `mode` | (positional arg) | Run mode: `report-only` / `fix` / `fix-and-pr` | `report-only` |
55
+ | `--repo` | `-r`, `--repository`, `--repositories` | Target repo (`owner/repo`), comma-separated | — |
56
+ | `--repos-file` | — | Read repo list from file (one `owner/repo` per line) | — |
57
+ | `--github-token` | — | GitHub Personal Access Token | `GITHUB_TOKEN` env var |
58
+ | `--severity-threshold` | — | Severity: `critical` / `high` / `medium` / `all` | `high` |
59
+ | `--dry-run` | — | Dry-run mode, do not actually write files | `false` |
60
+ | `--create-pr` | — | Create Pull Request (auto-enabled in `fix-and-pr` mode) | `false` |
61
+ | `--commit` | — | After fix, commit on local current branch (`fix` mode only; no push, no PR) | `false` |
62
+ | `--max-alerts-per-repository` | — | Max alerts processed per repo | `20` |
63
+ | `--commands` | — | Custom verification commands (comma-separated), override default `install/lint/build` | — |
64
+ | `--verbose` | — | Verbose logging | `false` |
65
+
66
+ ### Environment variables
67
+
68
+ | Env var | Description |
69
+ |:--------|:------------|
70
+ | `GITHUB_TOKEN` | GitHub auth token |
71
+
72
+ ## Programmatic usage
73
+
74
+ ```ts
75
+ import { DependfixApp, runCli } from 'dependfix'
76
+
77
+ // Parse CLI args
78
+ const { config } = runCli(process.argv.slice(2))
79
+
80
+ // Programmatic execution
81
+ const app = new DependfixApp({ config, verbose: true })
82
+ const { result, exitCode } = await app.run()
83
+ ```
84
+
85
+ ## Fix flow
86
+
87
+ 1. **Fetch alerts** — get Dependabot alerts via GitHub API
88
+ 2. **Filter and sort** — filter by severity, sort by priority, limit count
89
+ 3. **Upgrade dependencies** — `pnpm update <package>` to recommended version
90
+ 4. **Lockfile fix** — detect and fix `pnpm frozen-lockfile` issues
91
+ 5. **Verify** — execute `pnpm install --frozen-lockfile` → `pnpm lint` → `pnpm build`
92
+ 6. **Branch and PR** — in `fix-and-pr` mode, create branch, commit, push, PR
93
+
94
+ ## Related packages
95
+
96
+ - [dependfix main project](https://github.com/dependfix/dependfix) — this package's source and full docs
97
+ - [@dependfix/core](https://github.com/dependfix/dependfix/blob/master/packages/core/README.md) — core domain model library (this package depends on)
98
+ - [@dependfix/engine](https://github.com/dependfix/dependfix/blob/master/packages/engine/README.md) — execution engine (this package depends on)
99
+ - [@dependfix/skills](https://github.com/dependfix/dependfix/blob/master/packages/skills/README.md) — Agent Skill source of truth (this package depends on)
100
+ - [@dependfix/mcp](https://github.com/dependfix/dependfix/blob/master/packages/mcp/README.md) — MCP Server (AI assistant usage form)
package/README.md CHANGED
@@ -1,5 +1,12 @@
1
+ <p align="center">
2
+ <img alt="dependfix" src="../../assets/brand/png/banner.png">
3
+ </p>
4
+
1
5
  # dependfix
2
6
 
7
+ <!-- i18n: switch -->
8
+ [简体中文](./README.md) | [English](./README.en-US.md)
9
+
3
10
  > 自动化处理 GitHub Dependabot / Code Scanning 安全告警的 CLI 工具。
4
11
 
5
12
  ## 安装
@@ -86,4 +93,8 @@ const { result, exitCode } = await app.run()
86
93
 
87
94
  ## 相关包
88
95
 
89
- - [@dependfix/core](../core/README.md) — 核心领域模型库(本包依赖)
96
+ - [dependfix 主项目](https://github.com/dependfix/dependfix) — 本包源码与完整文档
97
+ - [@dependfix/core](https://github.com/dependfix/dependfix/blob/master/packages/core/README.md) — 核心领域模型库(本包依赖)
98
+ - [@dependfix/engine](https://github.com/dependfix/dependfix/blob/master/packages/engine/README.md) — 执行引擎(本包依赖)
99
+ - [@dependfix/skills](https://github.com/dependfix/dependfix/blob/master/packages/skills/README.md) — 产品 Agent Skill 权威源(本包依赖)
100
+ - [@dependfix/mcp](https://github.com/dependfix/dependfix/blob/master/packages/mcp/README.md) — MCP Server(AI 助手使用形态)
package/dist/index.d.mts CHANGED
@@ -1,13 +1,13 @@
1
- import { CliConfigOverrides, RuntimeConfig, RuntimeMode, resolveRuntimeConfig } from "@dependfix/engine";
1
+ import { AlertSourceKind, CliConfigOverrides, RuntimeConfig, RuntimeMode, SeverityThreshold, resolveRuntimeConfig } from "@dependfix/engine";
2
2
  export * from "@dependfix/core";
3
3
  export * from "@dependfix/engine";
4
4
  //#region src/cli/index.d.ts
5
- interface CliInvocation {
5
+ export interface CliInvocation {
6
6
  mode?: RuntimeMode;
7
7
  configOverrides: CliConfigOverrides;
8
8
  rawArgs: string[];
9
9
  }
10
- declare const argsDef: {
10
+ export declare const argsDef: {
11
11
  mode: {
12
12
  type: "positional";
13
13
  description: string;
@@ -90,6 +90,11 @@ declare const argsDef: {
90
90
  description: string;
91
91
  negativeDescription: string;
92
92
  };
93
+ 'code-quality': {
94
+ type: "boolean";
95
+ description: string;
96
+ negativeDescription: string;
97
+ };
93
98
  'allow-major-upgrade': {
94
99
  type: "boolean";
95
100
  description: string;
@@ -115,6 +120,11 @@ declare const argsDef: {
115
120
  description: string;
116
121
  default: "30000";
117
122
  };
123
+ 'max-repos': {
124
+ type: "string";
125
+ description: string;
126
+ default: "100";
127
+ };
118
128
  history: {
119
129
  type: "string";
120
130
  description: string;
@@ -165,16 +175,38 @@ declare const argsDef: {
165
175
  description: string;
166
176
  };
167
177
  };
168
- declare function parseCliArgs(rawArgs: string[]): CliInvocation;
178
+ export declare function isRuntimeMode(value: string): value is RuntimeMode;
179
+ export declare function isSeverityThreshold(value: string): value is SeverityThreshold;
180
+ export declare function isAlertSource(value: string): value is AlertSourceKind;
181
+ export declare function appendRepositories(target: string[], value: string): void;
182
+ export declare function parseCommandsFlag(value: string): string[];
183
+ /**
184
+ * 严格整数字面量解析(修复:拒绝 `2.5` 被 parseInt 静默截断为 2)。
185
+ * 仅接受 `^\d+$`;范围语义由调用方在 expected 描述中声明(config 校验兜底)。
186
+ */
187
+ export declare function parseIntegerFlag(value: string, flagName: string, expected: string): number;
188
+ /**
189
+ * 归一化可重复 flag 值(citty/mri 对重复传入返回数组,单次传入返回字符串):
190
+ * 按逗号拆分 + 去空白 + 去空项。`--owner a,b --owner c` → ['a', 'b', 'c']。
191
+ */
192
+ export declare function normalizeFlagList(value: string | string[] | undefined): string[];
193
+ /**
194
+ * 解析 `--upgrade-groups "name1:pkg1,pkg2;name2:pkg3"`。
195
+ * 与 config 的 normalizeUpgradeGroups 保持一致(CLI 与 env 同格式):
196
+ * 空 entry 忽略;非空但缺冒号/组名或包列表为空 → 抛 ARGUMENT_PARSE_ERROR;
197
+ * 原型链风险键名(__proto__ / constructor / prototype)忽略。
198
+ */
199
+ export declare function parseUpgradeGroupsFlag(value: string): Record<string, string[]>;
200
+ export declare function parseCliArgs(rawArgs: string[]): CliInvocation;
169
201
  //#endregion
170
202
  //#region src/cli/runner.d.ts
171
- interface CliRunResult {
203
+ export interface CliRunResult {
172
204
  ok: true;
173
205
  invocation: CliInvocation;
174
206
  config: RuntimeConfig;
175
207
  }
176
- declare function runCli(rawArgs: string[]): CliRunResult;
177
- declare const dependfixCommand: import("citty").CommandDef<{
208
+ export declare function runCli(rawArgs: string[]): CliRunResult;
209
+ export declare const dependfixCommand: import("citty").CommandDef<{
178
210
  mode: {
179
211
  type: "positional";
180
212
  description: string;
@@ -257,6 +289,11 @@ declare const dependfixCommand: import("citty").CommandDef<{
257
289
  description: string;
258
290
  negativeDescription: string;
259
291
  };
292
+ 'code-quality': {
293
+ type: "boolean";
294
+ description: string;
295
+ negativeDescription: string;
296
+ };
260
297
  'allow-major-upgrade': {
261
298
  type: "boolean";
262
299
  description: string;
@@ -282,6 +319,11 @@ declare const dependfixCommand: import("citty").CommandDef<{
282
319
  description: string;
283
320
  default: "30000";
284
321
  };
322
+ 'max-repos': {
323
+ type: "string";
324
+ description: string;
325
+ default: "100";
326
+ };
285
327
  history: {
286
328
  type: "string";
287
329
  description: string;
@@ -332,7 +374,7 @@ declare const dependfixCommand: import("citty").CommandDef<{
332
374
  description: string;
333
375
  };
334
376
  }>;
335
- declare function runDependfixMain(rawArgs?: string[]): Promise<void>;
377
+ export declare function runDependfixMain(rawArgs?: string[]): Promise<void>;
336
378
  //#endregion
337
379
  //#region src/app/pipeline.d.ts
338
380
  interface PipelineLogger {
@@ -366,13 +408,13 @@ interface Pipeline {
366
408
  /** 执行一次完整运行(含 history 查询分支),返回退出码 */
367
409
  run(rawArgs: string[]): Promise<number>;
368
410
  }
369
- declare function createPipeline(deps?: PipelineDeps): Pipeline;
411
+ export declare function createPipeline(deps?: PipelineDeps): Pipeline;
370
412
  //#endregion
371
413
  //#region src/index.d.ts
372
414
  /**
373
415
  * 简化调用的入口(内部数据处理,非 CLI 使用)。
374
416
  */
375
- declare function main(args?: string[]): CliRunResult;
417
+ export declare function main(args?: string[]): CliRunResult;
376
418
  //#endregion
377
- export { CliInvocation, CliRunResult, type Pipeline, type PipelineDeps, type PipelineLogger, type PipelineParseResult, argsDef, createPipeline, dependfixCommand, main, parseCliArgs, runCli, runDependfixMain };
419
+ export type { Pipeline, PipelineDeps, PipelineLogger, PipelineParseResult };
378
420
  //# sourceMappingURL=index.d.mts.map
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { a as argsDef, i as createPipeline, n as runCli, o as parseCliArgs, r as runDependfixMain, t as dependfixCommand } from "./runner.mjs";
1
+ import { a as appendRepositories, c as isRuntimeMode, d as parseCliArgs, f as parseCommandsFlag, i as createPipeline, l as isSeverityThreshold, m as parseUpgradeGroupsFlag, n as runCli, o as argsDef, p as parseIntegerFlag, r as runDependfixMain, s as isAlertSource, t as dependfixCommand, u as normalizeFlagList } from "./runner.mjs";
2
2
  import { pathToFileURL } from "node:url";
3
3
  import { toAppError } from "@dependfix/core";
4
4
 
@@ -25,5 +25,5 @@ if (isExecutedAsEntryPoint()) runDependfixMain().catch((error) => {
25
25
  });
26
26
 
27
27
  //#endregion
28
- export { argsDef, createPipeline, dependfixCommand, main, parseCliArgs, runCli, runDependfixMain };
28
+ export { appendRepositories, argsDef, createPipeline, dependfixCommand, isAlertSource, isRuntimeMode, isSeverityThreshold, main, normalizeFlagList, parseCliArgs, parseCommandsFlag, parseIntegerFlag, parseUpgradeGroupsFlag, runCli, runDependfixMain };
29
29
  //# sourceMappingURL=index.mjs.map
package/dist/runner.mjs CHANGED
@@ -95,6 +95,11 @@ const argsDef = {
95
95
  description: "同时拉取 Code Scanning alerts(与 Dependabot 并行,默认关闭;需要 token 具备 security-events: read,GITHUB_TOKEN 默认具备)",
96
96
  negativeDescription: "不拉取 Code Scanning alerts(默认)"
97
97
  },
98
+ "code-quality": {
99
+ type: "boolean",
100
+ description: "同时拉取 Code Quality findings(与 Dependabot 并行,默认关闭;需要 fine-grained PAT 具备 Code quality: read,或 classic PAT 具备 repo/public_repo scope)",
101
+ negativeDescription: "不拉取 Code Quality findings(默认)"
102
+ },
98
103
  "allow-major-upgrade": {
99
104
  type: "boolean",
100
105
  description: "跨线告警(推荐版本跨大版本,当前线内无修复版本)显式授权自动升级:仅根 package.json 直接依赖(workspace 成员独占声明维持人工)且 lockfile 单版本的告警自动跨线升级,升级后复核脆弱实例、强制完整验证(install+lint+build),失败自动回滚;间接依赖 / 多版本共存跨线告警维持人工处理。仅 CLI 可用,Action 不支持",
@@ -120,6 +125,11 @@ const argsDef = {
120
125
  description: "限流退避单次等待上限毫秒(100-120000,默认 30000;Retry-After / reset / 指数退避均受此约束)",
121
126
  default: "30000"
122
127
  },
128
+ "max-repos": {
129
+ type: "string",
130
+ description: "发现规模上限:最多保留的仓库数(默认 100;0 或负数表示不限制;大 org 场景下防止一次性全量发现)",
131
+ default: "100"
132
+ },
123
133
  history: {
124
134
  type: "string",
125
135
  description: "查询仓库历史运行摘要(读 dependfix-reports/index.json,倒序时间;不执行扫描)"
@@ -246,6 +256,7 @@ function parsedArgsToCliOverrides(parsed) {
246
256
  overrides.alertSource = alertsSource;
247
257
  }
248
258
  if (parsed["code-scanning"] !== void 0) overrides.codeScanningEnabled = parsed["code-scanning"];
259
+ if (parsed["code-quality"] !== void 0) overrides.codeQualityEnabled = parsed["code-quality"];
249
260
  if (parsed["allow-major-upgrade"] !== void 0) overrides.allowMajorUpgrade = parsed["allow-major-upgrade"];
250
261
  const maxAlerts = parsed["max-alerts-per-repository"];
251
262
  if (maxAlerts) overrides.maxAlertsPerRepository = parseIntegerFlag(maxAlerts, "--max-alerts-per-repository", "Expected a positive integer.");
@@ -255,6 +266,8 @@ function parsedArgsToCliOverrides(parsed) {
255
266
  if (maxRetries) overrides.maxRetries = parseIntegerFlag(maxRetries, "--max-retries", "Expected an integer between 0 and 10.");
256
267
  const maxBackoffMs = parsed["max-backoff-ms"];
257
268
  if (maxBackoffMs) overrides.maxBackoffMs = parseIntegerFlag(maxBackoffMs, "--max-backoff-ms", "Expected an integer between 100 and 120000.");
269
+ const maxRepos = parsed["max-repos"];
270
+ if (maxRepos) overrides.maxRepos = parseIntegerFlag(maxRepos, "--max-repos", "Expected a non-negative integer (0 = unlimited).");
258
271
  const history = parsed.history;
259
272
  if (history) overrides.history = history;
260
273
  if (parsed.verbose !== void 0) overrides.verbose = parsed.verbose;
@@ -788,5 +801,5 @@ async function runDependfixMain(rawArgs = process.argv.slice(2)) {
788
801
  }
789
802
 
790
803
  //#endregion
791
- export { argsDef as a, createPipeline as i, runCli as n, parseCliArgs as o, runDependfixMain as r, dependfixCommand as t };
804
+ export { appendRepositories as a, isRuntimeMode as c, parseCliArgs as d, parseCommandsFlag as f, createPipeline as i, isSeverityThreshold as l, parseUpgradeGroupsFlag as m, runCli as n, argsDef as o, parseIntegerFlag as p, runDependfixMain as r, isAlertSource as s, dependfixCommand as t, normalizeFlagList as u };
792
805
  //# sourceMappingURL=runner.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"runner.mjs","names":[],"sources":["../src/cli/index.ts","../src/app/pipeline.ts","../src/skills/agents.ts","../src/skills/source.ts","../src/skills/installer.ts","../src/skills/doctor.ts","../src/skills/index.ts","../src/cli/runner.ts"],"sourcesContent":["import {\n parseArgs,\n type ArgsDef,\n type ParsedArgs,\n} from 'citty'\nimport { AppError, isValidRepoIdentifier } from '@dependfix/core'\nimport {\n type CliConfigOverrides,\n type RuntimeMode,\n type SeverityThreshold,\n type AlertSourceKind,\n RUNTIME_MODES,\n SEVERITY_THRESHOLDS,\n ALERT_SOURCES,\n} from '@dependfix/engine'\n// ---------------------------------------------------------------------------\n// Public interfaces\n// ---------------------------------------------------------------------------\n\nexport interface CliInvocation {\n mode?: RuntimeMode\n configOverrides: CliConfigOverrides\n rawArgs: string[]\n}\n\n// ---------------------------------------------------------------------------\n// Args definition for citty\n// ---------------------------------------------------------------------------\n\nexport const argsDef = {\n mode: {\n type: 'positional' as const,\n description: '运行模式:report-only, fix, fix-and-pr, cleanup-branches',\n required: false,\n default: 'report-only' as const,\n },\n repo: {\n type: 'string' as const,\n description: '目标仓库 (owner/repo),逗号分隔多个',\n alias: ['r', 'repository', 'repositories'],\n },\n 'repos-file': {\n type: 'string' as const,\n description: '从文件读取仓库列表(每行一个 owner/repo)',\n },\n owner: {\n type: 'string' as const,\n description: 'owner / org 自动发现(逗号分隔多个或多次传入),与 --repo 合并去重(显式优先)',\n },\n 'repo-topics': {\n type: 'string' as const,\n description: '发现结果 topic 白名单(逗号分隔,AND 语义;仅影响 --owner 发现结果)',\n },\n 'repo-include': {\n type: 'string' as const,\n description: '仓库白名单 glob(逗号分隔多个或多次传入,如 owner/*、owner/pkg-*;仅作用于发现结果)',\n },\n 'repo-exclude': {\n type: 'string' as const,\n description: '仓库黑名单 glob(逗号分隔多个或多次传入;显式列表与发现结果均受约束,与 include 冲突时胜出)',\n },\n 'repo-topics-exclude': {\n type: 'string' as const,\n description: '发现结果 topic 黑名单(逗号分隔,排除含任一指定 topic 的仓库)',\n },\n 'severity-threshold': {\n type: 'string' as const,\n description: '严重级别阈值:critical, high, medium, all',\n default: 'high' as const,\n },\n 'dry-run': {\n type: 'boolean' as const,\n description: '试运行模式,不实际写入文件',\n negativeDescription: '关闭试运行模式',\n },\n 'create-pr': {\n type: 'boolean' as const,\n description: '创建 Pull Request',\n negativeDescription: '不创建 Pull Request',\n },\n commit: {\n type: 'boolean' as const,\n description: '修复完成后在本地当前分支直接提交(不推送、不创建 PR)',\n negativeDescription: '不自动提交(默认)',\n },\n 'cleanup-branches': {\n type: 'boolean' as const,\n description: '(fix-and-pr 模式)结束后列出已合并的 dependfix 分支到报告,不自动删除',\n negativeDescription: '不执行分支清理检查',\n },\n 'cleanup-branches-auto': {\n type: 'boolean' as const,\n description: '(fix-and-pr 模式)结束后自动删除已合并/已关闭的 dependfix 分支(非交互,不删有 open PR 的分支)',\n negativeDescription: '不自动删除分支',\n },\n 'github-token': {\n type: 'string' as const,\n description: 'GitHub Personal Access Token',\n },\n 'alerts-token': {\n type: 'string' as const,\n description: 'Dependabot alerts 专用 token(可选,最小权限 PAT,仅 Dependabot alerts: read;缺省回退 --github-token。GITHUB_TOKEN 无法读取 Dependabot alerts)',\n },\n 'alerts-source': {\n type: 'string' as const,\n description: '告警数据源:github-dependabot(默认,GitHub Dependabot alerts API)或 pnpm-audit(本地无 token 回退,扫描当前工作区 lockfile;repository 优先 --repo → git remote → local 兜底)',\n },\n 'code-scanning': {\n type: 'boolean' as const,\n description: '同时拉取 Code Scanning alerts(与 Dependabot 并行,默认关闭;需要 token 具备 security-events: read,GITHUB_TOKEN 默认具备)',\n negativeDescription: '不拉取 Code Scanning alerts(默认)',\n },\n 'allow-major-upgrade': {\n type: 'boolean' as const,\n description: '跨线告警(推荐版本跨大版本,当前线内无修复版本)显式授权自动升级:仅根 package.json 直接依赖(workspace 成员独占声明维持人工)且 lockfile 单版本的告警自动跨线升级,升级后复核脆弱实例、强制完整验证(install+lint+build),失败自动回滚;间接依赖 / 多版本共存跨线告警维持人工处理。仅 CLI 可用,Action 不支持',\n negativeDescription: '不自动升级跨线告警(默认,维持人工处理)',\n },\n 'max-alerts-per-repository': {\n type: 'string' as const,\n description: '每个仓库最多处理的告警数',\n default: '20' as const,\n },\n 'max-concurrency': {\n type: 'string' as const,\n description: '多仓库并发窗口(1-16,默认 1 保守串行;>1 可能触发 GitHub 限流)',\n default: '1' as const,\n },\n 'max-retries': {\n type: 'string' as const,\n description: 'GitHub API 限流重试次数(0-10,默认 3;429/rate limit 指数退避重试)',\n default: '3' as const,\n },\n 'max-backoff-ms': {\n type: 'string' as const,\n description: '限流退避单次等待上限毫秒(100-120000,默认 30000;Retry-After / reset / 指数退避均受此约束)',\n default: '30000' as const,\n },\n history: {\n type: 'string' as const,\n description: '查询仓库历史运行摘要(读 dependfix-reports/index.json,倒序时间;不执行扫描)',\n },\n 'upgrade-groups': {\n type: 'string' as const,\n description: '用户显式分组(覆盖自动分组),格式 \"name1:pkg1,pkg2;name2:pkg3\"',\n },\n 'toolchain-pnpm-version': {\n type: 'string' as const,\n description: 'lockfile 修复用的 pnpm 版本(工具链固定;缺省从 package.json packageManager 解析;PIN_TOOLCHAIN 策略用 corepack pnpm@<version> 执行)',\n },\n commands: {\n type: 'string' as const,\n description: '自定义验证命令(逗号分隔),覆盖默认的 install/lint/build',\n },\n verbose: {\n type: 'boolean' as const,\n description: '输出详细日志',\n },\n ai: {\n type: 'boolean' as const,\n description: '开启 AI breaking change 研判(默认关闭;需配置 AI API Key。触发范围见 --ai-trigger;dry-run 不触发、不产生费用)',\n negativeDescription: '关闭 AI 研判(默认)',\n },\n 'ai-provider': {\n type: 'string' as const,\n description: 'AI 提供商:openai-compatible(默认,DeepSeek 等指定 --ai-base-url 兼容)或 anthropic',\n },\n 'ai-model': {\n type: 'string' as const,\n description: 'AI 模型名(默认 deepseek-v4-flash)',\n },\n 'ai-base-url': {\n type: 'string' as const,\n description: 'OpenAI 兼容端点基地址(默认 https://api.deepseek.com,与默认模型 deepseek-v4-flash 配套;使用 OpenAI 官方模型时指定 https://api.openai.com/v1 + --ai-model)',\n },\n 'ai-api-url': {\n type: 'string' as const,\n description: 'Anthropic 兼容端点(仅 --ai-provider anthropic 生效;默认 https://api.anthropic.com/v1/messages,自托管/网关可显式指定)',\n },\n 'ai-api-key': {\n type: 'string' as const,\n description: 'AI API Key(优先 DEPENDFIX_AI_API_KEY env;注意命令行参数会出现在进程列表/shell history,敏感环境请用 env)',\n },\n 'ai-trigger': {\n type: 'string' as const,\n description: 'AI 研判触发范围:failure(升级验证失败)/ major(major 升级)/ both(默认)',\n },\n} satisfies ArgsDef\n\n// ---------------------------------------------------------------------------\n// Conversion helpers\n// ---------------------------------------------------------------------------\n\nfunction isRuntimeMode(value: string): value is RuntimeMode {\n return RUNTIME_MODES.includes(value as RuntimeMode)\n}\n\nfunction isSeverityThreshold(value: string): value is SeverityThreshold {\n return SEVERITY_THRESHOLDS.includes(value as SeverityThreshold)\n}\n\nfunction isAlertSource(value: string): value is AlertSourceKind {\n return ALERT_SOURCES.includes(value as AlertSourceKind)\n}\n\nfunction appendRepositories(target: string[], value: string): void {\n for (const repository of value.split(',')) {\n const trimmed = repository.trim()\n\n if (!trimmed) {\n continue\n }\n\n if (!isValidRepoIdentifier(trimmed)) {\n throw new AppError(\n 'ARGUMENT_PARSE_ERROR',\n `Invalid repository identifier: \"${trimmed}\". Expected format: owner/repo`,\n )\n }\n\n target.push(trimmed)\n }\n}\n\nfunction parseCommandsFlag(value: string): string[] {\n return value\n .split(',')\n .map((cmd) => cmd.trim())\n .filter(Boolean)\n}\n\n/**\n * 严格整数字面量解析(修复:拒绝 `2.5` 被 parseInt 静默截断为 2)。\n * 仅接受 `^\\d+$`;范围语义由调用方在 expected 描述中声明(config 校验兜底)。\n */\nfunction parseIntegerFlag(value: string, flagName: string, expected: string): number {\n const trimmed = value.trim()\n if (!/^\\d+$/.test(trimmed)) {\n throw new AppError(\n 'ARGUMENT_PARSE_ERROR',\n `Invalid ${flagName} value: \"${value}\". ${expected}`,\n )\n }\n return Number.parseInt(trimmed, 10)\n}\n\n/**\n * 归一化可重复 flag 值(citty/mri 对重复传入返回数组,单次传入返回字符串):\n * 按逗号拆分 + 去空白 + 去空项。`--owner a,b --owner c` → ['a', 'b', 'c']。\n */\nfunction normalizeFlagList(value: string | string[] | undefined): string[] {\n if (value === undefined) {\n return []\n }\n const parts = Array.isArray(value) ? value : [value]\n return parts\n .flatMap((v) => v.split(','))\n .map((s) => s.trim())\n .filter(Boolean)\n}\n\nfunction parsedArgsToCliOverrides(parsed: ParsedArgs<typeof argsDef>): CliConfigOverrides {\n const overrides: CliConfigOverrides = {}\n\n // mode\n const rawMode = parsed.mode\n if (isRuntimeMode(rawMode)) {\n overrides.mode = rawMode\n }\n\n // repositories (from --repo / --repository)\n const repoValue = parsed.repo\n if (repoValue) {\n const repos: string[] = []\n appendRepositories(repos, repoValue)\n if (repos.length > 0) {\n overrides.repositories = repos\n }\n }\n\n // repos-file\n const reposFile = parsed['repos-file']\n if (reposFile) {\n overrides.reposFilePath = reposFile\n }\n\n // owner(自动发现;逗号分隔多个或多次传入)\n const ownerValue = normalizeFlagList(parsed.owner)\n if (ownerValue.length > 0) {\n overrides.owner = ownerValue\n }\n\n // repo-topics(发现结果 topic 白名单,AND 语义)\n const repoTopicsValue = normalizeFlagList(parsed['repo-topics'])\n if (repoTopicsValue.length > 0) {\n overrides.repoTopics = repoTopicsValue\n }\n\n // repo-include / repo-exclude / repo-topics-exclude(名单策略)\n const repoIncludeValue = normalizeFlagList(parsed['repo-include'])\n if (repoIncludeValue.length > 0) {\n overrides.repoInclude = repoIncludeValue\n }\n const repoExcludeValue = normalizeFlagList(parsed['repo-exclude'])\n if (repoExcludeValue.length > 0) {\n overrides.repoExclude = repoExcludeValue\n }\n const repoTopicsExcludeValue = normalizeFlagList(parsed['repo-topics-exclude'])\n if (repoTopicsExcludeValue.length > 0) {\n overrides.repoTopicsExclude = repoTopicsExcludeValue\n }\n\n // severity-threshold\n const severityThreshold = parsed['severity-threshold']\n if (isSeverityThreshold(severityThreshold)) {\n overrides.severityThreshold = severityThreshold\n }\n\n // dry-run (three-state: true / false / undefined)\n if (parsed['dry-run'] !== undefined) {\n overrides.dryRun = parsed['dry-run']\n }\n\n // create-pr (three-state: true / false / undefined)\n if (parsed['create-pr'] !== undefined) {\n overrides.createPullRequest = parsed['create-pr']\n }\n\n // commit (three-state: true / false / undefined)\n if (parsed.commit !== undefined) {\n overrides.commit = parsed.commit\n }\n\n // cleanup-branches (three-state: true / false / undefined)\n if (parsed['cleanup-branches'] !== undefined) {\n overrides.cleanupBranches = parsed['cleanup-branches']\n }\n\n // cleanup-branches-auto (three-state: true / false / undefined)\n if (parsed['cleanup-branches-auto'] !== undefined) {\n overrides.cleanupBranchesAuto = parsed['cleanup-branches-auto']\n }\n\n // github-token\n const githubToken = parsed['github-token']\n if (githubToken) {\n overrides.githubToken = githubToken\n }\n\n // alerts-token\n const alertsToken = parsed['alerts-token']\n if (alertsToken) {\n overrides.alertsToken = alertsToken\n }\n\n // alerts-source\n const alertsSource = parsed['alerts-source']\n if (alertsSource) {\n if (!isAlertSource(alertsSource)) {\n throw new AppError(\n 'ARGUMENT_PARSE_ERROR',\n `Invalid --alerts-source value: \"${alertsSource}\". Expected one of: ${ALERT_SOURCES.join(', ')}.`,\n )\n }\n overrides.alertSource = alertsSource\n }\n\n // code-scanning (three-state: true / false / undefined)\n if (parsed['code-scanning'] !== undefined) {\n overrides.codeScanningEnabled = parsed['code-scanning']\n }\n\n // allow-major-upgrade (three-state: true / false / undefined; 无 env 通道,仅 CLI)\n if (parsed['allow-major-upgrade'] !== undefined) {\n overrides.allowMajorUpgrade = parsed['allow-major-upgrade']\n }\n\n // max-alerts-per-repository\n const maxAlerts = parsed['max-alerts-per-repository']\n if (maxAlerts) {\n overrides.maxAlertsPerRepository = parseIntegerFlag(maxAlerts, '--max-alerts-per-repository', 'Expected a positive integer.')\n }\n\n // max-concurrency(1-16,config 校验兜底)\n const maxConcurrency = parsed['max-concurrency']\n if (maxConcurrency) {\n overrides.maxConcurrency = parseIntegerFlag(maxConcurrency, '--max-concurrency', 'Expected an integer between 1 and 16.')\n }\n\n // max-retries(0-10,config 校验兜底)\n const maxRetries = parsed['max-retries']\n if (maxRetries) {\n overrides.maxRetries = parseIntegerFlag(maxRetries, '--max-retries', 'Expected an integer between 0 and 10.')\n }\n\n // max-backoff-ms(100-120000,config 校验兜底)\n const maxBackoffMs = parsed['max-backoff-ms']\n if (maxBackoffMs) {\n overrides.maxBackoffMs = parseIntegerFlag(maxBackoffMs, '--max-backoff-ms', 'Expected an integer between 100 and 120000.')\n }\n\n // history(独立查询命令,不进入运行配置)\n const history = parsed.history\n if (history) {\n overrides.history = history\n }\n\n // verbose (three-state: true / false / undefined)\n if (parsed.verbose !== undefined) {\n overrides.verbose = parsed.verbose\n }\n\n // commands\n const commandsValue = parsed.commands\n if (commandsValue) {\n overrides.commands = parseCommandsFlag(commandsValue)\n }\n\n // upgrade-groups\n const upgradeGroups = parsed['upgrade-groups']\n if (upgradeGroups) {\n overrides.upgradeGroups = parseUpgradeGroupsFlag(upgradeGroups)\n }\n\n // toolchain-pnpm-version\n const toolchainPnpmVersion = parsed['toolchain-pnpm-version']\n if (toolchainPnpmVersion) {\n overrides.toolchainPnpmVersion = toolchainPnpmVersion\n }\n\n // AI 研判(--ai 系列;--ai-api-key 为敏感参数,env 优先)\n if (parsed.ai !== undefined) {\n overrides.aiEnabled = parsed.ai\n }\n const aiProvider = parsed['ai-provider']\n if (aiProvider) {\n if (aiProvider !== 'openai-compatible' && aiProvider !== 'anthropic') {\n throw new AppError(\n 'ARGUMENT_PARSE_ERROR',\n `Invalid --ai-provider value: \"${aiProvider}\". Expected \"openai-compatible\" or \"anthropic\".`,\n )\n }\n overrides.aiProvider = aiProvider\n }\n const aiModel = parsed['ai-model']\n if (aiModel) {\n overrides.aiModel = aiModel\n }\n const aiBaseUrl = parsed['ai-base-url']\n if (aiBaseUrl) {\n overrides.aiBaseUrl = aiBaseUrl\n }\n const aiApiUrl = parsed['ai-api-url']\n if (aiApiUrl) {\n overrides.aiApiUrl = aiApiUrl\n }\n const aiApiKey = parsed['ai-api-key']\n if (aiApiKey) {\n overrides.aiApiKey = aiApiKey\n }\n const aiTrigger = parsed['ai-trigger']\n if (aiTrigger) {\n if (aiTrigger !== 'failure' && aiTrigger !== 'major' && aiTrigger !== 'both') {\n throw new AppError(\n 'ARGUMENT_PARSE_ERROR',\n `Invalid --ai-trigger value: \"${aiTrigger}\". Expected \"failure\", \"major\" or \"both\".`,\n )\n }\n overrides.aiTrigger = aiTrigger\n }\n\n return overrides\n}\n\n/**\n * 解析 `--upgrade-groups \"name1:pkg1,pkg2;name2:pkg3\"`。\n * 与 config 的 normalizeUpgradeGroups 保持一致(CLI 与 env 同格式):\n * 空 entry 忽略;非空但缺冒号/组名或包列表为空 → 抛 ARGUMENT_PARSE_ERROR;\n * 原型链风险键名(__proto__ / constructor / prototype)忽略。\n */\nfunction parseUpgradeGroupsFlag(value: string): Record<string, string[]> {\n const result: Record<string, string[]> = {}\n for (const entry of value.split(';')) {\n if (!entry.trim()) {\n continue\n }\n const idx = entry.indexOf(':')\n if (idx <= 0) {\n throw new AppError(\n 'ARGUMENT_PARSE_ERROR',\n `Invalid --upgrade-groups entry: \"${entry}\". Expected format: \"name:pkg1,pkg2\"`,\n )\n }\n const name = entry.slice(0, idx).trim()\n const pkgs = entry\n .slice(idx + 1)\n .split(',')\n .map((p) => p.trim())\n .filter(Boolean)\n if (name === '__proto__' || name === 'constructor' || name === 'prototype') {\n continue\n }\n if (!name || pkgs.length === 0) {\n throw new AppError(\n 'ARGUMENT_PARSE_ERROR',\n `Invalid --upgrade-groups entry: \"${entry}\". Expected format: \"name:pkg1,pkg2\"`,\n )\n }\n result[name] = pkgs\n }\n return result\n}\n\n// ---------------------------------------------------------------------------\n// Parsing API\n// ---------------------------------------------------------------------------\n\nexport function parseCliArgs(rawArgs: string[]): CliInvocation {\n const parsed = parseArgs<typeof argsDef>(rawArgs, argsDef)\n const configOverrides = parsedArgsToCliOverrides(parsed)\n\n return {\n mode: configOverrides.mode,\n configOverrides,\n rawArgs: [...rawArgs],\n }\n}\n","// 平台化管线抽象(独立平台前置):\n// local(CLI)与 platform 模式共用同一编排核心——参数解析 → 配置解析 →\n// DependfixApp.run → 退出码。process.env / console / process.exitCode\n// 全部经 PipelineDeps 注入,platform 可替换 env / logger / config resolver / exit。\n\nimport { resolveRuntimeConfig, queryRepoHistory, formatHistory, DependfixApp, type CliConfigOverrides } from '@dependfix/engine'\nimport { parseCliArgs, type CliInvocation } from '../cli'\n\nexport interface PipelineLogger {\n info(msg: string): void\n error(msg: string): void\n}\n\nexport interface PipelineDeps {\n /** 环境变量来源(默认 process.env)——platform 模式注入自定义 env */\n env?: NodeJS.ProcessEnv\n /** 日志输出(默认 console)——platform 模式注入自定义 logger */\n logger?: PipelineLogger\n /**\n * 配置解析(默认 resolveRuntimeConfig)。\n * platform 模式可注入自定义解析(如从数据库读取配置再合并 env)。\n */\n resolveConfig?: (opts: { env: NodeJS.ProcessEnv, cliOverrides: CliConfigOverrides }) => ReturnType<typeof resolveRuntimeConfig>\n /** 退出码设置(默认 process.exitCode)——platform 模式注入 */\n exit?: (code: number) => void\n}\n\nexport interface PipelineParseResult {\n ok: true\n invocation: CliInvocation\n config: ReturnType<typeof resolveRuntimeConfig>\n}\n\nexport interface Pipeline {\n /** 解析参数并解析配置(不执行扫描) */\n parse(rawArgs: string[]): PipelineParseResult\n /** 执行一次完整运行(含 history 查询分支),返回退出码 */\n run(rawArgs: string[]): Promise<number>\n}\n\nexport function createPipeline(deps: PipelineDeps = {}): Pipeline {\n const env = deps.env ?? process.env\n const logger = deps.logger ?? console\n const resolveConfig = deps.resolveConfig ?? ((opts: { env: NodeJS.ProcessEnv, cliOverrides: CliConfigOverrides }) => resolveRuntimeConfig(opts))\n const exit = deps.exit ?? ((code: number) => {\n process.exitCode = code\n })\n\n return {\n parse(rawArgs: string[]): PipelineParseResult {\n const invocation = parseCliArgs(rawArgs)\n const config = resolveConfig({ env, cliOverrides: invocation.configOverrides })\n return { ok: true, invocation, config }\n },\n\n async run(rawArgs: string[]): Promise<number> {\n const invocation = parseCliArgs(rawArgs)\n\n // --history:独立查询命令(读归档索引,不执行扫描、不要求 token/仓库配置)\n if (invocation.configOverrides.history) {\n const entries = queryRepoHistory(invocation.configOverrides.history)\n logger.info(formatHistory(entries, invocation.configOverrides.history))\n return 0\n }\n\n const config = resolveConfig({ env, cliOverrides: invocation.configOverrides })\n const app = new DependfixApp({\n config,\n verbose: invocation.configOverrides.verbose,\n commands: invocation.configOverrides.commands,\n })\n\n const { exitCode } = await app.run()\n exit(exitCode)\n return exitCode\n },\n }\n}\n","// ---------------------------------------------------------------------------\n// Agent 目录约定与检测\n// ---------------------------------------------------------------------------\n// 目录约定与 npx skills 生态对齐(vercel-labs/skills agents 定义):\n// - claude-code: 项目 .claude/skills,全局 ~/.claude/skills\n// - opencode: 项目 .agents/skills,全局 ~/.config/opencode/skills\n// - cursor: 项目 .cursor/skills,全局 ~/.cursor/skills\n// - copilot: 全局 ~/.copilot/skills(GitHub Copilot 无通用项目级目录约定)\n// 检测 = 对应主目录存在(存在即视为已安装该工具)。\n// homedir / projectRoot 均由调用方注入,便于测试。\n\nimport { existsSync } from 'node:fs'\nimport { join } from 'node:path'\n\nexport interface AgentDefinition {\n id: string\n displayName: string\n /** 项目级 skills 目录(相对项目根);不支持返回 undefined */\n projectSkillDir(projectRoot: string): string | undefined\n /** 用户级 skills 目录(绝对路径) */\n globalSkillDir(homeDir: string): string\n /** 检测是否已安装(对应主目录是否存在) */\n detectInstalled(homeDir: string): boolean\n}\n\nexport const AGENTS: AgentDefinition[] = [\n {\n id: 'claude-code',\n displayName: 'Claude Code',\n projectSkillDir: (root) => join(root, '.claude', 'skills'),\n globalSkillDir: (home) => join(home, '.claude', 'skills'),\n detectInstalled: (home) => existsSync(join(home, '.claude')),\n },\n {\n id: 'opencode',\n displayName: 'OpenCode',\n projectSkillDir: (root) => join(root, '.agents', 'skills'),\n globalSkillDir: (home) => join(home, '.config', 'opencode', 'skills'),\n detectInstalled: (home) => existsSync(join(home, '.config', 'opencode')),\n },\n {\n id: 'cursor',\n displayName: 'Cursor',\n projectSkillDir: (root) => join(root, '.cursor', 'skills'),\n globalSkillDir: (home) => join(home, '.cursor', 'skills'),\n detectInstalled: (home) => existsSync(join(home, '.cursor')),\n },\n {\n id: 'copilot',\n displayName: 'GitHub Copilot',\n projectSkillDir: () => undefined,\n globalSkillDir: (home) => join(home, '.copilot', 'skills'),\n detectInstalled: (home) => existsSync(join(home, '.copilot')),\n },\n]\n","// ---------------------------------------------------------------------------\n// 产品 skill 内容来源定位\n// ---------------------------------------------------------------------------\n// dependfix-remediator 权威源随 npm 包 @dependfix/skills 发布(files: dependfix-remediator)。\n// CLI 依赖该包,运行时通过 require.resolve 定位包内 skill 目录:\n// - 开发(tsx):workspace 链接解析到 packages/skills/dependfix-remediator\n// - 发布(npx dependfix):node_modules 中解析 @dependfix/skills/dependfix-remediator\n\nimport { createRequire } from 'node:module'\nimport { dirname, join } from 'node:path'\n\nexport const PRODUCT_SKILL_NAME = 'dependfix-remediator'\n\n/**\n * 解析产品 skill 内容目录(含 SKILL.md 的目录)。\n * 找不到包或内容目录时抛错(install / doctor 的必要前置)。\n */\nexport function resolveProductSkillSourceDir(): string {\n const require = createRequire(import.meta.url)\n const pkgJsonPath = require.resolve('@dependfix/skills/package.json')\n return join(dirname(pkgJsonPath), PRODUCT_SKILL_NAME)\n}\n","// ---------------------------------------------------------------------------\n// 产品 skill 安装器(dependfix skills install 核心)\n// ---------------------------------------------------------------------------\n// 语义:\n// - 目标不存在 → 创建并复制(installed)\n// - 目标已存在且内容一致 → 跳过(up-to-date,幂等)\n// - 目标已存在但内容不一致 → 覆盖需确认(force 或交互确认;拒绝则 skipped-conflict)\n// - dry-run 只输出将要执行的操作,不写文件\n// 覆盖采用镜像语义:删除旧内容后全量复制,保证与权威源严格一致。\n\nimport { createHash } from 'node:crypto'\nimport { cpSync, existsSync, mkdirSync, readdirSync, readFileSync, rmSync, statSync } from 'node:fs'\nimport { join } from 'node:path'\nimport { PRODUCT_SKILL_NAME } from './source'\n\nexport type InstallStatus = 'installed' | 'up-to-date' | 'skipped-conflict' | 'failed'\n\nexport interface InstallResult {\n status: InstallStatus\n /** 安装目标目录(依赖 fix-and-pr 模式外,本为 dependfix-remediator 目录) */\n targetDir: string\n detail?: string\n}\n\nexport interface InstallOptions {\n /** 权威源内容目录(含 SKILL.md) */\n sourceDir: string\n /** 目标 agent skills 目录(dependfix-remediator 将位于其下) */\n targetDir: string\n /** 强制覆盖(跳过确认) */\n force?: boolean\n /** 试运行:只输出将要执行的操作 */\n dryRun?: boolean\n /** 覆盖确认回调;缺省返回 false(非交互默认拒绝,不静默覆盖) */\n confirmOverwrite?: (existingDir: string) => Promise<boolean> | boolean\n}\n\n/** 收集目录内文件相对路径 -> sha256(递归) */\nexport function collectFileHashes(dir: string): Map<string, string> {\n const result = new Map<string, string>()\n if (!existsSync(dir)) {\n return result\n }\n const walk = (current: string, relPrefix: string) => {\n for (const entry of readdirSync(current, { withFileTypes: true })) {\n const full = join(current, entry.name)\n const rel = relPrefix ? `${relPrefix}/${entry.name}` : entry.name\n if (entry.isDirectory()) {\n walk(full, rel)\n } else if (entry.isFile()) {\n result.set(rel, hashFile(full))\n }\n }\n }\n walk(dir, '')\n return result\n}\n\nfunction hashFile(filePath: string): string {\n return createHash('sha256').update(readFileSync(filePath)).digest('hex')\n}\n\n/** 两个目录内容是否完全一致(文件集合 + 内容 hash) */\nexport function isContentSame(dirA: string, dirB: string): boolean {\n const mapA = collectFileHashes(dirA)\n const mapB = collectFileHashes(dirB)\n if (mapA.size !== mapB.size) {\n return false\n }\n for (const [rel, hash] of mapA) {\n if (mapB.get(rel) !== hash) {\n return false\n }\n }\n return true\n}\n\n/** 复制目录(镜像语义:先清空目标内同名子目录再复制) */\nfunction mirrorCopy(sourceDir: string, targetSkillDir: string): void {\n rmSync(targetSkillDir, { recursive: true, force: true })\n mkdirSync(targetSkillDir, { recursive: true })\n for (const entry of readdirSync(sourceDir)) {\n const src = join(sourceDir, entry)\n const dst = join(targetSkillDir, entry)\n if (statSync(src).isDirectory()) {\n cpSync(src, dst, { recursive: true })\n } else {\n cpSync(src, dst)\n }\n }\n}\n\n/**\n * 安装产品 skill 到单个 agent skills 目录。\n * 返回 InstallResult;失败时 status='failed' 且 detail 含错误信息(不抛错,便于批量收尾)。\n */\nexport async function installSkillToDir(options: InstallOptions): Promise<InstallResult> {\n const { sourceDir, targetDir, force, dryRun, confirmOverwrite } = options\n const skillTarget = join(targetDir, PRODUCT_SKILL_NAME)\n\n if (!existsSync(sourceDir)) {\n return { status: 'failed', targetDir, detail: `权威源不存在: ${sourceDir}` }\n }\n\n if (dryRun) {\n try {\n const same = existsSync(skillTarget) && isContentSame(sourceDir, skillTarget)\n return same\n ? { status: 'up-to-date', targetDir, detail: '[dry-run] 已一致' }\n : { status: 'installed', targetDir, detail: '[dry-run] 将安装' }\n } catch (error: unknown) {\n return { status: 'failed', targetDir, detail: errorMessage(error) }\n }\n }\n\n if (!existsSync(skillTarget)) {\n try {\n mirrorCopy(sourceDir, skillTarget)\n return { status: 'installed', targetDir }\n } catch (error: unknown) {\n cleanupPartial(skillTarget)\n return { status: 'failed', targetDir, detail: errorMessage(error) }\n }\n }\n\n // 已存在:内容一致则幂等跳过\n let same: boolean\n try {\n same = isContentSame(sourceDir, skillTarget)\n } catch (error: unknown) {\n return { status: 'failed', targetDir, detail: errorMessage(error) }\n }\n if (same) {\n return { status: 'up-to-date', targetDir }\n }\n\n // 内容不一致:需要确认覆盖(非交互默认拒绝)\n const allowed = force ?? (confirmOverwrite ? await confirmOverwrite(skillTarget) : false)\n if (!allowed) {\n return {\n status: 'skipped-conflict',\n targetDir,\n detail: '目标存在内容不一致的同名 skill,已跳过(使用 --force 或交互确认覆盖)',\n }\n }\n\n try {\n mirrorCopy(sourceDir, skillTarget)\n return { status: 'installed', targetDir, detail: '已覆盖旧版本' }\n } catch (error: unknown) {\n cleanupPartial(skillTarget)\n return { status: 'failed', targetDir, detail: errorMessage(error) }\n }\n}\n\n/** mirrorCopy 失败后清理半写目录(避免下次安装误判为内容不一致需 force) */\nfunction cleanupPartial(skillTarget: string): void {\n try {\n rmSync(skillTarget, { recursive: true, force: true })\n } catch {\n // 清理失败不掩盖原始错误\n }\n}\n\nfunction errorMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error)\n}\n","// ---------------------------------------------------------------------------\n// dependfix skills doctor 核心逻辑\n// ---------------------------------------------------------------------------\n// 检查项:\n// 1. 已检测 agent 的 skills 目录存在性(目录约定漂移提示:主目录在但 skills 目录缺失)\n// 2. 产品 skill 安装状态(已检测 agent 的 skills 目录中 dependfix-remediator 是否存在、\n// 内容与当前 CLI 携带版本是否一致)\n// 3. 内部开发 skill internal 标记完整性(在 dependfix 仓库内运行时,扫描 .github/skills)\n// 全部为只读检查,输出分级问题清单。\n\nimport { existsSync, readFileSync, readdirSync } from 'node:fs'\nimport { join } from 'node:path'\nimport { AGENTS } from './agents'\nimport { isContentSame } from './installer'\nimport { PRODUCT_SKILL_NAME, resolveProductSkillSourceDir } from './source'\n\nexport type DoctorLevel = 'ok' | 'warn' | 'error'\n\nexport interface DoctorFinding {\n level: DoctorLevel\n message: string\n}\n\nexport interface DoctorOptions {\n homeDir: string\n /** 项目根(用于项目级目录检查与内部 skill 扫描);缺省为当前工作目录 */\n projectRoot?: string\n /** 产品 skill 权威源目录(缺省从 @dependfix/skills 包解析;测试可注入) */\n productSourceDir?: string\n}\n\nexport function runDoctor(options: DoctorOptions): DoctorFinding[] {\n const { homeDir, projectRoot = process.cwd() } = options\n const findings: DoctorFinding[] = []\n\n // 1. agent 目录约定检查\n for (const agent of AGENTS) {\n const installed = agent.detectInstalled(homeDir)\n if (!installed) {\n continue\n }\n const globalDir = agent.globalSkillDir(homeDir)\n if (!existsSync(globalDir)) {\n findings.push({\n level: 'warn',\n message: `${agent.displayName} 已检测到,但全局 skills 目录缺失(${globalDir})——可能官方目录约定已变更,或尚未初始化`,\n })\n }\n const projectDir = agent.projectSkillDir(projectRoot)\n if (projectDir && !existsSync(projectDir)) {\n findings.push({\n level: 'ok',\n message: `${agent.displayName} 项目级 skills 目录不存在(${projectDir})——非问题,按需创建`,\n })\n }\n }\n\n // 2. 产品 skill 安装状态\n const sourceDir = options.productSourceDir ?? safeResolveSourceDir()\n if (sourceDir) {\n for (const agent of AGENTS) {\n if (!agent.detectInstalled(homeDir)) {\n continue\n }\n const installedDir = join(agent.globalSkillDir(homeDir), PRODUCT_SKILL_NAME)\n if (!existsSync(installedDir)) {\n findings.push({\n level: 'ok',\n message: `${agent.displayName}: ${PRODUCT_SKILL_NAME} 未安装(运行 dependfix skills install)`,\n })\n continue\n }\n if (isContentSame(sourceDir, installedDir)) {\n findings.push({\n level: 'ok',\n message: `${agent.displayName}: ${PRODUCT_SKILL_NAME} 已安装且与当前版本一致`,\n })\n } else {\n findings.push({\n level: 'warn',\n message: `${agent.displayName}: ${PRODUCT_SKILL_NAME} 已安装但内容与当前版本不一致(建议重新 install)`,\n })\n }\n }\n }\n\n // 3. 内部开发 skill internal 标记完整性(仅 dependfix 仓库内)\n const internalSkillsRoot = join(projectRoot, '.github', 'skills')\n if (existsSync(internalSkillsRoot)) {\n const missing: string[] = []\n for (const entry of readdirSync(internalSkillsRoot, { withFileTypes: true })) {\n if (!entry.isDirectory()) {\n continue\n }\n const skillFile = join(internalSkillsRoot, entry.name, 'SKILL.md')\n if (!existsSync(skillFile)) {\n missing.push(`${entry.name}(缺 SKILL.md)`)\n continue\n }\n const content = readFileSync(skillFile, 'utf8')\n if (!/metadata:\\s*\\r?\\n\\s*internal:\\s*true/.test(content)) {\n missing.push(entry.name)\n }\n }\n if (missing.length > 0) {\n findings.push({\n level: 'error',\n message: `内部 skill internal 标记缺失(生态可见泄漏风险): ${missing.join(', ')}`,\n })\n } else {\n findings.push({\n level: 'ok',\n message: `内部 skill internal 标记完整性检查通过(.github/skills)`,\n })\n }\n }\n\n return findings\n}\n\n/** 解析产品 skill 源目录;失败返回 undefined(如 CLI 运行在无 @dependfix/skills 的调试环境) */\nfunction safeResolveSourceDir(): string | undefined {\n try {\n return resolveProductSkillSourceDir()\n } catch {\n return undefined\n }\n}\n","// ---------------------------------------------------------------------------\n// dependfix skills 子命令(install / doctor)\n// ---------------------------------------------------------------------------\n// 定位:npx skills 生态的离线兜底安装器。\n// 不依赖 npx skills;不复刻 add/list/update/remove 完整命令矩阵。\n// 主通道(npx skills add dependfix/dependfix -s dependfix-remediator)见 README。\n\nimport { homedir } from 'node:os'\nimport { defineCommand, renderUsage } from 'citty'\nimport { AGENTS } from './agents'\nimport { runDoctor, type DoctorFinding } from './doctor'\nimport { installSkillToDir, type InstallResult } from './installer'\nimport { resolveProductSkillSourceDir } from './source'\n\n// ---------------------------------------------------------------------------\n// install\n// ---------------------------------------------------------------------------\n\ninterface InstallCliArgs {\n project?: boolean\n force?: boolean\n 'dry-run'?: boolean\n}\n\nasync function runInstall(args: InstallCliArgs): Promise<void> {\n const home = homedir()\n const projectRoot = process.cwd()\n\n let sourceDir: string\n try {\n sourceDir = resolveProductSkillSourceDir()\n } catch (error: unknown) {\n console.error(`无法定位产品 skill 内容(@dependfix/skills 未安装?): ${error instanceof Error ? error.message : String(error)}`)\n process.exitCode = 1\n return\n }\n\n const detected = AGENTS.filter((agent) => agent.detectInstalled(home))\n if (detected.length === 0) {\n console.info('未检测到已安装的 agent 工具(Claude Code / OpenCode / Cursor / Copilot)。')\n console.info('主通道安装(推荐): npx skills add dependfix/dependfix -s dependfix-remediator -g')\n return\n }\n\n console.info(`检测到 ${detected.length} 个 agent 工具,目标模式: ${args.project ? '项目级' : '全局'}\\n`)\n\n const results: { agent: string, result: InstallResult }[] = []\n for (const agent of detected) {\n const agentDir = args.project ? agent.projectSkillDir(projectRoot) : agent.globalSkillDir(home)\n if (!agentDir) {\n console.info(`- ${agent.displayName}: 不支持 ${args.project ? '项目级' : ''}安装,跳过`)\n continue\n }\n const result = await installSkillToDir({\n sourceDir,\n targetDir: agentDir,\n force: args.force,\n dryRun: args['dry-run'],\n confirmOverwrite: (existingDir) => confirmOverwritePrompt(agent.displayName, existingDir),\n })\n results.push({ agent: agent.displayName, result })\n }\n\n console.info('\\n安装清单:')\n const installIcons: Record<InstallResult['status'], string> = {\n installed: '✓',\n 'up-to-date': '=',\n 'skipped-conflict': '!',\n failed: '✗',\n }\n for (const { agent, result } of results) {\n const icon = installIcons[result.status]\n console.info(` ${icon} ${agent}: ${result.status}${result.detail ? ` — ${result.detail}` : ''}`)\n }\n\n const failed = results.filter((r) => r.result.status === 'failed')\n if (failed.length > 0) {\n process.exitCode = 1\n }\n}\n\n/** 交互式覆盖确认;非 TTY 返回 false(不静默覆盖) */\nasync function confirmOverwritePrompt(agentName: string, existingDir: string): Promise<boolean> {\n if (!process.stdin.isTTY) {\n console.warn(` ${agentName}: 目标已存在内容不一致的 dependfix-remediator,非交互环境跳过(使用 --force 覆盖)`)\n return false\n }\n const readline = (await import('node:readline')).createInterface({\n input: process.stdin,\n output: process.stdout,\n })\n return new Promise<boolean>((resolve) => {\n readline.question(` 覆盖 ${existingDir} 中的旧版本?[y/N] `, (answer) => {\n readline.close()\n resolve(answer.trim().toLowerCase() === 'y' || answer.trim().toLowerCase() === 'yes')\n })\n })\n}\n\n// ---------------------------------------------------------------------------\n// doctor\n// ---------------------------------------------------------------------------\n\nasync function runDoctorCli(): Promise<void> {\n const findings = runDoctor({ homeDir: homedir(), projectRoot: process.cwd() })\n const doctorIcons: Record<DoctorFinding['level'], string> = { ok: '✓', warn: '!', error: '✗' }\n let warnCount = 0\n let errorCount = 0\n for (const finding of findings) {\n const icon = doctorIcons[finding.level]\n console.info(` ${icon} [${finding.level}] ${finding.message}`)\n if (finding.level === 'warn') {\n warnCount++\n } else if (finding.level === 'error') {\n errorCount++\n }\n }\n console.info(`\\ndoctor 完成: ${findings.length} 项检查,${warnCount} warning, ${errorCount} error`)\n if (errorCount > 0) {\n process.exitCode = 1\n }\n}\n\n// ---------------------------------------------------------------------------\n// citty command\n// ---------------------------------------------------------------------------\n\nexport const skillsCommand = defineCommand({\n meta: {\n name: 'skills',\n description: '产品 skill 管理(npx skills 生态的离线兜底安装器)',\n },\n subCommands: {\n install: defineCommand({\n meta: {\n name: 'install',\n description: '检测本机已装 agent 工具并安装 dependfix-remediator 产品 skill',\n },\n args: {\n project: {\n type: 'boolean',\n description: '安装到当前项目目录(默认用户全局)',\n negativeDescription: '安装到用户全局(默认)',\n },\n force: {\n type: 'boolean',\n description: '覆盖已存在的内容不一致同名 skill(跳过确认)',\n negativeDescription: '内容不一致时需确认(默认)',\n },\n 'dry-run': {\n type: 'boolean',\n description: '只输出将要执行的操作,不写文件',\n negativeDescription: '实际执行安装',\n },\n },\n async run({ args }) {\n await runInstall(args as InstallCliArgs)\n },\n }),\n doctor: defineCommand({\n meta: {\n name: 'doctor',\n description: '检查 agent 目录约定、产品 skill 安装状态与内部 skill internal 标记完整性',\n },\n async run() {\n await runDoctorCli()\n },\n }),\n },\n async run({ cmd, rawArgs }) {\n // citty 0.2.2 在路由子命令后仍会执行父 run:子命令已执行时直接返回,避免重复输出 usage\n const sub = rawArgs[0]\n if (sub === 'install' || sub === 'doctor') {\n return\n }\n console.info(await renderUsage(cmd))\n },\n})\n","// CLI 执行层(解析与执行分离):\n// - cli/index.ts:argsDef + parseCliArgs(纯解析,无执行依赖)\n// - cli/runner.ts:runCli / runApp / dependfixCommand(经 createPipeline 执行)\n// - app/pipeline.ts:createPipeline(local 与 platform 共用编排核心)\n//\n// 依赖方向:runner → pipeline → cli/index(纯解析),无循环。\n\nimport { defineCommand, renderUsage, runCommand, runMain, showUsage } from 'citty'\nimport { toAppError } from '@dependfix/core'\nimport type { RuntimeConfig } from '@dependfix/engine'\nimport { createPipeline, type PipelineLogger } from '../app/pipeline'\nimport { skillsCommand } from '../skills'\nimport { argsDef, type CliInvocation } from './index'\n\nexport interface CliRunResult {\n ok: true\n invocation: CliInvocation\n config: RuntimeConfig\n}\n\n/** 默认 CLI 日志(console);platform 场景经 createPipeline 注入自定义 logger */\nconst cliLogger: PipelineLogger = console\n\n// ---------------------------------------------------------------------------\n// Public API(签名与行为保持兼容)\n// ---------------------------------------------------------------------------\n\nexport function runCli(rawArgs: string[]): CliRunResult {\n return createPipeline({ logger: cliLogger }).parse(rawArgs)\n}\n\n// ---------------------------------------------------------------------------\n// App execution\n// ---------------------------------------------------------------------------\n\nasync function runApp(rawArgs: string[]): Promise<number> {\n return createPipeline({ logger: cliLogger }).run(rawArgs)\n}\n\n// ---------------------------------------------------------------------------\n// citty command\n// ---------------------------------------------------------------------------\n// 注意:不使用 citty subCommands 字段——citty 0.2.2 在 subCommands 模式下会\n// ① 子命令执行后继续执行父 run;② 不匹配子命令的 positional(如 fix)抛\n// Unknown command。因此 skills 子命令由 run 首部编程路由(runCommand),\n// 主流程 positional 命令面不受影响。\n\nexport const dependfixCommand = defineCommand({\n meta: {\n name: 'dependfix',\n version: '0.1.0',\n description: '自动化处理 Dependabot / Code Scanning 安全告警的修复工具',\n },\n args: argsDef,\n async run({ rawArgs }) {\n // skills 子命令路由(install / doctor)\n if (rawArgs[0] === 'skills') {\n await runCommand(skillsCommand, { rawArgs: rawArgs.slice(1) })\n return\n }\n\n let exitCode = 1\n try {\n exitCode = await runApp(rawArgs)\n } catch (error: unknown) {\n const appError = toAppError(error, 'CLI_EXECUTION_FAILED')\n console.error(`Error: ${appError.message}`)\n exitCode = 1\n }\n process.exitCode = exitCode\n },\n})\n\n// ---------------------------------------------------------------------------\n// 入口封装:补 skills 子命令的 --help 路由\n// ---------------------------------------------------------------------------\n// citty runMain 在 runCommand 前拦截内建 --help,且 resolveSubCommand 依赖\n// subCommands 字段下钻;dependfixCommand 无该字段(见上),故 skills 相关\n// --help 会被截获为主命令 usage。此处显式路由到 skills usage。\n\nexport async function runDependfixMain(rawArgs: string[] = process.argv.slice(2)): Promise<void> {\n if (rawArgs[0] === 'skills' && (rawArgs.includes('--help') || rawArgs.includes('-h'))) {\n console.info(await renderUsage(skillsCommand))\n process.exitCode = 0\n return\n }\n await runMain(dependfixCommand, { showUsage })\n}\n"],"mappings":";;;;;;;;;;AA6BA,MAAa,UAAU;CACnB,MAAM;EACF,MAAM;EACN,aAAa;EACb,UAAU;EACV,SAAS;CACb;CACA,MAAM;EACF,MAAM;EACN,aAAa;EACb,OAAO;GAAC;GAAK;GAAc;EAAc;CAC7C;CACA,cAAc;EACV,MAAM;EACN,aAAa;CACjB;CACA,OAAO;EACH,MAAM;EACN,aAAa;CACjB;CACA,eAAe;EACX,MAAM;EACN,aAAa;CACjB;CACA,gBAAgB;EACZ,MAAM;EACN,aAAa;CACjB;CACA,gBAAgB;EACZ,MAAM;EACN,aAAa;CACjB;CACA,uBAAuB;EACnB,MAAM;EACN,aAAa;CACjB;CACA,sBAAsB;EAClB,MAAM;EACN,aAAa;EACb,SAAS;CACb;CACA,WAAW;EACP,MAAM;EACN,aAAa;EACb,qBAAqB;CACzB;CACA,aAAa;EACT,MAAM;EACN,aAAa;EACb,qBAAqB;CACzB;CACA,QAAQ;EACJ,MAAM;EACN,aAAa;EACb,qBAAqB;CACzB;CACA,oBAAoB;EAChB,MAAM;EACN,aAAa;EACb,qBAAqB;CACzB;CACA,yBAAyB;EACrB,MAAM;EACN,aAAa;EACb,qBAAqB;CACzB;CACA,gBAAgB;EACZ,MAAM;EACN,aAAa;CACjB;CACA,gBAAgB;EACZ,MAAM;EACN,aAAa;CACjB;CACA,iBAAiB;EACb,MAAM;EACN,aAAa;CACjB;CACA,iBAAiB;EACb,MAAM;EACN,aAAa;EACb,qBAAqB;CACzB;CACA,uBAAuB;EACnB,MAAM;EACN,aAAa;EACb,qBAAqB;CACzB;CACA,6BAA6B;EACzB,MAAM;EACN,aAAa;EACb,SAAS;CACb;CACA,mBAAmB;EACf,MAAM;EACN,aAAa;EACb,SAAS;CACb;CACA,eAAe;EACX,MAAM;EACN,aAAa;EACb,SAAS;CACb;CACA,kBAAkB;EACd,MAAM;EACN,aAAa;EACb,SAAS;CACb;CACA,SAAS;EACL,MAAM;EACN,aAAa;CACjB;CACA,kBAAkB;EACd,MAAM;EACN,aAAa;CACjB;CACA,0BAA0B;EACtB,MAAM;EACN,aAAa;CACjB;CACA,UAAU;EACN,MAAM;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"}
1
+ {"version":3,"file":"runner.mjs","names":[],"sources":["../src/cli/index.ts","../src/app/pipeline.ts","../src/skills/agents.ts","../src/skills/source.ts","../src/skills/installer.ts","../src/skills/doctor.ts","../src/skills/index.ts","../src/cli/runner.ts"],"sourcesContent":["import {\n parseArgs,\n type ArgsDef,\n type ParsedArgs,\n} from 'citty'\nimport { AppError, isValidRepoIdentifier } from '@dependfix/core'\nimport {\n type CliConfigOverrides,\n type RuntimeMode,\n type SeverityThreshold,\n type AlertSourceKind,\n RUNTIME_MODES,\n SEVERITY_THRESHOLDS,\n ALERT_SOURCES,\n} from '@dependfix/engine'\n// ---------------------------------------------------------------------------\n// Public interfaces\n// ---------------------------------------------------------------------------\n\nexport interface CliInvocation {\n mode?: RuntimeMode\n configOverrides: CliConfigOverrides\n rawArgs: string[]\n}\n\n// ---------------------------------------------------------------------------\n// Args definition for citty\n// ---------------------------------------------------------------------------\n\nexport const argsDef = {\n mode: {\n type: 'positional' as const,\n description: '运行模式:report-only, fix, fix-and-pr, cleanup-branches',\n required: false,\n default: 'report-only' as const,\n },\n repo: {\n type: 'string' as const,\n description: '目标仓库 (owner/repo),逗号分隔多个',\n alias: ['r', 'repository', 'repositories'],\n },\n 'repos-file': {\n type: 'string' as const,\n description: '从文件读取仓库列表(每行一个 owner/repo)',\n },\n owner: {\n type: 'string' as const,\n description: 'owner / org 自动发现(逗号分隔多个或多次传入),与 --repo 合并去重(显式优先)',\n },\n 'repo-topics': {\n type: 'string' as const,\n description: '发现结果 topic 白名单(逗号分隔,AND 语义;仅影响 --owner 发现结果)',\n },\n 'repo-include': {\n type: 'string' as const,\n description: '仓库白名单 glob(逗号分隔多个或多次传入,如 owner/*、owner/pkg-*;仅作用于发现结果)',\n },\n 'repo-exclude': {\n type: 'string' as const,\n description: '仓库黑名单 glob(逗号分隔多个或多次传入;显式列表与发现结果均受约束,与 include 冲突时胜出)',\n },\n 'repo-topics-exclude': {\n type: 'string' as const,\n description: '发现结果 topic 黑名单(逗号分隔,排除含任一指定 topic 的仓库)',\n },\n 'severity-threshold': {\n type: 'string' as const,\n description: '严重级别阈值:critical, high, medium, all',\n default: 'high' as const,\n },\n 'dry-run': {\n type: 'boolean' as const,\n description: '试运行模式,不实际写入文件',\n negativeDescription: '关闭试运行模式',\n },\n 'create-pr': {\n type: 'boolean' as const,\n description: '创建 Pull Request',\n negativeDescription: '不创建 Pull Request',\n },\n commit: {\n type: 'boolean' as const,\n description: '修复完成后在本地当前分支直接提交(不推送、不创建 PR)',\n negativeDescription: '不自动提交(默认)',\n },\n 'cleanup-branches': {\n type: 'boolean' as const,\n description: '(fix-and-pr 模式)结束后列出已合并的 dependfix 分支到报告,不自动删除',\n negativeDescription: '不执行分支清理检查',\n },\n 'cleanup-branches-auto': {\n type: 'boolean' as const,\n description: '(fix-and-pr 模式)结束后自动删除已合并/已关闭的 dependfix 分支(非交互,不删有 open PR 的分支)',\n negativeDescription: '不自动删除分支',\n },\n 'github-token': {\n type: 'string' as const,\n description: 'GitHub Personal Access Token',\n },\n 'alerts-token': {\n type: 'string' as const,\n description: 'Dependabot alerts 专用 token(可选,最小权限 PAT,仅 Dependabot alerts: read;缺省回退 --github-token。GITHUB_TOKEN 无法读取 Dependabot alerts)',\n },\n 'alerts-source': {\n type: 'string' as const,\n description: '告警数据源:github-dependabot(默认,GitHub Dependabot alerts API)或 pnpm-audit(本地无 token 回退,扫描当前工作区 lockfile;repository 优先 --repo → git remote → local 兜底)',\n },\n 'code-scanning': {\n type: 'boolean' as const,\n description: '同时拉取 Code Scanning alerts(与 Dependabot 并行,默认关闭;需要 token 具备 security-events: read,GITHUB_TOKEN 默认具备)',\n negativeDescription: '不拉取 Code Scanning alerts(默认)',\n },\n 'code-quality': {\n type: 'boolean' as const,\n description: '同时拉取 Code Quality findings(与 Dependabot 并行,默认关闭;需要 fine-grained PAT 具备 Code quality: read,或 classic PAT 具备 repo/public_repo scope)',\n negativeDescription: '不拉取 Code Quality findings(默认)',\n },\n 'allow-major-upgrade': {\n type: 'boolean' as const,\n description: '跨线告警(推荐版本跨大版本,当前线内无修复版本)显式授权自动升级:仅根 package.json 直接依赖(workspace 成员独占声明维持人工)且 lockfile 单版本的告警自动跨线升级,升级后复核脆弱实例、强制完整验证(install+lint+build),失败自动回滚;间接依赖 / 多版本共存跨线告警维持人工处理。仅 CLI 可用,Action 不支持',\n negativeDescription: '不自动升级跨线告警(默认,维持人工处理)',\n },\n 'max-alerts-per-repository': {\n type: 'string' as const,\n description: '每个仓库最多处理的告警数',\n default: '20' as const,\n },\n 'max-concurrency': {\n type: 'string' as const,\n description: '多仓库并发窗口(1-16,默认 1 保守串行;>1 可能触发 GitHub 限流)',\n default: '1' as const,\n },\n 'max-retries': {\n type: 'string' as const,\n description: 'GitHub API 限流重试次数(0-10,默认 3;429/rate limit 指数退避重试)',\n default: '3' as const,\n },\n 'max-backoff-ms': {\n type: 'string' as const,\n description: '限流退避单次等待上限毫秒(100-120000,默认 30000;Retry-After / reset / 指数退避均受此约束)',\n default: '30000' as const,\n },\n 'max-repos': {\n type: 'string' as const,\n description: '发现规模上限:最多保留的仓库数(默认 100;0 或负数表示不限制;大 org 场景下防止一次性全量发现)',\n default: '100' as const,\n },\n history: {\n type: 'string' as const,\n description: '查询仓库历史运行摘要(读 dependfix-reports/index.json,倒序时间;不执行扫描)',\n },\n 'upgrade-groups': {\n type: 'string' as const,\n description: '用户显式分组(覆盖自动分组),格式 \"name1:pkg1,pkg2;name2:pkg3\"',\n },\n 'toolchain-pnpm-version': {\n type: 'string' as const,\n description: 'lockfile 修复用的 pnpm 版本(工具链固定;缺省从 package.json packageManager 解析;PIN_TOOLCHAIN 策略用 corepack pnpm@<version> 执行)',\n },\n commands: {\n type: 'string' as const,\n description: '自定义验证命令(逗号分隔),覆盖默认的 install/lint/build',\n },\n verbose: {\n type: 'boolean' as const,\n description: '输出详细日志',\n },\n ai: {\n type: 'boolean' as const,\n description: '开启 AI breaking change 研判(默认关闭;需配置 AI API Key。触发范围见 --ai-trigger;dry-run 不触发、不产生费用)',\n negativeDescription: '关闭 AI 研判(默认)',\n },\n 'ai-provider': {\n type: 'string' as const,\n description: 'AI 提供商:openai-compatible(默认,DeepSeek 等指定 --ai-base-url 兼容)或 anthropic',\n },\n 'ai-model': {\n type: 'string' as const,\n description: 'AI 模型名(默认 deepseek-v4-flash)',\n },\n 'ai-base-url': {\n type: 'string' as const,\n description: 'OpenAI 兼容端点基地址(默认 https://api.deepseek.com,与默认模型 deepseek-v4-flash 配套;使用 OpenAI 官方模型时指定 https://api.openai.com/v1 + --ai-model)',\n },\n 'ai-api-url': {\n type: 'string' as const,\n description: 'Anthropic 兼容端点(仅 --ai-provider anthropic 生效;默认 https://api.anthropic.com/v1/messages,自托管/网关可显式指定)',\n },\n 'ai-api-key': {\n type: 'string' as const,\n description: 'AI API Key(优先 DEPENDFIX_AI_API_KEY env;注意命令行参数会出现在进程列表/shell history,敏感环境请用 env)',\n },\n 'ai-trigger': {\n type: 'string' as const,\n description: 'AI 研判触发范围:failure(升级验证失败)/ major(major 升级)/ both(默认)',\n },\n} satisfies ArgsDef\n\n// ---------------------------------------------------------------------------\n// Conversion helpers\n// ---------------------------------------------------------------------------\n\nexport function isRuntimeMode(value: string): value is RuntimeMode {\n return RUNTIME_MODES.includes(value as RuntimeMode)\n}\n\nexport function isSeverityThreshold(value: string): value is SeverityThreshold {\n return SEVERITY_THRESHOLDS.includes(value as SeverityThreshold)\n}\n\nexport function isAlertSource(value: string): value is AlertSourceKind {\n return ALERT_SOURCES.includes(value as AlertSourceKind)\n}\n\nexport function appendRepositories(target: string[], value: string): void {\n for (const repository of value.split(',')) {\n const trimmed = repository.trim()\n\n if (!trimmed) {\n continue\n }\n\n if (!isValidRepoIdentifier(trimmed)) {\n throw new AppError(\n 'ARGUMENT_PARSE_ERROR',\n `Invalid repository identifier: \"${trimmed}\". Expected format: owner/repo`,\n )\n }\n\n target.push(trimmed)\n }\n}\n\nexport function parseCommandsFlag(value: string): string[] {\n return value\n .split(',')\n .map((cmd) => cmd.trim())\n .filter(Boolean)\n}\n\n/**\n * 严格整数字面量解析(修复:拒绝 `2.5` 被 parseInt 静默截断为 2)。\n * 仅接受 `^\\d+$`;范围语义由调用方在 expected 描述中声明(config 校验兜底)。\n */\nexport function parseIntegerFlag(value: string, flagName: string, expected: string): number {\n const trimmed = value.trim()\n if (!/^\\d+$/.test(trimmed)) {\n throw new AppError(\n 'ARGUMENT_PARSE_ERROR',\n `Invalid ${flagName} value: \"${value}\". ${expected}`,\n )\n }\n return Number.parseInt(trimmed, 10)\n}\n\n/**\n * 归一化可重复 flag 值(citty/mri 对重复传入返回数组,单次传入返回字符串):\n * 按逗号拆分 + 去空白 + 去空项。`--owner a,b --owner c` → ['a', 'b', 'c']。\n */\nexport function normalizeFlagList(value: string | string[] | undefined): string[] {\n if (value === undefined) {\n return []\n }\n const parts = Array.isArray(value) ? value : [value]\n return parts\n .flatMap((v) => v.split(','))\n .map((s) => s.trim())\n .filter(Boolean)\n}\n\nfunction parsedArgsToCliOverrides(parsed: ParsedArgs<typeof argsDef>): CliConfigOverrides {\n const overrides: CliConfigOverrides = {}\n\n // mode\n const rawMode = parsed.mode\n if (isRuntimeMode(rawMode)) {\n overrides.mode = rawMode\n }\n\n // repositories (from --repo / --repository)\n const repoValue = parsed.repo\n if (repoValue) {\n const repos: string[] = []\n appendRepositories(repos, repoValue)\n if (repos.length > 0) {\n overrides.repositories = repos\n }\n }\n\n // repos-file\n const reposFile = parsed['repos-file']\n if (reposFile) {\n overrides.reposFilePath = reposFile\n }\n\n // owner(自动发现;逗号分隔多个或多次传入)\n const ownerValue = normalizeFlagList(parsed.owner)\n if (ownerValue.length > 0) {\n overrides.owner = ownerValue\n }\n\n // repo-topics(发现结果 topic 白名单,AND 语义)\n const repoTopicsValue = normalizeFlagList(parsed['repo-topics'])\n if (repoTopicsValue.length > 0) {\n overrides.repoTopics = repoTopicsValue\n }\n\n // repo-include / repo-exclude / repo-topics-exclude(名单策略)\n const repoIncludeValue = normalizeFlagList(parsed['repo-include'])\n if (repoIncludeValue.length > 0) {\n overrides.repoInclude = repoIncludeValue\n }\n const repoExcludeValue = normalizeFlagList(parsed['repo-exclude'])\n if (repoExcludeValue.length > 0) {\n overrides.repoExclude = repoExcludeValue\n }\n const repoTopicsExcludeValue = normalizeFlagList(parsed['repo-topics-exclude'])\n if (repoTopicsExcludeValue.length > 0) {\n overrides.repoTopicsExclude = repoTopicsExcludeValue\n }\n\n // severity-threshold\n const severityThreshold = parsed['severity-threshold']\n if (isSeverityThreshold(severityThreshold)) {\n overrides.severityThreshold = severityThreshold\n }\n\n // dry-run (three-state: true / false / undefined)\n if (parsed['dry-run'] !== undefined) {\n overrides.dryRun = parsed['dry-run']\n }\n\n // create-pr (three-state: true / false / undefined)\n if (parsed['create-pr'] !== undefined) {\n overrides.createPullRequest = parsed['create-pr']\n }\n\n // commit (three-state: true / false / undefined)\n if (parsed.commit !== undefined) {\n overrides.commit = parsed.commit\n }\n\n // cleanup-branches (three-state: true / false / undefined)\n if (parsed['cleanup-branches'] !== undefined) {\n overrides.cleanupBranches = parsed['cleanup-branches']\n }\n\n // cleanup-branches-auto (three-state: true / false / undefined)\n if (parsed['cleanup-branches-auto'] !== undefined) {\n overrides.cleanupBranchesAuto = parsed['cleanup-branches-auto']\n }\n\n // github-token\n const githubToken = parsed['github-token']\n if (githubToken) {\n overrides.githubToken = githubToken\n }\n\n // alerts-token\n const alertsToken = parsed['alerts-token']\n if (alertsToken) {\n overrides.alertsToken = alertsToken\n }\n\n // alerts-source\n const alertsSource = parsed['alerts-source']\n if (alertsSource) {\n if (!isAlertSource(alertsSource)) {\n throw new AppError(\n 'ARGUMENT_PARSE_ERROR',\n `Invalid --alerts-source value: \"${alertsSource}\". Expected one of: ${ALERT_SOURCES.join(', ')}.`,\n )\n }\n overrides.alertSource = alertsSource\n }\n\n // code-scanning (three-state: true / false / undefined)\n if (parsed['code-scanning'] !== undefined) {\n overrides.codeScanningEnabled = parsed['code-scanning']\n }\n\n // code-quality (three-state: true / false / undefined)\n if (parsed['code-quality'] !== undefined) {\n overrides.codeQualityEnabled = parsed['code-quality']\n }\n\n // allow-major-upgrade (three-state: true / false / undefined; 无 env 通道,仅 CLI)\n if (parsed['allow-major-upgrade'] !== undefined) {\n overrides.allowMajorUpgrade = parsed['allow-major-upgrade']\n }\n\n // max-alerts-per-repository\n const maxAlerts = parsed['max-alerts-per-repository']\n if (maxAlerts) {\n overrides.maxAlertsPerRepository = parseIntegerFlag(maxAlerts, '--max-alerts-per-repository', 'Expected a positive integer.')\n }\n\n // max-concurrency(1-16,config 校验兜底)\n const maxConcurrency = parsed['max-concurrency']\n if (maxConcurrency) {\n overrides.maxConcurrency = parseIntegerFlag(maxConcurrency, '--max-concurrency', 'Expected an integer between 1 and 16.')\n }\n\n // max-retries(0-10,config 校验兜底)\n const maxRetries = parsed['max-retries']\n if (maxRetries) {\n overrides.maxRetries = parseIntegerFlag(maxRetries, '--max-retries', 'Expected an integer between 0 and 10.')\n }\n\n // max-backoff-ms(100-120000,config 校验兜底)\n const maxBackoffMs = parsed['max-backoff-ms']\n if (maxBackoffMs) {\n overrides.maxBackoffMs = parseIntegerFlag(maxBackoffMs, '--max-backoff-ms', 'Expected an integer between 100 and 120000.')\n }\n\n // max-repos(发现规模上限,config 校验兜底)\n const maxRepos = parsed['max-repos']\n if (maxRepos) {\n overrides.maxRepos = parseIntegerFlag(maxRepos, '--max-repos', 'Expected a non-negative integer (0 = unlimited).')\n }\n\n // history(独立查询命令,不进入运行配置)\n const history = parsed.history\n if (history) {\n overrides.history = history\n }\n\n // verbose (three-state: true / false / undefined)\n if (parsed.verbose !== undefined) {\n overrides.verbose = parsed.verbose\n }\n\n // commands\n const commandsValue = parsed.commands\n if (commandsValue) {\n overrides.commands = parseCommandsFlag(commandsValue)\n }\n\n // upgrade-groups\n const upgradeGroups = parsed['upgrade-groups']\n if (upgradeGroups) {\n overrides.upgradeGroups = parseUpgradeGroupsFlag(upgradeGroups)\n }\n\n // toolchain-pnpm-version\n const toolchainPnpmVersion = parsed['toolchain-pnpm-version']\n if (toolchainPnpmVersion) {\n overrides.toolchainPnpmVersion = toolchainPnpmVersion\n }\n\n // AI 研判(--ai 系列;--ai-api-key 为敏感参数,env 优先)\n if (parsed.ai !== undefined) {\n overrides.aiEnabled = parsed.ai\n }\n const aiProvider = parsed['ai-provider']\n if (aiProvider) {\n if (aiProvider !== 'openai-compatible' && aiProvider !== 'anthropic') {\n throw new AppError(\n 'ARGUMENT_PARSE_ERROR',\n `Invalid --ai-provider value: \"${aiProvider}\". Expected \"openai-compatible\" or \"anthropic\".`,\n )\n }\n overrides.aiProvider = aiProvider\n }\n const aiModel = parsed['ai-model']\n if (aiModel) {\n overrides.aiModel = aiModel\n }\n const aiBaseUrl = parsed['ai-base-url']\n if (aiBaseUrl) {\n overrides.aiBaseUrl = aiBaseUrl\n }\n const aiApiUrl = parsed['ai-api-url']\n if (aiApiUrl) {\n overrides.aiApiUrl = aiApiUrl\n }\n const aiApiKey = parsed['ai-api-key']\n if (aiApiKey) {\n overrides.aiApiKey = aiApiKey\n }\n const aiTrigger = parsed['ai-trigger']\n if (aiTrigger) {\n if (aiTrigger !== 'failure' && aiTrigger !== 'major' && aiTrigger !== 'both') {\n throw new AppError(\n 'ARGUMENT_PARSE_ERROR',\n `Invalid --ai-trigger value: \"${aiTrigger}\". Expected \"failure\", \"major\" or \"both\".`,\n )\n }\n overrides.aiTrigger = aiTrigger\n }\n\n return overrides\n}\n\n/**\n * 解析 `--upgrade-groups \"name1:pkg1,pkg2;name2:pkg3\"`。\n * 与 config 的 normalizeUpgradeGroups 保持一致(CLI 与 env 同格式):\n * 空 entry 忽略;非空但缺冒号/组名或包列表为空 → 抛 ARGUMENT_PARSE_ERROR;\n * 原型链风险键名(__proto__ / constructor / prototype)忽略。\n */\nexport function parseUpgradeGroupsFlag(value: string): Record<string, string[]> {\n const result: Record<string, string[]> = {}\n for (const entry of value.split(';')) {\n if (!entry.trim()) {\n continue\n }\n const idx = entry.indexOf(':')\n if (idx <= 0) {\n throw new AppError(\n 'ARGUMENT_PARSE_ERROR',\n `Invalid --upgrade-groups entry: \"${entry}\". Expected format: \"name:pkg1,pkg2\"`,\n )\n }\n const name = entry.slice(0, idx).trim()\n const pkgs = entry\n .slice(idx + 1)\n .split(',')\n .map((p) => p.trim())\n .filter(Boolean)\n if (name === '__proto__' || name === 'constructor' || name === 'prototype') {\n continue\n }\n if (!name || pkgs.length === 0) {\n throw new AppError(\n 'ARGUMENT_PARSE_ERROR',\n `Invalid --upgrade-groups entry: \"${entry}\". Expected format: \"name:pkg1,pkg2\"`,\n )\n }\n result[name] = pkgs\n }\n return result\n}\n\n// ---------------------------------------------------------------------------\n// Parsing API\n// ---------------------------------------------------------------------------\n\nexport function parseCliArgs(rawArgs: string[]): CliInvocation {\n const parsed = parseArgs<typeof argsDef>(rawArgs, argsDef)\n const configOverrides = parsedArgsToCliOverrides(parsed)\n\n return {\n mode: configOverrides.mode,\n configOverrides,\n rawArgs: [...rawArgs],\n }\n}\n","// 平台化管线抽象(独立平台前置):\n// local(CLI)与 platform 模式共用同一编排核心——参数解析 → 配置解析 →\n// DependfixApp.run → 退出码。process.env / console / process.exitCode\n// 全部经 PipelineDeps 注入,platform 可替换 env / logger / config resolver / exit。\n\nimport { resolveRuntimeConfig, queryRepoHistory, formatHistory, DependfixApp, type CliConfigOverrides } from '@dependfix/engine'\nimport { parseCliArgs, type CliInvocation } from '../cli'\n\nexport interface PipelineLogger {\n info(msg: string): void\n error(msg: string): void\n}\n\nexport interface PipelineDeps {\n /** 环境变量来源(默认 process.env)——platform 模式注入自定义 env */\n env?: NodeJS.ProcessEnv\n /** 日志输出(默认 console)——platform 模式注入自定义 logger */\n logger?: PipelineLogger\n /**\n * 配置解析(默认 resolveRuntimeConfig)。\n * platform 模式可注入自定义解析(如从数据库读取配置再合并 env)。\n */\n resolveConfig?: (opts: { env: NodeJS.ProcessEnv, cliOverrides: CliConfigOverrides }) => ReturnType<typeof resolveRuntimeConfig>\n /** 退出码设置(默认 process.exitCode)——platform 模式注入 */\n exit?: (code: number) => void\n}\n\nexport interface PipelineParseResult {\n ok: true\n invocation: CliInvocation\n config: ReturnType<typeof resolveRuntimeConfig>\n}\n\nexport interface Pipeline {\n /** 解析参数并解析配置(不执行扫描) */\n parse(rawArgs: string[]): PipelineParseResult\n /** 执行一次完整运行(含 history 查询分支),返回退出码 */\n run(rawArgs: string[]): Promise<number>\n}\n\nexport function createPipeline(deps: PipelineDeps = {}): Pipeline {\n const env = deps.env ?? process.env\n const logger = deps.logger ?? console\n const resolveConfig = deps.resolveConfig ?? ((opts: { env: NodeJS.ProcessEnv, cliOverrides: CliConfigOverrides }) => resolveRuntimeConfig(opts))\n const exit = deps.exit ?? ((code: number) => {\n process.exitCode = code\n })\n\n return {\n parse(rawArgs: string[]): PipelineParseResult {\n const invocation = parseCliArgs(rawArgs)\n const config = resolveConfig({ env, cliOverrides: invocation.configOverrides })\n return { ok: true, invocation, config }\n },\n\n async run(rawArgs: string[]): Promise<number> {\n const invocation = parseCliArgs(rawArgs)\n\n // --history:独立查询命令(读归档索引,不执行扫描、不要求 token/仓库配置)\n if (invocation.configOverrides.history) {\n const entries = queryRepoHistory(invocation.configOverrides.history)\n logger.info(formatHistory(entries, invocation.configOverrides.history))\n return 0\n }\n\n const config = resolveConfig({ env, cliOverrides: invocation.configOverrides })\n const app = new DependfixApp({\n config,\n verbose: invocation.configOverrides.verbose,\n commands: invocation.configOverrides.commands,\n })\n\n const { exitCode } = await app.run()\n exit(exitCode)\n return exitCode\n },\n }\n}\n","// ---------------------------------------------------------------------------\n// Agent 目录约定与检测\n// ---------------------------------------------------------------------------\n// 目录约定与 npx skills 生态对齐(vercel-labs/skills agents 定义):\n// - claude-code: 项目 .claude/skills,全局 ~/.claude/skills\n// - opencode: 项目 .agents/skills,全局 ~/.config/opencode/skills\n// - cursor: 项目 .cursor/skills,全局 ~/.cursor/skills\n// - copilot: 全局 ~/.copilot/skills(GitHub Copilot 无通用项目级目录约定)\n// 检测 = 对应主目录存在(存在即视为已安装该工具)。\n// homedir / projectRoot 均由调用方注入,便于测试。\n\nimport { existsSync } from 'node:fs'\nimport { join } from 'node:path'\n\nexport interface AgentDefinition {\n id: string\n displayName: string\n /** 项目级 skills 目录(相对项目根);不支持返回 undefined */\n projectSkillDir(projectRoot: string): string | undefined\n /** 用户级 skills 目录(绝对路径) */\n globalSkillDir(homeDir: string): string\n /** 检测是否已安装(对应主目录是否存在) */\n detectInstalled(homeDir: string): boolean\n}\n\nexport const AGENTS: AgentDefinition[] = [\n {\n id: 'claude-code',\n displayName: 'Claude Code',\n projectSkillDir: (root) => join(root, '.claude', 'skills'),\n globalSkillDir: (home) => join(home, '.claude', 'skills'),\n detectInstalled: (home) => existsSync(join(home, '.claude')),\n },\n {\n id: 'opencode',\n displayName: 'OpenCode',\n projectSkillDir: (root) => join(root, '.agents', 'skills'),\n globalSkillDir: (home) => join(home, '.config', 'opencode', 'skills'),\n detectInstalled: (home) => existsSync(join(home, '.config', 'opencode')),\n },\n {\n id: 'cursor',\n displayName: 'Cursor',\n projectSkillDir: (root) => join(root, '.cursor', 'skills'),\n globalSkillDir: (home) => join(home, '.cursor', 'skills'),\n detectInstalled: (home) => existsSync(join(home, '.cursor')),\n },\n {\n id: 'copilot',\n displayName: 'GitHub Copilot',\n projectSkillDir: () => undefined,\n globalSkillDir: (home) => join(home, '.copilot', 'skills'),\n detectInstalled: (home) => existsSync(join(home, '.copilot')),\n },\n]\n","// ---------------------------------------------------------------------------\n// 产品 skill 内容来源定位\n// ---------------------------------------------------------------------------\n// dependfix-remediator 权威源随 npm 包 @dependfix/skills 发布(files: dependfix-remediator)。\n// CLI 依赖该包,运行时通过 require.resolve 定位包内 skill 目录:\n// - 开发(tsx):workspace 链接解析到 packages/skills/dependfix-remediator\n// - 发布(npx dependfix):node_modules 中解析 @dependfix/skills/dependfix-remediator\n\nimport { createRequire } from 'node:module'\nimport { dirname, join } from 'node:path'\n\nexport const PRODUCT_SKILL_NAME = 'dependfix-remediator'\n\n/**\n * 解析产品 skill 内容目录(含 SKILL.md 的目录)。\n * 找不到包或内容目录时抛错(install / doctor 的必要前置)。\n */\nexport function resolveProductSkillSourceDir(): string {\n const require = createRequire(import.meta.url)\n const pkgJsonPath = require.resolve('@dependfix/skills/package.json')\n return join(dirname(pkgJsonPath), PRODUCT_SKILL_NAME)\n}\n","// ---------------------------------------------------------------------------\n// 产品 skill 安装器(dependfix skills install 核心)\n// ---------------------------------------------------------------------------\n// 语义:\n// - 目标不存在 → 创建并复制(installed)\n// - 目标已存在且内容一致 → 跳过(up-to-date,幂等)\n// - 目标已存在但内容不一致 → 覆盖需确认(force 或交互确认;拒绝则 skipped-conflict)\n// - dry-run 只输出将要执行的操作,不写文件\n// 覆盖采用镜像语义:删除旧内容后全量复制,保证与权威源严格一致。\n\nimport { createHash } from 'node:crypto'\nimport { cpSync, existsSync, mkdirSync, readdirSync, readFileSync, rmSync, statSync } from 'node:fs'\nimport { join } from 'node:path'\nimport { PRODUCT_SKILL_NAME } from './source'\n\nexport type InstallStatus = 'installed' | 'up-to-date' | 'skipped-conflict' | 'failed'\n\nexport interface InstallResult {\n status: InstallStatus\n /** 安装目标目录(依赖 fix-and-pr 模式外,本为 dependfix-remediator 目录) */\n targetDir: string\n detail?: string\n}\n\nexport interface InstallOptions {\n /** 权威源内容目录(含 SKILL.md) */\n sourceDir: string\n /** 目标 agent skills 目录(dependfix-remediator 将位于其下) */\n targetDir: string\n /** 强制覆盖(跳过确认) */\n force?: boolean\n /** 试运行:只输出将要执行的操作 */\n dryRun?: boolean\n /** 覆盖确认回调;缺省返回 false(非交互默认拒绝,不静默覆盖) */\n confirmOverwrite?: (existingDir: string) => Promise<boolean> | boolean\n}\n\n/** 收集目录内文件相对路径 -> sha256(递归) */\nexport function collectFileHashes(dir: string): Map<string, string> {\n const result = new Map<string, string>()\n if (!existsSync(dir)) {\n return result\n }\n const walk = (current: string, relPrefix: string) => {\n for (const entry of readdirSync(current, { withFileTypes: true })) {\n const full = join(current, entry.name)\n const rel = relPrefix ? `${relPrefix}/${entry.name}` : entry.name\n if (entry.isDirectory()) {\n walk(full, rel)\n } else if (entry.isFile()) {\n result.set(rel, hashFile(full))\n }\n }\n }\n walk(dir, '')\n return result\n}\n\nfunction hashFile(filePath: string): string {\n return createHash('sha256').update(readFileSync(filePath)).digest('hex')\n}\n\n/** 两个目录内容是否完全一致(文件集合 + 内容 hash) */\nexport function isContentSame(dirA: string, dirB: string): boolean {\n const mapA = collectFileHashes(dirA)\n const mapB = collectFileHashes(dirB)\n if (mapA.size !== mapB.size) {\n return false\n }\n for (const [rel, hash] of mapA) {\n if (mapB.get(rel) !== hash) {\n return false\n }\n }\n return true\n}\n\n/** 复制目录(镜像语义:先清空目标内同名子目录再复制) */\nfunction mirrorCopy(sourceDir: string, targetSkillDir: string): void {\n rmSync(targetSkillDir, { recursive: true, force: true })\n mkdirSync(targetSkillDir, { recursive: true })\n for (const entry of readdirSync(sourceDir)) {\n const src = join(sourceDir, entry)\n const dst = join(targetSkillDir, entry)\n if (statSync(src).isDirectory()) {\n cpSync(src, dst, { recursive: true })\n } else {\n cpSync(src, dst)\n }\n }\n}\n\n/**\n * 安装产品 skill 到单个 agent skills 目录。\n * 返回 InstallResult;失败时 status='failed' 且 detail 含错误信息(不抛错,便于批量收尾)。\n */\nexport async function installSkillToDir(options: InstallOptions): Promise<InstallResult> {\n const { sourceDir, targetDir, force, dryRun, confirmOverwrite } = options\n const skillTarget = join(targetDir, PRODUCT_SKILL_NAME)\n\n if (!existsSync(sourceDir)) {\n return { status: 'failed', targetDir, detail: `权威源不存在: ${sourceDir}` }\n }\n\n if (dryRun) {\n try {\n const same = existsSync(skillTarget) && isContentSame(sourceDir, skillTarget)\n return same\n ? { status: 'up-to-date', targetDir, detail: '[dry-run] 已一致' }\n : { status: 'installed', targetDir, detail: '[dry-run] 将安装' }\n } catch (error: unknown) {\n return { status: 'failed', targetDir, detail: errorMessage(error) }\n }\n }\n\n if (!existsSync(skillTarget)) {\n try {\n mirrorCopy(sourceDir, skillTarget)\n return { status: 'installed', targetDir }\n } catch (error: unknown) {\n cleanupPartial(skillTarget)\n return { status: 'failed', targetDir, detail: errorMessage(error) }\n }\n }\n\n // 已存在:内容一致则幂等跳过\n let same: boolean\n try {\n same = isContentSame(sourceDir, skillTarget)\n } catch (error: unknown) {\n return { status: 'failed', targetDir, detail: errorMessage(error) }\n }\n if (same) {\n return { status: 'up-to-date', targetDir }\n }\n\n // 内容不一致:需要确认覆盖(非交互默认拒绝)\n const allowed = force ?? (confirmOverwrite ? await confirmOverwrite(skillTarget) : false)\n if (!allowed) {\n return {\n status: 'skipped-conflict',\n targetDir,\n detail: '目标存在内容不一致的同名 skill,已跳过(使用 --force 或交互确认覆盖)',\n }\n }\n\n try {\n mirrorCopy(sourceDir, skillTarget)\n return { status: 'installed', targetDir, detail: '已覆盖旧版本' }\n } catch (error: unknown) {\n cleanupPartial(skillTarget)\n return { status: 'failed', targetDir, detail: errorMessage(error) }\n }\n}\n\n/** mirrorCopy 失败后清理半写目录(避免下次安装误判为内容不一致需 force) */\nfunction cleanupPartial(skillTarget: string): void {\n try {\n rmSync(skillTarget, { recursive: true, force: true })\n } catch {\n // 清理失败不掩盖原始错误\n }\n}\n\nfunction errorMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error)\n}\n","// ---------------------------------------------------------------------------\n// dependfix skills doctor 核心逻辑\n// ---------------------------------------------------------------------------\n// 检查项:\n// 1. 已检测 agent 的 skills 目录存在性(目录约定漂移提示:主目录在但 skills 目录缺失)\n// 2. 产品 skill 安装状态(已检测 agent 的 skills 目录中 dependfix-remediator 是否存在、\n// 内容与当前 CLI 携带版本是否一致)\n// 3. 内部开发 skill internal 标记完整性(在 dependfix 仓库内运行时,扫描 .github/skills)\n// 全部为只读检查,输出分级问题清单。\n\nimport { existsSync, readFileSync, readdirSync } from 'node:fs'\nimport { join } from 'node:path'\nimport { AGENTS } from './agents'\nimport { isContentSame } from './installer'\nimport { PRODUCT_SKILL_NAME, resolveProductSkillSourceDir } from './source'\n\nexport type DoctorLevel = 'ok' | 'warn' | 'error'\n\nexport interface DoctorFinding {\n level: DoctorLevel\n message: string\n}\n\nexport interface DoctorOptions {\n homeDir: string\n /** 项目根(用于项目级目录检查与内部 skill 扫描);缺省为当前工作目录 */\n projectRoot?: string\n /** 产品 skill 权威源目录(缺省从 @dependfix/skills 包解析;测试可注入) */\n productSourceDir?: string\n}\n\nexport function runDoctor(options: DoctorOptions): DoctorFinding[] {\n const { homeDir, projectRoot = process.cwd() } = options\n const findings: DoctorFinding[] = []\n\n // 1. agent 目录约定检查\n for (const agent of AGENTS) {\n const installed = agent.detectInstalled(homeDir)\n if (!installed) {\n continue\n }\n const globalDir = agent.globalSkillDir(homeDir)\n if (!existsSync(globalDir)) {\n findings.push({\n level: 'warn',\n message: `${agent.displayName} 已检测到,但全局 skills 目录缺失(${globalDir})——可能官方目录约定已变更,或尚未初始化`,\n })\n }\n const projectDir = agent.projectSkillDir(projectRoot)\n if (projectDir && !existsSync(projectDir)) {\n findings.push({\n level: 'ok',\n message: `${agent.displayName} 项目级 skills 目录不存在(${projectDir})——非问题,按需创建`,\n })\n }\n }\n\n // 2. 产品 skill 安装状态\n const sourceDir = options.productSourceDir ?? safeResolveSourceDir()\n if (sourceDir) {\n for (const agent of AGENTS) {\n if (!agent.detectInstalled(homeDir)) {\n continue\n }\n const installedDir = join(agent.globalSkillDir(homeDir), PRODUCT_SKILL_NAME)\n if (!existsSync(installedDir)) {\n findings.push({\n level: 'ok',\n message: `${agent.displayName}: ${PRODUCT_SKILL_NAME} 未安装(运行 dependfix skills install)`,\n })\n continue\n }\n if (isContentSame(sourceDir, installedDir)) {\n findings.push({\n level: 'ok',\n message: `${agent.displayName}: ${PRODUCT_SKILL_NAME} 已安装且与当前版本一致`,\n })\n } else {\n findings.push({\n level: 'warn',\n message: `${agent.displayName}: ${PRODUCT_SKILL_NAME} 已安装但内容与当前版本不一致(建议重新 install)`,\n })\n }\n }\n }\n\n // 3. 内部开发 skill internal 标记完整性(仅 dependfix 仓库内)\n const internalSkillsRoot = join(projectRoot, '.github', 'skills')\n if (existsSync(internalSkillsRoot)) {\n const missing: string[] = []\n for (const entry of readdirSync(internalSkillsRoot, { withFileTypes: true })) {\n if (!entry.isDirectory()) {\n continue\n }\n const skillFile = join(internalSkillsRoot, entry.name, 'SKILL.md')\n if (!existsSync(skillFile)) {\n missing.push(`${entry.name}(缺 SKILL.md)`)\n continue\n }\n const content = readFileSync(skillFile, 'utf8')\n if (!/metadata:\\s*\\r?\\n\\s*internal:\\s*true/.test(content)) {\n missing.push(entry.name)\n }\n }\n if (missing.length > 0) {\n findings.push({\n level: 'error',\n message: `内部 skill internal 标记缺失(生态可见泄漏风险): ${missing.join(', ')}`,\n })\n } else {\n findings.push({\n level: 'ok',\n message: `内部 skill internal 标记完整性检查通过(.github/skills)`,\n })\n }\n }\n\n return findings\n}\n\n/** 解析产品 skill 源目录;失败返回 undefined(如 CLI 运行在无 @dependfix/skills 的调试环境) */\nfunction safeResolveSourceDir(): string | undefined {\n try {\n return resolveProductSkillSourceDir()\n } catch {\n return undefined\n }\n}\n","// ---------------------------------------------------------------------------\n// dependfix skills 子命令(install / doctor)\n// ---------------------------------------------------------------------------\n// 定位:npx skills 生态的离线兜底安装器。\n// 不依赖 npx skills;不复刻 add/list/update/remove 完整命令矩阵。\n// 主通道(npx skills add dependfix/dependfix -s dependfix-remediator)见 README。\n\nimport { homedir } from 'node:os'\nimport { defineCommand, renderUsage } from 'citty'\nimport { AGENTS } from './agents'\nimport { runDoctor, type DoctorFinding } from './doctor'\nimport { installSkillToDir, type InstallResult } from './installer'\nimport { resolveProductSkillSourceDir } from './source'\n\n// ---------------------------------------------------------------------------\n// install\n// ---------------------------------------------------------------------------\n\ninterface InstallCliArgs {\n project?: boolean\n force?: boolean\n 'dry-run'?: boolean\n}\n\nasync function runInstall(args: InstallCliArgs): Promise<void> {\n const home = homedir()\n const projectRoot = process.cwd()\n\n let sourceDir: string\n try {\n sourceDir = resolveProductSkillSourceDir()\n } catch (error: unknown) {\n console.error(`无法定位产品 skill 内容(@dependfix/skills 未安装?): ${error instanceof Error ? error.message : String(error)}`)\n process.exitCode = 1\n return\n }\n\n const detected = AGENTS.filter((agent) => agent.detectInstalled(home))\n if (detected.length === 0) {\n console.info('未检测到已安装的 agent 工具(Claude Code / OpenCode / Cursor / Copilot)。')\n console.info('主通道安装(推荐): npx skills add dependfix/dependfix -s dependfix-remediator -g')\n return\n }\n\n console.info(`检测到 ${detected.length} 个 agent 工具,目标模式: ${args.project ? '项目级' : '全局'}\\n`)\n\n const results: { agent: string, result: InstallResult }[] = []\n for (const agent of detected) {\n const agentDir = args.project ? agent.projectSkillDir(projectRoot) : agent.globalSkillDir(home)\n if (!agentDir) {\n console.info(`- ${agent.displayName}: 不支持 ${args.project ? '项目级' : ''}安装,跳过`)\n continue\n }\n const result = await installSkillToDir({\n sourceDir,\n targetDir: agentDir,\n force: args.force,\n dryRun: args['dry-run'],\n confirmOverwrite: (existingDir) => confirmOverwritePrompt(agent.displayName, existingDir),\n })\n results.push({ agent: agent.displayName, result })\n }\n\n console.info('\\n安装清单:')\n const installIcons: Record<InstallResult['status'], string> = {\n installed: '✓',\n 'up-to-date': '=',\n 'skipped-conflict': '!',\n failed: '✗',\n }\n for (const { agent, result } of results) {\n const icon = installIcons[result.status]\n console.info(` ${icon} ${agent}: ${result.status}${result.detail ? ` — ${result.detail}` : ''}`)\n }\n\n const failed = results.filter((r) => r.result.status === 'failed')\n if (failed.length > 0) {\n process.exitCode = 1\n }\n}\n\n/** 交互式覆盖确认;非 TTY 返回 false(不静默覆盖) */\nasync function confirmOverwritePrompt(agentName: string, existingDir: string): Promise<boolean> {\n if (!process.stdin.isTTY) {\n console.warn(` ${agentName}: 目标已存在内容不一致的 dependfix-remediator,非交互环境跳过(使用 --force 覆盖)`)\n return false\n }\n const readline = (await import('node:readline')).createInterface({\n input: process.stdin,\n output: process.stdout,\n })\n return new Promise<boolean>((resolve) => {\n readline.question(` 覆盖 ${existingDir} 中的旧版本?[y/N] `, (answer) => {\n readline.close()\n resolve(answer.trim().toLowerCase() === 'y' || answer.trim().toLowerCase() === 'yes')\n })\n })\n}\n\n// ---------------------------------------------------------------------------\n// doctor\n// ---------------------------------------------------------------------------\n\nasync function runDoctorCli(): Promise<void> {\n const findings = runDoctor({ homeDir: homedir(), projectRoot: process.cwd() })\n const doctorIcons: Record<DoctorFinding['level'], string> = { ok: '✓', warn: '!', error: '✗' }\n let warnCount = 0\n let errorCount = 0\n for (const finding of findings) {\n const icon = doctorIcons[finding.level]\n console.info(` ${icon} [${finding.level}] ${finding.message}`)\n if (finding.level === 'warn') {\n warnCount++\n } else if (finding.level === 'error') {\n errorCount++\n }\n }\n console.info(`\\ndoctor 完成: ${findings.length} 项检查,${warnCount} warning, ${errorCount} error`)\n if (errorCount > 0) {\n process.exitCode = 1\n }\n}\n\n// ---------------------------------------------------------------------------\n// citty command\n// ---------------------------------------------------------------------------\n\nexport const skillsCommand = defineCommand({\n meta: {\n name: 'skills',\n description: '产品 skill 管理(npx skills 生态的离线兜底安装器)',\n },\n subCommands: {\n install: defineCommand({\n meta: {\n name: 'install',\n description: '检测本机已装 agent 工具并安装 dependfix-remediator 产品 skill',\n },\n args: {\n project: {\n type: 'boolean',\n description: '安装到当前项目目录(默认用户全局)',\n negativeDescription: '安装到用户全局(默认)',\n },\n force: {\n type: 'boolean',\n description: '覆盖已存在的内容不一致同名 skill(跳过确认)',\n negativeDescription: '内容不一致时需确认(默认)',\n },\n 'dry-run': {\n type: 'boolean',\n description: '只输出将要执行的操作,不写文件',\n negativeDescription: '实际执行安装',\n },\n },\n async run({ args }) {\n await runInstall(args as InstallCliArgs)\n },\n }),\n doctor: defineCommand({\n meta: {\n name: 'doctor',\n description: '检查 agent 目录约定、产品 skill 安装状态与内部 skill internal 标记完整性',\n },\n async run() {\n await runDoctorCli()\n },\n }),\n },\n async run({ cmd, rawArgs }) {\n // citty 0.2.2 在路由子命令后仍会执行父 run:子命令已执行时直接返回,避免重复输出 usage\n const sub = rawArgs[0]\n if (sub === 'install' || sub === 'doctor') {\n return\n }\n console.info(await renderUsage(cmd))\n },\n})\n","// CLI 执行层(解析与执行分离):\n// - cli/index.ts:argsDef + parseCliArgs(纯解析,无执行依赖)\n// - cli/runner.ts:runCli / runApp / dependfixCommand(经 createPipeline 执行)\n// - app/pipeline.ts:createPipeline(local 与 platform 共用编排核心)\n//\n// 依赖方向:runner → pipeline → cli/index(纯解析),无循环。\n\nimport { defineCommand, renderUsage, runCommand, runMain, showUsage } from 'citty'\nimport { toAppError } from '@dependfix/core'\nimport type { RuntimeConfig } from '@dependfix/engine'\nimport { createPipeline, type PipelineLogger } from '../app/pipeline'\nimport { skillsCommand } from '../skills'\nimport { argsDef, type CliInvocation } from './index'\n\nexport interface CliRunResult {\n ok: true\n invocation: CliInvocation\n config: RuntimeConfig\n}\n\n/** 默认 CLI 日志(console);platform 场景经 createPipeline 注入自定义 logger */\nconst cliLogger: PipelineLogger = console\n\n// ---------------------------------------------------------------------------\n// Public API(签名与行为保持兼容)\n// ---------------------------------------------------------------------------\n\nexport function runCli(rawArgs: string[]): CliRunResult {\n return createPipeline({ logger: cliLogger }).parse(rawArgs)\n}\n\n// ---------------------------------------------------------------------------\n// App execution\n// ---------------------------------------------------------------------------\n\nasync function runApp(rawArgs: string[]): Promise<number> {\n return createPipeline({ logger: cliLogger }).run(rawArgs)\n}\n\n// ---------------------------------------------------------------------------\n// citty command\n// ---------------------------------------------------------------------------\n// 注意:不使用 citty subCommands 字段——citty 0.2.2 在 subCommands 模式下会\n// ① 子命令执行后继续执行父 run;② 不匹配子命令的 positional(如 fix)抛\n// Unknown command。因此 skills 子命令由 run 首部编程路由(runCommand),\n// 主流程 positional 命令面不受影响。\n\nexport const dependfixCommand = defineCommand({\n meta: {\n name: 'dependfix',\n version: '0.1.0',\n description: '自动化处理 Dependabot / Code Scanning 安全告警的修复工具',\n },\n args: argsDef,\n async run({ rawArgs }) {\n // skills 子命令路由(install / doctor)\n if (rawArgs[0] === 'skills') {\n await runCommand(skillsCommand, { rawArgs: rawArgs.slice(1) })\n return\n }\n\n let exitCode = 1\n try {\n exitCode = await runApp(rawArgs)\n } catch (error: unknown) {\n const appError = toAppError(error, 'CLI_EXECUTION_FAILED')\n console.error(`Error: ${appError.message}`)\n exitCode = 1\n }\n process.exitCode = exitCode\n },\n})\n\n// ---------------------------------------------------------------------------\n// 入口封装:补 skills 子命令的 --help 路由\n// ---------------------------------------------------------------------------\n// citty runMain 在 runCommand 前拦截内建 --help,且 resolveSubCommand 依赖\n// subCommands 字段下钻;dependfixCommand 无该字段(见上),故 skills 相关\n// --help 会被截获为主命令 usage。此处显式路由到 skills usage。\n\nexport async function runDependfixMain(rawArgs: string[] = process.argv.slice(2)): Promise<void> {\n if (rawArgs[0] === 'skills' && (rawArgs.includes('--help') || rawArgs.includes('-h'))) {\n console.info(await renderUsage(skillsCommand))\n process.exitCode = 0\n return\n }\n await runMain(dependfixCommand, { showUsage })\n}\n"],"mappings":";;;;;;;;;;AA6BA,MAAa,UAAU;CACnB,MAAM;EACF,MAAM;EACN,aAAa;EACb,UAAU;EACV,SAAS;CACb;CACA,MAAM;EACF,MAAM;EACN,aAAa;EACb,OAAO;GAAC;GAAK;GAAc;EAAc;CAC7C;CACA,cAAc;EACV,MAAM;EACN,aAAa;CACjB;CACA,OAAO;EACH,MAAM;EACN,aAAa;CACjB;CACA,eAAe;EACX,MAAM;EACN,aAAa;CACjB;CACA,gBAAgB;EACZ,MAAM;EACN,aAAa;CACjB;CACA,gBAAgB;EACZ,MAAM;EACN,aAAa;CACjB;CACA,uBAAuB;EACnB,MAAM;EACN,aAAa;CACjB;CACA,sBAAsB;EAClB,MAAM;EACN,aAAa;EACb,SAAS;CACb;CACA,WAAW;EACP,MAAM;EACN,aAAa;EACb,qBAAqB;CACzB;CACA,aAAa;EACT,MAAM;EACN,aAAa;EACb,qBAAqB;CACzB;CACA,QAAQ;EACJ,MAAM;EACN,aAAa;EACb,qBAAqB;CACzB;CACA,oBAAoB;EAChB,MAAM;EACN,aAAa;EACb,qBAAqB;CACzB;CACA,yBAAyB;EACrB,MAAM;EACN,aAAa;EACb,qBAAqB;CACzB;CACA,gBAAgB;EACZ,MAAM;EACN,aAAa;CACjB;CACA,gBAAgB;EACZ,MAAM;EACN,aAAa;CACjB;CACA,iBAAiB;EACb,MAAM;EACN,aAAa;CACjB;CACA,iBAAiB;EACb,MAAM;EACN,aAAa;EACb,qBAAqB;CACzB;CACA,gBAAgB;EACZ,MAAM;EACN,aAAa;EACb,qBAAqB;CACzB;CACA,uBAAuB;EACnB,MAAM;EACN,aAAa;EACb,qBAAqB;CACzB;CACA,6BAA6B;EACzB,MAAM;EACN,aAAa;EACb,SAAS;CACb;CACA,mBAAmB;EACf,MAAM;EACN,aAAa;EACb,SAAS;CACb;CACA,eAAe;EACX,MAAM;EACN,aAAa;EACb,SAAS;CACb;CACA,kBAAkB;EACd,MAAM;EACN,aAAa;EACb,SAAS;CACb;CACA,aAAa;EACT,MAAM;EACN,aAAa;EACb,SAAS;CACb;CACA,SAAS;EACL,MAAM;EACN,aAAa;CACjB;CA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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dependfix",
3
- "version": "0.3.2",
3
+ "version": "0.5.0",
4
4
  "description": "一个自动化修复 github security 告警的方案",
5
5
  "author": "CaoMeiYouRen",
6
6
  "license": "MIT",
@@ -43,7 +43,7 @@
43
43
  "dependencies": {
44
44
  "@octokit/rest": "^22.0.1",
45
45
  "citty": "^0.2.2",
46
- "dayjs": "^1.11.21",
46
+ "dayjs": "^1.11.23",
47
47
  "dotenv": "^17.4.2",
48
48
  "fs-extra": "^11.4.0",
49
49
  "isomorphic-unfetch": "^4.0.2",
@@ -51,21 +51,21 @@
51
51
  "tslib": "^2.8.1",
52
52
  "yaml": "^2.9.0",
53
53
  "zx": "^8.8.5",
54
- "@dependfix/core": "0.2.1",
55
- "@dependfix/skills": "0.1.0",
56
- "@dependfix/engine": "0.1.3"
54
+ "@dependfix/core": "0.5.0",
55
+ "@dependfix/engine": "0.4.0",
56
+ "@dependfix/skills": "0.2.0"
57
57
  },
58
58
  "devDependencies": {
59
59
  "@types/debug": "^4.1.13",
60
60
  "@types/fs-extra": "^11.0.4",
61
61
  "@types/lodash-es": "^4.17.12",
62
- "@types/node": "^26.1.2",
62
+ "@types/node": "^26.5.1",
63
63
  "cross-env": "^10.0.0",
64
64
  "debug": "^4.4.3",
65
65
  "nock": "^14.0.17",
66
66
  "rimraf": "^6.1.3",
67
- "tsdown": "^0.22.14",
68
- "tsx": "^4.23.1",
67
+ "tsdown": "^0.23.0",
68
+ "tsx": "^4.23.13",
69
69
  "typescript": "^6.0.3"
70
70
  },
71
71
  "scripts": {