everything-gemini 1.2.0 → 1.8.0

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