aiwg
Version:
Cognitive architecture for AI-augmented software development with structured memory, ensemble validation, and closed-loop correction. FAIR-aligned artifacts, 84% cost reduction via human-in-the-loop, standards adopted by 100+ organizations.
182 lines (162 loc) • 4.86 kB
text/typescript
/**
* Extension Registry Loader
*
* Populates the ExtensionRegistry with command definitions and builds
* capability indexes for fast lookup.
*
* @implements @.aiwg/requirements/use-cases/UC-004-extension-system.md
* @architecture @.aiwg/architecture/unified-extension-schema.md
* @tests @test/unit/extensions/loader.test.ts
*/
import { ExtensionRegistry, getRegistry, createRegistry } from './registry.js';
import { CapabilityIndex } from './capability-index.js';
import { commandDefinitions } from './commands/definitions.js';
import { allHandlers } from '../cli/handlers/index.js';
import type { CommandHandler } from '../cli/handlers/types.js';
/**
* Loader options
*/
export interface LoaderOptions {
/**
* Use existing registry or create new
*
* If not provided, a new registry instance is created.
*/
registry?: ExtensionRegistry;
/**
* Include capability indexing
*
* @default false
*/
indexCapabilities?: boolean;
}
/**
* Loaded registry result
*/
export interface LoadedRegistry {
/** Extension registry with all definitions */
registry: ExtensionRegistry;
/** Capability index (if indexCapabilities = true) */
capabilityIndex?: CapabilityIndex;
/** Handler map for O(1) handler lookup */
handlerMap: Map<string, CommandHandler>;
}
/**
* Load and populate the registry
*
* Loads command definitions, registers them with the registry, builds alias
* map, optionally builds capability index, and links handlers to definitions.
*
* @param options - Loader options
* @returns Loaded registry with handler map
*
* @example
* ```typescript
* // Load with capability indexing
* const result = await loadRegistry({ indexCapabilities: true });
*
* // Resolve command alias
* const id = result.registry.resolveCommand('--help'); // 'help'
*
* // Get extension definition
* const ext = result.registry.get(id);
*
* // Get handler
* const handler = result.handlerMap.get(id);
*
* // Query by capability
* const cliCommands = result.capabilityIndex?.getByCapability('cli');
* ```
*/
export async function loadRegistry(options?: LoaderOptions): Promise<LoadedRegistry> {
const { registry = createRegistry(), indexCapabilities = false } = options || {};
// Register all command definitions
for (const definition of commandDefinitions) {
registry.register(definition);
}
// Build alias map from command metadata
for (const definition of commandDefinitions) {
if (definition.type === 'command') {
// Find matching handler to get aliases
const handler = allHandlers.find(h => h.id === definition.id);
if (handler) {
// Register all aliases
for (const alias of handler.aliases) {
registry.registerAlias(alias, definition.id);
}
}
}
}
// Build capability index if requested
let capabilityIndex: CapabilityIndex | undefined;
if (indexCapabilities) {
capabilityIndex = new CapabilityIndex();
for (const extension of registry.getAll()) {
capabilityIndex.index(extension);
}
}
// Link handlers to definitions
const handlerMap = linkHandlers(allHandlers);
return {
registry,
capabilityIndex,
handlerMap,
};
}
/**
* Get the loaded global registry
*
* Convenience function for CLI - uses the global singleton registry.
* This is useful when you want the same registry instance across calls.
*
* @returns Loaded registry with handler map
*
* @example
* ```typescript
* // Get global registry
* const result = await getLoadedRegistry();
*
* // Later, in another module
* const sameResult = await getLoadedRegistry();
* // result.registry === sameResult.registry (same instance)
* ```
*/
export async function getLoadedRegistry(): Promise<LoadedRegistry> {
const globalRegistry = getRegistry();
// Check if already loaded
if (globalRegistry.size === 0) {
// Load into global registry
return loadRegistry({ registry: globalRegistry });
}
// Already loaded - just build handler map
const handlerMap = linkHandlers(allHandlers);
return {
registry: globalRegistry,
handlerMap,
};
}
/**
* Link handlers to command definitions
*
* Creates a map from handler ID to handler instance for O(1) lookup.
* This allows routing from extension definition to handler implementation.
*
* @param handlers - Array of command handlers
* @returns Map of handler ID -> handler
*
* @example
* ```typescript
* const handlerMap = linkHandlers(allHandlers);
* const helpHandler = handlerMap.get('help');
* await helpHandler.execute(ctx);
* ```
*/
export function linkHandlers(
handlers: readonly CommandHandler[]
): Map<string, CommandHandler> {
const handlerMap = new Map<string, CommandHandler>();
for (const handler of handlers) {
handlerMap.set(handler.id, handler);
}
return handlerMap;
}