feat: Add intelligent auto-router and enhanced integrations
- Add intelligent-router.sh hook for automatic agent routing - Add AUTO-TRIGGER-SUMMARY.md documentation - Add FINAL-INTEGRATION-SUMMARY.md documentation - Complete Prometheus integration (6 commands + 4 tools) - Complete Dexto integration (12 commands + 5 tools) - Enhanced Ralph with access to all agents - Fix /clawd command (removed disable-model-invocation) - Update hooks.json to v5 with intelligent routing - 291 total skills now available - All 21 commands with automatic routing 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,193 @@
|
||||
/**
|
||||
* Plugin Marketplace Registry
|
||||
*
|
||||
* Manages the known_marketplaces.json file that tracks registered marketplaces.
|
||||
*/
|
||||
|
||||
import * as path from 'path';
|
||||
import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'fs';
|
||||
import { homedir } from 'os';
|
||||
import { KnownMarketplacesFileSchema } from './schemas.js';
|
||||
import { MarketplaceError } from './errors.js';
|
||||
import type { KnownMarketplacesFile, MarketplaceEntry, MarketplaceSource } from './types.js';
|
||||
|
||||
/**
|
||||
* Default marketplace configuration
|
||||
* Claude Code's official plugin marketplace is included by default
|
||||
*/
|
||||
export const DEFAULT_MARKETPLACES: Array<{
|
||||
name: string;
|
||||
source: MarketplaceSource;
|
||||
}> = [
|
||||
{
|
||||
name: 'claude-plugins-official',
|
||||
source: {
|
||||
type: 'github',
|
||||
value: 'anthropics/claude-plugins-official',
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
/**
|
||||
* Get the path to known_marketplaces.json
|
||||
*/
|
||||
export function getMarketplacesRegistryPath(): string {
|
||||
return path.join(homedir(), '.dexto', 'plugins', 'known_marketplaces.json');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the directory where marketplaces are cloned
|
||||
*/
|
||||
export function getMarketplacesDir(): string {
|
||||
return path.join(homedir(), '.dexto', 'plugins', 'marketplaces');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the marketplace cache directory (for versioned plugin copies)
|
||||
*/
|
||||
export function getMarketplaceCacheDir(): string {
|
||||
return path.join(homedir(), '.dexto', 'plugins', 'cache');
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the known marketplaces registry
|
||||
*/
|
||||
export function loadKnownMarketplaces(): KnownMarketplacesFile {
|
||||
const filePath = getMarketplacesRegistryPath();
|
||||
|
||||
if (!existsSync(filePath)) {
|
||||
return { version: 1, marketplaces: {} };
|
||||
}
|
||||
|
||||
try {
|
||||
const content = readFileSync(filePath, 'utf-8');
|
||||
const parsed = JSON.parse(content);
|
||||
const result = KnownMarketplacesFileSchema.safeParse(parsed);
|
||||
|
||||
if (!result.success) {
|
||||
// Invalid file - return fresh structure
|
||||
return { version: 1, marketplaces: {} };
|
||||
}
|
||||
|
||||
return result.data as KnownMarketplacesFile;
|
||||
} catch {
|
||||
// File read/parse error - return fresh structure
|
||||
return { version: 1, marketplaces: {} };
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the known marketplaces registry
|
||||
*/
|
||||
export function saveKnownMarketplaces(data: KnownMarketplacesFile): void {
|
||||
const filePath = getMarketplacesRegistryPath();
|
||||
const dirPath = path.dirname(filePath);
|
||||
|
||||
// Ensure directory exists
|
||||
if (!existsSync(dirPath)) {
|
||||
mkdirSync(dirPath, { recursive: true });
|
||||
}
|
||||
|
||||
try {
|
||||
writeFileSync(filePath, JSON.stringify(data, null, 2), 'utf-8');
|
||||
} catch (error) {
|
||||
throw MarketplaceError.registryWriteFailed(
|
||||
filePath,
|
||||
error instanceof Error ? error.message : String(error)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a specific marketplace entry by name
|
||||
*/
|
||||
export function getMarketplaceEntry(name: string): MarketplaceEntry | null {
|
||||
const registry = loadKnownMarketplaces();
|
||||
return registry.marketplaces[name] || null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a marketplace exists by name
|
||||
*/
|
||||
export function marketplaceExists(name: string): boolean {
|
||||
return getMarketplaceEntry(name) !== null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all registered marketplaces
|
||||
*/
|
||||
export function getAllMarketplaces(): MarketplaceEntry[] {
|
||||
const registry = loadKnownMarketplaces();
|
||||
return Object.values(registry.marketplaces);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a marketplace entry to the registry
|
||||
*/
|
||||
export function addMarketplaceEntry(entry: MarketplaceEntry): void {
|
||||
const registry = loadKnownMarketplaces();
|
||||
registry.marketplaces[entry.name] = entry;
|
||||
saveKnownMarketplaces(registry);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a marketplace entry from the registry
|
||||
*/
|
||||
export function removeMarketplaceEntry(name: string): boolean {
|
||||
const registry = loadKnownMarketplaces();
|
||||
|
||||
if (!registry.marketplaces[name]) {
|
||||
return false;
|
||||
}
|
||||
|
||||
delete registry.marketplaces[name];
|
||||
saveKnownMarketplaces(registry);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a marketplace entry's lastUpdated timestamp
|
||||
*/
|
||||
export function updateMarketplaceTimestamp(name: string): void {
|
||||
const registry = loadKnownMarketplaces();
|
||||
|
||||
if (registry.marketplaces[name]) {
|
||||
registry.marketplaces[name].lastUpdated = new Date().toISOString();
|
||||
saveKnownMarketplaces(registry);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get default marketplaces that are not yet installed
|
||||
* Returns entries with a special flag indicating they need to be added
|
||||
*/
|
||||
export function getUninstalledDefaults(): Array<{
|
||||
name: string;
|
||||
source: MarketplaceSource;
|
||||
isDefault: true;
|
||||
}> {
|
||||
const registry = loadKnownMarketplaces();
|
||||
const uninstalled: Array<{
|
||||
name: string;
|
||||
source: MarketplaceSource;
|
||||
isDefault: true;
|
||||
}> = [];
|
||||
|
||||
for (const defaultMarket of DEFAULT_MARKETPLACES) {
|
||||
if (!registry.marketplaces[defaultMarket.name]) {
|
||||
uninstalled.push({
|
||||
...defaultMarket,
|
||||
isDefault: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return uninstalled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a marketplace is a default marketplace
|
||||
*/
|
||||
export function isDefaultMarketplace(name: string): boolean {
|
||||
return DEFAULT_MARKETPLACES.some((m) => m.name === name);
|
||||
}
|
||||
Reference in New Issue
Block a user