@jasondark/proompt
Version:
CLI tool for running AI prompts with structure and repeatability
200 lines • 9.62 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.documentDirsCommand = void 0;
const child_process_1 = require("child_process");
const fs_1 = require("fs");
const path = __importStar(require("path"));
const command_utils_1 = require("@/core/command-utils");
const resolver_1 = require("@/core/config/resolver");
const constants_1 = require("@/core/constants");
const doc_metadata_1 = require("@/core/utils/doc-metadata");
const file_tracker_1 = require("@/core/utils/file-tracker");
const git_1 = require("@/core/utils/git");
const repomix_1 = require("@/core/utils/repomix");
const rules_1 = require("@/core/utils/rules");
const temp_file_1 = require("@/core/utils/temp-file");
const schema_1 = require("./schema");
// Read proompt content
const proomptContent = (0, fs_1.readFileSync)(path.join(__dirname, 'proompt.md'), 'utf-8');
/**
* Custom handler that generates XML file before AI execution
*/
const customDocumentDirsHandler = async (args) => {
// Validate arguments using schema
const validatedArgs = schema_1.documentDirsArgsSchema.parse(args);
try {
// Get current commit hash for tracking
const commitHash = (0, git_1.getCurrentCommitHash)();
if (!commitHash) {
console.warn('⚠️ Warning: Not in a git repository, commit hash tracking disabled');
}
// Parse directory paths from CLI input string
const directoryPaths = validatedArgs.directoryPaths
.split(/\s+/)
.filter((path) => path.length > 0);
// Validate that all directory paths exist and are accessible
for (const dirPath of directoryPaths) {
try {
const stats = await fs_1.promises.stat(dirPath);
if (!stats.isDirectory()) {
throw new Error(`Path is not a directory: ${dirPath}`);
}
}
catch (error) {
if (error.code === 'ENOENT') {
throw new Error(`Directory does not exist: ${dirPath}`);
}
throw new Error(`Cannot access directory: ${dirPath} - ${error.message}`);
}
}
console.log(`📁 Validated ${directoryPaths.length} director${directoryPaths.length === 1 ? 'y' : 'ies'} for analysis`);
// Generate XML files for each directory
const directoryXmlMap = {};
console.log('📦 Packing directories with repomix...');
for (const dirPath of directoryPaths) {
const xmlFilePath = (0, temp_file_1.generateTempXmlPath)(`document-dir-${dirPath.replace(/[^a-zA-Z0-9]/g, '_')}`);
console.log(`📁 Packing ${dirPath}...`);
await (0, repomix_1.executeRepomix)({
outputPath: xmlFilePath,
workingDirectory: dirPath,
});
directoryXmlMap[dirPath] = xmlFilePath;
(0, temp_file_1.logTempFileLocation)(xmlFilePath);
}
console.log('✅ All directories packed successfully');
// Resolve settings using hierarchy: args > user settings > defaults
const settingsOverride = {
llmCli: args?.llmCli,
outputFormat: args?.outputFormat,
};
const resolvedSettings = (0, resolver_1.resolveSettings)(settingsOverride);
const llmCli = resolvedSettings.llmCli;
const outputFormat = resolvedSettings.outputFormat;
// Generate output file names based on configured formats
const outputFileNames = outputFormat.map((format) => constants_1.OUTPUT_FILE_NAMES[format]);
const isPlural = outputFileNames.length > 1;
// Create formatted directory-to-XML mapping for the prompt
const directoryXmlMapping = Object.entries(directoryXmlMap)
.map(([dir, xmlPath]) => `- ${dir}: \`${xmlPath}\``)
.join('\n');
// Check for optional RULES.md files in each directory
const rulesMap = (0, rules_1.readRulesFromDirectories)(directoryPaths);
const formattedRules = (0, rules_1.formatMultipleRulesForPrompt)(rulesMap) || '';
// Inject template variables including XML mappings and optional rules
const enhancedArgs = {
...validatedArgs,
directoryXmlMap: directoryXmlMapping,
directoryPaths: directoryPaths.join(', '),
outputFiles: outputFileNames.map((name) => `\`${name}\``).join(' and '),
outputFileList: outputFileNames.join(' and '),
outputAction: isPlural ? 'Create identical' : 'Create a',
fileOrFiles: isPlural ? 'files' : 'file',
requiredDocFiles: outputFileNames.map((name) => `"${name}"`).join(', '),
allRequiredFilesExist: `all required files (${outputFileNames.join(', ')}) exist`,
directoryRules: formattedRules,
};
// Replace variables with provided arguments using imported function
const processedContent = (0, command_utils_1.replaceVariables)(proomptContent, enhancedArgs);
// Record start time for file modification tracking
const startTime = new Date();
// Launch interactive CLI with initial prompt
console.log(`🤖 Launching ${llmCli} for directory analysis...`);
let child;
if (llmCli === 'claude') {
child = (0, child_process_1.spawn)('claude', [processedContent], {
stdio: 'inherit',
});
}
else if (llmCli === 'gemini') {
child = (0, child_process_1.spawn)('gemini', ['-i', processedContent], {
stdio: 'inherit',
});
}
else {
throw new Error(`Unsupported LLM CLI: ${llmCli}`);
}
return new Promise((resolve, reject) => {
child.on('close', (code) => {
if (code === 0) {
// Check if documentation files were actually modified in the documented directories
const filesModified = (0, file_tracker_1.anyDocumentationFilesModifiedInDirs)(startTime, outputFileNames, directoryPaths);
// Update metadata for each directory if files were modified and we have a commit hash
if (filesModified && commitHash) {
try {
for (const dirPath of directoryPaths) {
(0, doc_metadata_1.updateDirDocHash)(dirPath, commitHash);
}
const shortHash = commitHash.substring(0, 7);
console.log(`📝 Updated directory documentation metadata for ${directoryPaths.length} director${directoryPaths.length === 1 ? 'y' : 'ies'} with commit ${shortHash}`);
}
catch (error) {
console.warn('⚠️ Warning: Failed to update documentation metadata:', error.message);
}
}
else if (filesModified && !commitHash) {
console.log('📝 Documentation files were modified but no commit hash available for tracking');
}
resolve();
}
else {
reject(new Error(`${llmCli} command failed with exit code ${code}`));
}
});
child.on('error', (error) => {
reject(error);
});
});
}
catch (error) {
console.error('❌ Error during directory processing:', error.message);
throw error;
}
};
// Create and export the command module
exports.documentDirsCommand = (0, command_utils_1.createCommandModule)({
name: 'document-dirs',
description: 'Generate comprehensive documentation for AI coding tools for any directory with specific project logic',
arguments: [
{
name: 'directory-paths',
description: 'Paths to directories for documentation generation (space-separated)',
required: true,
type: 'string',
positional: true,
},
],
}, schema_1.documentDirsArgsSchema, proomptContent, customDocumentDirsHandler);
//# sourceMappingURL=index.js.map