16 KiB
Data Structures
This document details the key data structures used in the Package Manager, including their definitions, relationships, and usage patterns.
Package and Component Types
The Package Manager uses a type system to categorize different kinds of components:
ComponentType Enumeration
/**
* Supported component types
*/
export type ComponentType = "mode" | "prompt" | "package" | "mcp server"
These types represent the different kinds of components that can be managed by the Package Manager:
- mode: AI assistant personalities with specialized capabilities
- prompt: Pre-configured instructions for specific tasks
- package: Collections of related components
- mcp server: Model Context Protocol servers that provide additional functionality
The type system is extensible, allowing for new component types to be added in the future.
Metadata Interfaces
The Package Manager uses a set of interfaces to define the structure of metadata for different components:
BaseMetadata
/**
* Base metadata interface
*/
export interface BaseMetadata {
name: string
description: string
version: string
tags?: string[]
}
This interface defines the common properties shared by all metadata types:
- name: The display name of the component
- description: A detailed explanation of the component's purpose
- version: The semantic version number
- tags: Optional array of relevant keywords
RepositoryMetadata
/**
* Repository root metadata
*/
export interface RepositoryMetadata extends BaseMetadata {}
This interface represents the metadata for a package source repository. It currently inherits all properties from BaseMetadata without adding additional fields, but is defined separately to allow for future repository-specific extensions.
ComponentMetadata
/**
* Component metadata with type
*/
export interface ComponentMetadata extends BaseMetadata {
type: ComponentType
}
This interface extends BaseMetadata to include a type field, which specifies the component type.
PackageMetadata
/**
* Package metadata with optional subcomponents
*/
export interface PackageMetadata extends ComponentMetadata {
type: "package"
items?: {
type: ComponentType
path: string
metadata?: ComponentMetadata
}[]
}
This interface represents packages that can contain subcomponents:
- type: Always "package" for this interface
- items: Optional array of subcomponents, each with:
- type: The subcomponent type
- path: The file system path to the subcomponent
- metadata: Optional metadata for the subcomponent
SubcomponentMetadata
/**
* Subcomponent metadata with parent reference
*/
export interface SubcomponentMetadata extends ComponentMetadata {
parentPackage: {
name: string
path: string
}
}
This interface represents components that are part of a parent package:
- All fields from ComponentMetadata
- parentPackage: Reference to the parent package
- name: The name of the parent package
- path: The file system path to the parent package
Item Structures
The Package Manager uses several interfaces to represent items in the UI:
MatchInfo
/**
* Information about why an item matched search/filter criteria
*/
export interface MatchInfo {
matched: boolean
matchReason?: {
nameMatch?: boolean
descriptionMatch?: boolean
tagMatch?: boolean
hasMatchingSubcomponents?: boolean
}
}
This interface provides information about why an item matched search or filter criteria:
- matched: Boolean indicating if the item matched
- matchReason: Optional object with specific match reasons
- nameMatch: True if the name matched
- descriptionMatch: True if the description matched
- tagMatch: True if a tag matched
- hasMatchingSubcomponents: True if a subcomponent matched
PackageManagerItem
/**
* Represents an individual package manager item
*/
export interface PackageManagerItem {
name: string
description: string
type: ComponentType
url: string
repoUrl: string
sourceName?: string
author?: string
tags?: string[]
version?: string
lastUpdated?: string
sourceUrl?: string
items?: {
type: ComponentType
path: string
metadata?: ComponentMetadata
lastUpdated?: string
matchInfo?: MatchInfo
}[]
matchInfo?: MatchInfo
}
This interface represents a complete package manager item as displayed in the UI:
- name: The display name of the item
- description: A detailed explanation of the item's purpose
- type: The component type
- url: The URL to the item's source
- repoUrl: The URL to the repository containing the item
- sourceName: Optional name of the source repository
- author: Optional author name
- tags: Optional array of relevant keywords
- version: Optional semantic version number
- lastUpdated: Optional date of last update
- sourceUrl: Optional URL to additional documentation
- items: Optional array of subcomponents
- matchInfo: Optional information about search/filter matches
PackageManagerSource
/**
* Represents a Git repository source for package manager items
*/
export interface PackageManagerSource {
url: string
name?: string
enabled: boolean
}
This interface represents a package source repository:
- url: The URL to the Git repository
- name: Optional display name for the source
- enabled: Boolean indicating if the source is active
PackageManagerRepository
/**
* Represents a repository with its metadata and items
*/
export interface PackageManagerRepository {
metadata: RepositoryMetadata
items: PackageManagerItem[]
url: string
error?: string
}
This interface represents a complete repository with its metadata and items:
- metadata: The repository metadata
- items: Array of items in the repository
- url: The URL to the repository
- error: Optional error message if there was a problem loading the repository
LocalizedMetadata
/**
* Utility type for metadata files with locale
*/
export type LocalizedMetadata<T> = {
[locale: string]: T
}
This utility type represents metadata that can be localized to different languages:
- [locale: string]: Keys are locale identifiers (e.g., "en", "fr")
- T: The type of metadata being localized
UI Component Props
The Package Manager UI components use several prop interfaces:
PackageManagerItemCardProps
interface PackageManagerItemCardProps {
item: PackageManagerItem
filters: { type: string; search: string; tags: string[] }
setFilters: React.Dispatch<React.SetStateAction<{ type: string; search: string; tags: string[] }>>
activeTab: "browse" | "sources"
setActiveTab: React.Dispatch<React.SetStateAction<"browse" | "sources">>
}
This interface defines the props for the PackageManagerItemCard component:
- item: The package item to display
- filters: The current filter state
- setFilters: Function to update filters
- activeTab: The currently active tab
- setActiveTab: Function to change the active tab
ExpandableSectionProps
interface ExpandableSectionProps {
title: string
children: React.ReactNode
className?: string
defaultExpanded?: boolean
badge?: string
}
This interface defines the props for the ExpandableSection component:
- title: The section header text
- children: The content to display when expanded
- className: Optional CSS class name
- defaultExpanded: Optional flag to set initial expanded state
- badge: Optional badge text to display
TypeGroupProps
interface TypeGroupProps {
type: string
items: Array<{
name: string
description?: string
metadata?: any
path?: string
}>
className?: string
searchTerm?: string
}
This interface defines the props for the TypeGroup component:
- type: The component type to display
- items: Array of items of this type
- className: Optional CSS class name
- searchTerm: Optional search term for highlighting matches
Grouped Items Structure
The Package Manager uses a specialized structure for grouping items by type:
GroupedItems
export interface GroupedItems {
[type: string]: {
type: string
items: Array<{
name: string
description?: string
metadata?: any
path?: string
}>
}
}
This interface represents items grouped by their type:
- [type: string]: Keys are component types
- type: The component type (redundant with the key)
- items: Array of items of this type
- name: The item name
- description: Optional item description
- metadata: Optional additional metadata
- path: Optional file system path
Filter and Sort Structures
The Package Manager uses several structures for filtering and sorting:
Filters
interface Filters {
type: string
search: string
tags: string[]
}
This interface represents the filter criteria:
- type: The component type filter
- search: The search term
- tags: Array of tag filters
SortConfig
interface SortConfig {
by: string
order: "asc" | "desc"
}
This interface represents the sort configuration:
- by: The field to sort by (e.g., "name", "author")
- order: The sort order ("asc" for ascending, "desc" for descending)
Message Structures
The Package Manager uses a message-based architecture for communication:
Input Messages
// Get all items
{ type: "getItems" }
// Apply search and filter criteria
{
type: "search",
search: string,
typeFilter: string,
tagFilters: string[]
}
// Add a new package source
{
type: "addSource",
url: string,
name?: string
}
// Remove a package source
{
type: "removeSource",
url: string
}
// Refresh all sources
{ type: "refreshSources" }
Output Messages
// Response with all items
{
type: "items",
data: PackageManagerItem[]
}
// Response with filtered items
{
type: "searchResults",
data: PackageManagerItem[]
}
// Response after adding a source
{
type: "sourceAdded",
data: { success: boolean }
}
// Error response
{
type: "error",
error: string
}
Template Structure
The Package Manager uses a specific directory structure for templates:
Basic Template Structure
package-manager-template/
├── metadata.en.yml # Repository metadata
├── README.md # Repository documentation
├── packages/ # Directory for package components
│ └── data-platform/ # Example package
│ └── metadata.en.yml # Package metadata
├── modes/ # Directory for mode components
│ └── developer-mode/ # Example mode
│ └── metadata.en.yml # Mode metadata
├── mcp servers/ # Directory for MCP server components
│ ├── example-server/ # Example server
│ │ └── metadata.en.yml # Server metadata
│ └── file-analyzer/ # Another example server
│ └── metadata.en.yml # Server metadata
└── groups/ # Directory for grouping components
└── data-engineering/ # Example group
└── metadata.en.yml # Group metadata
Metadata File Structure
# Repository metadata (metadata.en.yml)
name: "Package Manager Template"
description: "A template repository for creating package manager sources"
version: "1.0.0"
# Component metadata (e.g., modes/developer-mode/metadata.en.yml)
name: "Developer Mode"
description: "A specialized mode for software development tasks"
version: "1.0.0"
type: "mode"
tags:
- development
- coding
- software
Data Flow and Transformations
The Package Manager transforms data through several stages:
From File System to Metadata
- Raw YAML files are read from the file system
- YAML is parsed into JavaScript objects
- Objects are validated against metadata interfaces
- Localized metadata is combined into a single structure
From Metadata to Items
- Metadata objects are transformed into PackageManagerItem objects
- File paths are converted to URLs
- Parent-child relationships are established
- Additional information is added (e.g., lastUpdated)
From Items to UI
- Items are filtered based on user criteria
- Match information is added to items
- Items are sorted according to user preferences
- Items are grouped by type for display
Data Validation
The Package Manager includes validation at several levels:
Metadata Validation
function validateMetadata(metadata: any): boolean {
// Required fields
if (!metadata.name || !metadata.description || !metadata.version) {
return false
}
// Type validation for components
if (metadata.type && !["mode", "prompt", "package", "mcp server"].includes(metadata.type)) {
return false
}
// Additional validation...
return true
}
URL Validation
function isValidUrl(urlString: string): boolean {
try {
new URL(urlString)
return true
} catch (e) {
return false
}
}
Tag Validation
function validateTags(tags: any[]): string[] {
if (!Array.isArray(tags)) {
return []
}
return tags.filter((tag) => typeof tag === "string" && tag.trim().length > 0).map((tag) => tag.trim())
}
Data Relationships
The Package Manager maintains several important relationships between data structures:
Parent-Child Relationships
Packages can contain subcomponents, creating a hierarchical structure:
Package
├── Mode
├── MCP Server
├── Prompt
└── Nested Package
├── Mode
└── MCP Server
This relationship is represented in the data structures:
- Packages have an
itemsarray containing subcomponents - Subcomponents have a
parentPackagereference
Source-Item Relationships
Items are associated with their source repositories:
- Each item has a
repoUrlfield pointing to its source - Sources have a list of items they provide
- When a source is disabled, its items are hidden
Type-Group Relationships
Items are grouped by their type for display:
- The
GroupedItemsinterface organizes items by type - Each type group contains items of that type
- The UI displays these groups separately
Serialization and Persistence
The Package Manager serializes data for persistence:
Source Persistence
// Save sources to extension state
private saveState(): void {
this.context.globalState.update("packageManagerSources", this.sources);
}
// Load sources from extension state
private loadState(): void {
const savedSources = this.context.globalState.get<PackageManagerSource[]>("packageManagerSources", []);
this.sources = savedSources;
}
Metadata Caching
// Cache metadata to improve performance
private cacheMetadata(url: string, metadata: any): void {
const cacheKey = `metadata_${url}`;
this.context.globalState.update(cacheKey, {
timestamp: Date.now(),
data: metadata
});
}
// Retrieve cached metadata
private getCachedMetadata(url: string): any | null {
const cacheKey = `metadata_${url}`;
const cached = this.context.globalState.get(cacheKey);
if (!cached || Date.now() - cached.timestamp > CACHE_TTL) {
return null;
}
return cached.data;
}
Data Structure Evolution
The Package Manager's data structures are designed for evolution:
Versioning Strategy
- Interfaces include version fields
- New fields are added as optional
- Breaking changes are avoided when possible
- Migration code handles legacy data formats
Extensibility Points
- The ComponentType can be extended with new types
- Metadata interfaces can be extended with new fields
- The message system can handle new message types
- The UI can adapt to display new data formats
Previous: Core Components | Next: Search and Filter Implementation