UNPKG

aetherlight

Version:

Voice-to-intelligence platform for developers. Voice capture, sprint planning with AI, bug/feature forms, pattern matching to prevent AI hallucinations.

216 lines 7.08 kB
"use strict"; /** * Workflow State Machine - Sprint execution lifecycle management * * DESIGN DECISION: Explicit state transitions with validation * WHY: Prevents invalid state transitions, enables workflow recovery * * REASONING CHAIN: * 1. Sprint starts: NOT_STARTED → IN_PROGRESS * 2. User pauses: IN_PROGRESS → PAUSED * 3. User resumes: PAUSED → IN_PROGRESS * 4. All tasks complete: IN_PROGRESS → COMPLETE * 5. Critical failure: ANY → FAILED * 6. Result: Predictable workflow lifecycle with recovery * * PATTERN: Pattern-STATE-MACHINE-001 (Workflow State Management) * RELATED: AS-003 (Task Scheduler), AS-014 (File-Based IPC) */ Object.defineProperty(exports, "__esModule", { value: true }); exports.WorkflowStateMachine = exports.WorkflowState = void 0; /** * Workflow state enumeration */ var WorkflowState; (function (WorkflowState) { /** Sprint not yet started */ WorkflowState["NOT_STARTED"] = "NOT_STARTED"; /** Sprint in progress (tasks executing) */ WorkflowState["IN_PROGRESS"] = "IN_PROGRESS"; /** Sprint paused by user */ WorkflowState["PAUSED"] = "PAUSED"; /** Sprint completed successfully */ WorkflowState["COMPLETE"] = "COMPLETE"; /** Sprint failed (critical error) */ WorkflowState["FAILED"] = "FAILED"; })(WorkflowState || (exports.WorkflowState = WorkflowState = {})); /** * Workflow state machine * * DESIGN DECISION: Immutable state with event sourcing * WHY: Enables state recovery, audit trail, debugging * * REASONING CHAIN: * 1. State stored as transitions history (event sourcing) * 2. Current state derived from latest transition * 3. All state changes recorded (audit trail) * 4. Can replay history for debugging * 5. Result: Recoverable, auditable workflow state */ class WorkflowStateMachine { constructor(tasksTotal) { this.tasksCompleted = 0; this.activeAgents = 0; this.state = WorkflowState.NOT_STARTED; this.transitions = []; this.tasksTotal = tasksTotal; } /** * Get current state */ getState() { return this.state; } /** * Get state transition history */ getTransitions() { return [...this.transitions]; } /** * Get workflow snapshot */ getSnapshot() { return { state: this.state, transitions: [...this.transitions], tasksCompleted: this.tasksCompleted, tasksRemaining: this.tasksTotal - this.tasksCompleted, activeAgents: this.activeAgents, lastUpdated: new Date().toISOString(), }; } /** * Check if transition is valid */ isValidTransition(to) { const validTransitions = WorkflowStateMachine.VALID_TRANSITIONS.get(this.state); return validTransitions ? validTransitions.includes(to) : false; } /** * Transition to new state * * @param to - Target state * @param reason - Reason for transition (optional) * @param user - User who triggered transition (optional) * @throws Error if transition is invalid */ transition(to, reason, user) { if (!this.isValidTransition(to)) { throw new Error(`Invalid state transition: ${this.state} → ${to}. ` + `Valid transitions from ${this.state}: ` + `[${WorkflowStateMachine.VALID_TRANSITIONS.get(this.state)?.join(', ') || 'none'}]`); } const transition = { from: this.state, to, timestamp: new Date().toISOString(), reason, user, }; this.transitions.push(transition); this.state = to; } /** * Start sprint */ start(reason) { this.transition(WorkflowState.IN_PROGRESS, reason || 'Sprint started'); } /** * Pause sprint */ pause(reason, user) { this.transition(WorkflowState.PAUSED, reason || 'Sprint paused', user); } /** * Resume sprint */ resume(reason, user) { this.transition(WorkflowState.IN_PROGRESS, reason || 'Sprint resumed', user); } /** * Complete sprint */ complete(reason) { this.transition(WorkflowState.COMPLETE, reason || 'Sprint completed successfully'); } /** * Fail sprint */ fail(reason, user) { this.transition(WorkflowState.FAILED, reason, user); } /** * Update task progress * * DESIGN DECISION: Auto-transition to COMPLETE when all tasks done * WHY: Automatic workflow progression, reduces manual steps */ updateTaskProgress(tasksCompleted, activeAgents) { this.tasksCompleted = tasksCompleted; this.activeAgents = activeAgents; // Auto-complete if all tasks done if (this.state === WorkflowState.IN_PROGRESS && this.tasksCompleted === this.tasksTotal && this.activeAgents === 0) { this.complete(`All tasks completed (${this.tasksCompleted}/${this.tasksTotal})`); } } /** * Check if workflow is terminal (cannot transition further) */ isTerminal() { return this.state === WorkflowState.COMPLETE || this.state === WorkflowState.FAILED; } /** * Check if workflow is active (can accept task updates) */ isActive() { return this.state === WorkflowState.IN_PROGRESS || this.state === WorkflowState.PAUSED; } /** * Serialize to JSON */ toJSON() { return { state: this.state, transitions: this.transitions, tasksCompleted: this.tasksCompleted, tasksTotal: this.tasksTotal, activeAgents: this.activeAgents, }; } /** * Deserialize from JSON * * DESIGN DECISION: Replay transitions to reconstruct state * WHY: Enables state recovery from disk, consistent with event sourcing */ static fromJSON(json) { const machine = new WorkflowStateMachine(json.tasksTotal); // Replay transitions for (const transition of json.transitions) { machine.state = transition.from; machine.transition(transition.to, transition.reason, transition.user); } machine.tasksCompleted = json.tasksCompleted; machine.activeAgents = json.activeAgents; return machine; } } exports.WorkflowStateMachine = WorkflowStateMachine; /** * Valid state transitions * * DESIGN DECISION: Whitelist approach for transitions * WHY: Prevents invalid state changes, explicit validation */ WorkflowStateMachine.VALID_TRANSITIONS = new Map([ [WorkflowState.NOT_STARTED, [WorkflowState.IN_PROGRESS, WorkflowState.FAILED]], [WorkflowState.IN_PROGRESS, [WorkflowState.PAUSED, WorkflowState.COMPLETE, WorkflowState.FAILED]], [WorkflowState.PAUSED, [WorkflowState.IN_PROGRESS, WorkflowState.FAILED]], [WorkflowState.COMPLETE, []], // Terminal state [WorkflowState.FAILED, []], // Terminal state ]); //# sourceMappingURL=state_machine.js.map