helloagents 1.1.0 → 2.2.8

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.
Files changed (38) hide show
  1. package/LICENSE.md +51 -0
  2. package/README.md +444 -841
  3. package/bin/cli.mjs +106 -0
  4. package/package.json +23 -38
  5. package/Claude/Skills/CN/CLAUDE.md +0 -998
  6. package/Claude/Skills/CN/skills/helloagents/analyze/SKILL.md +0 -187
  7. package/Claude/Skills/CN/skills/helloagents/design/SKILL.md +0 -261
  8. package/Claude/Skills/CN/skills/helloagents/develop/SKILL.md +0 -352
  9. package/Claude/Skills/CN/skills/helloagents/kb/SKILL.md +0 -249
  10. package/Claude/Skills/CN/skills/helloagents/templates/SKILL.md +0 -451
  11. package/Claude/Skills/EN/CLAUDE.md +0 -998
  12. package/Claude/Skills/EN/skills/helloagents/analyze/SKILL.md +0 -187
  13. package/Claude/Skills/EN/skills/helloagents/design/SKILL.md +0 -261
  14. package/Claude/Skills/EN/skills/helloagents/develop/SKILL.md +0 -352
  15. package/Claude/Skills/EN/skills/helloagents/kb/SKILL.md +0 -249
  16. package/Claude/Skills/EN/skills/helloagents/templates/SKILL.md +0 -451
  17. package/Codex/Skills/CN/AGENTS.md +0 -998
  18. package/Codex/Skills/CN/skills/helloagents/analyze/SKILL.md +0 -187
  19. package/Codex/Skills/CN/skills/helloagents/design/SKILL.md +0 -261
  20. package/Codex/Skills/CN/skills/helloagents/develop/SKILL.md +0 -352
  21. package/Codex/Skills/CN/skills/helloagents/kb/SKILL.md +0 -249
  22. package/Codex/Skills/CN/skills/helloagents/templates/SKILL.md +0 -451
  23. package/Codex/Skills/EN/AGENTS.md +0 -998
  24. package/Codex/Skills/EN/skills/helloagents/analyze/SKILL.md +0 -187
  25. package/Codex/Skills/EN/skills/helloagents/design/SKILL.md +0 -261
  26. package/Codex/Skills/EN/skills/helloagents/develop/SKILL.md +0 -352
  27. package/Codex/Skills/EN/skills/helloagents/kb/SKILL.md +0 -249
  28. package/Codex/Skills/EN/skills/helloagents/templates/SKILL.md +0 -451
  29. package/bin/cli.js +0 -85
  30. package/lib/args.js +0 -106
  31. package/lib/backup.js +0 -81
  32. package/lib/conflict.js +0 -118
  33. package/lib/copy.js +0 -125
  34. package/lib/defaults.js +0 -47
  35. package/lib/index.js +0 -297
  36. package/lib/output.js +0 -220
  37. package/lib/prompts.js +0 -173
  38. package/lib/utils.js +0 -225
package/lib/output.js DELETED
@@ -1,220 +0,0 @@
1
- /**
2
- * Output - Formatted output with ANSI colors
3
- */
4
-
5
- 'use strict';
6
-
7
- // Check if colors should be disabled
8
- const NO_COLOR = process.env.NO_COLOR !== undefined || process.argv.includes('--no-color');
9
-
10
- // ANSI color codes
11
- const colors = {
12
- reset: NO_COLOR ? '' : '\x1b[0m',
13
- bold: NO_COLOR ? '' : '\x1b[1m',
14
- dim: NO_COLOR ? '' : '\x1b[2m',
15
-
16
- // Foreground colors
17
- red: NO_COLOR ? '' : '\x1b[31m',
18
- green: NO_COLOR ? '' : '\x1b[32m',
19
- yellow: NO_COLOR ? '' : '\x1b[33m',
20
- blue: NO_COLOR ? '' : '\x1b[34m',
21
- magenta: NO_COLOR ? '' : '\x1b[35m',
22
- cyan: NO_COLOR ? '' : '\x1b[36m',
23
- white: NO_COLOR ? '' : '\x1b[37m',
24
- };
25
-
26
- // Symbols
27
- const symbols = {
28
- success: NO_COLOR ? '[OK]' : '✔',
29
- error: NO_COLOR ? '[ERROR]' : '✖',
30
- warning: NO_COLOR ? '[WARN]' : '⚠',
31
- info: NO_COLOR ? '[INFO]' : 'ℹ',
32
- arrow: NO_COLOR ? '->' : '→',
33
- bullet: NO_COLOR ? '*' : '•',
34
- };
35
-
36
- /**
37
- * Create output functions with injectable stdout
38
- * @param {Object} deps - Dependencies
39
- * @returns {Object} Output functions
40
- */
41
- function createOutput(deps = {}) {
42
- const stdout = deps.stdout || process.stdout;
43
- const stderr = deps.stderr || process.stderr;
44
-
45
- function write(stream, message) {
46
- stream.write(message + '\n');
47
- }
48
-
49
- return {
50
- /**
51
- * Print success message
52
- * @param {string} message
53
- */
54
- success(message) {
55
- write(stdout, `${colors.green}${symbols.success}${colors.reset} ${message}`);
56
- },
57
-
58
- /**
59
- * Print error message
60
- * @param {string} message
61
- */
62
- error(message) {
63
- write(stderr, `${colors.red}${symbols.error}${colors.reset} ${message}`);
64
- },
65
-
66
- /**
67
- * Print warning message
68
- * @param {string} message
69
- */
70
- warn(message) {
71
- write(stdout, `${colors.yellow}${symbols.warning}${colors.reset} ${message}`);
72
- },
73
-
74
- /**
75
- * Print info message
76
- * @param {string} message
77
- */
78
- info(message) {
79
- write(stdout, `${colors.cyan}${symbols.info}${colors.reset} ${message}`);
80
- },
81
-
82
- /**
83
- * Print plain message
84
- * @param {string} message
85
- */
86
- log(message) {
87
- write(stdout, message);
88
- },
89
-
90
- /**
91
- * Print empty line
92
- */
93
- newline() {
94
- write(stdout, '');
95
- },
96
-
97
- /**
98
- * Print header
99
- * @param {string} title
100
- */
101
- header(title) {
102
- write(stdout, `\n${colors.bold}${colors.cyan}${title}${colors.reset}\n`);
103
- },
104
-
105
- /**
106
- * Print divider
107
- */
108
- divider() {
109
- write(stdout, `${colors.dim}${'─'.repeat(40)}${colors.reset}`);
110
- },
111
-
112
- /**
113
- * Print operation item
114
- * @param {string} source
115
- * @param {string} target
116
- * @param {string} action
117
- */
118
- operation(source, target, action) {
119
- write(stdout, `\n源: ${colors.cyan}${source}${colors.reset}`);
120
- write(stdout, ` ${symbols.arrow} 目标: ${colors.cyan}${target}${colors.reset}`);
121
- write(stdout, ` ${symbols.arrow} 操作: ${action}`);
122
- },
123
-
124
- /**
125
- * Print dry-run summary
126
- * @param {Object} stats - { write, backup, newFile, skip }
127
- */
128
- printDryRunSummary(stats) {
129
- write(stdout, '');
130
- write(stdout, `${colors.dim}${'─'.repeat(40)}${colors.reset}`);
131
- write(stdout, `汇总: 写入 ${stats.write || 0} | 备份 ${stats.backup || 0} | 生成.new ${stats.newFile || 0} | 跳过 ${stats.skip || 0}`);
132
- write(stdout, '');
133
- write(stdout, `${colors.yellow}${symbols.warning}${colors.reset} Dry Run 模式:不会做任何写入`);
134
- },
135
-
136
- /**
137
- * Print final summary
138
- * @param {Object} stats - { write, backup, newFile, skip }
139
- * @param {Array} backups - List of backup paths
140
- */
141
- printSummary(stats, backups = []) {
142
- write(stdout, '');
143
- write(stdout, `${colors.dim}${'─'.repeat(40)}${colors.reset}`);
144
- write(stdout, `${colors.green}${symbols.success}${colors.reset} 安装完成!`);
145
- write(stdout, '');
146
- write(stdout, `汇总: 写入 ${stats.write || 0} | 备份 ${stats.backup || 0} | 生成.new ${stats.newFile || 0} | 跳过 ${stats.skip || 0}`);
147
-
148
- if (backups.length > 0) {
149
- write(stdout, '');
150
- write(stdout, `${colors.cyan}已创建的备份:${colors.reset}`);
151
- for (const backup of backups) {
152
- write(stdout, ` ${symbols.bullet} ${backup}`);
153
- }
154
- }
155
- },
156
-
157
- /**
158
- * Print welcome message
159
- */
160
- printWelcome() {
161
- write(stdout, '');
162
- write(stdout, `${colors.bold}${colors.cyan}HelloAGENTS${colors.reset} - AI编程模块化技能系统`);
163
- write(stdout, `${colors.dim}配置工具 v1.0.0${colors.reset}`);
164
- write(stdout, '');
165
- },
166
-
167
- /**
168
- * Print recovery instructions on failure
169
- * @param {string} errorMessage
170
- * @param {Array} backups - List of backup paths
171
- * @param {string} platform - 'claude' or 'codex'
172
- */
173
- printRecoveryInstructions(errorMessage, backups, platform) {
174
- const configDir = platform === 'claude' ? '.claude' : '.codex';
175
-
176
- write(stderr, '');
177
- write(stderr, `${colors.red}${symbols.error} 复制失败: ${errorMessage}${colors.reset}`);
178
-
179
- if (backups.length > 0) {
180
- write(stderr, '');
181
- write(stderr, `${colors.cyan}已创建的备份:${colors.reset}`);
182
- for (const backup of backups) {
183
- write(stderr, ` ${backup}`);
184
- }
185
-
186
- write(stderr, '');
187
- write(stderr, `${colors.cyan}恢复命令(如需回滚):${colors.reset}`);
188
- write(stderr, '');
189
- write(stderr, `# macOS/Linux`);
190
- for (const backup of backups) {
191
- const original = backup.replace(/\.backup-\d{8}-\d{6}\/?$/, '');
192
- const name = original.split('/').pop() || original.split('\\').pop();
193
- write(stderr, `rm -rf ${original}`);
194
- write(stderr, `mv ${backup} ${original}`);
195
- }
196
- write(stderr, '');
197
- write(stderr, `# Windows PowerShell`);
198
- for (const backup of backups) {
199
- const original = backup.replace(/\.backup-\d{8}-\d{6}\/?$/, '');
200
- const name = original.split('/').pop() || original.split('\\').pop();
201
- write(stderr, `Remove-Item "${original}" -Recurse -Force`);
202
- write(stderr, `Rename-Item "${backup}" "${name}"`);
203
- }
204
- }
205
-
206
- write(stderr, '');
207
- write(stderr, `请修复问题后重新运行,或使用上述命令手动恢复。`);
208
- },
209
- };
210
- }
211
-
212
- // Default instance
213
- const defaultOutput = createOutput();
214
-
215
- module.exports = {
216
- colors,
217
- symbols,
218
- createOutput,
219
- ...defaultOutput,
220
- };
package/lib/prompts.js DELETED
@@ -1,173 +0,0 @@
1
- /**
2
- * Prompts - Interactive prompts using native readline
3
- */
4
-
5
- 'use strict';
6
-
7
- const readline = require('readline');
8
-
9
- /**
10
- * Create readline interface
11
- * @returns {readline.Interface}
12
- */
13
- function createReadline() {
14
- return readline.createInterface({
15
- input: process.stdin,
16
- output: process.stdout,
17
- });
18
- }
19
-
20
- /**
21
- * Ask a question and get answer
22
- * @param {readline.Interface} rl - Readline interface
23
- * @param {string} question - Question to ask
24
- * @returns {Promise<string>}
25
- */
26
- function ask(rl, question) {
27
- return new Promise((resolve) => {
28
- rl.question(question, (answer) => {
29
- resolve(answer.trim());
30
- });
31
- });
32
- }
33
-
34
- /**
35
- * Ask for platform selection
36
- * @param {readline.Interface} rl - Readline interface
37
- * @param {string} defaultPlatform - Default platform
38
- * @param {string} reason - Reason for default
39
- * @returns {Promise<string>} 'claude' or 'codex'
40
- */
41
- async function askPlatform(rl, defaultPlatform = 'claude', reason = '') {
42
- const defaultNum = defaultPlatform === 'claude' ? '1' : '2';
43
- const reasonText = reason ? ` (${reason})` : '';
44
-
45
- console.log('');
46
- console.log('选择目标平台:');
47
- console.log(` 1. Claude Code${defaultPlatform === 'claude' ? ` [默认]${reasonText}` : ''}`);
48
- console.log(` 2. Codex${defaultPlatform === 'codex' ? ` [默认]${reasonText}` : ''}`);
49
- console.log('');
50
-
51
- const answer = await ask(rl, `请输入选项 (1-2) [${defaultNum}]: `);
52
-
53
- if (answer === '' || answer === defaultNum) {
54
- return defaultPlatform;
55
- }
56
-
57
- if (answer === '1') {
58
- return 'claude';
59
- }
60
-
61
- if (answer === '2') {
62
- return 'codex';
63
- }
64
-
65
- // Invalid input, ask again
66
- console.log('无效输入,请输入 1 或 2');
67
- return askPlatform(rl, defaultPlatform, reason);
68
- }
69
-
70
- /**
71
- * Ask for language selection
72
- * @param {readline.Interface} rl - Readline interface
73
- * @param {string} defaultLang - Default language
74
- * @returns {Promise<string>} 'cn' or 'en'
75
- */
76
- async function askLanguage(rl, defaultLang = 'cn') {
77
- const defaultNum = defaultLang === 'cn' ? '1' : '2';
78
-
79
- console.log('');
80
- console.log('选择语言版本:');
81
- console.log(` 1. 中文${defaultLang === 'cn' ? ' [默认]' : ''}`);
82
- console.log(` 2. English${defaultLang === 'en' ? ' [默认]' : ''}`);
83
- console.log('');
84
-
85
- const answer = await ask(rl, `请输入选项 (1-2) [${defaultNum}]: `);
86
-
87
- if (answer === '' || answer === defaultNum) {
88
- return defaultLang;
89
- }
90
-
91
- if (answer === '1') {
92
- return 'cn';
93
- }
94
-
95
- if (answer === '2') {
96
- return 'en';
97
- }
98
-
99
- // Invalid input, ask again
100
- console.log('无效输入,请输入 1 或 2');
101
- return askLanguage(rl, defaultLang);
102
- }
103
-
104
- /**
105
- * Ask for config file conflict resolution
106
- * @param {readline.Interface} rl - Readline interface
107
- * @param {string} fileName - Name of the config file
108
- * @returns {Promise<string>} 'new' | 'backup' | 'overwrite' | 'skip'
109
- */
110
- async function askConfigConflict(rl, fileName) {
111
- console.log('');
112
- console.log(`检测到 ${fileName} 已存在,请选择处理方式:`);
113
- console.log(' 1. 生成 .helloagents.new 文件(保留原文件)[默认]');
114
- console.log(' 2. 备份后覆盖');
115
- console.log(' 3. 直接覆盖(不备份)');
116
- console.log(' 4. 跳过');
117
- console.log('');
118
-
119
- const answer = await ask(rl, '请输入选项 (1-4) [1]: ');
120
-
121
- switch (answer) {
122
- case '':
123
- case '1':
124
- return 'new';
125
- case '2':
126
- return 'backup';
127
- case '3':
128
- return 'overwrite';
129
- case '4':
130
- return 'skip';
131
- default:
132
- console.log('无效输入,请输入 1-4');
133
- return askConfigConflict(rl, fileName);
134
- }
135
- }
136
-
137
- /**
138
- * Ask for skills directory conflict resolution
139
- * @param {readline.Interface} rl - Readline interface
140
- * @returns {Promise<string>} 'backup' | 'overwrite' | 'skip'
141
- */
142
- async function askSkillsConflict(rl) {
143
- console.log('');
144
- console.log('检测到 skills/helloagents 目录已存在,请选择处理方式:');
145
- console.log(' 1. 备份后覆盖 [默认]');
146
- console.log(' 2. 直接覆盖(不备份)');
147
- console.log(' 3. 跳过');
148
- console.log('');
149
-
150
- const answer = await ask(rl, '请输入选项 (1-3) [1]: ');
151
-
152
- switch (answer) {
153
- case '':
154
- case '1':
155
- return 'backup';
156
- case '2':
157
- return 'overwrite';
158
- case '3':
159
- return 'skip';
160
- default:
161
- console.log('无效输入,请输入 1-3');
162
- return askSkillsConflict(rl);
163
- }
164
- }
165
-
166
- module.exports = {
167
- createReadline,
168
- ask,
169
- askPlatform,
170
- askLanguage,
171
- askConfigConflict,
172
- askSkillsConflict,
173
- };
package/lib/utils.js DELETED
@@ -1,225 +0,0 @@
1
- /**
2
- * Utils - Utility functions with dependency injection support
3
- */
4
-
5
- 'use strict';
6
-
7
- const fs = require('fs');
8
- const fsPromises = require('fs').promises;
9
- const path = require('path');
10
- const os = require('os');
11
-
12
- /**
13
- * Get home directory (injectable for testing)
14
- * @param {Object} deps - Dependencies
15
- * @returns {string} Home directory path
16
- */
17
- function getHomeDir(deps = {}) {
18
- if (deps.homeDir) {
19
- return deps.homeDir;
20
- }
21
- return os.homedir();
22
- }
23
-
24
- /**
25
- * Get timestamp string (injectable for testing)
26
- * @param {Object} deps - Dependencies
27
- * @returns {string} Timestamp in YYYYMMDD-HHmmss format
28
- */
29
- function getTimestamp(deps = {}) {
30
- const now = deps.now ? deps.now() : new Date();
31
- const year = now.getFullYear();
32
- const month = String(now.getMonth() + 1).padStart(2, '0');
33
- const day = String(now.getDate()).padStart(2, '0');
34
- const hours = String(now.getHours()).padStart(2, '0');
35
- const minutes = String(now.getMinutes()).padStart(2, '0');
36
- const seconds = String(now.getSeconds()).padStart(2, '0');
37
- return `${year}${month}${day}-${hours}${minutes}${seconds}`;
38
- }
39
-
40
- /**
41
- * Generate random suffix (injectable for testing)
42
- * @param {Object} deps - Dependencies
43
- * @returns {string} Random 6-character string
44
- */
45
- function randomSuffix(deps = {}) {
46
- if (deps.randomSuffix) {
47
- return deps.randomSuffix();
48
- }
49
- return Math.random().toString(36).slice(2, 8);
50
- }
51
-
52
- /**
53
- * Check if file exists
54
- * @param {string} filePath - Path to check
55
- * @param {Object} deps - Dependencies
56
- * @returns {Promise<boolean>}
57
- */
58
- async function fileExists(filePath, deps = {}) {
59
- const fsModule = deps.fs || fsPromises;
60
- try {
61
- const stat = await fsModule.stat(filePath);
62
- return stat.isFile();
63
- } catch (err) {
64
- if (err.code === 'ENOENT') {
65
- return false;
66
- }
67
- throw err;
68
- }
69
- }
70
-
71
- /**
72
- * Check if directory exists
73
- * @param {string} dirPath - Path to check
74
- * @param {Object} deps - Dependencies
75
- * @returns {Promise<boolean>}
76
- */
77
- async function dirExists(dirPath, deps = {}) {
78
- const fsModule = deps.fs || fsPromises;
79
- try {
80
- const stat = await fsModule.stat(dirPath);
81
- return stat.isDirectory();
82
- } catch (err) {
83
- if (err.code === 'ENOENT') {
84
- return false;
85
- }
86
- throw err;
87
- }
88
- }
89
-
90
- /**
91
- * Read file content
92
- * @param {string} filePath - Path to read
93
- * @param {Object} deps - Dependencies
94
- * @returns {Promise<string>}
95
- */
96
- async function readFileContent(filePath, deps = {}) {
97
- const fsModule = deps.fs || fsPromises;
98
- return fsModule.readFile(filePath, 'utf8');
99
- }
100
-
101
- /**
102
- * Recursive delete (compatible with Node 16)
103
- * @param {string} targetPath - Path to delete
104
- * @param {Object} deps - Dependencies
105
- * @returns {Promise<void>}
106
- */
107
- async function rmrf(targetPath, deps = {}) {
108
- const fsModule = deps.fs || fsPromises;
109
-
110
- // Check if path exists
111
- try {
112
- await fsModule.stat(targetPath);
113
- } catch (err) {
114
- if (err.code === 'ENOENT') {
115
- return; // Already doesn't exist
116
- }
117
- throw err;
118
- }
119
-
120
- // Try fs.rm first (Node 16+)
121
- if (fsModule.rm) {
122
- try {
123
- await fsModule.rm(targetPath, { recursive: true, force: true });
124
- return;
125
- } catch (err) {
126
- // Fall through to rmdir
127
- }
128
- }
129
-
130
- // Fallback to fs.rmdir with recursive (Node 16+)
131
- if (fsModule.rmdir) {
132
- await fsModule.rmdir(targetPath, { recursive: true });
133
- return;
134
- }
135
-
136
- // Manual recursive delete as last resort
137
- const stat = await fsModule.stat(targetPath);
138
- if (stat.isDirectory()) {
139
- const entries = await fsModule.readdir(targetPath);
140
- for (const entry of entries) {
141
- await rmrf(path.join(targetPath, entry), deps);
142
- }
143
- await fsModule.rmdir(targetPath);
144
- } else {
145
- await fsModule.unlink(targetPath);
146
- }
147
- }
148
-
149
- /**
150
- * Ensure directory exists (create if not)
151
- * @param {string} dirPath - Directory path
152
- * @param {Object} deps - Dependencies
153
- * @returns {Promise<void>}
154
- */
155
- async function ensureDir(dirPath, deps = {}) {
156
- const fsModule = deps.fs || fsPromises;
157
- try {
158
- await fsModule.mkdir(dirPath, { recursive: true });
159
- } catch (err) {
160
- if (err.code !== 'EEXIST') {
161
- throw err;
162
- }
163
- }
164
- }
165
-
166
- /**
167
- * Get package root directory (where package.json is)
168
- * @returns {string}
169
- */
170
- function getPackageRoot() {
171
- return path.resolve(__dirname, '..');
172
- }
173
-
174
- /**
175
- * Get source path for platform and language
176
- * @param {string} platform - 'claude' or 'codex'
177
- * @param {string} lang - 'cn' or 'en'
178
- * @returns {Object} { configFile, skillsDir }
179
- */
180
- function getSourcePaths(platform, lang) {
181
- const root = getPackageRoot();
182
- const platformDir = platform === 'claude' ? 'Claude' : 'Codex';
183
- const langDir = lang === 'cn' ? 'CN' : 'EN';
184
- const configFileName = platform === 'claude' ? 'CLAUDE.md' : 'AGENTS.md';
185
-
186
- return {
187
- configFile: path.join(root, platformDir, 'Skills', langDir, configFileName),
188
- skillsDir: path.join(root, platformDir, 'Skills', langDir, 'skills', 'helloagents'),
189
- };
190
- }
191
-
192
- /**
193
- * Get target path for platform
194
- * @param {string} platform - 'claude' or 'codex'
195
- * @param {Object} deps - Dependencies
196
- * @returns {Object} { targetDir, configFile, skillsDir, newFile }
197
- */
198
- function getTargetPaths(platform, deps = {}) {
199
- const homeDir = getHomeDir(deps);
200
- const targetDir = platform === 'claude'
201
- ? path.join(homeDir, '.claude')
202
- : path.join(homeDir, '.codex');
203
- const configFileName = platform === 'claude' ? 'CLAUDE.md' : 'AGENTS.md';
204
-
205
- return {
206
- targetDir,
207
- configFile: path.join(targetDir, configFileName),
208
- skillsDir: path.join(targetDir, 'skills', 'helloagents'),
209
- newFile: path.join(targetDir, '.helloagents.new'),
210
- };
211
- }
212
-
213
- module.exports = {
214
- getHomeDir,
215
- getTimestamp,
216
- randomSuffix,
217
- fileExists,
218
- dirExists,
219
- readFileContent,
220
- rmrf,
221
- ensureDir,
222
- getPackageRoot,
223
- getSourcePaths,
224
- getTargetPaths,
225
- };