jarvis-agent-factory 2.0.3 → 2.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/.claude/agents/planner.md +26 -0
- package/.claude/commands/jarvis.md +1 -0
- package/.claude/skills/using-agent-skills/SKILL.md +1 -1
- package/README.md +27 -17
- package/package.json +1 -1
- package/src/cli.js +179 -77
|
@@ -61,6 +61,31 @@ model: deepseek-v4-pro
|
|
|
61
61
|
- TDD 任务的 Red→Green→Refactor 必须串行
|
|
62
62
|
- 不同 TDD 任务的 Red 步骤可并行
|
|
63
63
|
|
|
64
|
+
### 技能分配规则
|
|
65
|
+
|
|
66
|
+
根据任务类型和 test_strategy,在 Execution Packet 中指定 `required_skills`。子 Agent 收到后会在启动时加载这些技能。
|
|
67
|
+
|
|
68
|
+
| 任务场景 | required_skills(基础 + 场景) |
|
|
69
|
+
|---------|------|
|
|
70
|
+
| 所有任务(基础) | `behavioral-guidelines` `code-standards` |
|
|
71
|
+
| 代码实现 | + `source-driven-development` `incremental-implementation` `verification-before-completion` |
|
|
72
|
+
| TDD 任务 | + `test-driven-development` |
|
|
73
|
+
| 前端 UI/组件 | + `source-driven-development` `incremental-implementation` `verification-before-completion` |
|
|
74
|
+
| 后端业务逻辑 | + `source-driven-development` `incremental-implementation` `verification-before-completion` |
|
|
75
|
+
| 代码审查 | + `code-review-and-quality` |
|
|
76
|
+
| 架构设计 | + `source-driven-development` `documentation-and-adrs` |
|
|
77
|
+
| 安全审计 | + `security-and-hardening` |
|
|
78
|
+
| 数据层/DB | + `source-driven-development` |
|
|
79
|
+
| 性能测试 | + `debugging-and-error-recovery` |
|
|
80
|
+
| E2E 测试 | + `debugging-and-error-recovery` `verification-before-completion` |
|
|
81
|
+
| 浏览器测试 | + `agent-browser` `browser-testing` |
|
|
82
|
+
| Bug 修复 | + `source-driven-development` `debugging-and-error-recovery` |
|
|
83
|
+
| 重构 | + `code-simplification` `source-driven-development` `verification-before-completion` |
|
|
84
|
+
| API 文档 | + `source-driven-development` `chinese-documentation` |
|
|
85
|
+
| 发布/部署 | + `shipping-and-launch` `git-workflow-and-versioning` `finishing-a-development-branch` |
|
|
86
|
+
|
|
87
|
+
> 若任务有项目专属 skill(如 `.claude/skills/my-custom-skill/`),编排者可在 Execution Packet 的 `required_skills` 中追加。
|
|
88
|
+
|
|
64
89
|
### 变更规模控制
|
|
65
90
|
|
|
66
91
|
单轮次所有任务的预期变更总行数不应超过 ~1000 行。超过时考虑拆分为两个轮次。
|
|
@@ -212,6 +237,7 @@ Skill(skill="behavioral-guidelines")
|
|
|
212
237
|
### allowed_paths: <允许修改的目录/文件>
|
|
213
238
|
### forbidden_paths: <禁止修改的共享区域>
|
|
214
239
|
### dependencies: <依赖的 API / 契约 / schema>
|
|
240
|
+
### required_skills: <技能列表,按上方「技能分配规则」填写。子 Agent 启动后必须逐一 Skill() 加载>
|
|
215
241
|
### parallel_group: <可与此任务并行的任务 ID 列表>
|
|
216
242
|
### wait_for: <必须等待完成的任务 ID 列表>
|
|
217
243
|
### acceptance_criteria: <可验证的验收条件>
|
|
@@ -95,6 +95,7 @@ Batch 3: [TASK-005, TASK-006] ← 依赖 Batch 2 完成
|
|
|
95
95
|
- objective(一句话目标)
|
|
96
96
|
- allowed_paths 和 forbidden_paths
|
|
97
97
|
- dependencies(依赖的 API 契约 / Schema)
|
|
98
|
+
- required_skills(子 Agent 必须逐一 Skill() 加载的技能列表)
|
|
98
99
|
- acceptance_criteria(可验证的验收条件)
|
|
99
100
|
- test_strategy(tdd / test_after / manual_only)
|
|
100
101
|
- input_documents(上游文档路径)
|
|
@@ -124,7 +124,7 @@ Jarvis 按流程调度子 Agent
|
|
|
124
124
|
作为编排者,你不需要在每个阶段手动加载所有技能。关键规则:
|
|
125
125
|
|
|
126
126
|
1. **每个阶段只加载该阶段的核心技能**(1-3 个)
|
|
127
|
-
2.
|
|
127
|
+
2. **通过 Execution Packet 传递技能清单**——planner 在 `required_skills` 字段指定该任务需要的技能;编排者 spawn 子 Agent 时原样传递;子 Agent 启动后逐一 `Skill()` 加载
|
|
128
128
|
3. **behavioral-guidelines 是所有 Agent 的基座**——每个 Agent 都会自动遵守
|
|
129
129
|
4. **context-engineering 在三个关键时刻使用**:启动新会话、任务切换、子 Agent 结果偏离预期时
|
|
130
130
|
|
package/README.md
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
# Jarvis Agent Factory · 贾维斯智能体工厂
|
|
2
2
|
|
|
3
3
|
[](./LICENSE)
|
|
4
|
-
[](https://gitee.com/wujl1124/JarvisAgentFactory/releases)
|
|
5
5
|
<br>**简体中文** | [English](./README_EN.md)
|
|
6
6
|
|
|
7
7
|
一套跨平台的多智能体(Multi-Agent)AI 编程助手配置集,定义了一条**从想法到交付的完整软件开发流水线**。支持 Claude Code、OpenCode、Codex 三平台,共享同一套工作流规范与技能体系。
|
|
8
8
|
|
|
9
|
-
> **v2.0
|
|
9
|
+
> **v2.1.0** — Claude Code 47 agents + 15 commands / OpenCode 55 agents(纯智能体切换) / Codex 45 agents + 42 skills(Skill 触发)
|
|
10
10
|
|
|
11
11
|
## 核心概念
|
|
12
12
|
|
|
@@ -53,23 +53,33 @@
|
|
|
53
53
|
|
|
54
54
|
```bash
|
|
55
55
|
npm i -g jarvis-agent-factory
|
|
56
|
+
```
|
|
56
57
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
jarvis init
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
jarvis
|
|
63
|
-
jarvis
|
|
64
|
-
jarvis
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
58
|
+
| 命令 | 说明 |
|
|
59
|
+
|------|------|
|
|
60
|
+
| `jarvis` | 引导当前目录(≡ `jarvis init .`) |
|
|
61
|
+
| `jarvis init [path]` | 初始化项目,安装全部三平台 + Playwright MCP 配置 |
|
|
62
|
+
| `jarvis add <p...> [path]` | 添加指定平台(`claude` `opencode` `codex` 可多选) |
|
|
63
|
+
| `jarvis remove <p...> [path]` | 移除指定平台 + 对应 MCP 配置 |
|
|
64
|
+
| `jarvis upgrade [path]` | 升级已安装的配置到最新版本 |
|
|
65
|
+
| `jarvis doctor [path]` | 健康检查 |
|
|
66
|
+
| `-g, --global` | 安装到用户全局目录 `~/.claude/` 等 |
|
|
67
|
+
| `-y, --yes` | 跳过覆盖确认 |
|
|
68
|
+
| `-v, --version` | 查看版本 |
|
|
69
|
+
| `-h, --help` | 帮助 |
|
|
69
70
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
jarvis
|
|
71
|
+
```bash
|
|
72
|
+
# 常用
|
|
73
|
+
jarvis # 引导当前目录
|
|
74
|
+
jarvis init my-app -y # 一键初始化
|
|
75
|
+
jarvis add claude # 追加 Claude Code
|
|
76
|
+
jarvis remove codex # 移除 Codex
|
|
77
|
+
jarvis upgrade # 升级配置
|
|
78
|
+
jarvis doctor # 检查
|
|
79
|
+
|
|
80
|
+
# 全局安装
|
|
81
|
+
jarvis init -g -y # 一键全局安装
|
|
82
|
+
jarvis add opencode -g # 全局追加 OpenCode
|
|
73
83
|
```
|
|
74
84
|
|
|
75
85
|
### 手动安装
|
package/package.json
CHANGED
package/src/cli.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { fileURLToPath } from 'node:url';
|
|
2
2
|
import { dirname, resolve } from 'node:path';
|
|
3
|
-
import { readFileSync } from 'node:fs';
|
|
3
|
+
import { readFileSync, existsSync, rmSync } from 'node:fs';
|
|
4
4
|
import { execSync } from 'node:child_process';
|
|
5
|
+
import { createInterface } from 'node:readline';
|
|
5
6
|
import { homedir } from 'node:os';
|
|
6
7
|
import { install } from './install.js';
|
|
7
8
|
import { doctor } from './doctor.js';
|
|
@@ -13,26 +14,31 @@ const PKG_VERSION = PKG.version;
|
|
|
13
14
|
const PKG_NAME = PKG.name;
|
|
14
15
|
|
|
15
16
|
const PLATFORMS = {
|
|
16
|
-
claude:
|
|
17
|
-
opencode:{ dir: '.opencode',desc: 'OpenCode — 55 agents
|
|
18
|
-
codex:
|
|
17
|
+
claude: { dir: '.claude', desc: 'Claude Code — 47 agents + 15 commands + 27 skills' },
|
|
18
|
+
opencode: { dir: '.opencode', desc: 'OpenCode — 55 agents + 27 skills (agent switching)' },
|
|
19
|
+
codex: { dir: '.codex', desc: 'Codex — 45 agents + 42 skills (skill-triggered)' },
|
|
19
20
|
};
|
|
20
21
|
|
|
21
|
-
const
|
|
22
|
-
|
|
22
|
+
const ALL_PLATFORMS = Object.keys(PLATFORMS);
|
|
23
|
+
|
|
24
|
+
const HELP = `🧠 Jarvis Agent Factory v${PKG_VERSION}
|
|
25
|
+
|
|
26
|
+
Bootstrap multi-agent AI coding assistant configs
|
|
27
|
+
for Claude Code, OpenCode, and Codex.
|
|
23
28
|
|
|
24
29
|
Usage:
|
|
25
|
-
jarvis
|
|
26
|
-
jarvis
|
|
27
|
-
jarvis
|
|
28
|
-
jarvis
|
|
29
|
-
jarvis
|
|
30
|
-
jarvis
|
|
30
|
+
jarvis [path] ≡ jarvis init [path]
|
|
31
|
+
jarvis init [path] Bootstrap project with all platforms + MCP
|
|
32
|
+
jarvis add <p...> [path] Add platform(s) to project
|
|
33
|
+
jarvis remove <p...> [path] Remove platform(s) from project
|
|
34
|
+
jarvis upgrade [path] Upgrade to latest config version
|
|
35
|
+
jarvis doctor [path] Verify installation
|
|
31
36
|
|
|
32
37
|
Options:
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
--help
|
|
38
|
+
-g, --global Target user global directory instead of project
|
|
39
|
+
-y, --yes Skip confirmation prompts
|
|
40
|
+
-h, --help Show this help
|
|
41
|
+
-v, --version Show version
|
|
36
42
|
|
|
37
43
|
Platforms:
|
|
38
44
|
claude ${PLATFORMS.claude.desc}
|
|
@@ -40,23 +46,28 @@ Platforms:
|
|
|
40
46
|
codex ${PLATFORMS.codex.desc}
|
|
41
47
|
|
|
42
48
|
Examples:
|
|
43
|
-
jarvis
|
|
44
|
-
jarvis init
|
|
45
|
-
jarvis
|
|
46
|
-
jarvis
|
|
49
|
+
jarvis Bootstrap current directory
|
|
50
|
+
jarvis init my-app Bootstrap new project
|
|
51
|
+
jarvis add claude opencode Add platforms to current directory
|
|
52
|
+
jarvis add claude -g Add Claude Code globally
|
|
53
|
+
jarvis remove codex Remove Codex from project
|
|
54
|
+
jarvis upgrade Upgrade all configs
|
|
55
|
+
jarvis doctor Check current directory
|
|
47
56
|
`;
|
|
48
57
|
|
|
49
58
|
function showHelp() { console.log(HELP); }
|
|
50
59
|
|
|
51
|
-
function
|
|
52
|
-
const
|
|
53
|
-
const
|
|
54
|
-
for (const a of
|
|
55
|
-
if (a === '
|
|
56
|
-
else if (a === '
|
|
57
|
-
else
|
|
60
|
+
function parseArgs(raw) {
|
|
61
|
+
const opts = { yes: false, global: false };
|
|
62
|
+
const positional = [];
|
|
63
|
+
for (const a of raw) {
|
|
64
|
+
if (a === '-y' || a === '--yes') opts.yes = true;
|
|
65
|
+
else if (a === '-g' || a === '--global') opts.global = true;
|
|
66
|
+
else if (a === '-h' || a === '--help') { opts.help = true; return { opts, positional }; }
|
|
67
|
+
else if (a === '-v' || a === '--version') { opts.version = true; return { opts, positional }; }
|
|
68
|
+
else positional.push(a);
|
|
58
69
|
}
|
|
59
|
-
return {
|
|
70
|
+
return { opts, positional };
|
|
60
71
|
}
|
|
61
72
|
|
|
62
73
|
function checkLatest() {
|
|
@@ -67,80 +78,171 @@ function checkLatest() {
|
|
|
67
78
|
} catch { return null; }
|
|
68
79
|
}
|
|
69
80
|
|
|
81
|
+
function resolveTarget(path, isGlobal) {
|
|
82
|
+
return isGlobal ? resolve('.') : resolve(path || '.');
|
|
83
|
+
}
|
|
84
|
+
|
|
70
85
|
export async function run() {
|
|
71
|
-
const
|
|
72
|
-
const { flags, args } = parseFlags(rawArgs);
|
|
73
|
-
const cmd = args[0];
|
|
86
|
+
const { opts, positional } = parseArgs(process.argv.slice(2));
|
|
74
87
|
|
|
75
|
-
if (
|
|
88
|
+
if (opts.help) { showHelp(); return; }
|
|
89
|
+
if (opts.version) {
|
|
90
|
+
console.log(`${PKG_NAME} v${PKG_VERSION}`);
|
|
91
|
+
const latest = checkLatest();
|
|
92
|
+
if (latest && latest !== PKG_VERSION) {
|
|
93
|
+
console.log(`\n Update available: v${latest} → npm i -g ${PKG_NAME}@latest`);
|
|
94
|
+
}
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const cmd = positional[0];
|
|
99
|
+
|
|
100
|
+
// jarvis (no args) ≡ jarvis init .
|
|
101
|
+
if (!cmd) {
|
|
102
|
+
const target = resolve('.');
|
|
103
|
+
const scope = opts.global ? '~ (global)' : target;
|
|
104
|
+
console.log(`\n🚀 Jarvis v${PKG_VERSION}\n`);
|
|
105
|
+
console.log(` Target: ${scope}\n`);
|
|
106
|
+
for (const name of ALL_PLATFORMS) {
|
|
107
|
+
await install({ platform: name, target, pkgRoot: PKG_ROOT, platforms: PLATFORMS, force: opts.yes, global: opts.global });
|
|
108
|
+
}
|
|
109
|
+
console.log(`\n✅ Done! \`jarvis doctor\` to verify.\n`);
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
76
112
|
|
|
77
113
|
switch (cmd) {
|
|
78
|
-
case '
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
114
|
+
case 'init': {
|
|
115
|
+
const path = positional[1];
|
|
116
|
+
const target = resolveTarget(path, opts.global);
|
|
117
|
+
const scope = opts.global ? '~ (global)' : target;
|
|
118
|
+
console.log(`\n🚀 Jarvis v${PKG_VERSION}\n`);
|
|
119
|
+
console.log(` Target: ${scope}\n`);
|
|
120
|
+
for (const name of ALL_PLATFORMS) {
|
|
121
|
+
await install({ platform: name, target, pkgRoot: PKG_ROOT, platforms: PLATFORMS, force: opts.yes, global: opts.global });
|
|
86
122
|
}
|
|
123
|
+
console.log(`\n✅ Done!\n`);
|
|
87
124
|
break;
|
|
88
125
|
}
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
126
|
+
|
|
127
|
+
case 'add': {
|
|
128
|
+
const platforms = [];
|
|
129
|
+
let path = '.';
|
|
130
|
+
for (let i = 1; i < positional.length; i++) {
|
|
131
|
+
const p = positional[i];
|
|
132
|
+
if (PLATFORMS[p]) platforms.push(p);
|
|
133
|
+
else if (!p.startsWith('-')) path = p;
|
|
94
134
|
}
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
135
|
+
if (platforms.length === 0) {
|
|
136
|
+
console.error('\n❌ No valid platform specified.\n');
|
|
137
|
+
console.log(`Valid platforms: ${ALL_PLATFORMS.join(', ')}\n`);
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
const target = resolveTarget(path, opts.global);
|
|
141
|
+
const scope = opts.global ? '~ (global)' : target;
|
|
142
|
+
console.log(`\n📦 Adding to ${scope}\n`);
|
|
143
|
+
for (const name of platforms) {
|
|
144
|
+
await install({ platform: name, target, pkgRoot: PKG_ROOT, platforms: PLATFORMS, force: opts.yes, global: opts.global });
|
|
99
145
|
}
|
|
100
146
|
console.log(`\n✅ Done!\n`);
|
|
101
147
|
break;
|
|
102
148
|
}
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
for (
|
|
109
|
-
|
|
149
|
+
|
|
150
|
+
case 'remove':
|
|
151
|
+
case 'rm': {
|
|
152
|
+
const platforms = [];
|
|
153
|
+
let path = '.';
|
|
154
|
+
for (let i = 1; i < positional.length; i++) {
|
|
155
|
+
const p = positional[i];
|
|
156
|
+
if (PLATFORMS[p]) platforms.push(p);
|
|
157
|
+
else if (!p.startsWith('-')) path = p;
|
|
110
158
|
}
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
case 'install': {
|
|
115
|
-
const platform = args[1];
|
|
116
|
-
if (!platform || !PLATFORMS[platform]) {
|
|
117
|
-
console.error(`\n❌ Unknown platform: ${platform || '(none)'}\n`);
|
|
118
|
-
console.log(`Available: ${Object.keys(PLATFORMS).join(', ')}\n`);
|
|
159
|
+
if (platforms.length === 0) {
|
|
160
|
+
console.error('\n❌ No valid platform specified.\n');
|
|
161
|
+
console.log(`Valid platforms: ${ALL_PLATFORMS.join(', ')}\n`);
|
|
119
162
|
return;
|
|
120
163
|
}
|
|
121
|
-
const target =
|
|
122
|
-
const scope =
|
|
123
|
-
|
|
124
|
-
|
|
164
|
+
const target = resolveTarget(path, opts.global);
|
|
165
|
+
const scope = opts.global ? '~ (global)' : target;
|
|
166
|
+
for (const name of platforms) {
|
|
167
|
+
const dir = opts.global ? (GLOBAL_ROOTS[name]) : resolve(target, PLATFORMS[name].dir);
|
|
168
|
+
if (existsSync(dir)) {
|
|
169
|
+
if (!opts.yes) {
|
|
170
|
+
const ok = await confirm(` Remove ${dir}? [y/N] `);
|
|
171
|
+
if (!ok) { console.log(` ⏭ Skipped ${name}`); continue; }
|
|
172
|
+
}
|
|
173
|
+
rmSync(dir, { recursive: true, force: true });
|
|
174
|
+
console.log(` - ${PLATFORMS[name].dir.padEnd(10)} removed`);
|
|
175
|
+
// Also remove MCP config
|
|
176
|
+
removeMcp(name, target, opts.global);
|
|
177
|
+
} else {
|
|
178
|
+
console.log(` ⏭ ${PLATFORMS[name].dir.padEnd(10)} not found`);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
125
181
|
console.log(`\n✅ Done!\n`);
|
|
126
182
|
break;
|
|
127
183
|
}
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
184
|
+
|
|
185
|
+
case 'upgrade':
|
|
186
|
+
case 'update': {
|
|
187
|
+
// Check CLI self-upgrade
|
|
188
|
+
const latest = checkLatest();
|
|
189
|
+
if (latest && latest !== PKG_VERSION) {
|
|
190
|
+
console.log(`\n⬆️ CLI: v${PKG_VERSION} → v${latest}`);
|
|
191
|
+
console.log(` npm i -g ${PKG_NAME}@latest\n`);
|
|
192
|
+
}
|
|
193
|
+
const path = positional[1];
|
|
194
|
+
const target = resolveTarget(path, opts.global);
|
|
195
|
+
const scope = opts.global ? '~ (global)' : target;
|
|
196
|
+
console.log(`🔄 Upgrading → ${scope}\n`);
|
|
197
|
+
for (const name of ALL_PLATFORMS) {
|
|
198
|
+
const dir = opts.global ? GLOBAL_ROOTS[name] : resolve(target, PLATFORMS[name].dir);
|
|
199
|
+
if (existsSync(dir)) {
|
|
200
|
+
await install({ platform: name, target, pkgRoot: PKG_ROOT, platforms: PLATFORMS, force: opts.yes, global: opts.global });
|
|
201
|
+
} else {
|
|
202
|
+
console.log(` ⏭ ${PLATFORMS[name].dir} not installed, skipped`);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
console.log(`\n✅ Done!\n`);
|
|
131
206
|
break;
|
|
132
207
|
}
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
208
|
+
|
|
209
|
+
case 'doctor':
|
|
210
|
+
case 'check': {
|
|
211
|
+
const path = positional[1];
|
|
212
|
+
const target = resolveTarget(path, opts.global);
|
|
213
|
+
doctor({ target, platforms: PLATFORMS, pkgRoot: PKG_ROOT, global: opts.global });
|
|
139
214
|
break;
|
|
140
215
|
}
|
|
216
|
+
|
|
141
217
|
default: {
|
|
142
|
-
console.error(`\n❌
|
|
218
|
+
console.error(`\n❌ Unknown command: ${cmd}\n`);
|
|
143
219
|
showHelp();
|
|
144
220
|
}
|
|
145
221
|
}
|
|
146
222
|
}
|
|
223
|
+
|
|
224
|
+
const GLOBAL_ROOTS = {
|
|
225
|
+
claude: resolve(homedir(), '.claude'),
|
|
226
|
+
opencode: resolve(homedir(), '.config', 'opencode'),
|
|
227
|
+
codex: resolve(homedir(), '.codex'),
|
|
228
|
+
};
|
|
229
|
+
|
|
230
|
+
function removeMcp(platform, target, isGlobal) {
|
|
231
|
+
const files = {
|
|
232
|
+
claude: '.mcp.json',
|
|
233
|
+
opencode: 'opencode.json',
|
|
234
|
+
codex: '.codex/config.toml',
|
|
235
|
+
};
|
|
236
|
+
const f = files[platform];
|
|
237
|
+
if (!f) return;
|
|
238
|
+
const dest = isGlobal ? resolve(homedir(), f) : resolve(target, f);
|
|
239
|
+
if (existsSync(dest)) {
|
|
240
|
+
rmSync(dest, { recursive: true, force: true });
|
|
241
|
+
console.log(` - ${f.padEnd(18)} removed`);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
async function confirm(q) {
|
|
246
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
247
|
+
return new Promise(res => { rl.question(q, a => { rl.close(); res(a.toLowerCase() === 'y' || a.toLowerCase() === 'yes'); }); });
|
|
248
|
+
}
|