mirror of
https://github.com/colbymchenry/codegraph.git
synced 2026-10-19 06:22:38 +08:00
53 lines
3.7 KiB
TypeScript
53 lines
3.7 KiB
TypeScript
import type { Command } from 'commander';
|
|
import * as fs from 'node:fs';
|
|
import * as path from 'node:path';
|
|
import { ExtensionManager, downloadPackage } from './manager';
|
|
import { startExtensionBridge } from './bridge';
|
|
import { packExtension } from './package';
|
|
import { createExtensionProject, testExtension } from './author';
|
|
|
|
export function registerExtensionCommands(program: Command): void {
|
|
const extensions = program.command('extensions').description('Install and manage framework extensions');
|
|
extensions.command('create <directory>').description('Create a portable Python event-map extension starter and author tests')
|
|
.requiredOption('--id <id>', 'Unique lowercase extension id')
|
|
.action((directory, options) => {
|
|
createExtensionProject(directory, options.id);
|
|
console.log(`Created ${path.resolve(directory)}. Next: codegraph extensions test ${directory}`);
|
|
});
|
|
extensions.command('test <directory>').description('Check compatibility, graph assertions, determinism and removal in disposable projects; executes your extension')
|
|
.option('--fixtures <file>', 'Author fixture JSON relative to extension directory', 'extension.test.json')
|
|
.action(async (directory, options) => {
|
|
console.log(JSON.stringify(await testExtension(directory, { fixtures: options.fixtures }), null, 2));
|
|
});
|
|
extensions.command('list').option('--path <path>', 'Project directory', '.').action(options => {
|
|
console.log(JSON.stringify(new ExtensionManager(options.path).list(), null, 2));
|
|
});
|
|
for (const action of ['install', 'update']) extensions.command(`${action} <package>`)
|
|
.description('Install a .cgext package or HTTPS release; extension code runs with your permissions')
|
|
.option('--path <path>', 'Project directory', '.')
|
|
.option('--replaces <frameworks>', 'Explicitly replace comma-separated built-in resolvers')
|
|
.action(async (source, options) => {
|
|
const bytes = /^https?:/.test(source) ? await downloadPackage(source) : fs.readFileSync(path.resolve(source));
|
|
await new ExtensionManager(options.path, p => console.error(`${p.state}: ${p.message}`)).install({ bytes,
|
|
source: /^https?:/.test(source) ? source : undefined, replaces: options.replaces?.split(',') });
|
|
});
|
|
for (const action of ['disable', 'enable', 'remove']) extensions.command(`${action} <id>`)
|
|
.option('--path <path>', 'Project directory', '.').action(async (id, options) => {
|
|
const manager = new ExtensionManager(options.path, p => console.error(`${p.state}: ${p.message}`));
|
|
if (action === 'remove') await manager.remove(id); else await manager.setEnabled(id, action === 'enable');
|
|
});
|
|
extensions.command('connect [projects...]').description('Connect selected local projects to a marketplace; keep this process running')
|
|
.requiredOption('--marketplace <url>', 'Marketplace website URL')
|
|
.option('--port <port>', 'Local companion port', '0').action(async (projects: string[], options) => {
|
|
const bridge = await startExtensionBridge(projects.length ? projects : ['.'], options.marketplace, Number(options.port));
|
|
console.log(`Open this connection link in your browser:\n${bridge.connectionUrl}\n\nKeep this process running. Press Ctrl+C to disconnect.`);
|
|
process.once('SIGINT', () => { void bridge.close(); });
|
|
process.once('SIGTERM', () => { void bridge.close(); });
|
|
});
|
|
extensions.command('pack <directory>').description('Bundle an extension directory; validates metadata without executing code')
|
|
.requiredOption('--out <file>', 'Output .cgext file').action((directory, options) => {
|
|
const bytes = packExtension(directory);
|
|
fs.writeFileSync(options.out, bytes); console.log(`Packed extension into ${options.out}`);
|
|
});
|
|
}
|