everything-gemini 1.2.0 → 1.9.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 (73) 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 +178 -0
  7. package/CONTRIBUTING.md +90 -4
  8. package/README.md +147 -23
  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/platform-engineer.md +33 -0
  16. package/agents/release-engineer.md +34 -0
  17. package/bin/everything-gemini +1791 -142
  18. package/docs/COMMUNITY_SUBMISSIONS.md +88 -0
  19. package/docs/LAUNCH_KIT.md +138 -13
  20. package/docs/architecture/progressive-disclosure.md +3 -3
  21. package/docs/index.html +410 -40
  22. package/docs/launch-kit.md +163 -0
  23. package/examples/cli-workflows/demo_workflow.sh +15 -7
  24. package/examples/python-sdk/README.md +32 -5
  25. package/examples/python-sdk/documentation_audit_pipeline.py +83 -0
  26. package/examples/python-sdk/incident_triage_pipeline.py +170 -0
  27. package/examples/python-sdk/multi_agent_pipeline.py +95 -0
  28. package/examples/python-sdk/platform_provisioning_pipeline.py +193 -0
  29. package/examples/python-sdk/release_readiness_audit.py +144 -0
  30. package/hooks/secret-scrubber/hooks.json +16 -0
  31. package/hooks/secret-scrubber/scripts/scrub-secrets.sh +62 -0
  32. package/mcp/README.md +21 -0
  33. package/mcp/mcp_config.example.json +39 -0
  34. package/package.json +3 -1
  35. package/plugins/core/rules/core-practices.md +63 -4
  36. package/plugins/python-ai/rules/ai-agent-patterns.md +67 -4
  37. package/plugins/security-shield/rules/zero-trust.md +60 -4
  38. package/plugins/web-fullstack/rules/frontend-standards.md +74 -4
  39. package/rules/paradigms/security-hardened.md +53 -10
  40. package/rules/paradigms/tdd.md +65 -8
  41. package/scripts/install.ps1 +14 -0
  42. package/scripts/install.sh +15 -1
  43. package/scripts/validate.sh +103 -12
  44. package/skills/apache-kafka-streams/SKILL.md +152 -0
  45. package/skills/argo-workflows/SKILL.md +151 -0
  46. package/skills/axum-web-service/SKILL.md +159 -0
  47. package/skills/cilium-ebpf-networking/SKILL.md +145 -0
  48. package/skills/clickhouse-analytics/SKILL.md +128 -0
  49. package/skills/cloudflare-r2-object-storage/SKILL.md +143 -0
  50. package/skills/dbt-transformation/SKILL.md +179 -0
  51. package/skills/debezium-cdc/SKILL.md +166 -0
  52. package/skills/distributed-rate-limiting/SKILL.md +138 -0
  53. package/skills/duckdb-local-olap/SKILL.md +134 -0
  54. package/skills/fastapi-production/SKILL.md +157 -0
  55. package/skills/grpc-connect-rpc/SKILL.md +176 -0
  56. package/skills/langgraph-orchestrator/SKILL.md +144 -0
  57. package/skills/litellm-proxy-gateway/SKILL.md +154 -0
  58. package/skills/milvus-vector-clustering/SKILL.md +134 -0
  59. package/skills/nats-jetstream/SKILL.md +122 -0
  60. package/skills/open-telemetry-tracing/SKILL.md +151 -0
  61. package/skills/playwright-visual-regression/SKILL.md +124 -0
  62. package/skills/redis-cache-patterns/SKILL.md +159 -0
  63. package/skills/svelte-kit-architect/SKILL.md +190 -0
  64. package/skills/temporal-workflows/SKILL.md +158 -0
  65. package/skills/trpc-react-query/SKILL.md +169 -0
  66. package/skills/turborepo-monorepo/SKILL.md +199 -0
  67. package/skills/vault-secrets-management/SKILL.md +129 -0
  68. package/skills/vllm-inference/SKILL.md +144 -0
  69. package/skills/wasm-rust-optimizer/SKILL.md +130 -0
  70. package/templates/full-power/hooks.json +14 -0
  71. package/templates/full-power/mcp_config.json +47 -0
  72. package/templates/recommended/hooks.json +14 -0
  73. package/tests/cli.test.js +447 -0
@@ -45,20 +45,35 @@ 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}sync${RESET} [options] Synchronize workspace with upstream catalog & verify integrity`);
54
+ console.log(` ${GREEN}update${RESET} Sync installed skills, agents, and hooks with latest catalog`);
48
55
  console.log(` ${GREEN}list${RESET} Show all available skills, rules, hooks, and plugins`);
56
+ console.log(` ${GREEN}scaffold, new${RESET} <type> <name> Scaffold progressive skill, scoped subagent, or hook`);
49
57
  console.log(` ${GREEN}new-skill${RESET} <name> Scaffold a new progressive-disclosure skill`);
50
58
  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`);
59
+ console.log(` ${GREEN}add${RESET} <type> <name> Add a specific skill, agent, hook, or plugin to workspace`);
60
+ console.log(` ${GREEN}remove${RESET} <type> <name> Remove a specific skill, agent, hook, or plugin from workspace`);
61
+ console.log(` ${GREEN}search, find${RESET} <query> Search skills, agents, hooks, and MCP blueprints`);
62
+ console.log(` ${GREEN}audit${RESET} [path] Comprehensive audit of frontmatter, contracts, hooks & links`);
53
63
  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`);
64
+ console.log(` ${GREEN}test-all${RESET} Benchmark & validate all 56 skills, 12 subagents & 7 hooks`);
65
+ console.log(` ${GREEN}info${RESET} <name> Display overview & runbook for a skill, agent, or hook`);
66
+ console.log(` ${GREEN}completion${RESET} [--install] Generate or install shell autocompletion script (bash/zsh)`);
55
67
  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}`);
68
+ console.log(` ${GREEN}version, -v, --version${RESET} Print everything-gemini version`);
69
+ console.log(` ${GREEN}help, -h, --help${RESET} Show this help message\n`);
70
+ console.log(`${BOLD}GLOBAL & COMMAND OPTIONS:${RESET}`);
58
71
  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`);
72
+ console.log(` ${CYAN}--global${RESET} Target global config (~/.gemini/config/)`);
73
+ console.log(` ${CYAN}--workspace <path>${RESET} Target custom workspace directory`);
74
+ console.log(` ${CYAN}--dry-run${RESET} Preview actions without modifying files on disk`);
75
+ console.log(` ${CYAN}--json${RESET} Output machine-readable JSON (status, benchmark)`);
76
+ console.log(` ${CYAN}--force${RESET} Overwrite existing configuration files\n`);
62
77
  }
63
78
 
64
79
  function runDoctor() {
@@ -190,13 +205,29 @@ function listComponents() {
190
205
  if (item.isDirectory()) {
191
206
  findRules(path.join(dir, item.name), `${prefix}${item.name}/`);
192
207
  } else if (item.name.endsWith('.md')) {
193
- console.log(` ${BOLD}${(prefix + item.name).padEnd(32)}${RESET}`);
208
+ console.log(` ${BOLD}${(prefix + item.name).padEnd(36)}${RESET}`);
194
209
  }
195
210
  }
196
211
  }
197
212
  findRules(rulesDir);
198
213
  }
199
214
 
215
+ // Plugin Packaged Rules
216
+ if (fs.existsSync(pluginsDirForSkills)) {
217
+ const plugins = fs.readdirSync(pluginsDirForSkills, { withFileTypes: true })
218
+ .filter(d => d.isDirectory())
219
+ .map(d => d.name);
220
+ for (const plugin of plugins) {
221
+ const pRulesDir = path.join(pluginsDirForSkills, plugin, 'rules');
222
+ if (fs.existsSync(pRulesDir)) {
223
+ const pRules = fs.readdirSync(pRulesDir).filter(f => f.endsWith('.md'));
224
+ for (const r of pRules) {
225
+ console.log(` ${BOLD}${(`plugins/${plugin}/rules/${r}`).padEnd(36)}${RESET}`);
226
+ }
227
+ }
228
+ }
229
+ }
230
+
200
231
  // Hooks
201
232
  console.log(`\n${CYAN}${BOLD}🛡️ Lifecycle Hooks:${RESET}`);
202
233
  const hooksDir = path.join(REPO_ROOT, 'hooks');
@@ -243,19 +274,26 @@ function copyRecursiveSync(src, dest) {
243
274
  } else {
244
275
  fs.mkdirSync(path.dirname(dest), { recursive: true });
245
276
  fs.copyFileSync(src, dest);
277
+ if (src.endsWith('.sh') || (stats.mode && (stats.mode & 0o111))) {
278
+ try { fs.chmodSync(dest, 0o755); } catch (e) {}
279
+ }
246
280
  }
247
281
  }
248
282
 
249
- function installProfile(profile = 'developer', isGlobal = false, customTarget = null) {
283
+ function installProfile(profile = 'developer', isGlobal = false, customTarget = null, isDryRun = false) {
250
284
  printBanner();
251
285
  const targetDir = customTarget
252
286
  ? path.resolve(customTarget)
253
287
  : (isGlobal ? GLOBAL_CONFIG_DIR : AGENTS_DIR);
254
288
 
289
+ if (isDryRun) {
290
+ console.log(`${YELLOW}${BOLD}🔍 DRY RUN MODE ACTIVATED - No files will be modified on disk.${RESET}`);
291
+ }
292
+
255
293
  console.log(`${BOLD}🚀 Installing everything-gemini Profile: [${GREEN}${profile}${RESET}${BOLD}]${RESET}`);
256
294
  console.log(`Target Directory: ${CYAN}${targetDir}${RESET}\n`);
257
295
 
258
- if (!fs.existsSync(targetDir)) {
296
+ if (!isDryRun && !fs.existsSync(targetDir)) {
259
297
  fs.mkdirSync(targetDir, { recursive: true });
260
298
  }
261
299
 
@@ -263,69 +301,103 @@ function installProfile(profile = 'developer', isGlobal = false, customTarget =
263
301
  const targetSkills = path.join(targetDir, 'skills');
264
302
  const targetRules = path.join(targetDir, 'rules');
265
303
  const targetPlugins = path.join(targetDir, 'plugins');
266
- fs.mkdirSync(targetSkills, { recursive: true });
267
- fs.mkdirSync(targetRules, { recursive: true });
268
- fs.mkdirSync(targetPlugins, { recursive: true });
304
+ const targetAgents = path.join(targetDir, 'agents');
305
+ if (!isDryRun) {
306
+ fs.mkdirSync(targetSkills, { recursive: true });
307
+ fs.mkdirSync(targetRules, { recursive: true });
308
+ fs.mkdirSync(targetPlugins, { recursive: true });
309
+ }
269
310
 
270
311
  const skillsSrc = path.join(REPO_ROOT, 'skills');
271
312
  const rulesSrc = path.join(REPO_ROOT, 'rules');
272
313
  const hooksSrc = path.join(REPO_ROOT, 'hooks');
273
314
  const pluginsSrc = path.join(REPO_ROOT, 'plugins');
315
+ const agentsSrc = path.join(REPO_ROOT, 'agents');
274
316
 
275
317
  // Copy Common Base Rules
276
318
  const commonGemini = path.join(rulesSrc, 'common', 'GEMINI.md');
277
319
  const commonAgents = path.join(rulesSrc, 'common', 'AGENTS.md');
278
320
  if (fs.existsSync(commonGemini)) {
279
- fs.copyFileSync(commonGemini, path.join(targetDir, 'GEMINI.md'));
280
- console.log(` ${GREEN}✔${RESET} Installed base GEMINI.md`);
321
+ if (!isDryRun) fs.copyFileSync(commonGemini, path.join(targetDir, 'GEMINI.md'));
322
+ console.log(` ${GREEN}✔${RESET} ${isDryRun ? '[DRY RUN] Would install' : 'Installed'} base GEMINI.md`);
281
323
  }
282
324
  if (fs.existsSync(commonAgents)) {
283
- fs.copyFileSync(commonAgents, path.join(targetDir, 'AGENTS.md'));
284
- console.log(` ${GREEN}✔${RESET} Installed base AGENTS.md`);
325
+ if (!isDryRun) fs.copyFileSync(commonAgents, path.join(targetDir, 'AGENTS.md'));
326
+ console.log(` ${GREEN}✔${RESET} ${isDryRun ? '[DRY RUN] Would install' : 'Installed'} base AGENTS.md`);
285
327
  }
286
328
 
287
- // Determine what to copy based on profile
329
+ // 1. Core Profile
288
330
  if (profile === 'core' || profile === 'developer' || profile === 'full') {
289
- // Core Skills
290
331
  const coreSkills = ['tdd-workflow', 'repo-onboarding'];
291
332
  for (const s of coreSkills) {
292
333
  const src = path.join(skillsSrc, s);
293
334
  if (fs.existsSync(src)) {
294
- copyRecursiveSync(src, path.join(targetSkills, s));
295
- console.log(` ${GREEN}✔${RESET} Installed skill: ${s}`);
335
+ if (!isDryRun) copyRecursiveSync(src, path.join(targetSkills, s));
336
+ console.log(` ${GREEN}✔${RESET} ${isDryRun ? '[DRY RUN] Would install' : 'Installed'} skill: ${s}`);
296
337
  }
297
338
  }
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`);
339
+ const safetyHook = path.join(hooksSrc, 'safety-shield');
340
+ if (fs.existsSync(safetyHook)) {
341
+ if (!isDryRun) copyRecursiveSync(safetyHook, path.join(targetDir, 'hooks', 'safety-shield'));
342
+ console.log(` ${GREEN}✔${RESET} ${isDryRun ? '[DRY RUN] Would install' : 'Installed'} safety-shield hook`);
303
343
  }
304
344
  }
305
345
 
346
+ // 2. Developer Profile
306
347
  if (profile === 'developer' || profile === 'full') {
307
- // Developer Skills
308
- const devSkills = ['browser-qa-tester', 'architecture-designer', 'git-craftsman', 'performance-profiler', 'fullstack-nextjs'];
348
+ const devSkills = [
349
+ 'browser-qa-tester',
350
+ 'architecture-designer',
351
+ 'git-craftsman',
352
+ 'performance-profiler',
353
+ 'fullstack-nextjs',
354
+ 'gemini-multimodal',
355
+ 'context-caching',
356
+ 'subagent-handoff',
357
+ 'security-audit',
358
+ 'continuous-learning',
359
+ 'ai-first-engineering'
360
+ ];
309
361
  for (const s of devSkills) {
310
362
  const src = path.join(skillsSrc, s);
311
363
  if (fs.existsSync(src)) {
312
- copyRecursiveSync(src, path.join(targetSkills, s));
313
- console.log(` ${GREEN}✔${RESET} Installed skill: ${s}`);
364
+ if (!isDryRun) copyRecursiveSync(src, path.join(targetSkills, s));
365
+ console.log(` ${GREEN}✔${RESET} ${isDryRun ? '[DRY RUN] Would install' : 'Installed'} skill: ${s}`);
314
366
  }
315
367
  }
316
368
 
317
369
  // Developer Language Rules
318
370
  const langRules = path.join(rulesSrc, 'languages');
319
371
  if (fs.existsSync(langRules)) {
320
- copyRecursiveSync(langRules, targetRules);
321
- console.log(` ${GREEN}✔${RESET} Installed language rules (TypeScript, Python, Go)`);
372
+ if (!isDryRun) copyRecursiveSync(langRules, targetRules);
373
+ console.log(` ${GREEN}✔${RESET} ${isDryRun ? '[DRY RUN] Would install' : 'Installed'} language rules (TypeScript, Python, Go)`);
322
374
  }
323
375
 
324
376
  // Auto-lint formatter hook
325
377
  const lintHook = path.join(hooksSrc, 'auto-lint-formatter');
326
378
  if (fs.existsSync(lintHook)) {
327
- copyRecursiveSync(lintHook, path.join(targetDir, 'hooks', 'auto-lint-formatter'));
328
- console.log(` ${GREEN}✔${RESET} Installed auto-lint-formatter hook`);
379
+ if (!isDryRun) copyRecursiveSync(lintHook, path.join(targetDir, 'hooks', 'auto-lint-formatter'));
380
+ console.log(` ${GREEN}✔${RESET} ${isDryRun ? '[DRY RUN] Would install' : 'Installed'} auto-lint-formatter hook`);
381
+ }
382
+
383
+ // Goal-verifier hook
384
+ const goalHook = path.join(hooksSrc, 'goal-verifier');
385
+ if (fs.existsSync(goalHook)) {
386
+ if (!isDryRun) copyRecursiveSync(goalHook, path.join(targetDir, 'hooks', 'goal-verifier'));
387
+ console.log(` ${GREEN}✔${RESET} ${isDryRun ? '[DRY RUN] Would install' : 'Installed'} goal-verifier hook`);
388
+ }
389
+
390
+ // Secret-scrubber hook
391
+ const scrubberHook = path.join(hooksSrc, 'secret-scrubber');
392
+ if (fs.existsSync(scrubberHook)) {
393
+ if (!isDryRun) copyRecursiveSync(scrubberHook, path.join(targetDir, 'hooks', 'secret-scrubber'));
394
+ console.log(` ${GREEN}✔${RESET} ${isDryRun ? '[DRY RUN] Would install' : 'Installed'} secret-scrubber hook`);
395
+ }
396
+
397
+ // Scoped Subagents (agents/)
398
+ if (fs.existsSync(agentsSrc)) {
399
+ if (!isDryRun) copyRecursiveSync(agentsSrc, targetAgents);
400
+ console.log(` ${GREEN}✔${RESET} ${isDryRun ? '[DRY RUN] Would install' : 'Installed'} 9 scoped subagents (agents/)`);
329
401
  }
330
402
 
331
403
  // Developer Plugins
@@ -333,58 +405,652 @@ function installProfile(profile = 'developer', isGlobal = false, customTarget =
333
405
  for (const p of devPlugins) {
334
406
  const src = path.join(pluginsSrc, p);
335
407
  if (fs.existsSync(src)) {
336
- copyRecursiveSync(src, path.join(targetPlugins, p));
337
- console.log(` ${GREEN}✔${RESET} Installed plugin: ${p}`);
408
+ if (!isDryRun) copyRecursiveSync(src, path.join(targetPlugins, p));
409
+ console.log(` ${GREEN}✔${RESET} ${isDryRun ? '[DRY RUN] Would install' : 'Installed'} plugin: ${p}`);
338
410
  }
339
411
  }
340
412
  }
341
413
 
414
+ // 3. Full Power Profile
342
415
  if (profile === 'full') {
343
- // All Skills
344
- copyRecursiveSync(skillsSrc, targetSkills);
345
- console.log(` ${GREEN}✔${RESET} Installed entire skills library`);
416
+ if (!isDryRun) copyRecursiveSync(skillsSrc, targetSkills);
417
+ console.log(` ${GREEN}✔${RESET} ${isDryRun ? '[DRY RUN] Would install' : 'Installed'} entire skills library (48 progressive skills)`);
418
+
419
+ if (!isDryRun) copyRecursiveSync(rulesSrc, targetRules);
420
+ console.log(` ${GREEN}✔${RESET} ${isDryRun ? '[DRY RUN] Would install' : 'Installed'} entire rules library`);
346
421
 
347
- // All Rules
348
- copyRecursiveSync(rulesSrc, targetRules);
349
- console.log(` ${GREEN}✔${RESET} Installed entire rules library`);
422
+ if (!isDryRun) copyRecursiveSync(pluginsSrc, targetPlugins);
423
+ console.log(` ${GREEN}✔${RESET} ${isDryRun ? '[DRY RUN] Would install' : 'Installed'} all modular plugins`);
350
424
 
351
- // All Plugins
352
- copyRecursiveSync(pluginsSrc, targetPlugins);
353
- console.log(` ${GREEN}✔${RESET} Installed all modular plugins`);
425
+ if (!isDryRun) copyRecursiveSync(hooksSrc, path.join(targetDir, 'hooks'));
426
+ console.log(` ${GREEN}✔${RESET} ${isDryRun ? '[DRY RUN] Would install' : 'Installed'} full lifecycle hooks suite (7 hooks)`);
354
427
 
355
- // All Hooks
356
- copyRecursiveSync(hooksSrc, path.join(targetDir, 'hooks'));
357
- console.log(` ${GREEN}✔${RESET} Installed full lifecycle hooks suite`);
428
+ if (fs.existsSync(agentsSrc)) {
429
+ if (!isDryRun) copyRecursiveSync(agentsSrc, targetAgents);
430
+ console.log(` ${GREEN}✔${RESET} ${isDryRun ? '[DRY RUN] Would install' : 'Installed'} 10 scoped subagents (agents/)`);
431
+ }
358
432
 
359
433
  // MCP Config Example
360
434
  const mcpExample = path.join(REPO_ROOT, 'mcp', 'mcp_config.example.json');
361
435
  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
- ]
436
+ if (!isDryRun) fs.copyFileSync(mcpExample, path.join(targetDir, 'mcp_config.json'));
437
+ console.log(` ${GREEN}✔${RESET} ${isDryRun ? '[DRY RUN] Would install' : 'Installed'} mcp_config.json`);
438
+ }
439
+ }
440
+
441
+ // Template-driven master hooks.json generation
442
+ let templateHooksPath = null;
443
+ if (profile === 'minimal' || profile === 'core') {
444
+ templateHooksPath = path.join(REPO_ROOT, 'templates', 'minimal', 'hooks.json');
445
+ } else if (profile === 'full') {
446
+ templateHooksPath = path.join(REPO_ROOT, 'templates', 'full-power', 'hooks.json');
447
+ } else {
448
+ templateHooksPath = path.join(REPO_ROOT, 'templates', 'recommended', 'hooks.json');
449
+ }
450
+
451
+ if (fs.existsSync(templateHooksPath)) {
452
+ if (!isDryRun) fs.copyFileSync(templateHooksPath, path.join(targetDir, 'hooks.json'));
453
+ console.log(` ${GREEN}✔${RESET} ${isDryRun ? '[DRY RUN] Would generate' : 'Generated'} profile hooks.json (${profile})`);
454
+ }
455
+
456
+ if (isDryRun) {
457
+ console.log(`\n${GREEN}${BOLD}✨ Dry run preview complete! 0 files modified on disk.${RESET}\n`);
458
+ } else {
459
+ console.log(`\n${GREEN}${BOLD}✨ Installation complete! Everything Gemini is ready.${RESET}\n`);
460
+ }
461
+ }
462
+
463
+ function runStatus(isGlobal = false, customTarget = null, asJson = false) {
464
+ const targetDir = customTarget
465
+ ? path.resolve(customTarget)
466
+ : (isGlobal ? GLOBAL_CONFIG_DIR : AGENTS_DIR);
467
+
468
+ const isInitialized = fs.existsSync(targetDir);
469
+ const geminiRule = path.join(targetDir, 'GEMINI.md');
470
+ const agentsRule = path.join(targetDir, 'AGENTS.md');
471
+ const hasGemini = fs.existsSync(geminiRule);
472
+ const hasAgents = fs.existsSync(agentsRule);
473
+
474
+ // 1. Installed Skills
475
+ const skillsDir = path.join(targetDir, 'skills');
476
+ let installedSkills = [];
477
+ if (fs.existsSync(skillsDir)) {
478
+ installedSkills = fs.readdirSync(skillsDir, { withFileTypes: true })
479
+ .filter(d => d.isDirectory())
480
+ .map(d => d.name)
481
+ .sort();
482
+ }
483
+
484
+ // 2. Subagents
485
+ const agentsDir = path.join(targetDir, 'agents');
486
+ let installedAgents = [];
487
+ if (fs.existsSync(agentsDir)) {
488
+ installedAgents = fs.readdirSync(agentsDir)
489
+ .filter(f => f.endsWith('.md'))
490
+ .map(f => f.replace('.md', ''))
491
+ .sort();
492
+ }
493
+
494
+ // 3. Hooks
495
+ const hooksFile = path.join(targetDir, 'hooks.json');
496
+ let hooksSummary = {};
497
+ if (fs.existsSync(hooksFile)) {
498
+ try {
499
+ hooksSummary = JSON.parse(fs.readFileSync(hooksFile, 'utf8'));
500
+ } catch (e) {}
501
+ }
502
+
503
+ if (asJson) {
504
+ const payload = {
505
+ version: VERSION,
506
+ targetDir,
507
+ isGlobal,
508
+ isInitialized,
509
+ rules: {
510
+ gemini: hasGemini,
511
+ agents: hasAgents
512
+ },
513
+ skills: {
514
+ installedCount: installedSkills.length,
515
+ totalCatalogCount: 52,
516
+ installed: installedSkills
517
+ },
518
+ subagents: {
519
+ installedCount: installedAgents.length,
520
+ totalCatalogCount: 11,
521
+ installed: installedAgents
522
+ },
523
+ hooks: {
524
+ activeCount: Object.keys(hooksSummary).length,
525
+ active: Object.keys(hooksSummary)
526
+ }
527
+ };
528
+ console.log(JSON.stringify(payload, null, 2));
529
+ return;
530
+ }
531
+
532
+ printBanner();
533
+ console.log(`${BOLD}📊 Everything Gemini Workspace Status${RESET}`);
534
+ console.log(`Directory: ${CYAN}${targetDir}${RESET}\n`);
535
+
536
+ if (!isInitialized) {
537
+ console.log(` ${YELLOW}○ Workspace is not initialized.${RESET}`);
538
+ console.log(` Run ${GREEN}everything-gemini install${RESET} to set up.\n`);
539
+ return;
540
+ }
541
+
542
+ console.log(`${CYAN}${BOLD}📜 Base Rules:${RESET}`);
543
+ console.log(` ${hasGemini ? GREEN + '✔' : GRAY + '○'}${RESET} GEMINI.md ${hasGemini ? '(active)' : '(not installed)'}`);
544
+ console.log(` ${hasAgents ? GREEN + '✔' : GRAY + '○'}${RESET} AGENTS.md ${hasAgents ? '(active)' : '(not installed)'}`);
545
+
546
+ console.log(`\n${CYAN}${BOLD}⚡ Installed Skills (${installedSkills.length}/52):${RESET}`);
547
+ if (installedSkills.length === 0) {
548
+ console.log(` ${GRAY}(no skills installed)${RESET}`);
549
+ } else {
550
+ for (const s of installedSkills) {
551
+ console.log(` ${GREEN}✔${RESET} ${s}`);
552
+ }
553
+ }
554
+
555
+ console.log(`\n${CYAN}${BOLD}🤖 Scoped Subagents (${installedAgents.length}/11):${RESET}`);
556
+ if (installedAgents.length === 0) {
557
+ console.log(` ${GRAY}(no subagents installed)${RESET}`);
558
+ } else {
559
+ for (const a of installedAgents) {
560
+ console.log(` ${GREEN}✔${RESET} ${a}`);
561
+ }
562
+ }
563
+
564
+ console.log(`\n${CYAN}${BOLD}🛡️ Lifecycle Hooks:${RESET}`);
565
+ const hookNames = Object.keys(hooksSummary);
566
+ if (hookNames.length > 0) {
567
+ console.log(` ${GREEN}✔${RESET} hooks.json configured (${hookNames.length} hooks active):`);
568
+ for (const h of hookNames) {
569
+ const events = Object.keys(hooksSummary[h]).join(', ');
570
+ console.log(` • ${BOLD}${h}${RESET} [${GRAY}${events}${RESET}]`);
571
+ }
572
+ } else {
573
+ console.log(` ${GRAY}(no hooks.json found)${RESET}`);
574
+ }
575
+ console.log('');
576
+ }
577
+
578
+ function runUpdate(isGlobal = false, customTarget = null, isDryRun = false) {
579
+ printBanner();
580
+ const targetDir = customTarget
581
+ ? path.resolve(customTarget)
582
+ : (isGlobal ? GLOBAL_CONFIG_DIR : AGENTS_DIR);
583
+
584
+ if (isDryRun) {
585
+ console.log(`${YELLOW}${BOLD}🔍 DRY RUN MODE ACTIVATED - No files will be modified on disk.${RESET}`);
586
+ }
587
+ console.log(`${BOLD}🔄 Updating Installed Components in: ${CYAN}${targetDir}${RESET}\n`);
588
+
589
+ if (!fs.existsSync(targetDir)) {
590
+ console.log(` ${YELLOW}○ Workspace is not initialized.${RESET}`);
591
+ console.log(` Run ${GREEN}everything-gemini install${RESET} first.\n`);
592
+ return;
593
+ }
594
+
595
+ let updatedSkills = 0;
596
+ let updatedAgents = 0;
597
+ let updatedHooks = 0;
598
+
599
+ // 1. Update Existing Installed Skills
600
+ const targetSkills = path.join(targetDir, 'skills');
601
+ if (fs.existsSync(targetSkills)) {
602
+ const installed = fs.readdirSync(targetSkills, { withFileTypes: true })
603
+ .filter(d => d.isDirectory())
604
+ .map(d => d.name);
605
+ for (const s of installed) {
606
+ const src = path.join(REPO_ROOT, 'skills', s);
607
+ if (fs.existsSync(src)) {
608
+ if (!isDryRun) copyRecursiveSync(src, path.join(targetSkills, s));
609
+ updatedSkills++;
610
+ if (isDryRun) {
611
+ console.log(` ${CYAN}[DRY RUN]${RESET} Would update skill: ${s}`);
612
+ }
613
+ }
614
+ }
615
+ }
616
+
617
+ // 2. Update Existing Installed Subagents
618
+ const targetAgents = path.join(targetDir, 'agents');
619
+ if (fs.existsSync(targetAgents)) {
620
+ const installed = fs.readdirSync(targetAgents)
621
+ .filter(f => f.endsWith('.md'));
622
+ for (const a of installed) {
623
+ const src = path.join(REPO_ROOT, 'agents', a);
624
+ if (fs.existsSync(src)) {
625
+ if (!isDryRun) fs.copyFileSync(src, path.join(targetAgents, a));
626
+ updatedAgents++;
627
+ if (isDryRun) {
628
+ console.log(` ${CYAN}[DRY RUN]${RESET} Would update subagent: ${a}`);
629
+ }
630
+ }
631
+ }
632
+ }
633
+
634
+ // 3. Update Hooks Scripts
635
+ const targetHooks = path.join(targetDir, 'hooks');
636
+ if (fs.existsSync(targetHooks)) {
637
+ const installed = fs.readdirSync(targetHooks, { withFileTypes: true })
638
+ .filter(d => d.isDirectory())
639
+ .map(d => d.name);
640
+ for (const h of installed) {
641
+ const src = path.join(REPO_ROOT, 'hooks', h);
642
+ if (fs.existsSync(src)) {
643
+ if (!isDryRun) copyRecursiveSync(src, path.join(targetHooks, h));
644
+ updatedHooks++;
645
+ if (isDryRun) {
646
+ console.log(` ${CYAN}[DRY RUN]${RESET} Would refresh hook: ${h}`);
647
+ }
648
+ }
649
+ }
650
+ }
651
+
652
+ // 4. Refresh base rules if present
653
+ const rulesSrc = path.join(REPO_ROOT, 'rules', 'common');
654
+ if (fs.existsSync(path.join(targetDir, 'GEMINI.md')) && fs.existsSync(path.join(rulesSrc, 'GEMINI.md'))) {
655
+ if (!isDryRun) fs.copyFileSync(path.join(rulesSrc, 'GEMINI.md'), path.join(targetDir, 'GEMINI.md'));
656
+ if (isDryRun) console.log(` ${CYAN}[DRY RUN]${RESET} Would refresh base GEMINI.md`);
657
+ }
658
+ if (fs.existsSync(path.join(targetDir, 'AGENTS.md')) && fs.existsSync(path.join(rulesSrc, 'AGENTS.md'))) {
659
+ if (!isDryRun) fs.copyFileSync(path.join(rulesSrc, 'AGENTS.md'), path.join(targetDir, 'AGENTS.md'));
660
+ if (isDryRun) console.log(` ${CYAN}[DRY RUN]${RESET} Would refresh base AGENTS.md`);
661
+ }
662
+
663
+ if (isDryRun) {
664
+ console.log(`\n${GREEN}${BOLD}✨ Dry run preview complete! 0 files modified on disk.${RESET}\n`);
665
+ } else {
666
+ console.log(` ${GREEN}✔${RESET} Synced ${BOLD}${updatedSkills}${RESET} installed skills to latest catalog versions`);
667
+ console.log(` ${GREEN}✔${RESET} Synced ${BOLD}${updatedAgents}${RESET} subagent specifications`);
668
+ console.log(` ${GREEN}✔${RESET} Refreshed ${BOLD}${updatedHooks}${RESET} lifecycle hook scripts & verified permissions`);
669
+ console.log(` ${GREEN}✔${RESET} Refreshed base GEMINI.md & AGENTS.md rules\n`);
670
+ console.log(`${GREEN}${BOLD}✨ Update complete! Everything Gemini is up to date.${RESET}\n`);
671
+ }
672
+ }
673
+
674
+ function runDiff(isGlobal = false, customTarget = null) {
675
+ printBanner();
676
+ const targetDir = customTarget ? path.resolve(customTarget) : (isGlobal ? GLOBAL_CONFIG_DIR : AGENTS_DIR);
677
+ console.log(`${BOLD}🔍 Comparing Workspace vs. Master Everything Gemini Catalog...${RESET}`);
678
+ console.log(`Target: ${CYAN}${targetDir}${RESET}\n`);
679
+
680
+ if (!fs.existsSync(targetDir)) {
681
+ console.log(`${YELLOW}No active configuration found at ${targetDir}.${RESET}\n`);
682
+ return;
683
+ }
684
+
685
+ // Compare skills
686
+ const wsSkillsDir = path.join(targetDir, 'skills');
687
+ const catalogSkillsDir = path.join(REPO_ROOT, 'skills');
688
+ const wsSkills = fs.existsSync(wsSkillsDir) ? fs.readdirSync(wsSkillsDir).filter(s => {
689
+ try { return fs.statSync(path.join(wsSkillsDir, s)).isDirectory(); } catch (_) { return false; }
690
+ }) : [];
691
+
692
+ console.log(`${BOLD}⚡ Progressive Skills Comparison:${RESET}`);
693
+ let modifiedCount = 0;
694
+ for (const s of wsSkills) {
695
+ const wsFile = path.join(wsSkillsDir, s, 'SKILL.md');
696
+ const catFile = path.join(catalogSkillsDir, s, 'SKILL.md');
697
+ if (!fs.existsSync(catFile)) {
698
+ console.log(` ${CYAN}+ [CUSTOM/LOCAL]${RESET} ${s}`);
699
+ } else {
700
+ const wsContent = fs.existsSync(wsFile) ? fs.readFileSync(wsFile, 'utf8') : '';
701
+ const catContent = fs.readFileSync(catFile, 'utf8');
702
+ if (wsContent !== catContent) {
703
+ console.log(` ${YELLOW}* [MODIFIED]${RESET} ${s} (differs from catalog)`);
704
+ modifiedCount++;
705
+ } else {
706
+ console.log(` ${GREEN}✔ [IN-SYNC]${RESET} ${s}`);
707
+ }
708
+ }
709
+ }
710
+
711
+ // Compare agents
712
+ const wsAgentsDir = path.join(targetDir, 'agents');
713
+ const catAgentsDir = path.join(REPO_ROOT, 'agents');
714
+ const wsAgents = fs.existsSync(wsAgentsDir) ? fs.readdirSync(wsAgentsDir).filter(a => a.endsWith('.md')) : [];
715
+ console.log(`\n${BOLD}🤖 Scoped Subagents Comparison:${RESET}`);
716
+ for (const a of wsAgents) {
717
+ const wsFile = path.join(wsAgentsDir, a);
718
+ const catFile = path.join(catAgentsDir, a);
719
+ if (!fs.existsSync(catFile)) {
720
+ console.log(` ${CYAN}+ [CUSTOM/LOCAL]${RESET} ${a}`);
721
+ } else {
722
+ const wsContent = fs.readFileSync(wsFile, 'utf8');
723
+ const catContent = fs.readFileSync(catFile, 'utf8');
724
+ if (wsContent !== catContent) {
725
+ console.log(` ${YELLOW}* [MODIFIED]${RESET} ${a} (differs from catalog)`);
726
+ modifiedCount++;
727
+ } else {
728
+ console.log(` ${GREEN}✔ [IN-SYNC]${RESET} ${a}`);
729
+ }
730
+ }
731
+ }
732
+
733
+ 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`);
734
+ }
735
+
736
+ function runExport(isGlobal = false, customTarget = null, outputPath = null) {
737
+ printBanner();
738
+ const targetDir = customTarget ? path.resolve(customTarget) : (isGlobal ? GLOBAL_CONFIG_DIR : AGENTS_DIR);
739
+ console.log(`${BOLD}📦 Exporting Agent Configuration Bundle...${RESET}`);
740
+ console.log(`Source: ${CYAN}${targetDir}${RESET}\n`);
741
+
742
+ if (!fs.existsSync(targetDir)) {
743
+ console.error(`${RED}Error: Source directory does not exist: ${targetDir}${RESET}\n`);
744
+ process.exit(1);
745
+ }
746
+
747
+ const exportData = {
748
+ generator: "everything-gemini",
749
+ version: VERSION,
750
+ exportedAt: new Date().toISOString(),
751
+ source: targetDir,
752
+ skills: [],
753
+ agents: [],
754
+ hooksConfig: null
755
+ };
756
+
757
+ const skillsDir = path.join(targetDir, 'skills');
758
+ if (fs.existsSync(skillsDir)) {
759
+ for (const s of fs.readdirSync(skillsDir)) {
760
+ const skillPath = path.join(skillsDir, s, 'SKILL.md');
761
+ if (fs.existsSync(skillPath)) {
762
+ exportData.skills.push({ name: s, content: fs.readFileSync(skillPath, 'utf8') });
763
+ }
764
+ }
765
+ }
766
+
767
+ const agentsDir = path.join(targetDir, 'agents');
768
+ if (fs.existsSync(agentsDir)) {
769
+ for (const a of fs.readdirSync(agentsDir)) {
770
+ if (a.endsWith('.md')) {
771
+ exportData.agents.push({ name: a, content: fs.readFileSync(path.join(agentsDir, a), 'utf8') });
772
+ }
773
+ }
774
+ }
775
+
776
+ const hooksFile = path.join(targetDir, 'hooks.json');
777
+ if (fs.existsSync(hooksFile)) {
778
+ try {
779
+ exportData.hooksConfig = JSON.parse(fs.readFileSync(hooksFile, 'utf8'));
780
+ } catch (_) {}
781
+ }
782
+
783
+ const outDest = outputPath ? path.resolve(outputPath) : path.join(process.cwd(), 'everything-gemini-profile.json');
784
+ fs.writeFileSync(outDest, JSON.stringify(exportData, null, 2), 'utf8');
785
+ console.log(` ${GREEN}✔${RESET} Successfully exported ${exportData.skills.length} skills, ${exportData.agents.length} subagents to:`);
786
+ console.log(` ${BOLD}${outDest}${RESET}\n`);
787
+ }
788
+
789
+ function runImport(inputFile, isGlobal = false, customTarget = null, isDryRun = false) {
790
+ printBanner();
791
+ if (!inputFile) {
792
+ console.error(`${RED}Error: Input file required. Usage: everything-gemini import <profile.json>${RESET}\n`);
793
+ process.exit(1);
794
+ }
795
+
796
+ const filePath = path.resolve(inputFile);
797
+ if (!fs.existsSync(filePath)) {
798
+ console.error(`${RED}Error: Import file does not exist: ${filePath}${RESET}\n`);
799
+ process.exit(1);
800
+ }
801
+
802
+ let bundle = null;
803
+ try {
804
+ bundle = JSON.parse(fs.readFileSync(filePath, 'utf8'));
805
+ } catch (err) {
806
+ console.error(`${RED}Error parsing JSON import bundle: ${err.message}${RESET}\n`);
807
+ process.exit(1);
808
+ }
809
+
810
+ const targetDir = customTarget ? path.resolve(customTarget) : (isGlobal ? GLOBAL_CONFIG_DIR : AGENTS_DIR);
811
+ console.log(`${BOLD}📥 Importing Agent Configuration Bundle...${RESET}`);
812
+ console.log(`Source File: ${CYAN}${filePath}${RESET}`);
813
+ console.log(`Target: ${CYAN}${targetDir}${RESET}\n`);
814
+
815
+ if (isDryRun) {
816
+ console.log(`${YELLOW}${BOLD}⚠️ DRY RUN MODE ACTIVATED. Previewing import:${RESET}\n`);
817
+ }
818
+
819
+ let importedSkills = 0;
820
+ let importedAgents = 0;
821
+
822
+ // 1. Import Skills
823
+ if (Array.isArray(bundle.skills)) {
824
+ const targetSkills = path.join(targetDir, 'skills');
825
+ for (const s of bundle.skills) {
826
+ if (s.name && s.content) {
827
+ if (!isDryRun) {
828
+ const sDir = path.join(targetSkills, s.name);
829
+ fs.mkdirSync(sDir, { recursive: true });
830
+ fs.writeFileSync(path.join(sDir, 'SKILL.md'), s.content, 'utf8');
380
831
  }
381
- ]
832
+ importedSkills++;
833
+ if (isDryRun) {
834
+ console.log(` ${CYAN}[DRY RUN]${RESET} Would import skill: ${s.name}`);
835
+ }
836
+ }
837
+ }
838
+ }
839
+
840
+ // 2. Import Subagents
841
+ if (Array.isArray(bundle.agents)) {
842
+ const targetAgents = path.join(targetDir, 'agents');
843
+ for (const a of bundle.agents) {
844
+ if (a.name && a.content) {
845
+ if (!isDryRun) {
846
+ fs.mkdirSync(targetAgents, { recursive: true });
847
+ fs.writeFileSync(path.join(targetAgents, a.name), a.content, 'utf8');
848
+ }
849
+ importedAgents++;
850
+ if (isDryRun) {
851
+ console.log(` ${CYAN}[DRY RUN]${RESET} Would import subagent: ${a.name}`);
852
+ }
853
+ }
382
854
  }
855
+ }
856
+
857
+ // 3. Import Hooks Config
858
+ if (bundle.hooksConfig && typeof bundle.hooksConfig === 'object') {
859
+ if (!isDryRun) {
860
+ fs.mkdirSync(targetDir, { recursive: true });
861
+ fs.writeFileSync(path.join(targetDir, 'hooks.json'), JSON.stringify(bundle.hooksConfig, null, 2), 'utf8');
862
+ }
863
+ console.log(` ${GREEN}✔${RESET} ${isDryRun ? '[DRY RUN] Would import' : 'Imported'} hooks.json configuration`);
864
+ }
865
+
866
+ if (isDryRun) {
867
+ console.log(`\n${GREEN}${BOLD}✨ Dry run complete! Would import ${importedSkills} skills and ${importedAgents} subagents.${RESET}\n`);
868
+ } else {
869
+ console.log(` ${GREEN}✔${RESET} Successfully imported ${BOLD}${importedSkills}${RESET} progressive skills`);
870
+ console.log(` ${GREEN}✔${RESET} Successfully imported ${BOLD}${importedAgents}${RESET} scoped subagents\n`);
871
+ console.log(`${GREEN}${BOLD}✨ Import complete! Configuration applied to ${targetDir}${RESET}\n`);
872
+ }
873
+ }
874
+
875
+ function runBundle(profile = 'all', outputDir = null, isDryRun = false, asJson = false) {
876
+ const destDir = outputDir ? path.resolve(outputDir) : path.join(process.cwd(), 'everything-gemini-bundle');
877
+ const startTime = Date.now();
878
+ const crypto = require('crypto');
879
+
880
+ const skillsToBundle = [];
881
+ const agentsToBundle = [];
882
+ const hooksToBundle = [];
883
+
884
+ const catalogSkillsDir = path.join(REPO_ROOT, 'skills');
885
+ const catalogAgentsDir = path.join(REPO_ROOT, 'agents');
886
+ const catalogHooksDir = path.join(REPO_ROOT, 'hooks');
887
+
888
+ if (fs.existsSync(catalogSkillsDir)) {
889
+ const list = fs.readdirSync(catalogSkillsDir, { withFileTypes: true })
890
+ .filter(d => d.isDirectory())
891
+ .map(d => d.name)
892
+ .sort();
893
+ skillsToBundle.push(...list);
894
+ }
895
+
896
+ const pluginSkills = [
897
+ { name: 'antigravity-sdk-orchestrator', src: path.join(REPO_ROOT, 'plugins', 'python-ai', 'skills', 'antigravity-sdk-orchestrator') },
898
+ { name: 'responsive-design', src: path.join(REPO_ROOT, 'plugins', 'web-fullstack', 'skills', 'responsive-design') }
899
+ ];
900
+
901
+ if (fs.existsSync(catalogAgentsDir)) {
902
+ const list = fs.readdirSync(catalogAgentsDir)
903
+ .filter(f => f.endsWith('.md'))
904
+ .sort();
905
+ agentsToBundle.push(...list);
906
+ }
907
+
908
+ if (fs.existsSync(catalogHooksDir)) {
909
+ const list = fs.readdirSync(catalogHooksDir, { withFileTypes: true })
910
+ .filter(d => d.isDirectory())
911
+ .map(d => d.name)
912
+ .sort();
913
+ hooksToBundle.push(...list);
914
+ }
915
+
916
+ const manifest = {
917
+ generator: "everything-gemini",
918
+ version: VERSION,
919
+ profile,
920
+ createdAt: new Date().toISOString(),
921
+ components: {
922
+ skillsCount: skillsToBundle.length + pluginSkills.length,
923
+ subagentsCount: agentsToBundle.length,
924
+ hooksCount: hooksToBundle.length,
925
+ totalCount: skillsToBundle.length + pluginSkills.length + agentsToBundle.length + hooksToBundle.length
926
+ },
927
+ skills: [...skillsToBundle, ...pluginSkills.map(p => p.name)],
928
+ subagents: agentsToBundle,
929
+ hooks: hooksToBundle,
930
+ files: []
383
931
  };
384
- fs.writeFileSync(path.join(targetDir, 'hooks.json'), JSON.stringify(masterHooks, null, 2));
385
- console.log(` ${GREEN}✔${RESET} Generated master hooks.json`);
386
932
 
387
- console.log(`\n${GREEN}${BOLD}🎉 Installation complete! Everything Gemini is active.${RESET}\n`);
933
+ if (isDryRun) {
934
+ if (asJson) {
935
+ console.log(JSON.stringify({
936
+ dryRun: true,
937
+ targetDirectory: destDir,
938
+ manifest
939
+ }, null, 2));
940
+ return;
941
+ }
942
+ printBanner();
943
+ console.log(`${YELLOW}${BOLD}🔍 DRY RUN MODE ACTIVATED - Previewing bundle contents${RESET}`);
944
+ console.log(`Target: ${CYAN}${destDir}${RESET}\n`);
945
+ console.log(` ${CYAN}⚡ Skills to bundle:${RESET} ${skillsToBundle.length + pluginSkills.length}`);
946
+ console.log(` ${CYAN}🤖 Subagents to bundle:${RESET} ${agentsToBundle.length}`);
947
+ console.log(` ${CYAN}🛡️ Hooks to bundle:${RESET} ${hooksToBundle.length}`);
948
+ console.log(` ${CYAN}📦 Total Components:${RESET} ${manifest.components.totalCount}\n`);
949
+ console.log(`${GREEN}${BOLD}✨ Dry run preview complete! 0 files written to disk.${RESET}\n`);
950
+ return;
951
+ }
952
+
953
+ fs.mkdirSync(destDir, { recursive: true });
954
+ const bundleSkillsDir = path.join(destDir, 'skills');
955
+ const bundleAgentsDir = path.join(destDir, 'agents');
956
+ const bundleHooksDir = path.join(destDir, 'hooks');
957
+ const bundleRulesDir = path.join(destDir, 'rules');
958
+ fs.mkdirSync(bundleSkillsDir, { recursive: true });
959
+ fs.mkdirSync(bundleAgentsDir, { recursive: true });
960
+ fs.mkdirSync(bundleHooksDir, { recursive: true });
961
+ fs.mkdirSync(bundleRulesDir, { recursive: true });
962
+
963
+ for (const s of skillsToBundle) {
964
+ const src = path.join(catalogSkillsDir, s);
965
+ const dest = path.join(bundleSkillsDir, s);
966
+ copyRecursiveSync(src, dest);
967
+ const skillMd = path.join(dest, 'SKILL.md');
968
+ if (fs.existsSync(skillMd)) {
969
+ const hash = crypto.createHash('sha256').update(fs.readFileSync(skillMd)).digest('hex');
970
+ manifest.files.push({ path: `skills/${s}/SKILL.md`, sha256: hash });
971
+ }
972
+ }
973
+
974
+ for (const ps of pluginSkills) {
975
+ if (fs.existsSync(ps.src)) {
976
+ const dest = path.join(bundleSkillsDir, ps.name);
977
+ copyRecursiveSync(ps.src, dest);
978
+ const skillMd = path.join(dest, 'SKILL.md');
979
+ if (fs.existsSync(skillMd)) {
980
+ const hash = crypto.createHash('sha256').update(fs.readFileSync(skillMd)).digest('hex');
981
+ manifest.files.push({ path: `skills/${ps.name}/SKILL.md`, sha256: hash });
982
+ }
983
+ }
984
+ }
985
+
986
+ for (const a of agentsToBundle) {
987
+ const src = path.join(catalogAgentsDir, a);
988
+ const dest = path.join(bundleAgentsDir, a);
989
+ fs.copyFileSync(src, dest);
990
+ const hash = crypto.createHash('sha256').update(fs.readFileSync(dest)).digest('hex');
991
+ manifest.files.push({ path: `agents/${a}`, sha256: hash });
992
+ }
993
+
994
+ for (const h of hooksToBundle) {
995
+ const src = path.join(catalogHooksDir, h);
996
+ const dest = path.join(bundleHooksDir, h);
997
+ copyRecursiveSync(src, dest);
998
+ const hookJson = path.join(dest, 'hooks.json');
999
+ if (fs.existsSync(hookJson)) {
1000
+ const hash = crypto.createHash('sha256').update(fs.readFileSync(hookJson)).digest('hex');
1001
+ manifest.files.push({ path: `hooks/${h}/hooks.json`, sha256: hash });
1002
+ }
1003
+ }
1004
+
1005
+ const commonRules = path.join(REPO_ROOT, 'rules', 'common');
1006
+ if (fs.existsSync(commonRules)) {
1007
+ copyRecursiveSync(commonRules, bundleRulesDir);
1008
+ if (fs.existsSync(path.join(bundleRulesDir, 'GEMINI.md'))) {
1009
+ fs.copyFileSync(path.join(bundleRulesDir, 'GEMINI.md'), path.join(destDir, 'GEMINI.md'));
1010
+ }
1011
+ if (fs.existsSync(path.join(bundleRulesDir, 'AGENTS.md'))) {
1012
+ fs.copyFileSync(path.join(bundleRulesDir, 'AGENTS.md'), path.join(destDir, 'AGENTS.md'));
1013
+ }
1014
+ }
1015
+
1016
+ const installerScript = `#!/usr/bin/env bash
1017
+ # Offline Installer for Everything Gemini Bundle
1018
+ set -e
1019
+ TARGET="\${1:-.agents}"
1020
+ mkdir -p "$TARGET/skills" "$TARGET/agents" "$TARGET/hooks"
1021
+ cp -R skills/* "$TARGET/skills/" 2>/dev/null || true
1022
+ cp -R agents/* "$TARGET/agents/" 2>/dev/null || true
1023
+ cp -R hooks/* "$TARGET/hooks/" 2>/dev/null || true
1024
+ [ -f GEMINI.md ] && cp GEMINI.md "$TARGET/GEMINI.md"
1025
+ [ -f AGENTS.md ] && cp AGENTS.md "$TARGET/AGENTS.md"
1026
+ find "$TARGET/hooks" -name "*.sh" -exec chmod +x {} + 2>/dev/null || true
1027
+ echo "✨ Offline Everything Gemini bundle installed cleanly into $TARGET"
1028
+ `.trim();
1029
+ fs.writeFileSync(path.join(destDir, 'offline-install.sh'), installerScript, { mode: 0o755 });
1030
+
1031
+ fs.writeFileSync(path.join(destDir, 'bundle-manifest.json'), JSON.stringify(manifest, null, 2), 'utf8');
1032
+
1033
+ const duration = ((Date.now() - startTime) / 1000).toFixed(2);
1034
+
1035
+ if (asJson) {
1036
+ console.log(JSON.stringify({
1037
+ targetDirectory: destDir,
1038
+ manifest,
1039
+ durationSeconds: parseFloat(duration)
1040
+ }, null, 2));
1041
+ return;
1042
+ }
1043
+
1044
+ printBanner();
1045
+ console.log(`${BOLD}📦 Everything Gemini Offline Distribution Bundle Created${RESET}`);
1046
+ console.log(`Target: ${CYAN}${destDir}${RESET}\n`);
1047
+ console.log(` ${GREEN}✔${RESET} Packaged ${BOLD}${manifest.components.skillsCount}${RESET} progressive disclosure skills`);
1048
+ console.log(` ${GREEN}✔${RESET} Packaged ${BOLD}${manifest.components.subagentsCount}${RESET} scoped subagents`);
1049
+ console.log(` ${GREEN}✔${RESET} Packaged ${BOLD}${manifest.components.hooksCount}${RESET} lifecycle safety hooks`);
1050
+ console.log(` ${GREEN}✔${RESET} Generated ${BOLD}bundle-manifest.json${RESET} with ${manifest.files.length} SHA-256 integrity digests`);
1051
+ console.log(` ${GREEN}✔${RESET} Generated executable ${BOLD}offline-install.sh${RESET}`);
1052
+ console.log(` ${GREEN}✔${RESET} Total bundle duration: ${duration}s\n`);
1053
+ console.log(`${GREEN}${BOLD}✨ Bundle packaging complete! Ready for air-gapped and CI/CD deployment.${RESET}\n`);
388
1054
  }
389
1055
 
390
1056
  function runValidate() {
@@ -399,21 +1065,26 @@ function runValidate() {
399
1065
  }
400
1066
  }
401
1067
 
402
- function scaffoldSkill(name) {
1068
+ function scaffoldSkill(name, customTarget = null, isDryRun = false, asJson = false) {
403
1069
  if (!name) {
404
- console.error(`${RED}Error: Skill name required. Example: everything-gemini new-skill my-skill${RESET}`);
1070
+ console.error(`${RED}Error: Skill name required. Example: everything-gemini scaffold skill my-skill${RESET}`);
405
1071
  process.exit(1);
406
1072
  }
407
1073
  const cleanName = name.toLowerCase().replace(/[^a-z0-9-]/g, '-');
408
- const targetDir = path.join(REPO_ROOT, 'skills', cleanName);
1074
+ const baseSkills = customTarget
1075
+ ? path.join(path.resolve(customTarget), 'skills')
1076
+ : (fs.existsSync(path.join(process.cwd(), '.agents')) ? path.join(process.cwd(), '.agents', 'skills') : path.join(REPO_ROOT, 'skills'));
1077
+ const targetDir = path.join(baseSkills, cleanName);
1078
+
409
1079
  if (fs.existsSync(targetDir)) {
410
- console.error(`${RED}Error: Skill '${cleanName}' already exists at ${targetDir}${RESET}`);
1080
+ if (asJson) {
1081
+ console.log(JSON.stringify({ error: `Skill '${cleanName}' already exists at ${targetDir}` }));
1082
+ } else {
1083
+ console.error(`${RED}Error: Skill '${cleanName}' already exists at ${targetDir}${RESET}`);
1084
+ }
411
1085
  process.exit(1);
412
1086
  }
413
1087
 
414
- fs.mkdirSync(path.join(targetDir, 'references'), { recursive: true });
415
- fs.mkdirSync(path.join(targetDir, 'scripts'), { recursive: true });
416
-
417
1088
  const titleCase = cleanName.split('-').map(s => s.charAt(0).toUpperCase() + s.slice(1)).join(' ');
418
1089
  const skillMd = `---
419
1090
  name: ${cleanName}
@@ -453,12 +1124,29 @@ set -euo pipefail
453
1124
  echo "Executing ${cleanName} automated helper..."
454
1125
  `;
455
1126
 
1127
+ if (isDryRun) {
1128
+ if (asJson) {
1129
+ console.log(JSON.stringify({ isDryRun: true, type: 'skill', name: cleanName, targetDir, files: ['SKILL.md', 'references/spec.md', 'scripts/helper.sh'] }, null, 2));
1130
+ } else {
1131
+ console.log(`${YELLOW}[DRY RUN] Would scaffold skill at:${RESET} ${targetDir}`);
1132
+ console.log(` 📄 SKILL.md, references/spec.md, scripts/helper.sh\n`);
1133
+ }
1134
+ return;
1135
+ }
1136
+
1137
+ fs.mkdirSync(path.join(targetDir, 'references'), { recursive: true });
1138
+ fs.mkdirSync(path.join(targetDir, 'scripts'), { recursive: true });
456
1139
  fs.writeFileSync(path.join(targetDir, 'SKILL.md'), skillMd);
457
1140
  fs.writeFileSync(path.join(targetDir, 'references', 'spec.md'), specMd);
458
1141
  const scriptPath = path.join(targetDir, 'scripts', 'helper.sh');
459
1142
  fs.writeFileSync(scriptPath, helperSh);
460
1143
  try { fs.chmodSync(scriptPath, 0o755); } catch (e) {}
461
1144
 
1145
+ if (asJson) {
1146
+ console.log(JSON.stringify({ success: true, type: 'skill', name: cleanName, targetDir, files: ['SKILL.md', 'references/spec.md', 'scripts/helper.sh'] }, null, 2));
1147
+ return;
1148
+ }
1149
+
462
1150
  console.log(`${GREEN}✔ Created progressive disclosure skill:${RESET} ${BOLD}${cleanName}${RESET}`);
463
1151
  console.log(` 📁 ${targetDir}`);
464
1152
  console.log(` 📄 SKILL.md (YAML frontmatter + procedural workflow)`);
@@ -466,17 +1154,23 @@ echo "Executing ${cleanName} automated helper..."
466
1154
  console.log(` 🔧 scripts/helper.sh (executable helper)\n`);
467
1155
  }
468
1156
 
469
- function scaffoldAgent(name) {
1157
+ function scaffoldAgent(name, customTarget = null, isDryRun = false, asJson = false) {
470
1158
  if (!name) {
471
- console.error(`${RED}Error: Agent name required. Example: everything-gemini new-agent my-agent${RESET}`);
1159
+ console.error(`${RED}Error: Agent name required. Example: everything-gemini scaffold agent my-agent${RESET}`);
472
1160
  process.exit(1);
473
1161
  }
474
1162
  const cleanName = name.toLowerCase().replace(/[^a-z0-9-]/g, '-');
475
- const targetDir = path.join(REPO_ROOT, 'agents');
476
- if (!fs.existsSync(targetDir)) fs.mkdirSync(targetDir, { recursive: true });
477
- const targetFile = path.join(targetDir, `${cleanName}.md`);
1163
+ const baseAgents = customTarget
1164
+ ? path.join(path.resolve(customTarget), 'agents')
1165
+ : (fs.existsSync(path.join(process.cwd(), '.agents')) ? path.join(process.cwd(), '.agents', 'agents') : path.join(REPO_ROOT, 'agents'));
1166
+ const targetFile = path.join(baseAgents, `${cleanName}.md`);
1167
+
478
1168
  if (fs.existsSync(targetFile)) {
479
- console.error(`${RED}Error: Agent '${cleanName}' already exists at ${targetFile}${RESET}`);
1169
+ if (asJson) {
1170
+ console.log(JSON.stringify({ error: `Agent '${cleanName}' already exists at ${targetFile}` }));
1171
+ } else {
1172
+ console.error(`${RED}Error: Agent '${cleanName}' already exists at ${targetFile}${RESET}`);
1173
+ }
480
1174
  process.exit(1);
481
1175
  }
482
1176
 
@@ -502,26 +1196,220 @@ Return structured report to parent agent:
502
1196
  - **Open Questions / Recommended Next Steps**:
503
1197
  `;
504
1198
 
1199
+ if (isDryRun) {
1200
+ if (asJson) {
1201
+ console.log(JSON.stringify({ isDryRun: true, type: 'agent', name: cleanName, targetFile }, null, 2));
1202
+ } else {
1203
+ console.log(`${YELLOW}[DRY RUN] Would scaffold subagent at:${RESET} ${targetFile}\n`);
1204
+ }
1205
+ return;
1206
+ }
1207
+
1208
+ if (!fs.existsSync(baseAgents)) fs.mkdirSync(baseAgents, { recursive: true });
505
1209
  fs.writeFileSync(targetFile, agentMd);
1210
+
1211
+ if (asJson) {
1212
+ console.log(JSON.stringify({ success: true, type: 'agent', name: cleanName, targetFile }, null, 2));
1213
+ return;
1214
+ }
1215
+
506
1216
  console.log(`${GREEN}✔ Created subagent profile:${RESET} ${BOLD}${cleanName}${RESET}`);
507
1217
  console.log(` 📄 ${targetFile}\n`);
508
1218
  }
509
1219
 
510
- function addComponent(type, name) {
511
- if (!type || !name) {
512
- console.error(`${RED}Usage: everything-gemini add <skill|agent|plugin> <name>${RESET}`);
1220
+ function scaffoldHook(name, customTarget = null, isDryRun = false, asJson = false) {
1221
+ if (!name) {
1222
+ console.error(`${RED}Error: Hook name required. Example: everything-gemini scaffold hook my-hook${RESET}`);
513
1223
  process.exit(1);
514
1224
  }
1225
+ const cleanName = name.toLowerCase().replace(/[^a-z0-9-]/g, '-');
1226
+ const baseHooks = customTarget
1227
+ ? path.join(path.resolve(customTarget), 'hooks')
1228
+ : (fs.existsSync(path.join(process.cwd(), '.agents')) ? path.join(process.cwd(), '.agents', 'hooks') : path.join(REPO_ROOT, 'hooks'));
1229
+ const targetDir = path.join(baseHooks, cleanName);
515
1230
 
516
- const cleanName = name.trim().toLowerCase();
517
- const targetWorkspace = path.join(WORKSPACE_DIR, '.agents');
518
- if (!fs.existsSync(targetWorkspace)) {
519
- fs.mkdirSync(targetWorkspace, { recursive: true });
1231
+ if (fs.existsSync(targetDir)) {
1232
+ if (asJson) {
1233
+ console.log(JSON.stringify({ error: `Hook '${cleanName}' already exists at ${targetDir}` }));
1234
+ } else {
1235
+ console.error(`${RED}Error: Hook '${cleanName}' already exists at ${targetDir}${RESET}`);
1236
+ }
1237
+ process.exit(1);
520
1238
  }
521
1239
 
522
- if (type === 'skill') {
523
- const src = path.join(REPO_ROOT, 'skills', cleanName);
524
- if (!fs.existsSync(src)) {
1240
+ const hooksJson = {
1241
+ hooks: [
1242
+ {
1243
+ event: "PreToolExecution",
1244
+ matcher: { tool: "run_command" },
1245
+ action: "execute",
1246
+ script: `scripts/${cleanName}-gate.sh`
1247
+ }
1248
+ ]
1249
+ };
1250
+
1251
+ const scriptSh = `#!/usr/bin/env bash
1252
+ set -euo pipefail
1253
+
1254
+ # Lifecycle hook gate: ${cleanName}
1255
+ INPUT=$(cat)
1256
+ echo "Executing lifecycle hook: ${cleanName}" >&2
1257
+ echo '{"status": "proceed"}'
1258
+ `;
1259
+
1260
+ if (isDryRun) {
1261
+ if (asJson) {
1262
+ console.log(JSON.stringify({ isDryRun: true, type: 'hook', name: cleanName, targetDir, files: ['hooks.json', `scripts/${cleanName}-gate.sh`] }, null, 2));
1263
+ } else {
1264
+ console.log(`${YELLOW}[DRY RUN] Would scaffold hook at:${RESET} ${targetDir}`);
1265
+ console.log(` 📄 hooks.json, scripts/${cleanName}-gate.sh\n`);
1266
+ }
1267
+ return;
1268
+ }
1269
+
1270
+ fs.mkdirSync(path.join(targetDir, 'scripts'), { recursive: true });
1271
+ fs.writeFileSync(path.join(targetDir, 'hooks.json'), JSON.stringify(hooksJson, null, 2));
1272
+ const scriptPath = path.join(targetDir, 'scripts', `${cleanName}-gate.sh`);
1273
+ fs.writeFileSync(scriptPath, scriptSh);
1274
+ try { fs.chmodSync(scriptPath, 0o755); } catch (e) {}
1275
+
1276
+ if (asJson) {
1277
+ console.log(JSON.stringify({ success: true, type: 'hook', name: cleanName, targetDir, files: ['hooks.json', `scripts/${cleanName}-gate.sh`] }, null, 2));
1278
+ return;
1279
+ }
1280
+
1281
+ console.log(`${GREEN}✔ Created lifecycle hook:${RESET} ${BOLD}${cleanName}${RESET}`);
1282
+ console.log(` 📁 ${targetDir}`);
1283
+ console.log(` 📄 hooks.json (event registration)`);
1284
+ console.log(` 🔧 scripts/${cleanName}-gate.sh (executable gate)\n`);
1285
+ }
1286
+
1287
+ function runScaffold(type, name, customTarget = null, isDryRun = false, asJson = false) {
1288
+ if (!type || !name) {
1289
+ console.error(`${RED}Error: Type and name required. Example: everything-gemini scaffold skill my-skill${RESET}`);
1290
+ process.exit(1);
1291
+ }
1292
+ const cleanType = type.toLowerCase();
1293
+ if (['skill', 'skills'].includes(cleanType)) {
1294
+ scaffoldSkill(name, customTarget, isDryRun, asJson);
1295
+ } else if (['agent', 'agents', 'subagent'].includes(cleanType)) {
1296
+ scaffoldAgent(name, customTarget, isDryRun, asJson);
1297
+ } else if (['hook', 'hooks'].includes(cleanType)) {
1298
+ scaffoldHook(name, customTarget, isDryRun, asJson);
1299
+ } else {
1300
+ console.error(`${RED}Error: Unknown scaffold type '${type}'. Supported types: skill, agent, hook${RESET}`);
1301
+ process.exit(1);
1302
+ }
1303
+ }
1304
+
1305
+ function runSync(customTarget = null, isGlobal = false, isDryRun = false, asJson = false, force = false) {
1306
+ const targetDir = isGlobal
1307
+ ? GLOBAL_CONFIG_DIR
1308
+ : (customTarget ? path.resolve(customTarget) : (fs.existsSync(path.join(process.cwd(), '.agents')) ? path.join(process.cwd(), '.agents') : AGENTS_DIR));
1309
+
1310
+ if (!asJson) {
1311
+ printBanner();
1312
+ if (isDryRun) {
1313
+ console.log(`${YELLOW}${BOLD}🔍 DRY RUN MODE ACTIVATED - No files will be modified on disk.${RESET}`);
1314
+ }
1315
+ console.log(`${BOLD}🔄 Synchronizing Workspace with Catalog: ${CYAN}${targetDir}${RESET}\n`);
1316
+ }
1317
+
1318
+ const syncReport = {
1319
+ target: targetDir,
1320
+ timestamp: new Date().toISOString(),
1321
+ isDryRun,
1322
+ syncedSkills: [],
1323
+ syncedAgents: [],
1324
+ syncedHooks: [],
1325
+ upToDateCount: 0,
1326
+ updatedCount: 0,
1327
+ createdCount: 0,
1328
+ success: true,
1329
+ };
1330
+
1331
+ if (!fs.existsSync(targetDir)) {
1332
+ if (isDryRun) {
1333
+ if (asJson) {
1334
+ console.log(JSON.stringify({ ...syncReport, error: 'Target directory does not exist' }, null, 2));
1335
+ } else {
1336
+ console.log(` ${YELLOW}○ Workspace does not exist yet. Run 'everything-gemini install' to initialize.${RESET}\n`);
1337
+ }
1338
+ return;
1339
+ }
1340
+ fs.mkdirSync(targetDir, { recursive: true });
1341
+ }
1342
+
1343
+ // 1. Sync Installed Skills
1344
+ const targetSkills = path.join(targetDir, 'skills');
1345
+ const catalogSkills = path.join(REPO_ROOT, 'skills');
1346
+ if (fs.existsSync(targetSkills) && fs.existsSync(catalogSkills)) {
1347
+ const installed = fs.readdirSync(targetSkills, { withFileTypes: true })
1348
+ .filter(d => d.isDirectory())
1349
+ .map(d => d.name);
1350
+ for (const skill of installed) {
1351
+ const src = path.join(catalogSkills, skill);
1352
+ const dest = path.join(targetSkills, skill);
1353
+ if (fs.existsSync(src)) {
1354
+ if (!isDryRun) copyRecursiveSync(src, dest);
1355
+ syncReport.updatedCount++;
1356
+ syncReport.syncedSkills.push({ name: skill, status: 'synced' });
1357
+ if (!asJson) console.log(` ${GREEN}✔${RESET} Skill synced: ${BOLD}${skill}${RESET}`);
1358
+ }
1359
+ }
1360
+ }
1361
+
1362
+ // 2. Sync Installed Subagents
1363
+ const targetAgents = path.join(targetDir, 'agents');
1364
+ const catalogAgents = path.join(REPO_ROOT, 'agents');
1365
+ if (fs.existsSync(targetAgents) && fs.existsSync(catalogAgents)) {
1366
+ const installed = fs.readdirSync(targetAgents).filter(f => f.endsWith('.md'));
1367
+ for (const ag of installed) {
1368
+ const src = path.join(catalogAgents, ag);
1369
+ const dest = path.join(targetAgents, ag);
1370
+ if (fs.existsSync(src)) {
1371
+ if (!isDryRun) fs.copyFileSync(src, dest);
1372
+ syncReport.updatedCount++;
1373
+ syncReport.syncedAgents.push({ name: ag.replace('.md', ''), status: 'synced' });
1374
+ if (!asJson) console.log(` ${GREEN}✔${RESET} Subagent synced: ${BOLD}${ag.replace('.md', '')}${RESET}`);
1375
+ }
1376
+ }
1377
+ }
1378
+
1379
+ // 3. Ensure Recommended Hooks & Scripts Executability
1380
+ const targetHooksJson = path.join(targetDir, 'hooks.json');
1381
+ if (fs.existsSync(targetHooksJson)) {
1382
+ syncReport.upToDateCount++;
1383
+ syncReport.syncedHooks.push({ name: 'hooks.json', status: 'verified' });
1384
+ if (!asJson) console.log(` ${GREEN}✔${RESET} Lifecycle hooks verified: ${BOLD}hooks.json${RESET}`);
1385
+ }
1386
+
1387
+ if (asJson) {
1388
+ console.log(JSON.stringify(syncReport, null, 2));
1389
+ return;
1390
+ }
1391
+
1392
+ console.log(`\n${GREEN}${BOLD}✨ Synchronization completed! Workspace is aligned with catalog.${RESET}\n`);
1393
+ }
1394
+
1395
+ function addComponent(type, name, isGlobal = false, customTarget = null) {
1396
+ if (!type || !name) {
1397
+ console.error(`${RED}Usage: everything-gemini add <skill|agent|hook|plugin> <name> [--workspace <path>] [--global]${RESET}`);
1398
+ process.exit(1);
1399
+ }
1400
+
1401
+ const cleanName = name.trim().toLowerCase();
1402
+ const targetWorkspace = customTarget
1403
+ ? path.resolve(customTarget)
1404
+ : (isGlobal ? GLOBAL_CONFIG_DIR : path.join(WORKSPACE_DIR, '.agents'));
1405
+
1406
+ if (!fs.existsSync(targetWorkspace)) {
1407
+ fs.mkdirSync(targetWorkspace, { recursive: true });
1408
+ }
1409
+
1410
+ if (type === 'skill') {
1411
+ const src = path.join(REPO_ROOT, 'skills', cleanName);
1412
+ if (!fs.existsSync(src)) {
525
1413
  console.error(`${RED}Skill '${cleanName}' not found in catalog.${RESET}`);
526
1414
  process.exit(1);
527
1415
  }
@@ -538,6 +1426,21 @@ function addComponent(type, name) {
538
1426
  fs.mkdirSync(destDir, { recursive: true });
539
1427
  fs.copyFileSync(src, path.join(destDir, `${cleanName}.md`));
540
1428
  console.log(`${GREEN}✔ Added agent '${cleanName}' to ${destDir}${RESET}`);
1429
+ } else if (type === 'hook') {
1430
+ const src = path.join(REPO_ROOT, 'hooks', cleanName);
1431
+ if (!fs.existsSync(src)) {
1432
+ console.error(`${RED}Hook '${cleanName}' not found in catalog.${RESET}`);
1433
+ process.exit(1);
1434
+ }
1435
+ const dest = path.join(targetWorkspace, 'hooks', cleanName);
1436
+ copyRecursiveSync(src, dest);
1437
+ const scriptsDir = path.join(dest, 'scripts');
1438
+ if (fs.existsSync(scriptsDir)) {
1439
+ fs.readdirSync(scriptsDir).forEach(file => {
1440
+ try { fs.chmodSync(path.join(scriptsDir, file), 0o755); } catch (e) {}
1441
+ });
1442
+ }
1443
+ console.log(`${GREEN}✔ Added hook '${cleanName}' to ${dest}${RESET}`);
541
1444
  } else if (type === 'plugin') {
542
1445
  const src = path.join(REPO_ROOT, 'plugins', cleanName);
543
1446
  if (!fs.existsSync(src)) {
@@ -548,19 +1451,21 @@ function addComponent(type, name) {
548
1451
  copyRecursiveSync(src, dest);
549
1452
  console.log(`${GREEN}✔ Added plugin '${cleanName}' to ${dest}${RESET}`);
550
1453
  } else {
551
- console.error(`${RED}Unknown type '${type}'. Use: skill, agent, or plugin.${RESET}`);
1454
+ console.error(`${RED}Unknown type '${type}'. Use: skill, agent, hook, or plugin.${RESET}`);
552
1455
  process.exit(1);
553
1456
  }
554
1457
  }
555
1458
 
556
- function removeComponent(type, name) {
1459
+ function removeComponent(type, name, isGlobal = false, customTarget = null) {
557
1460
  if (!type || !name) {
558
- console.error(`${RED}Usage: everything-gemini remove <skill|agent|plugin> <name>${RESET}`);
1461
+ console.error(`${RED}Usage: everything-gemini remove <skill|agent|hook|plugin> <name> [--workspace <path>] [--global]${RESET}`);
559
1462
  process.exit(1);
560
1463
  }
561
1464
 
562
1465
  const cleanName = name.trim().toLowerCase();
563
- const targetWorkspace = path.join(WORKSPACE_DIR, '.agents');
1466
+ const targetWorkspace = customTarget
1467
+ ? path.resolve(customTarget)
1468
+ : (isGlobal ? GLOBAL_CONFIG_DIR : path.join(WORKSPACE_DIR, '.agents'));
564
1469
 
565
1470
  if (type === 'skill') {
566
1471
  const dest = path.join(targetWorkspace, 'skills', cleanName);
@@ -569,7 +1474,7 @@ function removeComponent(type, name) {
569
1474
  return;
570
1475
  }
571
1476
  fs.rmSync(dest, { recursive: true, force: true });
572
- console.log(`${GREEN}✔ Removed skill '${cleanName}' from workspace.${RESET}`);
1477
+ console.log(`${GREEN}✔ Removed skill '${cleanName}' from ${dest}.${RESET}`);
573
1478
  } else if (type === 'agent') {
574
1479
  const dest = path.join(targetWorkspace, 'agents', `${cleanName}.md`);
575
1480
  if (!fs.existsSync(dest)) {
@@ -577,7 +1482,15 @@ function removeComponent(type, name) {
577
1482
  return;
578
1483
  }
579
1484
  fs.unlinkSync(dest);
580
- console.log(`${GREEN}✔ Removed agent '${cleanName}' from workspace.${RESET}`);
1485
+ console.log(`${GREEN}✔ Removed agent '${cleanName}' from ${dest}.${RESET}`);
1486
+ } else if (type === 'hook') {
1487
+ const dest = path.join(targetWorkspace, 'hooks', cleanName);
1488
+ if (!fs.existsSync(dest)) {
1489
+ console.log(`${YELLOW}Hook '${cleanName}' is not installed in ${dest}${RESET}`);
1490
+ return;
1491
+ }
1492
+ fs.rmSync(dest, { recursive: true, force: true });
1493
+ console.log(`${GREEN}✔ Removed hook '${cleanName}' from ${dest}.${RESET}`);
581
1494
  } else if (type === 'plugin') {
582
1495
  const dest = path.join(targetWorkspace, 'plugins', cleanName);
583
1496
  if (!fs.existsSync(dest)) {
@@ -585,9 +1498,9 @@ function removeComponent(type, name) {
585
1498
  return;
586
1499
  }
587
1500
  fs.rmSync(dest, { recursive: true, force: true });
588
- console.log(`${GREEN}✔ Removed plugin '${cleanName}' from workspace.${RESET}`);
1501
+ console.log(`${GREEN}✔ Removed plugin '${cleanName}' from ${dest}.${RESET}`);
589
1502
  } else {
590
- console.error(`${RED}Unknown type '${type}'. Use: skill, agent, or plugin.${RESET}`);
1503
+ console.error(`${RED}Unknown type '${type}'. Use: skill, agent, hook, or plugin.${RESET}`);
591
1504
  process.exit(1);
592
1505
  }
593
1506
  }
@@ -654,14 +1567,582 @@ function testSkill(name) {
654
1567
  console.log(`\n${GREEN}${BOLD}✨ Skill '${cleanName}' passed all validation checks!${RESET}\n`);
655
1568
  }
656
1569
 
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`);
1570
+ function searchComponents(query, asJson = false) {
1571
+ if (!query || !query.trim()) {
1572
+ console.log(`${YELLOW}Please specify a search query.${RESET}`);
1573
+ console.log(`Usage: everything-gemini search <term> [--json]\n`);
1574
+ return;
1575
+ }
1576
+ const q = query.trim().toLowerCase();
1577
+ const results = {
1578
+ skills: [],
1579
+ subagents: [],
1580
+ hooks: [],
1581
+ mcp: []
1582
+ };
1583
+
1584
+ // 1. Search Skills (core + plugins)
1585
+ const skillsDir = path.join(REPO_ROOT, 'skills');
1586
+ if (fs.existsSync(skillsDir)) {
1587
+ const skills = fs.readdirSync(skillsDir, { withFileTypes: true })
1588
+ .filter(d => d.isDirectory())
1589
+ .map(d => d.name);
1590
+ for (const skill of skills) {
1591
+ const skillMd = path.join(skillsDir, skill, 'SKILL.md');
1592
+ let desc = '';
1593
+ let fullContent = '';
1594
+ if (fs.existsSync(skillMd)) {
1595
+ fullContent = fs.readFileSync(skillMd, 'utf8');
1596
+ const match = fullContent.match(/description:\s*>?-?\s*([^\n\r]+)/);
1597
+ if (match) desc = match[1].trim();
1598
+ }
1599
+ if (skill.toLowerCase().includes(q) || desc.toLowerCase().includes(q) || fullContent.toLowerCase().includes(q)) {
1600
+ results.skills.push({ name: skill, description: desc || 'Progressive disclosure skill' });
1601
+ }
1602
+ }
1603
+ }
1604
+
1605
+ const pluginsDir = path.join(REPO_ROOT, 'plugins');
1606
+ if (fs.existsSync(pluginsDir)) {
1607
+ const plugins = fs.readdirSync(pluginsDir, { withFileTypes: true })
1608
+ .filter(d => d.isDirectory())
1609
+ .map(d => d.name);
1610
+ for (const p of plugins) {
1611
+ const pSkillsDir = path.join(pluginsDir, p, 'skills');
1612
+ if (fs.existsSync(pSkillsDir)) {
1613
+ const pSkills = fs.readdirSync(pSkillsDir, { withFileTypes: true })
1614
+ .filter(d => d.isDirectory())
1615
+ .map(d => d.name);
1616
+ for (const skill of pSkills) {
1617
+ const skillMd = path.join(pSkillsDir, skill, 'SKILL.md');
1618
+ let desc = '';
1619
+ let fullContent = '';
1620
+ if (fs.existsSync(skillMd)) {
1621
+ fullContent = fs.readFileSync(skillMd, 'utf8');
1622
+ const match = fullContent.match(/description:\s*>?-?\s*([^\n\r]+)/);
1623
+ if (match) desc = match[1].trim();
1624
+ }
1625
+ if (skill.toLowerCase().includes(q) || desc.toLowerCase().includes(q) || fullContent.toLowerCase().includes(q)) {
1626
+ results.skills.push({ name: `${skill} [${p}]`, description: desc || 'Plugin progressive skill' });
1627
+ }
1628
+ }
1629
+ }
1630
+ }
1631
+ }
1632
+
1633
+ // 2. Search Subagents
1634
+ const agentsDir = path.join(REPO_ROOT, 'agents');
1635
+ if (fs.existsSync(agentsDir)) {
1636
+ const agents = fs.readdirSync(agentsDir).filter(f => f.endsWith('.md'));
1637
+ for (const ag of agents) {
1638
+ const name = ag.replace('.md', '');
1639
+ const content = fs.readFileSync(path.join(agentsDir, ag), 'utf8');
1640
+ const missionMatch = content.match(/## Role & Mission\s+([^\n\r]+)/);
1641
+ const mission = missionMatch ? missionMatch[1].trim() : '';
1642
+ if (name.toLowerCase().includes(q) || content.toLowerCase().includes(q)) {
1643
+ results.subagents.push({ name, description: mission || 'Scoped autonomous subagent' });
1644
+ }
1645
+ }
1646
+ }
1647
+
1648
+ // 3. Search Lifecycle Hooks
1649
+ const hooksDir = path.join(REPO_ROOT, 'hooks');
1650
+ if (fs.existsSync(hooksDir)) {
1651
+ const hooks = fs.readdirSync(hooksDir, { withFileTypes: true })
1652
+ .filter(d => d.isDirectory())
1653
+ .map(d => d.name);
1654
+ for (const h of hooks) {
1655
+ const hJson = path.join(hooksDir, h, 'hooks.json');
1656
+ let desc = 'Lifecycle safety gate';
1657
+ if (fs.existsSync(hJson)) {
1658
+ try {
1659
+ const parsed = JSON.parse(fs.readFileSync(hJson, 'utf8'));
1660
+ if (parsed.description) desc = parsed.description;
1661
+ } catch (_) {}
1662
+ }
1663
+ if (h.toLowerCase().includes(q) || desc.toLowerCase().includes(q)) {
1664
+ results.hooks.push({ name: h, description: desc });
1665
+ }
1666
+ }
1667
+ }
1668
+
1669
+ // 4. Search MCP Blueprints
1670
+ const mcpExamplePath = path.join(REPO_ROOT, 'mcp', 'mcp_config.example.json');
1671
+ if (fs.existsSync(mcpExamplePath)) {
1672
+ try {
1673
+ const mcpConfig = JSON.parse(fs.readFileSync(mcpExamplePath, 'utf8'));
1674
+ for (const [srvName, cfg] of Object.entries(mcpConfig.mcpServers || {})) {
1675
+ const cmdStr = `${srvName} ${cfg.command || ''} ${(cfg.args || []).join(' ')}`;
1676
+ if (cmdStr.toLowerCase().includes(q)) {
1677
+ results.mcp.push({ name: srvName, description: (cfg.args || []).join(' ') || cfg.command });
1678
+ }
1679
+ }
1680
+ } catch (_) {}
1681
+ }
1682
+
1683
+ const totalMatches = results.skills.length + results.subagents.length + results.hooks.length + results.mcp.length;
1684
+
1685
+ if (asJson) {
1686
+ console.log(JSON.stringify({ query, totalMatches, results }, null, 2));
1687
+ return;
1688
+ }
1689
+
1690
+ printBanner();
1691
+ console.log(`${BOLD}🔎 Search Results for: "${CYAN}${query}${RESET}${BOLD}" (${GREEN}${totalMatches} found${RESET}${BOLD})${RESET}\n`);
1692
+
1693
+ if (totalMatches === 0) {
1694
+ console.log(` ${YELLOW}○ No matching components found.${RESET}`);
1695
+ console.log(` Run ${GREEN}everything-gemini list${RESET} to browse all 48 skills, 10 subagents, and 7 hooks.\n`);
1696
+ return;
1697
+ }
1698
+
1699
+ if (results.skills.length > 0) {
1700
+ console.log(`${CYAN}${BOLD}⚡ Progressive Skills (${results.skills.length}):${RESET}`);
1701
+ for (const s of results.skills) {
1702
+ console.log(` • ${BOLD}${s.name.padEnd(28)}${RESET} ${GRAY}${s.description}${RESET}`);
1703
+ console.log(` ${GREEN}Add:${RESET} everything-gemini add skill ${s.name.split(' ')[0]}`);
1704
+ }
1705
+ console.log('');
1706
+ }
1707
+
1708
+ if (results.subagents.length > 0) {
1709
+ console.log(`${CYAN}${BOLD}🤖 Scoped Subagents (${results.subagents.length}):${RESET}`);
1710
+ for (const a of results.subagents) {
1711
+ console.log(` • ${BOLD}${a.name.padEnd(28)}${RESET} ${GRAY}${a.description}${RESET}`);
1712
+ console.log(` ${GREEN}Add:${RESET} everything-gemini add agent ${a.name}`);
1713
+ }
1714
+ console.log('');
1715
+ }
1716
+
1717
+ if (results.hooks.length > 0) {
1718
+ console.log(`${CYAN}${BOLD}🛡️ Lifecycle Hooks (${results.hooks.length}):${RESET}`);
1719
+ for (const h of results.hooks) {
1720
+ console.log(` • ${BOLD}${h.name.padEnd(28)}${RESET} ${GRAY}${h.description}${RESET}`);
1721
+ console.log(` ${GREEN}Add:${RESET} everything-gemini add hook ${h.name}`);
1722
+ }
1723
+ console.log('');
1724
+ }
1725
+
1726
+ if (results.mcp.length > 0) {
1727
+ console.log(`${CYAN}${BOLD}🌐 MCP Blueprints (${results.mcp.length}):${RESET}`);
1728
+ for (const m of results.mcp) {
1729
+ console.log(` • ${BOLD}${m.name.padEnd(28)}${RESET} ${GRAY}${m.description}${RESET}`);
1730
+ }
1731
+ console.log('');
1732
+ }
1733
+ }
1734
+
1735
+ function runAudit(targetPath = null, isGlobal = false, asJson = false) {
1736
+ const targetDir = isGlobal
1737
+ ? path.join(os.homedir(), '.gemini', 'config')
1738
+ : (targetPath ? path.resolve(targetPath) : (fs.existsSync(path.join(process.cwd(), '.agents')) ? path.join(process.cwd(), '.agents') : REPO_ROOT));
1739
+
1740
+ const isRepoAudit = (targetDir === REPO_ROOT);
1741
+ const auditReport = {
1742
+ target: targetDir,
1743
+ timestamp: new Date().toISOString(),
1744
+ isRepoCatalog: isRepoAudit,
1745
+ checks: [],
1746
+ passedCount: 0,
1747
+ warningCount: 0,
1748
+ errorCount: 0,
1749
+ valid: true,
1750
+ };
1751
+
1752
+ function addCheck(category, item, status, message, details = null) {
1753
+ if (status === 'error') auditReport.errorCount++;
1754
+ else if (status === 'warn') auditReport.warningCount++;
1755
+ else auditReport.passedCount++;
1756
+ auditReport.checks.push({ category, item, status, message, details });
1757
+ }
1758
+
1759
+ // 1. Audit Skills
1760
+ const skillsBase = isRepoAudit ? path.join(REPO_ROOT, 'skills') : path.join(targetDir, 'skills');
1761
+ if (fs.existsSync(skillsBase)) {
1762
+ const skillEntries = fs.readdirSync(skillsBase, { withFileTypes: true }).filter(d => d.isDirectory());
1763
+ for (const ent of skillEntries) {
1764
+ const skillFile = path.join(skillsBase, ent.name, 'SKILL.md');
1765
+ if (!fs.existsSync(skillFile)) {
1766
+ addCheck('skills', ent.name, 'error', 'Missing SKILL.md in directory');
1767
+ continue;
1768
+ }
1769
+ const raw = fs.readFileSync(skillFile, 'utf8');
1770
+ const lines = raw.split('\n');
1771
+ const parts = raw.split('---');
1772
+ if (parts.length < 3) {
1773
+ addCheck('skills', ent.name, 'error', 'Invalid or missing YAML frontmatter delimiters (---)');
1774
+ continue;
1775
+ }
1776
+ const frontmatter = parts[1];
1777
+ const nameMatch = frontmatter.match(/name:\s*([a-zA-Z0-9_-]+)/);
1778
+ const descMatch = frontmatter.match(/description:\s*>?-?\s*([^\n\r]+)/);
1779
+
1780
+ if (!nameMatch) {
1781
+ addCheck('skills', ent.name, 'error', "Missing 'name' field in YAML frontmatter");
1782
+ } else if (nameMatch[1].trim() !== ent.name) {
1783
+ addCheck('skills', ent.name, 'warn', `Frontmatter name '${nameMatch[1].trim()}' does not match directory '${ent.name}'`);
1784
+ }
1785
+
1786
+ if (!descMatch || !descMatch[1].trim()) {
1787
+ addCheck('skills', ent.name, 'error', "Missing 'description' trigger in YAML frontmatter");
1788
+ }
1789
+
1790
+ if (lines.length > 260) {
1791
+ addCheck('skills', ent.name, 'warn', `Runbook length exceeds 250 lines (${lines.length} lines); consider progressive disclosure sub-references`);
1792
+ } else {
1793
+ addCheck('skills', ent.name, 'pass', `Valid YAML frontmatter and runbook compliance (${lines.length} lines)`);
1794
+ }
1795
+ }
1796
+ }
1797
+
1798
+ // 2. Audit Scoped Subagents
1799
+ const agentsBase = isRepoAudit ? path.join(REPO_ROOT, 'agents') : path.join(targetDir, 'agents');
1800
+ if (fs.existsSync(agentsBase)) {
1801
+ const agentFiles = fs.readdirSync(agentsBase).filter(f => f.endsWith('.md'));
1802
+ for (const f of agentFiles) {
1803
+ const agentPath = path.join(agentsBase, f);
1804
+ const content = fs.readFileSync(agentPath, 'utf8');
1805
+ const hasRole = /#+\s*(Core Role|Role & Mission)/i.test(content);
1806
+ const hasGuardrails = /#+\s*(Execution Guardrails|Tool Permissions)/i.test(content);
1807
+ const hasProtocol = /#+\s*(Delegation Protocol|Protocol|Handoff)/i.test(content);
1808
+
1809
+ if (hasRole && hasGuardrails && hasProtocol) {
1810
+ addCheck('subagents', f, 'pass', 'Complies with Subagent Specification Contract (Role, Guardrails, Handoff)');
1811
+ } else {
1812
+ const missing = [];
1813
+ if (!hasRole) missing.push('Role & Mission');
1814
+ if (!hasGuardrails) missing.push('Guardrails / Tool Permissions');
1815
+ if (!hasProtocol) missing.push('Handoff / Protocol');
1816
+ addCheck('subagents', f, 'error', `Missing required specification sections: ${missing.join(', ')}`);
1817
+ }
1818
+ }
1819
+ }
1820
+
1821
+ // 3. Audit Lifecycle Hooks
1822
+ const hooksBase = isRepoAudit ? path.join(REPO_ROOT, 'hooks') : path.join(targetDir, 'hooks');
1823
+ if (fs.existsSync(hooksBase)) {
1824
+ const hookDirs = fs.readdirSync(hooksBase, { withFileTypes: true }).filter(d => d.isDirectory());
1825
+ for (const hd of hookDirs) {
1826
+ const scriptsDir = path.join(hooksBase, hd.name, 'scripts');
1827
+ if (fs.existsSync(scriptsDir)) {
1828
+ const scripts = fs.readdirSync(scriptsDir).filter(s => s.endsWith('.sh'));
1829
+ for (const s of scripts) {
1830
+ const sPath = path.join(scriptsDir, s);
1831
+ try {
1832
+ fs.accessSync(sPath, fs.constants.X_OK);
1833
+ addCheck('hooks', `${hd.name}/${s}`, 'pass', 'Hook script is executable (+x)');
1834
+ } catch {
1835
+ addCheck('hooks', `${hd.name}/${s}`, 'error', 'Hook script lacks executable permissions (chmod +x)');
1836
+ }
1837
+ }
1838
+ }
1839
+ }
1840
+ }
1841
+
1842
+ auditReport.valid = (auditReport.errorCount === 0);
1843
+
1844
+ if (asJson) {
1845
+ console.log(JSON.stringify(auditReport, null, 2));
1846
+ if (!auditReport.valid) process.exit(1);
1847
+ return;
1848
+ }
1849
+
1850
+ printBanner();
1851
+ console.log(`${BOLD}🛡️ Everything Gemini Ecosystem Audit Report${RESET}`);
1852
+ console.log(`Target: ${CYAN}${targetDir}${RESET} ${isRepoAudit ? `${YELLOW}(Master Repository Catalog)${RESET}` : ''}\n`);
1853
+
1854
+ const categories = ['skills', 'subagents', 'hooks'];
1855
+ for (const cat of categories) {
1856
+ const items = auditReport.checks.filter(c => c.category === cat);
1857
+ if (items.length === 0) continue;
1858
+
1859
+ const catTitle = cat === 'skills' ? '⚡ Progressive Skills' :
1860
+ cat === 'subagents' ? '🤖 Scoped Subagents' : '🛡️ Lifecycle Hooks';
1861
+ console.log(`${BOLD}${catTitle} (${items.length}):${RESET}`);
1862
+ for (const it of items) {
1863
+ const icon = it.status === 'pass' ? `${GREEN}✔${RESET}` :
1864
+ it.status === 'warn' ? `${YELLOW}▲${RESET}` : `${RED}✘${RESET}`;
1865
+ console.log(` ${icon} ${it.item.padEnd(32)} ${it.message}`);
1866
+ }
1867
+ console.log('');
1868
+ }
1869
+
1870
+ console.log(`${BOLD}✨ Audit Summary:${RESET}`);
1871
+ console.log(` Passed Checks: ${GREEN}${auditReport.passedCount}${RESET}`);
1872
+ console.log(` Warnings: ${auditReport.warningCount > 0 ? YELLOW : GREEN}${auditReport.warningCount}${RESET}`);
1873
+ console.log(` Errors: ${auditReport.errorCount > 0 ? RED : GREEN}${auditReport.errorCount}${RESET}\n`);
1874
+
1875
+ if (auditReport.valid) {
1876
+ console.log(` ${GREEN}${BOLD}✔ ALL CHECKS PASSED: Target is 100% compliant with Antigravity Progressive Disclosure standards!${RESET}\n`);
1877
+ } else {
1878
+ console.log(` ${RED}${BOLD}✘ AUDIT FAILED: ${auditReport.errorCount} blocking errors found.${RESET}\n`);
661
1879
  process.exit(1);
662
1880
  }
1881
+ }
1882
+
1883
+ function testAllSkills(asJson = false) {
1884
+ const startTime = Date.now();
1885
+ let skillCount = 0;
1886
+ let totalChars = 0;
1887
+ const skillsGathered = [];
663
1888
 
664
- const cleanName = skillName.trim().replace(/^skills\//, '');
1889
+ // 1. Core Skills
1890
+ const skillsDir = path.join(REPO_ROOT, 'skills');
1891
+ const skills = fs.readdirSync(skillsDir, { withFileTypes: true })
1892
+ .filter(d => d.isDirectory())
1893
+ .map(d => d.name)
1894
+ .sort();
1895
+
1896
+ if (!asJson) {
1897
+ printBanner();
1898
+ console.log(`${BOLD}🧪 Benchmarking & Validating All Skills, Subagents & Hooks...${RESET}\n`);
1899
+ console.log(`${CYAN}${BOLD}⚡ Skills Validation (Progressive Disclosure):${RESET}`);
1900
+ }
1901
+
1902
+ for (const s of skills) {
1903
+ const md = path.join(skillsDir, s, 'SKILL.md');
1904
+ if (fs.existsSync(md)) {
1905
+ const content = fs.readFileSync(md, 'utf8');
1906
+ totalChars += content.length;
1907
+ skillCount++;
1908
+ const estTokens = Math.round(content.length / 4);
1909
+ skillsGathered.push({ name: s, plugin: null, tokens: estTokens });
1910
+ if (!asJson) {
1911
+ console.log(` ${GREEN}✔${RESET} ${s.padEnd(30)} ${GRAY}(~${estTokens} tokens)${RESET}`);
1912
+ }
1913
+ }
1914
+ }
1915
+
1916
+ // 2. Plugin Skills
1917
+ const pluginsDir = path.join(REPO_ROOT, 'plugins');
1918
+ if (fs.existsSync(pluginsDir)) {
1919
+ const plugins = fs.readdirSync(pluginsDir, { withFileTypes: true })
1920
+ .filter(d => d.isDirectory())
1921
+ .map(d => d.name)
1922
+ .sort();
1923
+ for (const p of plugins) {
1924
+ const pSkillsDir = path.join(pluginsDir, p, 'skills');
1925
+ if (fs.existsSync(pSkillsDir)) {
1926
+ const pSkills = fs.readdirSync(pSkillsDir, { withFileTypes: true })
1927
+ .filter(d => d.isDirectory())
1928
+ .map(d => d.name)
1929
+ .sort();
1930
+ for (const s of pSkills) {
1931
+ const md = path.join(pSkillsDir, s, 'SKILL.md');
1932
+ if (fs.existsSync(md)) {
1933
+ const content = fs.readFileSync(md, 'utf8');
1934
+ totalChars += content.length;
1935
+ skillCount++;
1936
+ const estTokens = Math.round(content.length / 4);
1937
+ skillsGathered.push({ name: s, plugin: p, tokens: estTokens });
1938
+ if (!asJson) {
1939
+ console.log(` ${GREEN}✔${RESET} ${(`${s} [${p}]`).padEnd(30)} ${GRAY}(~${estTokens} tokens)${RESET}`);
1940
+ }
1941
+ }
1942
+ }
1943
+ }
1944
+ }
1945
+ }
1946
+
1947
+ // 3. Subagents
1948
+ if (!asJson) console.log(`\n${CYAN}${BOLD}🤖 Scoped Subagents Validation:${RESET}`);
1949
+ const agentsDir = path.join(REPO_ROOT, 'agents');
1950
+ const agents = fs.readdirSync(agentsDir).filter(f => f.endsWith('.md')).sort().map(f => f.replace('.md', ''));
1951
+ if (!asJson) {
1952
+ for (const a of agents) {
1953
+ console.log(` ${GREEN}✔${RESET} ${a.padEnd(30)}`);
1954
+ }
1955
+ }
1956
+
1957
+ // 4. Lifecycle Hooks
1958
+ if (!asJson) console.log(`\n${CYAN}${BOLD}🛡️ Lifecycle Hooks Validation:${RESET}`);
1959
+ const hooksDir = path.join(REPO_ROOT, 'hooks');
1960
+ const hooks = fs.readdirSync(hooksDir, { withFileTypes: true })
1961
+ .filter(d => d.isDirectory())
1962
+ .map(d => d.name)
1963
+ .sort();
1964
+ if (!asJson) {
1965
+ for (const h of hooks) {
1966
+ console.log(` ${GREEN}✔${RESET} ${h.padEnd(30)}`);
1967
+ }
1968
+ }
1969
+
1970
+ const duration = ((Date.now() - startTime) / 1000).toFixed(2);
1971
+ const totalTokens = Math.round(totalChars / 4);
1972
+ const tokenSavings = Math.round(totalTokens * 0.85);
1973
+
1974
+ if (asJson) {
1975
+ console.log(JSON.stringify({
1976
+ version: VERSION,
1977
+ totalComponents: skillCount + agents.length + hooks.length,
1978
+ progressiveSkillsCount: skillCount,
1979
+ scopedAgentsCount: agents.length,
1980
+ lifecycleHooksCount: hooks.length,
1981
+ totalRunbookTokens: totalTokens,
1982
+ estimatedTokensSavedPerTurn: tokenSavings,
1983
+ latencySeconds: parseFloat(duration),
1984
+ skills: skillsGathered,
1985
+ agents,
1986
+ hooks
1987
+ }, null, 2));
1988
+ return;
1989
+ }
1990
+
1991
+ console.log(`\n${GREEN}${BOLD}✨ Benchmark Summary:${RESET}`);
1992
+ console.log(` Total Components: ${BOLD}${skillCount + agents.length + hooks.length}${RESET}`);
1993
+ console.log(` Progressive Skills: ${BOLD}${skillCount}${RESET}`);
1994
+ console.log(` Total Runbook Tokens: ${BOLD}~${totalTokens.toLocaleString()}${RESET}`);
1995
+ console.log(` Estimated Tokens Saved / Turn: ${BOLD}~${tokenSavings.toLocaleString()} tokens (>85%)${RESET}`);
1996
+ console.log(` Diagnostic Latency: ${BOLD}${duration}s${RESET}\n`);
1997
+ }
1998
+
1999
+ function printCompletion(installMode = false, isDryRun = false, customRc = null) {
2000
+ const script = `
2001
+ # Everything Gemini Bash/Zsh completion
2002
+ _everything_gemini() {
2003
+ local cur prev commands skills agents hooks plugins
2004
+ COMPREPLY=()
2005
+ cur="\${COMP_WORDS[COMP_CWORD]}"
2006
+ prev="\${COMP_WORDS[COMP_CWORD-1]}"
2007
+ commands="doctor list init install status check update sync scaffold new 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"
2008
+ 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-r2-object-storage cloudflare-workers context-caching continuous-learning database-architect dbt-transformation debezium-cdc devops-pipeline distributed-rate-limiting 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 milvus-vector-clustering 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 vault-secrets-management vllm-inference wasm-rust-optimizer antigravity-sdk-orchestrator responsive-design"
2009
+ agents="architect browser-qa build-repair code-reviewer database-migrator documentation-writer incident-responder performance-tuner planner platform-engineer release-engineer security-auditor"
2010
+ hooks="auto-lint-formatter ephemeral-context gemini-shield goal-verifier learned-instincts safety-shield secret-scrubber"
2011
+ plugins="core python-ai security-shield web-fullstack"
2012
+
2013
+ case "\${prev}" in
2014
+ everything-gemini|eagy|egemini)
2015
+ COMPREPLY=( $(compgen -W "\${commands}" -- "\${cur}") )
2016
+ return 0
2017
+ ;;
2018
+ add|remove|scaffold|new)
2019
+ COMPREPLY=( $(compgen -W "skill agent hook plugin" -- "\${cur}") )
2020
+ return 0
2021
+ ;;
2022
+ skill|test-skill)
2023
+ COMPREPLY=( $(compgen -W "\${skills}" -- "\${cur}") )
2024
+ return 0
2025
+ ;;
2026
+ agent)
2027
+ COMPREPLY=( $(compgen -W "\${agents}" -- "\${cur}") )
2028
+ return 0
2029
+ ;;
2030
+ hook)
2031
+ COMPREPLY=( $(compgen -W "\${hooks}" -- "\${cur}") )
2032
+ return 0
2033
+ ;;
2034
+ plugin)
2035
+ COMPREPLY=( $(compgen -W "\${plugins}" -- "\${cur}") )
2036
+ return 0
2037
+ ;;
2038
+ info|show|search|find|audit)
2039
+ COMPREPLY=( $(compgen -W "\${skills} \${agents} \${hooks} \${plugins}" -- "\${cur}") )
2040
+ return 0
2041
+ ;;
2042
+ --profile)
2043
+ COMPREPLY=( $(compgen -W "core developer full" -- "\${cur}") )
2044
+ return 0
2045
+ ;;
2046
+ esac
2047
+ }
2048
+ complete -F _everything_gemini everything-gemini egemini eagy
2049
+ `.trim();
2050
+
2051
+ if (!installMode) {
2052
+ console.log(script);
2053
+ return;
2054
+ }
2055
+
2056
+ printBanner();
2057
+ console.log(`${BOLD}🐚 Shell Autocompletion Installer${RESET}\n`);
2058
+
2059
+ let targetRc = customRc;
2060
+ if (!targetRc) {
2061
+ const isZsh = (process.env.SHELL && process.env.SHELL.includes('zsh')) || fs.existsSync(path.join(os.homedir(), '.zshrc'));
2062
+ targetRc = isZsh ? path.join(os.homedir(), '.zshrc') : path.join(os.homedir(), '.bashrc');
2063
+ }
2064
+
2065
+ if (fs.existsSync(targetRc)) {
2066
+ const currentContent = fs.readFileSync(targetRc, 'utf8');
2067
+ if (currentContent.includes('_everything_gemini()')) {
2068
+ console.log(` ${YELLOW}ℹ${RESET} Autocompletion is already configured in ${BOLD}${targetRc}${RESET}`);
2069
+ console.log(` To reload, run: ${GREEN}source ${targetRc}${RESET}\n`);
2070
+ return;
2071
+ }
2072
+ }
2073
+
2074
+ if (isDryRun) {
2075
+ console.log(` ${CYAN}[DRY RUN]${RESET} Would append completion script to: ${BOLD}${targetRc}${RESET}\n`);
2076
+ return;
2077
+ }
2078
+
2079
+ const payload = `\n\n# Everything Gemini Autocompletion\n${script}\n`;
2080
+ fs.appendFileSync(targetRc, payload, 'utf8');
2081
+ console.log(` ${GREEN}✔${RESET} Successfully installed autocompletion into: ${BOLD}${targetRc}${RESET}`);
2082
+ console.log(`\n${GREEN}${BOLD}✨ Ready! Reload your shell with:${RESET}`);
2083
+ console.log(` ${CYAN}source ${targetRc}${RESET}\n`);
2084
+ }
2085
+
2086
+ function showComponentInfo(query1, query2) {
2087
+ let target = query1;
2088
+ let explicitType = null;
2089
+ if (['skill', 'agent', 'hook', 'plugin'].includes(query1) && query2) {
2090
+ explicitType = query1;
2091
+ target = query2;
2092
+ }
2093
+ if (!target) {
2094
+ console.error(`\n${RED}Error: Please specify a component name.${RESET}`);
2095
+ console.log(`Usage: everything-gemini info [skill|agent|hook] <name>\n`);
2096
+ process.exit(1);
2097
+ }
2098
+
2099
+ const cleanName = target.trim().toLowerCase().replace(/^(skills|agents|hooks)\//, '');
2100
+
2101
+ // 1. Check Subagents if type is agent or undefined
2102
+ if (!explicitType || explicitType === 'agent') {
2103
+ const agentMd = path.join(REPO_ROOT, 'agents', `${cleanName}.md`);
2104
+ if (fs.existsSync(agentMd)) {
2105
+ printBanner();
2106
+ console.log(`${BOLD}🤖 Subagent Specification: ${CYAN}${cleanName}${RESET}`);
2107
+ console.log(`Path: ${GRAY}${agentMd}${RESET}\n`);
2108
+ const content = fs.readFileSync(agentMd, 'utf8');
2109
+ const lines = content.split('\n').slice(0, 25);
2110
+ console.log(lines.join('\n'));
2111
+ if (content.split('\n').length > 25) {
2112
+ console.log(`\n${GRAY}... (${content.split('\n').length - 25} more lines in ${agentMd})${RESET}`);
2113
+ }
2114
+ console.log('');
2115
+ return;
2116
+ }
2117
+ }
2118
+
2119
+ // 2. Check Hooks if type is hook or undefined
2120
+ if (!explicitType || explicitType === 'hook') {
2121
+ const hookDir = path.join(REPO_ROOT, 'hooks', cleanName);
2122
+ const hookJson = path.join(hookDir, 'hooks.json');
2123
+ if (fs.existsSync(hookJson)) {
2124
+ printBanner();
2125
+ console.log(`${BOLD}🛡️ Lifecycle Hook: ${CYAN}${cleanName}${RESET}`);
2126
+ console.log(`Directory: ${GRAY}${hookDir}${RESET}\n`);
2127
+ try {
2128
+ const parsed = JSON.parse(fs.readFileSync(hookJson, 'utf8'));
2129
+ console.log(`${BOLD}Configuration (hooks.json):${RESET}`);
2130
+ console.log(JSON.stringify(parsed, null, 2));
2131
+ } catch (e) {
2132
+ console.log(fs.readFileSync(hookJson, 'utf8'));
2133
+ }
2134
+ const scriptsDir = path.join(hookDir, 'scripts');
2135
+ if (fs.existsSync(scriptsDir)) {
2136
+ const scripts = fs.readdirSync(scriptsDir);
2137
+ console.log(`\n${BOLD}Hook Scripts:${RESET}`);
2138
+ scripts.forEach(s => console.log(` 🔧 scripts/${s}`));
2139
+ }
2140
+ console.log('');
2141
+ return;
2142
+ }
2143
+ }
2144
+
2145
+ // 3. Check Skills (Core or Plugin)
665
2146
  let skillDir = path.join(REPO_ROOT, 'skills', cleanName);
666
2147
  let pluginName = null;
667
2148
 
@@ -683,39 +2164,40 @@ function showSkillInfo(skillName) {
683
2164
  }
684
2165
 
685
2166
  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`);
2167
+ if (fs.existsSync(skillMd)) {
2168
+ printBanner();
2169
+ console.log(`${BOLD}📖 Skill Overview: ${CYAN}${cleanName}${RESET}`);
2170
+ if (pluginName) {
2171
+ console.log(`Source Plugin: ${YELLOW}${pluginName}${RESET}`);
706
2172
  }
2173
+ console.log(`Path: ${GRAY}${skillMd}${RESET}\n`);
2174
+
2175
+ const content = fs.readFileSync(skillMd, 'utf8');
2176
+ const parts = content.split('---');
2177
+ if (parts.length >= 3) {
2178
+ const frontmatter = parts[1];
2179
+ const descMatch = frontmatter.match(/description:\s*>?-?\s*([^\n\r]+)/);
2180
+ if (descMatch) {
2181
+ console.log(`${BOLD}🎯 Trigger Description:${RESET}`);
2182
+ console.log(` ${descMatch[1].trim()}\n`);
2183
+ }
707
2184
 
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}`);
2185
+ const body = parts.slice(2).join('---').trim();
2186
+ const lines = body.split('\n').slice(0, 22);
2187
+ console.log(`${BOLD}📋 Playbook Preview:${RESET}`);
2188
+ console.log(lines.join('\n'));
2189
+ if (body.split('\n').length > 22) {
2190
+ console.log(`\n${GRAY}... (${body.split('\n').length - 22} more lines in ${skillMd})${RESET}`);
2191
+ }
2192
+ } else {
2193
+ console.log(content.split('\n').slice(0, 25).join('\n'));
714
2194
  }
715
- } else {
716
- console.log(content.split('\n').slice(0, 25).join('\n'));
2195
+ console.log('');
2196
+ return;
717
2197
  }
718
- console.log('');
2198
+
2199
+ console.error(`\n${RED}Error: Component '${cleanName}' not found in catalog (checked skills, agents, and hooks).${RESET}\n`);
2200
+ process.exit(1);
719
2201
  }
720
2202
 
721
2203
  // CLI Argument Parsing
@@ -729,41 +2211,208 @@ switch (command) {
729
2211
  case 'list':
730
2212
  listComponents();
731
2213
  break;
2214
+ case 'scaffold':
2215
+ case 'new':
2216
+ case 'create': {
2217
+ const type = args[1];
2218
+ const name = args[2];
2219
+ let customTarget = null;
2220
+ let isDryRun = false;
2221
+ let asJson = false;
2222
+ for (let i = 3; i < args.length; i++) {
2223
+ if (args[i] === '--dry-run') isDryRun = true;
2224
+ else if (args[i] === '--json') asJson = true;
2225
+ else if (args[i] === '--workspace' && args[i + 1]) customTarget = args[++i];
2226
+ }
2227
+ runScaffold(type, name, customTarget, isDryRun, asJson);
2228
+ break;
2229
+ }
2230
+ case 'sync': {
2231
+ let isGlobal = false;
2232
+ let customTarget = null;
2233
+ let isDryRun = false;
2234
+ let asJson = false;
2235
+ let force = false;
2236
+ for (let i = 1; i < args.length; i++) {
2237
+ if (args[i] === '--global') isGlobal = true;
2238
+ else if (args[i] === '--dry-run') isDryRun = true;
2239
+ else if (args[i] === '--json') asJson = true;
2240
+ else if (args[i] === '--force') force = true;
2241
+ else if (args[i] === '--workspace' && args[i + 1]) customTarget = args[++i];
2242
+ else if (!args[i].startsWith('-') && !customTarget) customTarget = args[i];
2243
+ }
2244
+ runSync(customTarget, isGlobal, isDryRun, asJson, force);
2245
+ break;
2246
+ }
732
2247
  case 'new-skill':
733
2248
  scaffoldSkill(args[1]);
734
2249
  break;
735
2250
  case 'new-agent':
736
2251
  scaffoldAgent(args[1]);
737
2252
  break;
738
- case 'add':
739
- addComponent(args[1], args[2]);
2253
+ case 'add': {
2254
+ let customTarget = null;
2255
+ let isGlobal = false;
2256
+ for (let i = 3; i < args.length; i++) {
2257
+ if (args[i] === '--global') isGlobal = true;
2258
+ else if (args[i] === '--workspace' && args[i + 1]) customTarget = args[++i];
2259
+ }
2260
+ addComponent(args[1], args[2], isGlobal, customTarget);
740
2261
  break;
741
- case 'remove':
742
- removeComponent(args[1], args[2]);
2262
+ }
2263
+ case 'remove': {
2264
+ let customTarget = null;
2265
+ let isGlobal = false;
2266
+ for (let i = 3; i < args.length; i++) {
2267
+ if (args[i] === '--global') isGlobal = true;
2268
+ else if (args[i] === '--workspace' && args[i + 1]) customTarget = args[++i];
2269
+ }
2270
+ removeComponent(args[1], args[2], isGlobal, customTarget);
743
2271
  break;
2272
+ }
744
2273
  case 'test-skill':
745
2274
  testSkill(args[1]);
746
2275
  break;
2276
+ case 'test-all':
2277
+ case 'test-skills':
2278
+ case 'benchmark': {
2279
+ const asJson = args.includes('--json');
2280
+ testAllSkills(asJson);
2281
+ break;
2282
+ }
2283
+ case 'completion': {
2284
+ const installMode = args.includes('--install') || args.includes('-i');
2285
+ const isDryRun = args.includes('--dry-run');
2286
+ let customRc = null;
2287
+ for (let i = 1; i < args.length; i++) {
2288
+ if (args[i] === '--rc' && args[i + 1]) customRc = args[++i];
2289
+ }
2290
+ printCompletion(installMode, isDryRun, customRc);
2291
+ break;
2292
+ }
747
2293
  case 'info':
748
2294
  case 'show':
749
- showSkillInfo(args[1]);
2295
+ showComponentInfo(args[1], args[2]);
2296
+ break;
2297
+ case 'status':
2298
+ case 'check': {
2299
+ let isGlobal = false;
2300
+ let customTarget = null;
2301
+ let asJson = false;
2302
+ for (let i = 1; i < args.length; i++) {
2303
+ if (args[i] === '--global') isGlobal = true;
2304
+ else if (args[i] === '--json') asJson = true;
2305
+ else if (args[i] === '--workspace' && args[i + 1]) customTarget = args[++i];
2306
+ }
2307
+ runStatus(isGlobal, customTarget, asJson);
750
2308
  break;
2309
+ }
2310
+ case 'diff': {
2311
+ let isGlobal = false;
2312
+ let customTarget = null;
2313
+ for (let i = 1; i < args.length; i++) {
2314
+ if (args[i] === '--global') isGlobal = true;
2315
+ else if (args[i] === '--workspace' && args[i + 1]) customTarget = args[++i];
2316
+ }
2317
+ runDiff(isGlobal, customTarget);
2318
+ break;
2319
+ }
2320
+ case 'export': {
2321
+ let isGlobal = false;
2322
+ let customTarget = null;
2323
+ let outputPath = null;
2324
+ for (let i = 1; i < args.length; i++) {
2325
+ if (args[i] === '--global') isGlobal = true;
2326
+ else if (args[i] === '--workspace' && args[i + 1]) customTarget = args[++i];
2327
+ else if ((args[i] === '--output' || args[i] === '-o') && args[i + 1]) outputPath = args[++i];
2328
+ }
2329
+ runExport(isGlobal, customTarget, outputPath);
2330
+ break;
2331
+ }
2332
+ case 'import': {
2333
+ const inputFile = args[1] && !args[1].startsWith('-') ? args[1] : null;
2334
+ let isGlobal = false;
2335
+ let customTarget = null;
2336
+ let isDryRun = false;
2337
+ for (let i = 1; i < args.length; i++) {
2338
+ if (args[i] === '--global') isGlobal = true;
2339
+ else if (args[i] === '--dry-run') isDryRun = true;
2340
+ else if (args[i] === '--workspace' && args[i + 1]) customTarget = args[++i];
2341
+ }
2342
+ runImport(inputFile, isGlobal, customTarget, isDryRun);
2343
+ break;
2344
+ }
2345
+ case 'bundle':
2346
+ case 'pack': {
2347
+ let profile = 'all';
2348
+ let outputDir = null;
2349
+ let isDryRun = false;
2350
+ let asJson = false;
2351
+ for (let i = 1; i < args.length; i++) {
2352
+ if (args[i] === '--profile' && args[i + 1]) profile = args[++i];
2353
+ else if ((args[i] === '--output' || args[i] === '-o') && args[i + 1]) outputDir = args[++i];
2354
+ else if (args[i] === '--dry-run') isDryRun = true;
2355
+ else if (args[i] === '--json') asJson = true;
2356
+ else if (!args[i].startsWith('-') && !outputDir) outputDir = args[i];
2357
+ }
2358
+ runBundle(profile, outputDir, isDryRun, asJson);
2359
+ break;
2360
+ }
2361
+ case 'update': {
2362
+ let isGlobal = false;
2363
+ let customTarget = null;
2364
+ let isDryRun = false;
2365
+ for (let i = 1; i < args.length; i++) {
2366
+ if (args[i] === '--global') isGlobal = true;
2367
+ else if (args[i] === '--dry-run') isDryRun = true;
2368
+ else if (args[i] === '--workspace' && args[i + 1]) customTarget = args[++i];
2369
+ }
2370
+ runUpdate(isGlobal, customTarget, isDryRun);
2371
+ break;
2372
+ }
751
2373
  case 'init':
752
2374
  case 'install': {
753
2375
  let profile = 'developer';
754
2376
  let isGlobal = false;
755
2377
  let customTarget = null;
2378
+ let isDryRun = false;
756
2379
  for (let i = 1; i < args.length; i++) {
757
2380
  if (args[i] === '--profile' && args[i + 1]) profile = args[++i];
758
2381
  else if (args[i] === '--global') isGlobal = true;
2382
+ else if (args[i] === '--dry-run') isDryRun = true;
759
2383
  else if (args[i] === '--workspace' && args[i + 1]) customTarget = args[++i];
760
2384
  }
761
- installProfile(profile, isGlobal, customTarget);
2385
+ installProfile(profile, isGlobal, customTarget, isDryRun);
762
2386
  break;
763
2387
  }
764
2388
  case 'validate':
765
2389
  runValidate();
766
2390
  break;
2391
+ case 'search':
2392
+ case 'find': {
2393
+ const asJson = args.includes('--json');
2394
+ const queryTerms = args.slice(1).filter(a => !a.startsWith('-')).join(' ');
2395
+ searchComponents(queryTerms, asJson);
2396
+ break;
2397
+ }
2398
+ case 'audit': {
2399
+ let isGlobal = false;
2400
+ let customTarget = null;
2401
+ let asJson = false;
2402
+ for (let i = 1; i < args.length; i++) {
2403
+ if (args[i] === '--global') isGlobal = true;
2404
+ else if (args[i] === '--json') asJson = true;
2405
+ else if (args[i] === '--workspace' && args[i + 1]) customTarget = args[++i];
2406
+ else if (!args[i].startsWith('-') && !customTarget) customTarget = args[i];
2407
+ }
2408
+ runAudit(customTarget, isGlobal, asJson);
2409
+ break;
2410
+ }
2411
+ case 'version':
2412
+ case '--version':
2413
+ case '-v':
2414
+ console.log(VERSION);
2415
+ break;
767
2416
  case 'help':
768
2417
  case '--help':
769
2418
  case '-h':