@sprucelabs/spruce-cli
Version:
Command line interface for building Spruce skills.
280 lines • 10.6 kB
JavaScript
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
;