everything-gemini 1.1.1 → 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/.vscode/extensions.json +8 -0
- package/.vscode/settings.json +3 -0
- package/CHANGELOG.md +167 -0
- package/CONTRIBUTING.md +85 -4
- package/README.md +139 -18
- package/SECURITY.md +38 -0
- 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 +1550 -86
- package/docs/COMMUNITY_SUBMISSIONS.md +88 -0
- package/docs/LAUNCH_KIT.md +148 -22
- package/docs/architecture/progressive-disclosure.md +3 -3
- package/docs/index.html +401 -37
- package/docs/launch-kit.md +163 -0
- package/examples/cli-workflows/README.md +45 -0
- package/examples/cli-workflows/demo_workflow.sh +39 -0
- 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/agent-evals/SKILL.md +61 -0
- 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/docker-compose-orchestrator/SKILL.md +85 -0
- package/skills/duckdb-local-olap/SKILL.md +134 -0
- package/skills/fastapi-production/SKILL.md +157 -0
- package/skills/graphql-architect/SKILL.md +78 -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,19 +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`);
|
|
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)`);
|
|
54
65
|
console.log(` ${GREEN}validate${RESET} Run self-test on frontmatter, JSON schemas & hooks`);
|
|
55
|
-
console.log(` ${GREEN}
|
|
56
|
-
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}`);
|
|
57
69
|
console.log(` ${CYAN}--profile <core|developer|full>${RESET} Installation preset profile (default: developer)`);
|
|
58
|
-
console.log(` ${CYAN}--global${RESET}
|
|
59
|
-
console.log(` ${CYAN}--workspace <path>${RESET}
|
|
60
|
-
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`);
|
|
61
75
|
}
|
|
62
76
|
|
|
63
77
|
function runDoctor() {
|
|
@@ -189,13 +203,29 @@ function listComponents() {
|
|
|
189
203
|
if (item.isDirectory()) {
|
|
190
204
|
findRules(path.join(dir, item.name), `${prefix}${item.name}/`);
|
|
191
205
|
} else if (item.name.endsWith('.md')) {
|
|
192
|
-
console.log(` ${BOLD}${(prefix + item.name).padEnd(
|
|
206
|
+
console.log(` ${BOLD}${(prefix + item.name).padEnd(36)}${RESET}`);
|
|
193
207
|
}
|
|
194
208
|
}
|
|
195
209
|
}
|
|
196
210
|
findRules(rulesDir);
|
|
197
211
|
}
|
|
198
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
|
+
|
|
199
229
|
// Hooks
|
|
200
230
|
console.log(`\n${CYAN}${BOLD}🛡️ Lifecycle Hooks:${RESET}`);
|
|
201
231
|
const hooksDir = path.join(REPO_ROOT, 'hooks');
|
|
@@ -242,19 +272,26 @@ function copyRecursiveSync(src, dest) {
|
|
|
242
272
|
} else {
|
|
243
273
|
fs.mkdirSync(path.dirname(dest), { recursive: true });
|
|
244
274
|
fs.copyFileSync(src, dest);
|
|
275
|
+
if (src.endsWith('.sh') || (stats.mode && (stats.mode & 0o111))) {
|
|
276
|
+
try { fs.chmodSync(dest, 0o755); } catch (e) {}
|
|
277
|
+
}
|
|
245
278
|
}
|
|
246
279
|
}
|
|
247
280
|
|
|
248
|
-
function installProfile(profile = 'developer', isGlobal = false, customTarget = null) {
|
|
281
|
+
function installProfile(profile = 'developer', isGlobal = false, customTarget = null, isDryRun = false) {
|
|
249
282
|
printBanner();
|
|
250
283
|
const targetDir = customTarget
|
|
251
284
|
? path.resolve(customTarget)
|
|
252
285
|
: (isGlobal ? GLOBAL_CONFIG_DIR : AGENTS_DIR);
|
|
253
286
|
|
|
287
|
+
if (isDryRun) {
|
|
288
|
+
console.log(`${YELLOW}${BOLD}🔍 DRY RUN MODE ACTIVATED - No files will be modified on disk.${RESET}`);
|
|
289
|
+
}
|
|
290
|
+
|
|
254
291
|
console.log(`${BOLD}🚀 Installing everything-gemini Profile: [${GREEN}${profile}${RESET}${BOLD}]${RESET}`);
|
|
255
292
|
console.log(`Target Directory: ${CYAN}${targetDir}${RESET}\n`);
|
|
256
293
|
|
|
257
|
-
if (!fs.existsSync(targetDir)) {
|
|
294
|
+
if (!isDryRun && !fs.existsSync(targetDir)) {
|
|
258
295
|
fs.mkdirSync(targetDir, { recursive: true });
|
|
259
296
|
}
|
|
260
297
|
|
|
@@ -262,69 +299,103 @@ function installProfile(profile = 'developer', isGlobal = false, customTarget =
|
|
|
262
299
|
const targetSkills = path.join(targetDir, 'skills');
|
|
263
300
|
const targetRules = path.join(targetDir, 'rules');
|
|
264
301
|
const targetPlugins = path.join(targetDir, 'plugins');
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
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
|
+
}
|
|
268
308
|
|
|
269
309
|
const skillsSrc = path.join(REPO_ROOT, 'skills');
|
|
270
310
|
const rulesSrc = path.join(REPO_ROOT, 'rules');
|
|
271
311
|
const hooksSrc = path.join(REPO_ROOT, 'hooks');
|
|
272
312
|
const pluginsSrc = path.join(REPO_ROOT, 'plugins');
|
|
313
|
+
const agentsSrc = path.join(REPO_ROOT, 'agents');
|
|
273
314
|
|
|
274
315
|
// Copy Common Base Rules
|
|
275
316
|
const commonGemini = path.join(rulesSrc, 'common', 'GEMINI.md');
|
|
276
317
|
const commonAgents = path.join(rulesSrc, 'common', 'AGENTS.md');
|
|
277
318
|
if (fs.existsSync(commonGemini)) {
|
|
278
|
-
fs.copyFileSync(commonGemini, path.join(targetDir, 'GEMINI.md'));
|
|
279
|
-
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`);
|
|
280
321
|
}
|
|
281
322
|
if (fs.existsSync(commonAgents)) {
|
|
282
|
-
fs.copyFileSync(commonAgents, path.join(targetDir, 'AGENTS.md'));
|
|
283
|
-
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`);
|
|
284
325
|
}
|
|
285
326
|
|
|
286
|
-
//
|
|
327
|
+
// 1. Core Profile
|
|
287
328
|
if (profile === 'core' || profile === 'developer' || profile === 'full') {
|
|
288
|
-
// Core Skills
|
|
289
329
|
const coreSkills = ['tdd-workflow', 'repo-onboarding'];
|
|
290
330
|
for (const s of coreSkills) {
|
|
291
331
|
const src = path.join(skillsSrc, s);
|
|
292
332
|
if (fs.existsSync(src)) {
|
|
293
|
-
copyRecursiveSync(src, path.join(targetSkills, s));
|
|
294
|
-
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}`);
|
|
295
335
|
}
|
|
296
336
|
}
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
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`);
|
|
302
341
|
}
|
|
303
342
|
}
|
|
304
343
|
|
|
344
|
+
// 2. Developer Profile
|
|
305
345
|
if (profile === 'developer' || profile === 'full') {
|
|
306
|
-
|
|
307
|
-
|
|
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
|
+
];
|
|
308
359
|
for (const s of devSkills) {
|
|
309
360
|
const src = path.join(skillsSrc, s);
|
|
310
361
|
if (fs.existsSync(src)) {
|
|
311
|
-
copyRecursiveSync(src, path.join(targetSkills, s));
|
|
312
|
-
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}`);
|
|
313
364
|
}
|
|
314
365
|
}
|
|
315
366
|
|
|
316
367
|
// Developer Language Rules
|
|
317
368
|
const langRules = path.join(rulesSrc, 'languages');
|
|
318
369
|
if (fs.existsSync(langRules)) {
|
|
319
|
-
copyRecursiveSync(langRules, targetRules);
|
|
320
|
-
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)`);
|
|
321
372
|
}
|
|
322
373
|
|
|
323
374
|
// Auto-lint formatter hook
|
|
324
375
|
const lintHook = path.join(hooksSrc, 'auto-lint-formatter');
|
|
325
376
|
if (fs.existsSync(lintHook)) {
|
|
326
|
-
copyRecursiveSync(lintHook, path.join(targetDir, 'hooks', 'auto-lint-formatter'));
|
|
327
|
-
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/)`);
|
|
328
399
|
}
|
|
329
400
|
|
|
330
401
|
// Developer Plugins
|
|
@@ -332,58 +403,652 @@ function installProfile(profile = 'developer', isGlobal = false, customTarget =
|
|
|
332
403
|
for (const p of devPlugins) {
|
|
333
404
|
const src = path.join(pluginsSrc, p);
|
|
334
405
|
if (fs.existsSync(src)) {
|
|
335
|
-
copyRecursiveSync(src, path.join(targetPlugins, p));
|
|
336
|
-
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}`);
|
|
337
408
|
}
|
|
338
409
|
}
|
|
339
410
|
}
|
|
340
411
|
|
|
412
|
+
// 3. Full Power Profile
|
|
341
413
|
if (profile === 'full') {
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
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`);
|
|
345
419
|
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
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`);
|
|
349
422
|
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
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)`);
|
|
353
425
|
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
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
|
+
}
|
|
357
430
|
|
|
358
431
|
// MCP Config Example
|
|
359
432
|
const mcpExample = path.join(REPO_ROOT, 'mcp', 'mcp_config.example.json');
|
|
360
433
|
if (fs.existsSync(mcpExample)) {
|
|
361
|
-
fs.copyFileSync(mcpExample, path.join(targetDir, 'mcp_config.json'));
|
|
362
|
-
console.log(` ${GREEN}✔${RESET} Installed mcp_config.json`);
|
|
363
|
-
}
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
//
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
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}`);
|
|
379
610
|
}
|
|
380
|
-
|
|
611
|
+
}
|
|
381
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}`);
|
|
645
|
+
}
|
|
646
|
+
}
|
|
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
|
|
382
753
|
};
|
|
383
|
-
fs.writeFileSync(path.join(targetDir, 'hooks.json'), JSON.stringify(masterHooks, null, 2));
|
|
384
|
-
console.log(` ${GREEN}✔${RESET} Generated master hooks.json`);
|
|
385
754
|
|
|
386
|
-
|
|
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: []
|
|
929
|
+
};
|
|
930
|
+
|
|
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`);
|
|
387
1052
|
}
|
|
388
1053
|
|
|
389
1054
|
function runValidate() {
|
|
@@ -506,14 +1171,17 @@ Return structured report to parent agent:
|
|
|
506
1171
|
console.log(` 📄 ${targetFile}\n`);
|
|
507
1172
|
}
|
|
508
1173
|
|
|
509
|
-
function addComponent(type, name) {
|
|
1174
|
+
function addComponent(type, name, isGlobal = false, customTarget = null) {
|
|
510
1175
|
if (!type || !name) {
|
|
511
|
-
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}`);
|
|
512
1177
|
process.exit(1);
|
|
513
1178
|
}
|
|
514
1179
|
|
|
515
1180
|
const cleanName = name.trim().toLowerCase();
|
|
516
|
-
const targetWorkspace =
|
|
1181
|
+
const targetWorkspace = customTarget
|
|
1182
|
+
? path.resolve(customTarget)
|
|
1183
|
+
: (isGlobal ? GLOBAL_CONFIG_DIR : path.join(WORKSPACE_DIR, '.agents'));
|
|
1184
|
+
|
|
517
1185
|
if (!fs.existsSync(targetWorkspace)) {
|
|
518
1186
|
fs.mkdirSync(targetWorkspace, { recursive: true });
|
|
519
1187
|
}
|
|
@@ -537,6 +1205,21 @@ function addComponent(type, name) {
|
|
|
537
1205
|
fs.mkdirSync(destDir, { recursive: true });
|
|
538
1206
|
fs.copyFileSync(src, path.join(destDir, `${cleanName}.md`));
|
|
539
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}`);
|
|
540
1223
|
} else if (type === 'plugin') {
|
|
541
1224
|
const src = path.join(REPO_ROOT, 'plugins', cleanName);
|
|
542
1225
|
if (!fs.existsSync(src)) {
|
|
@@ -547,19 +1230,21 @@ function addComponent(type, name) {
|
|
|
547
1230
|
copyRecursiveSync(src, dest);
|
|
548
1231
|
console.log(`${GREEN}✔ Added plugin '${cleanName}' to ${dest}${RESET}`);
|
|
549
1232
|
} else {
|
|
550
|
-
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}`);
|
|
551
1234
|
process.exit(1);
|
|
552
1235
|
}
|
|
553
1236
|
}
|
|
554
1237
|
|
|
555
|
-
function removeComponent(type, name) {
|
|
1238
|
+
function removeComponent(type, name, isGlobal = false, customTarget = null) {
|
|
556
1239
|
if (!type || !name) {
|
|
557
|
-
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}`);
|
|
558
1241
|
process.exit(1);
|
|
559
1242
|
}
|
|
560
1243
|
|
|
561
1244
|
const cleanName = name.trim().toLowerCase();
|
|
562
|
-
const targetWorkspace =
|
|
1245
|
+
const targetWorkspace = customTarget
|
|
1246
|
+
? path.resolve(customTarget)
|
|
1247
|
+
: (isGlobal ? GLOBAL_CONFIG_DIR : path.join(WORKSPACE_DIR, '.agents'));
|
|
563
1248
|
|
|
564
1249
|
if (type === 'skill') {
|
|
565
1250
|
const dest = path.join(targetWorkspace, 'skills', cleanName);
|
|
@@ -568,7 +1253,7 @@ function removeComponent(type, name) {
|
|
|
568
1253
|
return;
|
|
569
1254
|
}
|
|
570
1255
|
fs.rmSync(dest, { recursive: true, force: true });
|
|
571
|
-
console.log(`${GREEN}✔ Removed skill '${cleanName}' from
|
|
1256
|
+
console.log(`${GREEN}✔ Removed skill '${cleanName}' from ${dest}.${RESET}`);
|
|
572
1257
|
} else if (type === 'agent') {
|
|
573
1258
|
const dest = path.join(targetWorkspace, 'agents', `${cleanName}.md`);
|
|
574
1259
|
if (!fs.existsSync(dest)) {
|
|
@@ -576,7 +1261,15 @@ function removeComponent(type, name) {
|
|
|
576
1261
|
return;
|
|
577
1262
|
}
|
|
578
1263
|
fs.unlinkSync(dest);
|
|
579
|
-
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}`);
|
|
580
1273
|
} else if (type === 'plugin') {
|
|
581
1274
|
const dest = path.join(targetWorkspace, 'plugins', cleanName);
|
|
582
1275
|
if (!fs.existsSync(dest)) {
|
|
@@ -584,9 +1277,9 @@ function removeComponent(type, name) {
|
|
|
584
1277
|
return;
|
|
585
1278
|
}
|
|
586
1279
|
fs.rmSync(dest, { recursive: true, force: true });
|
|
587
|
-
console.log(`${GREEN}✔ Removed plugin '${cleanName}' from
|
|
1280
|
+
console.log(`${GREEN}✔ Removed plugin '${cleanName}' from ${dest}.${RESET}`);
|
|
588
1281
|
} else {
|
|
589
|
-
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}`);
|
|
590
1283
|
process.exit(1);
|
|
591
1284
|
}
|
|
592
1285
|
}
|
|
@@ -653,6 +1346,639 @@ function testSkill(name) {
|
|
|
653
1346
|
console.log(`\n${GREEN}${BOLD}✨ Skill '${cleanName}' passed all validation checks!${RESET}\n`);
|
|
654
1347
|
}
|
|
655
1348
|
|
|
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`);
|
|
1875
|
+
process.exit(1);
|
|
1876
|
+
}
|
|
1877
|
+
|
|
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)
|
|
1925
|
+
let skillDir = path.join(REPO_ROOT, 'skills', cleanName);
|
|
1926
|
+
let pluginName = null;
|
|
1927
|
+
|
|
1928
|
+
if (!fs.existsSync(skillDir)) {
|
|
1929
|
+
const pluginsDir = path.join(REPO_ROOT, 'plugins');
|
|
1930
|
+
if (fs.existsSync(pluginsDir)) {
|
|
1931
|
+
const plugins = fs.readdirSync(pluginsDir, { withFileTypes: true })
|
|
1932
|
+
.filter(d => d.isDirectory())
|
|
1933
|
+
.map(d => d.name);
|
|
1934
|
+
for (const p of plugins) {
|
|
1935
|
+
const candidate = path.join(pluginsDir, p, 'skills', cleanName);
|
|
1936
|
+
if (fs.existsSync(candidate)) {
|
|
1937
|
+
skillDir = candidate;
|
|
1938
|
+
pluginName = p;
|
|
1939
|
+
break;
|
|
1940
|
+
}
|
|
1941
|
+
}
|
|
1942
|
+
}
|
|
1943
|
+
}
|
|
1944
|
+
|
|
1945
|
+
const skillMd = path.join(skillDir, 'SKILL.md');
|
|
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}`);
|
|
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
|
+
}
|
|
1963
|
+
|
|
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'));
|
|
1973
|
+
}
|
|
1974
|
+
console.log('');
|
|
1975
|
+
return;
|
|
1976
|
+
}
|
|
1977
|
+
|
|
1978
|
+
console.error(`\n${RED}Error: Component '${cleanName}' not found in catalog (checked skills, agents, and hooks).${RESET}\n`);
|
|
1979
|
+
process.exit(1);
|
|
1980
|
+
}
|
|
1981
|
+
|
|
656
1982
|
// CLI Argument Parsing
|
|
657
1983
|
const args = process.argv.slice(2);
|
|
658
1984
|
const command = args[0] || 'help';
|
|
@@ -670,31 +1996,169 @@ switch (command) {
|
|
|
670
1996
|
case 'new-agent':
|
|
671
1997
|
scaffoldAgent(args[1]);
|
|
672
1998
|
break;
|
|
673
|
-
case 'add':
|
|
674
|
-
|
|
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);
|
|
675
2007
|
break;
|
|
676
|
-
|
|
677
|
-
|
|
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);
|
|
678
2017
|
break;
|
|
2018
|
+
}
|
|
679
2019
|
case 'test-skill':
|
|
680
2020
|
testSkill(args[1]);
|
|
681
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
|
+
}
|
|
2039
|
+
case 'info':
|
|
2040
|
+
case 'show':
|
|
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);
|
|
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
|
+
}
|
|
682
2119
|
case 'init':
|
|
683
2120
|
case 'install': {
|
|
684
2121
|
let profile = 'developer';
|
|
685
2122
|
let isGlobal = false;
|
|
686
2123
|
let customTarget = null;
|
|
2124
|
+
let isDryRun = false;
|
|
687
2125
|
for (let i = 1; i < args.length; i++) {
|
|
688
2126
|
if (args[i] === '--profile' && args[i + 1]) profile = args[++i];
|
|
689
2127
|
else if (args[i] === '--global') isGlobal = true;
|
|
2128
|
+
else if (args[i] === '--dry-run') isDryRun = true;
|
|
690
2129
|
else if (args[i] === '--workspace' && args[i + 1]) customTarget = args[++i];
|
|
691
2130
|
}
|
|
692
|
-
installProfile(profile, isGlobal, customTarget);
|
|
2131
|
+
installProfile(profile, isGlobal, customTarget, isDryRun);
|
|
693
2132
|
break;
|
|
694
2133
|
}
|
|
695
2134
|
case 'validate':
|
|
696
2135
|
runValidate();
|
|
697
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;
|
|
698
2162
|
case 'help':
|
|
699
2163
|
case '--help':
|
|
700
2164
|
case '-h':
|