everything-gemini 1.2.0 → 1.8.0
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/.github/ISSUE_TEMPLATE/bug_report.md +29 -0
- package/.github/ISSUE_TEMPLATE/feature_request.md +27 -0
- package/.github/ISSUE_TEMPLATE/subagent_proposal.md +29 -0
- package/.github/workflows/ci.yml +72 -1
- package/.github/workflows/release.yml +17 -2
- package/CHANGELOG.md +155 -0
- package/CONTRIBUTING.md +85 -4
- package/README.md +134 -19
- package/action.yml +35 -0
- package/agents/browser-qa.md +1 -1
- package/agents/database-migrator.md +26 -0
- package/agents/documentation-writer.md +27 -0
- package/agents/incident-responder.md +34 -0
- package/agents/performance-tuner.md +27 -0
- package/agents/release-engineer.md +34 -0
- package/bin/everything-gemini +1517 -122
- package/docs/COMMUNITY_SUBMISSIONS.md +88 -0
- package/docs/LAUNCH_KIT.md +138 -13
- package/docs/architecture/progressive-disclosure.md +3 -3
- package/docs/index.html +401 -40
- package/docs/launch-kit.md +163 -0
- package/examples/cli-workflows/demo_workflow.sh +15 -7
- package/examples/python-sdk/README.md +28 -5
- package/examples/python-sdk/documentation_audit_pipeline.py +83 -0
- package/examples/python-sdk/incident_triage_pipeline.py +170 -0
- package/examples/python-sdk/multi_agent_pipeline.py +95 -0
- package/examples/python-sdk/release_readiness_audit.py +144 -0
- package/hooks/secret-scrubber/hooks.json +16 -0
- package/hooks/secret-scrubber/scripts/scrub-secrets.sh +62 -0
- package/mcp/README.md +20 -0
- package/mcp/mcp_config.example.json +35 -0
- package/package.json +3 -1
- package/plugins/core/rules/core-practices.md +63 -4
- package/plugins/python-ai/rules/ai-agent-patterns.md +67 -4
- package/plugins/security-shield/rules/zero-trust.md +60 -4
- package/plugins/web-fullstack/rules/frontend-standards.md +74 -4
- package/rules/paradigms/security-hardened.md +53 -10
- package/rules/paradigms/tdd.md +65 -8
- package/scripts/install.ps1 +14 -0
- package/scripts/install.sh +15 -1
- package/scripts/validate.sh +103 -12
- package/skills/apache-kafka-streams/SKILL.md +152 -0
- package/skills/argo-workflows/SKILL.md +151 -0
- package/skills/axum-web-service/SKILL.md +159 -0
- package/skills/cilium-ebpf-networking/SKILL.md +145 -0
- package/skills/clickhouse-analytics/SKILL.md +128 -0
- package/skills/dbt-transformation/SKILL.md +179 -0
- package/skills/debezium-cdc/SKILL.md +166 -0
- package/skills/duckdb-local-olap/SKILL.md +134 -0
- package/skills/fastapi-production/SKILL.md +157 -0
- package/skills/grpc-connect-rpc/SKILL.md +176 -0
- package/skills/langgraph-orchestrator/SKILL.md +144 -0
- package/skills/litellm-proxy-gateway/SKILL.md +154 -0
- package/skills/nats-jetstream/SKILL.md +122 -0
- package/skills/open-telemetry-tracing/SKILL.md +151 -0
- package/skills/playwright-visual-regression/SKILL.md +124 -0
- package/skills/redis-cache-patterns/SKILL.md +159 -0
- package/skills/svelte-kit-architect/SKILL.md +190 -0
- package/skills/temporal-workflows/SKILL.md +158 -0
- package/skills/trpc-react-query/SKILL.md +169 -0
- package/skills/turborepo-monorepo/SKILL.md +199 -0
- package/skills/vllm-inference/SKILL.md +144 -0
- package/skills/wasm-rust-optimizer/SKILL.md +130 -0
- package/templates/full-power/hooks.json +14 -0
- package/templates/full-power/mcp_config.json +43 -0
- package/templates/recommended/hooks.json +14 -0
- package/tests/cli.test.js +383 -0
package/bin/everything-gemini
CHANGED
|
@@ -45,20 +45,33 @@ function printHelp() {
|
|
|
45
45
|
console.log(` ${GREEN}doctor${RESET} Inspect system, AGY surfaces, and configuration health`);
|
|
46
46
|
console.log(` ${GREEN}install${RESET} [options] Install everything-gemini profiles into workspace or globally`);
|
|
47
47
|
console.log(` ${GREEN}init${RESET} [options] Initialize everything-gemini in current workspace`);
|
|
48
|
+
console.log(` ${GREEN}status, check${RESET} Show active skills, subagents, and hooks in workspace`);
|
|
49
|
+
console.log(` ${GREEN}diff${RESET} Compare installed workspace components against master catalog`);
|
|
50
|
+
console.log(` ${GREEN}export${RESET} [options] Export installed configuration into a portable bundle`);
|
|
51
|
+
console.log(` ${GREEN}import${RESET} <file.json> Import portable agent configuration bundle into workspace`);
|
|
52
|
+
console.log(` ${GREEN}bundle, pack${RESET} [options] Package offline distribution bundle with manifest & installer`);
|
|
53
|
+
console.log(` ${GREEN}update${RESET} Sync installed skills, agents, and hooks with latest catalog`);
|
|
48
54
|
console.log(` ${GREEN}list${RESET} Show all available skills, rules, hooks, and plugins`);
|
|
49
55
|
console.log(` ${GREEN}new-skill${RESET} <name> Scaffold a new progressive-disclosure skill`);
|
|
50
56
|
console.log(` ${GREEN}new-agent${RESET} <name> Scaffold a new scoped subagent specification`);
|
|
51
|
-
console.log(` ${GREEN}add${RESET} <type> <name> Add a specific skill, agent, or plugin to workspace`);
|
|
52
|
-
console.log(` ${GREEN}remove${RESET} <type> <name> Remove a specific skill, agent, or plugin from workspace`);
|
|
57
|
+
console.log(` ${GREEN}add${RESET} <type> <name> Add a specific skill, agent, hook, or plugin to workspace`);
|
|
58
|
+
console.log(` ${GREEN}remove${RESET} <type> <name> Remove a specific skill, agent, hook, or plugin from workspace`);
|
|
59
|
+
console.log(` ${GREEN}search, find${RESET} <query> Search skills, agents, hooks, and MCP blueprints`);
|
|
60
|
+
console.log(` ${GREEN}audit${RESET} [path] Comprehensive audit of frontmatter, contracts, hooks & links`);
|
|
53
61
|
console.log(` ${GREEN}test-skill${RESET} <name> Validate a specific skill frontmatter & scripts`);
|
|
54
|
-
console.log(` ${GREEN}
|
|
62
|
+
console.log(` ${GREEN}test-all${RESET} Benchmark & validate all 52 skills, 11 subagents & 7 hooks`);
|
|
63
|
+
console.log(` ${GREEN}info${RESET} <name> Display overview & runbook for a skill, agent, or hook`);
|
|
64
|
+
console.log(` ${GREEN}completion${RESET} [--install] Generate or install shell autocompletion script (bash/zsh)`);
|
|
55
65
|
console.log(` ${GREEN}validate${RESET} Run self-test on frontmatter, JSON schemas & hooks`);
|
|
56
|
-
console.log(` ${GREEN}
|
|
57
|
-
console.log(
|
|
66
|
+
console.log(` ${GREEN}version, -v, --version${RESET} Print everything-gemini version`);
|
|
67
|
+
console.log(` ${GREEN}help, -h, --help${RESET} Show this help message\n`);
|
|
68
|
+
console.log(`${BOLD}GLOBAL & COMMAND OPTIONS:${RESET}`);
|
|
58
69
|
console.log(` ${CYAN}--profile <core|developer|full>${RESET} Installation preset profile (default: developer)`);
|
|
59
|
-
console.log(` ${CYAN}--global${RESET}
|
|
60
|
-
console.log(` ${CYAN}--workspace <path>${RESET}
|
|
61
|
-
console.log(` ${CYAN}--
|
|
70
|
+
console.log(` ${CYAN}--global${RESET} Target global config (~/.gemini/config/)`);
|
|
71
|
+
console.log(` ${CYAN}--workspace <path>${RESET} Target custom workspace directory`);
|
|
72
|
+
console.log(` ${CYAN}--dry-run${RESET} Preview actions without modifying files on disk`);
|
|
73
|
+
console.log(` ${CYAN}--json${RESET} Output machine-readable JSON (status, benchmark)`);
|
|
74
|
+
console.log(` ${CYAN}--force${RESET} Overwrite existing configuration files\n`);
|
|
62
75
|
}
|
|
63
76
|
|
|
64
77
|
function runDoctor() {
|
|
@@ -190,13 +203,29 @@ function listComponents() {
|
|
|
190
203
|
if (item.isDirectory()) {
|
|
191
204
|
findRules(path.join(dir, item.name), `${prefix}${item.name}/`);
|
|
192
205
|
} else if (item.name.endsWith('.md')) {
|
|
193
|
-
console.log(` ${BOLD}${(prefix + item.name).padEnd(
|
|
206
|
+
console.log(` ${BOLD}${(prefix + item.name).padEnd(36)}${RESET}`);
|
|
194
207
|
}
|
|
195
208
|
}
|
|
196
209
|
}
|
|
197
210
|
findRules(rulesDir);
|
|
198
211
|
}
|
|
199
212
|
|
|
213
|
+
// Plugin Packaged Rules
|
|
214
|
+
if (fs.existsSync(pluginsDirForSkills)) {
|
|
215
|
+
const plugins = fs.readdirSync(pluginsDirForSkills, { withFileTypes: true })
|
|
216
|
+
.filter(d => d.isDirectory())
|
|
217
|
+
.map(d => d.name);
|
|
218
|
+
for (const plugin of plugins) {
|
|
219
|
+
const pRulesDir = path.join(pluginsDirForSkills, plugin, 'rules');
|
|
220
|
+
if (fs.existsSync(pRulesDir)) {
|
|
221
|
+
const pRules = fs.readdirSync(pRulesDir).filter(f => f.endsWith('.md'));
|
|
222
|
+
for (const r of pRules) {
|
|
223
|
+
console.log(` ${BOLD}${(`plugins/${plugin}/rules/${r}`).padEnd(36)}${RESET}`);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
200
229
|
// Hooks
|
|
201
230
|
console.log(`\n${CYAN}${BOLD}🛡️ Lifecycle Hooks:${RESET}`);
|
|
202
231
|
const hooksDir = path.join(REPO_ROOT, 'hooks');
|
|
@@ -243,19 +272,26 @@ function copyRecursiveSync(src, dest) {
|
|
|
243
272
|
} else {
|
|
244
273
|
fs.mkdirSync(path.dirname(dest), { recursive: true });
|
|
245
274
|
fs.copyFileSync(src, dest);
|
|
275
|
+
if (src.endsWith('.sh') || (stats.mode && (stats.mode & 0o111))) {
|
|
276
|
+
try { fs.chmodSync(dest, 0o755); } catch (e) {}
|
|
277
|
+
}
|
|
246
278
|
}
|
|
247
279
|
}
|
|
248
280
|
|
|
249
|
-
function installProfile(profile = 'developer', isGlobal = false, customTarget = null) {
|
|
281
|
+
function installProfile(profile = 'developer', isGlobal = false, customTarget = null, isDryRun = false) {
|
|
250
282
|
printBanner();
|
|
251
283
|
const targetDir = customTarget
|
|
252
284
|
? path.resolve(customTarget)
|
|
253
285
|
: (isGlobal ? GLOBAL_CONFIG_DIR : AGENTS_DIR);
|
|
254
286
|
|
|
287
|
+
if (isDryRun) {
|
|
288
|
+
console.log(`${YELLOW}${BOLD}🔍 DRY RUN MODE ACTIVATED - No files will be modified on disk.${RESET}`);
|
|
289
|
+
}
|
|
290
|
+
|
|
255
291
|
console.log(`${BOLD}🚀 Installing everything-gemini Profile: [${GREEN}${profile}${RESET}${BOLD}]${RESET}`);
|
|
256
292
|
console.log(`Target Directory: ${CYAN}${targetDir}${RESET}\n`);
|
|
257
293
|
|
|
258
|
-
if (!fs.existsSync(targetDir)) {
|
|
294
|
+
if (!isDryRun && !fs.existsSync(targetDir)) {
|
|
259
295
|
fs.mkdirSync(targetDir, { recursive: true });
|
|
260
296
|
}
|
|
261
297
|
|
|
@@ -263,69 +299,103 @@ function installProfile(profile = 'developer', isGlobal = false, customTarget =
|
|
|
263
299
|
const targetSkills = path.join(targetDir, 'skills');
|
|
264
300
|
const targetRules = path.join(targetDir, 'rules');
|
|
265
301
|
const targetPlugins = path.join(targetDir, 'plugins');
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
302
|
+
const targetAgents = path.join(targetDir, 'agents');
|
|
303
|
+
if (!isDryRun) {
|
|
304
|
+
fs.mkdirSync(targetSkills, { recursive: true });
|
|
305
|
+
fs.mkdirSync(targetRules, { recursive: true });
|
|
306
|
+
fs.mkdirSync(targetPlugins, { recursive: true });
|
|
307
|
+
}
|
|
269
308
|
|
|
270
309
|
const skillsSrc = path.join(REPO_ROOT, 'skills');
|
|
271
310
|
const rulesSrc = path.join(REPO_ROOT, 'rules');
|
|
272
311
|
const hooksSrc = path.join(REPO_ROOT, 'hooks');
|
|
273
312
|
const pluginsSrc = path.join(REPO_ROOT, 'plugins');
|
|
313
|
+
const agentsSrc = path.join(REPO_ROOT, 'agents');
|
|
274
314
|
|
|
275
315
|
// Copy Common Base Rules
|
|
276
316
|
const commonGemini = path.join(rulesSrc, 'common', 'GEMINI.md');
|
|
277
317
|
const commonAgents = path.join(rulesSrc, 'common', 'AGENTS.md');
|
|
278
318
|
if (fs.existsSync(commonGemini)) {
|
|
279
|
-
fs.copyFileSync(commonGemini, path.join(targetDir, 'GEMINI.md'));
|
|
280
|
-
console.log(` ${GREEN}✔${RESET} Installed base GEMINI.md`);
|
|
319
|
+
if (!isDryRun) fs.copyFileSync(commonGemini, path.join(targetDir, 'GEMINI.md'));
|
|
320
|
+
console.log(` ${GREEN}✔${RESET} ${isDryRun ? '[DRY RUN] Would install' : 'Installed'} base GEMINI.md`);
|
|
281
321
|
}
|
|
282
322
|
if (fs.existsSync(commonAgents)) {
|
|
283
|
-
fs.copyFileSync(commonAgents, path.join(targetDir, 'AGENTS.md'));
|
|
284
|
-
console.log(` ${GREEN}✔${RESET} Installed base AGENTS.md`);
|
|
323
|
+
if (!isDryRun) fs.copyFileSync(commonAgents, path.join(targetDir, 'AGENTS.md'));
|
|
324
|
+
console.log(` ${GREEN}✔${RESET} ${isDryRun ? '[DRY RUN] Would install' : 'Installed'} base AGENTS.md`);
|
|
285
325
|
}
|
|
286
326
|
|
|
287
|
-
//
|
|
327
|
+
// 1. Core Profile
|
|
288
328
|
if (profile === 'core' || profile === 'developer' || profile === 'full') {
|
|
289
|
-
// Core Skills
|
|
290
329
|
const coreSkills = ['tdd-workflow', 'repo-onboarding'];
|
|
291
330
|
for (const s of coreSkills) {
|
|
292
331
|
const src = path.join(skillsSrc, s);
|
|
293
332
|
if (fs.existsSync(src)) {
|
|
294
|
-
copyRecursiveSync(src, path.join(targetSkills, s));
|
|
295
|
-
console.log(` ${GREEN}✔${RESET} Installed skill: ${s}`);
|
|
333
|
+
if (!isDryRun) copyRecursiveSync(src, path.join(targetSkills, s));
|
|
334
|
+
console.log(` ${GREEN}✔${RESET} ${isDryRun ? '[DRY RUN] Would install' : 'Installed'} skill: ${s}`);
|
|
296
335
|
}
|
|
297
336
|
}
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
console.log(` ${GREEN}✔${RESET} Installed safety-shield hook`);
|
|
337
|
+
const safetyHook = path.join(hooksSrc, 'safety-shield');
|
|
338
|
+
if (fs.existsSync(safetyHook)) {
|
|
339
|
+
if (!isDryRun) copyRecursiveSync(safetyHook, path.join(targetDir, 'hooks', 'safety-shield'));
|
|
340
|
+
console.log(` ${GREEN}✔${RESET} ${isDryRun ? '[DRY RUN] Would install' : 'Installed'} safety-shield hook`);
|
|
303
341
|
}
|
|
304
342
|
}
|
|
305
343
|
|
|
344
|
+
// 2. Developer Profile
|
|
306
345
|
if (profile === 'developer' || profile === 'full') {
|
|
307
|
-
|
|
308
|
-
|
|
346
|
+
const devSkills = [
|
|
347
|
+
'browser-qa-tester',
|
|
348
|
+
'architecture-designer',
|
|
349
|
+
'git-craftsman',
|
|
350
|
+
'performance-profiler',
|
|
351
|
+
'fullstack-nextjs',
|
|
352
|
+
'gemini-multimodal',
|
|
353
|
+
'context-caching',
|
|
354
|
+
'subagent-handoff',
|
|
355
|
+
'security-audit',
|
|
356
|
+
'continuous-learning',
|
|
357
|
+
'ai-first-engineering'
|
|
358
|
+
];
|
|
309
359
|
for (const s of devSkills) {
|
|
310
360
|
const src = path.join(skillsSrc, s);
|
|
311
361
|
if (fs.existsSync(src)) {
|
|
312
|
-
copyRecursiveSync(src, path.join(targetSkills, s));
|
|
313
|
-
console.log(` ${GREEN}✔${RESET} Installed skill: ${s}`);
|
|
362
|
+
if (!isDryRun) copyRecursiveSync(src, path.join(targetSkills, s));
|
|
363
|
+
console.log(` ${GREEN}✔${RESET} ${isDryRun ? '[DRY RUN] Would install' : 'Installed'} skill: ${s}`);
|
|
314
364
|
}
|
|
315
365
|
}
|
|
316
366
|
|
|
317
367
|
// Developer Language Rules
|
|
318
368
|
const langRules = path.join(rulesSrc, 'languages');
|
|
319
369
|
if (fs.existsSync(langRules)) {
|
|
320
|
-
copyRecursiveSync(langRules, targetRules);
|
|
321
|
-
console.log(` ${GREEN}✔${RESET} Installed language rules (TypeScript, Python, Go)`);
|
|
370
|
+
if (!isDryRun) copyRecursiveSync(langRules, targetRules);
|
|
371
|
+
console.log(` ${GREEN}✔${RESET} ${isDryRun ? '[DRY RUN] Would install' : 'Installed'} language rules (TypeScript, Python, Go)`);
|
|
322
372
|
}
|
|
323
373
|
|
|
324
374
|
// Auto-lint formatter hook
|
|
325
375
|
const lintHook = path.join(hooksSrc, 'auto-lint-formatter');
|
|
326
376
|
if (fs.existsSync(lintHook)) {
|
|
327
|
-
copyRecursiveSync(lintHook, path.join(targetDir, 'hooks', 'auto-lint-formatter'));
|
|
328
|
-
console.log(` ${GREEN}✔${RESET} Installed auto-lint-formatter hook`);
|
|
377
|
+
if (!isDryRun) copyRecursiveSync(lintHook, path.join(targetDir, 'hooks', 'auto-lint-formatter'));
|
|
378
|
+
console.log(` ${GREEN}✔${RESET} ${isDryRun ? '[DRY RUN] Would install' : 'Installed'} auto-lint-formatter hook`);
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
// Goal-verifier hook
|
|
382
|
+
const goalHook = path.join(hooksSrc, 'goal-verifier');
|
|
383
|
+
if (fs.existsSync(goalHook)) {
|
|
384
|
+
if (!isDryRun) copyRecursiveSync(goalHook, path.join(targetDir, 'hooks', 'goal-verifier'));
|
|
385
|
+
console.log(` ${GREEN}✔${RESET} ${isDryRun ? '[DRY RUN] Would install' : 'Installed'} goal-verifier hook`);
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
// Secret-scrubber hook
|
|
389
|
+
const scrubberHook = path.join(hooksSrc, 'secret-scrubber');
|
|
390
|
+
if (fs.existsSync(scrubberHook)) {
|
|
391
|
+
if (!isDryRun) copyRecursiveSync(scrubberHook, path.join(targetDir, 'hooks', 'secret-scrubber'));
|
|
392
|
+
console.log(` ${GREEN}✔${RESET} ${isDryRun ? '[DRY RUN] Would install' : 'Installed'} secret-scrubber hook`);
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
// Scoped Subagents (agents/)
|
|
396
|
+
if (fs.existsSync(agentsSrc)) {
|
|
397
|
+
if (!isDryRun) copyRecursiveSync(agentsSrc, targetAgents);
|
|
398
|
+
console.log(` ${GREEN}✔${RESET} ${isDryRun ? '[DRY RUN] Would install' : 'Installed'} 9 scoped subagents (agents/)`);
|
|
329
399
|
}
|
|
330
400
|
|
|
331
401
|
// Developer Plugins
|
|
@@ -333,58 +403,652 @@ function installProfile(profile = 'developer', isGlobal = false, customTarget =
|
|
|
333
403
|
for (const p of devPlugins) {
|
|
334
404
|
const src = path.join(pluginsSrc, p);
|
|
335
405
|
if (fs.existsSync(src)) {
|
|
336
|
-
copyRecursiveSync(src, path.join(targetPlugins, p));
|
|
337
|
-
console.log(` ${GREEN}✔${RESET} Installed plugin: ${p}`);
|
|
406
|
+
if (!isDryRun) copyRecursiveSync(src, path.join(targetPlugins, p));
|
|
407
|
+
console.log(` ${GREEN}✔${RESET} ${isDryRun ? '[DRY RUN] Would install' : 'Installed'} plugin: ${p}`);
|
|
338
408
|
}
|
|
339
409
|
}
|
|
340
410
|
}
|
|
341
411
|
|
|
412
|
+
// 3. Full Power Profile
|
|
342
413
|
if (profile === 'full') {
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
414
|
+
if (!isDryRun) copyRecursiveSync(skillsSrc, targetSkills);
|
|
415
|
+
console.log(` ${GREEN}✔${RESET} ${isDryRun ? '[DRY RUN] Would install' : 'Installed'} entire skills library (48 progressive skills)`);
|
|
416
|
+
|
|
417
|
+
if (!isDryRun) copyRecursiveSync(rulesSrc, targetRules);
|
|
418
|
+
console.log(` ${GREEN}✔${RESET} ${isDryRun ? '[DRY RUN] Would install' : 'Installed'} entire rules library`);
|
|
346
419
|
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
console.log(` ${GREEN}✔${RESET} Installed entire rules library`);
|
|
420
|
+
if (!isDryRun) copyRecursiveSync(pluginsSrc, targetPlugins);
|
|
421
|
+
console.log(` ${GREEN}✔${RESET} ${isDryRun ? '[DRY RUN] Would install' : 'Installed'} all modular plugins`);
|
|
350
422
|
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
console.log(` ${GREEN}✔${RESET} Installed all modular plugins`);
|
|
423
|
+
if (!isDryRun) copyRecursiveSync(hooksSrc, path.join(targetDir, 'hooks'));
|
|
424
|
+
console.log(` ${GREEN}✔${RESET} ${isDryRun ? '[DRY RUN] Would install' : 'Installed'} full lifecycle hooks suite (7 hooks)`);
|
|
354
425
|
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
426
|
+
if (fs.existsSync(agentsSrc)) {
|
|
427
|
+
if (!isDryRun) copyRecursiveSync(agentsSrc, targetAgents);
|
|
428
|
+
console.log(` ${GREEN}✔${RESET} ${isDryRun ? '[DRY RUN] Would install' : 'Installed'} 10 scoped subagents (agents/)`);
|
|
429
|
+
}
|
|
358
430
|
|
|
359
431
|
// MCP Config Example
|
|
360
432
|
const mcpExample = path.join(REPO_ROOT, 'mcp', 'mcp_config.example.json');
|
|
361
433
|
if (fs.existsSync(mcpExample)) {
|
|
362
|
-
fs.copyFileSync(mcpExample, path.join(targetDir, 'mcp_config.json'));
|
|
363
|
-
console.log(` ${GREEN}✔${RESET} Installed mcp_config.json`);
|
|
364
|
-
}
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
//
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
434
|
+
if (!isDryRun) fs.copyFileSync(mcpExample, path.join(targetDir, 'mcp_config.json'));
|
|
435
|
+
console.log(` ${GREEN}✔${RESET} ${isDryRun ? '[DRY RUN] Would install' : 'Installed'} mcp_config.json`);
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
// Template-driven master hooks.json generation
|
|
440
|
+
let templateHooksPath = null;
|
|
441
|
+
if (profile === 'minimal' || profile === 'core') {
|
|
442
|
+
templateHooksPath = path.join(REPO_ROOT, 'templates', 'minimal', 'hooks.json');
|
|
443
|
+
} else if (profile === 'full') {
|
|
444
|
+
templateHooksPath = path.join(REPO_ROOT, 'templates', 'full-power', 'hooks.json');
|
|
445
|
+
} else {
|
|
446
|
+
templateHooksPath = path.join(REPO_ROOT, 'templates', 'recommended', 'hooks.json');
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
if (fs.existsSync(templateHooksPath)) {
|
|
450
|
+
if (!isDryRun) fs.copyFileSync(templateHooksPath, path.join(targetDir, 'hooks.json'));
|
|
451
|
+
console.log(` ${GREEN}✔${RESET} ${isDryRun ? '[DRY RUN] Would generate' : 'Generated'} profile hooks.json (${profile})`);
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
if (isDryRun) {
|
|
455
|
+
console.log(`\n${GREEN}${BOLD}✨ Dry run preview complete! 0 files modified on disk.${RESET}\n`);
|
|
456
|
+
} else {
|
|
457
|
+
console.log(`\n${GREEN}${BOLD}✨ Installation complete! Everything Gemini is ready.${RESET}\n`);
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
function runStatus(isGlobal = false, customTarget = null, asJson = false) {
|
|
462
|
+
const targetDir = customTarget
|
|
463
|
+
? path.resolve(customTarget)
|
|
464
|
+
: (isGlobal ? GLOBAL_CONFIG_DIR : AGENTS_DIR);
|
|
465
|
+
|
|
466
|
+
const isInitialized = fs.existsSync(targetDir);
|
|
467
|
+
const geminiRule = path.join(targetDir, 'GEMINI.md');
|
|
468
|
+
const agentsRule = path.join(targetDir, 'AGENTS.md');
|
|
469
|
+
const hasGemini = fs.existsSync(geminiRule);
|
|
470
|
+
const hasAgents = fs.existsSync(agentsRule);
|
|
471
|
+
|
|
472
|
+
// 1. Installed Skills
|
|
473
|
+
const skillsDir = path.join(targetDir, 'skills');
|
|
474
|
+
let installedSkills = [];
|
|
475
|
+
if (fs.existsSync(skillsDir)) {
|
|
476
|
+
installedSkills = fs.readdirSync(skillsDir, { withFileTypes: true })
|
|
477
|
+
.filter(d => d.isDirectory())
|
|
478
|
+
.map(d => d.name)
|
|
479
|
+
.sort();
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
// 2. Subagents
|
|
483
|
+
const agentsDir = path.join(targetDir, 'agents');
|
|
484
|
+
let installedAgents = [];
|
|
485
|
+
if (fs.existsSync(agentsDir)) {
|
|
486
|
+
installedAgents = fs.readdirSync(agentsDir)
|
|
487
|
+
.filter(f => f.endsWith('.md'))
|
|
488
|
+
.map(f => f.replace('.md', ''))
|
|
489
|
+
.sort();
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
// 3. Hooks
|
|
493
|
+
const hooksFile = path.join(targetDir, 'hooks.json');
|
|
494
|
+
let hooksSummary = {};
|
|
495
|
+
if (fs.existsSync(hooksFile)) {
|
|
496
|
+
try {
|
|
497
|
+
hooksSummary = JSON.parse(fs.readFileSync(hooksFile, 'utf8'));
|
|
498
|
+
} catch (e) {}
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
if (asJson) {
|
|
502
|
+
const payload = {
|
|
503
|
+
version: VERSION,
|
|
504
|
+
targetDir,
|
|
505
|
+
isGlobal,
|
|
506
|
+
isInitialized,
|
|
507
|
+
rules: {
|
|
508
|
+
gemini: hasGemini,
|
|
509
|
+
agents: hasAgents
|
|
510
|
+
},
|
|
511
|
+
skills: {
|
|
512
|
+
installedCount: installedSkills.length,
|
|
513
|
+
totalCatalogCount: 52,
|
|
514
|
+
installed: installedSkills
|
|
515
|
+
},
|
|
516
|
+
subagents: {
|
|
517
|
+
installedCount: installedAgents.length,
|
|
518
|
+
totalCatalogCount: 11,
|
|
519
|
+
installed: installedAgents
|
|
520
|
+
},
|
|
521
|
+
hooks: {
|
|
522
|
+
activeCount: Object.keys(hooksSummary).length,
|
|
523
|
+
active: Object.keys(hooksSummary)
|
|
524
|
+
}
|
|
525
|
+
};
|
|
526
|
+
console.log(JSON.stringify(payload, null, 2));
|
|
527
|
+
return;
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
printBanner();
|
|
531
|
+
console.log(`${BOLD}📊 Everything Gemini Workspace Status${RESET}`);
|
|
532
|
+
console.log(`Directory: ${CYAN}${targetDir}${RESET}\n`);
|
|
533
|
+
|
|
534
|
+
if (!isInitialized) {
|
|
535
|
+
console.log(` ${YELLOW}○ Workspace is not initialized.${RESET}`);
|
|
536
|
+
console.log(` Run ${GREEN}everything-gemini install${RESET} to set up.\n`);
|
|
537
|
+
return;
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
console.log(`${CYAN}${BOLD}📜 Base Rules:${RESET}`);
|
|
541
|
+
console.log(` ${hasGemini ? GREEN + '✔' : GRAY + '○'}${RESET} GEMINI.md ${hasGemini ? '(active)' : '(not installed)'}`);
|
|
542
|
+
console.log(` ${hasAgents ? GREEN + '✔' : GRAY + '○'}${RESET} AGENTS.md ${hasAgents ? '(active)' : '(not installed)'}`);
|
|
543
|
+
|
|
544
|
+
console.log(`\n${CYAN}${BOLD}⚡ Installed Skills (${installedSkills.length}/52):${RESET}`);
|
|
545
|
+
if (installedSkills.length === 0) {
|
|
546
|
+
console.log(` ${GRAY}(no skills installed)${RESET}`);
|
|
547
|
+
} else {
|
|
548
|
+
for (const s of installedSkills) {
|
|
549
|
+
console.log(` ${GREEN}✔${RESET} ${s}`);
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
console.log(`\n${CYAN}${BOLD}🤖 Scoped Subagents (${installedAgents.length}/11):${RESET}`);
|
|
554
|
+
if (installedAgents.length === 0) {
|
|
555
|
+
console.log(` ${GRAY}(no subagents installed)${RESET}`);
|
|
556
|
+
} else {
|
|
557
|
+
for (const a of installedAgents) {
|
|
558
|
+
console.log(` ${GREEN}✔${RESET} ${a}`);
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
console.log(`\n${CYAN}${BOLD}🛡️ Lifecycle Hooks:${RESET}`);
|
|
563
|
+
const hookNames = Object.keys(hooksSummary);
|
|
564
|
+
if (hookNames.length > 0) {
|
|
565
|
+
console.log(` ${GREEN}✔${RESET} hooks.json configured (${hookNames.length} hooks active):`);
|
|
566
|
+
for (const h of hookNames) {
|
|
567
|
+
const events = Object.keys(hooksSummary[h]).join(', ');
|
|
568
|
+
console.log(` • ${BOLD}${h}${RESET} [${GRAY}${events}${RESET}]`);
|
|
569
|
+
}
|
|
570
|
+
} else {
|
|
571
|
+
console.log(` ${GRAY}(no hooks.json found)${RESET}`);
|
|
572
|
+
}
|
|
573
|
+
console.log('');
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
function runUpdate(isGlobal = false, customTarget = null, isDryRun = false) {
|
|
577
|
+
printBanner();
|
|
578
|
+
const targetDir = customTarget
|
|
579
|
+
? path.resolve(customTarget)
|
|
580
|
+
: (isGlobal ? GLOBAL_CONFIG_DIR : AGENTS_DIR);
|
|
581
|
+
|
|
582
|
+
if (isDryRun) {
|
|
583
|
+
console.log(`${YELLOW}${BOLD}🔍 DRY RUN MODE ACTIVATED - No files will be modified on disk.${RESET}`);
|
|
584
|
+
}
|
|
585
|
+
console.log(`${BOLD}🔄 Updating Installed Components in: ${CYAN}${targetDir}${RESET}\n`);
|
|
586
|
+
|
|
587
|
+
if (!fs.existsSync(targetDir)) {
|
|
588
|
+
console.log(` ${YELLOW}○ Workspace is not initialized.${RESET}`);
|
|
589
|
+
console.log(` Run ${GREEN}everything-gemini install${RESET} first.\n`);
|
|
590
|
+
return;
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
let updatedSkills = 0;
|
|
594
|
+
let updatedAgents = 0;
|
|
595
|
+
let updatedHooks = 0;
|
|
596
|
+
|
|
597
|
+
// 1. Update Existing Installed Skills
|
|
598
|
+
const targetSkills = path.join(targetDir, 'skills');
|
|
599
|
+
if (fs.existsSync(targetSkills)) {
|
|
600
|
+
const installed = fs.readdirSync(targetSkills, { withFileTypes: true })
|
|
601
|
+
.filter(d => d.isDirectory())
|
|
602
|
+
.map(d => d.name);
|
|
603
|
+
for (const s of installed) {
|
|
604
|
+
const src = path.join(REPO_ROOT, 'skills', s);
|
|
605
|
+
if (fs.existsSync(src)) {
|
|
606
|
+
if (!isDryRun) copyRecursiveSync(src, path.join(targetSkills, s));
|
|
607
|
+
updatedSkills++;
|
|
608
|
+
if (isDryRun) {
|
|
609
|
+
console.log(` ${CYAN}[DRY RUN]${RESET} Would update skill: ${s}`);
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
// 2. Update Existing Installed Subagents
|
|
616
|
+
const targetAgents = path.join(targetDir, 'agents');
|
|
617
|
+
if (fs.existsSync(targetAgents)) {
|
|
618
|
+
const installed = fs.readdirSync(targetAgents)
|
|
619
|
+
.filter(f => f.endsWith('.md'));
|
|
620
|
+
for (const a of installed) {
|
|
621
|
+
const src = path.join(REPO_ROOT, 'agents', a);
|
|
622
|
+
if (fs.existsSync(src)) {
|
|
623
|
+
if (!isDryRun) fs.copyFileSync(src, path.join(targetAgents, a));
|
|
624
|
+
updatedAgents++;
|
|
625
|
+
if (isDryRun) {
|
|
626
|
+
console.log(` ${CYAN}[DRY RUN]${RESET} Would update subagent: ${a}`);
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
// 3. Update Hooks Scripts
|
|
633
|
+
const targetHooks = path.join(targetDir, 'hooks');
|
|
634
|
+
if (fs.existsSync(targetHooks)) {
|
|
635
|
+
const installed = fs.readdirSync(targetHooks, { withFileTypes: true })
|
|
636
|
+
.filter(d => d.isDirectory())
|
|
637
|
+
.map(d => d.name);
|
|
638
|
+
for (const h of installed) {
|
|
639
|
+
const src = path.join(REPO_ROOT, 'hooks', h);
|
|
640
|
+
if (fs.existsSync(src)) {
|
|
641
|
+
if (!isDryRun) copyRecursiveSync(src, path.join(targetHooks, h));
|
|
642
|
+
updatedHooks++;
|
|
643
|
+
if (isDryRun) {
|
|
644
|
+
console.log(` ${CYAN}[DRY RUN]${RESET} Would refresh hook: ${h}`);
|
|
380
645
|
}
|
|
381
|
-
|
|
646
|
+
}
|
|
382
647
|
}
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
// 4. Refresh base rules if present
|
|
651
|
+
const rulesSrc = path.join(REPO_ROOT, 'rules', 'common');
|
|
652
|
+
if (fs.existsSync(path.join(targetDir, 'GEMINI.md')) && fs.existsSync(path.join(rulesSrc, 'GEMINI.md'))) {
|
|
653
|
+
if (!isDryRun) fs.copyFileSync(path.join(rulesSrc, 'GEMINI.md'), path.join(targetDir, 'GEMINI.md'));
|
|
654
|
+
if (isDryRun) console.log(` ${CYAN}[DRY RUN]${RESET} Would refresh base GEMINI.md`);
|
|
655
|
+
}
|
|
656
|
+
if (fs.existsSync(path.join(targetDir, 'AGENTS.md')) && fs.existsSync(path.join(rulesSrc, 'AGENTS.md'))) {
|
|
657
|
+
if (!isDryRun) fs.copyFileSync(path.join(rulesSrc, 'AGENTS.md'), path.join(targetDir, 'AGENTS.md'));
|
|
658
|
+
if (isDryRun) console.log(` ${CYAN}[DRY RUN]${RESET} Would refresh base AGENTS.md`);
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
if (isDryRun) {
|
|
662
|
+
console.log(`\n${GREEN}${BOLD}✨ Dry run preview complete! 0 files modified on disk.${RESET}\n`);
|
|
663
|
+
} else {
|
|
664
|
+
console.log(` ${GREEN}✔${RESET} Synced ${BOLD}${updatedSkills}${RESET} installed skills to latest catalog versions`);
|
|
665
|
+
console.log(` ${GREEN}✔${RESET} Synced ${BOLD}${updatedAgents}${RESET} subagent specifications`);
|
|
666
|
+
console.log(` ${GREEN}✔${RESET} Refreshed ${BOLD}${updatedHooks}${RESET} lifecycle hook scripts & verified permissions`);
|
|
667
|
+
console.log(` ${GREEN}✔${RESET} Refreshed base GEMINI.md & AGENTS.md rules\n`);
|
|
668
|
+
console.log(`${GREEN}${BOLD}✨ Update complete! Everything Gemini is up to date.${RESET}\n`);
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
function runDiff(isGlobal = false, customTarget = null) {
|
|
673
|
+
printBanner();
|
|
674
|
+
const targetDir = customTarget ? path.resolve(customTarget) : (isGlobal ? GLOBAL_CONFIG_DIR : AGENTS_DIR);
|
|
675
|
+
console.log(`${BOLD}🔍 Comparing Workspace vs. Master Everything Gemini Catalog...${RESET}`);
|
|
676
|
+
console.log(`Target: ${CYAN}${targetDir}${RESET}\n`);
|
|
677
|
+
|
|
678
|
+
if (!fs.existsSync(targetDir)) {
|
|
679
|
+
console.log(`${YELLOW}No active configuration found at ${targetDir}.${RESET}\n`);
|
|
680
|
+
return;
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
// Compare skills
|
|
684
|
+
const wsSkillsDir = path.join(targetDir, 'skills');
|
|
685
|
+
const catalogSkillsDir = path.join(REPO_ROOT, 'skills');
|
|
686
|
+
const wsSkills = fs.existsSync(wsSkillsDir) ? fs.readdirSync(wsSkillsDir).filter(s => {
|
|
687
|
+
try { return fs.statSync(path.join(wsSkillsDir, s)).isDirectory(); } catch (_) { return false; }
|
|
688
|
+
}) : [];
|
|
689
|
+
|
|
690
|
+
console.log(`${BOLD}⚡ Progressive Skills Comparison:${RESET}`);
|
|
691
|
+
let modifiedCount = 0;
|
|
692
|
+
for (const s of wsSkills) {
|
|
693
|
+
const wsFile = path.join(wsSkillsDir, s, 'SKILL.md');
|
|
694
|
+
const catFile = path.join(catalogSkillsDir, s, 'SKILL.md');
|
|
695
|
+
if (!fs.existsSync(catFile)) {
|
|
696
|
+
console.log(` ${CYAN}+ [CUSTOM/LOCAL]${RESET} ${s}`);
|
|
697
|
+
} else {
|
|
698
|
+
const wsContent = fs.existsSync(wsFile) ? fs.readFileSync(wsFile, 'utf8') : '';
|
|
699
|
+
const catContent = fs.readFileSync(catFile, 'utf8');
|
|
700
|
+
if (wsContent !== catContent) {
|
|
701
|
+
console.log(` ${YELLOW}* [MODIFIED]${RESET} ${s} (differs from catalog)`);
|
|
702
|
+
modifiedCount++;
|
|
703
|
+
} else {
|
|
704
|
+
console.log(` ${GREEN}✔ [IN-SYNC]${RESET} ${s}`);
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
// Compare agents
|
|
710
|
+
const wsAgentsDir = path.join(targetDir, 'agents');
|
|
711
|
+
const catAgentsDir = path.join(REPO_ROOT, 'agents');
|
|
712
|
+
const wsAgents = fs.existsSync(wsAgentsDir) ? fs.readdirSync(wsAgentsDir).filter(a => a.endsWith('.md')) : [];
|
|
713
|
+
console.log(`\n${BOLD}🤖 Scoped Subagents Comparison:${RESET}`);
|
|
714
|
+
for (const a of wsAgents) {
|
|
715
|
+
const wsFile = path.join(wsAgentsDir, a);
|
|
716
|
+
const catFile = path.join(catAgentsDir, a);
|
|
717
|
+
if (!fs.existsSync(catFile)) {
|
|
718
|
+
console.log(` ${CYAN}+ [CUSTOM/LOCAL]${RESET} ${a}`);
|
|
719
|
+
} else {
|
|
720
|
+
const wsContent = fs.readFileSync(wsFile, 'utf8');
|
|
721
|
+
const catContent = fs.readFileSync(catFile, 'utf8');
|
|
722
|
+
if (wsContent !== catContent) {
|
|
723
|
+
console.log(` ${YELLOW}* [MODIFIED]${RESET} ${a} (differs from catalog)`);
|
|
724
|
+
modifiedCount++;
|
|
725
|
+
} else {
|
|
726
|
+
console.log(` ${GREEN}✔ [IN-SYNC]${RESET} ${a}`);
|
|
727
|
+
}
|
|
728
|
+
}
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
console.log(`\n${BOLD}Diff Summary:${RESET} ${wsSkills.length} skills, ${wsAgents.length} subagents checked. ${modifiedCount === 0 ? GREEN + 'All matching components are in sync with master catalog!' + RESET : YELLOW + `${modifiedCount} modified component(s) detected.` + RESET}\n`);
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
function runExport(isGlobal = false, customTarget = null, outputPath = null) {
|
|
735
|
+
printBanner();
|
|
736
|
+
const targetDir = customTarget ? path.resolve(customTarget) : (isGlobal ? GLOBAL_CONFIG_DIR : AGENTS_DIR);
|
|
737
|
+
console.log(`${BOLD}📦 Exporting Agent Configuration Bundle...${RESET}`);
|
|
738
|
+
console.log(`Source: ${CYAN}${targetDir}${RESET}\n`);
|
|
739
|
+
|
|
740
|
+
if (!fs.existsSync(targetDir)) {
|
|
741
|
+
console.error(`${RED}Error: Source directory does not exist: ${targetDir}${RESET}\n`);
|
|
742
|
+
process.exit(1);
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
const exportData = {
|
|
746
|
+
generator: "everything-gemini",
|
|
747
|
+
version: VERSION,
|
|
748
|
+
exportedAt: new Date().toISOString(),
|
|
749
|
+
source: targetDir,
|
|
750
|
+
skills: [],
|
|
751
|
+
agents: [],
|
|
752
|
+
hooksConfig: null
|
|
753
|
+
};
|
|
754
|
+
|
|
755
|
+
const skillsDir = path.join(targetDir, 'skills');
|
|
756
|
+
if (fs.existsSync(skillsDir)) {
|
|
757
|
+
for (const s of fs.readdirSync(skillsDir)) {
|
|
758
|
+
const skillPath = path.join(skillsDir, s, 'SKILL.md');
|
|
759
|
+
if (fs.existsSync(skillPath)) {
|
|
760
|
+
exportData.skills.push({ name: s, content: fs.readFileSync(skillPath, 'utf8') });
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
const agentsDir = path.join(targetDir, 'agents');
|
|
766
|
+
if (fs.existsSync(agentsDir)) {
|
|
767
|
+
for (const a of fs.readdirSync(agentsDir)) {
|
|
768
|
+
if (a.endsWith('.md')) {
|
|
769
|
+
exportData.agents.push({ name: a, content: fs.readFileSync(path.join(agentsDir, a), 'utf8') });
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
const hooksFile = path.join(targetDir, 'hooks.json');
|
|
775
|
+
if (fs.existsSync(hooksFile)) {
|
|
776
|
+
try {
|
|
777
|
+
exportData.hooksConfig = JSON.parse(fs.readFileSync(hooksFile, 'utf8'));
|
|
778
|
+
} catch (_) {}
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
const outDest = outputPath ? path.resolve(outputPath) : path.join(process.cwd(), 'everything-gemini-profile.json');
|
|
782
|
+
fs.writeFileSync(outDest, JSON.stringify(exportData, null, 2), 'utf8');
|
|
783
|
+
console.log(` ${GREEN}✔${RESET} Successfully exported ${exportData.skills.length} skills, ${exportData.agents.length} subagents to:`);
|
|
784
|
+
console.log(` ${BOLD}${outDest}${RESET}\n`);
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
function runImport(inputFile, isGlobal = false, customTarget = null, isDryRun = false) {
|
|
788
|
+
printBanner();
|
|
789
|
+
if (!inputFile) {
|
|
790
|
+
console.error(`${RED}Error: Input file required. Usage: everything-gemini import <profile.json>${RESET}\n`);
|
|
791
|
+
process.exit(1);
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
const filePath = path.resolve(inputFile);
|
|
795
|
+
if (!fs.existsSync(filePath)) {
|
|
796
|
+
console.error(`${RED}Error: Import file does not exist: ${filePath}${RESET}\n`);
|
|
797
|
+
process.exit(1);
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
let bundle = null;
|
|
801
|
+
try {
|
|
802
|
+
bundle = JSON.parse(fs.readFileSync(filePath, 'utf8'));
|
|
803
|
+
} catch (err) {
|
|
804
|
+
console.error(`${RED}Error parsing JSON import bundle: ${err.message}${RESET}\n`);
|
|
805
|
+
process.exit(1);
|
|
806
|
+
}
|
|
807
|
+
|
|
808
|
+
const targetDir = customTarget ? path.resolve(customTarget) : (isGlobal ? GLOBAL_CONFIG_DIR : AGENTS_DIR);
|
|
809
|
+
console.log(`${BOLD}📥 Importing Agent Configuration Bundle...${RESET}`);
|
|
810
|
+
console.log(`Source File: ${CYAN}${filePath}${RESET}`);
|
|
811
|
+
console.log(`Target: ${CYAN}${targetDir}${RESET}\n`);
|
|
812
|
+
|
|
813
|
+
if (isDryRun) {
|
|
814
|
+
console.log(`${YELLOW}${BOLD}⚠️ DRY RUN MODE ACTIVATED. Previewing import:${RESET}\n`);
|
|
815
|
+
}
|
|
816
|
+
|
|
817
|
+
let importedSkills = 0;
|
|
818
|
+
let importedAgents = 0;
|
|
819
|
+
|
|
820
|
+
// 1. Import Skills
|
|
821
|
+
if (Array.isArray(bundle.skills)) {
|
|
822
|
+
const targetSkills = path.join(targetDir, 'skills');
|
|
823
|
+
for (const s of bundle.skills) {
|
|
824
|
+
if (s.name && s.content) {
|
|
825
|
+
if (!isDryRun) {
|
|
826
|
+
const sDir = path.join(targetSkills, s.name);
|
|
827
|
+
fs.mkdirSync(sDir, { recursive: true });
|
|
828
|
+
fs.writeFileSync(path.join(sDir, 'SKILL.md'), s.content, 'utf8');
|
|
829
|
+
}
|
|
830
|
+
importedSkills++;
|
|
831
|
+
if (isDryRun) {
|
|
832
|
+
console.log(` ${CYAN}[DRY RUN]${RESET} Would import skill: ${s.name}`);
|
|
833
|
+
}
|
|
834
|
+
}
|
|
835
|
+
}
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
// 2. Import Subagents
|
|
839
|
+
if (Array.isArray(bundle.agents)) {
|
|
840
|
+
const targetAgents = path.join(targetDir, 'agents');
|
|
841
|
+
for (const a of bundle.agents) {
|
|
842
|
+
if (a.name && a.content) {
|
|
843
|
+
if (!isDryRun) {
|
|
844
|
+
fs.mkdirSync(targetAgents, { recursive: true });
|
|
845
|
+
fs.writeFileSync(path.join(targetAgents, a.name), a.content, 'utf8');
|
|
846
|
+
}
|
|
847
|
+
importedAgents++;
|
|
848
|
+
if (isDryRun) {
|
|
849
|
+
console.log(` ${CYAN}[DRY RUN]${RESET} Would import subagent: ${a.name}`);
|
|
850
|
+
}
|
|
851
|
+
}
|
|
852
|
+
}
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
// 3. Import Hooks Config
|
|
856
|
+
if (bundle.hooksConfig && typeof bundle.hooksConfig === 'object') {
|
|
857
|
+
if (!isDryRun) {
|
|
858
|
+
fs.mkdirSync(targetDir, { recursive: true });
|
|
859
|
+
fs.writeFileSync(path.join(targetDir, 'hooks.json'), JSON.stringify(bundle.hooksConfig, null, 2), 'utf8');
|
|
860
|
+
}
|
|
861
|
+
console.log(` ${GREEN}✔${RESET} ${isDryRun ? '[DRY RUN] Would import' : 'Imported'} hooks.json configuration`);
|
|
862
|
+
}
|
|
863
|
+
|
|
864
|
+
if (isDryRun) {
|
|
865
|
+
console.log(`\n${GREEN}${BOLD}✨ Dry run complete! Would import ${importedSkills} skills and ${importedAgents} subagents.${RESET}\n`);
|
|
866
|
+
} else {
|
|
867
|
+
console.log(` ${GREEN}✔${RESET} Successfully imported ${BOLD}${importedSkills}${RESET} progressive skills`);
|
|
868
|
+
console.log(` ${GREEN}✔${RESET} Successfully imported ${BOLD}${importedAgents}${RESET} scoped subagents\n`);
|
|
869
|
+
console.log(`${GREEN}${BOLD}✨ Import complete! Configuration applied to ${targetDir}${RESET}\n`);
|
|
870
|
+
}
|
|
871
|
+
}
|
|
872
|
+
|
|
873
|
+
function runBundle(profile = 'all', outputDir = null, isDryRun = false, asJson = false) {
|
|
874
|
+
const destDir = outputDir ? path.resolve(outputDir) : path.join(process.cwd(), 'everything-gemini-bundle');
|
|
875
|
+
const startTime = Date.now();
|
|
876
|
+
const crypto = require('crypto');
|
|
877
|
+
|
|
878
|
+
const skillsToBundle = [];
|
|
879
|
+
const agentsToBundle = [];
|
|
880
|
+
const hooksToBundle = [];
|
|
881
|
+
|
|
882
|
+
const catalogSkillsDir = path.join(REPO_ROOT, 'skills');
|
|
883
|
+
const catalogAgentsDir = path.join(REPO_ROOT, 'agents');
|
|
884
|
+
const catalogHooksDir = path.join(REPO_ROOT, 'hooks');
|
|
885
|
+
|
|
886
|
+
if (fs.existsSync(catalogSkillsDir)) {
|
|
887
|
+
const list = fs.readdirSync(catalogSkillsDir, { withFileTypes: true })
|
|
888
|
+
.filter(d => d.isDirectory())
|
|
889
|
+
.map(d => d.name)
|
|
890
|
+
.sort();
|
|
891
|
+
skillsToBundle.push(...list);
|
|
892
|
+
}
|
|
893
|
+
|
|
894
|
+
const pluginSkills = [
|
|
895
|
+
{ name: 'antigravity-sdk-orchestrator', src: path.join(REPO_ROOT, 'plugins', 'python-ai', 'skills', 'antigravity-sdk-orchestrator') },
|
|
896
|
+
{ name: 'responsive-design', src: path.join(REPO_ROOT, 'plugins', 'web-fullstack', 'skills', 'responsive-design') }
|
|
897
|
+
];
|
|
898
|
+
|
|
899
|
+
if (fs.existsSync(catalogAgentsDir)) {
|
|
900
|
+
const list = fs.readdirSync(catalogAgentsDir)
|
|
901
|
+
.filter(f => f.endsWith('.md'))
|
|
902
|
+
.sort();
|
|
903
|
+
agentsToBundle.push(...list);
|
|
904
|
+
}
|
|
905
|
+
|
|
906
|
+
if (fs.existsSync(catalogHooksDir)) {
|
|
907
|
+
const list = fs.readdirSync(catalogHooksDir, { withFileTypes: true })
|
|
908
|
+
.filter(d => d.isDirectory())
|
|
909
|
+
.map(d => d.name)
|
|
910
|
+
.sort();
|
|
911
|
+
hooksToBundle.push(...list);
|
|
912
|
+
}
|
|
913
|
+
|
|
914
|
+
const manifest = {
|
|
915
|
+
generator: "everything-gemini",
|
|
916
|
+
version: VERSION,
|
|
917
|
+
profile,
|
|
918
|
+
createdAt: new Date().toISOString(),
|
|
919
|
+
components: {
|
|
920
|
+
skillsCount: skillsToBundle.length + pluginSkills.length,
|
|
921
|
+
subagentsCount: agentsToBundle.length,
|
|
922
|
+
hooksCount: hooksToBundle.length,
|
|
923
|
+
totalCount: skillsToBundle.length + pluginSkills.length + agentsToBundle.length + hooksToBundle.length
|
|
924
|
+
},
|
|
925
|
+
skills: [...skillsToBundle, ...pluginSkills.map(p => p.name)],
|
|
926
|
+
subagents: agentsToBundle,
|
|
927
|
+
hooks: hooksToBundle,
|
|
928
|
+
files: []
|
|
383
929
|
};
|
|
384
|
-
fs.writeFileSync(path.join(targetDir, 'hooks.json'), JSON.stringify(masterHooks, null, 2));
|
|
385
|
-
console.log(` ${GREEN}✔${RESET} Generated master hooks.json`);
|
|
386
930
|
|
|
387
|
-
|
|
931
|
+
if (isDryRun) {
|
|
932
|
+
if (asJson) {
|
|
933
|
+
console.log(JSON.stringify({
|
|
934
|
+
dryRun: true,
|
|
935
|
+
targetDirectory: destDir,
|
|
936
|
+
manifest
|
|
937
|
+
}, null, 2));
|
|
938
|
+
return;
|
|
939
|
+
}
|
|
940
|
+
printBanner();
|
|
941
|
+
console.log(`${YELLOW}${BOLD}🔍 DRY RUN MODE ACTIVATED - Previewing bundle contents${RESET}`);
|
|
942
|
+
console.log(`Target: ${CYAN}${destDir}${RESET}\n`);
|
|
943
|
+
console.log(` ${CYAN}⚡ Skills to bundle:${RESET} ${skillsToBundle.length + pluginSkills.length}`);
|
|
944
|
+
console.log(` ${CYAN}🤖 Subagents to bundle:${RESET} ${agentsToBundle.length}`);
|
|
945
|
+
console.log(` ${CYAN}🛡️ Hooks to bundle:${RESET} ${hooksToBundle.length}`);
|
|
946
|
+
console.log(` ${CYAN}📦 Total Components:${RESET} ${manifest.components.totalCount}\n`);
|
|
947
|
+
console.log(`${GREEN}${BOLD}✨ Dry run preview complete! 0 files written to disk.${RESET}\n`);
|
|
948
|
+
return;
|
|
949
|
+
}
|
|
950
|
+
|
|
951
|
+
fs.mkdirSync(destDir, { recursive: true });
|
|
952
|
+
const bundleSkillsDir = path.join(destDir, 'skills');
|
|
953
|
+
const bundleAgentsDir = path.join(destDir, 'agents');
|
|
954
|
+
const bundleHooksDir = path.join(destDir, 'hooks');
|
|
955
|
+
const bundleRulesDir = path.join(destDir, 'rules');
|
|
956
|
+
fs.mkdirSync(bundleSkillsDir, { recursive: true });
|
|
957
|
+
fs.mkdirSync(bundleAgentsDir, { recursive: true });
|
|
958
|
+
fs.mkdirSync(bundleHooksDir, { recursive: true });
|
|
959
|
+
fs.mkdirSync(bundleRulesDir, { recursive: true });
|
|
960
|
+
|
|
961
|
+
for (const s of skillsToBundle) {
|
|
962
|
+
const src = path.join(catalogSkillsDir, s);
|
|
963
|
+
const dest = path.join(bundleSkillsDir, s);
|
|
964
|
+
copyRecursiveSync(src, dest);
|
|
965
|
+
const skillMd = path.join(dest, 'SKILL.md');
|
|
966
|
+
if (fs.existsSync(skillMd)) {
|
|
967
|
+
const hash = crypto.createHash('sha256').update(fs.readFileSync(skillMd)).digest('hex');
|
|
968
|
+
manifest.files.push({ path: `skills/${s}/SKILL.md`, sha256: hash });
|
|
969
|
+
}
|
|
970
|
+
}
|
|
971
|
+
|
|
972
|
+
for (const ps of pluginSkills) {
|
|
973
|
+
if (fs.existsSync(ps.src)) {
|
|
974
|
+
const dest = path.join(bundleSkillsDir, ps.name);
|
|
975
|
+
copyRecursiveSync(ps.src, dest);
|
|
976
|
+
const skillMd = path.join(dest, 'SKILL.md');
|
|
977
|
+
if (fs.existsSync(skillMd)) {
|
|
978
|
+
const hash = crypto.createHash('sha256').update(fs.readFileSync(skillMd)).digest('hex');
|
|
979
|
+
manifest.files.push({ path: `skills/${ps.name}/SKILL.md`, sha256: hash });
|
|
980
|
+
}
|
|
981
|
+
}
|
|
982
|
+
}
|
|
983
|
+
|
|
984
|
+
for (const a of agentsToBundle) {
|
|
985
|
+
const src = path.join(catalogAgentsDir, a);
|
|
986
|
+
const dest = path.join(bundleAgentsDir, a);
|
|
987
|
+
fs.copyFileSync(src, dest);
|
|
988
|
+
const hash = crypto.createHash('sha256').update(fs.readFileSync(dest)).digest('hex');
|
|
989
|
+
manifest.files.push({ path: `agents/${a}`, sha256: hash });
|
|
990
|
+
}
|
|
991
|
+
|
|
992
|
+
for (const h of hooksToBundle) {
|
|
993
|
+
const src = path.join(catalogHooksDir, h);
|
|
994
|
+
const dest = path.join(bundleHooksDir, h);
|
|
995
|
+
copyRecursiveSync(src, dest);
|
|
996
|
+
const hookJson = path.join(dest, 'hooks.json');
|
|
997
|
+
if (fs.existsSync(hookJson)) {
|
|
998
|
+
const hash = crypto.createHash('sha256').update(fs.readFileSync(hookJson)).digest('hex');
|
|
999
|
+
manifest.files.push({ path: `hooks/${h}/hooks.json`, sha256: hash });
|
|
1000
|
+
}
|
|
1001
|
+
}
|
|
1002
|
+
|
|
1003
|
+
const commonRules = path.join(REPO_ROOT, 'rules', 'common');
|
|
1004
|
+
if (fs.existsSync(commonRules)) {
|
|
1005
|
+
copyRecursiveSync(commonRules, bundleRulesDir);
|
|
1006
|
+
if (fs.existsSync(path.join(bundleRulesDir, 'GEMINI.md'))) {
|
|
1007
|
+
fs.copyFileSync(path.join(bundleRulesDir, 'GEMINI.md'), path.join(destDir, 'GEMINI.md'));
|
|
1008
|
+
}
|
|
1009
|
+
if (fs.existsSync(path.join(bundleRulesDir, 'AGENTS.md'))) {
|
|
1010
|
+
fs.copyFileSync(path.join(bundleRulesDir, 'AGENTS.md'), path.join(destDir, 'AGENTS.md'));
|
|
1011
|
+
}
|
|
1012
|
+
}
|
|
1013
|
+
|
|
1014
|
+
const installerScript = `#!/usr/bin/env bash
|
|
1015
|
+
# Offline Installer for Everything Gemini Bundle
|
|
1016
|
+
set -e
|
|
1017
|
+
TARGET="\${1:-.agents}"
|
|
1018
|
+
mkdir -p "$TARGET/skills" "$TARGET/agents" "$TARGET/hooks"
|
|
1019
|
+
cp -R skills/* "$TARGET/skills/" 2>/dev/null || true
|
|
1020
|
+
cp -R agents/* "$TARGET/agents/" 2>/dev/null || true
|
|
1021
|
+
cp -R hooks/* "$TARGET/hooks/" 2>/dev/null || true
|
|
1022
|
+
[ -f GEMINI.md ] && cp GEMINI.md "$TARGET/GEMINI.md"
|
|
1023
|
+
[ -f AGENTS.md ] && cp AGENTS.md "$TARGET/AGENTS.md"
|
|
1024
|
+
find "$TARGET/hooks" -name "*.sh" -exec chmod +x {} + 2>/dev/null || true
|
|
1025
|
+
echo "✨ Offline Everything Gemini bundle installed cleanly into $TARGET"
|
|
1026
|
+
`.trim();
|
|
1027
|
+
fs.writeFileSync(path.join(destDir, 'offline-install.sh'), installerScript, { mode: 0o755 });
|
|
1028
|
+
|
|
1029
|
+
fs.writeFileSync(path.join(destDir, 'bundle-manifest.json'), JSON.stringify(manifest, null, 2), 'utf8');
|
|
1030
|
+
|
|
1031
|
+
const duration = ((Date.now() - startTime) / 1000).toFixed(2);
|
|
1032
|
+
|
|
1033
|
+
if (asJson) {
|
|
1034
|
+
console.log(JSON.stringify({
|
|
1035
|
+
targetDirectory: destDir,
|
|
1036
|
+
manifest,
|
|
1037
|
+
durationSeconds: parseFloat(duration)
|
|
1038
|
+
}, null, 2));
|
|
1039
|
+
return;
|
|
1040
|
+
}
|
|
1041
|
+
|
|
1042
|
+
printBanner();
|
|
1043
|
+
console.log(`${BOLD}📦 Everything Gemini Offline Distribution Bundle Created${RESET}`);
|
|
1044
|
+
console.log(`Target: ${CYAN}${destDir}${RESET}\n`);
|
|
1045
|
+
console.log(` ${GREEN}✔${RESET} Packaged ${BOLD}${manifest.components.skillsCount}${RESET} progressive disclosure skills`);
|
|
1046
|
+
console.log(` ${GREEN}✔${RESET} Packaged ${BOLD}${manifest.components.subagentsCount}${RESET} scoped subagents`);
|
|
1047
|
+
console.log(` ${GREEN}✔${RESET} Packaged ${BOLD}${manifest.components.hooksCount}${RESET} lifecycle safety hooks`);
|
|
1048
|
+
console.log(` ${GREEN}✔${RESET} Generated ${BOLD}bundle-manifest.json${RESET} with ${manifest.files.length} SHA-256 integrity digests`);
|
|
1049
|
+
console.log(` ${GREEN}✔${RESET} Generated executable ${BOLD}offline-install.sh${RESET}`);
|
|
1050
|
+
console.log(` ${GREEN}✔${RESET} Total bundle duration: ${duration}s\n`);
|
|
1051
|
+
console.log(`${GREEN}${BOLD}✨ Bundle packaging complete! Ready for air-gapped and CI/CD deployment.${RESET}\n`);
|
|
388
1052
|
}
|
|
389
1053
|
|
|
390
1054
|
function runValidate() {
|
|
@@ -507,14 +1171,17 @@ Return structured report to parent agent:
|
|
|
507
1171
|
console.log(` 📄 ${targetFile}\n`);
|
|
508
1172
|
}
|
|
509
1173
|
|
|
510
|
-
function addComponent(type, name) {
|
|
1174
|
+
function addComponent(type, name, isGlobal = false, customTarget = null) {
|
|
511
1175
|
if (!type || !name) {
|
|
512
|
-
console.error(`${RED}Usage: everything-gemini add <skill|agent|plugin> <name
|
|
1176
|
+
console.error(`${RED}Usage: everything-gemini add <skill|agent|hook|plugin> <name> [--workspace <path>] [--global]${RESET}`);
|
|
513
1177
|
process.exit(1);
|
|
514
1178
|
}
|
|
515
1179
|
|
|
516
1180
|
const cleanName = name.trim().toLowerCase();
|
|
517
|
-
const targetWorkspace =
|
|
1181
|
+
const targetWorkspace = customTarget
|
|
1182
|
+
? path.resolve(customTarget)
|
|
1183
|
+
: (isGlobal ? GLOBAL_CONFIG_DIR : path.join(WORKSPACE_DIR, '.agents'));
|
|
1184
|
+
|
|
518
1185
|
if (!fs.existsSync(targetWorkspace)) {
|
|
519
1186
|
fs.mkdirSync(targetWorkspace, { recursive: true });
|
|
520
1187
|
}
|
|
@@ -538,6 +1205,21 @@ function addComponent(type, name) {
|
|
|
538
1205
|
fs.mkdirSync(destDir, { recursive: true });
|
|
539
1206
|
fs.copyFileSync(src, path.join(destDir, `${cleanName}.md`));
|
|
540
1207
|
console.log(`${GREEN}✔ Added agent '${cleanName}' to ${destDir}${RESET}`);
|
|
1208
|
+
} else if (type === 'hook') {
|
|
1209
|
+
const src = path.join(REPO_ROOT, 'hooks', cleanName);
|
|
1210
|
+
if (!fs.existsSync(src)) {
|
|
1211
|
+
console.error(`${RED}Hook '${cleanName}' not found in catalog.${RESET}`);
|
|
1212
|
+
process.exit(1);
|
|
1213
|
+
}
|
|
1214
|
+
const dest = path.join(targetWorkspace, 'hooks', cleanName);
|
|
1215
|
+
copyRecursiveSync(src, dest);
|
|
1216
|
+
const scriptsDir = path.join(dest, 'scripts');
|
|
1217
|
+
if (fs.existsSync(scriptsDir)) {
|
|
1218
|
+
fs.readdirSync(scriptsDir).forEach(file => {
|
|
1219
|
+
try { fs.chmodSync(path.join(scriptsDir, file), 0o755); } catch (e) {}
|
|
1220
|
+
});
|
|
1221
|
+
}
|
|
1222
|
+
console.log(`${GREEN}✔ Added hook '${cleanName}' to ${dest}${RESET}`);
|
|
541
1223
|
} else if (type === 'plugin') {
|
|
542
1224
|
const src = path.join(REPO_ROOT, 'plugins', cleanName);
|
|
543
1225
|
if (!fs.existsSync(src)) {
|
|
@@ -548,19 +1230,21 @@ function addComponent(type, name) {
|
|
|
548
1230
|
copyRecursiveSync(src, dest);
|
|
549
1231
|
console.log(`${GREEN}✔ Added plugin '${cleanName}' to ${dest}${RESET}`);
|
|
550
1232
|
} else {
|
|
551
|
-
console.error(`${RED}Unknown type '${type}'. Use: skill, agent, or plugin.${RESET}`);
|
|
1233
|
+
console.error(`${RED}Unknown type '${type}'. Use: skill, agent, hook, or plugin.${RESET}`);
|
|
552
1234
|
process.exit(1);
|
|
553
1235
|
}
|
|
554
1236
|
}
|
|
555
1237
|
|
|
556
|
-
function removeComponent(type, name) {
|
|
1238
|
+
function removeComponent(type, name, isGlobal = false, customTarget = null) {
|
|
557
1239
|
if (!type || !name) {
|
|
558
|
-
console.error(`${RED}Usage: everything-gemini remove <skill|agent|plugin> <name
|
|
1240
|
+
console.error(`${RED}Usage: everything-gemini remove <skill|agent|hook|plugin> <name> [--workspace <path>] [--global]${RESET}`);
|
|
559
1241
|
process.exit(1);
|
|
560
1242
|
}
|
|
561
1243
|
|
|
562
1244
|
const cleanName = name.trim().toLowerCase();
|
|
563
|
-
const targetWorkspace =
|
|
1245
|
+
const targetWorkspace = customTarget
|
|
1246
|
+
? path.resolve(customTarget)
|
|
1247
|
+
: (isGlobal ? GLOBAL_CONFIG_DIR : path.join(WORKSPACE_DIR, '.agents'));
|
|
564
1248
|
|
|
565
1249
|
if (type === 'skill') {
|
|
566
1250
|
const dest = path.join(targetWorkspace, 'skills', cleanName);
|
|
@@ -569,7 +1253,7 @@ function removeComponent(type, name) {
|
|
|
569
1253
|
return;
|
|
570
1254
|
}
|
|
571
1255
|
fs.rmSync(dest, { recursive: true, force: true });
|
|
572
|
-
console.log(`${GREEN}✔ Removed skill '${cleanName}' from
|
|
1256
|
+
console.log(`${GREEN}✔ Removed skill '${cleanName}' from ${dest}.${RESET}`);
|
|
573
1257
|
} else if (type === 'agent') {
|
|
574
1258
|
const dest = path.join(targetWorkspace, 'agents', `${cleanName}.md`);
|
|
575
1259
|
if (!fs.existsSync(dest)) {
|
|
@@ -577,7 +1261,15 @@ function removeComponent(type, name) {
|
|
|
577
1261
|
return;
|
|
578
1262
|
}
|
|
579
1263
|
fs.unlinkSync(dest);
|
|
580
|
-
console.log(`${GREEN}✔ Removed agent '${cleanName}' from
|
|
1264
|
+
console.log(`${GREEN}✔ Removed agent '${cleanName}' from ${dest}.${RESET}`);
|
|
1265
|
+
} else if (type === 'hook') {
|
|
1266
|
+
const dest = path.join(targetWorkspace, 'hooks', cleanName);
|
|
1267
|
+
if (!fs.existsSync(dest)) {
|
|
1268
|
+
console.log(`${YELLOW}Hook '${cleanName}' is not installed in ${dest}${RESET}`);
|
|
1269
|
+
return;
|
|
1270
|
+
}
|
|
1271
|
+
fs.rmSync(dest, { recursive: true, force: true });
|
|
1272
|
+
console.log(`${GREEN}✔ Removed hook '${cleanName}' from ${dest}.${RESET}`);
|
|
581
1273
|
} else if (type === 'plugin') {
|
|
582
1274
|
const dest = path.join(targetWorkspace, 'plugins', cleanName);
|
|
583
1275
|
if (!fs.existsSync(dest)) {
|
|
@@ -585,9 +1277,9 @@ function removeComponent(type, name) {
|
|
|
585
1277
|
return;
|
|
586
1278
|
}
|
|
587
1279
|
fs.rmSync(dest, { recursive: true, force: true });
|
|
588
|
-
console.log(`${GREEN}✔ Removed plugin '${cleanName}' from
|
|
1280
|
+
console.log(`${GREEN}✔ Removed plugin '${cleanName}' from ${dest}.${RESET}`);
|
|
589
1281
|
} else {
|
|
590
|
-
console.error(`${RED}Unknown type '${type}'. Use: skill, agent, or plugin.${RESET}`);
|
|
1282
|
+
console.error(`${RED}Unknown type '${type}'. Use: skill, agent, hook, or plugin.${RESET}`);
|
|
591
1283
|
process.exit(1);
|
|
592
1284
|
}
|
|
593
1285
|
}
|
|
@@ -654,14 +1346,582 @@ function testSkill(name) {
|
|
|
654
1346
|
console.log(`\n${GREEN}${BOLD}✨ Skill '${cleanName}' passed all validation checks!${RESET}\n`);
|
|
655
1347
|
}
|
|
656
1348
|
|
|
657
|
-
function
|
|
658
|
-
if (!
|
|
659
|
-
console.
|
|
660
|
-
console.log(`Usage: everything-gemini
|
|
1349
|
+
function searchComponents(query, asJson = false) {
|
|
1350
|
+
if (!query || !query.trim()) {
|
|
1351
|
+
console.log(`${YELLOW}Please specify a search query.${RESET}`);
|
|
1352
|
+
console.log(`Usage: everything-gemini search <term> [--json]\n`);
|
|
1353
|
+
return;
|
|
1354
|
+
}
|
|
1355
|
+
const q = query.trim().toLowerCase();
|
|
1356
|
+
const results = {
|
|
1357
|
+
skills: [],
|
|
1358
|
+
subagents: [],
|
|
1359
|
+
hooks: [],
|
|
1360
|
+
mcp: []
|
|
1361
|
+
};
|
|
1362
|
+
|
|
1363
|
+
// 1. Search Skills (core + plugins)
|
|
1364
|
+
const skillsDir = path.join(REPO_ROOT, 'skills');
|
|
1365
|
+
if (fs.existsSync(skillsDir)) {
|
|
1366
|
+
const skills = fs.readdirSync(skillsDir, { withFileTypes: true })
|
|
1367
|
+
.filter(d => d.isDirectory())
|
|
1368
|
+
.map(d => d.name);
|
|
1369
|
+
for (const skill of skills) {
|
|
1370
|
+
const skillMd = path.join(skillsDir, skill, 'SKILL.md');
|
|
1371
|
+
let desc = '';
|
|
1372
|
+
let fullContent = '';
|
|
1373
|
+
if (fs.existsSync(skillMd)) {
|
|
1374
|
+
fullContent = fs.readFileSync(skillMd, 'utf8');
|
|
1375
|
+
const match = fullContent.match(/description:\s*>?-?\s*([^\n\r]+)/);
|
|
1376
|
+
if (match) desc = match[1].trim();
|
|
1377
|
+
}
|
|
1378
|
+
if (skill.toLowerCase().includes(q) || desc.toLowerCase().includes(q) || fullContent.toLowerCase().includes(q)) {
|
|
1379
|
+
results.skills.push({ name: skill, description: desc || 'Progressive disclosure skill' });
|
|
1380
|
+
}
|
|
1381
|
+
}
|
|
1382
|
+
}
|
|
1383
|
+
|
|
1384
|
+
const pluginsDir = path.join(REPO_ROOT, 'plugins');
|
|
1385
|
+
if (fs.existsSync(pluginsDir)) {
|
|
1386
|
+
const plugins = fs.readdirSync(pluginsDir, { withFileTypes: true })
|
|
1387
|
+
.filter(d => d.isDirectory())
|
|
1388
|
+
.map(d => d.name);
|
|
1389
|
+
for (const p of plugins) {
|
|
1390
|
+
const pSkillsDir = path.join(pluginsDir, p, 'skills');
|
|
1391
|
+
if (fs.existsSync(pSkillsDir)) {
|
|
1392
|
+
const pSkills = fs.readdirSync(pSkillsDir, { withFileTypes: true })
|
|
1393
|
+
.filter(d => d.isDirectory())
|
|
1394
|
+
.map(d => d.name);
|
|
1395
|
+
for (const skill of pSkills) {
|
|
1396
|
+
const skillMd = path.join(pSkillsDir, skill, 'SKILL.md');
|
|
1397
|
+
let desc = '';
|
|
1398
|
+
let fullContent = '';
|
|
1399
|
+
if (fs.existsSync(skillMd)) {
|
|
1400
|
+
fullContent = fs.readFileSync(skillMd, 'utf8');
|
|
1401
|
+
const match = fullContent.match(/description:\s*>?-?\s*([^\n\r]+)/);
|
|
1402
|
+
if (match) desc = match[1].trim();
|
|
1403
|
+
}
|
|
1404
|
+
if (skill.toLowerCase().includes(q) || desc.toLowerCase().includes(q) || fullContent.toLowerCase().includes(q)) {
|
|
1405
|
+
results.skills.push({ name: `${skill} [${p}]`, description: desc || 'Plugin progressive skill' });
|
|
1406
|
+
}
|
|
1407
|
+
}
|
|
1408
|
+
}
|
|
1409
|
+
}
|
|
1410
|
+
}
|
|
1411
|
+
|
|
1412
|
+
// 2. Search Subagents
|
|
1413
|
+
const agentsDir = path.join(REPO_ROOT, 'agents');
|
|
1414
|
+
if (fs.existsSync(agentsDir)) {
|
|
1415
|
+
const agents = fs.readdirSync(agentsDir).filter(f => f.endsWith('.md'));
|
|
1416
|
+
for (const ag of agents) {
|
|
1417
|
+
const name = ag.replace('.md', '');
|
|
1418
|
+
const content = fs.readFileSync(path.join(agentsDir, ag), 'utf8');
|
|
1419
|
+
const missionMatch = content.match(/## Role & Mission\s+([^\n\r]+)/);
|
|
1420
|
+
const mission = missionMatch ? missionMatch[1].trim() : '';
|
|
1421
|
+
if (name.toLowerCase().includes(q) || content.toLowerCase().includes(q)) {
|
|
1422
|
+
results.subagents.push({ name, description: mission || 'Scoped autonomous subagent' });
|
|
1423
|
+
}
|
|
1424
|
+
}
|
|
1425
|
+
}
|
|
1426
|
+
|
|
1427
|
+
// 3. Search Lifecycle Hooks
|
|
1428
|
+
const hooksDir = path.join(REPO_ROOT, 'hooks');
|
|
1429
|
+
if (fs.existsSync(hooksDir)) {
|
|
1430
|
+
const hooks = fs.readdirSync(hooksDir, { withFileTypes: true })
|
|
1431
|
+
.filter(d => d.isDirectory())
|
|
1432
|
+
.map(d => d.name);
|
|
1433
|
+
for (const h of hooks) {
|
|
1434
|
+
const hJson = path.join(hooksDir, h, 'hooks.json');
|
|
1435
|
+
let desc = 'Lifecycle safety gate';
|
|
1436
|
+
if (fs.existsSync(hJson)) {
|
|
1437
|
+
try {
|
|
1438
|
+
const parsed = JSON.parse(fs.readFileSync(hJson, 'utf8'));
|
|
1439
|
+
if (parsed.description) desc = parsed.description;
|
|
1440
|
+
} catch (_) {}
|
|
1441
|
+
}
|
|
1442
|
+
if (h.toLowerCase().includes(q) || desc.toLowerCase().includes(q)) {
|
|
1443
|
+
results.hooks.push({ name: h, description: desc });
|
|
1444
|
+
}
|
|
1445
|
+
}
|
|
1446
|
+
}
|
|
1447
|
+
|
|
1448
|
+
// 4. Search MCP Blueprints
|
|
1449
|
+
const mcpExamplePath = path.join(REPO_ROOT, 'mcp', 'mcp_config.example.json');
|
|
1450
|
+
if (fs.existsSync(mcpExamplePath)) {
|
|
1451
|
+
try {
|
|
1452
|
+
const mcpConfig = JSON.parse(fs.readFileSync(mcpExamplePath, 'utf8'));
|
|
1453
|
+
for (const [srvName, cfg] of Object.entries(mcpConfig.mcpServers || {})) {
|
|
1454
|
+
const cmdStr = `${srvName} ${cfg.command || ''} ${(cfg.args || []).join(' ')}`;
|
|
1455
|
+
if (cmdStr.toLowerCase().includes(q)) {
|
|
1456
|
+
results.mcp.push({ name: srvName, description: (cfg.args || []).join(' ') || cfg.command });
|
|
1457
|
+
}
|
|
1458
|
+
}
|
|
1459
|
+
} catch (_) {}
|
|
1460
|
+
}
|
|
1461
|
+
|
|
1462
|
+
const totalMatches = results.skills.length + results.subagents.length + results.hooks.length + results.mcp.length;
|
|
1463
|
+
|
|
1464
|
+
if (asJson) {
|
|
1465
|
+
console.log(JSON.stringify({ query, totalMatches, results }, null, 2));
|
|
1466
|
+
return;
|
|
1467
|
+
}
|
|
1468
|
+
|
|
1469
|
+
printBanner();
|
|
1470
|
+
console.log(`${BOLD}🔎 Search Results for: "${CYAN}${query}${RESET}${BOLD}" (${GREEN}${totalMatches} found${RESET}${BOLD})${RESET}\n`);
|
|
1471
|
+
|
|
1472
|
+
if (totalMatches === 0) {
|
|
1473
|
+
console.log(` ${YELLOW}○ No matching components found.${RESET}`);
|
|
1474
|
+
console.log(` Run ${GREEN}everything-gemini list${RESET} to browse all 48 skills, 10 subagents, and 7 hooks.\n`);
|
|
1475
|
+
return;
|
|
1476
|
+
}
|
|
1477
|
+
|
|
1478
|
+
if (results.skills.length > 0) {
|
|
1479
|
+
console.log(`${CYAN}${BOLD}⚡ Progressive Skills (${results.skills.length}):${RESET}`);
|
|
1480
|
+
for (const s of results.skills) {
|
|
1481
|
+
console.log(` • ${BOLD}${s.name.padEnd(28)}${RESET} ${GRAY}${s.description}${RESET}`);
|
|
1482
|
+
console.log(` ${GREEN}Add:${RESET} everything-gemini add skill ${s.name.split(' ')[0]}`);
|
|
1483
|
+
}
|
|
1484
|
+
console.log('');
|
|
1485
|
+
}
|
|
1486
|
+
|
|
1487
|
+
if (results.subagents.length > 0) {
|
|
1488
|
+
console.log(`${CYAN}${BOLD}🤖 Scoped Subagents (${results.subagents.length}):${RESET}`);
|
|
1489
|
+
for (const a of results.subagents) {
|
|
1490
|
+
console.log(` • ${BOLD}${a.name.padEnd(28)}${RESET} ${GRAY}${a.description}${RESET}`);
|
|
1491
|
+
console.log(` ${GREEN}Add:${RESET} everything-gemini add agent ${a.name}`);
|
|
1492
|
+
}
|
|
1493
|
+
console.log('');
|
|
1494
|
+
}
|
|
1495
|
+
|
|
1496
|
+
if (results.hooks.length > 0) {
|
|
1497
|
+
console.log(`${CYAN}${BOLD}🛡️ Lifecycle Hooks (${results.hooks.length}):${RESET}`);
|
|
1498
|
+
for (const h of results.hooks) {
|
|
1499
|
+
console.log(` • ${BOLD}${h.name.padEnd(28)}${RESET} ${GRAY}${h.description}${RESET}`);
|
|
1500
|
+
console.log(` ${GREEN}Add:${RESET} everything-gemini add hook ${h.name}`);
|
|
1501
|
+
}
|
|
1502
|
+
console.log('');
|
|
1503
|
+
}
|
|
1504
|
+
|
|
1505
|
+
if (results.mcp.length > 0) {
|
|
1506
|
+
console.log(`${CYAN}${BOLD}🌐 MCP Blueprints (${results.mcp.length}):${RESET}`);
|
|
1507
|
+
for (const m of results.mcp) {
|
|
1508
|
+
console.log(` • ${BOLD}${m.name.padEnd(28)}${RESET} ${GRAY}${m.description}${RESET}`);
|
|
1509
|
+
}
|
|
1510
|
+
console.log('');
|
|
1511
|
+
}
|
|
1512
|
+
}
|
|
1513
|
+
|
|
1514
|
+
function runAudit(targetPath = null, isGlobal = false, asJson = false) {
|
|
1515
|
+
const targetDir = isGlobal
|
|
1516
|
+
? path.join(os.homedir(), '.gemini', 'config')
|
|
1517
|
+
: (targetPath ? path.resolve(targetPath) : (fs.existsSync(path.join(process.cwd(), '.agents')) ? path.join(process.cwd(), '.agents') : REPO_ROOT));
|
|
1518
|
+
|
|
1519
|
+
const isRepoAudit = (targetDir === REPO_ROOT);
|
|
1520
|
+
const auditReport = {
|
|
1521
|
+
target: targetDir,
|
|
1522
|
+
timestamp: new Date().toISOString(),
|
|
1523
|
+
isRepoCatalog: isRepoAudit,
|
|
1524
|
+
checks: [],
|
|
1525
|
+
passedCount: 0,
|
|
1526
|
+
warningCount: 0,
|
|
1527
|
+
errorCount: 0,
|
|
1528
|
+
valid: true,
|
|
1529
|
+
};
|
|
1530
|
+
|
|
1531
|
+
function addCheck(category, item, status, message, details = null) {
|
|
1532
|
+
if (status === 'error') auditReport.errorCount++;
|
|
1533
|
+
else if (status === 'warn') auditReport.warningCount++;
|
|
1534
|
+
else auditReport.passedCount++;
|
|
1535
|
+
auditReport.checks.push({ category, item, status, message, details });
|
|
1536
|
+
}
|
|
1537
|
+
|
|
1538
|
+
// 1. Audit Skills
|
|
1539
|
+
const skillsBase = isRepoAudit ? path.join(REPO_ROOT, 'skills') : path.join(targetDir, 'skills');
|
|
1540
|
+
if (fs.existsSync(skillsBase)) {
|
|
1541
|
+
const skillEntries = fs.readdirSync(skillsBase, { withFileTypes: true }).filter(d => d.isDirectory());
|
|
1542
|
+
for (const ent of skillEntries) {
|
|
1543
|
+
const skillFile = path.join(skillsBase, ent.name, 'SKILL.md');
|
|
1544
|
+
if (!fs.existsSync(skillFile)) {
|
|
1545
|
+
addCheck('skills', ent.name, 'error', 'Missing SKILL.md in directory');
|
|
1546
|
+
continue;
|
|
1547
|
+
}
|
|
1548
|
+
const raw = fs.readFileSync(skillFile, 'utf8');
|
|
1549
|
+
const lines = raw.split('\n');
|
|
1550
|
+
const parts = raw.split('---');
|
|
1551
|
+
if (parts.length < 3) {
|
|
1552
|
+
addCheck('skills', ent.name, 'error', 'Invalid or missing YAML frontmatter delimiters (---)');
|
|
1553
|
+
continue;
|
|
1554
|
+
}
|
|
1555
|
+
const frontmatter = parts[1];
|
|
1556
|
+
const nameMatch = frontmatter.match(/name:\s*([a-zA-Z0-9_-]+)/);
|
|
1557
|
+
const descMatch = frontmatter.match(/description:\s*>?-?\s*([^\n\r]+)/);
|
|
1558
|
+
|
|
1559
|
+
if (!nameMatch) {
|
|
1560
|
+
addCheck('skills', ent.name, 'error', "Missing 'name' field in YAML frontmatter");
|
|
1561
|
+
} else if (nameMatch[1].trim() !== ent.name) {
|
|
1562
|
+
addCheck('skills', ent.name, 'warn', `Frontmatter name '${nameMatch[1].trim()}' does not match directory '${ent.name}'`);
|
|
1563
|
+
}
|
|
1564
|
+
|
|
1565
|
+
if (!descMatch || !descMatch[1].trim()) {
|
|
1566
|
+
addCheck('skills', ent.name, 'error', "Missing 'description' trigger in YAML frontmatter");
|
|
1567
|
+
}
|
|
1568
|
+
|
|
1569
|
+
if (lines.length > 260) {
|
|
1570
|
+
addCheck('skills', ent.name, 'warn', `Runbook length exceeds 250 lines (${lines.length} lines); consider progressive disclosure sub-references`);
|
|
1571
|
+
} else {
|
|
1572
|
+
addCheck('skills', ent.name, 'pass', `Valid YAML frontmatter and runbook compliance (${lines.length} lines)`);
|
|
1573
|
+
}
|
|
1574
|
+
}
|
|
1575
|
+
}
|
|
1576
|
+
|
|
1577
|
+
// 2. Audit Scoped Subagents
|
|
1578
|
+
const agentsBase = isRepoAudit ? path.join(REPO_ROOT, 'agents') : path.join(targetDir, 'agents');
|
|
1579
|
+
if (fs.existsSync(agentsBase)) {
|
|
1580
|
+
const agentFiles = fs.readdirSync(agentsBase).filter(f => f.endsWith('.md'));
|
|
1581
|
+
for (const f of agentFiles) {
|
|
1582
|
+
const agentPath = path.join(agentsBase, f);
|
|
1583
|
+
const content = fs.readFileSync(agentPath, 'utf8');
|
|
1584
|
+
const hasRole = /#+\s*(Core Role|Role & Mission)/i.test(content);
|
|
1585
|
+
const hasGuardrails = /#+\s*(Execution Guardrails|Tool Permissions)/i.test(content);
|
|
1586
|
+
const hasProtocol = /#+\s*(Delegation Protocol|Protocol|Handoff)/i.test(content);
|
|
1587
|
+
|
|
1588
|
+
if (hasRole && hasGuardrails && hasProtocol) {
|
|
1589
|
+
addCheck('subagents', f, 'pass', 'Complies with Subagent Specification Contract (Role, Guardrails, Handoff)');
|
|
1590
|
+
} else {
|
|
1591
|
+
const missing = [];
|
|
1592
|
+
if (!hasRole) missing.push('Role & Mission');
|
|
1593
|
+
if (!hasGuardrails) missing.push('Guardrails / Tool Permissions');
|
|
1594
|
+
if (!hasProtocol) missing.push('Handoff / Protocol');
|
|
1595
|
+
addCheck('subagents', f, 'error', `Missing required specification sections: ${missing.join(', ')}`);
|
|
1596
|
+
}
|
|
1597
|
+
}
|
|
1598
|
+
}
|
|
1599
|
+
|
|
1600
|
+
// 3. Audit Lifecycle Hooks
|
|
1601
|
+
const hooksBase = isRepoAudit ? path.join(REPO_ROOT, 'hooks') : path.join(targetDir, 'hooks');
|
|
1602
|
+
if (fs.existsSync(hooksBase)) {
|
|
1603
|
+
const hookDirs = fs.readdirSync(hooksBase, { withFileTypes: true }).filter(d => d.isDirectory());
|
|
1604
|
+
for (const hd of hookDirs) {
|
|
1605
|
+
const scriptsDir = path.join(hooksBase, hd.name, 'scripts');
|
|
1606
|
+
if (fs.existsSync(scriptsDir)) {
|
|
1607
|
+
const scripts = fs.readdirSync(scriptsDir).filter(s => s.endsWith('.sh'));
|
|
1608
|
+
for (const s of scripts) {
|
|
1609
|
+
const sPath = path.join(scriptsDir, s);
|
|
1610
|
+
try {
|
|
1611
|
+
fs.accessSync(sPath, fs.constants.X_OK);
|
|
1612
|
+
addCheck('hooks', `${hd.name}/${s}`, 'pass', 'Hook script is executable (+x)');
|
|
1613
|
+
} catch {
|
|
1614
|
+
addCheck('hooks', `${hd.name}/${s}`, 'error', 'Hook script lacks executable permissions (chmod +x)');
|
|
1615
|
+
}
|
|
1616
|
+
}
|
|
1617
|
+
}
|
|
1618
|
+
}
|
|
1619
|
+
}
|
|
1620
|
+
|
|
1621
|
+
auditReport.valid = (auditReport.errorCount === 0);
|
|
1622
|
+
|
|
1623
|
+
if (asJson) {
|
|
1624
|
+
console.log(JSON.stringify(auditReport, null, 2));
|
|
1625
|
+
if (!auditReport.valid) process.exit(1);
|
|
1626
|
+
return;
|
|
1627
|
+
}
|
|
1628
|
+
|
|
1629
|
+
printBanner();
|
|
1630
|
+
console.log(`${BOLD}🛡️ Everything Gemini Ecosystem Audit Report${RESET}`);
|
|
1631
|
+
console.log(`Target: ${CYAN}${targetDir}${RESET} ${isRepoAudit ? `${YELLOW}(Master Repository Catalog)${RESET}` : ''}\n`);
|
|
1632
|
+
|
|
1633
|
+
const categories = ['skills', 'subagents', 'hooks'];
|
|
1634
|
+
for (const cat of categories) {
|
|
1635
|
+
const items = auditReport.checks.filter(c => c.category === cat);
|
|
1636
|
+
if (items.length === 0) continue;
|
|
1637
|
+
|
|
1638
|
+
const catTitle = cat === 'skills' ? '⚡ Progressive Skills' :
|
|
1639
|
+
cat === 'subagents' ? '🤖 Scoped Subagents' : '🛡️ Lifecycle Hooks';
|
|
1640
|
+
console.log(`${BOLD}${catTitle} (${items.length}):${RESET}`);
|
|
1641
|
+
for (const it of items) {
|
|
1642
|
+
const icon = it.status === 'pass' ? `${GREEN}✔${RESET}` :
|
|
1643
|
+
it.status === 'warn' ? `${YELLOW}▲${RESET}` : `${RED}✘${RESET}`;
|
|
1644
|
+
console.log(` ${icon} ${it.item.padEnd(32)} ${it.message}`);
|
|
1645
|
+
}
|
|
1646
|
+
console.log('');
|
|
1647
|
+
}
|
|
1648
|
+
|
|
1649
|
+
console.log(`${BOLD}✨ Audit Summary:${RESET}`);
|
|
1650
|
+
console.log(` Passed Checks: ${GREEN}${auditReport.passedCount}${RESET}`);
|
|
1651
|
+
console.log(` Warnings: ${auditReport.warningCount > 0 ? YELLOW : GREEN}${auditReport.warningCount}${RESET}`);
|
|
1652
|
+
console.log(` Errors: ${auditReport.errorCount > 0 ? RED : GREEN}${auditReport.errorCount}${RESET}\n`);
|
|
1653
|
+
|
|
1654
|
+
if (auditReport.valid) {
|
|
1655
|
+
console.log(` ${GREEN}${BOLD}✔ ALL CHECKS PASSED: Target is 100% compliant with Antigravity Progressive Disclosure standards!${RESET}\n`);
|
|
1656
|
+
} else {
|
|
1657
|
+
console.log(` ${RED}${BOLD}✘ AUDIT FAILED: ${auditReport.errorCount} blocking errors found.${RESET}\n`);
|
|
1658
|
+
process.exit(1);
|
|
1659
|
+
}
|
|
1660
|
+
}
|
|
1661
|
+
|
|
1662
|
+
function testAllSkills(asJson = false) {
|
|
1663
|
+
const startTime = Date.now();
|
|
1664
|
+
let skillCount = 0;
|
|
1665
|
+
let totalChars = 0;
|
|
1666
|
+
const skillsGathered = [];
|
|
1667
|
+
|
|
1668
|
+
// 1. Core Skills
|
|
1669
|
+
const skillsDir = path.join(REPO_ROOT, 'skills');
|
|
1670
|
+
const skills = fs.readdirSync(skillsDir, { withFileTypes: true })
|
|
1671
|
+
.filter(d => d.isDirectory())
|
|
1672
|
+
.map(d => d.name)
|
|
1673
|
+
.sort();
|
|
1674
|
+
|
|
1675
|
+
if (!asJson) {
|
|
1676
|
+
printBanner();
|
|
1677
|
+
console.log(`${BOLD}🧪 Benchmarking & Validating All Skills, Subagents & Hooks...${RESET}\n`);
|
|
1678
|
+
console.log(`${CYAN}${BOLD}⚡ Skills Validation (Progressive Disclosure):${RESET}`);
|
|
1679
|
+
}
|
|
1680
|
+
|
|
1681
|
+
for (const s of skills) {
|
|
1682
|
+
const md = path.join(skillsDir, s, 'SKILL.md');
|
|
1683
|
+
if (fs.existsSync(md)) {
|
|
1684
|
+
const content = fs.readFileSync(md, 'utf8');
|
|
1685
|
+
totalChars += content.length;
|
|
1686
|
+
skillCount++;
|
|
1687
|
+
const estTokens = Math.round(content.length / 4);
|
|
1688
|
+
skillsGathered.push({ name: s, plugin: null, tokens: estTokens });
|
|
1689
|
+
if (!asJson) {
|
|
1690
|
+
console.log(` ${GREEN}✔${RESET} ${s.padEnd(30)} ${GRAY}(~${estTokens} tokens)${RESET}`);
|
|
1691
|
+
}
|
|
1692
|
+
}
|
|
1693
|
+
}
|
|
1694
|
+
|
|
1695
|
+
// 2. Plugin Skills
|
|
1696
|
+
const pluginsDir = path.join(REPO_ROOT, 'plugins');
|
|
1697
|
+
if (fs.existsSync(pluginsDir)) {
|
|
1698
|
+
const plugins = fs.readdirSync(pluginsDir, { withFileTypes: true })
|
|
1699
|
+
.filter(d => d.isDirectory())
|
|
1700
|
+
.map(d => d.name)
|
|
1701
|
+
.sort();
|
|
1702
|
+
for (const p of plugins) {
|
|
1703
|
+
const pSkillsDir = path.join(pluginsDir, p, 'skills');
|
|
1704
|
+
if (fs.existsSync(pSkillsDir)) {
|
|
1705
|
+
const pSkills = fs.readdirSync(pSkillsDir, { withFileTypes: true })
|
|
1706
|
+
.filter(d => d.isDirectory())
|
|
1707
|
+
.map(d => d.name)
|
|
1708
|
+
.sort();
|
|
1709
|
+
for (const s of pSkills) {
|
|
1710
|
+
const md = path.join(pSkillsDir, s, 'SKILL.md');
|
|
1711
|
+
if (fs.existsSync(md)) {
|
|
1712
|
+
const content = fs.readFileSync(md, 'utf8');
|
|
1713
|
+
totalChars += content.length;
|
|
1714
|
+
skillCount++;
|
|
1715
|
+
const estTokens = Math.round(content.length / 4);
|
|
1716
|
+
skillsGathered.push({ name: s, plugin: p, tokens: estTokens });
|
|
1717
|
+
if (!asJson) {
|
|
1718
|
+
console.log(` ${GREEN}✔${RESET} ${(`${s} [${p}]`).padEnd(30)} ${GRAY}(~${estTokens} tokens)${RESET}`);
|
|
1719
|
+
}
|
|
1720
|
+
}
|
|
1721
|
+
}
|
|
1722
|
+
}
|
|
1723
|
+
}
|
|
1724
|
+
}
|
|
1725
|
+
|
|
1726
|
+
// 3. Subagents
|
|
1727
|
+
if (!asJson) console.log(`\n${CYAN}${BOLD}🤖 Scoped Subagents Validation:${RESET}`);
|
|
1728
|
+
const agentsDir = path.join(REPO_ROOT, 'agents');
|
|
1729
|
+
const agents = fs.readdirSync(agentsDir).filter(f => f.endsWith('.md')).sort().map(f => f.replace('.md', ''));
|
|
1730
|
+
if (!asJson) {
|
|
1731
|
+
for (const a of agents) {
|
|
1732
|
+
console.log(` ${GREEN}✔${RESET} ${a.padEnd(30)}`);
|
|
1733
|
+
}
|
|
1734
|
+
}
|
|
1735
|
+
|
|
1736
|
+
// 4. Lifecycle Hooks
|
|
1737
|
+
if (!asJson) console.log(`\n${CYAN}${BOLD}🛡️ Lifecycle Hooks Validation:${RESET}`);
|
|
1738
|
+
const hooksDir = path.join(REPO_ROOT, 'hooks');
|
|
1739
|
+
const hooks = fs.readdirSync(hooksDir, { withFileTypes: true })
|
|
1740
|
+
.filter(d => d.isDirectory())
|
|
1741
|
+
.map(d => d.name)
|
|
1742
|
+
.sort();
|
|
1743
|
+
if (!asJson) {
|
|
1744
|
+
for (const h of hooks) {
|
|
1745
|
+
console.log(` ${GREEN}✔${RESET} ${h.padEnd(30)}`);
|
|
1746
|
+
}
|
|
1747
|
+
}
|
|
1748
|
+
|
|
1749
|
+
const duration = ((Date.now() - startTime) / 1000).toFixed(2);
|
|
1750
|
+
const totalTokens = Math.round(totalChars / 4);
|
|
1751
|
+
const tokenSavings = Math.round(totalTokens * 0.85);
|
|
1752
|
+
|
|
1753
|
+
if (asJson) {
|
|
1754
|
+
console.log(JSON.stringify({
|
|
1755
|
+
version: VERSION,
|
|
1756
|
+
totalComponents: skillCount + agents.length + hooks.length,
|
|
1757
|
+
progressiveSkillsCount: skillCount,
|
|
1758
|
+
scopedAgentsCount: agents.length,
|
|
1759
|
+
lifecycleHooksCount: hooks.length,
|
|
1760
|
+
totalRunbookTokens: totalTokens,
|
|
1761
|
+
estimatedTokensSavedPerTurn: tokenSavings,
|
|
1762
|
+
latencySeconds: parseFloat(duration),
|
|
1763
|
+
skills: skillsGathered,
|
|
1764
|
+
agents,
|
|
1765
|
+
hooks
|
|
1766
|
+
}, null, 2));
|
|
1767
|
+
return;
|
|
1768
|
+
}
|
|
1769
|
+
|
|
1770
|
+
console.log(`\n${GREEN}${BOLD}✨ Benchmark Summary:${RESET}`);
|
|
1771
|
+
console.log(` Total Components: ${BOLD}${skillCount + agents.length + hooks.length}${RESET}`);
|
|
1772
|
+
console.log(` Progressive Skills: ${BOLD}${skillCount}${RESET}`);
|
|
1773
|
+
console.log(` Total Runbook Tokens: ${BOLD}~${totalTokens.toLocaleString()}${RESET}`);
|
|
1774
|
+
console.log(` Estimated Tokens Saved / Turn: ${BOLD}~${tokenSavings.toLocaleString()} tokens (>85%)${RESET}`);
|
|
1775
|
+
console.log(` Diagnostic Latency: ${BOLD}${duration}s${RESET}\n`);
|
|
1776
|
+
}
|
|
1777
|
+
|
|
1778
|
+
function printCompletion(installMode = false, isDryRun = false, customRc = null) {
|
|
1779
|
+
const script = `
|
|
1780
|
+
# Everything Gemini Bash/Zsh completion
|
|
1781
|
+
_everything_gemini() {
|
|
1782
|
+
local cur prev commands skills agents hooks plugins
|
|
1783
|
+
COMPREPLY=()
|
|
1784
|
+
cur="\${COMP_WORDS[COMP_CWORD]}"
|
|
1785
|
+
prev="\${COMP_WORDS[COMP_CWORD-1]}"
|
|
1786
|
+
commands="doctor list init install status check update new-skill new-agent add remove test-skill test-all benchmark info show completion validate version help diff export import bundle pack search find audit"
|
|
1787
|
+
skills="agent-evals ai-first-engineering apache-kafka-streams api-craftsman architecture-designer argo-workflows axum-web-service browser-qa-tester cilium-ebpf-networking clickhouse-analytics cloudflare-workers context-caching continuous-learning database-architect dbt-transformation debezium-cdc devops-pipeline docker-compose-orchestrator duckdb-local-olap fastapi-production fullstack-nextjs gemini-function-calling gemini-grounding gemini-multimodal git-craftsman github-ops graphql-architect grpc-connect-rpc kubernetes-operator langgraph-orchestrator litellm-proxy-gateway nats-jetstream open-telemetry-tracing performance-profiler playwright-visual-regression rag-architect redis-cache-patterns repo-onboarding root-cause-debugger security-audit stripe-integration subagent-handoff supabase-architect svelte-kit-architect tdd-workflow temporal-workflows trpc-react-query turborepo-monorepo vllm-inference wasm-rust-optimizer antigravity-sdk-orchestrator responsive-design"
|
|
1788
|
+
agents="architect browser-qa build-repair code-reviewer database-migrator documentation-writer incident-responder performance-tuner planner release-engineer security-auditor"
|
|
1789
|
+
hooks="auto-lint-formatter ephemeral-context gemini-shield goal-verifier learned-instincts safety-shield secret-scrubber"
|
|
1790
|
+
plugins="core python-ai security-shield web-fullstack"
|
|
1791
|
+
|
|
1792
|
+
case "\${prev}" in
|
|
1793
|
+
everything-gemini|eagy|egemini)
|
|
1794
|
+
COMPREPLY=( $(compgen -W "\${commands}" -- "\${cur}") )
|
|
1795
|
+
return 0
|
|
1796
|
+
;;
|
|
1797
|
+
add|remove)
|
|
1798
|
+
COMPREPLY=( $(compgen -W "skill agent hook plugin" -- "\${cur}") )
|
|
1799
|
+
return 0
|
|
1800
|
+
;;
|
|
1801
|
+
skill|test-skill)
|
|
1802
|
+
COMPREPLY=( $(compgen -W "\${skills}" -- "\${cur}") )
|
|
1803
|
+
return 0
|
|
1804
|
+
;;
|
|
1805
|
+
agent)
|
|
1806
|
+
COMPREPLY=( $(compgen -W "\${agents}" -- "\${cur}") )
|
|
1807
|
+
return 0
|
|
1808
|
+
;;
|
|
1809
|
+
hook)
|
|
1810
|
+
COMPREPLY=( $(compgen -W "\${hooks}" -- "\${cur}") )
|
|
1811
|
+
return 0
|
|
1812
|
+
;;
|
|
1813
|
+
plugin)
|
|
1814
|
+
COMPREPLY=( $(compgen -W "\${plugins}" -- "\${cur}") )
|
|
1815
|
+
return 0
|
|
1816
|
+
;;
|
|
1817
|
+
info|show|search|find|audit)
|
|
1818
|
+
COMPREPLY=( $(compgen -W "\${skills} \${agents} \${hooks} \${plugins}" -- "\${cur}") )
|
|
1819
|
+
return 0
|
|
1820
|
+
;;
|
|
1821
|
+
--profile)
|
|
1822
|
+
COMPREPLY=( $(compgen -W "core developer full" -- "\${cur}") )
|
|
1823
|
+
return 0
|
|
1824
|
+
;;
|
|
1825
|
+
esac
|
|
1826
|
+
}
|
|
1827
|
+
complete -F _everything_gemini everything-gemini egemini eagy
|
|
1828
|
+
`.trim();
|
|
1829
|
+
|
|
1830
|
+
if (!installMode) {
|
|
1831
|
+
console.log(script);
|
|
1832
|
+
return;
|
|
1833
|
+
}
|
|
1834
|
+
|
|
1835
|
+
printBanner();
|
|
1836
|
+
console.log(`${BOLD}🐚 Shell Autocompletion Installer${RESET}\n`);
|
|
1837
|
+
|
|
1838
|
+
let targetRc = customRc;
|
|
1839
|
+
if (!targetRc) {
|
|
1840
|
+
const isZsh = (process.env.SHELL && process.env.SHELL.includes('zsh')) || fs.existsSync(path.join(os.homedir(), '.zshrc'));
|
|
1841
|
+
targetRc = isZsh ? path.join(os.homedir(), '.zshrc') : path.join(os.homedir(), '.bashrc');
|
|
1842
|
+
}
|
|
1843
|
+
|
|
1844
|
+
if (fs.existsSync(targetRc)) {
|
|
1845
|
+
const currentContent = fs.readFileSync(targetRc, 'utf8');
|
|
1846
|
+
if (currentContent.includes('_everything_gemini()')) {
|
|
1847
|
+
console.log(` ${YELLOW}ℹ${RESET} Autocompletion is already configured in ${BOLD}${targetRc}${RESET}`);
|
|
1848
|
+
console.log(` To reload, run: ${GREEN}source ${targetRc}${RESET}\n`);
|
|
1849
|
+
return;
|
|
1850
|
+
}
|
|
1851
|
+
}
|
|
1852
|
+
|
|
1853
|
+
if (isDryRun) {
|
|
1854
|
+
console.log(` ${CYAN}[DRY RUN]${RESET} Would append completion script to: ${BOLD}${targetRc}${RESET}\n`);
|
|
1855
|
+
return;
|
|
1856
|
+
}
|
|
1857
|
+
|
|
1858
|
+
const payload = `\n\n# Everything Gemini Autocompletion\n${script}\n`;
|
|
1859
|
+
fs.appendFileSync(targetRc, payload, 'utf8');
|
|
1860
|
+
console.log(` ${GREEN}✔${RESET} Successfully installed autocompletion into: ${BOLD}${targetRc}${RESET}`);
|
|
1861
|
+
console.log(`\n${GREEN}${BOLD}✨ Ready! Reload your shell with:${RESET}`);
|
|
1862
|
+
console.log(` ${CYAN}source ${targetRc}${RESET}\n`);
|
|
1863
|
+
}
|
|
1864
|
+
|
|
1865
|
+
function showComponentInfo(query1, query2) {
|
|
1866
|
+
let target = query1;
|
|
1867
|
+
let explicitType = null;
|
|
1868
|
+
if (['skill', 'agent', 'hook', 'plugin'].includes(query1) && query2) {
|
|
1869
|
+
explicitType = query1;
|
|
1870
|
+
target = query2;
|
|
1871
|
+
}
|
|
1872
|
+
if (!target) {
|
|
1873
|
+
console.error(`\n${RED}Error: Please specify a component name.${RESET}`);
|
|
1874
|
+
console.log(`Usage: everything-gemini info [skill|agent|hook] <name>\n`);
|
|
661
1875
|
process.exit(1);
|
|
662
1876
|
}
|
|
663
1877
|
|
|
664
|
-
const cleanName =
|
|
1878
|
+
const cleanName = target.trim().toLowerCase().replace(/^(skills|agents|hooks)\//, '');
|
|
1879
|
+
|
|
1880
|
+
// 1. Check Subagents if type is agent or undefined
|
|
1881
|
+
if (!explicitType || explicitType === 'agent') {
|
|
1882
|
+
const agentMd = path.join(REPO_ROOT, 'agents', `${cleanName}.md`);
|
|
1883
|
+
if (fs.existsSync(agentMd)) {
|
|
1884
|
+
printBanner();
|
|
1885
|
+
console.log(`${BOLD}🤖 Subagent Specification: ${CYAN}${cleanName}${RESET}`);
|
|
1886
|
+
console.log(`Path: ${GRAY}${agentMd}${RESET}\n`);
|
|
1887
|
+
const content = fs.readFileSync(agentMd, 'utf8');
|
|
1888
|
+
const lines = content.split('\n').slice(0, 25);
|
|
1889
|
+
console.log(lines.join('\n'));
|
|
1890
|
+
if (content.split('\n').length > 25) {
|
|
1891
|
+
console.log(`\n${GRAY}... (${content.split('\n').length - 25} more lines in ${agentMd})${RESET}`);
|
|
1892
|
+
}
|
|
1893
|
+
console.log('');
|
|
1894
|
+
return;
|
|
1895
|
+
}
|
|
1896
|
+
}
|
|
1897
|
+
|
|
1898
|
+
// 2. Check Hooks if type is hook or undefined
|
|
1899
|
+
if (!explicitType || explicitType === 'hook') {
|
|
1900
|
+
const hookDir = path.join(REPO_ROOT, 'hooks', cleanName);
|
|
1901
|
+
const hookJson = path.join(hookDir, 'hooks.json');
|
|
1902
|
+
if (fs.existsSync(hookJson)) {
|
|
1903
|
+
printBanner();
|
|
1904
|
+
console.log(`${BOLD}🛡️ Lifecycle Hook: ${CYAN}${cleanName}${RESET}`);
|
|
1905
|
+
console.log(`Directory: ${GRAY}${hookDir}${RESET}\n`);
|
|
1906
|
+
try {
|
|
1907
|
+
const parsed = JSON.parse(fs.readFileSync(hookJson, 'utf8'));
|
|
1908
|
+
console.log(`${BOLD}Configuration (hooks.json):${RESET}`);
|
|
1909
|
+
console.log(JSON.stringify(parsed, null, 2));
|
|
1910
|
+
} catch (e) {
|
|
1911
|
+
console.log(fs.readFileSync(hookJson, 'utf8'));
|
|
1912
|
+
}
|
|
1913
|
+
const scriptsDir = path.join(hookDir, 'scripts');
|
|
1914
|
+
if (fs.existsSync(scriptsDir)) {
|
|
1915
|
+
const scripts = fs.readdirSync(scriptsDir);
|
|
1916
|
+
console.log(`\n${BOLD}Hook Scripts:${RESET}`);
|
|
1917
|
+
scripts.forEach(s => console.log(` 🔧 scripts/${s}`));
|
|
1918
|
+
}
|
|
1919
|
+
console.log('');
|
|
1920
|
+
return;
|
|
1921
|
+
}
|
|
1922
|
+
}
|
|
1923
|
+
|
|
1924
|
+
// 3. Check Skills (Core or Plugin)
|
|
665
1925
|
let skillDir = path.join(REPO_ROOT, 'skills', cleanName);
|
|
666
1926
|
let pluginName = null;
|
|
667
1927
|
|
|
@@ -683,39 +1943,40 @@ function showSkillInfo(skillName) {
|
|
|
683
1943
|
}
|
|
684
1944
|
|
|
685
1945
|
const skillMd = path.join(skillDir, 'SKILL.md');
|
|
686
|
-
if (
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
printBanner();
|
|
692
|
-
console.log(`${BOLD}📖 Skill Overview: ${CYAN}${cleanName}${RESET}`);
|
|
693
|
-
if (pluginName) {
|
|
694
|
-
console.log(`Source Plugin: ${YELLOW}${pluginName}${RESET}`);
|
|
695
|
-
}
|
|
696
|
-
console.log(`Path: ${GRAY}${skillMd}${RESET}\n`);
|
|
697
|
-
|
|
698
|
-
const content = fs.readFileSync(skillMd, 'utf8');
|
|
699
|
-
const parts = content.split('---');
|
|
700
|
-
if (parts.length >= 3) {
|
|
701
|
-
const frontmatter = parts[1];
|
|
702
|
-
const descMatch = frontmatter.match(/description:\s*>?-?\s*([^\n\r]+)/);
|
|
703
|
-
if (descMatch) {
|
|
704
|
-
console.log(`${BOLD}🎯 Trigger Description:${RESET}`);
|
|
705
|
-
console.log(` ${descMatch[1].trim()}\n`);
|
|
1946
|
+
if (fs.existsSync(skillMd)) {
|
|
1947
|
+
printBanner();
|
|
1948
|
+
console.log(`${BOLD}📖 Skill Overview: ${CYAN}${cleanName}${RESET}`);
|
|
1949
|
+
if (pluginName) {
|
|
1950
|
+
console.log(`Source Plugin: ${YELLOW}${pluginName}${RESET}`);
|
|
706
1951
|
}
|
|
1952
|
+
console.log(`Path: ${GRAY}${skillMd}${RESET}\n`);
|
|
1953
|
+
|
|
1954
|
+
const content = fs.readFileSync(skillMd, 'utf8');
|
|
1955
|
+
const parts = content.split('---');
|
|
1956
|
+
if (parts.length >= 3) {
|
|
1957
|
+
const frontmatter = parts[1];
|
|
1958
|
+
const descMatch = frontmatter.match(/description:\s*>?-?\s*([^\n\r]+)/);
|
|
1959
|
+
if (descMatch) {
|
|
1960
|
+
console.log(`${BOLD}🎯 Trigger Description:${RESET}`);
|
|
1961
|
+
console.log(` ${descMatch[1].trim()}\n`);
|
|
1962
|
+
}
|
|
707
1963
|
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
1964
|
+
const body = parts.slice(2).join('---').trim();
|
|
1965
|
+
const lines = body.split('\n').slice(0, 22);
|
|
1966
|
+
console.log(`${BOLD}📋 Playbook Preview:${RESET}`);
|
|
1967
|
+
console.log(lines.join('\n'));
|
|
1968
|
+
if (body.split('\n').length > 22) {
|
|
1969
|
+
console.log(`\n${GRAY}... (${body.split('\n').length - 22} more lines in ${skillMd})${RESET}`);
|
|
1970
|
+
}
|
|
1971
|
+
} else {
|
|
1972
|
+
console.log(content.split('\n').slice(0, 25).join('\n'));
|
|
714
1973
|
}
|
|
715
|
-
|
|
716
|
-
|
|
1974
|
+
console.log('');
|
|
1975
|
+
return;
|
|
717
1976
|
}
|
|
718
|
-
|
|
1977
|
+
|
|
1978
|
+
console.error(`\n${RED}Error: Component '${cleanName}' not found in catalog (checked skills, agents, and hooks).${RESET}\n`);
|
|
1979
|
+
process.exit(1);
|
|
719
1980
|
}
|
|
720
1981
|
|
|
721
1982
|
// CLI Argument Parsing
|
|
@@ -735,35 +1996,169 @@ switch (command) {
|
|
|
735
1996
|
case 'new-agent':
|
|
736
1997
|
scaffoldAgent(args[1]);
|
|
737
1998
|
break;
|
|
738
|
-
case 'add':
|
|
739
|
-
|
|
1999
|
+
case 'add': {
|
|
2000
|
+
let customTarget = null;
|
|
2001
|
+
let isGlobal = false;
|
|
2002
|
+
for (let i = 3; i < args.length; i++) {
|
|
2003
|
+
if (args[i] === '--global') isGlobal = true;
|
|
2004
|
+
else if (args[i] === '--workspace' && args[i + 1]) customTarget = args[++i];
|
|
2005
|
+
}
|
|
2006
|
+
addComponent(args[1], args[2], isGlobal, customTarget);
|
|
740
2007
|
break;
|
|
741
|
-
|
|
742
|
-
|
|
2008
|
+
}
|
|
2009
|
+
case 'remove': {
|
|
2010
|
+
let customTarget = null;
|
|
2011
|
+
let isGlobal = false;
|
|
2012
|
+
for (let i = 3; i < args.length; i++) {
|
|
2013
|
+
if (args[i] === '--global') isGlobal = true;
|
|
2014
|
+
else if (args[i] === '--workspace' && args[i + 1]) customTarget = args[++i];
|
|
2015
|
+
}
|
|
2016
|
+
removeComponent(args[1], args[2], isGlobal, customTarget);
|
|
743
2017
|
break;
|
|
2018
|
+
}
|
|
744
2019
|
case 'test-skill':
|
|
745
2020
|
testSkill(args[1]);
|
|
746
2021
|
break;
|
|
2022
|
+
case 'test-all':
|
|
2023
|
+
case 'test-skills':
|
|
2024
|
+
case 'benchmark': {
|
|
2025
|
+
const asJson = args.includes('--json');
|
|
2026
|
+
testAllSkills(asJson);
|
|
2027
|
+
break;
|
|
2028
|
+
}
|
|
2029
|
+
case 'completion': {
|
|
2030
|
+
const installMode = args.includes('--install') || args.includes('-i');
|
|
2031
|
+
const isDryRun = args.includes('--dry-run');
|
|
2032
|
+
let customRc = null;
|
|
2033
|
+
for (let i = 1; i < args.length; i++) {
|
|
2034
|
+
if (args[i] === '--rc' && args[i + 1]) customRc = args[++i];
|
|
2035
|
+
}
|
|
2036
|
+
printCompletion(installMode, isDryRun, customRc);
|
|
2037
|
+
break;
|
|
2038
|
+
}
|
|
747
2039
|
case 'info':
|
|
748
2040
|
case 'show':
|
|
749
|
-
|
|
2041
|
+
showComponentInfo(args[1], args[2]);
|
|
2042
|
+
break;
|
|
2043
|
+
case 'status':
|
|
2044
|
+
case 'check': {
|
|
2045
|
+
let isGlobal = false;
|
|
2046
|
+
let customTarget = null;
|
|
2047
|
+
let asJson = false;
|
|
2048
|
+
for (let i = 1; i < args.length; i++) {
|
|
2049
|
+
if (args[i] === '--global') isGlobal = true;
|
|
2050
|
+
else if (args[i] === '--json') asJson = true;
|
|
2051
|
+
else if (args[i] === '--workspace' && args[i + 1]) customTarget = args[++i];
|
|
2052
|
+
}
|
|
2053
|
+
runStatus(isGlobal, customTarget, asJson);
|
|
2054
|
+
break;
|
|
2055
|
+
}
|
|
2056
|
+
case 'diff': {
|
|
2057
|
+
let isGlobal = false;
|
|
2058
|
+
let customTarget = null;
|
|
2059
|
+
for (let i = 1; i < args.length; i++) {
|
|
2060
|
+
if (args[i] === '--global') isGlobal = true;
|
|
2061
|
+
else if (args[i] === '--workspace' && args[i + 1]) customTarget = args[++i];
|
|
2062
|
+
}
|
|
2063
|
+
runDiff(isGlobal, customTarget);
|
|
2064
|
+
break;
|
|
2065
|
+
}
|
|
2066
|
+
case 'export': {
|
|
2067
|
+
let isGlobal = false;
|
|
2068
|
+
let customTarget = null;
|
|
2069
|
+
let outputPath = null;
|
|
2070
|
+
for (let i = 1; i < args.length; i++) {
|
|
2071
|
+
if (args[i] === '--global') isGlobal = true;
|
|
2072
|
+
else if (args[i] === '--workspace' && args[i + 1]) customTarget = args[++i];
|
|
2073
|
+
else if ((args[i] === '--output' || args[i] === '-o') && args[i + 1]) outputPath = args[++i];
|
|
2074
|
+
}
|
|
2075
|
+
runExport(isGlobal, customTarget, outputPath);
|
|
2076
|
+
break;
|
|
2077
|
+
}
|
|
2078
|
+
case 'import': {
|
|
2079
|
+
const inputFile = args[1] && !args[1].startsWith('-') ? args[1] : null;
|
|
2080
|
+
let isGlobal = false;
|
|
2081
|
+
let customTarget = null;
|
|
2082
|
+
let isDryRun = false;
|
|
2083
|
+
for (let i = 1; i < args.length; i++) {
|
|
2084
|
+
if (args[i] === '--global') isGlobal = true;
|
|
2085
|
+
else if (args[i] === '--dry-run') isDryRun = true;
|
|
2086
|
+
else if (args[i] === '--workspace' && args[i + 1]) customTarget = args[++i];
|
|
2087
|
+
}
|
|
2088
|
+
runImport(inputFile, isGlobal, customTarget, isDryRun);
|
|
750
2089
|
break;
|
|
2090
|
+
}
|
|
2091
|
+
case 'bundle':
|
|
2092
|
+
case 'pack': {
|
|
2093
|
+
let profile = 'all';
|
|
2094
|
+
let outputDir = null;
|
|
2095
|
+
let isDryRun = false;
|
|
2096
|
+
let asJson = false;
|
|
2097
|
+
for (let i = 1; i < args.length; i++) {
|
|
2098
|
+
if (args[i] === '--profile' && args[i + 1]) profile = args[++i];
|
|
2099
|
+
else if ((args[i] === '--output' || args[i] === '-o') && args[i + 1]) outputDir = args[++i];
|
|
2100
|
+
else if (args[i] === '--dry-run') isDryRun = true;
|
|
2101
|
+
else if (args[i] === '--json') asJson = true;
|
|
2102
|
+
else if (!args[i].startsWith('-') && !outputDir) outputDir = args[i];
|
|
2103
|
+
}
|
|
2104
|
+
runBundle(profile, outputDir, isDryRun, asJson);
|
|
2105
|
+
break;
|
|
2106
|
+
}
|
|
2107
|
+
case 'update': {
|
|
2108
|
+
let isGlobal = false;
|
|
2109
|
+
let customTarget = null;
|
|
2110
|
+
let isDryRun = false;
|
|
2111
|
+
for (let i = 1; i < args.length; i++) {
|
|
2112
|
+
if (args[i] === '--global') isGlobal = true;
|
|
2113
|
+
else if (args[i] === '--dry-run') isDryRun = true;
|
|
2114
|
+
else if (args[i] === '--workspace' && args[i + 1]) customTarget = args[++i];
|
|
2115
|
+
}
|
|
2116
|
+
runUpdate(isGlobal, customTarget, isDryRun);
|
|
2117
|
+
break;
|
|
2118
|
+
}
|
|
751
2119
|
case 'init':
|
|
752
2120
|
case 'install': {
|
|
753
2121
|
let profile = 'developer';
|
|
754
2122
|
let isGlobal = false;
|
|
755
2123
|
let customTarget = null;
|
|
2124
|
+
let isDryRun = false;
|
|
756
2125
|
for (let i = 1; i < args.length; i++) {
|
|
757
2126
|
if (args[i] === '--profile' && args[i + 1]) profile = args[++i];
|
|
758
2127
|
else if (args[i] === '--global') isGlobal = true;
|
|
2128
|
+
else if (args[i] === '--dry-run') isDryRun = true;
|
|
759
2129
|
else if (args[i] === '--workspace' && args[i + 1]) customTarget = args[++i];
|
|
760
2130
|
}
|
|
761
|
-
installProfile(profile, isGlobal, customTarget);
|
|
2131
|
+
installProfile(profile, isGlobal, customTarget, isDryRun);
|
|
762
2132
|
break;
|
|
763
2133
|
}
|
|
764
2134
|
case 'validate':
|
|
765
2135
|
runValidate();
|
|
766
2136
|
break;
|
|
2137
|
+
case 'search':
|
|
2138
|
+
case 'find': {
|
|
2139
|
+
const asJson = args.includes('--json');
|
|
2140
|
+
const queryTerms = args.slice(1).filter(a => !a.startsWith('-')).join(' ');
|
|
2141
|
+
searchComponents(queryTerms, asJson);
|
|
2142
|
+
break;
|
|
2143
|
+
}
|
|
2144
|
+
case 'audit': {
|
|
2145
|
+
let isGlobal = false;
|
|
2146
|
+
let customTarget = null;
|
|
2147
|
+
let asJson = false;
|
|
2148
|
+
for (let i = 1; i < args.length; i++) {
|
|
2149
|
+
if (args[i] === '--global') isGlobal = true;
|
|
2150
|
+
else if (args[i] === '--json') asJson = true;
|
|
2151
|
+
else if (args[i] === '--workspace' && args[i + 1]) customTarget = args[++i];
|
|
2152
|
+
else if (!args[i].startsWith('-') && !customTarget) customTarget = args[i];
|
|
2153
|
+
}
|
|
2154
|
+
runAudit(customTarget, isGlobal, asJson);
|
|
2155
|
+
break;
|
|
2156
|
+
}
|
|
2157
|
+
case 'version':
|
|
2158
|
+
case '--version':
|
|
2159
|
+
case '-v':
|
|
2160
|
+
console.log(VERSION);
|
|
2161
|
+
break;
|
|
767
2162
|
case 'help':
|
|
768
2163
|
case '--help':
|
|
769
2164
|
case '-h':
|