jarvis-agent-factory 2.0.1 → 2.0.2
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/README.md +2 -2
- package/package.json +1 -1
- package/src/install.js +49 -26
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.0.1** — Claude Code 47 agents + 15 commands / OpenCode 55 agents(纯智能体切换) / Codex 45 agents + 42 skills(Skill 触发)
|
|
10
10
|
|
|
11
11
|
## 核心概念
|
|
12
12
|
|
package/package.json
CHANGED
package/src/install.js
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
|
-
import { resolve, join } from 'node:path';
|
|
1
|
+
import { resolve, join, basename } from 'node:path';
|
|
2
2
|
import { existsSync, mkdirSync, readdirSync, statSync, copyFileSync } from 'node:fs';
|
|
3
3
|
import { createInterface } from 'node:readline';
|
|
4
4
|
|
|
5
|
+
// Only these subdirectories are installed — everything else in the platform dir is left untouched
|
|
6
|
+
const INSTALL_BUCKETS = ['agents', 'commands', 'skills'];
|
|
7
|
+
|
|
5
8
|
const SKIP_FILES = new Set([
|
|
6
9
|
'settings.json',
|
|
7
10
|
'settings.local.json',
|
|
@@ -10,39 +13,66 @@ const SKIP_FILES = new Set([
|
|
|
10
13
|
]);
|
|
11
14
|
|
|
12
15
|
/**
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
* Skips sensitive files.
|
|
16
|
+
* Install platform config: only agents/ commands/ skills/ subdirectories.
|
|
17
|
+
* File-level merge: new files added, same-name overwritten, extra files in target preserved.
|
|
16
18
|
*/
|
|
17
19
|
export async function install({ platform, target, pkgRoot, platforms, force }) {
|
|
18
20
|
const info = platforms[platform];
|
|
19
|
-
const
|
|
20
|
-
const
|
|
21
|
+
const srcRoot = resolve(pkgRoot, info.dir);
|
|
22
|
+
const destRoot = resolve(target, info.dir);
|
|
21
23
|
|
|
22
|
-
if (!existsSync(
|
|
23
|
-
console.error(` ⚠ Source not found: ${
|
|
24
|
+
if (!existsSync(srcRoot)) {
|
|
25
|
+
console.error(` ⚠ Source not found: ${srcRoot}`);
|
|
24
26
|
return;
|
|
25
27
|
}
|
|
26
28
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
+
const destExists = existsSync(destRoot);
|
|
30
|
+
|
|
31
|
+
// Only confirm if target already has this platform
|
|
29
32
|
if (destExists && !force) {
|
|
30
|
-
const ok = await confirm(` 📁 ${info.dir}/
|
|
33
|
+
const ok = await confirm(` 📁 ${info.dir}/ exists, merge agents/skills/commands? [y/N] `);
|
|
31
34
|
if (!ok) {
|
|
32
|
-
console.log(` ⏭ Skipped ${platform}
|
|
35
|
+
console.log(` ⏭ Skipped ${platform}`);
|
|
33
36
|
return;
|
|
34
37
|
}
|
|
35
38
|
}
|
|
36
39
|
|
|
37
|
-
|
|
40
|
+
// Ensure platform root exists
|
|
41
|
+
if (!destExists) {
|
|
42
|
+
mkdirSync(destRoot, { recursive: true });
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
let totalFiles = 0;
|
|
46
|
+
let totalDirs = 0;
|
|
47
|
+
|
|
48
|
+
for (const bucket of INSTALL_BUCKETS) {
|
|
49
|
+
const srcDir = join(srcRoot, bucket);
|
|
50
|
+
const destDir = join(destRoot, bucket);
|
|
51
|
+
|
|
52
|
+
if (!existsSync(srcDir)) continue;
|
|
53
|
+
|
|
54
|
+
const stats = mergeDir(srcDir, destDir);
|
|
55
|
+
totalFiles += stats.files;
|
|
56
|
+
totalDirs += stats.dirs;
|
|
57
|
+
|
|
58
|
+
const existed = existsSync(destDir) && stats.files > 0;
|
|
59
|
+
const tag = existed ? '~' : '+';
|
|
60
|
+
console.log(` ${tag} ${info.dir}/${bucket.padEnd(8)} → ${stats.files} files`);
|
|
61
|
+
}
|
|
62
|
+
|
|
38
63
|
const status = destExists ? 'updated' : 'installed';
|
|
39
|
-
console.log(` ✅ ${platform.padEnd(10)} ${status}
|
|
64
|
+
console.log(` ✅ ${platform.padEnd(10)} ${status} (${totalFiles} files total)`);
|
|
40
65
|
}
|
|
41
66
|
|
|
42
|
-
|
|
67
|
+
/**
|
|
68
|
+
* Merge files from src into dest.
|
|
69
|
+
* - New files: added
|
|
70
|
+
* - Same-name files: overwritten
|
|
71
|
+
* - Extra files in dest: PRESERVED
|
|
72
|
+
*/
|
|
73
|
+
function mergeDir(src, dest) {
|
|
43
74
|
let files = 0;
|
|
44
75
|
let dirs = 0;
|
|
45
|
-
let skipped = 0;
|
|
46
76
|
|
|
47
77
|
if (!existsSync(dest)) {
|
|
48
78
|
mkdirSync(dest, { recursive: true });
|
|
@@ -50,29 +80,22 @@ function copyDir(src, dest) {
|
|
|
50
80
|
|
|
51
81
|
for (const entry of readdirSync(src)) {
|
|
52
82
|
if (SKIP_FILES.has(entry)) continue;
|
|
53
|
-
|
|
54
|
-
if (entry.startsWith('.')) {
|
|
55
|
-
if (entry !== '.mcp.json' &&
|
|
56
|
-
!entry.startsWith('.claude') &&
|
|
57
|
-
!entry.startsWith('.opencode') &&
|
|
58
|
-
!entry.startsWith('.codex')) continue;
|
|
59
|
-
}
|
|
83
|
+
if (entry.startsWith('.') || entry === 'node_modules') continue;
|
|
60
84
|
|
|
61
85
|
const srcPath = join(src, entry);
|
|
62
86
|
const destPath = join(dest, entry);
|
|
63
87
|
|
|
64
88
|
if (statSync(srcPath).isDirectory()) {
|
|
65
|
-
const d =
|
|
89
|
+
const d = mergeDir(srcPath, destPath);
|
|
66
90
|
files += d.files;
|
|
67
91
|
dirs += d.dirs + 1;
|
|
68
|
-
skipped += d.skipped;
|
|
69
92
|
} else {
|
|
70
93
|
copyFileSync(srcPath, destPath);
|
|
71
94
|
files++;
|
|
72
95
|
}
|
|
73
96
|
}
|
|
74
97
|
|
|
75
|
-
return { files, dirs
|
|
98
|
+
return { files, dirs };
|
|
76
99
|
}
|
|
77
100
|
|
|
78
101
|
async function confirm(question) {
|