UNPKG

@2501-ai/cli

Version:

[![npm version](https://img.shields.io/npm/v/@2501-ai/cli.svg)](https://www.npmjs.com/package/@2501-ai/cli) [![HumanEval Score](https://img.shields.io/badge/HumanEval-96.95%25-brightgreen.svg)](https://www.2501.ai/research/full-humaneval-benchmark) [![Lic

258 lines (255 loc) 11.1 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.tasksSubscriptionCommand = tasksSubscriptionCommand; const os_1 = __importDefault(require("os")); const path_1 = __importDefault(require("path")); const crypto_1 = __importDefault(require("crypto")); const fs_1 = __importDefault(require("fs")); const actions_1 = require("../helpers/actions"); const api_1 = require("../helpers/api"); const workspace_1 = require("../helpers/workspace"); const conf_1 = require("../utils/conf"); const logger_1 = __importDefault(require("../utils/logger")); const shellCommands_1 = require("../utils/shellCommands"); const query_1 = require("./query"); function getTfzoExecPath() { return __awaiter(this, void 0, void 0, function* () { const whichCommand = os_1.default.platform() === 'win32' ? 'where' : 'which'; const whichNode = yield (0, actions_1.run_shell)({ command: `${whichCommand} node`, shell: true, }); if ((0, actions_1.hasError)(whichNode)) { logger_1.default.error(whichNode); return null; } const binary = os_1.default.platform() === 'win32' ? 'a2501.cmd' : '@2501'; const whichTFZO = yield (0, actions_1.run_shell)({ command: `${whichCommand} ${binary}`, shell: true, }); if ((0, actions_1.hasError)(whichTFZO)) { logger_1.default.error(whichTFZO); return null; } return os_1.default.platform() === 'win32' ? whichTFZO.trim() : `${whichNode.trim()} ${whichTFZO.trim()}`; }); } function subscribeUnix(workspace, tfzoExecPath) { return __awaiter(this, void 0, void 0, function* () { const shellOutput = yield (0, actions_1.run_shell)({ command: `echo $SHELL`, shell: true, }); if ((0, actions_1.hasError)(shellOutput)) { return shellOutput; } const sourceCommandOutput = yield (0, actions_1.run_shell)({ command: shellCommands_1.unixSourceCommand, shell: shellOutput, }); if ((0, actions_1.hasError)(sourceCommandOutput)) { return sourceCommandOutput; } const crontabOutput = yield (0, actions_1.run_shell)({ shell: true, command: `(crontab -l 2>/dev/null; echo "* * * * * mkdir -p ${actions_1.LOG_DIR} && ${shellOutput} -c \\"${sourceCommandOutput} && cd ${workspace} && ${tfzoExecPath} tasks --listen\\" >> ${actions_1.LOGFILE_PATH} 2>>${actions_1.ERRORFILE_PATH}") | crontab -`, }); if ((0, actions_1.hasError)(crontabOutput)) { return crontabOutput; } return null; }); } function unsubscribeUnix(workspace, tfzoExecPath) { return __awaiter(this, void 0, void 0, function* () { const crontabOutput = yield (0, actions_1.run_shell)({ shell: true, command: `crontab -l | grep -v "cd ${workspace} && ${tfzoExecPath} tasks --listen" | crontab -`, }); if ((0, actions_1.hasError)(crontabOutput)) { return crontabOutput; } return null; }); } function generateTaskName(workspace) { const hash = crypto_1.default .createHash('md5') .update(workspace) .digest('hex') .substring(0, 8); const baseName = path_1.default.basename(workspace); return `2501-tasks-listener-${baseName}-${hash}`; } function subscribeWindows(workspace, tfzoExecPath) { return __awaiter(this, void 0, void 0, function* () { const taskName = generateTaskName(workspace); const logDir = actions_1.LOG_DIR.replace(/\//g, '\\'); const logFile = actions_1.LOGFILE_PATH.replace(/\//g, '\\'); const errorFile = actions_1.ERRORFILE_PATH.replace(/\//g, '\\'); try { fs_1.default.mkdirSync(logDir, { recursive: true }); } catch (error) { return `Failed to create log directory: ${error}`; } const appDataDir = path_1.default.join(os_1.default.homedir(), 'AppData', 'Local', '2501'); const permanentBatchFile = path_1.default.join(appDataDir, `${taskName}.bat`); const timestamp = new Date() .toISOString() .replace(/[:.]/g, '-') .substring(0, 16); const timestampedLogFile = logFile.replace('.log', `-${timestamp}.log`); const timestampedErrorFile = errorFile.replace('.log', `-${timestamp}.log`); const currentPath = process.env.PATH || ''; const batchContent = `@echo off REM Preserve current user environment for scheduled task set "PATH=${currentPath}" REM Change to workspace directory cd /d "${workspace}" REM Run the task - execute .cmd file directly "${tfzoExecPath}" tasks --listen >> "${timestampedLogFile}" 2>> "${timestampedErrorFile}"`; try { fs_1.default.mkdirSync(appDataDir, { recursive: true }); fs_1.default.writeFileSync(permanentBatchFile, batchContent, 'utf8'); } catch (error) { return `Failed to create batch file: ${error}`; } const schtasksOutput = yield (0, actions_1.run_shell)({ shell: true, command: `schtasks /create /tn "${taskName}" /tr "${permanentBatchFile}" /sc minute /mo 1 /f`, }); if ((0, actions_1.hasError)(schtasksOutput)) { return schtasksOutput; } return null; }); } function unsubscribeWindows(workspace) { return __awaiter(this, void 0, void 0, function* () { const taskName = generateTaskName(workspace); const appDataDir = path_1.default.join(os_1.default.homedir(), 'AppData', 'Local', '2501'); const permanentBatchFile = path_1.default.join(appDataDir, `${taskName}.bat`); const schtasksOutput = yield (0, actions_1.run_shell)({ shell: true, command: `schtasks /delete /tn "${taskName}" /f`, }); if ((0, actions_1.hasError)(schtasksOutput)) { return schtasksOutput; } try { if (fs_1.default.existsSync(permanentBatchFile)) { fs_1.default.unlinkSync(permanentBatchFile); } } catch (error) { console.warn(`Warning: Could not delete batch file: ${error}`); } return null; }); } function subscribeToTasks(workspace, tfzoExecPath) { return __awaiter(this, void 0, void 0, function* () { const isWindows = os_1.default.platform() === 'win32'; return isWindows ? yield subscribeWindows(workspace, tfzoExecPath) : yield subscribeUnix(workspace, tfzoExecPath); }); } function unsubscribeFromTasks(workspace, tfzoExecPath) { return __awaiter(this, void 0, void 0, function* () { const isWindows = os_1.default.platform() === 'win32'; return isWindows ? yield unsubscribeWindows(workspace) : yield unsubscribeUnix(workspace, tfzoExecPath); }); } function tasksSubscriptionCommand(options) { return __awaiter(this, void 0, void 0, function* () { const logger = new logger_1.default(); const workspace = (0, workspace_1.resolveWorkspacePath)(options); logger.intro('2501 - Tasks Subscription'); const tfzoExecPath = yield getTfzoExecPath(); if (!tfzoExecPath) { throw new Error('Failed to get TFZO executable path'); } if (options.subscribe) { logger.start('Subscribing for new tasks'); const error = yield subscribeToTasks(workspace, tfzoExecPath); if (error) { logger_1.default.error('Subscription failed:', error); return; } logger.stop(`Subscribed to the API for new tasks on workspace ${workspace}`); return; } if (options.unsubscribe) { logger.start('Unsubscribing for new jobs'); const error = yield unsubscribeFromTasks(workspace, tfzoExecPath); if (error) { logger_1.default.error('Unsubscription failed:', error); return; } logger.stop(`Unsubscribed to the API for new tasks on workspace ${workspace}`); return; } if (options.listen) { try { const agent = (0, conf_1.getEligibleAgent)(workspace); if (!agent) { logger.outro('No agents available in the workspace'); return; } logger.start(); logger.log(`Listening for new tasks on ${workspace}`); const status = 'assigned'; logger.log(`Retrieving tasks for agent ${agent.id} with status ${status}`); const tasks = yield (0, api_1.getTasks)(agent.id, status); if (!tasks.length) { logger.stop(`No tasks found`); return; } logger.log(`Found ${tasks.length} tasks to execute`); const exitCodes = []; for (const idx in tasks) { logger.log(`Processing task ${tasks[idx].id}`); yield (0, query_1.queryCommand)(tasks[idx].brief, { workspace, agentId: agent.id, taskId: tasks[idx].id, }).catch((error) => __awaiter(this, void 0, void 0, function* () { yield (0, api_1.updateTask)(agent.id, tasks[idx].id, { status: 'failed', result: `CLI Error: ${error}`, }); logger_1.default.error(`Task ${tasks[idx].id} failed: ${error}`); exitCodes.push(1); })); } logger.log(`${exitCodes.length}/${tasks.length} tasks have been processed`); logger.stop(); } catch (error) { logger.stop('Tasks error', 1); throw error; } } throw new Error('No option provided to listen for tasks.'); }); }