helloagents 2.3.8 → 3.0.2-beta.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-plugin/marketplace.json +20 -0
- package/.claude-plugin/plugin.json +21 -0
- package/.codex-plugin/plugin.json +46 -0
- package/README.md +494 -636
- package/README_CN.md +778 -0
- package/assets/dogdoing/complete.wav +0 -0
- package/assets/dogdoing/confirm.wav +0 -0
- package/assets/dogdoing/error.wav +0 -0
- package/assets/dogdoing/idle.wav +0 -0
- package/assets/dogdoing/warning.wav +0 -0
- package/assets/icons/icon-large.png +0 -0
- package/assets/icons/icon.png +0 -0
- package/assets/sounds/complete.wav +0 -0
- package/assets/sounds/confirm.wav +0 -0
- package/assets/sounds/error.wav +0 -0
- package/assets/sounds/idle.wav +0 -0
- package/assets/sounds/warning.wav +0 -0
- package/bootstrap-lite.md +199 -0
- package/bootstrap.md +296 -0
- package/cli.mjs +453 -0
- package/gemini-extension.json +8 -0
- package/hooks/hooks-claude.json +88 -0
- package/hooks/hooks.json +76 -0
- package/package.json +36 -6
- package/scripts/cli-codex.mjs +428 -0
- package/scripts/cli-config.mjs +37 -0
- package/scripts/cli-hosts.mjs +75 -0
- package/scripts/cli-messages.mjs +92 -0
- package/scripts/cli-toml.mjs +251 -0
- package/scripts/cli-utils.mjs +139 -0
- package/scripts/guard.mjs +217 -0
- package/scripts/notify-context.mjs +123 -0
- package/scripts/notify-events.mjs +11 -0
- package/scripts/notify-shared.mjs +47 -0
- package/scripts/notify-ui.mjs +92 -0
- package/scripts/notify.mjs +219 -0
- package/scripts/ralph-loop.mjs +246 -0
- package/skills/_meta/SKILL.md +19 -0
- package/skills/commands/auto/SKILL.md +91 -0
- package/skills/commands/clean/SKILL.md +21 -0
- package/skills/commands/commit/SKILL.md +26 -0
- package/skills/commands/design/SKILL.md +108 -0
- package/skills/commands/help/SKILL.md +45 -0
- package/skills/commands/init/SKILL.md +60 -0
- package/skills/commands/loop/SKILL.md +98 -0
- package/skills/commands/prd/SKILL.md +151 -0
- package/skills/commands/review/SKILL.md +16 -0
- package/skills/commands/test/SKILL.md +16 -0
- package/skills/commands/verify/SKILL.md +21 -0
- package/skills/hello-api/SKILL.md +40 -0
- package/skills/hello-arch/SKILL.md +38 -0
- package/skills/hello-data/SKILL.md +39 -0
- package/skills/hello-debug/SKILL.md +58 -0
- package/skills/hello-errors/SKILL.md +39 -0
- package/skills/hello-perf/SKILL.md +40 -0
- package/skills/hello-reflect/SKILL.md +34 -0
- package/skills/hello-review/SKILL.md +33 -0
- package/skills/hello-security/SKILL.md +40 -0
- package/skills/hello-subagent/SKILL.md +32 -0
- package/skills/hello-test/SKILL.md +55 -0
- package/skills/hello-ui/SKILL.md +197 -0
- package/skills/hello-verify/SKILL.md +132 -0
- package/skills/hello-write/SKILL.md +33 -0
- package/skills/helloagents/SKILL.md +107 -0
- package/templates/CHANGELOG.md +5 -0
- package/templates/DESIGN.md +19 -0
- package/templates/STATE.md +19 -0
- package/templates/archive/_index.md +4 -0
- package/templates/context.md +19 -0
- package/templates/guidelines.md +15 -0
- package/templates/modules/module.md +13 -0
- package/templates/plans/decisions.md +10 -0
- package/templates/plans/design.md +14 -0
- package/templates/plans/prd/00-overview.md +23 -0
- package/templates/plans/prd/01-user-stories.md +19 -0
- package/templates/plans/prd/02-functional.md +30 -0
- package/templates/plans/prd/03-ui-design.md +31 -0
- package/templates/plans/prd/04-technical.md +25 -0
- package/templates/plans/prd/05-nonfunctional.md +28 -0
- package/templates/plans/prd/06-i18n-l10n.md +23 -0
- package/templates/plans/prd/07-accessibility.md +20 -0
- package/templates/plans/prd/08-content.md +20 -0
- package/templates/plans/prd/09-testing.md +22 -0
- package/templates/plans/prd/10-deployment.md +23 -0
- package/templates/plans/prd/11-legal-privacy.md +18 -0
- package/templates/plans/prd/12-timeline.md +21 -0
- package/templates/plans/requirements.md +18 -0
- package/templates/plans/tasks.md +10 -0
- package/templates/verify.yaml +9 -0
- package/bin/cli.mjs +0 -106
package/cli.mjs
ADDED
|
@@ -0,0 +1,453 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* HelloAGENTS CLI — Quality-driven orchestration kernel for AI CLIs.
|
|
4
|
+
* Runs as npm lifecycle script (postinstall/preuninstall). Zero external dependencies.
|
|
5
|
+
*/
|
|
6
|
+
'use strict';
|
|
7
|
+
|
|
8
|
+
import { homedir } from 'node:os';
|
|
9
|
+
import { join, resolve, dirname } from 'node:path';
|
|
10
|
+
import { fileURLToPath } from 'node:url';
|
|
11
|
+
import { existsSync, writeFileSync } from 'node:fs';
|
|
12
|
+
import { safeRead, safeWrite, safeJson, ensureDir } from './scripts/cli-utils.mjs';
|
|
13
|
+
import {
|
|
14
|
+
installCodexStandby,
|
|
15
|
+
uninstallCodexStandby,
|
|
16
|
+
installCodexGlobal,
|
|
17
|
+
uninstallCodexGlobal,
|
|
18
|
+
CODEX_MARKETPLACE_NAME,
|
|
19
|
+
CODEX_PLUGIN_KEY,
|
|
20
|
+
CODEX_PLUGIN_NAME,
|
|
21
|
+
} from './scripts/cli-codex.mjs';
|
|
22
|
+
import { installClaudeStandby, uninstallClaudeStandby, installGeminiStandby, uninstallGeminiStandby } from './scripts/cli-hosts.mjs';
|
|
23
|
+
import { DEFAULTS, ensureConfig, loadPackageVersion } from './scripts/cli-config.mjs';
|
|
24
|
+
import { createMessageHelpers, createInstallMessagePrinter } from './scripts/cli-messages.mjs';
|
|
25
|
+
|
|
26
|
+
const HOME = homedir();
|
|
27
|
+
const PKG_ROOT = resolve(dirname(fileURLToPath(import.meta.url)));
|
|
28
|
+
const HELLOAGENTS_HOME = join(HOME, '.helloagents');
|
|
29
|
+
const CONFIG_FILE = join(HELLOAGENTS_HOME, 'helloagents.json');
|
|
30
|
+
const pkg = loadPackageVersion(PKG_ROOT);
|
|
31
|
+
|
|
32
|
+
const isCN = (() => {
|
|
33
|
+
const lang = (process.env.LANG || process.env.LANGUAGE || process.env.LC_ALL || '').toLowerCase();
|
|
34
|
+
return lang.includes('zh') || lang.includes('cn');
|
|
35
|
+
})();
|
|
36
|
+
const { msg, ok } = createMessageHelpers(isCN);
|
|
37
|
+
const { printHelp, printInstallMsg } = createInstallMessagePrinter({
|
|
38
|
+
home: HOME,
|
|
39
|
+
pkgVersion: pkg.version,
|
|
40
|
+
msg,
|
|
41
|
+
});
|
|
42
|
+
const HOSTS = ['claude', 'gemini', 'codex'];
|
|
43
|
+
const HOST_ALIASES = new Map([
|
|
44
|
+
['all', 'all'],
|
|
45
|
+
['*', 'all'],
|
|
46
|
+
['claude', 'claude'],
|
|
47
|
+
['claude-code', 'claude'],
|
|
48
|
+
['gemini', 'gemini'],
|
|
49
|
+
['gemini-cli', 'gemini'],
|
|
50
|
+
['codex', 'codex'],
|
|
51
|
+
['codex-cli', 'codex'],
|
|
52
|
+
]);
|
|
53
|
+
|
|
54
|
+
function readSettings(shouldEnsure = false) {
|
|
55
|
+
if (shouldEnsure) ensureConfig(HELLOAGENTS_HOME, CONFIG_FILE, safeJson, ensureDir);
|
|
56
|
+
return safeJson(CONFIG_FILE) || {};
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function writeSettings(settings) {
|
|
60
|
+
ensureDir(HELLOAGENTS_HOME);
|
|
61
|
+
writeFileSync(CONFIG_FILE, JSON.stringify(settings, null, 2), 'utf-8');
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function hasTrackedHostModes(settings) {
|
|
65
|
+
return !!settings
|
|
66
|
+
&& typeof settings.host_install_modes === 'object'
|
|
67
|
+
&& !Array.isArray(settings.host_install_modes);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function getTrackedHostMode(settings, host) {
|
|
71
|
+
return hasTrackedHostModes(settings) ? settings.host_install_modes[host] || '' : '';
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function setTrackedHostMode(settings, host, mode) {
|
|
75
|
+
if (!hasTrackedHostModes(settings)) settings.host_install_modes = {};
|
|
76
|
+
settings.host_install_modes[host] = mode;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function clearTrackedHostMode(settings, host) {
|
|
80
|
+
if (!hasTrackedHostModes(settings)) {
|
|
81
|
+
settings.host_install_modes = {};
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
delete settings.host_install_modes[host];
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function setAllTrackedHostModes(settings, mode) {
|
|
88
|
+
settings.host_install_modes = Object.fromEntries(HOSTS.map((host) => [host, mode]));
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function clearAllTrackedHostModes(settings) {
|
|
92
|
+
settings.host_install_modes = {};
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function normalizeHost(value = '') {
|
|
96
|
+
return HOST_ALIASES.get(String(value || '').toLowerCase()) || '';
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function parseModeFlag(args) {
|
|
100
|
+
const hasGlobal = args.includes('--global');
|
|
101
|
+
const hasStandby = args.includes('--standby');
|
|
102
|
+
if (hasGlobal && hasStandby) {
|
|
103
|
+
throw new Error(msg('不能同时指定 --global 和 --standby', 'Cannot use --global and --standby together'));
|
|
104
|
+
}
|
|
105
|
+
if (hasGlobal) return 'global';
|
|
106
|
+
if (hasStandby) return 'standby';
|
|
107
|
+
return '';
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function parseLifecycleArgs(args) {
|
|
111
|
+
const explicitMode = parseModeFlag(args);
|
|
112
|
+
const wantsAll = args.includes('--all');
|
|
113
|
+
const positionals = args.filter((arg) => !arg.startsWith('--'));
|
|
114
|
+
const unknownFlags = args.filter((arg) =>
|
|
115
|
+
arg.startsWith('--')
|
|
116
|
+
&& arg !== '--global'
|
|
117
|
+
&& arg !== '--standby'
|
|
118
|
+
&& arg !== '--all');
|
|
119
|
+
if (unknownFlags.length) {
|
|
120
|
+
throw new Error(msg(`未知参数: ${unknownFlags.join(', ')}`, `Unknown flags: ${unknownFlags.join(', ')}`));
|
|
121
|
+
}
|
|
122
|
+
if (wantsAll && positionals.length) {
|
|
123
|
+
throw new Error(msg('`--all` 不能与具体 CLI 同时使用', '`--all` cannot be combined with a specific CLI'));
|
|
124
|
+
}
|
|
125
|
+
if (positionals.length > 1) {
|
|
126
|
+
throw new Error(msg(`参数过多: ${positionals.join(' ')}`, `Too many arguments: ${positionals.join(' ')}`));
|
|
127
|
+
}
|
|
128
|
+
const host = normalizeHost(wantsAll ? 'all' : (positionals[0] || 'all'));
|
|
129
|
+
if (!host) {
|
|
130
|
+
throw new Error(msg(`不支持的 CLI: ${positionals[0]}`, `Unsupported CLI: ${positionals[0]}`));
|
|
131
|
+
}
|
|
132
|
+
return { host, explicitMode };
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function hasHelloagentsMarker(filePath) {
|
|
136
|
+
return (safeRead(filePath) || '').includes('HELLOAGENTS_START');
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function hasHelloagentsSettings(filePath) {
|
|
140
|
+
return JSON.stringify(safeJson(filePath) || {}).includes('helloagents');
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function detectClaudeMode() {
|
|
144
|
+
const claudeDir = join(HOME, '.claude');
|
|
145
|
+
if (
|
|
146
|
+
existsSync(join(claudeDir, 'helloagents'))
|
|
147
|
+
|| hasHelloagentsMarker(join(claudeDir, 'CLAUDE.md'))
|
|
148
|
+
|| hasHelloagentsSettings(join(claudeDir, 'settings.json'))
|
|
149
|
+
) {
|
|
150
|
+
return 'standby';
|
|
151
|
+
}
|
|
152
|
+
return '';
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function detectGeminiMode() {
|
|
156
|
+
const geminiDir = join(HOME, '.gemini');
|
|
157
|
+
if (
|
|
158
|
+
existsSync(join(geminiDir, 'helloagents'))
|
|
159
|
+
|| hasHelloagentsMarker(join(geminiDir, 'GEMINI.md'))
|
|
160
|
+
|| hasHelloagentsSettings(join(geminiDir, 'settings.json'))
|
|
161
|
+
) {
|
|
162
|
+
return 'standby';
|
|
163
|
+
}
|
|
164
|
+
return '';
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
function detectCodexMode() {
|
|
168
|
+
const codexDir = join(HOME, '.codex');
|
|
169
|
+
const codexConfig = safeRead(join(codexDir, 'config.toml')) || '';
|
|
170
|
+
const marketplace = safeRead(join(HOME, '.agents', 'plugins', 'marketplace.json')) || '';
|
|
171
|
+
if (
|
|
172
|
+
existsSync(join(HOME, 'plugins', CODEX_PLUGIN_NAME))
|
|
173
|
+
|| existsSync(join(codexDir, 'plugins', 'cache', CODEX_MARKETPLACE_NAME, CODEX_PLUGIN_NAME))
|
|
174
|
+
|| marketplace.includes(`"name": "${CODEX_PLUGIN_NAME}"`)
|
|
175
|
+
|| codexConfig.includes(CODEX_PLUGIN_KEY)
|
|
176
|
+
|| codexConfig.includes(`/plugins/${CODEX_PLUGIN_NAME}/scripts/notify.mjs`)
|
|
177
|
+
) {
|
|
178
|
+
return 'global';
|
|
179
|
+
}
|
|
180
|
+
if (
|
|
181
|
+
existsSync(join(codexDir, 'helloagents'))
|
|
182
|
+
|| hasHelloagentsMarker(join(codexDir, 'AGENTS.md'))
|
|
183
|
+
|| codexConfig.includes('codex-notify')
|
|
184
|
+
|| codexConfig.includes('HelloAGENTS')
|
|
185
|
+
) {
|
|
186
|
+
return 'standby';
|
|
187
|
+
}
|
|
188
|
+
return '';
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
function detectHostMode(host) {
|
|
192
|
+
if (host === 'claude') return detectClaudeMode();
|
|
193
|
+
if (host === 'gemini') return detectGeminiMode();
|
|
194
|
+
if (host === 'codex') return detectCodexMode();
|
|
195
|
+
return '';
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
function resolveHostMode(host, explicitMode, settings) {
|
|
199
|
+
if (explicitMode) return explicitMode;
|
|
200
|
+
return detectHostMode(host)
|
|
201
|
+
|| getTrackedHostMode(settings, host)
|
|
202
|
+
|| (!hasTrackedHostModes(settings) ? (settings.install_mode || '') : '')
|
|
203
|
+
|| DEFAULTS.install_mode;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
function resolveInstallMode(explicitMode, settings) {
|
|
207
|
+
return explicitMode || settings.install_mode || DEFAULTS.install_mode;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
function getHostLabel(host) {
|
|
211
|
+
if (host === 'claude') return 'Claude Code';
|
|
212
|
+
if (host === 'gemini') return 'Gemini CLI';
|
|
213
|
+
if (host === 'codex') return 'Codex CLI';
|
|
214
|
+
return 'All CLIs';
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
function reportHostAction(action, host, mode, result = {}) {
|
|
218
|
+
const label = getHostLabel(host);
|
|
219
|
+
const isCleanup = action === 'cleanup' || action === 'uninstall';
|
|
220
|
+
if (result.skipped) {
|
|
221
|
+
console.log(msg(` - ${label} 未检测到,跳过`, ` - ${label} not detected, skipped`));
|
|
222
|
+
} else if (isCleanup) {
|
|
223
|
+
ok(msg(`${label} 已清理(${mode} 模式)`, `${label} cleaned (${mode} mode)`));
|
|
224
|
+
} else if (mode === 'standby') {
|
|
225
|
+
ok(msg(`${label} 已配置(standby 模式)`, `${label} configured (standby mode)`));
|
|
226
|
+
} else if (host === 'codex') {
|
|
227
|
+
ok(msg(`${label} 已安装原生本地插件(global 模式)`, `${label} native local plugin installed (global mode)`));
|
|
228
|
+
} else {
|
|
229
|
+
ok(msg(`${label} 已切到 global 模式`, `${label} switched to global mode`));
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
if (result.noteCN || result.noteEN) {
|
|
233
|
+
console.log(msg(` ℹ ${result.noteCN}`, ` ℹ ${result.noteEN}`));
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
function installHostStandby(host) {
|
|
238
|
+
if (host === 'claude') {
|
|
239
|
+
installClaudeStandby(HOME, PKG_ROOT);
|
|
240
|
+
return {};
|
|
241
|
+
}
|
|
242
|
+
if (host === 'gemini') {
|
|
243
|
+
installGeminiStandby(HOME, PKG_ROOT);
|
|
244
|
+
return {};
|
|
245
|
+
}
|
|
246
|
+
uninstallCodexGlobal(HOME);
|
|
247
|
+
if (!installCodexStandby(HOME, PKG_ROOT)) return { skipped: true };
|
|
248
|
+
return {};
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
function installHostGlobal(host) {
|
|
252
|
+
if (host === 'claude') {
|
|
253
|
+
uninstallClaudeStandby(HOME);
|
|
254
|
+
return {
|
|
255
|
+
noteCN: 'Claude Code 的 global 模式需手动安装插件: /plugin marketplace add hellowind777/helloagents',
|
|
256
|
+
noteEN: 'Claude Code global mode still needs a manual plugin install: /plugin marketplace add hellowind777/helloagents',
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
if (host === 'gemini') {
|
|
260
|
+
uninstallGeminiStandby(HOME);
|
|
261
|
+
return {
|
|
262
|
+
noteCN: 'Gemini CLI 的 global 模式需手动安装扩展: gemini extensions install https://github.com/hellowind777/helloagents',
|
|
263
|
+
noteEN: 'Gemini CLI global mode still needs a manual extension install: gemini extensions install https://github.com/hellowind777/helloagents',
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
uninstallCodexStandby(HOME);
|
|
267
|
+
if (!installCodexGlobal(HOME, PKG_ROOT)) return { skipped: true };
|
|
268
|
+
return {};
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
function cleanupHostStandby(host) {
|
|
272
|
+
if (host === 'claude') return { skipped: !uninstallClaudeStandby(HOME) };
|
|
273
|
+
if (host === 'gemini') return { skipped: !uninstallGeminiStandby(HOME) };
|
|
274
|
+
const standbyCleaned = uninstallCodexStandby(HOME);
|
|
275
|
+
const globalResidueCleaned = uninstallCodexGlobal(HOME);
|
|
276
|
+
return { skipped: !(standbyCleaned || globalResidueCleaned) };
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
function cleanupHostGlobal(host) {
|
|
280
|
+
if (host === 'claude') {
|
|
281
|
+
uninstallClaudeStandby(HOME);
|
|
282
|
+
return {
|
|
283
|
+
noteCN: '如已安装 Claude Code 插件,请手动执行: /plugin remove helloagents',
|
|
284
|
+
noteEN: 'If the Claude Code plugin is installed, remove it manually: /plugin remove helloagents',
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
if (host === 'gemini') {
|
|
288
|
+
uninstallGeminiStandby(HOME);
|
|
289
|
+
return {
|
|
290
|
+
noteCN: '如已安装 Gemini CLI 扩展,请手动执行: gemini extensions uninstall helloagents',
|
|
291
|
+
noteEN: 'If the Gemini CLI extension is installed, remove it manually: gemini extensions uninstall helloagents',
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
return { skipped: !uninstallCodexGlobal(HOME) };
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
function runHostInstall(host, mode) {
|
|
298
|
+
return mode === 'global' ? installHostGlobal(host) : installHostStandby(host);
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
function runHostCleanup(host, mode) {
|
|
302
|
+
return mode === 'global' ? cleanupHostGlobal(host) : cleanupHostStandby(host);
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
function installStandby() {
|
|
306
|
+
uninstallCodexGlobal(HOME);
|
|
307
|
+
if (installClaudeStandby(HOME, PKG_ROOT)) ok(msg('Claude Code 已配置(standby 模式)', 'Claude Code configured (standby mode)'));
|
|
308
|
+
if (installGeminiStandby(HOME, PKG_ROOT)) ok(msg('Gemini CLI 已配置(standby 模式)', 'Gemini CLI configured (standby mode)'));
|
|
309
|
+
if (installCodexStandby(HOME, PKG_ROOT)) ok(msg('Codex CLI 已配置(standby 模式)', 'Codex CLI configured (standby mode)'));
|
|
310
|
+
else console.log(msg(' - Codex CLI 未检测到,跳过', ' - Codex CLI not detected, skipped'));
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
function installGlobal() {
|
|
314
|
+
uninstallClaudeStandby(HOME);
|
|
315
|
+
uninstallGeminiStandby(HOME);
|
|
316
|
+
uninstallCodexStandby(HOME);
|
|
317
|
+
if (installCodexGlobal(HOME, PKG_ROOT)) ok(msg('Codex CLI 已安装原生本地插件(global 模式)', 'Codex CLI native local plugin installed (global mode)'));
|
|
318
|
+
else console.log(msg(' - Codex CLI 未检测到,跳过', ' - Codex CLI not detected, skipped'));
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
function uninstallAll() {
|
|
322
|
+
uninstallClaudeStandby(HOME);
|
|
323
|
+
uninstallGeminiStandby(HOME);
|
|
324
|
+
uninstallCodexStandby(HOME);
|
|
325
|
+
uninstallCodexGlobal(HOME);
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
function syncVersion() {
|
|
329
|
+
const ver = pkg.version;
|
|
330
|
+
const targets = [
|
|
331
|
+
join(PKG_ROOT, '.claude-plugin', 'plugin.json'),
|
|
332
|
+
join(PKG_ROOT, '.codex-plugin', 'plugin.json'),
|
|
333
|
+
join(PKG_ROOT, 'gemini-extension.json'),
|
|
334
|
+
];
|
|
335
|
+
for (const path of targets) {
|
|
336
|
+
const obj = safeJson(path);
|
|
337
|
+
if (obj) {
|
|
338
|
+
obj.version = ver;
|
|
339
|
+
safeWrite(path, JSON.stringify(obj, null, 2) + '\n');
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
const marketPath = join(PKG_ROOT, '.claude-plugin', 'marketplace.json');
|
|
343
|
+
const market = safeJson(marketPath);
|
|
344
|
+
if (market?.plugins?.[0]) {
|
|
345
|
+
market.plugins[0].version = ver;
|
|
346
|
+
safeWrite(marketPath, JSON.stringify(market, null, 2) + '\n');
|
|
347
|
+
}
|
|
348
|
+
ok(`Version synced to ${ver}`);
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
function switchMode(newMode) {
|
|
352
|
+
const config = readSettings(true);
|
|
353
|
+
const oldMode = config.install_mode || DEFAULTS.install_mode;
|
|
354
|
+
|
|
355
|
+
const isRefresh = oldMode === newMode;
|
|
356
|
+
if (!isRefresh) {
|
|
357
|
+
config.install_mode = newMode;
|
|
358
|
+
ok(msg(`模式已切换为: ${newMode}`, `Mode switched to: ${newMode}`));
|
|
359
|
+
} else {
|
|
360
|
+
ok(msg(`当前已是 ${newMode} 模式,正在刷新安装`, `Already in ${newMode} mode, refreshing installation`));
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
if (newMode === 'global') installGlobal();
|
|
364
|
+
else installStandby();
|
|
365
|
+
setAllTrackedHostModes(config, newMode);
|
|
366
|
+
writeSettings(config);
|
|
367
|
+
printInstallMsg(newMode, isRefresh ? 'refresh' : 'switch');
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
function runScopedLifecycle(action, rawArgs) {
|
|
371
|
+
const { host, explicitMode } = parseLifecycleArgs(rawArgs);
|
|
372
|
+
|
|
373
|
+
if (host === 'all') {
|
|
374
|
+
if (action === 'cleanup' || action === 'uninstall') {
|
|
375
|
+
console.log(`\n HelloAGENTS — ${msg('正在清理', 'Cleaning up')}\n`);
|
|
376
|
+
uninstallAll();
|
|
377
|
+
if (existsSync(CONFIG_FILE)) {
|
|
378
|
+
const settings = readSettings();
|
|
379
|
+
clearAllTrackedHostModes(settings);
|
|
380
|
+
writeSettings(settings);
|
|
381
|
+
}
|
|
382
|
+
ok(msg('所有 CLI 配置已清理', 'All CLI configurations cleaned'));
|
|
383
|
+
console.log(msg(
|
|
384
|
+
' ℹ ~/.helloagents/ 已保留(如需彻底清理请手动删除)\n ℹ 如已安装 Claude Code 插件,请手动执行: /plugin remove helloagents\n ℹ 如已安装 Gemini CLI 扩展,请手动执行: gemini extensions uninstall helloagents',
|
|
385
|
+
' ℹ ~/.helloagents/ preserved (delete manually if desired)\n ℹ If Claude Code plugin installed, run: /plugin remove helloagents\n ℹ If Gemini CLI extension installed, run: gemini extensions uninstall helloagents',
|
|
386
|
+
));
|
|
387
|
+
console.log();
|
|
388
|
+
return;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
const settings = readSettings(true);
|
|
392
|
+
const mode = resolveInstallMode(explicitMode, settings);
|
|
393
|
+
if (explicitMode) settings.install_mode = explicitMode;
|
|
394
|
+
if (mode === 'global') installGlobal();
|
|
395
|
+
else installStandby();
|
|
396
|
+
setAllTrackedHostModes(settings, mode);
|
|
397
|
+
writeSettings(settings);
|
|
398
|
+
printInstallMsg(mode, action === 'update' ? 'refresh' : 'install');
|
|
399
|
+
return;
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
const shouldEnsure = action === 'install' || action === 'update';
|
|
403
|
+
const settings = readSettings(shouldEnsure);
|
|
404
|
+
const mode = resolveHostMode(host, explicitMode, settings);
|
|
405
|
+
const result = (action === 'cleanup' || action === 'uninstall')
|
|
406
|
+
? runHostCleanup(host, mode)
|
|
407
|
+
: runHostInstall(host, mode);
|
|
408
|
+
|
|
409
|
+
if (action === 'cleanup' || action === 'uninstall') {
|
|
410
|
+
if (existsSync(CONFIG_FILE)) {
|
|
411
|
+
clearTrackedHostMode(settings, host);
|
|
412
|
+
writeSettings(settings);
|
|
413
|
+
}
|
|
414
|
+
} else {
|
|
415
|
+
if (!result.skipped) {
|
|
416
|
+
setTrackedHostMode(settings, host, mode);
|
|
417
|
+
writeSettings(settings);
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
reportHostAction(action, host, mode, result);
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
const argv = process.argv.slice(2);
|
|
425
|
+
const cmd = argv[0] || '';
|
|
426
|
+
|
|
427
|
+
if (cmd === 'postinstall') {
|
|
428
|
+
console.log(`\n HelloAGENTS v${pkg.version}\n`);
|
|
429
|
+
ensureConfig(HELLOAGENTS_HOME, CONFIG_FILE, safeJson, ensureDir);
|
|
430
|
+
ok('~/.helloagents/helloagents.json');
|
|
431
|
+
|
|
432
|
+
const settings = readSettings();
|
|
433
|
+
const mode = settings.install_mode || DEFAULTS.install_mode;
|
|
434
|
+
console.log(msg(
|
|
435
|
+
` HelloAGENTS 包已安装,尚未自动部署到任何 CLI。\n 使用显式命令部署:\n helloagents install codex --${mode}\n helloagents install --all --${mode}\n`,
|
|
436
|
+
` HelloAGENTS package installed. No CLI targets were configured automatically.\n Deploy explicitly with:\n helloagents install codex --${mode}\n helloagents install --all --${mode}\n`,
|
|
437
|
+
));
|
|
438
|
+
} else if (cmd === 'preuninstall') {
|
|
439
|
+
runScopedLifecycle('cleanup', []);
|
|
440
|
+
} else if (cmd === 'sync-version') {
|
|
441
|
+
syncVersion();
|
|
442
|
+
} else if (cmd === '--global' || cmd === '--standby') {
|
|
443
|
+
switchMode(cmd === '--global' ? 'global' : 'standby');
|
|
444
|
+
} else if (['install', 'update', 'uninstall', 'cleanup', '--cleanup'].includes(cmd)) {
|
|
445
|
+
try {
|
|
446
|
+
runScopedLifecycle(cmd === '--cleanup' ? 'cleanup' : cmd, argv.slice(1));
|
|
447
|
+
} catch (error) {
|
|
448
|
+
console.error(`\n ✗ ${error.message}\n`);
|
|
449
|
+
process.exitCode = 1;
|
|
450
|
+
}
|
|
451
|
+
} else {
|
|
452
|
+
printHelp();
|
|
453
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
{
|
|
2
|
+
"hooks": {
|
|
3
|
+
"SessionStart": [
|
|
4
|
+
{
|
|
5
|
+
"matcher": "",
|
|
6
|
+
"hooks": [
|
|
7
|
+
{
|
|
8
|
+
"type": "command",
|
|
9
|
+
"command": "node \"${CLAUDE_PLUGIN_ROOT}/scripts/notify.mjs\" inject --claude",
|
|
10
|
+
"timeout": 10
|
|
11
|
+
}
|
|
12
|
+
]
|
|
13
|
+
}
|
|
14
|
+
],
|
|
15
|
+
"UserPromptSubmit": [
|
|
16
|
+
{
|
|
17
|
+
"matcher": "",
|
|
18
|
+
"hooks": [
|
|
19
|
+
{
|
|
20
|
+
"type": "command",
|
|
21
|
+
"command": "node \"${CLAUDE_PLUGIN_ROOT}/scripts/notify.mjs\" route --claude",
|
|
22
|
+
"timeout": 5
|
|
23
|
+
}
|
|
24
|
+
]
|
|
25
|
+
}
|
|
26
|
+
],
|
|
27
|
+
"PreToolUse": [
|
|
28
|
+
{
|
|
29
|
+
"matcher": "Bash",
|
|
30
|
+
"hooks": [
|
|
31
|
+
{
|
|
32
|
+
"type": "command",
|
|
33
|
+
"command": "node \"${CLAUDE_PLUGIN_ROOT}/scripts/guard.mjs\"",
|
|
34
|
+
"timeout": 5
|
|
35
|
+
}
|
|
36
|
+
]
|
|
37
|
+
}
|
|
38
|
+
],
|
|
39
|
+
"PostToolUse": [
|
|
40
|
+
{
|
|
41
|
+
"matcher": "Write|Edit|NotebookEdit",
|
|
42
|
+
"hooks": [
|
|
43
|
+
{
|
|
44
|
+
"type": "command",
|
|
45
|
+
"command": "node \"${CLAUDE_PLUGIN_ROOT}/scripts/guard.mjs\" post-write",
|
|
46
|
+
"timeout": 5
|
|
47
|
+
}
|
|
48
|
+
]
|
|
49
|
+
}
|
|
50
|
+
],
|
|
51
|
+
"PreCompact": [
|
|
52
|
+
{
|
|
53
|
+
"matcher": "",
|
|
54
|
+
"hooks": [
|
|
55
|
+
{
|
|
56
|
+
"type": "command",
|
|
57
|
+
"command": "node \"${CLAUDE_PLUGIN_ROOT}/scripts/notify.mjs\" pre-compact --claude",
|
|
58
|
+
"timeout": 10
|
|
59
|
+
}
|
|
60
|
+
]
|
|
61
|
+
}
|
|
62
|
+
],
|
|
63
|
+
"SubagentStop": [
|
|
64
|
+
{
|
|
65
|
+
"matcher": "",
|
|
66
|
+
"hooks": [
|
|
67
|
+
{
|
|
68
|
+
"type": "command",
|
|
69
|
+
"command": "node \"${CLAUDE_PLUGIN_ROOT}/scripts/ralph-loop.mjs\" subagent",
|
|
70
|
+
"timeout": 120
|
|
71
|
+
}
|
|
72
|
+
]
|
|
73
|
+
}
|
|
74
|
+
],
|
|
75
|
+
"Stop": [
|
|
76
|
+
{
|
|
77
|
+
"matcher": "",
|
|
78
|
+
"hooks": [
|
|
79
|
+
{
|
|
80
|
+
"type": "command",
|
|
81
|
+
"command": "node \"${CLAUDE_PLUGIN_ROOT}/scripts/notify.mjs\" stop --claude",
|
|
82
|
+
"timeout": 120
|
|
83
|
+
}
|
|
84
|
+
]
|
|
85
|
+
}
|
|
86
|
+
]
|
|
87
|
+
}
|
|
88
|
+
}
|
package/hooks/hooks.json
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
{
|
|
2
|
+
"hooks": {
|
|
3
|
+
"SessionStart": [
|
|
4
|
+
{
|
|
5
|
+
"matcher": "",
|
|
6
|
+
"hooks": [
|
|
7
|
+
{
|
|
8
|
+
"type": "command",
|
|
9
|
+
"command": "node \"${extensionPath}/scripts/notify.mjs\" inject --gemini",
|
|
10
|
+
"timeout": 10000
|
|
11
|
+
}
|
|
12
|
+
]
|
|
13
|
+
}
|
|
14
|
+
],
|
|
15
|
+
"BeforeAgent": [
|
|
16
|
+
{
|
|
17
|
+
"matcher": "",
|
|
18
|
+
"hooks": [
|
|
19
|
+
{
|
|
20
|
+
"type": "command",
|
|
21
|
+
"command": "node \"${extensionPath}/scripts/notify.mjs\" route --gemini",
|
|
22
|
+
"timeout": 5000
|
|
23
|
+
}
|
|
24
|
+
]
|
|
25
|
+
}
|
|
26
|
+
],
|
|
27
|
+
"BeforeTool": [
|
|
28
|
+
{
|
|
29
|
+
"matcher": "shell|bash",
|
|
30
|
+
"hooks": [
|
|
31
|
+
{
|
|
32
|
+
"type": "command",
|
|
33
|
+
"command": "node \"${extensionPath}/scripts/guard.mjs\" --gemini",
|
|
34
|
+
"timeout": 5000
|
|
35
|
+
}
|
|
36
|
+
]
|
|
37
|
+
}
|
|
38
|
+
],
|
|
39
|
+
"AfterModel": [
|
|
40
|
+
{
|
|
41
|
+
"matcher": "write_file|edit_file",
|
|
42
|
+
"hooks": [
|
|
43
|
+
{
|
|
44
|
+
"type": "command",
|
|
45
|
+
"command": "node \"${extensionPath}/scripts/guard.mjs\" post-write --gemini",
|
|
46
|
+
"timeout": 5000
|
|
47
|
+
}
|
|
48
|
+
]
|
|
49
|
+
}
|
|
50
|
+
],
|
|
51
|
+
"AfterAgent": [
|
|
52
|
+
{
|
|
53
|
+
"matcher": "",
|
|
54
|
+
"hooks": [
|
|
55
|
+
{
|
|
56
|
+
"type": "command",
|
|
57
|
+
"command": "node \"${extensionPath}/scripts/ralph-loop.mjs\" subagent --gemini",
|
|
58
|
+
"timeout": 120000
|
|
59
|
+
}
|
|
60
|
+
]
|
|
61
|
+
}
|
|
62
|
+
],
|
|
63
|
+
"SessionEnd": [
|
|
64
|
+
{
|
|
65
|
+
"matcher": "",
|
|
66
|
+
"hooks": [
|
|
67
|
+
{
|
|
68
|
+
"type": "command",
|
|
69
|
+
"command": "node \"${extensionPath}/scripts/notify.mjs\" stop --gemini",
|
|
70
|
+
"timeout": 120000
|
|
71
|
+
}
|
|
72
|
+
]
|
|
73
|
+
}
|
|
74
|
+
]
|
|
75
|
+
}
|
|
76
|
+
}
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "helloagents",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "3.0.2-beta.1",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"description": "HelloAGENTS
|
|
5
|
+
"description": "HelloAGENTS — The orchestration kernel that makes any AI CLI smarter. Adds intelligent routing, quality verification (Ralph Loop), safety guards, and notifications.",
|
|
6
6
|
"author": "HelloWind",
|
|
7
7
|
"license": "Apache-2.0",
|
|
8
8
|
"homepage": "https://github.com/hellowind777/helloagents",
|
|
@@ -11,13 +11,43 @@
|
|
|
11
11
|
"url": "git+https://github.com/hellowind777/helloagents.git"
|
|
12
12
|
},
|
|
13
13
|
"bin": {
|
|
14
|
-
"helloagents": "
|
|
14
|
+
"helloagents": "cli.mjs",
|
|
15
|
+
"helloagents-js": "cli.mjs"
|
|
16
|
+
},
|
|
17
|
+
"scripts": {
|
|
18
|
+
"test": "node --test",
|
|
19
|
+
"postinstall": "node cli.mjs postinstall",
|
|
20
|
+
"preuninstall": "node cli.mjs preuninstall",
|
|
21
|
+
"uninstall": "node cli.mjs preuninstall",
|
|
22
|
+
"postuninstall": "node cli.mjs preuninstall",
|
|
23
|
+
"prepublishOnly": "node cli.mjs sync-version"
|
|
15
24
|
},
|
|
16
25
|
"files": [
|
|
17
|
-
"
|
|
26
|
+
"cli.mjs",
|
|
27
|
+
"scripts/",
|
|
28
|
+
"hooks/",
|
|
29
|
+
"skills/",
|
|
30
|
+
"templates/",
|
|
31
|
+
"assets/",
|
|
32
|
+
"bootstrap.md",
|
|
33
|
+
"bootstrap-lite.md",
|
|
34
|
+
"README_CN.md",
|
|
35
|
+
"gemini-extension.json",
|
|
36
|
+
".claude-plugin/",
|
|
37
|
+
".codex-plugin/"
|
|
38
|
+
],
|
|
39
|
+
"keywords": [
|
|
40
|
+
"ai",
|
|
41
|
+
"agent",
|
|
42
|
+
"claude",
|
|
43
|
+
"codex",
|
|
44
|
+
"cli",
|
|
45
|
+
"orchestration",
|
|
46
|
+
"subagent",
|
|
47
|
+
"hooks",
|
|
48
|
+
"skills"
|
|
18
49
|
],
|
|
19
|
-
"keywords": ["ai", "agent", "claude", "codex", "gemini", "qwen", "grok", "opencode", "cli", "workflow"],
|
|
20
50
|
"engines": {
|
|
21
|
-
"node": ">=
|
|
51
|
+
"node": ">=18"
|
|
22
52
|
}
|
|
23
53
|
}
|