agentic-data-stack-community
Version:
AI Agentic Data Stack Framework - Community Edition. Open source data engineering framework with 4 core agents, essential templates, and 3-dimensional quality validation.
1,263 lines (1,091 loc) ⢠41.8 kB
JavaScript
/**
* Knowledge Base Integration System
*
* Implements advanced knowledge management with:
* - Dynamic knowledge base loading and indexing
* - Contextual knowledge retrieval and search
* - Technical preferences and personalization
* - Interactive KB mode with guided exploration
* - Multi-source knowledge aggregation
* - Version-aware documentation management
* - Agent-specific knowledge filtering
* - Real-time knowledge updates and caching
*/
const chalk = require('chalk');
const inquirer = require('inquirer');
const fs = require('fs-extra');
const path = require('path');
const yaml = require('yaml');
class KnowledgeBase {
constructor(options = {}) {
this.rootDir = options.rootDir || process.cwd();
this.dataCore = path.join(this.rootDir, 'data-core');
this.kbPath = path.join(this.dataCore, 'data');
this.docsPath = path.join(this.rootDir, 'docs');
this.knowledgeIndex = new Map();
this.searchIndex = new Map();
this.technicalPreferences = new Map();
this.sessionContext = new Map();
this.cacheTimeout = options.cacheTimeout || 3600000; // 1 hour
this.lastIndexTime = null;
this.agentOrchestrator = options.agentOrchestrator;
this.documentManager = options.documentManager;
}
/**
* Initialize knowledge base and load core data
*/
async initialize() {
console.log(chalk.blue('š§ Initializing Knowledge Base...'));
try {
// Load core knowledge documents
await this.loadCoreKnowledge();
// Load technical preferences
await this.loadTechnicalPreferences();
// Build search index
await this.buildSearchIndex();
// Load project-specific documentation
await this.loadProjectDocumentation();
console.log(chalk.green('ā
Knowledge Base initialized successfully'));
return { success: true, documentsLoaded: this.knowledgeIndex.size };
} catch (error) {
console.error(chalk.red(`ā Knowledge Base initialization failed: ${error.message}`));
return { success: false, error: error.message };
}
}
/**
* Load core knowledge documents from data-core
*/
async loadCoreKnowledge() {
const coreFiles = [
'bmad-kb.md',
'elicitation-methods.md',
'brainstorming-techniques.md',
'technical-preferences.md'
];
for (const file of coreFiles) {
const filePath = path.join(this.kbPath, file);
if (await fs.pathExists(filePath)) {
const content = await fs.readFile(filePath, 'utf8');
const metadata = this.extractMetadata(content);
this.knowledgeIndex.set(file, {
path: filePath,
content,
metadata,
type: 'core',
lastModified: (await fs.stat(filePath)).mtime,
category: this.categorizeDocument(file, content)
});
}
}
// Load additional knowledge files from data directory
if (await fs.pathExists(this.kbPath)) {
const files = await fs.readdir(this.kbPath);
for (const file of files) {
if (file.endsWith('.md') && !coreFiles.includes(file)) {
await this.loadKnowledgeFile(path.join(this.kbPath, file), 'data');
}
}
}
}
/**
* Load a knowledge file and index it
*/
async loadKnowledgeFile(filePath, type = 'custom') {
try {
const content = await fs.readFile(filePath, 'utf8');
const fileName = path.basename(filePath);
const metadata = this.extractMetadata(content);
this.knowledgeIndex.set(fileName, {
path: filePath,
content,
metadata,
type,
lastModified: (await fs.stat(filePath)).mtime,
category: this.categorizeDocument(fileName, content)
});
} catch (error) {
console.warn(chalk.yellow(`Warning: Could not load ${filePath}: ${error.message}`));
}
}
/**
* Load technical preferences
*/
async loadTechnicalPreferences() {
const prefsPath = path.join(this.kbPath, 'technical-preferences.md');
if (await fs.pathExists(prefsPath)) {
const content = await fs.readFile(prefsPath, 'utf8');
const preferences = this.parseTechnicalPreferences(content);
preferences.forEach(pref => {
this.technicalPreferences.set(pref.category, pref);
});
}
// Load user-specific preferences if available
const userPrefsPath = path.join(this.rootDir, '.technical-preferences.yaml');
if (await fs.pathExists(userPrefsPath)) {
try {
const userPrefs = await fs.readFile(userPrefsPath, 'utf8');
const parsed = yaml.parse(userPrefs);
Object.entries(parsed).forEach(([category, prefs]) => {
this.technicalPreferences.set(category, {
category,
preferences: prefs,
source: 'user'
});
});
} catch (error) {
console.warn(chalk.yellow('Warning: Could not parse user preferences'));
}
}
}
/**
* Parse technical preferences from markdown
*/
parseTechnicalPreferences(content) {
const preferences = [];
const lines = content.split('\n');
let currentCategory = null;
let currentPrefs = [];
for (const line of lines) {
if (line.startsWith('## ')) {
if (currentCategory && currentPrefs.length > 0) {
preferences.push({
category: currentCategory,
preferences: currentPrefs,
source: 'default'
});
}
currentCategory = line.replace('## ', '').trim();
currentPrefs = [];
} else if (line.trim().startsWith('- ')) {
currentPrefs.push(line.trim().substring(2));
}
}
if (currentCategory && currentPrefs.length > 0) {
preferences.push({
category: currentCategory,
preferences: currentPrefs,
source: 'default'
});
}
return preferences;
}
/**
* Build search index for fast retrieval
*/
async buildSearchIndex() {
console.log(chalk.dim('Building search index...'));
this.knowledgeIndex.forEach((doc, fileName) => {
// Extract searchable terms
const terms = this.extractSearchTerms(doc.content);
terms.forEach(term => {
if (!this.searchIndex.has(term)) {
this.searchIndex.set(term, []);
}
this.searchIndex.get(term).push(fileName);
});
// Index metadata
if (doc.metadata.tags) {
doc.metadata.tags.forEach(tag => {
const tagKey = `tag:${tag}`;
if (!this.searchIndex.has(tagKey)) {
this.searchIndex.set(tagKey, []);
}
this.searchIndex.get(tagKey).push(fileName);
});
}
});
this.lastIndexTime = new Date();
}
/**
* Extract search terms from content
*/
extractSearchTerms(content) {
const terms = new Set();
// Extract words (alphanumeric, minimum 3 characters)
const words = content.toLowerCase().match(/\b[a-z0-9]{3,}\b/g) || [];
words.forEach(word => terms.add(word));
// Extract headings
const headings = content.match(/^#{1,6}\s+(.+)$/gm) || [];
headings.forEach(heading => {
const clean = heading.replace(/^#{1,6}\s+/, '').toLowerCase();
terms.add(clean);
// Also add individual words from headings
clean.split(/\s+/).forEach(word => {
if (word.length >= 3) terms.add(word);
});
});
// Extract code identifiers
const codeBlocks = content.match(/`([^`]+)`/g) || [];
codeBlocks.forEach(block => {
const identifier = block.replace(/`/g, '').toLowerCase();
if (identifier.length >= 3) terms.add(identifier);
});
return Array.from(terms);
}
/**
* Extract metadata from document content
*/
extractMetadata(content) {
const metadata = {
title: '',
description: '',
tags: [],
category: '',
lastUpdated: null
};
// Extract title from first H1
const titleMatch = content.match(/^#\s+(.+)$/m);
if (titleMatch) {
metadata.title = titleMatch[1];
}
// Extract description from overview section or first paragraph
const overviewMatch = content.match(/##\s+Overview\s*\n\n([^\n]+)/);
if (overviewMatch) {
metadata.description = overviewMatch[1];
} else {
const firstParaMatch = content.match(/^#[^\n]+\n\n([^\n]+)/);
if (firstParaMatch) {
metadata.description = firstParaMatch[1];
}
}
// Extract tags from content patterns
if (content.includes('workflow')) metadata.tags.push('workflow');
if (content.includes('template')) metadata.tags.push('template');
if (content.includes('agent')) metadata.tags.push('agent');
if (content.includes('development')) metadata.tags.push('development');
if (content.includes('configuration')) metadata.tags.push('configuration');
return metadata;
}
/**
* Categorize document based on content
*/
categorizeDocument(fileName, content) {
const fileNameLower = fileName.toLowerCase();
const contentLower = content.toLowerCase();
if (fileNameLower.includes('install') || contentLower.includes('installation')) {
return 'setup';
} else if (fileNameLower.includes('workflow')) {
return 'workflows';
} else if (fileNameLower.includes('agent') || contentLower.includes('## agents')) {
return 'agents';
} else if (fileNameLower.includes('template') || fileNameLower.includes('prd') || fileNameLower.includes('architecture')) {
return 'documents';
} else if (contentLower.includes('agile') || contentLower.includes('scrum')) {
return 'agile';
} else if (fileNameLower.includes('config') || contentLower.includes('configuration')) {
return 'configuration';
} else if (fileNameLower.includes('best') || fileNameLower.includes('practice')) {
return 'best-practices';
} else {
return 'general';
}
}
/**
* Load project-specific documentation
*/
async loadProjectDocumentation() {
if (!await fs.pathExists(this.docsPath)) {
return;
}
const docFiles = await this.findMarkdownFiles(this.docsPath);
for (const file of docFiles) {
await this.loadKnowledgeFile(file, 'project');
}
}
/**
* Recursively find markdown files
*/
async findMarkdownFiles(dir, files = []) {
const entries = await fs.readdir(dir, { withFileTypes: true });
for (const entry of entries) {
const fullPath = path.join(dir, entry.name);
if (entry.isDirectory() && !entry.name.startsWith('.')) {
await this.findMarkdownFiles(fullPath, files);
} else if (entry.isFile() && entry.name.endsWith('.md')) {
files.push(fullPath);
}
}
return files;
}
/**
* Interactive KB mode interface
*/
async enterKBMode(context = {}) {
console.log(chalk.bold.blue('\nš§ Knowledge Base Mode Activated'));
console.log(chalk.dim('Access to comprehensive framework knowledge and project documentation\n'));
const topicAreas = [
'Setup & Installation - Getting started with the framework',
'Workflows - Choosing the right workflow for your project',
'Web vs IDE - When to use each environment',
'Agents - Understanding specialized agents and their roles',
'Documents - PRDs, Architecture, Stories, and more',
'Agile Process - How the framework implements Agile methodologies',
'Configuration - Customizing the framework for your needs',
'Best Practices - Tips for effective framework usage',
'Technical Preferences - View and update your preferences',
'Search Knowledge Base - Find specific information',
'Exit KB Mode'
];
let continueKBMode = true;
while (continueKBMode) {
console.log(chalk.bold('\nWhat would you like to know more about?\n'));
const { topic } = await inquirer.prompt([{
type: 'list',
name: 'topic',
message: 'Select a topic:',
choices: topicAreas.map((area, index) => ({
name: `${index + 1}. ${area}`,
value: index
}))
}]);
switch (topic) {
case 0: // Setup & Installation
await this.showTopicKnowledge('setup', 'Setup & Installation');
break;
case 1: // Workflows
await this.showTopicKnowledge('workflows', 'Workflows');
break;
case 2: // Web vs IDE
await this.showEnvironmentComparison();
break;
case 3: // Agents
await this.showAgentKnowledge();
break;
case 4: // Documents
await this.showDocumentKnowledge();
break;
case 5: // Agile Process
await this.showTopicKnowledge('agile', 'Agile Process');
break;
case 6: // Configuration
await this.showConfigurationKnowledge();
break;
case 7: // Best Practices
await this.showTopicKnowledge('best-practices', 'Best Practices');
break;
case 8: // Technical Preferences
await this.manageTechnicalPreferences();
break;
case 9: // Search
await this.interactiveSearch();
break;
case 10: // Exit
continueKBMode = false;
break;
}
if (continueKBMode && topic !== 10) {
const { continueExploring } = await inquirer.prompt([{
type: 'confirm',
name: 'continueExploring',
message: 'Would you like to explore another topic?',
default: true
}]);
continueKBMode = continueExploring;
}
}
console.log(chalk.green('\nā
Exiting Knowledge Base Mode'));
console.log(chalk.dim('You can return anytime with *kb-mode'));
return { success: true, mode: 'exited' };
}
/**
* Show knowledge for a specific topic category
*/
async showTopicKnowledge(category, title) {
console.log(chalk.bold.blue(`\nš ${title}\n`));
const relevantDocs = Array.from(this.knowledgeIndex.entries())
.filter(([_, doc]) => doc.category === category)
.map(([fileName, doc]) => ({ fileName, ...doc }));
if (relevantDocs.length === 0) {
// Search for content containing the category
const searchResults = await this.search(category);
if (searchResults.length > 0) {
console.log(chalk.yellow(`Found ${searchResults.length} related documents:\n`));
await this.displaySearchResults(searchResults);
} else {
console.log(chalk.yellow('No specific documents found for this category.'));
console.log(chalk.dim('Try searching for specific terms or check other categories.'));
}
return;
}
// Display summary of available documents
console.log(chalk.bold('Available Resources:'));
relevantDocs.forEach((doc, index) => {
console.log(`\n${index + 1}. ${chalk.bold(doc.metadata.title || doc.fileName)}`);
if (doc.metadata.description) {
console.log(chalk.dim(` ${doc.metadata.description}`));
}
});
// Allow user to select specific document
if (relevantDocs.length > 1) {
const { selectedDoc } = await inquirer.prompt([{
type: 'list',
name: 'selectedDoc',
message: 'Select a document to view:',
choices: [
...relevantDocs.map((doc, index) => ({
name: doc.metadata.title || doc.fileName,
value: index
})),
{ name: 'View All Summaries', value: -1 },
{ name: 'Back to Topics', value: -2 }
]
}]);
if (selectedDoc >= 0) {
await this.displayDocument(relevantDocs[selectedDoc]);
} else if (selectedDoc === -1) {
for (const doc of relevantDocs) {
await this.displayDocumentSummary(doc);
}
}
} else if (relevantDocs.length === 1) {
await this.displayDocument(relevantDocs[0]);
}
}
/**
* Show environment comparison (Web vs IDE)
*/
async showEnvironmentComparison() {
console.log(chalk.bold.blue('\nš Web UI vs š» IDE Environment\n'));
console.log(chalk.bold('Web UI Best For:'));
console.log(chalk.green('⢠Initial planning and documentation phases'));
console.log(chalk.green('⢠Cost-effective large document creation (especially Gemini)'));
console.log(chalk.green('⢠Multi-agent consultation and brainstorming'));
console.log(chalk.green('⢠Projects without local file access needs'));
console.log(chalk.bold('\nIDE Best For:'));
console.log(chalk.blue('⢠Active development and implementation'));
console.log(chalk.blue('⢠File operations and project integration'));
console.log(chalk.blue('⢠Document sharding and story management'));
console.log(chalk.blue('⢠Real-time code editing and testing'));
console.log(chalk.bold('\nCost-Saving Strategy:'));
console.log(chalk.yellow('1. Create large documents (PRD, Architecture) in Web UI'));
console.log(chalk.yellow('2. Copy to project as docs/prd.md and docs/architecture.md'));
console.log(chalk.yellow('3. Switch to IDE for development workflow'));
console.log(chalk.yellow('4. Use sharding to break documents into manageable pieces'));
const { learnMore } = await inquirer.prompt([{
type: 'confirm',
name: 'learnMore',
message: 'Would you like to learn about specific environment setup?',
default: false
}]);
if (learnMore) {
const { environment } = await inquirer.prompt([{
type: 'list',
name: 'environment',
message: 'Which environment?',
choices: ['Web UI Setup', 'IDE Setup', 'Migration Between Environments']
}]);
// Show relevant documentation
const searchTerm = environment.toLowerCase().replace(' setup', '');
const results = await this.search(searchTerm);
if (results.length > 0) {
await this.displaySearchResults(results.slice(0, 3));
}
}
}
/**
* Show agent knowledge
*/
async showAgentKnowledge() {
console.log(chalk.bold.blue('\nš¤ Agent System Overview\n'));
const agentCategories = {
'Core Development Team': [
{ id: 'analyst', name: 'Business Analyst', role: 'Market research, requirements gathering' },
{ id: 'pm', name: 'Product Manager', role: 'PRD creation, feature prioritization' },
{ id: 'architect', name: 'Solution Architect', role: 'System design, technical architecture' },
{ id: 'dev', name: 'Developer', role: 'Code implementation, debugging' },
{ id: 'qa', name: 'QA Specialist', role: 'Test planning, quality assurance' },
{ id: 'ux-expert', name: 'UX Designer', role: 'UI/UX design, prototypes' },
{ id: 'po', name: 'Product Owner', role: 'Backlog management, story validation' },
{ id: 'sm', name: 'Scrum Master', role: 'Sprint planning, story creation' }
],
'Meta Agents': [
{ id: 'bmad-orchestrator', name: 'Team Coordinator', role: 'Multi-agent workflows, role switching' },
{ id: 'bmad-master', name: 'Universal Expert', role: 'All capabilities without switching' }
]
};
console.log(chalk.bold('Available Agents by Category:\n'));
Object.entries(agentCategories).forEach(([category, agents]) => {
console.log(chalk.bold.yellow(category + ':'));
agents.forEach(agent => {
console.log(` ${chalk.green(agent.id)} - ${agent.name}`);
console.log(chalk.dim(` ${agent.role}`));
});
console.log('');
});
const { agentAction } = await inquirer.prompt([{
type: 'list',
name: 'agentAction',
message: 'What would you like to do?',
choices: [
'Learn about a specific agent',
'View agent activation commands',
'Understand agent collaboration',
'Back to topics'
]
}]);
switch (agentAction) {
case 'Learn about a specific agent':
await this.showSpecificAgentDetails();
break;
case 'View agent activation commands':
await this.showAgentCommands();
break;
case 'Understand agent collaboration':
await this.showAgentCollaboration();
break;
}
}
/**
* Display document content with formatting
*/
async displayDocument(doc) {
console.log(chalk.bold.blue(`\nš ${doc.metadata.title || doc.fileName}\n`));
// Display content in sections
const sections = this.splitIntoSections(doc.content);
for (const section of sections) {
console.log(chalk.bold(section.title));
console.log(section.content);
if (sections.indexOf(section) < sections.length - 1) {
const { continueReading } = await inquirer.prompt([{
type: 'confirm',
name: 'continueReading',
message: 'Continue reading?',
default: true
}]);
if (!continueReading) break;
}
}
}
/**
* Display document summary
*/
async displayDocumentSummary(doc) {
console.log(chalk.bold(`\nš ${doc.metadata.title || doc.fileName}`));
if (doc.metadata.description) {
console.log(chalk.dim(doc.metadata.description));
}
console.log(chalk.dim(`Type: ${doc.type} | Category: ${doc.category}`));
console.log('');
}
/**
* Split content into readable sections
*/
splitIntoSections(content) {
const sections = [];
const lines = content.split('\n');
let currentSection = { title: 'Introduction', content: '' };
for (const line of lines) {
if (line.match(/^#{1,2}\s+(.+)$/)) {
if (currentSection.content.trim()) {
sections.push(currentSection);
}
currentSection = {
title: line,
content: ''
};
} else {
currentSection.content += line + '\n';
}
}
if (currentSection.content.trim()) {
sections.push(currentSection);
}
return sections;
}
/**
* Interactive search interface
*/
async interactiveSearch() {
console.log(chalk.bold.blue('\nš Knowledge Base Search\n'));
const { searchQuery } = await inquirer.prompt([{
type: 'input',
name: 'searchQuery',
message: 'Enter search terms:',
validate: input => input.trim().length >= 2 || 'Please enter at least 2 characters'
}]);
const results = await this.search(searchQuery);
if (results.length === 0) {
console.log(chalk.yellow('No results found. Try different search terms.'));
return;
}
console.log(chalk.green(`\nFound ${results.length} results:\n`));
await this.displaySearchResults(results);
}
/**
* Search knowledge base
*/
async search(query, options = {}) {
const queryLower = query.toLowerCase();
const words = queryLower.split(/\s+/);
const results = new Map();
// Search in index
words.forEach(word => {
if (this.searchIndex.has(word)) {
this.searchIndex.get(word).forEach(fileName => {
if (!results.has(fileName)) {
results.set(fileName, { fileName, score: 0, matches: [] });
}
results.get(fileName).score += 1;
results.get(fileName).matches.push(word);
});
}
});
// Search in content
this.knowledgeIndex.forEach((doc, fileName) => {
const contentLower = doc.content.toLowerCase();
let contentScore = 0;
words.forEach(word => {
const occurrences = (contentLower.match(new RegExp(word, 'g')) || []).length;
if (occurrences > 0) {
contentScore += occurrences;
if (!results.has(fileName)) {
results.set(fileName, { fileName, score: 0, matches: [] });
}
results.get(fileName).score += occurrences;
if (!results.get(fileName).matches.includes(word)) {
results.get(fileName).matches.push(word);
}
}
});
// Boost score for title matches
if (doc.metadata.title && doc.metadata.title.toLowerCase().includes(queryLower)) {
if (!results.has(fileName)) {
results.set(fileName, { fileName, score: 0, matches: [] });
}
results.get(fileName).score += 10;
}
});
// Sort by score and return
const sortedResults = Array.from(results.values())
.sort((a, b) => b.score - a.score)
.slice(0, options.limit || 10);
return sortedResults.map(result => ({
...result,
document: this.knowledgeIndex.get(result.fileName)
}));
}
/**
* Display search results
*/
async displaySearchResults(results) {
results.forEach((result, index) => {
const doc = result.document;
console.log(`${index + 1}. ${chalk.bold(doc.metadata.title || result.fileName)}`);
console.log(chalk.dim(` Score: ${result.score} | Matches: ${result.matches.join(', ')}`));
if (doc.metadata.description) {
console.log(chalk.dim(` ${doc.metadata.description.substring(0, 100)}...`));
}
console.log('');
});
if (results.length > 0) {
const { viewDoc } = await inquirer.prompt([{
type: 'list',
name: 'viewDoc',
message: 'Select a document to view:',
choices: [
...results.map((result, index) => ({
name: result.document.metadata.title || result.fileName,
value: index
})),
{ name: 'Back to search', value: -1 }
]
}]);
if (viewDoc >= 0) {
await this.displayDocument(results[viewDoc].document);
}
}
}
/**
* Manage technical preferences
*/
async manageTechnicalPreferences() {
console.log(chalk.bold.blue('\nāļø Technical Preferences\n'));
if (this.technicalPreferences.size === 0) {
console.log(chalk.yellow('No technical preferences configured yet.'));
const { addPrefs } = await inquirer.prompt([{
type: 'confirm',
name: 'addPrefs',
message: 'Would you like to add technical preferences?',
default: true
}]);
if (addPrefs) {
await this.addTechnicalPreferences();
}
return;
}
console.log(chalk.bold('Current Preferences:\n'));
this.technicalPreferences.forEach((pref, category) => {
console.log(chalk.bold.yellow(`${category}:`));
pref.preferences.forEach(item => {
console.log(chalk.green(` ⢠${item}`));
});
console.log('');
});
const { action } = await inquirer.prompt([{
type: 'list',
name: 'action',
message: 'What would you like to do?',
choices: [
'Add new category',
'Edit existing category',
'Remove category',
'Save preferences',
'Back to topics'
]
}]);
switch (action) {
case 'Add new category':
await this.addTechnicalPreferences();
break;
case 'Edit existing category':
await this.editTechnicalPreferences();
break;
case 'Remove category':
await this.removeTechnicalPreferences();
break;
case 'Save preferences':
await this.saveTechnicalPreferences();
break;
}
}
/**
* Add technical preferences
*/
async addTechnicalPreferences() {
const categories = [
'Frontend Framework',
'Backend Language',
'Database',
'Testing Framework',
'Build Tools',
'Deployment',
'Custom Category'
];
const { category } = await inquirer.prompt([{
type: 'list',
name: 'category',
message: 'Select preference category:',
choices: categories
}]);
const finalCategory = category === 'Custom Category' ?
(await inquirer.prompt([{
type: 'input',
name: 'custom',
message: 'Enter custom category name:'
}])).custom : category;
const { preferences } = await inquirer.prompt([{
type: 'input',
name: 'preferences',
message: `Enter ${finalCategory} preferences (comma-separated):`,
validate: input => input.trim().length > 0 || 'Please enter at least one preference'
}]);
this.technicalPreferences.set(finalCategory, {
category: finalCategory,
preferences: preferences.split(',').map(p => p.trim()),
source: 'user'
});
console.log(chalk.green(`ā
Added preferences for ${finalCategory}`));
}
/**
* Save technical preferences to file
*/
async saveTechnicalPreferences() {
const userPrefs = {};
this.technicalPreferences.forEach((pref, category) => {
if (pref.source === 'user') {
userPrefs[category] = pref.preferences;
}
});
const prefsPath = path.join(this.rootDir, '.technical-preferences.yaml');
await fs.writeFile(prefsPath, yaml.stringify(userPrefs), 'utf8');
console.log(chalk.green(`ā
Preferences saved to ${prefsPath}`));
}
/**
* Get context-aware knowledge
*/
async getContextualKnowledge(context = {}) {
const { agent, task, topic } = context;
const relevant = [];
// Filter by agent if specified
if (agent) {
this.knowledgeIndex.forEach((doc, fileName) => {
if (doc.content.toLowerCase().includes(agent.toLowerCase()) ||
(doc.metadata.tags && doc.metadata.tags.includes('agent'))) {
relevant.push({ fileName, ...doc, relevance: 'agent' });
}
});
}
// Filter by task if specified
if (task) {
const taskResults = await this.search(task, { limit: 5 });
taskResults.forEach(result => {
relevant.push({ ...result.document, relevance: 'task' });
});
}
// Filter by topic if specified
if (topic) {
const topicDocs = Array.from(this.knowledgeIndex.entries())
.filter(([_, doc]) => doc.category === topic)
.map(([fileName, doc]) => ({ fileName, ...doc, relevance: 'topic' }));
relevant.push(...topicDocs);
}
return relevant;
}
/**
* Get agent-specific knowledge
*/
async getAgentKnowledge(agentId) {
const agentKnowledge = {
general: [],
tasks: [],
templates: [],
workflows: []
};
this.knowledgeIndex.forEach((doc, fileName) => {
const contentLower = doc.content.toLowerCase();
const agentLower = agentId.toLowerCase();
if (contentLower.includes(agentLower)) {
if (fileName.includes('task')) {
agentKnowledge.tasks.push({ fileName, ...doc });
} else if (fileName.includes('template')) {
agentKnowledge.templates.push({ fileName, ...doc });
} else if (fileName.includes('workflow')) {
agentKnowledge.workflows.push({ fileName, ...doc });
} else {
agentKnowledge.general.push({ fileName, ...doc });
}
}
});
return agentKnowledge;
}
/**
* Update knowledge base with new information
*/
async updateKnowledge(fileName, content, metadata = {}) {
const filePath = path.join(this.kbPath, fileName);
try {
await fs.writeFile(filePath, content, 'utf8');
this.knowledgeIndex.set(fileName, {
path: filePath,
content,
metadata: { ...this.extractMetadata(content), ...metadata },
type: 'custom',
lastModified: new Date(),
category: this.categorizeDocument(fileName, content)
});
// Rebuild search index
await this.buildSearchIndex();
console.log(chalk.green(`ā
Knowledge base updated: ${fileName}`));
return { success: true, fileName };
} catch (error) {
console.error(chalk.red(`ā Failed to update knowledge: ${error.message}`));
return { success: false, error: error.message };
}
}
/**
* Export knowledge for agent consumption
*/
async exportForAgent(agentId, format = 'markdown') {
const agentKnowledge = await this.getAgentKnowledge(agentId);
let exportContent = '';
if (format === 'markdown') {
exportContent = `# Knowledge Base for ${agentId}\n\n`;
Object.entries(agentKnowledge).forEach(([category, docs]) => {
if (docs.length > 0) {
exportContent += `## ${category.charAt(0).toUpperCase() + category.slice(1)}\n\n`;
docs.forEach(doc => {
exportContent += `### ${doc.metadata.title || doc.fileName}\n\n`;
exportContent += doc.content + '\n\n---\n\n';
});
}
});
} else if (format === 'json') {
exportContent = JSON.stringify(agentKnowledge, null, 2);
}
return exportContent;
}
/**
* Show specific agent details
*/
async showSpecificAgentDetails() {
const agents = [
'analyst', 'pm', 'architect', 'dev', 'qa',
'ux-expert', 'po', 'sm', 'orchestrator', 'master'
];
const { selectedAgent } = await inquirer.prompt([{
type: 'list',
name: 'selectedAgent',
message: 'Select an agent to learn about:',
choices: agents
}]);
const agentKnowledge = await this.getAgentKnowledge(selectedAgent);
console.log(chalk.bold.blue(`\nš¤ ${selectedAgent.toUpperCase()} Agent Details\n`));
if (agentKnowledge.general.length > 0) {
const doc = agentKnowledge.general[0];
const excerpt = doc.content.substring(0, 500) + '...';
console.log(excerpt);
}
if (agentKnowledge.tasks.length > 0) {
console.log(chalk.bold('\nAvailable Tasks:'));
agentKnowledge.tasks.forEach(task => {
console.log(` ⢠${task.metadata.title || task.fileName}`);
});
}
if (agentKnowledge.templates.length > 0) {
console.log(chalk.bold('\nAvailable Templates:'));
agentKnowledge.templates.forEach(template => {
console.log(` ⢠${template.metadata.title || template.fileName}`);
});
}
}
/**
* Show agent activation commands
*/
async showAgentCommands() {
console.log(chalk.bold.blue('\nš» Agent Activation Commands\n'));
console.log(chalk.bold('IDE-Specific Syntax:'));
console.log(chalk.green('⢠Claude Code: /agent-name (e.g., /dev)'));
console.log(chalk.green('⢠Cursor: @agent-name (e.g., @dev)'));
console.log(chalk.green('⢠Windsurf: @agent-name (e.g., @dev)'));
console.log(chalk.green('⢠VS Code with Cline: Select from mode selector'));
console.log(chalk.green('⢠Roo Code: Select from mode selector'));
console.log(chalk.bold('\nCommon Commands:'));
console.log(chalk.blue('⢠*help - Show available commands'));
console.log(chalk.blue('⢠*status - Show current context/progress'));
console.log(chalk.blue('⢠*exit - Exit the agent mode'));
console.log(chalk.blue('⢠*task <name> - Execute a specific task'));
console.log(chalk.blue('⢠*create-doc <template> - Create document from template'));
console.log(chalk.bold('\nWeb UI Commands:'));
console.log(chalk.yellow('⢠/help - Show available commands'));
console.log(chalk.yellow('⢠/switch <agent> - Change active agent'));
console.log(chalk.yellow('⢠/pm create-doc prd - Create PRD with PM agent'));
}
/**
* Show agent collaboration patterns
*/
async showAgentCollaboration() {
console.log(chalk.bold.blue('\nš¤ Agent Collaboration Patterns\n'));
console.log(chalk.bold('Development Workflow:'));
console.log(chalk.green('1. SM Agent ā Creates next story from sharded docs'));
console.log(chalk.green('2. You ā Review and approve story'));
console.log(chalk.green('3. Dev Agent ā Implements approved story'));
console.log(chalk.green('4. QA Agent ā Reviews and refactors code'));
console.log(chalk.green('5. You ā Verify completion'));
console.log(chalk.green('6. Repeat until epic complete'));
console.log(chalk.bold('\nKey Principles:'));
console.log(chalk.blue('⢠Clean Handoffs - Always start fresh when switching agents'));
console.log(chalk.blue('⢠Agent Specialization - Each agent has specific expertise'));
console.log(chalk.blue('⢠Sequential Progress - One story at a time'));
console.log(chalk.blue('⢠Human Oversight - You validate each step'));
console.log(chalk.bold('\nCritical Rules:'));
console.log(chalk.red('⢠ALWAYS use SM agent for story creation'));
console.log(chalk.red('⢠ALWAYS use Dev agent for implementation'));
console.log(chalk.red('⢠NEVER use master/orchestrator for dev workflow'));
}
/**
* Show document knowledge and templates
*/
async showDocumentKnowledge() {
console.log(chalk.bold.blue('\nš Document System Overview\n'));
const documentTypes = {
'Planning Documents': [
{ name: 'PRD (Product Requirements)', file: 'docs/prd.md', template: 'prd-tmpl' },
{ name: 'Architecture Specification', file: 'docs/architecture.md', template: 'architecture-tmpl' },
{ name: 'Project Brief', file: 'docs/brief.md', template: 'project-brief-tmpl' }
],
'Development Documents': [
{ name: 'User Stories', file: 'docs/stories/*.md', template: 'story-tmpl' },
{ name: 'Technical Specs', file: 'docs/specs/*.md', template: 'tech-spec-tmpl' },
{ name: 'API Documentation', file: 'docs/api/*.md', template: 'api-doc-tmpl' }
],
'Analysis Documents': [
{ name: 'Market Research', file: 'docs/research.md', template: 'market-research-tmpl' },
{ name: 'Competitive Analysis', file: 'docs/competitive.md', template: 'competitor-analysis-tmpl' },
{ name: 'Requirements Analysis', file: 'docs/requirements.md', template: 'requirements-tmpl' }
]
};
console.log(chalk.bold('Document Types and Templates:\n'));
Object.entries(documentTypes).forEach(([category, docs]) => {
console.log(chalk.bold.yellow(category + ':'));
docs.forEach(doc => {
console.log(` ${chalk.green(doc.name)}`);
console.log(chalk.dim(` File: ${doc.file}`));
console.log(chalk.dim(` Template: ${doc.template}`));
});
console.log('');
});
const { docAction } = await inquirer.prompt([{
type: 'list',
name: 'docAction',
message: 'What would you like to learn about?',
choices: [
'Document creation workflow',
'Document sharding process',
'Template system',
'Back to topics'
]
}]);
switch (docAction) {
case 'Document creation workflow':
console.log(chalk.bold('\nš Document Creation Workflow:'));
console.log('1. Use appropriate agent (PM for PRD, Architect for tech specs)');
console.log('2. Execute *create-doc command with template name');
console.log('3. Follow interactive prompts for each section');
console.log('4. Review and refine with elicitation methods');
console.log('5. Save to standard location (docs/prd.md, etc.)');
break;
case 'Document sharding process':
console.log(chalk.bold('\nāļø Document Sharding:'));
console.log('⢠Purpose: Break large documents into manageable pieces');
console.log('⢠Command: *shard-doc docs/prd.md');
console.log('⢠Creates: docs/prd/ folder with section files');
console.log('⢠Benefits: Better context management for dev workflow');
break;
case 'Template system':
console.log(chalk.bold('\nš Template System:'));
console.log('⢠YAML-based templates define document structure');
console.log('⢠Progressive disclosure for complex documents');
console.log('⢠Interactive elicitation for quality content');
console.log('⢠Agent-specific templates for specialized needs');
break;
}
}
/**
* Show configuration knowledge
*/
async showConfigurationKnowledge() {
console.log(chalk.bold.blue('\nāļø Configuration System\n'));
console.log(chalk.bold('Core Configuration (core-config.yaml):'));
console.log(chalk.green('⢠Version settings - Control document format versions'));
console.log(chalk.green('⢠Sharding configuration - Define document organization'));
console.log(chalk.green('⢠Developer files - Specify always-loaded files'));
console.log(chalk.green('⢠Debug settings - Configure logging and diagnostics'));
console.log(chalk.bold('\nKey Configuration Areas:'));
console.log(chalk.blue('⢠PRD Configuration - Version and sharding settings'));
console.log(chalk.blue('⢠Architecture Configuration - Document structure'));
console.log(chalk.blue('⢠Developer Context - Files loaded for every task'));
console.log(chalk.blue('⢠Workflow Settings - Process customization'));
const { showExample } = await inquirer.prompt([{
type: 'confirm',
name: 'showExample',
message: 'Would you like to see example configurations?',
default: true
}]);
if (showExample) {
console.log(chalk.bold('\nExample Configurations:\n'));
console.log(chalk.yellow('Legacy V3 Project:'));
console.log(chalk.dim(`prdVersion: v3
prdSharded: false
architectureVersion: v3
architectureSharded: false`));
console.log(chalk.yellow('\nV4 Optimized Project:'));
console.log(chalk.dim(`prdVersion: v4
prdSharded: true
prdShardedLocation: docs/prd
architectureVersion: v4
architectureSharded: true
architectureShardedLocation: docs/architecture`));
}
}
}
module.exports = KnowledgeBase;