UNPKG

@sprucelabs/spruce-cli

Version:

Command line interface for building Spruce skills.

280 lines • 10.6 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const os_1 = __importDefault(require("os")); const mercury_client_1 = require("@sprucelabs/mercury-client"); const spruce_skill_utils_1 = require("@sprucelabs/spruce-skill-utils"); const spruce_templates_1 = require("@sprucelabs/spruce-templates"); const constants_1 = require("../constants"); const SpruceError_1 = __importDefault(require("../errors/SpruceError")); const ActionExecuter_1 = __importDefault(require("../features/ActionExecuter")); const ActionFactory_1 = __importDefault(require("../features/ActionFactory")); const FeatureCommandAttacher_1 = __importDefault(require("../features/FeatureCommandAttacher")); const FeatureInstallerFactory_1 = __importDefault(require("../features/FeatureInstallerFactory")); const GlobalEmitter_1 = __importDefault(require("../GlobalEmitter")); const TerminalInterface_1 = __importDefault(require("../interfaces/TerminalInterface")); const ImportService_1 = __importDefault(require("../services/ImportService")); const ServiceFactory_1 = __importDefault(require("../services/ServiceFactory")); const StoreFactory_1 = __importDefault(require("../stores/StoreFactory")); const apiClient_utility_1 = __importDefault(require("../utilities/apiClient.utility")); const argParser_utility_1 = require("../utilities/argParser.utility"); const WriterFactory_1 = __importDefault(require("../writers/WriterFactory")); class Cli { cwd; featureInstaller; serviceFactory; emitter; static apiClients = {}; attacher; actionExecuter; constructor(cwd, featureInstaller, serviceFactory, emitter, attacher, actionExecuter) { this.cwd = cwd; this.featureInstaller = featureInstaller; this.serviceFactory = serviceFactory; this.emitter = emitter; this.attacher = attacher; this.actionExecuter = actionExecuter; } static async resetApiClients() { for (const key in this.apiClients) { await (await this.apiClients[key]).disconnect(); } this.apiClients = {}; } getAttacher() { return this.attacher; } getActionExecuter() { return this.actionExecuter; } async on(...args) { //@ts-ignore return this.emitter.on(...args); } async off(...args) { //@ts-ignore return this.emitter.off(...args); } async emit(...args) { //@ts-ignore return this.emitter.emit(...args); } async emitAndFlattenResponses(...args) { //@ts-ignore return this.emitter.emitAndFlattenResponses(...args); } async installFeatures(options) { return this.featureInstaller.install(options); } getFeature(code) { return this.featureInstaller.getFeature(code); } async checkHealth(options) { const isInstalled = await this.featureInstaller.isInstalled('skill'); if (!isInstalled) { return { skill: { status: 'failed', errors: [ new SpruceError_1.default({ // @ts-ignore code: 'SKILL_NOT_INSTALLED', }), ], }, }; } try { const commandService = this.serviceFactory.Service(this.cwd, 'command'); const command = options?.shouldRunOnSourceFiles === false ? 'yarn health' : 'yarn health.local'; const results = await commandService.execute(command); const resultParts = results.stdout.split(spruce_skill_utils_1.HEALTH_DIVIDER); return JSON.parse(resultParts[1]); } catch (originalError) { const error = new SpruceError_1.default({ code: 'BOOT_ERROR', originalError, }); return { skill: { status: 'failed', errors: [error], }, }; } } static async Boot(options) { const program = options?.program; const emitter = options?.emitter ?? GlobalEmitter_1.default.Emitter(); let cwd = options?.cwd ?? process.cwd(); ImportService_1.default.enableCaching(); const services = new ServiceFactory_1.default(); const apiClientFactory = options?.apiClientFactory ?? Cli.buildApiClientFactory(cwd, services, options); const storeFactory = new StoreFactory_1.default({ cwd, serviceFactory: services, homeDir: options?.homeDir ?? os_1.default.homedir(), emitter, apiClientFactory, }); const ui = (options?.graphicsInterface ?? new TerminalInterface_1.default(cwd)); let featureInstaller; const writerFactory = new WriterFactory_1.default({ templates: spruce_templates_1.templates, ui, settings: services.Service(cwd, 'settings'), linter: services.Service(cwd, 'lint'), }); const pkg = services.Service(cwd, 'pkg'); const optionOverrides = this.loadOptionOverrides(pkg); const blockedCommands = this.loadCommandBlocks(services.Service(cwd, 'pkg')); try { const s = pkg.getSkillNamespace(); if (s) { ui.setTitle(s); } } catch { // no skill } const actionFactory = new ActionFactory_1.default({ ui, emitter, apiClientFactory, cwd, serviceFactory: services, storeFactory, templates: spruce_templates_1.templates, writerFactory, blockedCommands, optionOverrides, }); const actionExecuter = new ActionExecuter_1.default({ actionFactory, ui, emitter, featureInstallerFactory: () => featureInstaller, }); featureInstaller = options?.featureInstaller ?? FeatureInstallerFactory_1.default.WithAllFeatures({ cwd, serviceFactory: services, storeFactory, ui, emitter, apiClientFactory, actionExecuter, }); let attacher; if (program) { attacher = new FeatureCommandAttacher_1.default({ pkgService: pkg, program, ui, actionExecuter, }); const codes = FeatureInstallerFactory_1.default.featureCodes; for (const code of codes) { const feature = featureInstaller.getFeature(code); await attacher.attachFeature(feature); } program.commands.sort((a, b) => a._name.localeCompare(b._name)); program.action((_, command) => { throw new SpruceError_1.default({ code: 'INVALID_COMMAND', args: command.args || [], }); }); } const cli = new Cli(cwd, featureInstaller, services, emitter, attacher, actionExecuter); return cli; } static loadCommandBlocks(pkg) { let blocks = {}; if (pkg.doesExist()) { blocks = pkg.get('skill.blockedCommands') ?? {}; } return blocks; } static loadOptionOverrides(pkg) { const mapped = {}; if (pkg.doesExist()) { const overrides = pkg.get('skill.commandOverrides'); Object.keys(overrides ?? {}).forEach((command) => { const options = argParser_utility_1.argParserUtil.parse(overrides[command]); mapped[command] = options; }); } return mapped; } static buildApiClientFactory(cwd, serviceFactory, bootOptions) { const apiClientFactory = async (options) => { const key = apiClient_utility_1.default.generateClientCacheKey(options); if (!Cli.apiClients[key]) { Cli.apiClients[key] = Cli.connectToApi(cwd, serviceFactory, options, bootOptions); } return Cli.apiClients[key]; }; return apiClientFactory; } static async connectToApi(cwd, serviceFactory, options, bootOptions) { const connect = bootOptions?.apiClientFactory ? bootOptions.apiClientFactory : async () => { const eventsContracts = require('./../.spruce/events/events.contract').default; const client = await mercury_client_1.MercuryClientFactory.Client({ contracts: eventsContracts, host: bootOptions?.host ?? constants_1.DEFAULT_HOST, allowSelfSignedCrt: true, ...bootOptions, }); return client; }; const { shouldAuthAsCurrentSkill = false, shouldAuthAsLoggedInPerson = true, } = options ?? {}; const client = await connect(); let auth = {}; const pkg = serviceFactory.Service(cwd, 'pkg'); const doesPkgExist = pkg.doesExist(); if (options?.skillId && options?.apiKey) { auth = { skillId: options.skillId, apiKey: options.apiKey, }; } else if (shouldAuthAsCurrentSkill) { const skill = serviceFactory.Service(cwd, 'auth').getCurrentSkill(); if (skill) { auth = { skillId: skill.id, apiKey: skill.apiKey, }; } } else if (doesPkgExist && shouldAuthAsLoggedInPerson) { const person = serviceFactory .Service(cwd, 'auth') .getLoggedInPerson(); if (person) { auth.token = person.token; } } if (Object.keys(auth).length > 0) { await client.authenticate({ ...auth, }); //@ts-ignore client.auth = auth; } return client; } } exports.default = Cli; //# sourceMappingURL=Cli.js.map