@lenne.tech/cli
Version:
lenne.Tech CLI: lt
296 lines (294 loc) • 12.6 kB
JavaScript
;
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
const child_process_1 = require("child_process");
const path_1 = require("path");
/**
* Copy text to clipboard (cross-platform)
*/
function copyToClipboard(text) {
return __awaiter(this, void 0, void 0, function* () {
try {
const platform = process.platform;
if (platform === 'darwin') {
return new Promise((resolve) => {
const proc = (0, child_process_1.spawn)('pbcopy');
proc.stdin.write(text);
proc.stdin.end();
proc.on('close', () => resolve(true));
proc.on('error', () => resolve(false));
});
}
else if (platform === 'linux') {
try {
return new Promise((resolve) => {
const proc = (0, child_process_1.spawn)('xclip', ['-selection', 'clipboard']);
proc.stdin.write(text);
proc.stdin.end();
proc.on('close', () => resolve(true));
proc.on('error', () => resolve(false));
});
}
catch (_a) {
return false;
}
}
else if (platform === 'win32') {
return new Promise((resolve) => {
const proc = (0, child_process_1.spawn)('clip');
proc.stdin.write(text);
proc.stdin.end();
proc.on('close', () => resolve(true));
proc.on('error', () => resolve(false));
});
}
return false;
}
catch (_b) {
return false;
}
});
}
/**
* Extract prompt content (everything after frontmatter)
*/
function getPromptContent(promptPath, filesystem) {
const content = filesystem.read(promptPath);
// Remove frontmatter if present
const withoutFrontmatter = content.replace(/^---\n[\s\S]*?\n---\n*/, '');
return withoutFrontmatter.trim();
}
/**
* Get prompt metadata from .md frontmatter
*/
function getPromptMetadata(promptPath, filesystem) {
if (!filesystem.exists(promptPath)) {
return { description: 'No description available', name: '' };
}
const content = filesystem.read(promptPath);
const frontmatterMatch = content.match(/^---\n([\s\S]*?)\n---/);
if (!frontmatterMatch) {
return { description: 'No description available', name: '' };
}
const frontmatter = frontmatterMatch[1];
const descMatch = frontmatter.match(/description:\s*([^\n]+)/);
const nameMatch = frontmatter.match(/name:\s*([^\n]+)/);
return {
description: descMatch ? descMatch[1].trim() : 'No description available',
name: nameMatch ? nameMatch[1].trim() : '',
};
}
/**
* LLM Prompt Templates - Get prompts for various LLMs
*/
const LlmCommand = {
alias: ['llm', 'prompts'],
description: 'Get LLM prompt templates',
hidden: false,
name: 'llm',
run: (toolbox) => __awaiter(void 0, void 0, void 0, function* () {
const { filesystem, parameters, print: { error, highlight, info, success, warning }, prompt, } = toolbox;
try {
// Get the CLI installation directory
const cliRoot = (0, path_1.join)(__dirname, '..', '..');
const promptsTemplateDir = (0, path_1.join)(cliRoot, 'templates', 'llm-prompts');
// Check if llm-prompts directory exists
if (!filesystem.exists(promptsTemplateDir)) {
error('LLM prompts directory not found in CLI installation.');
info(`Expected location: ${promptsTemplateDir}`);
info('Please reinstall the CLI or report this issue.');
return;
}
// Get all available prompts (*.md files)
const allFiles = filesystem.list(promptsTemplateDir) || [];
const availablePrompts = allFiles.filter((file) => file.endsWith('.md'));
if (availablePrompts.length === 0) {
error('No LLM prompts found in CLI installation.');
return;
}
// Show available prompts if no specific prompt requested
let selectedPrompt;
if (parameters.first) {
// Check if the requested prompt exists
const requestedPrompt = parameters.first.endsWith('.md') ? parameters.first : `${parameters.first}.md`;
if (!availablePrompts.includes(requestedPrompt)) {
error(`Prompt "${parameters.first}" not found.`);
info('');
info('Available prompts:');
availablePrompts.forEach((p) => {
const promptPath = (0, path_1.join)(promptsTemplateDir, p);
const metadata = getPromptMetadata(promptPath, filesystem);
const promptName = p.replace('.md', '');
info(` • ${promptName}`);
info(` ${metadata.description}`);
info('');
});
return;
}
selectedPrompt = requestedPrompt;
}
else {
// Interactive mode: show menu
info('');
info('Available LLM Prompt Templates:');
info('');
const choices = [];
availablePrompts.forEach((p) => {
const promptPath = (0, path_1.join)(promptsTemplateDir, p);
const metadata = getPromptMetadata(promptPath, filesystem);
const promptName = p.replace('.md', '');
choices.push({
message: `${promptName} - ${metadata.description}`,
name: promptName,
value: p,
});
});
const { selected } = yield prompt.ask({
choices: choices.map((c) => c.message),
message: 'Select a prompt template:',
name: 'selected',
type: 'select',
});
// Find the selected prompt file
const selectedChoice = choices.find((c) => c.message === selected);
if (!selectedChoice) {
error('Invalid selection.');
return;
}
selectedPrompt = selectedChoice.value;
}
// Get prompt content
const promptPath = (0, path_1.join)(promptsTemplateDir, selectedPrompt);
const promptContent = getPromptContent(promptPath, filesystem);
const metadata = getPromptMetadata(promptPath, filesystem);
// Determine output method
let outputMethod;
if (parameters.options.output || parameters.options.o) {
// Save to file
outputMethod = 'file';
}
else if (parameters.options.clipboard || parameters.options.c) {
// Copy to clipboard
outputMethod = 'clipboard';
}
else if (parameters.options.display || parameters.options.d) {
// Display only
outputMethod = 'display';
}
else {
// Interactive: ask user
const { action } = yield prompt.ask({
choices: ['Display in terminal', 'Copy to clipboard', 'Save as Markdown file'],
message: 'What would you like to do with this prompt?',
name: 'action',
type: 'select',
});
if (action === 'Display in terminal') {
outputMethod = 'display';
}
else if (action === 'Copy to clipboard') {
outputMethod = 'clipboard';
}
else {
outputMethod = 'file';
}
}
// Execute output method
if (outputMethod === 'clipboard') {
const copied = yield copyToClipboard(promptContent);
if (copied) {
success('✓ Prompt copied to clipboard!');
info('');
info('You can now paste it into ChatGPT, Gemini, Claude, or any other LLM.');
}
else {
warning('Could not copy to clipboard automatically.');
info('');
info('The prompt will be displayed below for manual copying:');
info('');
info('─'.repeat(60));
info(promptContent);
info('─'.repeat(60));
}
}
else if (outputMethod === 'display') {
info('');
info('─'.repeat(60));
highlight(`📝 ${metadata.name || selectedPrompt.replace('.md', '')}`);
info('─'.repeat(60));
info('');
info(promptContent);
info('');
info('─'.repeat(60));
success('Prompt displayed above. Copy and paste into your preferred LLM.');
}
else if (outputMethod === 'file') {
let outputPath;
if (typeof parameters.options.output === 'string') {
outputPath = parameters.options.output;
}
else if (typeof parameters.options.o === 'string') {
outputPath = parameters.options.o;
}
else {
// Ask for file path
const defaultFilename = selectedPrompt;
const { filepath } = yield prompt.ask({
initial: defaultFilename,
message: 'Enter the file path to save:',
name: 'filepath',
type: 'input',
});
outputPath = filepath;
}
// Ensure .md extension
if (!outputPath.endsWith('.md')) {
outputPath += '.md';
}
// Check if file exists
if (filesystem.exists(outputPath)) {
const { overwrite } = yield prompt.ask({
initial: false,
message: `File "${outputPath}" already exists. Overwrite?`,
name: 'overwrite',
type: 'confirm',
});
if (!overwrite) {
info('Operation cancelled.');
return;
}
}
// Write file with frontmatter
const fileContent = `---
name: ${metadata.name || selectedPrompt.replace('.md', '')}
description: ${metadata.description}
source: lenne.tech CLI (lt templates llm)
---
${promptContent}
`;
filesystem.write(outputPath, fileContent);
success(`✓ Prompt saved to: ${outputPath}`);
}
info('');
// Exit if not running from menu
if (!toolbox.parameters.options.fromGluegunMenu) {
process.exit();
}
// For tests
return `templates llm ${selectedPrompt.replace('.md', '')}`;
}
catch (err) {
error(`Failed to process prompt: ${err.message}`);
return;
}
}),
};
exports.default = LlmCommand;