@mison/ling 1.0.2 → 1.1.1
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/.agents/rules/GEMINI.md +17 -0
- package/.agents/skills/clean-code/SKILL.md +24 -14
- package/.agents/skills/doc.md +9 -5
- package/CHANGELOG.md +29 -3
- package/README.md +37 -23
- package/bin/adapters/codex.js +6 -6
- package/bin/adapters/gemini.js +1 -1
- package/bin/core/generator.js +1 -0
- package/bin/interactive.js +68 -1
- package/bin/{ag-kit.js → ling-cli.js} +1078 -131
- package/bin/ling.js +1 -1
- package/bin/utils/managed-block.js +17 -4
- package/bin/utils.js +53 -10
- package/docs/TECH.md +37 -13
- package/package.json +6 -3
- package/scripts/ci-verify.js +9 -3
- package/scripts/postinstall-check.js +5 -6
- package/tests/clean-script.test.js +1 -1
- package/tests/cli-smoke.test.js +85 -0
- package/tests/managed-block.test.js +18 -1
- package/tests/phase-c.test.js +2 -2
- package/tests/spec-init-doctor.test.js +175 -0
- package/tests/spec-profile.test.js +68 -0
- package/tests/standards-compliance.test.js +1 -1
- package/tests/transformer.test.js +1 -1
package/.agents/rules/GEMINI.md
CHANGED
|
@@ -27,6 +27,23 @@ trigger: always_on
|
|
|
27
27
|
|
|
28
28
|
---
|
|
29
29
|
|
|
30
|
+
## Spec 协议(任务跟踪 CSV 驱动)
|
|
31
|
+
|
|
32
|
+
当工作区存在 `issues.csv` 时,视其为任务跟踪文件(单一事实源),并遵循:
|
|
33
|
+
|
|
34
|
+
1. 读取 `issues.csv` 并只锁定一个原子任务。
|
|
35
|
+
2. 将任务状态从“未开始”改为“进行中”,再开始开发。
|
|
36
|
+
3. 修改完成后运行最小充分验证,并记录证据。
|
|
37
|
+
4. 自审通过后将状态改为“已完成”。
|
|
38
|
+
5. 若验证失败,先修复或回退,不得静默降级。
|
|
39
|
+
|
|
40
|
+
模板参考:
|
|
41
|
+
|
|
42
|
+
- 优先:`.ling/spec/templates/driver-prompt.md`
|
|
43
|
+
- 其次:`~/.ling/spec/templates/driver-prompt.md`(若已启用全局 Spec Profile)
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
30
47
|
## 请求分类器(第 1 步)
|
|
31
48
|
|
|
32
49
|
**在执行任何动作前,先对请求分类:**
|
|
@@ -143,24 +143,34 @@ File to edit: UserService.ts
|
|
|
143
143
|
|
|
144
144
|
> [CRITICAL] **核心要求:** 每个代理完成后仅运行所属技能脚本。
|
|
145
145
|
|
|
146
|
+
### 脚本路径约定
|
|
147
|
+
|
|
148
|
+
下表中的 `<skills_root>` 代表 Skills 根目录,常见取值:
|
|
149
|
+
|
|
150
|
+
- Ling 仓库源码:`.agents/skills`
|
|
151
|
+
- Gemini 工作区:`.agent/skills`
|
|
152
|
+
- Codex 全局:`~/.codex/skills`
|
|
153
|
+
- Gemini CLI 全局:`~/.gemini/skills`
|
|
154
|
+
- Antigravity 全局:`~/.gemini/antigravity/skills`
|
|
155
|
+
|
|
146
156
|
### 代理 -> 脚本映射
|
|
147
157
|
|
|
148
158
|
| 代理 | 脚本 | 命令 |
|
|
149
159
|
|-------|--------|---------|
|
|
150
|
-
| **frontend-specialist** | UX Audit | `python
|
|
151
|
-
| **frontend-specialist** | A11y Check | `python
|
|
152
|
-
| **backend-specialist** | API Validator | `python
|
|
153
|
-
| **mobile-developer** | Mobile Audit | `python
|
|
154
|
-
| **database-architect** | Schema Validate | `python
|
|
155
|
-
| **security-auditor** | Security Scan | `python
|
|
156
|
-
| **seo-specialist** | SEO Check | `python
|
|
157
|
-
| **seo-specialist** | GEO Check | `python
|
|
158
|
-
| **performance-optimizer** | Lighthouse | `python
|
|
159
|
-
| **test-engineer** | Test Runner | `python
|
|
160
|
-
| **test-engineer** | Playwright | `python
|
|
161
|
-
| **Any agent** | Lint Check | `python
|
|
162
|
-
| **Any agent** | Type Coverage | `python
|
|
163
|
-
| **Any agent** | i18n Check | `python
|
|
160
|
+
| **frontend-specialist** | UX Audit | `python <skills_root>/frontend-design/scripts/ux_audit.py .` |
|
|
161
|
+
| **frontend-specialist** | A11y Check | `python <skills_root>/frontend-design/scripts/accessibility_checker.py .` |
|
|
162
|
+
| **backend-specialist** | API Validator | `python <skills_root>/api-patterns/scripts/api_validator.py .` |
|
|
163
|
+
| **mobile-developer** | Mobile Audit | `python <skills_root>/mobile-design/scripts/mobile_audit.py .` |
|
|
164
|
+
| **database-architect** | Schema Validate | `python <skills_root>/database-design/scripts/schema_validator.py .` |
|
|
165
|
+
| **security-auditor** | Security Scan | `python <skills_root>/vulnerability-scanner/scripts/security_scan.py .` |
|
|
166
|
+
| **seo-specialist** | SEO Check | `python <skills_root>/seo-fundamentals/scripts/seo_checker.py .` |
|
|
167
|
+
| **seo-specialist** | GEO Check | `python <skills_root>/geo-fundamentals/scripts/geo_checker.py .` |
|
|
168
|
+
| **performance-optimizer** | Lighthouse | `python <skills_root>/performance-profiling/scripts/lighthouse_audit.py <url>` |
|
|
169
|
+
| **test-engineer** | Test Runner | `python <skills_root>/testing-patterns/scripts/test_runner.py .` |
|
|
170
|
+
| **test-engineer** | Playwright | `python <skills_root>/webapp-testing/scripts/playwright_runner.py <url>` |
|
|
171
|
+
| **Any agent** | Lint Check | `python <skills_root>/lint-and-validate/scripts/lint_runner.py .` |
|
|
172
|
+
| **Any agent** | Type Coverage | `python <skills_root>/lint-and-validate/scripts/type_coverage.py .` |
|
|
173
|
+
| **Any agent** | i18n Check | `python <skills_root>/i18n-localization/scripts/i18n_checker.py .` |
|
|
164
174
|
|
|
165
175
|
> [FAIL] **错误做法:** `test-engineer` 运行 `ux_audit.py`
|
|
166
176
|
> [OK] **正确做法:** `frontend-specialist` 运行 `ux_audit.py`
|
package/.agents/skills/doc.md
CHANGED
|
@@ -18,7 +18,11 @@
|
|
|
18
18
|
|
|
19
19
|
| 范围 | 路径 | 说明 |
|
|
20
20
|
|---------|-----------|-------|
|
|
21
|
-
| **
|
|
21
|
+
| **Ling 仓库源码(Canonical)** | `<ling-repo>/.agents/skills/` | 模板源,用于构建与分发 |
|
|
22
|
+
| **Workspace(工作区)** | `<workspace-root>/.agent/skills/` | 仅作用于当前项目(Gemini/Antigravity) |
|
|
23
|
+
| **Global(全局)** | `~/.codex/skills/`、`~/.gemini/skills/`、`~/.gemini/antigravity/skills/` | 跨项目复用(按目标工具读取) |
|
|
24
|
+
|
|
25
|
+
> 约定:下文示例使用 `<skills_root>` 表示 Skills 根目录;请按你的安装方式替换为上表路径。
|
|
22
26
|
|
|
23
27
|
### 技能目录结构
|
|
24
28
|
|
|
@@ -39,7 +43,7 @@ my-skill/
|
|
|
39
43
|
### 步骤 1:创建目录
|
|
40
44
|
|
|
41
45
|
```bash
|
|
42
|
-
mkdir -p
|
|
46
|
+
mkdir -p <skills_root>/code-review
|
|
43
47
|
```
|
|
44
48
|
|
|
45
49
|
### 步骤 2:创建 SKILL.md
|
|
@@ -119,12 +123,12 @@ Agent(智能体)会自动识别 `code-review` 技能,加载信息并按指
|
|
|
119
123
|
### 步骤 1:创建目录
|
|
120
124
|
|
|
121
125
|
```bash
|
|
122
|
-
mkdir -p
|
|
126
|
+
mkdir -p <skills_root>/license-header-adder/resources
|
|
123
127
|
```
|
|
124
128
|
|
|
125
129
|
### 步骤 2:创建模板文件
|
|
126
130
|
|
|
127
|
-
|
|
131
|
+
**`<skills_root>/license-header-adder/resources/HEADER.txt`**:
|
|
128
132
|
|
|
129
133
|
```
|
|
130
134
|
/*
|
|
@@ -136,7 +140,7 @@ mkdir -p .agent/skills/license-header-adder/resources
|
|
|
136
140
|
|
|
137
141
|
### 步骤 3:创建 SKILL.md
|
|
138
142
|
|
|
139
|
-
|
|
143
|
+
**`<skills_root>/license-header-adder/SKILL.md`**:
|
|
140
144
|
|
|
141
145
|
```markdown
|
|
142
146
|
---
|
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,31 @@
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [ling-1.1.1] - 2026-03-14
|
|
11
|
+
|
|
12
|
+
### 新增
|
|
13
|
+
|
|
14
|
+
- Spec 项目级工作区初始化与诊断:新增 `ling spec init` / `ling spec doctor`,在工作区落盘 `.ling/spec` 资产与 `issues.csv` 校验。
|
|
15
|
+
- Spec Profiles 资产:全局与项目级均包含 `profiles/`,并纳入完整性校验与回退语义。
|
|
16
|
+
- Spec 资产分支拉取:`ling spec init --branch <name>` 支持从指定分支的 `.spec/` 拉取 templates/references/profiles。
|
|
17
|
+
|
|
18
|
+
### 变更
|
|
19
|
+
|
|
20
|
+
- Spec 状态判定强化:`ling spec status` 增加文件级完整性校验,且在 `state.json` 缺失但检测到残留 artifacts 时返回 `broken` 并给出修复提示。
|
|
21
|
+
- CI 改为 npm:CI 矩阵不再依赖 bun,统一使用 `npm ci/test/run` 执行验证。
|
|
22
|
+
|
|
23
|
+
## [ling-1.1.0] - 2026-03-13
|
|
24
|
+
|
|
25
|
+
### 新增
|
|
26
|
+
|
|
27
|
+
- 已有资产冲突处理:`init/update/update-all/global sync/spec enable` 在交互终端逐项确认(保留 / 备份后移除 / 直接移除),并支持按资产类别复用选择。
|
|
28
|
+
- 预备份与回退:项目级覆盖前快照落盘到 `.agent-backup/.agents-backup`;全局与 Spec 维持快照备份路径。
|
|
29
|
+
|
|
30
|
+
### 维护
|
|
31
|
+
|
|
32
|
+
- ag-kit 更名清理:内部 CLI 入口更名为 `bin/ling-cli.js`,并移除 `AG_KIT_*` 兼容环境变量与 `~/.ag-kit` 控制目录迁移逻辑。
|
|
33
|
+
- 托管区块标记更名为 `LING MANAGED BLOCK`,并兼容识别旧 `AG-KIT` 标记后自动迁移。
|
|
34
|
+
|
|
10
35
|
## [ling-1.0.2] - 2026-03-13
|
|
11
36
|
|
|
12
37
|
### 变更
|
|
@@ -22,7 +47,7 @@
|
|
|
22
47
|
|
|
23
48
|
### 维护
|
|
24
49
|
|
|
25
|
-
- CLI 入口权限:`bin/ling.js` 设置为可执行,保持与 `bin/
|
|
50
|
+
- CLI 入口权限:`bin/ling.js` 设置为可执行,保持与 `bin/ling-cli.js` 一致。
|
|
26
51
|
|
|
27
52
|
## [ling-1.0.0] - 2026-03-13
|
|
28
53
|
|
|
@@ -35,7 +60,6 @@
|
|
|
35
60
|
|
|
36
61
|
- 品牌更名基础设施:
|
|
37
62
|
- 主命令切换为 `ling`
|
|
38
|
-
- `ag-kit` 保留兼容入口
|
|
39
63
|
- 目标目录结构:`gemini -> .agent/`,`codex -> .agents/`
|
|
40
64
|
- 控制目录、索引和备份默认迁移到 `~/.ling/`
|
|
41
65
|
- `antigravity.rules` 收敛为 `ling.rules`
|
|
@@ -56,7 +80,9 @@
|
|
|
56
80
|
|
|
57
81
|
本项目在 Ling 重启前的 2.x/3.x 版本记录已冻结,不再维护。
|
|
58
82
|
|
|
59
|
-
[Unreleased]: https://github.com/MisonL/Ling/compare/ling-1.
|
|
83
|
+
[Unreleased]: https://github.com/MisonL/Ling/compare/ling-1.1.1...HEAD
|
|
84
|
+
[ling-1.1.1]: https://github.com/MisonL/Ling/releases/tag/ling-1.1.1
|
|
85
|
+
[ling-1.1.0]: https://github.com/MisonL/Ling/releases/tag/ling-1.1.0
|
|
60
86
|
[ling-1.0.2]: https://github.com/MisonL/Ling/releases/tag/ling-1.0.2
|
|
61
87
|
[ling-1.0.1]: https://github.com/MisonL/Ling/releases/tag/ling-1.0.1
|
|
62
88
|
[ling-1.0.0]: https://github.com/MisonL/Ling/releases/tag/ling-1.0.0
|
package/README.md
CHANGED
|
@@ -6,25 +6,12 @@
|
|
|
6
6
|
|
|
7
7
|
> 面向 Gemini CLI、Antigravity 与 Codex 的中文 AI Agent 模板工具包,提供 Skills、Agents、Workflows 与 CLI 的一键安装、更新和治理。
|
|
8
8
|
|
|
9
|
-
## 致谢
|
|
10
|
-
|
|
11
|
-
本项目吸收并整合了社区项目的经验与资产,感谢:
|
|
12
|
-
|
|
13
|
-
- [vudovn/antigravity-kit](https://github.com/vudovn/antigravity-kit)
|
|
14
|
-
- [2217173240/Coding-Agent-prompt-best-practice](https://github.com/2217173240/Coding-Agent-prompt-best-practice)
|
|
15
|
-
|
|
16
9
|
## 快速安装
|
|
17
10
|
|
|
18
11
|
```bash
|
|
19
12
|
npm install -g @mison/ling
|
|
20
13
|
```
|
|
21
14
|
|
|
22
|
-
或使用 Bun:
|
|
23
|
-
|
|
24
|
-
```bash
|
|
25
|
-
bun install -g @mison/ling
|
|
26
|
-
```
|
|
27
|
-
|
|
28
15
|
然后在你的目标项目中初始化:
|
|
29
16
|
|
|
30
17
|
```bash
|
|
@@ -83,6 +70,27 @@ ling global status
|
|
|
83
70
|
- npm 包版本遵循 SemVer(`package.json`)
|
|
84
71
|
- git tag 与 CLI `--version` 显示使用 `ling-<SemVer>`(例如 `ling-1.0.0`)
|
|
85
72
|
|
|
73
|
+
### 已有资产冲突处理(交互确认 + 备份回退)
|
|
74
|
+
|
|
75
|
+
当检测到目标目录已存在且内容不同(或 Codex 目录存在漂移、缺失 `manifest.json`、包含未知文件)时,`ling` 会在交互终端中逐项询问处理方式:
|
|
76
|
+
|
|
77
|
+
- `k` 保留(跳过此资产)
|
|
78
|
+
- `b` 备份后移除(推荐)
|
|
79
|
+
- `r` 直接移除(不备份)
|
|
80
|
+
|
|
81
|
+
同一类别的冲突可选择“一键复用”,后续遇到同类资产不再重复询问。
|
|
82
|
+
|
|
83
|
+
备份落盘位置:
|
|
84
|
+
- 项目级预备份:
|
|
85
|
+
- Gemini:`<project>/.agent-backup/<timestamp>/preflight/.agent/`
|
|
86
|
+
- Codex:`<project>/.agents-backup/<timestamp>/preflight/.agents/` 或 `<project>/.agents-backup/<timestamp>/preflight/.codex/`
|
|
87
|
+
- 全局 Skills:`$HOME/.ling/backups/global/<timestamp>/...`
|
|
88
|
+
- Spec Profile:`$HOME/.ling/backups/spec/<timestamp>/before/...`
|
|
89
|
+
|
|
90
|
+
非交互环境(无 TTY 或 `--non-interactive`)不会进入询问:
|
|
91
|
+
- `update`/`update-all`/`global sync`/`spec enable` 在需要覆盖时默认执行“备份后覆盖”
|
|
92
|
+
- `init` 在检测到已有资产且未指定 `--force` 时会报错提示改用交互终端或显式 `--force`
|
|
93
|
+
|
|
86
94
|
### Spec Profile(可选进阶能力)
|
|
87
95
|
|
|
88
96
|
- 默认关闭,不随 `ling init / update / global sync` 自动安装
|
|
@@ -138,7 +146,7 @@ ling spec disable --target codex
|
|
|
138
146
|
| 组件 | 数量 | 描述 |
|
|
139
147
|
| --- | --- | --- |
|
|
140
148
|
| Agents(智能体) | 20 | 专家级 AI 人设(前端、后端、安全、产品、QA 等) |
|
|
141
|
-
| Skills(技能) |
|
|
149
|
+
| Skills(技能) | 38 | 特定领域的知识模块 |
|
|
142
150
|
| Workflows(工作流) | 12 | 斜杠命令流程 |
|
|
143
151
|
|
|
144
152
|
## 使用方法
|
|
@@ -263,21 +271,20 @@ ling exclude remove --path /path/to/dir # 删除排除路径
|
|
|
263
271
|
### 开发维护命令
|
|
264
272
|
|
|
265
273
|
```bash
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
274
|
+
npm run clean # 清理本地生成产物(如 web/.next、web/node_modules)
|
|
275
|
+
npm run clean:dry-run # 预览将被清理的路径
|
|
276
|
+
npm test # 执行 tests/ 目录下测试
|
|
277
|
+
npm run health-check # 一键执行全链路健康复检
|
|
270
278
|
```
|
|
271
279
|
|
|
272
280
|
如果你在 `web/` 子项目内开发,可按需执行:
|
|
273
281
|
|
|
274
282
|
```bash
|
|
275
|
-
|
|
276
|
-
|
|
283
|
+
cd web
|
|
284
|
+
npm install
|
|
285
|
+
npm run lint
|
|
277
286
|
```
|
|
278
287
|
|
|
279
|
-
> 说明:若你通过 `bun install -g` 安装 CLI,Bun 默认会阻止本包 `postinstall`。上游同名包冲突提示会在首次执行 `ling init/update/update-all/global sync` 时给出。
|
|
280
|
-
|
|
281
288
|
## 卸载
|
|
282
289
|
|
|
283
290
|
### 卸载本机全局 CLI
|
|
@@ -353,6 +360,13 @@ ling exclude add --path /path/to/your-project
|
|
|
353
360
|
</tr>
|
|
354
361
|
</table>
|
|
355
362
|
|
|
363
|
+
## 致谢
|
|
364
|
+
|
|
365
|
+
本项目吸收并整合了社区项目的经验与资产,感谢:
|
|
366
|
+
|
|
367
|
+
- [vudovn/antigravity-kit](https://github.com/vudovn/antigravity-kit)
|
|
368
|
+
- [2217173240/Coding-Agent-prompt-best-practice](https://github.com/2217173240/Coding-Agent-prompt-best-practice)
|
|
369
|
+
|
|
356
370
|
## 许可证
|
|
357
371
|
|
|
358
|
-
MIT ©
|
|
372
|
+
MIT © [vudovn](https://github.com/vudovn), [Mison](https://github.com/MisonL), [2217173240](https://github.com/2217173240)
|
package/bin/adapters/codex.js
CHANGED
|
@@ -140,11 +140,11 @@ class CodexAdapter extends BaseAdapter {
|
|
|
140
140
|
if (!isCodexPrebuilt) {
|
|
141
141
|
if (hasSkillsDir) {
|
|
142
142
|
this.log("[build] 检测到模板目录格式,正在构建 Codex 结构...");
|
|
143
|
-
const mockRoot = fs.mkdtempSync(path.join(os.tmpdir(), "
|
|
143
|
+
const mockRoot = fs.mkdtempSync(path.join(os.tmpdir(), "ling-build-root-"));
|
|
144
144
|
const mockAgents = path.join(mockRoot, ".agents");
|
|
145
145
|
this._copyDir(installSource, mockAgents);
|
|
146
146
|
|
|
147
|
-
buildTemp = fs.mkdtempSync(path.join(os.tmpdir(), "
|
|
147
|
+
buildTemp = fs.mkdtempSync(path.join(os.tmpdir(), "ling-build-out-"));
|
|
148
148
|
CodexBuilder.build(mockRoot, buildTemp);
|
|
149
149
|
installSource = buildTemp;
|
|
150
150
|
sourceLabel = `${sourceLabel}:compiled`;
|
|
@@ -157,7 +157,7 @@ class CodexAdapter extends BaseAdapter {
|
|
|
157
157
|
};
|
|
158
158
|
} else if (hasAgentsRoot) {
|
|
159
159
|
this.log("[build] 检测到仓库根目录格式(.agents),正在构建 Codex 结构...");
|
|
160
|
-
buildTemp = fs.mkdtempSync(path.join(os.tmpdir(), "
|
|
160
|
+
buildTemp = fs.mkdtempSync(path.join(os.tmpdir(), "ling-build-out-"));
|
|
161
161
|
CodexBuilder.build(installSource, buildTemp);
|
|
162
162
|
installSource = buildTemp;
|
|
163
163
|
sourceLabel = `${sourceLabel}:compiled`;
|
|
@@ -169,11 +169,11 @@ class CodexAdapter extends BaseAdapter {
|
|
|
169
169
|
};
|
|
170
170
|
} else if (hasLegacyAgentRoot) {
|
|
171
171
|
this.log("[build] 检测到旧版仓库根目录格式(.agent),正在构建 Codex 结构...");
|
|
172
|
-
const mockRoot = fs.mkdtempSync(path.join(os.tmpdir(), "
|
|
172
|
+
const mockRoot = fs.mkdtempSync(path.join(os.tmpdir(), "ling-build-root-"));
|
|
173
173
|
const mockAgents = path.join(mockRoot, ".agents");
|
|
174
174
|
this._copyDir(path.join(installSource, ".agent"), mockAgents);
|
|
175
175
|
|
|
176
|
-
buildTemp = fs.mkdtempSync(path.join(os.tmpdir(), "
|
|
176
|
+
buildTemp = fs.mkdtempSync(path.join(os.tmpdir(), "ling-build-out-"));
|
|
177
177
|
CodexBuilder.build(mockRoot, buildTemp);
|
|
178
178
|
installSource = buildTemp;
|
|
179
179
|
sourceLabel = `${sourceLabel}:compiled`;
|
|
@@ -191,7 +191,7 @@ class CodexAdapter extends BaseAdapter {
|
|
|
191
191
|
}
|
|
192
192
|
|
|
193
193
|
_createStaging(installSource, sourceLabel) {
|
|
194
|
-
const stagingDir = fs.mkdtempSync(path.join(os.tmpdir(), "
|
|
194
|
+
const stagingDir = fs.mkdtempSync(path.join(os.tmpdir(), "ling-codex-stage-"));
|
|
195
195
|
this._copyDir(installSource, stagingDir);
|
|
196
196
|
|
|
197
197
|
const manifestPath = path.join(stagingDir, "manifest.json");
|
package/bin/adapters/gemini.js
CHANGED
|
@@ -70,7 +70,7 @@ class GeminiAdapter extends BaseAdapter {
|
|
|
70
70
|
}
|
|
71
71
|
|
|
72
72
|
if (this._samePath(installSource, targetDir) && !this.options.dryRun) {
|
|
73
|
-
const tempSource = fs.mkdtempSync(path.join(os.tmpdir(), "
|
|
73
|
+
const tempSource = fs.mkdtempSync(path.join(os.tmpdir(), "ling-gemini-src-"));
|
|
74
74
|
this._copyDir(installSource, tempSource);
|
|
75
75
|
const oldCleanup = cleanup;
|
|
76
76
|
cleanup = () => {
|
package/bin/core/generator.js
CHANGED
|
@@ -37,6 +37,7 @@ class RuleGenerator {
|
|
|
37
37
|
agentsMd += `1. Managed resources are synchronized under \`.agents/skills\`.\n`;
|
|
38
38
|
agentsMd += `2. Do not rename managed skill folders manually.\n`;
|
|
39
39
|
agentsMd += `3. Use \`ling doctor --target codex --fix\` to recover missing managed artifacts.\n`;
|
|
40
|
+
agentsMd += `4. If \`issues.csv\` exists, treat it as the task tracking source of truth and keep at most one task in \`进行中\`.\n`;
|
|
40
41
|
|
|
41
42
|
// 3. Generate risk controls
|
|
42
43
|
let lingRules = `# Ling Risk Controls (Codex Managed)\n\n`;
|
package/bin/interactive.js
CHANGED
|
@@ -15,6 +15,10 @@ function askQuestion(rl, query) {
|
|
|
15
15
|
});
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
+
function isInteractiveTerminal() {
|
|
19
|
+
return Boolean(process.stdin.isTTY && process.stdout.isTTY);
|
|
20
|
+
}
|
|
21
|
+
|
|
18
22
|
/**
|
|
19
23
|
* Prompt user to select targets from a list.
|
|
20
24
|
* Supports multiple selection by comma separated numbers or names.
|
|
@@ -27,6 +31,10 @@ async function selectTargets(options) {
|
|
|
27
31
|
throw new Error("非交互模式下必须通过 --target 或 --targets 指定目标");
|
|
28
32
|
}
|
|
29
33
|
|
|
34
|
+
if (!isInteractiveTerminal()) {
|
|
35
|
+
throw new Error("当前环境不是交互终端,请通过 --target 或 --targets 指定目标");
|
|
36
|
+
}
|
|
37
|
+
|
|
30
38
|
const rl = createInterface();
|
|
31
39
|
|
|
32
40
|
try {
|
|
@@ -60,6 +68,65 @@ async function selectTargets(options) {
|
|
|
60
68
|
}
|
|
61
69
|
}
|
|
62
70
|
|
|
71
|
+
/**
|
|
72
|
+
* Create an interactive prompter for resolving asset conflicts.
|
|
73
|
+
* @param {object} options CLI options
|
|
74
|
+
* @returns {{resolveConflict: function, close: function}|null}
|
|
75
|
+
*/
|
|
76
|
+
function createConflictPrompter(options) {
|
|
77
|
+
if (options.nonInteractive || !isInteractiveTerminal()) {
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const rl = createInterface();
|
|
82
|
+
const categoryDefaults = new Map();
|
|
83
|
+
|
|
84
|
+
async function resolveConflict(conflict) {
|
|
85
|
+
const category = String(conflict.category || "default");
|
|
86
|
+
if (categoryDefaults.has(category)) {
|
|
87
|
+
return categoryDefaults.get(category);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const label = String(conflict.label || "未知资产");
|
|
91
|
+
const location = conflict.path ? ` (${conflict.path})` : "";
|
|
92
|
+
|
|
93
|
+
console.log(`\n[confirm] 检测到已存在资产: ${label}${location}`);
|
|
94
|
+
console.log("请选择处理方式:");
|
|
95
|
+
console.log(" k) 保留(跳过此资产)");
|
|
96
|
+
console.log(" b) 备份后移除(推荐)");
|
|
97
|
+
console.log(" r) 直接移除(不备份)");
|
|
98
|
+
|
|
99
|
+
while (true) {
|
|
100
|
+
const answer = String(await askQuestion(rl, "请输入 k / b / r: ")).trim().toLowerCase();
|
|
101
|
+
let action = "";
|
|
102
|
+
if (answer === "k") action = "keep";
|
|
103
|
+
if (answer === "b") action = "backup";
|
|
104
|
+
if (answer === "r") action = "remove";
|
|
105
|
+
|
|
106
|
+
if (!action) {
|
|
107
|
+
console.log("[warn] 输入无效,请重新输入。");
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const applyAnswer = String(await askQuestion(rl, `是否对同类资产(类别: ${category})后续冲突复用该选择? (y/N): `))
|
|
112
|
+
.trim()
|
|
113
|
+
.toLowerCase();
|
|
114
|
+
if (applyAnswer === "y" || applyAnswer === "yes") {
|
|
115
|
+
categoryDefaults.set(category, action);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return action;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function close() {
|
|
123
|
+
rl.close();
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
return { resolveConflict, close };
|
|
127
|
+
}
|
|
128
|
+
|
|
63
129
|
module.exports = {
|
|
64
|
-
selectTargets
|
|
130
|
+
selectTargets,
|
|
131
|
+
createConflictPrompter,
|
|
65
132
|
};
|