UNPKG

auto-builder-sdk

Version:

SDK for building Auto Builder workflow plugins

144 lines (137 loc) 4.92 kB
#!/usr/bin/env node // auto-builder-sdk/src/bin/cli.ts import { dirname, join } from 'node:path'; import { fileURLToPath } from 'node:url'; import fs from 'node:fs'; import inquirer from 'inquirer'; import chalk from 'chalk'; const [, , cmd, pluginName] = process.argv; const usage = () => { console.log('\nUsage:'); console.log(' npx auto-builder-sdk init <my-plugin>\n'); }; if (cmd !== 'init' || !pluginName) { usage(); process.exit(cmd ? 1 : 0); } // Resolve SDK version by walking up directories until we find the nearest // package.json (works both from `src/` and the compiled `dist/` layout). const findPkgJson = (start) => { let dir = start; // eslint-disable-next-line no-constant-condition while (true) { const candidate = join(dir, 'package.json'); if (fs.existsSync(candidate)) return candidate; const parent = dirname(dir); if (parent === dir) throw new Error('package.json not found'); dir = parent; } }; const pkgPath = findPkgJson(dirname(fileURLToPath(import.meta.url))); const { version: sdkVersion } = JSON.parse(fs.readFileSync(pkgPath, 'utf8')); (async () => { const dest = join(process.cwd(), pluginName); if (fs.existsSync(dest)) { console.error(chalk.red(`Directory ${pluginName} already exists`)); process.exit(1); } let description = process.env.PLUGIN_DESC ?? ''; if (process.stdin.isTTY && !description) { const answers = await inquirer.prompt([ { type: 'input', name: 'description', message: 'Plugin description:', default: '' }, ]); description = answers.description; } fs.mkdirSync(dest, { recursive: true }); fs.writeFileSync(join(dest, 'package.json'), JSON.stringify({ name: pluginName, version: '0.0.1', description, type: 'module', main: 'dist/index.js', nodes: ['HelloNode'], engines: { 'auto-builder': '^1.0.0', node: '>=18', }, scripts: { build: 'tsc', test: 'vitest', verify: 'vitest run --coverage', prepare: 'npm run build', prepublishOnly: 'npm run verify', dev: 'nodemon --watch src --ext ts,js,json --exec "npm run build && npm run deploy-plugin"', 'deploy-plugin': `mkdir -p ../../auto-builder/plugins/${pluginName} && cp -R ./dist ../../auto-builder/plugins/${pluginName}/ && cp package.json ../../auto-builder/plugins/${pluginName}/`, }, devDependencies: { typescript: '^5.8.3', vitest: '^1.6.1', '@vitest/coverage-v8': '^1.6.1', 'auto-builder-sdk': `^${sdkVersion}`, }, 'auto-builder-plugin': true, }, null, 2)); // --- Vitest configuration with coverage provider ------------------ fs.writeFileSync(join(dest, 'vitest.config.ts'), `import { defineConfig } from 'vitest/config';\n\nexport default defineConfig({\n test: {\n coverage: { provider: 'v8' },\n },\n});\n`); // --- TypeScript config ------------------------------------------- fs.writeFileSync(join(dest, 'tsconfig.json'), `{ "compilerOptions": { "rootDir": "src", "outDir": "dist", "module": "NodeNext", "moduleResolution": "NodeNext", "target": "ES2022", "strict": true, "declaration": true, "esModuleInterop": true, "skipLibCheck": true }, "include": ["src"] } `); const srcDir = join(dest, 'src'); fs.mkdirSync(srcDir); const sample = `import { BaseNodeExecutor } from 'auto-builder-sdk'; export class HelloNode extends BaseNodeExecutor { static type = 'hello.world'; readonly nodeType = 'hello.world'; async execute(node, inputData, context) { return [{ json: { message: 'Hello from ${pluginName}!' }, binary: {} }]; } } export default { name: '${pluginName}', version: '0.0.1', main: './dist/index.js', nodes: ['HelloNode'], engines: { 'auto-builder': '^1.0.0' }, }; `; fs.writeFileSync(join(srcDir, 'index.ts'), sample); // --- Sample unit test -------------------------------------------- const testsDir = join(dest, 'tests'); fs.mkdirSync(testsDir); fs.writeFileSync(join(testsDir, 'hello-node.test.ts'), `import { describe, it, expect, vi } from 'vitest'; // Minimal stub for SDK so the test runs without full Auto-Builder. vi.mock('auto-builder-sdk', () => { class StubBase { async execute() { return []; } } return { BaseNodeExecutor: StubBase, definePlugin: (m: any) => m, makeStubContext: () => ({}) as any, makeStubNode: (t: string) => ({ type: t }) as any, }; }); import { HelloNode } from '../src/index'; describe('HelloNode', () => { it('class is defined', () => { expect(HelloNode).toBeDefined(); }); }); `); console.log(chalk.green(`\n✔ Plugin ${pluginName} scaffolded!`)); })();