@daomar/agentfleet
Advanced tools
| "use strict"; | ||
| var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { | ||
| if (k2 === undefined) k2 = k; | ||
| var desc = Object.getOwnPropertyDescriptor(m, k); | ||
| if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { | ||
| desc = { enumerable: true, get: function() { return m[k]; } }; | ||
| } | ||
| Object.defineProperty(o, k2, desc); | ||
| }) : (function(o, m, k, k2) { | ||
| if (k2 === undefined) k2 = k; | ||
| o[k2] = m[k]; | ||
| })); | ||
| var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { | ||
| Object.defineProperty(o, "default", { enumerable: true, value: v }); | ||
| }) : function(o, v) { | ||
| o["default"] = v; | ||
| }); | ||
| var __importStar = (this && this.__importStar) || (function () { | ||
| var ownKeys = function(o) { | ||
| ownKeys = Object.getOwnPropertyNames || function (o) { | ||
| var ar = []; | ||
| for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; | ||
| return ar; | ||
| }; | ||
| return ownKeys(o); | ||
| }; | ||
| return function (mod) { | ||
| if (mod && mod.__esModule) return mod; | ||
| var result = {}; | ||
| if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); | ||
| __setModuleDefault(result, mod); | ||
| return result; | ||
| }; | ||
| })(); | ||
| Object.defineProperty(exports, "__esModule", { value: true }); | ||
@@ -6,4 +39,7 @@ exports.LocalFolderBackend = exports.validateRelativePath = exports.TransientIOError = exports.PermissionError = exports.AlreadyExistsError = exports.NotFoundError = exports.BackendError = void 0; | ||
| exports.listBackends = listBackends; | ||
| const path = __importStar(require("path")); | ||
| const fs = __importStar(require("fs")); | ||
| const local_folder_js_1 = require("./local-folder.js"); | ||
| const i18n_js_1 = require("../services/i18n.js"); | ||
| const onedrive_detector_js_1 = require("../services/onedrive-detector.js"); | ||
| var errors_js_1 = require("./errors.js"); | ||
@@ -19,2 +55,21 @@ Object.defineProperty(exports, "BackendError", { enumerable: true, get: function () { return errors_js_1.BackendError; } }); | ||
| Object.defineProperty(exports, "LocalFolderBackend", { enumerable: true, get: function () { return local_folder_js_2.LocalFolderBackend; } }); | ||
| function createOnedriveBackend(business) { | ||
| return (config) => { | ||
| // If path is already resolved (from config), use it directly | ||
| if (config.path && typeof config.path === 'string') { | ||
| return new local_folder_js_1.LocalFolderBackend({ path: config.path }); | ||
| } | ||
| // Auto-detect OneDrive path | ||
| const detector = new onedrive_detector_js_1.OneDriveDetector(); | ||
| const accounts = detector.detectAccounts(); | ||
| const account = accounts.find((a) => a.isBusiness === business); | ||
| if (!account) { | ||
| const key = business ? 'init.onedrive_business_not_found' : 'init.onedrive_not_found'; | ||
| throw new Error((0, i18n_js_1.t)(key)); | ||
| } | ||
| const fleetPath = path.join(account.path, 'AgentFleet'); | ||
| fs.mkdirSync(fleetPath, { recursive: true }); | ||
| return new local_folder_js_1.LocalFolderBackend({ path: fleetPath }); | ||
| }; | ||
| } | ||
| const registry = new Map([ | ||
@@ -30,2 +85,4 @@ [ | ||
| ], | ||
| ['onedrive', createOnedriveBackend(false)], | ||
| ['onedrive-business', createOnedriveBackend(true)], | ||
| ]); | ||
@@ -32,0 +89,0 @@ /** |
+1
-1
@@ -72,3 +72,3 @@ #!/usr/bin/env node | ||
| .requiredOption('--backend <name>', (0, i18n_1.t)('init.option_backend'), 'local-folder') | ||
| .requiredOption('--path <dir>', (0, i18n_1.t)('init.option_path')) | ||
| .option('--path <dir>', (0, i18n_1.t)('init.option_path')) | ||
| .option('--force', 'Overwrite existing configuration') | ||
@@ -75,0 +75,0 @@ .action(init_1.initCommand); |
@@ -43,7 +43,8 @@ "use strict"; | ||
| const i18n_js_1 = require("../services/i18n.js"); | ||
| const onedrive_detector_js_1 = require("../services/onedrive-detector.js"); | ||
| const CONFIG_DIR = path.join(os.homedir(), '.agentfleet'); | ||
| const CONFIG_PATH = path.join(CONFIG_DIR, 'config.json'); | ||
| const LOGS_DIR = path.join(CONFIG_DIR, 'logs'); | ||
| const FLEET_DIRS = ['tasks', 'claims', 'heartbeats', 'results', 'archive', 'fleet']; | ||
| const VERSION = '3.0.0'; | ||
| const FLEET_DIRS = ['tasks', 'results']; | ||
| const VERSION = '3.1.0'; | ||
| function generateAgentId() { | ||
@@ -67,3 +68,2 @@ const hostname = os.hostname().replace(/[^a-zA-Z0-9_-]/g, '').substring(0, 32); | ||
| const backendName = options.backend; | ||
| const fleetPath = path.resolve(options.path); | ||
| // Validate backend name | ||
@@ -76,2 +76,36 @@ const available = deps.listBackends(); | ||
| } | ||
| // Resolve fleet path | ||
| let fleetPath; | ||
| const isOneDrive = backendName === 'onedrive' || backendName === 'onedrive-business'; | ||
| if (options.path) { | ||
| fleetPath = path.resolve(options.path); | ||
| } | ||
| else if (isOneDrive) { | ||
| // Auto-detect OneDrive path | ||
| const isBusiness = backendName === 'onedrive-business'; | ||
| try { | ||
| const detectFn = deps.detectOneDrive ?? (() => new onedrive_detector_js_1.OneDriveDetector().detectAccounts()); | ||
| const accounts = detectFn(); | ||
| const account = accounts.find((a) => a.isBusiness === isBusiness); | ||
| if (!account) { | ||
| const key = isBusiness ? 'init.onedrive_business_not_found' : 'init.onedrive_not_found'; | ||
| console.error(`❌ ${(0, i18n_js_1.t)(key)}`); | ||
| process.exitCode = 1; | ||
| return; | ||
| } | ||
| fleetPath = path.join(account.path, 'AgentFleet'); | ||
| console.log(`📂 ${(0, i18n_js_1.t)('init.onedrive_detected', { path: fleetPath })}`); | ||
| } | ||
| catch (err) { | ||
| const key = isBusiness ? 'init.onedrive_business_not_found' : 'init.onedrive_not_found'; | ||
| console.error(`❌ ${(0, i18n_js_1.t)(key)}`); | ||
| process.exitCode = 1; | ||
| return; | ||
| } | ||
| } | ||
| else { | ||
| console.error(`❌ ${(0, i18n_js_1.t)('init.path_required_for_backend', { backend: backendName })}`); | ||
| process.exitCode = 1; | ||
| return; | ||
| } | ||
| // Check existing config (unless --force) | ||
@@ -78,0 +112,0 @@ if (!options.force) { |
@@ -6,7 +6,17 @@ "use strict"; | ||
| const daemon_1 = require("../services/daemon"); | ||
| const config_1 = require("../services/config"); | ||
| const i18n_1 = require("../services/i18n"); | ||
| function installCommand(_options, _cmdObj, dependencies = {}) { | ||
| async function installCommand(_options, _cmdObj, dependencies = {}) { | ||
| const autoStartManager = dependencies.autoStartManager ?? (0, auto_start_1.createAutoStartManager)(); | ||
| const daemonService = dependencies.daemonService ?? new daemon_1.DaemonService(); | ||
| const exit = dependencies.exit ?? ((code) => process.exit(code)); | ||
| // Check v3 config exists | ||
| const loadConfigFn = dependencies.loadConfigFn ?? config_1.loadConfig; | ||
| try { | ||
| await loadConfigFn(); | ||
| } | ||
| catch { | ||
| console.error(`❌ ${(0, i18n_1.t)('run.no_config')}`); | ||
| return exit(1); | ||
| } | ||
| if (!autoStartManager.isSupported()) { | ||
@@ -13,0 +23,0 @@ console.error(`❌ ${(0, i18n_1.t)('autostart.unsupported', { platform: process.platform })}`); |
+114
-94
| "use strict"; | ||
| var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { | ||
| if (k2 === undefined) k2 = k; | ||
| var desc = Object.getOwnPropertyDescriptor(m, k); | ||
| if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { | ||
| desc = { enumerable: true, get: function() { return m[k]; } }; | ||
| } | ||
| Object.defineProperty(o, k2, desc); | ||
| }) : (function(o, m, k, k2) { | ||
| if (k2 === undefined) k2 = k; | ||
| o[k2] = m[k]; | ||
| })); | ||
| var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { | ||
| Object.defineProperty(o, "default", { enumerable: true, value: v }); | ||
| }) : function(o, v) { | ||
| o["default"] = v; | ||
| }); | ||
| var __importStar = (this && this.__importStar) || (function () { | ||
| var ownKeys = function(o) { | ||
| ownKeys = Object.getOwnPropertyNames || function (o) { | ||
| var ar = []; | ||
| for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; | ||
| return ar; | ||
| }; | ||
| return ownKeys(o); | ||
| }; | ||
| return function (mod) { | ||
| if (mod && mod.__esModule) return mod; | ||
| var result = {}; | ||
| if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); | ||
| __setModuleDefault(result, mod); | ||
| return result; | ||
| }; | ||
| })(); | ||
| Object.defineProperty(exports, "__esModule", { value: true }); | ||
@@ -12,2 +45,20 @@ exports.runCommand = runCommand; | ||
| const protocol_engine_1 = require("../services/protocol-engine"); | ||
| const fs = __importStar(require("fs")); | ||
| const path = __importStar(require("path")); | ||
| const os = __importStar(require("os")); | ||
| const AGENTFLEET_DIR = path.join(os.homedir(), '.agentfleet'); | ||
| function loadProcessedIds(processedPath) { | ||
| try { | ||
| if (fs.existsSync(processedPath)) { | ||
| const data = JSON.parse(fs.readFileSync(processedPath, 'utf-8')); | ||
| return new Set(data.processedIds ?? []); | ||
| } | ||
| } | ||
| catch { /* ignore corrupt file */ } | ||
| return new Set(); | ||
| } | ||
| function saveProcessedIds(processedPath, ids) { | ||
| fs.mkdirSync(path.dirname(processedPath), { recursive: true }); | ||
| fs.writeFileSync(processedPath, JSON.stringify({ processedIds: Array.from(ids) }, null, 2)); | ||
| } | ||
| async function runCommand(options, dependencies = {}) { | ||
@@ -90,4 +141,3 @@ const exit = dependencies.exit ?? ((code) => process.exit(code)); | ||
| : new protocol_engine_1.ProtocolEngine(backend, config.agentId, { | ||
| convergenceWindowMs: config.convergenceWindowMs, | ||
| heartbeatIntervalMs: config.heartbeatIntervalMs, | ||
| pollIntervalMs: pollIntervalSeconds * 1000, | ||
| }); | ||
@@ -101,3 +151,3 @@ // Create executor with v2-compatible config shape | ||
| onedriveAccountType: 'personal', | ||
| hostname: require('os').hostname(), | ||
| hostname: os.hostname(), | ||
| defaultAgent: config.defaultAgent ?? 'claude-code', | ||
@@ -113,6 +163,9 @@ defaultAgentCommand: config.defaultAgentCommand ?? 'claude -p {prompt}', | ||
| : new agent_executor_1.AgentExecutor(executorConfig); | ||
| // Load local processed IDs | ||
| const processedPath = dependencies.processedPath ?? path.join(AGENTFLEET_DIR, 'processed.json'); | ||
| const processedIds = loadProcessedIds(processedPath); | ||
| let running = 0; | ||
| let shuttingDown = false; | ||
| let polling = false; | ||
| // Poll-claim loop | ||
| // Broadcast poll loop | ||
| async function pollCycle() { | ||
@@ -123,108 +176,74 @@ if (shuttingDown || polling) | ||
| try { | ||
| // 1. Check stale claims and heartbeats | ||
| const staleClaims = await engine.checkStaleClaims(); | ||
| for (const taskId of staleClaims) { | ||
| console.log(`🔄 ${(0, i18n_1.t)('protocol.stale_claim_recovered', { taskId })}`); | ||
| await engine.resetTaskToPending(taskId); | ||
| } | ||
| const staleHeartbeats = await engine.checkStaleHeartbeats(); | ||
| for (const taskId of staleHeartbeats) { | ||
| console.log(`🔄 ${(0, i18n_1.t)('protocol.stale_heartbeat_recovered', { taskId })}`); | ||
| await engine.resetTaskToPending(taskId); | ||
| } | ||
| // 2. Skip scan if at max concurrency | ||
| // Skip if at max concurrency | ||
| if (running >= maxConcurrency) | ||
| return; | ||
| // 3. Scan for pending tasks | ||
| // Scan for pending tasks | ||
| const { tasks, errors } = await engine.scan(); | ||
| // 4. Reject malformed tasks | ||
| for (const err of errors) { | ||
| const match = err.match(/^tasks\/(.+)\.json:/); | ||
| if (match) { | ||
| console.log(`⛔ ${(0, i18n_1.t)('run.task_rejected', { taskId: match[1], reason: err })}`); | ||
| await engine.rejectTask(match[1], err); | ||
| } | ||
| console.warn(`⚠️ ${err}`); | ||
| } | ||
| if (tasks.length === 0) | ||
| return; | ||
| // 5. Pick highest-priority task | ||
| const task = tasks[0]; | ||
| // 5a. Attempt claim | ||
| console.log(`🏁 ${(0, i18n_1.t)('protocol.claim_attempt', { taskId: task.id })}`); | ||
| const claimed = await engine.attemptClaim(task.id); | ||
| if (!claimed) | ||
| return; | ||
| // 5b. Wait for convergence | ||
| const convergenceMs = engine.getConvergenceWindowMs(); | ||
| console.log(`⏳ ${(0, i18n_1.t)('run.convergence_waiting', { seconds: (convergenceMs / 1000).toFixed(1), taskId: task.id })}`); | ||
| await sleepFn(convergenceMs); | ||
| // 5c. Resolve claim winner | ||
| const { won, winnerId } = await engine.resolveClaimWinner(task.id); | ||
| if (!won) { | ||
| console.log(`❌ ${(0, i18n_1.t)('protocol.claim_lost', { taskId: task.id, winnerId })}`); | ||
| return; | ||
| } | ||
| console.log(`✅ ${(0, i18n_1.t)('protocol.claim_won', { taskId: task.id })}`); | ||
| // 5d. Update status | ||
| await engine.updateTaskStatus(task.id, 'claimed'); | ||
| await engine.updateTaskStatus(task.id, 'running'); | ||
| // 5e. Start heartbeat timer | ||
| const heartbeatInterval = setInterval(async () => { | ||
| try { | ||
| await engine.writeHeartbeat(task.id); | ||
| // Process unprocessed tasks | ||
| for (const task of tasks) { | ||
| if (shuttingDown) | ||
| break; | ||
| if (running >= maxConcurrency) | ||
| break; | ||
| if (processedIds.has(task.id)) | ||
| continue; | ||
| // Also check if we already have a result on the backend | ||
| const alreadyDone = await engine.hasResult(task.id); | ||
| if (alreadyDone) { | ||
| processedIds.add(task.id); | ||
| saveProcessedIds(processedPath, processedIds); | ||
| continue; | ||
| } | ||
| catch (err) { | ||
| console.warn(`⚠️ ${(0, i18n_1.t)('run.heartbeat_failed', { taskId: task.id, message: err.message })}`); | ||
| } | ||
| }, engine.getHeartbeatIntervalMs()); | ||
| running++; | ||
| // 5f. Execute via AgentExecutor | ||
| const startTime = Date.now(); | ||
| try { | ||
| await engine.writeHeartbeat(task.id); | ||
| const execResult = await executor.execute({ | ||
| id: task.id, | ||
| prompt: task.prompt, | ||
| command: task.command || executorConfig.defaultAgentCommand, | ||
| workingDirectory: task.workingDirectory, | ||
| }); | ||
| // 5g. Write protocol result | ||
| const result = { | ||
| taskId: task.id, | ||
| agentId: config.agentId, | ||
| status: execResult.status === 'completed' ? 'completed' : 'failed', | ||
| exitCode: execResult.exitCode, | ||
| stdout: execResult.stdout?.substring(0, 64 * 1024), | ||
| completedAt: new Date().toISOString(), | ||
| durationMs: Date.now() - startTime, | ||
| error: execResult.error, | ||
| }; | ||
| // 5h. Archive task | ||
| await engine.archiveTask(task.id, result); | ||
| } | ||
| catch (err) { | ||
| console.error(`❌ ${(0, i18n_1.t)('run.execution_error', { taskId: task.id, message: err.message })}`); | ||
| // Try to mark as failed | ||
| console.log(`\n📋 ${(0, i18n_1.t)('run.new_task', { taskId: task.id, title: task.title ? ` - ${task.title}` : '' })}`); | ||
| running++; | ||
| const startTime = Date.now(); | ||
| try { | ||
| const failResult = { | ||
| const execResult = await executor.execute({ | ||
| id: task.id, | ||
| prompt: task.prompt, | ||
| command: task.command || executorConfig.defaultAgentCommand, | ||
| workingDirectory: task.workingDirectory, | ||
| }); | ||
| // Write per-agent result | ||
| const result = { | ||
| taskId: task.id, | ||
| agentId: config.agentId, | ||
| status: 'failed', | ||
| exitCode: null, | ||
| status: execResult.status === 'completed' ? 'completed' : 'failed', | ||
| exitCode: execResult.exitCode, | ||
| stdout: execResult.stdout?.substring(0, 64 * 1024), | ||
| completedAt: new Date().toISOString(), | ||
| durationMs: Date.now() - startTime, | ||
| error: err.message, | ||
| error: execResult.error, | ||
| }; | ||
| await engine.archiveTask(task.id, failResult); | ||
| await engine.writeResult(task.id, result); | ||
| console.log(`✅ ${(0, i18n_1.t)('run.task_completed', { taskId: task.id, duration: ((Date.now() - startTime) / 1000).toFixed(1) })}`); | ||
| } | ||
| catch { | ||
| // Last resort: reset to pending | ||
| await engine.resetTaskToPending(task.id); | ||
| catch (err) { | ||
| console.error(`❌ ${(0, i18n_1.t)('run.execution_error', { taskId: task.id, message: err.message })}`); | ||
| // Write failure result | ||
| try { | ||
| const failResult = { | ||
| taskId: task.id, | ||
| agentId: config.agentId, | ||
| status: 'failed', | ||
| exitCode: null, | ||
| completedAt: new Date().toISOString(), | ||
| durationMs: Date.now() - startTime, | ||
| error: err.message, | ||
| }; | ||
| await engine.writeResult(task.id, failResult); | ||
| } | ||
| catch { /* best effort */ } | ||
| } | ||
| finally { | ||
| running--; | ||
| processedIds.add(task.id); | ||
| saveProcessedIds(processedPath, processedIds); | ||
| } | ||
| } | ||
| finally { | ||
| // 5i. Clear heartbeat timer | ||
| clearInterval(heartbeatInterval); | ||
| running--; | ||
| } | ||
| } | ||
@@ -238,3 +257,4 @@ catch (err) { | ||
| } | ||
| console.log(`\n🟢 ${(0, i18n_1.t)('run.running_on', { hostname: require('os').hostname() })}`); | ||
| console.log(`\n🟢 ${(0, i18n_1.t)('run.running_on', { hostname: os.hostname() })}`); | ||
| console.log(` ${(0, i18n_1.t)('run.agent_id', { agentId: config.agentId })}`); | ||
| console.log(` ${(0, i18n_1.t)('run.concurrency', { value: maxConcurrency })}`); | ||
@@ -241,0 +261,0 @@ console.log(` ${(0, i18n_1.t)('run.poll_interval', { value: pollIntervalSeconds })}`); |
+72
-81
@@ -37,18 +37,15 @@ "use strict"; | ||
| exports.statusCommand = statusCommand; | ||
| const fs = __importStar(require("fs")); | ||
| const path = __importStar(require("path")); | ||
| const setup_1 = require("../services/setup"); | ||
| const daemon_1 = require("../services/daemon"); | ||
| const auto_start_1 = require("../services/auto-start"); | ||
| const version_checker_1 = require("../services/version-checker"); | ||
| const bootstrap_1 = require("../services/bootstrap"); | ||
| const config_1 = require("../services/config"); | ||
| const index_1 = require("../backends/index"); | ||
| const protocol_engine_1 = require("../services/protocol-engine"); | ||
| const i18n_1 = require("../services/i18n"); | ||
| const fs = __importStar(require("fs")); | ||
| async function statusCommand(taskId, _cmdObj, dependencies = {}) { | ||
| const setup = dependencies.setup ?? new setup_1.SetupService(); | ||
| const daemonService = dependencies.daemonService ?? new daemon_1.DaemonService(); | ||
| const autoStartManager = dependencies.autoStartManager ?? (0, auto_start_1.createAutoStartManager)(); | ||
| const versionChecker = dependencies.versionChecker ?? new version_checker_1.VersionChecker(); | ||
| await (dependencies.bootstrapFn ?? bootstrap_1.bootstrap)({ setup }); | ||
| const tasksDir = setup.getTasksDir(); | ||
| const outputDir = setup.getOutputDir(); | ||
| const exit = dependencies.exit ?? ((code) => { process.exitCode = code; }); | ||
| // Show version info | ||
@@ -58,8 +55,27 @@ await showVersionInfo(versionChecker); | ||
| showProcessInfo(daemonService, autoStartManager); | ||
| // Load v3 config | ||
| let config; | ||
| try { | ||
| const loadConfigFn = dependencies.loadConfigFn ?? config_1.loadConfig; | ||
| config = await loadConfigFn(); | ||
| } | ||
| catch (err) { | ||
| console.error(`❌ ${(0, i18n_1.t)('run.no_config')}`); | ||
| exit(1); | ||
| return; | ||
| } | ||
| // Create backend + engine | ||
| const createBackendFn = dependencies.createBackend ?? index_1.getBackend; | ||
| const backend = createBackendFn(config.backend, config.backendConfig); | ||
| await backend.initialize(); | ||
| const engine = dependencies.createEngine | ||
| ? dependencies.createEngine(backend, config.agentId) | ||
| : new protocol_engine_1.ProtocolEngine(backend, config.agentId); | ||
| if (taskId) { | ||
| showTaskDetail(taskId, tasksDir, outputDir); | ||
| await showTaskDetail(taskId, engine); | ||
| } | ||
| else { | ||
| showAllTasks(tasksDir, outputDir); | ||
| await showAllTasks(engine); | ||
| } | ||
| await backend.shutdown(); | ||
| } | ||
@@ -110,33 +126,26 @@ function showProcessInfo(daemonService, autoStartManager) { | ||
| } | ||
| function showAllTasks(tasksDir, outputDir) { | ||
| const taskFiles = fs.readdirSync(tasksDir).filter(f => f.endsWith('.json')); | ||
| if (taskFiles.length === 0) { | ||
| async function showAllTasks(engine) { | ||
| const { tasks, errors } = await engine.listAllTasks(); | ||
| for (const err of errors) { | ||
| console.warn(`⚠️ ${err}`); | ||
| } | ||
| if (tasks.length === 0) { | ||
| console.log((0, i18n_1.t)('status.no_tasks')); | ||
| return; | ||
| } | ||
| console.log(`\n📋 ${(0, i18n_1.t)('status.tasks_header', { count: taskFiles.length })}\n`); | ||
| console.log(`\n📋 ${(0, i18n_1.t)('status.tasks_header', { count: tasks.length })}\n`); | ||
| console.log(padRight((0, i18n_1.t)('status.col_id'), 36) + padRight((0, i18n_1.t)('status.col_title'), 30) + padRight((0, i18n_1.t)('status.col_status'), 12) + (0, i18n_1.t)('status.col_results')); | ||
| console.log('─'.repeat(90)); | ||
| for (const file of taskFiles) { | ||
| for (const task of tasks) { | ||
| try { | ||
| const content = fs.readFileSync(path.join(tasksDir, file), 'utf-8'); | ||
| const task = JSON.parse(content); | ||
| // Check for results | ||
| const taskOutputDir = path.join(outputDir, task.id); | ||
| let resultCount = 0; | ||
| let machines = []; | ||
| if (fs.existsSync(taskOutputDir)) { | ||
| const resultFiles = fs.readdirSync(taskOutputDir).filter(f => f.endsWith('-result.json')); | ||
| resultCount = resultFiles.length; | ||
| machines = resultFiles.map(f => f.replace('-result.json', '')); | ||
| } | ||
| const status = resultCount > 0 ? (0, i18n_1.t)('status.status_done', { count: resultCount }) : (0, i18n_1.t)('status.status_pending'); | ||
| const machineStr = machines.length > 0 ? machines.join(', ') : '-'; | ||
| const agents = await engine.listResults(task.id); | ||
| const status = agents.length > 0 ? (0, i18n_1.t)('status.status_done', { count: agents.length }) : (0, i18n_1.t)('status.status_pending'); | ||
| const agentStr = agents.length > 0 ? agents.join(', ') : '-'; | ||
| console.log(padRight(task.id, 36) + | ||
| padRight(task.title || (0, i18n_1.t)('status.untitled'), 30) + | ||
| padRight(status, 12) + | ||
| machineStr); | ||
| agentStr); | ||
| } | ||
| catch { | ||
| console.log(padRight(file, 36) + (0, i18n_1.t)('status.error_reading')); | ||
| console.log(padRight(task.id, 36) + (0, i18n_1.t)('status.error_reading')); | ||
| } | ||
@@ -146,20 +155,8 @@ } | ||
| } | ||
| function showTaskDetail(taskId, tasksDir, outputDir) { | ||
| // Find task file | ||
| const taskFiles = fs.readdirSync(tasksDir).filter(f => f.endsWith('.json')); | ||
| let task = null; | ||
| for (const file of taskFiles) { | ||
| try { | ||
| const content = fs.readFileSync(path.join(tasksDir, file), 'utf-8'); | ||
| const parsed = JSON.parse(content); | ||
| if (parsed.id === taskId) { | ||
| task = parsed; | ||
| break; | ||
| } | ||
| } | ||
| catch { /* skip */ } | ||
| } | ||
| async function showTaskDetail(taskId, engine) { | ||
| const task = await engine.readTask(taskId); | ||
| if (!task) { | ||
| console.error(`❌ ${(0, i18n_1.t)('status.task_not_found', { taskId })}`); | ||
| process.exit(1); | ||
| process.exitCode = 1; | ||
| return; | ||
| } | ||
@@ -169,36 +166,37 @@ console.log(`\n📋 ${(0, i18n_1.t)('status.task_header', { taskId: task.id })}`); | ||
| console.log(` ${(0, i18n_1.t)('status.task_prompt', { prompt: task.prompt })}`); | ||
| console.log(` ${(0, i18n_1.t)('status.task_working_dir', { path: task.workingDirectory || (0, i18n_1.t)('status.task_default') })}`); | ||
| console.log(` ${(0, i18n_1.t)('status.task_agent', { agent: task.command || (0, i18n_1.t)('status.task_default') })}`); | ||
| if (task.workingDirectory) { | ||
| console.log(` ${(0, i18n_1.t)('status.task_working_dir', { path: task.workingDirectory })}`); | ||
| } | ||
| if (task.command) { | ||
| console.log(` ${(0, i18n_1.t)('status.task_agent', { agent: task.command })}`); | ||
| } | ||
| console.log(` ${(0, i18n_1.t)('status.task_created', { date: task.createdAt ? (0, i18n_1.formatDate)(task.createdAt) : (0, i18n_1.t)('status.task_unknown') })}`); | ||
| console.log(` ${(0, i18n_1.t)('status.task_created_by', { hostname: task.createdBy || (0, i18n_1.t)('status.task_unknown') })}`); | ||
| // Show results | ||
| const taskOutputDir = path.join(outputDir, task.id); | ||
| if (fs.existsSync(taskOutputDir)) { | ||
| const resultFiles = fs.readdirSync(taskOutputDir).filter(f => f.endsWith('-result.json')); | ||
| if (resultFiles.length > 0) { | ||
| console.log(`\n📊 ${(0, i18n_1.t)('status.results_header', { count: resultFiles.length })}\n`); | ||
| for (const resultFile of resultFiles) { | ||
| try { | ||
| const content = fs.readFileSync(path.join(taskOutputDir, resultFile), 'utf-8'); | ||
| const result = JSON.parse(content); | ||
| const icon = result.status === 'completed' ? '✅' : result.status === 'timeout' ? '⏰' : '❌'; | ||
| console.log(` ${icon} ${result.hostname}`); | ||
| console.log(` ${(0, i18n_1.t)('status.result_status', { status: result.status, exitCode: result.exitCode })}`); | ||
| console.log(` ${(0, i18n_1.t)('status.result_started', { date: (0, i18n_1.formatDate)(result.startedAt) })}`); | ||
| const agents = await engine.listResults(taskId); | ||
| if (agents.length > 0) { | ||
| console.log(`\n📊 ${(0, i18n_1.t)('status.results_header', { count: agents.length })}\n`); | ||
| for (const agentId of agents) { | ||
| try { | ||
| const result = await engine.readResult(taskId, agentId); | ||
| if (!result) | ||
| continue; | ||
| const icon = result.status === 'completed' ? '✅' : '❌'; | ||
| console.log(` ${icon} ${agentId}`); | ||
| console.log(` ${(0, i18n_1.t)('status.result_status', { status: result.status, exitCode: result.exitCode ?? 'N/A' })}`); | ||
| if (result.completedAt) { | ||
| console.log(` ${(0, i18n_1.t)('status.result_completed', { date: (0, i18n_1.formatDate)(result.completedAt) })}`); | ||
| if (result.error) | ||
| console.log(` ${(0, i18n_1.t)('status.result_error', { error: result.error })}`); | ||
| } | ||
| catch { /* skip */ } | ||
| if (result.durationMs) { | ||
| console.log(` Duration: ${(result.durationMs / 1000).toFixed(1)}s`); | ||
| } | ||
| if (result.error) { | ||
| console.log(` ${(0, i18n_1.t)('status.result_error', { error: result.error })}`); | ||
| } | ||
| if (result.stdout) { | ||
| const excerpt = result.stdout.substring(0, 200); | ||
| console.log(` Output: ${excerpt}${result.stdout.length > 200 ? '...' : ''}`); | ||
| } | ||
| } | ||
| catch { /* skip */ } | ||
| } | ||
| // List all output files | ||
| const allFiles = fs.readdirSync(taskOutputDir); | ||
| if (allFiles.length > 0) { | ||
| console.log(`\n📁 ${(0, i18n_1.t)('status.output_files')}`); | ||
| for (const f of allFiles) { | ||
| const stats = fs.statSync(path.join(taskOutputDir, f)); | ||
| console.log(` ${f} (${formatBytes(stats.size)})`); | ||
| } | ||
| } | ||
| } | ||
@@ -213,9 +211,2 @@ else { | ||
| } | ||
| function formatBytes(bytes) { | ||
| if (bytes < 1024) | ||
| return `${bytes}B`; | ||
| if (bytes < 1024 * 1024) | ||
| return `${(bytes / 1024).toFixed(1)}KB`; | ||
| return `${(bytes / (1024 * 1024)).toFixed(1)}MB`; | ||
| } | ||
| //# sourceMappingURL=status.js.map |
| { | ||
| "cli.description": "Distributed agent orchestration, without a control plane.", | ||
| "cli.run_description": "Start AgentFleet: auto-initialize if needed, then watch for tasks", | ||
| "cli.run_description": "Start watching for tasks and execute them", | ||
| "cli.run_option_poll": "Polling interval in seconds", | ||
@@ -172,2 +172,6 @@ "cli.run_option_concurrency": "Maximum concurrent agent processes", | ||
| "init.option_path": "Path to the shared fleet directory", | ||
| "init.onedrive_detected": "OneDrive detected: {path}", | ||
| "init.onedrive_not_found": "No personal OneDrive account found. Please install OneDrive and sign in.", | ||
| "init.onedrive_business_not_found": "No OneDrive for Business account found. Please install OneDrive and sign in with your work account.", | ||
| "init.path_required_for_backend": "The --path option is required for backend '{backend}'.", | ||
@@ -184,2 +188,4 @@ "protocol.claim_attempt": "Attempting claim on task {taskId}", | ||
| "run.new_task": "New task: {taskId}{title}", | ||
| "run.task_completed": "Task {taskId} completed in {duration}s", | ||
| "run.task_rejected": "Task {taskId} rejected: {reason}", | ||
@@ -191,2 +197,3 @@ "run.heartbeat_failed": "Heartbeat failed for task {taskId}: {message}", | ||
| "run.convergence_waiting": "Waiting {seconds}s for convergence on task {taskId}...", | ||
| "run.agent_id": "Agent ID: {agentId}", | ||
@@ -193,0 +200,0 @@ "submit.created": "Task {taskId} created via v3 protocol", |
| { | ||
| "cli.description": "分布式智能体编排,无需控制平面。", | ||
| "cli.run_description": "启动 AgentFleet:如需初始化则自动完成,然后监听任务", | ||
| "cli.run_description": "开始监听任务并执行", | ||
| "cli.run_option_poll": "轮询间隔(秒)", | ||
@@ -172,2 +172,6 @@ "cli.run_option_concurrency": "最大并发代理进程数", | ||
| "init.option_path": "共享 Fleet 目录的路径", | ||
| "init.onedrive_detected": "已检测到 OneDrive: {path}", | ||
| "init.onedrive_not_found": "未找到个人 OneDrive 帐户。请安装 OneDrive 并登录。", | ||
| "init.onedrive_business_not_found": "未找到 OneDrive 企业版帐户。请安装 OneDrive 并使用工作帐户登录。", | ||
| "init.path_required_for_backend": "后端 '{backend}' 需要 --path 参数。", | ||
@@ -184,2 +188,4 @@ "protocol.claim_attempt": "正在尝试认领任务 {taskId}", | ||
| "run.new_task": "新任务: {taskId}{title}", | ||
| "run.task_completed": "任务 {taskId} 已完成,耗时 {duration}秒", | ||
| "run.task_rejected": "任务 {taskId} 已拒绝: {reason}", | ||
@@ -191,2 +197,3 @@ "run.heartbeat_failed": "任务 {taskId} 心跳失败: {message}", | ||
| "run.convergence_waiting": "正在等待任务 {taskId} 的 {seconds}秒 收敛窗口...", | ||
| "run.agent_id": "Agent ID: {agentId}", | ||
@@ -193,0 +200,0 @@ "submit.created": "任务 {taskId} 已通过 v3 协议创建", |
| "use strict"; | ||
| Object.defineProperty(exports, "__esModule", { value: true }); | ||
| exports.ProtocolEngine = void 0; | ||
| const errors_js_1 = require("../backends/errors.js"); | ||
| const DEFAULTS = { | ||
| convergenceWindowMs: 5000, | ||
| heartbeatIntervalMs: 30000, | ||
| claimAgeTimeoutFactor: 2, // claimAgeTimeout = convergenceWindow * factor | ||
| heartbeatStaleFactor: 3, // heartbeatStale = heartbeatInterval * factor | ||
| }; | ||
| const errors_1 = require("../backends/errors"); | ||
| /** | ||
| * Protocol engine for broadcast execution model. | ||
| * Every agent executes every task. No claims, no tiebreaks. | ||
| */ | ||
| class ProtocolEngine { | ||
@@ -15,20 +13,13 @@ constructor(backend, agentId, options = {}) { | ||
| this.agentId = agentId; | ||
| const convergence = options.convergenceWindowMs | ||
| ?? backend.getRecommendedConvergenceWindow() | ||
| ?? DEFAULTS.convergenceWindowMs; | ||
| this.convergenceWindowMs = convergence; | ||
| this.heartbeatIntervalMs = options.heartbeatIntervalMs ?? DEFAULTS.heartbeatIntervalMs; | ||
| this.claimAgeTimeoutMs = options.claimAgeTimeoutMs ?? convergence * DEFAULTS.claimAgeTimeoutFactor; | ||
| this.heartbeatStaleMs = options.heartbeatStaleMs ?? this.heartbeatIntervalMs * DEFAULTS.heartbeatStaleFactor; | ||
| this.pollIntervalMs = options.pollIntervalMs ?? 10000; | ||
| } | ||
| getConvergenceWindowMs() { | ||
| return this.convergenceWindowMs; | ||
| getAgentId() { | ||
| return this.agentId; | ||
| } | ||
| getHeartbeatIntervalMs() { | ||
| return this.heartbeatIntervalMs; | ||
| getPollIntervalMs() { | ||
| return this.pollIntervalMs; | ||
| } | ||
| /** | ||
| * Scan tasks/ directory, parse JSON files, return pending tasks sorted by | ||
| * priority (desc) then createdAt (asc). | ||
| * v2 compat: tasks without status are treated as 'pending'. | ||
| * Scan tasks/ for all tasks, return pending ones sorted by priority desc then createdAt asc. | ||
| * v2 compat: tasks without a status field are treated as pending. | ||
| */ | ||
@@ -42,3 +33,3 @@ async scan() { | ||
| catch (err) { | ||
| if (err instanceof errors_js_1.NotFoundError) { | ||
| if (err instanceof errors_1.NotFoundError) { | ||
| return { tasks: [], errors: [] }; | ||
@@ -89,19 +80,12 @@ } | ||
| /** | ||
| * Attempt to claim a task by writing claims/{taskId}/{agentId}. | ||
| * Returns true if the claim file was created, false if it already exists. | ||
| * Read a single task by ID. | ||
| */ | ||
| async attemptClaim(taskId) { | ||
| const claimPath = `claims/${taskId}/${this.agentId}`; | ||
| const claimData = { | ||
| agentId: this.agentId, | ||
| claimedAt: new Date().toISOString(), | ||
| }; | ||
| async readTask(taskId) { | ||
| try { | ||
| await this.backend.createExclusive(claimPath, JSON.stringify(claimData)); | ||
| return true; | ||
| const content = await this.backend.readFile(`tasks/${taskId}.json`); | ||
| return JSON.parse(content); | ||
| } | ||
| catch (err) { | ||
| if (err instanceof errors_js_1.AlreadyExistsError) { | ||
| return false; | ||
| } | ||
| if (err instanceof errors_1.NotFoundError) | ||
| return null; | ||
| throw err; | ||
@@ -111,222 +95,87 @@ } | ||
| /** | ||
| * Resolve claim winner for a task. | ||
| * Reads all claim files under claims/{taskId}/, picks lowest agentId (ASCII sort). | ||
| * If this agent is not the winner, deletes our own claim. | ||
| * Returns { won: boolean, winnerId: string }. | ||
| * List all tasks (any status). | ||
| */ | ||
| async resolveClaimWinner(taskId) { | ||
| const claimDir = `claims/${taskId}`; | ||
| async listAllTasks() { | ||
| const errors = []; | ||
| let files; | ||
| try { | ||
| files = await this.backend.listFiles(claimDir); | ||
| files = await this.backend.listFiles('tasks'); | ||
| } | ||
| catch (err) { | ||
| if (err instanceof errors_js_1.NotFoundError) { | ||
| return { won: false, winnerId: '' }; | ||
| if (err instanceof errors_1.NotFoundError) { | ||
| return { tasks: [], errors: [] }; | ||
| } | ||
| throw err; | ||
| } | ||
| // Extract agent IDs from file paths | ||
| const agentIds = files.map((f) => { | ||
| const parts = f.split('/'); | ||
| return parts[parts.length - 1]; | ||
| }).filter((id) => id.length > 0); | ||
| if (agentIds.length === 0) { | ||
| return { won: false, winnerId: '' }; | ||
| const tasks = []; | ||
| for (const file of files) { | ||
| if (!file.endsWith('.json')) | ||
| continue; | ||
| try { | ||
| const content = await this.backend.readFile(file); | ||
| const parsed = JSON.parse(content); | ||
| if (!parsed.id || !parsed.prompt) { | ||
| errors.push(`${file}: missing required fields`); | ||
| continue; | ||
| } | ||
| if (!parsed.status) | ||
| parsed.status = 'pending'; | ||
| tasks.push(parsed); | ||
| } | ||
| catch (err) { | ||
| errors.push(`${file}: ${err.message}`); | ||
| } | ||
| } | ||
| // Sort lexicographically, lowest wins | ||
| agentIds.sort(); | ||
| const winnerId = agentIds[0]; | ||
| const won = winnerId === this.agentId; | ||
| // If we lost, delete our claim | ||
| if (!won) { | ||
| const ourClaim = `claims/${taskId}/${this.agentId}`; | ||
| await this.backend.deleteFile(ourClaim); | ||
| } | ||
| return { won, winnerId }; | ||
| return { tasks, errors }; | ||
| } | ||
| /** | ||
| * Update the status field of a task file. Read-modify-write. | ||
| * Write a per-agent result to results/{taskId}/{agentId}.json | ||
| */ | ||
| async updateTaskStatus(taskId, status) { | ||
| const taskPath = `tasks/${taskId}.json`; | ||
| const content = await this.backend.readFile(taskPath); | ||
| const task = JSON.parse(content); | ||
| task.status = status; | ||
| task.updatedAt = new Date().toISOString(); | ||
| await this.backend.writeFile(taskPath, JSON.stringify(task, null, 2)); | ||
| async writeResult(taskId, result) { | ||
| const resultPath = `results/${taskId}/${this.agentId}.json`; | ||
| await this.backend.writeFile(resultPath, JSON.stringify(result, null, 2)); | ||
| } | ||
| /** | ||
| * Write a heartbeat file for the given task. | ||
| * List all agent results for a task. | ||
| * Returns array of agentIds that have results. | ||
| */ | ||
| async writeHeartbeat(taskId) { | ||
| const heartbeatPath = `heartbeats/${taskId}`; | ||
| const heartbeat = { | ||
| agentId: this.agentId, | ||
| taskId, | ||
| timestamp: new Date().toISOString(), | ||
| pid: process.pid, | ||
| }; | ||
| await this.backend.writeFile(heartbeatPath, JSON.stringify(heartbeat)); | ||
| } | ||
| /** | ||
| * Check for stale claims: claims older than claimAgeTimeout with no heartbeat. | ||
| * Returns task IDs that should be reset to pending. | ||
| */ | ||
| async checkStaleClaims() { | ||
| const staleTaskIds = []; | ||
| let claimDirs; | ||
| async listResults(taskId) { | ||
| try { | ||
| claimDirs = await this.backend.listFiles('claims'); | ||
| const files = await this.backend.listFiles(`results/${taskId}`); | ||
| return files | ||
| .filter((f) => f.endsWith('.json')) | ||
| .map((f) => { | ||
| // f is like "results/{taskId}/agent-1.json" | ||
| const basename = f.split('/').pop() ?? ''; | ||
| return basename.replace('.json', ''); | ||
| }); | ||
| } | ||
| catch (err) { | ||
| if (err instanceof errors_js_1.NotFoundError) | ||
| if (err instanceof errors_1.NotFoundError) | ||
| return []; | ||
| throw err; | ||
| } | ||
| const now = Date.now(); | ||
| for (const claimDir of claimDirs) { | ||
| const taskId = claimDir.split('/').pop(); | ||
| // Check if there's a heartbeat for this task | ||
| const hasHeartbeat = await this.backend.fileExists(`heartbeats/${taskId}`); | ||
| if (hasHeartbeat) | ||
| continue; | ||
| // Check claim age | ||
| let claimFiles; | ||
| try { | ||
| claimFiles = await this.backend.listFiles(claimDir); | ||
| } | ||
| catch { | ||
| continue; | ||
| } | ||
| let isStale = false; | ||
| for (const claimFile of claimFiles) { | ||
| const mtime = await this.backend.getFileModifiedTime(claimFile); | ||
| if (mtime && (now - mtime.getTime()) > this.claimAgeTimeoutMs) { | ||
| isStale = true; | ||
| // Delete the stale claim | ||
| await this.backend.deleteFile(claimFile); | ||
| } | ||
| } | ||
| if (isStale) { | ||
| staleTaskIds.push(taskId); | ||
| } | ||
| } | ||
| return staleTaskIds; | ||
| } | ||
| /** | ||
| * Check for stale heartbeats: heartbeats older than heartbeatStaleMs. | ||
| * Returns task IDs that should be reset to pending. | ||
| * Read a specific agent's result for a task. | ||
| */ | ||
| async checkStaleHeartbeats() { | ||
| const staleTaskIds = []; | ||
| let heartbeatFiles; | ||
| async readResult(taskId, agentId) { | ||
| try { | ||
| heartbeatFiles = await this.backend.listFiles('heartbeats'); | ||
| const content = await this.backend.readFile(`results/${taskId}/${agentId}.json`); | ||
| return JSON.parse(content); | ||
| } | ||
| catch (err) { | ||
| if (err instanceof errors_js_1.NotFoundError) | ||
| return []; | ||
| if (err instanceof errors_1.NotFoundError) | ||
| return null; | ||
| throw err; | ||
| } | ||
| const now = Date.now(); | ||
| for (const hbFile of heartbeatFiles) { | ||
| const mtime = await this.backend.getFileModifiedTime(hbFile); | ||
| if (mtime && (now - mtime.getTime()) > this.heartbeatStaleMs) { | ||
| const taskId = hbFile.split('/').pop(); | ||
| staleTaskIds.push(taskId); | ||
| // Clean up stale heartbeat | ||
| await this.backend.deleteFile(hbFile); | ||
| } | ||
| } | ||
| return staleTaskIds; | ||
| } | ||
| /** | ||
| * Archive a completed task. Write archive + result, then clean up. | ||
| * Cleanup: delete claims dir files, heartbeat, task file. | ||
| * Check if this agent already has a result for a task. | ||
| */ | ||
| async archiveTask(taskId, result) { | ||
| // Read the task file | ||
| const taskPath = `tasks/${taskId}.json`; | ||
| const taskContent = await this.backend.readFile(taskPath); | ||
| const task = JSON.parse(taskContent); | ||
| // Write result | ||
| await this.backend.writeFile(`results/${taskId}.json`, JSON.stringify(result, null, 2)); | ||
| // Write archive | ||
| const archived = { | ||
| task, | ||
| result, | ||
| archivedAt: new Date().toISOString(), | ||
| }; | ||
| await this.backend.writeFile(`archive/${taskId}.json`, JSON.stringify(archived, null, 2)); | ||
| // Clean up claims | ||
| try { | ||
| const claimFiles = await this.backend.listFiles(`claims/${taskId}`); | ||
| for (const f of claimFiles) { | ||
| await this.backend.deleteFile(f); | ||
| } | ||
| } | ||
| catch { | ||
| // claims dir may not exist | ||
| } | ||
| // Clean up heartbeat | ||
| await this.backend.deleteFile(`heartbeats/${taskId}`); | ||
| // Delete task file | ||
| await this.backend.deleteFile(taskPath); | ||
| async hasResult(taskId) { | ||
| return this.backend.fileExists(`results/${taskId}/${this.agentId}.json`); | ||
| } | ||
| /** | ||
| * Reject a malformed task. Write archive with rejected status, then delete task. | ||
| */ | ||
| async rejectTask(taskId, reason) { | ||
| const taskPath = `tasks/${taskId}.json`; | ||
| let task; | ||
| try { | ||
| const content = await this.backend.readFile(taskPath); | ||
| task = JSON.parse(content); | ||
| } | ||
| catch { | ||
| // If we can't read the task, create a minimal record | ||
| task = { | ||
| id: taskId, | ||
| prompt: '', | ||
| status: 'rejected', | ||
| createdAt: new Date().toISOString(), | ||
| updatedAt: new Date().toISOString(), | ||
| }; | ||
| } | ||
| task.status = 'rejected'; | ||
| task.updatedAt = new Date().toISOString(); | ||
| const result = { | ||
| taskId, | ||
| agentId: this.agentId, | ||
| status: 'failed', | ||
| exitCode: null, | ||
| completedAt: new Date().toISOString(), | ||
| durationMs: 0, | ||
| error: reason, | ||
| }; | ||
| const archived = { | ||
| task, | ||
| result, | ||
| archivedAt: new Date().toISOString(), | ||
| }; | ||
| await this.backend.writeFile(`archive/${taskId}.json`, JSON.stringify(archived, null, 2)); | ||
| // Delete task file | ||
| await this.backend.deleteFile(taskPath); | ||
| } | ||
| /** | ||
| * Reset a task to pending. Used after recovering stale claims/heartbeats. | ||
| */ | ||
| async resetTaskToPending(taskId) { | ||
| try { | ||
| await this.updateTaskStatus(taskId, 'pending'); | ||
| } | ||
| catch (err) { | ||
| if (err instanceof errors_js_1.NotFoundError) | ||
| return; // Task was already cleaned up | ||
| throw err; | ||
| } | ||
| } | ||
| } | ||
| exports.ProtocolEngine = ProtocolEngine; | ||
| //# sourceMappingURL=protocol-engine.js.map |
+1
-1
| { | ||
| "name": "@daomar/agentfleet", | ||
| "version": "3.0.0", | ||
| "version": "3.1.0", | ||
| "description": "Distributed agent orchestration, without a control plane.", | ||
@@ -5,0 +5,0 @@ "main": "dist/cli.js", |
AI-detected potential malware
Supply chain riskAI has identified this package as malware. This is a strong signal that the package may be malicious.
Found 1 instance in 1 package
AI-detected potential code anomaly
Supply chain riskAI has identified unusual behaviors that may pose a security risk.
Found 2 instances in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
AI-detected potential malware
Supply chain riskAI has identified this package as malware. This is a strong signal that the package may be malicious.
Found 1 instance in 1 package
AI-detected potential code anomaly
Supply chain riskAI has identified unusual behaviors that may pose a security risk.
Found 3 instances in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
400965
-0.26%4007
-0.62%22
4.76%