@jahanxu/code-flow 0.2.1 → 0.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jahanxu/code-flow",
3
- "version": "0.2.1",
3
+ "version": "0.2.3",
4
4
  "license": "UNLICENSED",
5
5
  "bin": {
6
6
  "code-flow": "src/cli.js"
@@ -0,0 +1,56 @@
1
+ # cf-task:archive
2
+
3
+ 归档已完成的整个 task 文件。
4
+
5
+ ## 输入
6
+
7
+ - `/cf-task:archive <file>` — 归档指定的 task 文件
8
+
9
+ 其中 `<file>` 可省略日期目录前缀和 `.md` 后缀。
10
+
11
+ 查找逻辑:用 Glob 搜索 `.code-flow/tasks/**/<file>.md`(排除 `archived/`),匹配第一个结果。
12
+
13
+ ## 执行步骤
14
+
15
+ ### 1. 完成度检查
16
+
17
+ 1. 用 Read 读取匹配到的 task 文件
18
+ 2. 提取所有 `## TASK-xxx` 段落的 Status
19
+ 3. 检查是否所有子任务均为 `done`
20
+
21
+ 若有未完成子任务,拒绝归档并输出:
22
+
23
+ ```
24
+ 无法归档: 以下子任务未完成
25
+
26
+ - TASK-002: in-progress (进度 1/4)
27
+ - TASK-004: blocked ([BLOCKED] 等待 SDK)
28
+
29
+ 请先完成所有子任务后再归档。
30
+ 当前完成度: 2/4 (50%)
31
+ ```
32
+
33
+ ### 2. 执行归档
34
+
35
+ 所有子任务已完成:
36
+
37
+ 1. 提取文件所在的日期目录名(如 `2026-03-15`)
38
+ 2. 用 Bash 创建归档目录并移动文件:
39
+ ```bash
40
+ mkdir -p .code-flow/tasks/archived/<日期目录>
41
+ mv .code-flow/tasks/<日期目录>/<file>.md .code-flow/tasks/archived/<日期目录>/
42
+ ```
43
+ 3. 如果原日期目录为空,删除空目录
44
+
45
+ ### 3. 归档摘要
46
+
47
+ ```
48
+ 已归档: <file>.md → .code-flow/tasks/archived/<日期目录>/<file>.md
49
+
50
+ 摘要:
51
+ - 来源: docs/xxx设计说明书.md
52
+ - 子任务数: N 个
53
+ - 创建日期: 2026-03-15
54
+ - 归档日期: 2026-03-20
55
+ - 历时: 5 天
56
+ ```
@@ -0,0 +1,30 @@
1
+ # cf-task:block
2
+
3
+ 标记子任务为阻塞状态。
4
+
5
+ ## 输入
6
+
7
+ - `/cf-task:block <file> TASK-001 "阻塞原因"`
8
+
9
+ 其中 `<file>` 可省略日期目录前缀和 `.md` 后缀。
10
+
11
+ 查找逻辑:用 Glob 搜索 `.code-flow/tasks/**/<file>.md`(排除 `archived/`),匹配第一个结果。
12
+
13
+ ## 执行步骤
14
+
15
+ 1. 用 Glob 定位任务文件,Read 读取
16
+ 2. 定位 `## TASK-001` 段落,检查当前 Status:
17
+ - `done` → 拒绝:`TASK-001 已完成,无法标记阻塞`
18
+ - `blocked` → 提示:`TASK-001 已处于 blocked 状态`,仍追加新的阻塞原因
19
+ - `draft` / `in-progress` → 继续
20
+ 3. 用 Edit 更新 Status 为 `blocked`
21
+ 4. 在 `### Notes` 追加:`- [BLOCKED] <阻塞原因>`
22
+ 5. 在 `### Log` 追加:`- [<当前日期>] blocked (<阻塞原因>)`
23
+ 6. 更新文件头 `Updated` 日期
24
+ 7. 输出确认:`TASK-001 已标记为 blocked: <原因>`
25
+
26
+ ## 解除阻塞
27
+
28
+ 阻塞的解除不通过本命令操作,而是:
29
+ - 如果是 Notes 导致的阻塞 → 用 `/cf-task:note resolve` 解决批注后自动解除
30
+ - 如果是 `[BLOCKED]` 标记 → 用户手动编辑文件移除 `[BLOCKED]` 条目,或用 `/cf-task:start` 重新启动(需所有阻塞条件清除)
@@ -0,0 +1,73 @@
1
+ # cf-task:graph
2
+
3
+ 可视化子任务的依赖关系 DAG,识别可并行执行的任务组。
4
+
5
+ ## 输入
6
+
7
+ - `/cf-task:graph <file>` — 显示指定文件的依赖图
8
+ - `/cf-task:graph` — 显示所有活跃 task 文件的依赖图
9
+
10
+ 其中 `<file>` 可省略日期目录前缀和 `.md` 后缀。
11
+
12
+ 查找逻辑:用 Glob 搜索 `.code-flow/tasks/**/<file>.md`(排除 `archived/`),匹配第一个结果。
13
+
14
+ ## 执行步骤
15
+
16
+ ### 1. 读取任务数据
17
+
18
+ - 指定文件:Glob 定位后 Read
19
+ - 全部文件:Glob `.code-flow/tasks/**/*.md`(排除 `archived/` 目录),逐个 Read
20
+
21
+ 从每个 `## TASK-xxx` 段落提取:ID、标题、Status、Depends。
22
+
23
+ ### 2. 构建依赖 DAG
24
+
25
+ 按依赖关系构建有向无环图。检测循环依赖,若存在则报错。
26
+
27
+ ### 3. 输出可视化
28
+
29
+ 用 ASCII art 渲染 DAG,格式示例:
30
+
31
+ ```
32
+ 依赖关系图: auth-module
33
+
34
+ Layer 0 (无依赖):
35
+ ┌──────────────────────┐ ┌──────────────────────┐
36
+ │ TASK-001 [draft] │ │ TASK-003 [draft] │
37
+ │ 用户模型定义 │ │ JWT 工具函数 │
38
+ └──────────┬───────────┘ └──────────┬───────────┘
39
+ │ │
40
+ ▼ │
41
+ Layer 1: │ │
42
+ ┌──────────┴───────────┐ │
43
+ │ TASK-002 [draft] │◄─────────────┘
44
+ │ 注册接口实现 │
45
+ └──────────┬───────────┘
46
+
47
+
48
+ Layer 2:
49
+ ┌──────────┴───────────┐
50
+ │ TASK-004 [draft] │
51
+ │ 登录接口实现 │
52
+ └──────────────────────┘
53
+
54
+ 可并行执行组:
55
+ - 组 1: TASK-001, TASK-003 (无依赖,可同时开始)
56
+ - 组 2: TASK-002 (需等待组 1 完成)
57
+ - 组 3: TASK-004 (需等待组 2 完成)
58
+
59
+ 建议执行顺序: TASK-001 → TASK-003 → TASK-002 → TASK-004
60
+ 关键路径: TASK-001 → TASK-002 → TASK-004
61
+ ```
62
+
63
+ ### 4. 状态标注
64
+
65
+ 按子任务状态标注:
66
+ - `[draft]` — 待启动
67
+ - `[in-progress]` — 进行中
68
+ - `[done]` — 已完成
69
+ - `[blocked]` — 被阻塞(附原因)
70
+
71
+ ### 5. 多文件模式
72
+
73
+ 当显示所有文件时,按文件分组输出,每个文件一个独立的 DAG。
@@ -0,0 +1,42 @@
1
+ # cf-task:note
2
+
3
+ 为子任务添加审阅批注或标记批注为已解决。
4
+
5
+ ## 输入
6
+
7
+ - `/cf-task:note <file> TASK-001 "批注内容"` — 添加新批注
8
+ - `/cf-task:note <file> TASK-001 resolve NOTE-1` — 标记批注为已解决
9
+ - `/cf-task:note <file> TASK-001 resolve all` — 标记所有批注为已解决
10
+
11
+ 其中 `<file>` 可省略日期目录前缀和 `.md` 后缀。
12
+
13
+ 查找逻辑:用 Glob 搜索 `.code-flow/tasks/**/<file>.md`(排除 `archived/`),匹配第一个结果。
14
+
15
+ ## 添加批注
16
+
17
+ ### 执行步骤
18
+
19
+ 1. 用 Glob 定位任务文件,Read 读取
20
+ 2. 定位 `## TASK-001` 段落下的 `### Notes` 区域
21
+ 3. 扫描已有 `[NOTE-n]`,计算下一个编号
22
+ 4. 用 Edit 在 `### Notes` 下追加:`- [NOTE-<n>] <批注内容>`
23
+ 5. 如果子任务 Status 为 `in-progress`,自动用 Edit 改为 `blocked`,并在 `### Log` 追加:`- [<当前日期>] blocked (unresolved note)`
24
+ 6. 更新文件头 `Updated` 日期
25
+ 7. 输出确认:`已添加 [NOTE-<n>],TASK-001 状态: blocked`
26
+
27
+ ## 解决批注
28
+
29
+ ### 执行步骤
30
+
31
+ 1. 用 Read 读取任务文件
32
+ 2. 定位指定的 `[NOTE-n]` 批注
33
+ 3. 用 Edit 将 `[NOTE-n]` 改为 `[NOTE-n] [RESOLVED]`
34
+ 4. 检查是否还有未解决的 Notes:
35
+ - 全部解决 + 状态为 blocked → 自动恢复为 `draft`(如果之前是 draft 被阻塞)或 `in-progress`
36
+ - 在 `### Log` 追加:`- [<当前日期>] unblocked (notes resolved)`
37
+ 5. 更新文件头 `Updated` 日期
38
+ 6. 输出确认
39
+
40
+ ## resolve all 模式
41
+
42
+ 批量标记所有未解决的 Notes 为 `[RESOLVED]`,同时检查是否可以自动解除 blocked 状态。
@@ -0,0 +1,161 @@
1
+ # cf-task:plan
2
+
3
+ 从设计文档拆解需求,生成结构化任务文件。
4
+
5
+ ## 输入
6
+
7
+ - `/cf-task:plan <设计文档路径>` — 指定文档路径
8
+ - `/cf-task:plan` — 交互式选择(从 `docs/` 目录列出候选)
9
+
10
+ ## 执行步骤
11
+
12
+ ### 1. 获取设计文档
13
+
14
+ 如果用户提供了路径,直接用 Read 读取。
15
+
16
+ 如果未提供路径:
17
+ 1. 用 Glob 搜索 `docs/**/*.md` 列出所有文档
18
+ 2. 展示列表,让用户选择目标文档
19
+ 3. Read 读取选中的文档
20
+
21
+ ### 2. 建立章节索引
22
+
23
+ Read 设计文档后,**先扫描文档结构**,建立章节索引表:
24
+
25
+ ```
26
+ 章节索引:
27
+ §1 概述 (L1-L25)
28
+ §2 需求分析 (L26-L80)
29
+ §2.1 用户故事 (L28-L55)
30
+ §2.2 非功能需求 (L56-L80)
31
+ §3 详细设计 (L81-L200)
32
+ §3.1 数据模型 (L83-L110)
33
+ §3.2 API 接口 (L111-L155)
34
+ §3.3 业务逻辑 (L156-L200)
35
+ ...
36
+ ```
37
+
38
+ 此索引用于后续步骤中精确记录每个子任务的来源章节。
39
+
40
+ ### 3. 分析文档,拆解子任务
41
+
42
+ 阅读设计文档内容,按以下原则拆解:
43
+
44
+ **拆解粒度**:
45
+ - 每个子任务应是一个可独立编码和验证的原子单元
46
+ - 一个子任务对应 1-3 个文件的修改
47
+ - 预估编码时间 15-60 分钟
48
+
49
+ **提取内容**:
50
+ - 功能需求 → 子任务标题 + 描述(提炼重点,不必复制全文)
51
+ - 实现要点 → Checklist 条目
52
+ - 模块依赖 → Depends 字段
53
+ - 紧急程度 → Priority(P0 核心功能 / P1 重要功能 / P2 优化项)
54
+
55
+ **关键:精确记录章节引用**
56
+
57
+ 每个子任务的 `Source` 字段必须记录该任务对应的详设文档**具体章节和行号范围**。
58
+
59
+ 引用格式:`文件路径#章节标题(L起始-L结束)`,多个章节用逗号分隔。
60
+
61
+ 验证方法:记录引用后,用 Read 工具按行号范围回读验证,确保引用内容与子任务描述一致。如不一致,修正行号。
62
+
63
+ ### 4. 生成任务文件方案
64
+
65
+ 将拆解结果按以下格式组织,展示给用户确认:
66
+
67
+ ```markdown
68
+ # Tasks: <功能/模块名称>
69
+
70
+ - **Source**: <设计文档路径>
71
+ - **Created**: <当前日期>
72
+ - **Updated**: <当前日期>
73
+
74
+ ---
75
+
76
+ ## TASK-001: <子任务标题>
77
+
78
+ - **Status**: draft
79
+ - **Priority**: P0
80
+ - **Depends**:
81
+ - **Source**: docs/xxx.md#§3.1 数据模型(L83-L110)
82
+
83
+ ### Description
84
+ <从设计文档提取的需求重点,不必复制全文>
85
+
86
+ ### Checklist
87
+ - [ ] <具体实现步骤1>
88
+ - [ ] <具体实现步骤2>
89
+ - [ ] <编写测试>
90
+
91
+ ### Notes
92
+
93
+ ### Log
94
+ - [<当前日期>] created (draft)
95
+
96
+ ---
97
+
98
+ ## TASK-002: <子任务标题>
99
+
100
+ - **Status**: draft
101
+ - **Priority**: P1
102
+ - **Depends**: TASK-001
103
+ - **Source**: docs/xxx.md#§3.2 API 接口(L111-L155), docs/xxx.md#§3.3 业务逻辑(L156-L180)
104
+
105
+ ### Description
106
+ ...
107
+ ```
108
+
109
+ **展示格式**(供用户审阅):
110
+
111
+ ```
112
+ 拆解结果(共 N 个子任务):
113
+
114
+ TASK-001: <标题> [P0]
115
+ 来源: §3.1 数据模型 (L83-L110)
116
+ 描述: ...
117
+ Checklist: N 项
118
+ 依赖: 无
119
+
120
+ TASK-002: <标题> [P1]
121
+ 来源: §3.2 API 接口 (L111-L155), §3.3 业务逻辑 (L156-L180)
122
+ 描述: ...
123
+ Checklist: N 项
124
+ 依赖: TASK-001
125
+
126
+ 确认写入?可以调整:
127
+ - 修改某个子任务的内容
128
+ - 删除不需要的子任务
129
+ - 合并过于细碎的子任务
130
+ - 调整依赖关系和章节引用
131
+ ```
132
+
133
+ 等待用户确认或调整。
134
+
135
+ ### 5. 写入文件
136
+
137
+ 用户确认后:
138
+ 1. 文件名取模块/功能名(kebab-case),如 `auth-module.md`
139
+ 2. 按当前日期创建目录:`.code-flow/tasks/<YYYY-MM-DD>/`
140
+ 3. 用 Write 写入 `.code-flow/tasks/<YYYY-MM-DD>/<name>.md`
141
+
142
+ ### 6. 输出摘要
143
+
144
+ ```
145
+ 已生成任务文件: .code-flow/tasks/2026-03-15/auth-module.md
146
+ - 子任务数: N
147
+ - P0: x 个, P1: y 个, P2: z 个
148
+ - 依赖链深度: N 层
149
+ - 详设引用覆盖: §3.1, §3.2, §3.3, §3.5 (共 4 个章节)
150
+
151
+ 建议执行顺序:
152
+ 1. TASK-001 (无依赖)
153
+ 2. TASK-003 (无依赖) ← 可与 TASK-001 并行
154
+ 3. TASK-002 (依赖: TASK-001)
155
+ ...
156
+
157
+ 下一步:
158
+ - 审阅任务: 直接阅读 .code-flow/tasks/2026-03-15/auth-module.md
159
+ - 添加批注: /cf-task:note auth-module TASK-001 "批注内容"
160
+ - 开始编码: /cf-task:start auth-module
161
+ ```
@@ -0,0 +1,118 @@
1
+ # cf-task:start
2
+
3
+ 激活子任务并开始编码。支持单任务模式和整文件模式。
4
+
5
+ ## 输入
6
+
7
+ - `/cf-task:start <file> TASK-001` — 激活指定文件中的单个子任务
8
+ - `/cf-task:start <file>` — 激活文件内所有可执行的 draft 子任务
9
+
10
+ 其中 `<file>` 为 `.code-flow/tasks/` 下的文件名,可省略日期目录前缀和 `.md` 后缀。
11
+
12
+ 查找逻辑:用 Glob 搜索 `.code-flow/tasks/**/<file>.md`,匹配第一个结果。
13
+
14
+ 示例:
15
+ - `/cf-task:start auth-module TASK-002`
16
+ - `/cf-task:start auth-module`
17
+
18
+ ## 单任务模式
19
+
20
+ ### 1. 前置检查
21
+
22
+ 用 Read 读取任务文件,定位 `## TASK-xxx` 段落:
23
+
24
+ **状态检查**:Status 必须为 `draft`。若为其他状态:
25
+ - `in-progress` → 提示"任务已在进行中,继续编码"(不阻塞,直接跳到步骤 2)
26
+ - `done` → 提示"任务已完成",结束
27
+ - `blocked` → 提示"任务被阻塞",列出 Notes 中的阻塞原因,结束
28
+
29
+ **Notes 检查**:扫描 `### Notes` 区域
30
+ - 如果存在 `[NOTE-n]` 格式的批注且未标记 `[RESOLVED]`,则拒绝启动
31
+ - 输出:`前置检查失败:以下 Notes 未解决\n- [NOTE-1] xxx\n- [NOTE-2] xxx\n请先解决后重试,或用 /cf-task:note 标记为 [RESOLVED]`
32
+
33
+ **依赖检查**:读取 `Depends` 字段
34
+ - 对每个依赖的 TASK-ID,在同文件中查找其 Status
35
+ - 所有依赖必须为 `done`
36
+ - 未满足 → 输出:`前置检查失败:以下依赖未完成\n- TASK-001: in-progress\n- TASK-003: draft`
37
+
38
+ ### 2. 加载详设上下文
39
+
40
+ 前置检查通过后,**编码前先加载关联的详设文档章节**:
41
+
42
+ 1. 读取子任务的 `Source` 字段,解析章节引用
43
+ - 格式:`docs/xxx.md#§3.1 数据模型(L83-L110)`
44
+ - 提取:文件路径 + 行号范围
45
+ 2. 用 Read 按行号范围读取详设文档的对应章节(使用 offset/limit 参数)
46
+ 3. 将读取的章节内容作为编码上下文,与 Checklist 一起指导实现
47
+
48
+ 示例:Source 为 `docs/auth.md#§3.2 API 接口(L111-L155), docs/auth.md#§3.5 错误码(L201-L220)`
49
+ → Read `docs/auth.md` offset=111 limit=45
50
+ → Read `docs/auth.md` offset=201 limit=20
51
+
52
+ ### 3. 激活并编码
53
+
54
+ 1. 用 Edit 更新子任务 Status 为 `in-progress`
55
+ 2. 在 `### Log` 追加:`- [<当前日期>] started (in-progress)`
56
+ 3. 更新文件头 `Updated` 日期
57
+ 4. 结合详设上下文 + Checklist,逐项执行编码工作
58
+ 5. 每完成一个 checklist 项 → 用 Edit 将 `- [ ]` 改为 `- [x]`
59
+
60
+ ### 4. 自动完成
61
+
62
+ 当所有 checklist 项都勾选为 `[x]` 后:
63
+ 1. 用 Edit 更新 Status 为 `done`
64
+ 2. 在 `### Log` 追加:`- [<当前日期>] completed (done)`
65
+ 3. 更新文件头 `Updated` 日期
66
+ 4. 输出:`TASK-xxx 已完成`
67
+
68
+ ## 整文件模式
69
+
70
+ ### 1. 扫描所有子任务
71
+
72
+ 用 Read 读取整个 task 文件,提取所有 `## TASK-xxx` 段落的 ID、Status、Depends。
73
+
74
+ ### 2. 加载详设文档
75
+
76
+ 读取文件头的 `Source` 字段,用 Read 加载完整的详设文档作为全局上下文。
77
+
78
+ > 注:整文件模式加载完整详设(因为涉及所有子任务),单任务模式只加载关联章节(节省 token)。
79
+
80
+ ### 3. 构建执行计划
81
+
82
+ 按依赖关系拓扑排序:
83
+ 1. 筛选所有 `draft` 状态的子任务
84
+ 2. 按依赖关系排序:先无依赖的,再逐层解锁
85
+ 3. 逐个检查 Notes 前置条件
86
+
87
+ 输出执行计划:
88
+ ```
89
+ 执行计划(共 N 个可激活子任务):
90
+
91
+ 批次 1(可并行):
92
+ - TASK-001: xxx
93
+ - TASK-003: xxx
94
+
95
+ 批次 2(依赖批次 1):
96
+ - TASK-002: xxx (依赖 TASK-001)
97
+
98
+ 跳过(前置条件未满足):
99
+ - TASK-004: Notes 未解决 [NOTE-1]
100
+ - TASK-005: 依赖 TASK-004 (blocked)
101
+
102
+ 开始执行...
103
+ ```
104
+
105
+ ### 4. 按序执行
106
+
107
+ 对每个可激活的子任务,执行单任务模式的步骤 3-4(详设已在步骤 2 加载,无需重复读取)。
108
+
109
+ 完成一个子任务后,检查是否解锁了新的子任务(依赖已满足),如果是则继续执行。
110
+
111
+ ### 5. 输出摘要
112
+
113
+ ```
114
+ 执行完成:
115
+ - 完成: TASK-001, TASK-003, TASK-002
116
+ - 跳过: TASK-004 (Notes 未解决)
117
+ - 剩余 draft: 1 个
118
+ ```
@@ -0,0 +1,59 @@
1
+ # cf-task:status
2
+
3
+ 显示任务状态总览。
4
+
5
+ ## 输入
6
+
7
+ - `/cf-task:status` — 显示所有活跃 task 文件的状态
8
+ - `/cf-task:status <file>` — 显示指定文件的详细状态
9
+
10
+ ## 执行步骤
11
+
12
+ ### 1. 读取任务数据
13
+
14
+ - 用 Glob 搜索 `.code-flow/tasks/**/*.md`(排除 `archived/` 目录)
15
+ - 逐个 Read,提取每个 `## TASK-xxx` 的:ID、标题、Status、Priority、Depends、Checklist 完成度
16
+
17
+ ### 2. 输出总览表格
18
+
19
+ ```
20
+ 任务状态总览
21
+ ============
22
+
23
+ 📋 auth-module.md (来源: docs/auth-design.md)
24
+ ┌──────────┬──────────────────┬────────────┬──────┬──────────────┐
25
+ │ ID │ 标题 │ 状态 │ 优先 │ 进度 │
26
+ ├──────────┼──────────────────┼────────────┼──────┼──────────────┤
27
+ │ TASK-001 │ 用户模型定义 │ done │ P0 │ 3/3 [100%] │
28
+ │ TASK-002 │ 注册接口实现 │ in-progress│ P0 │ 1/4 [25%] │
29
+ │ TASK-003 │ JWT 工具函数 │ draft │ P1 │ 0/2 [0%] │
30
+ │ TASK-004 │ 登录接口实现 │ blocked │ P0 │ 0/3 [0%] │
31
+ └──────────┴──────────────────┴────────────┴──────┴──────────────┘
32
+ 汇总: 4 个子任务 | done: 1 | in-progress: 1 | draft: 1 | blocked: 1
33
+ 整体完成度: 25%
34
+
35
+ 📋 payment-api.md (来源: docs/payment-design.md)
36
+ ...
37
+
38
+ ═══════════════════════════
39
+ 全局汇总: 2 个文件, 8 个子任务
40
+ done: 3 | in-progress: 2 | draft: 2 | blocked: 1
41
+ ```
42
+
43
+ ### 3. 阻塞详情
44
+
45
+ 如果存在 blocked 子任务,额外输出:
46
+
47
+ ```
48
+ ⚠ 阻塞任务:
49
+ - auth-module/TASK-004: [BLOCKED] 等待第三方 SDK 文档
50
+ - auth-module/TASK-004: [NOTE-2] 接口签名需与前端对齐
51
+ ```
52
+
53
+ ### 4. 指定文件模式
54
+
55
+ 当指定 `<file>` 时,输出该文件的详细信息,包括:
56
+ - 完整的子任务表格
57
+ - 每个子任务的 Checklist 明细
58
+ - 未解决的 Notes 列表
59
+ - 依赖关系简图
File without changes