diff options
| author | Agando <roduccomm@gmail.com> | 2026-06-02 18:00:37 +0200 |
|---|---|---|
| committer | Agando <roduccomm@gmail.com> | 2026-06-02 18:00:37 +0200 |
| commit | aafb0fbde5289a45f9f818a00141f80b149be283 (patch) | |
| tree | d4d8f588187719c99240fbaef1940c068402b892 /modules/core/module-leases.js | |
| parent | 6d41e590a38c73ef60f1c04beaf8f5438f350f46 (diff) | |
auto: 2026-06-02_18:00 changes
Diffstat (limited to 'modules/core/module-leases.js')
| -rw-r--r-- | modules/core/module-leases.js | 102 |
1 files changed, 102 insertions, 0 deletions
diff --git a/modules/core/module-leases.js b/modules/core/module-leases.js new file mode 100644 index 0000000..b79870c --- /dev/null +++ b/modules/core/module-leases.js @@ -0,0 +1,102 @@ +// module-leases.js — Lease system for agent task delegation +// Commands: lease-create, lease-list, lease-revoke, lease-renew +class LeaseModule { + constructor() { + this.commands = {}; + this.terminal = null; + this._leases = {}; + this._watchdogTimer = null; + } + registerCommands() { + this.commands['lease-create'] = (args) => this.createLease(args); + this.commands['lease-list'] = () => this.listLeases(); + this.commands['lease-revoke'] = (args) => this.revokeLease(args[0]); + this.commands['lease-renew'] = (args) => this.renewLease(args[0], parseInt(args[1]) || 30); + } + init(terminal) { + this.terminal = terminal; + if (!this.terminal.fs.readFile('/leases/')) { + this.terminal.fs.mkdir('leases'); + } + // Restore persisted leases + const files = this.terminal.fs.ls('/leases/'); + if (files) { + files.forEach(f => { + if (f.name.endsWith('.json')) { + const data = this.terminal.fs.readFile(`/leases/${f.name}`); + if (data) { + try { + const lease = JSON.parse(data); + this._leases[lease.id] = lease; + } catch (e) {} + } + } + }); + } + // Start watchdog every 5 seconds + this._watchdogTimer = setInterval(() => this._checkExpired(), 5000); + this.terminal.print('📜 Lease system loaded', 'info'); + } + createLease(args) { + const workerId = args[1]; + const duration = parseInt(args[2]) || 30; + const task = args.slice(3).join(' ') || 'generic task'; + if (!workerId) return this.terminal.print('Usage: lease-create <agent-id> [duration_sec] [task]', 'error'); + + const lease = { + id: `lease-${Date.now()}`, + workerId, + orchestratorId: 'orchestrator-0', + task, + createdAt: new Date().toISOString(), + expiresAt: new Date(Date.now() + duration * 1000).toISOString(), + status: 'active', + duration + }; + this._leases[lease.id] = lease; + this.terminal.fs.writeFile(`leases/${lease.id}.json`, JSON.stringify(lease)); + this.terminal.print(`📜 Lease ${lease.id} created for ${workerId} (${duration}s, task: ${task.substring(0, 40)})`, 'success'); + return lease; + } + listLeases() { + const all = Object.values(this._leases); + const active = all.filter(l => l.status === 'active'); + const expired = all.filter(l => l.status === 'expired'); + const revoked = all.filter(l => l.status === 'revoked'); + this.terminal.print(`📜 Leases: ${active.length} active, ${expired.length} expired, ${revoked.length} revoked`, 'header'); + active.forEach(l => { + const remaining = Math.max(0, Math.round((new Date(l.expiresAt) - Date.now()) / 1000)); + this.terminal.print(` ${l.id} → ${l.workerId} (${remaining}s remain) — ${l.task.substring(0, 40)}`, 'info'); + }); + } + revokeLease(id) { + if (!this._leases[id]) return this.terminal.print(`❌ Lease ${id} not found`, 'error'); + this._leases[id].status = 'revoked'; + this._leases[id].revokedAt = new Date().toISOString(); + this.terminal.fs.writeFile(`leases/${id}.json`, JSON.stringify(this._leases[id])); + this.terminal.print(`✅ Lease ${id} revoked`, 'warning'); + } + renewLease(id, additionalSeconds) { + if (!this._leases[id] || this._leases[id].status !== 'active') { + return this.terminal.print(`❌ Lease ${id} not found or not active`, 'error'); + } + const lease = this._leases[id]; + const newExpiry = new Date(Date.now() + additionalSeconds * 1000); + lease.expiresAt = newExpiry.toISOString(); + lease.duration += additionalSeconds; + lease.renewedAt = new Date().toISOString(); + this.terminal.fs.writeFile(`leases/${id}.json`, JSON.stringify(lease)); + this.terminal.print(`✅ Lease ${id} renewed (+${additionalSeconds}s)`, 'success'); + } + _checkExpired() { + const now = Date.now(); + Object.values(this._leases).forEach(lease => { + if (lease.status === 'active' && new Date(lease.expiresAt) < now) { + lease.status = 'expired'; + lease.expiredAt = new Date().toISOString(); + this.terminal.fs.writeFile(`leases/${lease.id}.json`, JSON.stringify(lease)); + this.terminal.log('INFO', 'Lease', `Lease ${lease.id} for ${lease.workerId} expired`); + } + }); + } +}
\ No newline at end of file |