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.
- package/.github/ISSUE_TEMPLATE/bug_report.md +29 -0
- package/.github/ISSUE_TEMPLATE/feature_request.md +27 -0
- package/.github/ISSUE_TEMPLATE/subagent_proposal.md +29 -0
- package/.github/workflows/ci.yml +72 -1
- package/.github/workflows/release.yml +17 -2
- package/CHANGELOG.md +178 -0
- package/CONTRIBUTING.md +90 -4
- package/README.md +147 -23
- package/action.yml +35 -0
- package/agents/browser-qa.md +1 -1
- package/agents/database-migrator.md +26 -0
- package/agents/documentation-writer.md +27 -0
- package/agents/incident-responder.md +34 -0
- package/agents/performance-tuner.md +27 -0
- package/agents/platform-engineer.md +33 -0
- package/agents/release-engineer.md +34 -0
- package/bin/everything-gemini +1791 -142
- package/docs/COMMUNITY_SUBMISSIONS.md +88 -0
- package/docs/LAUNCH_KIT.md +138 -13
- package/docs/architecture/progressive-disclosure.md +3 -3
- package/docs/index.html +410 -40
- package/docs/launch-kit.md +163 -0
- package/examples/cli-workflows/demo_workflow.sh +15 -7
- package/examples/python-sdk/README.md +32 -5
- package/examples/python-sdk/documentation_audit_pipeline.py +83 -0
- package/examples/python-sdk/incident_triage_pipeline.py +170 -0
- package/examples/python-sdk/multi_agent_pipeline.py +95 -0
- package/examples/python-sdk/platform_provisioning_pipeline.py +193 -0
- package/examples/python-sdk/release_readiness_audit.py +144 -0
- package/hooks/secret-scrubber/hooks.json +16 -0
- package/hooks/secret-scrubber/scripts/scrub-secrets.sh +62 -0
- package/mcp/README.md +21 -0
- package/mcp/mcp_config.example.json +39 -0
- package/package.json +3 -1
- package/plugins/core/rules/core-practices.md +63 -4
- package/plugins/python-ai/rules/ai-agent-patterns.md +67 -4
- package/plugins/security-shield/rules/zero-trust.md +60 -4
- package/plugins/web-fullstack/rules/frontend-standards.md +74 -4
- package/rules/paradigms/security-hardened.md +53 -10
- package/rules/paradigms/tdd.md +65 -8
- package/scripts/install.ps1 +14 -0
- package/scripts/install.sh +15 -1
- package/scripts/validate.sh +103 -12
- package/skills/apache-kafka-streams/SKILL.md +152 -0
- package/skills/argo-workflows/SKILL.md +151 -0
- package/skills/axum-web-service/SKILL.md +159 -0
- package/skills/cilium-ebpf-networking/SKILL.md +145 -0
- package/skills/clickhouse-analytics/SKILL.md +128 -0
- package/skills/cloudflare-r2-object-storage/SKILL.md +143 -0
- package/skills/dbt-transformation/SKILL.md +179 -0
- package/skills/debezium-cdc/SKILL.md +166 -0
- package/skills/distributed-rate-limiting/SKILL.md +138 -0
- package/skills/duckdb-local-olap/SKILL.md +134 -0
- package/skills/fastapi-production/SKILL.md +157 -0
- package/skills/grpc-connect-rpc/SKILL.md +176 -0
- package/skills/langgraph-orchestrator/SKILL.md +144 -0
- package/skills/litellm-proxy-gateway/SKILL.md +154 -0
- package/skills/milvus-vector-clustering/SKILL.md +134 -0
- package/skills/nats-jetstream/SKILL.md +122 -0
- package/skills/open-telemetry-tracing/SKILL.md +151 -0
- package/skills/playwright-visual-regression/SKILL.md +124 -0
- package/skills/redis-cache-patterns/SKILL.md +159 -0
- package/skills/svelte-kit-architect/SKILL.md +190 -0
- package/skills/temporal-workflows/SKILL.md +158 -0
- package/skills/trpc-react-query/SKILL.md +169 -0
- package/skills/turborepo-monorepo/SKILL.md +199 -0
- package/skills/vault-secrets-management/SKILL.md +129 -0
- package/skills/vllm-inference/SKILL.md +144 -0
- package/skills/wasm-rust-optimizer/SKILL.md +130 -0
- package/templates/full-power/hooks.json +14 -0
- package/templates/full-power/mcp_config.json +47 -0
- package/templates/recommended/hooks.json +14 -0
- package/tests/cli.test.js +447 -0
package/bin/everything-gemini
CHANGED
|
@@ -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}
|
|
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}
|
|
57
|
-
console.log(
|
|
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}
|
|
60
|
-
console.log(` ${CYAN}--workspace <path>${RESET}
|
|
61
|
-
console.log(` ${CYAN}--
|
|
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(
|
|
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
|
-
|
|
267
|
-
|
|
268
|
-
|
|
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
|
-
//
|
|
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
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
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
|
-
|
|
308
|
-
|
|
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
|
-
|
|
344
|
-
|
|
345
|
-
|
|
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
|
-
|
|
348
|
-
|
|
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
|
-
|
|
352
|
-
|
|
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
|
-
|
|
356
|
-
|
|
357
|
-
|
|
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
|
-
//
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
|
476
|
-
|
|
477
|
-
|
|
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
|
-
|
|
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
|
|
511
|
-
if (!
|
|
512
|
-
console.error(`${RED}
|
|
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
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
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
|
-
|
|
523
|
-
|
|
524
|
-
|
|
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
|
|
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 =
|
|
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
|
|
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
|
|
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
|
|
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
|
|
658
|
-
if (!
|
|
659
|
-
console.
|
|
660
|
-
console.log(`Usage: everything-gemini
|
|
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
|
-
|
|
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 (
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
printBanner();
|
|
692
|
-
console.log(`${BOLD}📖 Skill Overview: ${CYAN}${cleanName}${RESET}`);
|
|
693
|
-
if (pluginName) {
|
|
694
|
-
console.log(`Source Plugin: ${YELLOW}${pluginName}${RESET}`);
|
|
695
|
-
}
|
|
696
|
-
console.log(`Path: ${GRAY}${skillMd}${RESET}\n`);
|
|
697
|
-
|
|
698
|
-
const content = fs.readFileSync(skillMd, 'utf8');
|
|
699
|
-
const parts = content.split('---');
|
|
700
|
-
if (parts.length >= 3) {
|
|
701
|
-
const frontmatter = parts[1];
|
|
702
|
-
const descMatch = frontmatter.match(/description:\s*>?-?\s*([^\n\r]+)/);
|
|
703
|
-
if (descMatch) {
|
|
704
|
-
console.log(`${BOLD}🎯 Trigger Description:${RESET}`);
|
|
705
|
-
console.log(` ${descMatch[1].trim()}\n`);
|
|
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
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
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
|
-
|
|
716
|
-
|
|
2195
|
+
console.log('');
|
|
2196
|
+
return;
|
|
717
2197
|
}
|
|
718
|
-
|
|
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
|
-
|
|
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
|
-
|
|
742
|
-
|
|
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
|
-
|
|
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':
|