@agentled/cli
Version:
CLI for Agentled — manage workflows, apps, and knowledge from the command line. Zero context-window cost for AI agents.
103 lines • 4.57 kB
JavaScript
/* eslint-disable no-console */
import { existsSync, readFileSync, readdirSync, writeFileSync } from 'node:fs';
import { join, dirname, resolve } from 'node:path';
import { homedir } from 'node:os';
import { fileURLToPath } from 'node:url';
function resolveBundledScaffoldsDir() {
const here = fileURLToPath(import.meta.url);
// dist/commands/scaffold.js → package root is two levels up
const pkgRoot = resolve(dirname(here), '..', '..');
return join(pkgRoot, 'scaffolds');
}
function resolveLocalScaffoldDirs() {
const dirs = [];
if (process.env.AGENTLED_SCAFFOLDS_DIR)
dirs.push(process.env.AGENTLED_SCAFFOLDS_DIR);
dirs.push(join(homedir(), '.agentled', 'scaffolds'));
return dirs.filter(existsSync);
}
function readDir(dir, source) {
if (!existsSync(dir))
return [];
return readdirSync(dir)
.filter(f => f.endsWith('.json'))
.map(file => {
const path = join(dir, file);
const slug = file.replace(/\.json$/, '');
try {
const obj = JSON.parse(readFileSync(path, 'utf-8'));
return { slug, name: obj.name ?? slug, goal: obj.goal ?? '', path, source };
}
catch {
return { slug, name: slug, goal: '(invalid JSON)', path, source };
}
});
}
function loadScaffolds() {
// Local scaffolds shadow bundled ones with the same slug. Enables a
// workspace / customer / team to ship their own scaffold library without
// waiting on a CLI release, while keeping the bundled patterns as a
// canonical fallback.
const bundled = readDir(resolveBundledScaffoldsDir(), 'bundled');
const local = [];
for (const dir of resolveLocalScaffoldDirs())
local.push(...readDir(dir, 'local'));
const bySlug = new Map();
for (const s of bundled)
bySlug.set(s.slug, s);
for (const s of local)
bySlug.set(s.slug, s); // local wins
return [...bySlug.values()].sort((a, b) => a.slug.localeCompare(b.slug));
}
function findScaffold(scaffolds, query) {
const q = query.toLowerCase();
return (scaffolds.find(s => s.slug.toLowerCase() === q) ??
scaffolds.find(s => s.slug.toLowerCase().includes(q)) ??
null);
}
export function registerScaffoldCommand(workflows) {
workflows
.command('scaffold [pattern]')
.description('Emit a working pipeline JSON skeleton for a named pattern. Run without args to list available scaffolds.')
.option('--list', 'List available scaffolds')
.option('--out <path>', 'Write the scaffold JSON to this path instead of stdout')
.action((pattern, opts) => {
const scaffolds = loadScaffolds();
if (scaffolds.length === 0) {
console.error('No scaffolds bundled with this CLI version.');
process.exit(1);
}
if (!pattern || opts.list) {
console.log('Available scaffolds:\n');
for (const s of scaffolds) {
const tag = s.source === 'local' ? ' [local]' : '';
console.log(` ${s.slug.padEnd(28)}${tag.padEnd(8)} ${s.name}`);
if (s.goal)
console.log(` ${' '.repeat(36)} ${s.goal}`);
}
console.log('\nUsage:');
console.log(' agentled workflows scaffold <pattern> # print JSON to stdout');
console.log(' agentled workflows scaffold <pattern> --out x.json # write to file');
console.log(' agentled workflows validate --file x.json # preflight before create');
console.log(' agentled workflows create --file x.json # create + auto-validate');
console.log('\nBring your own: drop JSON files in ~/.agentled/scaffolds/ or set');
console.log('$AGENTLED_SCAFFOLDS_DIR. Local slugs shadow bundled ones with the same name.');
return;
}
const found = findScaffold(scaffolds, pattern);
if (!found) {
console.error(`Scaffold "${pattern}" not found. Run \`agentled workflows scaffold --list\` for available scaffolds.`);
process.exit(1);
}
const content = readFileSync(found.path, 'utf-8');
if (opts.out) {
writeFileSync(opts.out, content);
console.error(` ✓ Wrote ${found.slug} to ${opts.out}`);
console.error(` Next: agentled workflows validate --file ${opts.out}`);
}
else {
process.stdout.write(content);
}
});
}
//# sourceMappingURL=scaffold.js.map