Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
607 changes: 607 additions & 0 deletions .aios-core/cli/commands/config/index.js

Large diffs are not rendered by default.

222 changes: 222 additions & 0 deletions .aios-core/cli/commands/generate/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,222 @@
/**
* Generate Command
*
* CLI command for generating documents using the Template Engine.
* Supports: prd, adr, pmdr, dbdr, story, epic, task
*
* @module cli/commands/generate
* @version 1.0.0
* @story 3.9 - Template PMDR (AC3.9.8)
*/

'use strict';

const { Command } = require('commander');
const path = require('path');

// Lazy load TemplateEngine to avoid startup overhead
let TemplateEngine = null;

/**
* Get TemplateEngine instance (lazy loaded)
* @returns {Object} TemplateEngine class
*/
function getTemplateEngine() {
if (!TemplateEngine) {
const enginePath = path.join(__dirname, '..', '..', '..', 'product', 'templates', 'engine');
const engine = require(enginePath);
TemplateEngine = engine.TemplateEngine;
}
return TemplateEngine;
}

/**
* Generate a document from template
* @param {string} templateType - Template type (prd, adr, pmdr, etc.)
* @param {Object} options - Command options
*/
async function generateDocument(templateType, options) {
const Engine = getTemplateEngine();

const engine = new Engine({
interactive: !options.nonInteractive,
baseDir: options.baseDir || process.cwd(),
});

// Validate template type
if (!engine.supportedTypes.includes(templateType)) {
console.error(`❌ Unsupported template type: ${templateType}`);
console.log(`\nSupported types: ${engine.supportedTypes.join(', ')}`);
process.exit(1);
}

try {
console.log(`\nπŸ“ Generating ${templateType.toUpperCase()} document...\n`);

// Build context from options
const context = {};
if (options.title) context.title = options.title;
if (options.number) context.number = parseInt(options.number, 10);
if (options.status) context.status = options.status;
if (options.owner) context.owner = options.owner;

// Generate document
const result = await engine.generate(templateType, context, {
validate: !options.skipValidation,
save: options.save,
outputPath: options.output,
});

// Output result
if (options.save && result.savedTo) {
console.log(`\nβœ… Document saved to: ${result.savedTo}`);
} else if (!options.save) {
console.log('\n--- Generated Document ---\n');
console.log(result.content);
console.log('\n--- End Document ---\n');
}

// Show validation warnings
if (result.validation && !result.validation.isValid) {
console.warn('\n⚠️ Validation warnings:');
result.validation.errors.forEach(err => console.warn(` - ${err}`));
}

// Show metadata
if (options.verbose) {
console.log('\nπŸ“Š Metadata:');
console.log(` Template: ${result.templateType}`);
console.log(` Generated: ${result.generatedAt}`);
if (result.savedTo) console.log(` Saved to: ${result.savedTo}`);
}

} catch (error) {
console.error(`\n❌ Generation failed: ${error.message}`);
if (options.verbose) {
console.error('\nStack trace:', error.stack);
}
process.exit(1);
}
}

/**
* List available templates
* @param {Object} options - Command options
*/
async function listTemplates(options) {
const Engine = getTemplateEngine();
const engine = new Engine({ interactive: false });

try {
const templates = await engine.listTemplates();

console.log('\nπŸ“‹ Available Templates:\n');

if (options.json) {
console.log(JSON.stringify(templates, null, 2));
} else {
templates.forEach(t => {
const status = t.status === 'missing' ? '⚠️ (missing)' : 'βœ…';
console.log(` ${status} ${t.type.padEnd(10)} - ${t.name} v${t.version}`);

if (options.verbose && t.variables.length > 0) {
console.log(' Variables:');
t.variables.forEach(v => {
const req = v.required ? '*' : ' ';
console.log(` ${req}${v.name} (${v.type})`);
});
}
});
}

console.log('');
} catch (error) {
console.error(`❌ Error listing templates: ${error.message}`);
process.exit(1);
}
}

/**
* Show template info
* @param {string} templateType - Template type
* @param {Object} options - Command options
*/
async function showTemplateInfo(templateType, options) {
const Engine = getTemplateEngine();
const engine = new Engine({ interactive: false });

try {
const info = await engine.getTemplateInfo(templateType);

if (options.json) {
console.log(JSON.stringify(info, null, 2));
} else {
console.log(`\nπŸ“ Template: ${info.name}`);
console.log(` Type: ${info.type}`);
console.log(` Version: ${info.version}`);
console.log('\n Variables:');
info.variables.forEach(v => {
const req = v.required ? '(required)' : '(optional)';
console.log(` - ${v.name}: ${v.type} ${req}`);
if (v.description) console.log(` ${v.description}`);
});
console.log('');
}
} catch (error) {
console.error(`❌ Error getting template info: ${error.message}`);
process.exit(1);
}
}

/**
* Create the generate command
* @returns {Command} Commander command instance
*/
function createGenerateCommand() {
const generate = new Command('generate')
.description('Generate documents from templates (prd, adr, pmdr, dbdr, story, epic, task)')
.argument('[type]', 'Template type to generate')
.option('-t, --title <title>', 'Document title')
.option('-n, --number <number>', 'Document number')
.option('-s, --status <status>', 'Initial status')
.option('-o, --owner <owner>', 'Document owner')
.option('--output <path>', 'Output file path')
.option('--save', 'Save to file (default location if --output not specified)')
.option('--non-interactive', 'Disable interactive prompts')
.option('--skip-validation', 'Skip schema validation')
.option('--base-dir <dir>', 'Base directory for paths')
.option('-v, --verbose', 'Show detailed output')
.option('--json', 'Output as JSON')
.action(async (type, options) => {
if (!type) {
// No type specified - show help
generate.help();
return;
}
await generateDocument(type, options);
});

// Add list subcommand
generate
.command('list')
.description('List available templates')
.option('-v, --verbose', 'Show variable details')
.option('--json', 'Output as JSON')
.action(listTemplates);

// Add info subcommand
generate
.command('info <type>')
.description('Show template information')
.option('--json', 'Output as JSON')
.action(showTemplateInfo);

return generate;
}

module.exports = {
createGenerateCommand,
generateDocument,
listTemplates,
showTemplateInfo,
};
46 changes: 46 additions & 0 deletions .aios-core/cli/commands/manifest/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/**
* Manifest Command Module
*
* Entry point for all manifest-related CLI commands.
* Includes validate and regenerate subcommands.
*
* @module cli/commands/manifest
* @version 1.0.0
* @story 2.13 - Manifest System
*/

const { Command } = require('commander');
const { createValidateCommand } = require('./validate');
const { createRegenerateCommand } = require('./regenerate');

/**
* Create the manifest command with all subcommands
* @returns {Command} Commander command instance
*/
function createManifestCommand() {
const manifest = new Command('manifest');

manifest
.description('Manage AIOS manifest files for agents, workers, and tasks')
.addHelpText('after', `
Commands:
validate Validate all manifest files
regenerate Regenerate manifests from source files

Examples:
$ aios manifest validate
$ aios manifest validate --verbose
$ aios manifest regenerate
$ aios manifest regenerate --force
`);

// Add subcommands
manifest.addCommand(createValidateCommand());
manifest.addCommand(createRegenerateCommand());

return manifest;
}

module.exports = {
createManifestCommand,
};
96 changes: 96 additions & 0 deletions .aios-core/cli/commands/manifest/regenerate.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
/**
* Manifest Regenerate Command
*
* CLI command to regenerate all manifest files from source.
*
* @module cli/commands/manifest/regenerate
* @version 1.0.0
* @story 2.13 - Manifest System
*/

const { Command } = require('commander');
const path = require('path');
const { createManifestGenerator } = require('../../../core/manifest/manifest-generator');

/**
* Create the regenerate subcommand
* @returns {Command} Commander command instance
*/
function createRegenerateCommand() {
const regenerate = new Command('regenerate');

regenerate
.description('Regenerate all manifest files from source files')
.option('-f, --force', 'Force regeneration even if manifests exist')
.option('--json', 'Output results as JSON')
.option('--dry-run', 'Show what would be generated without writing files')
.action(async (options) => {
try {
const generator = createManifestGenerator({
basePath: process.cwd(),
});

if (!options.dryRun) {
console.log('Scanning .aios-core/...\n');
} else {
console.log('[DRY RUN] Would generate:\n');
}

const results = await generator.generateAll();

if (options.json) {
console.log(JSON.stringify(results, null, 2));
return;
}

// Format output
const formatResult = (name, result) => {
if (result.success) {
const verb = options.dryRun ? 'Would generate' : 'Generated';
console.log(`βœ“ ${verb} ${name}.csv (${result.count} entries)`);
if (result.errors.length > 0) {
result.errors.forEach(e => console.log(` ⚠ ${e}`));
}
} else {
console.log(`βœ— Failed to generate ${name}.csv`);
result.errors.forEach(e => console.log(` βœ— ${e}`));
}
};

formatResult('agents', results.agents);
formatResult('workers', results.workers);
formatResult('tasks', results.tasks);

console.log('');

if (results.errors.length > 0) {
console.log('❌ Errors during generation:');
results.errors.forEach(e => console.log(` βœ— ${e}`));
process.exit(1);
}

const allSuccess = results.agents.success &&
results.workers.success &&
results.tasks.success;

if (allSuccess) {
const verb = options.dryRun ? 'Would be generated' : 'regenerated';
console.log(`βœ… Manifests ${verb}!`);
console.log(` Duration: ${results.duration}ms`);
} else {
console.log('❌ Some manifests failed to generate');
process.exit(1);
}

} catch (error) {
console.error(`Error: ${error.message}`);
process.exit(1);
}
});

return regenerate;
}

module.exports = {
createRegenerateCommand,
};
Loading
Loading