@maestroai/core 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,1007 @@
1
+ import EventEmitter, { EventEmitter as EventEmitter$1 } from 'eventemitter3';
2
+ import pino from 'pino';
3
+
4
+ type AgentRole = 'orchestrator' | 'project-manager' | 'architect' | 'developer' | 'designer' | 'qa-engineer' | 'devops' | 'technical-writer' | 'code-reviewer';
5
+ type AgentStatus = 'idle' | 'starting' | 'running' | 'stopping' | 'stopped' | 'error';
6
+ interface AgentConfig {
7
+ id: string;
8
+ role: AgentRole;
9
+ name: string;
10
+ model?: string;
11
+ systemPrompt: string;
12
+ allowedTools?: string[];
13
+ maxBudgetUsd?: number;
14
+ workingDirectory: string;
15
+ permissionMode: 'default' | 'acceptEdits' | 'bypassPermissions';
16
+ /** Path to the claude CLI binary (default: "claude") */
17
+ claudeCommand?: string;
18
+ /** Extra CLI args appended to every invocation */
19
+ claudeArgs?: string[];
20
+ /** Extra environment variables merged into the subprocess env */
21
+ claudeEnv?: Record<string, string>;
22
+ /** Max agentic turns per invocation (maps to --max-turns) */
23
+ maxTurns?: number;
24
+ }
25
+ interface AgentState {
26
+ config: AgentConfig;
27
+ status: AgentStatus;
28
+ pid: number | null;
29
+ sessionId: string | null;
30
+ currentTask: string | null;
31
+ startedAt: string | null;
32
+ lastActivityAt: string | null;
33
+ totalCostUsd: number;
34
+ turnCount: number;
35
+ totalInputTokens: number;
36
+ totalOutputTokens: number;
37
+ totalCacheReadTokens: number;
38
+ totalCacheCreationTokens: number;
39
+ error: string | null;
40
+ /** Set when the agent result has is_error: true (e.g. rate limit) */
41
+ resultError: string | null;
42
+ /** True when the agent hit an API rate limit (429) */
43
+ rateLimited: boolean;
44
+ /** Human-readable rate limit reset time from the API response */
45
+ rateLimitResetAt: string | null;
46
+ }
47
+ interface AgentStreamEvent {
48
+ type: 'system' | 'user' | 'assistant' | 'tool_use' | 'tool_result' | 'result' | 'error';
49
+ agentId: string;
50
+ timestamp: string;
51
+ data: Record<string, unknown>;
52
+ }
53
+
54
+ type TaskStatus = 'pending' | 'in-progress' | 'done' | 'blocked' | 'cancelled';
55
+ type TaskPriority = 'critical' | 'high' | 'medium' | 'low';
56
+ interface Task {
57
+ id: string;
58
+ title: string;
59
+ description: string;
60
+ status: TaskStatus;
61
+ priority: TaskPriority;
62
+ assignee: string | null;
63
+ dependencies: string[];
64
+ tags: string[];
65
+ createdAt: string;
66
+ updatedAt: string;
67
+ completedAt: string | null;
68
+ notes: string[];
69
+ }
70
+ interface TaskFilter {
71
+ status?: TaskStatus[];
72
+ assignee?: string | null;
73
+ priority?: TaskPriority[];
74
+ tags?: string[];
75
+ }
76
+ interface TaskUpdate {
77
+ status?: TaskStatus;
78
+ assignee?: string | null;
79
+ priority?: TaskPriority;
80
+ notes?: string[];
81
+ }
82
+
83
+ type MessageType = 'task-assignment' | 'task-update' | 'task-complete' | 'task-blocked' | 'question' | 'answer' | 'review-request' | 'review-result' | 'system' | 'directive';
84
+ interface Message {
85
+ id: string;
86
+ type: MessageType;
87
+ from: string;
88
+ to: string;
89
+ subject: string;
90
+ body: string;
91
+ replyTo?: string;
92
+ taskId?: string;
93
+ priority: 'normal' | 'urgent';
94
+ timestamp: string;
95
+ metadata?: Record<string, unknown>;
96
+ }
97
+ interface MessageEnvelope {
98
+ message: Message;
99
+ deliveredAt: string | null;
100
+ readAt: string | null;
101
+ status: 'pending' | 'delivered' | 'read' | 'processed';
102
+ }
103
+
104
+ type InteractionMode = 'unattended' | 'supervised' | 'interactive';
105
+ interface PlanProposal {
106
+ id: string;
107
+ tasks: PlannedTaskSummary[];
108
+ totalEstimatedTasks: number;
109
+ projectGoal: string;
110
+ createdAt: string;
111
+ status: 'pending' | 'approved' | 'rejected' | 'modified';
112
+ }
113
+ interface PlannedTaskSummary {
114
+ title: string;
115
+ description: string;
116
+ priority: string;
117
+ assignedRole: string;
118
+ tags: string[];
119
+ }
120
+ interface UserQuestion {
121
+ id: string;
122
+ fromAgent: string;
123
+ taskId?: string;
124
+ question: string;
125
+ context?: string;
126
+ options?: string[];
127
+ createdAt: string;
128
+ status: 'pending' | 'answered' | 'timed-out';
129
+ answer?: string;
130
+ }
131
+ interface ProgressReport {
132
+ id: string;
133
+ phase: string;
134
+ completedTasks: number;
135
+ totalTasks: number;
136
+ percentComplete: number;
137
+ recentCompletions: string[];
138
+ upcomingWork: string[];
139
+ blockers: string[];
140
+ totalCostUsd: number;
141
+ createdAt: string;
142
+ }
143
+ interface MilestoneEvent {
144
+ id: string;
145
+ name: string;
146
+ percentComplete: number;
147
+ message: string;
148
+ requiresAck: boolean;
149
+ createdAt: string;
150
+ }
151
+ interface FeedbackSettings {
152
+ interactionMode: InteractionMode;
153
+ progressReportIntervalMs: number;
154
+ milestonePercentages: number[];
155
+ questionTimeoutMs: number;
156
+ requirePlanApproval: boolean;
157
+ }
158
+
159
+ interface TechStackConfig {
160
+ frontend?: string;
161
+ uiLibrary?: string;
162
+ backend?: string;
163
+ database?: string;
164
+ other?: string;
165
+ }
166
+ interface ProjectConfig {
167
+ name: string;
168
+ description: string;
169
+ version: string;
170
+ agents: AgentRoleConfig[];
171
+ settings: ProjectSettings;
172
+ techStack?: TechStackConfig;
173
+ }
174
+ interface ProjectSettings {
175
+ workingDirectory: string;
176
+ todoFile: string;
177
+ messagesDirectory: string;
178
+ logsDirectory: string;
179
+ defaultModel: string;
180
+ maxConcurrentAgents: number;
181
+ pollIntervalMs: number;
182
+ maxTotalBudgetUsd?: number;
183
+ feedback?: FeedbackSettings;
184
+ /** Path to the claude CLI binary (default: "claude") */
185
+ claudeCommand?: string;
186
+ /** Extra CLI args passed to every agent invocation */
187
+ claudeArgs?: string[];
188
+ /** Extra environment variables passed to every agent invocation */
189
+ claudeEnv?: Record<string, string>;
190
+ }
191
+ interface AgentRoleConfig {
192
+ role: AgentRole;
193
+ count: number;
194
+ model?: string;
195
+ systemPromptFile?: string;
196
+ systemPromptOverride?: string;
197
+ allowedTools?: string[];
198
+ maxBudgetUsd?: number;
199
+ permissionMode?: 'default' | 'acceptEdits' | 'bypassPermissions';
200
+ /** Extra CLI args for this agent (merged with settings.claudeArgs) */
201
+ claudeArgs?: string[];
202
+ /** Extra environment variables for this agent (merged with settings.claudeEnv) */
203
+ claudeEnv?: Record<string, string>;
204
+ /** Max agentic turns per invocation (maps to --max-turns) */
205
+ maxTurns?: number;
206
+ }
207
+
208
+ /**
209
+ * Orchestrator activity log types.
210
+ *
211
+ * These represent structured events that the orchestrator emits so that
212
+ * a persistent "Orchestrator" panel in the TUI can display what's happening
213
+ * at a high level: task delegations, status updates, phase transitions,
214
+ * agent hand-offs, and pipeline progress.
215
+ */
216
+ type OrchestratorActivityKind = 'task-delegated' | 'task-completed' | 'task-blocked' | 'task-failed' | 'agent-spawned' | 'agent-stopped' | 'agent-error' | 'phase-changed' | 'pipeline-handoff' | 'plan-created' | 'plan-approved' | 'plan-rejected' | 'budget-warning' | 'rate-limit' | 'project-completed' | 'cycle-summary' | 'gap-detected' | 'pm-scan' | 'info';
217
+ interface OrchestratorActivity {
218
+ id: string;
219
+ kind: OrchestratorActivityKind;
220
+ timestamp: string;
221
+ message: string;
222
+ details?: {
223
+ taskId?: string;
224
+ taskTitle?: string;
225
+ agentId?: string;
226
+ agentRole?: string;
227
+ fromPhase?: string;
228
+ toPhase?: string;
229
+ pipelineStage?: string;
230
+ cost?: number;
231
+ [key: string]: unknown;
232
+ };
233
+ }
234
+ /**
235
+ * Task pipeline stages — each task flows through a defined sequence of
236
+ * stages with role-based handoffs between agents.
237
+ */
238
+ type PipelineStage = 'plan' | 'develop' | 'qa' | 'review';
239
+ declare const PIPELINE_STAGE_ORDER: PipelineStage[];
240
+ /**
241
+ * Maps pipeline stages to the agent roles responsible for executing them.
242
+ */
243
+ declare const PIPELINE_STAGE_ROLES: Record<PipelineStage, string[]>;
244
+ interface TaskPipelineState {
245
+ taskId: string;
246
+ currentStage: PipelineStage;
247
+ stageHistory: {
248
+ stage: PipelineStage;
249
+ agentId: string;
250
+ startedAt: string;
251
+ completedAt: string | null;
252
+ status: 'in-progress' | 'completed' | 'failed';
253
+ }[];
254
+ createdAt: string;
255
+ }
256
+
257
+ interface AgentInfo {
258
+ id: string;
259
+ name: string;
260
+ role: string;
261
+ status: AgentStatus;
262
+ spawned: boolean;
263
+ currentTask: string | null;
264
+ }
265
+ interface OrchestratorStats {
266
+ totalTasks: number;
267
+ completedTasks: number;
268
+ activeAgents: number;
269
+ totalCostUsd: number;
270
+ totalInputTokens: number;
271
+ totalOutputTokens: number;
272
+ totalCacheReadTokens: number;
273
+ totalCacheCreationTokens: number;
274
+ uptimeMs: number;
275
+ agents: AgentInfo[];
276
+ }
277
+ interface ProjectCompletionSummary {
278
+ totalTasks: number;
279
+ doneTasks: number;
280
+ cancelledTasks: number;
281
+ totalCostUsd: number;
282
+ totalInputTokens: number;
283
+ totalOutputTokens: number;
284
+ totalCacheReadTokens: number;
285
+ totalCacheCreationTokens: number;
286
+ uptimeMs: number;
287
+ agentSummaries: {
288
+ agentId: string;
289
+ name: string;
290
+ role: string;
291
+ tasksCompleted: number;
292
+ costUsd: number;
293
+ inputTokens: number;
294
+ outputTokens: number;
295
+ }[];
296
+ completedAt: string;
297
+ }
298
+ interface MaestroEvents {
299
+ 'agent:spawned': (state: AgentState) => void;
300
+ 'agent:status-changed': (agentId: string, oldStatus: AgentStatus, newStatus: AgentStatus) => void;
301
+ 'agent:output': (event: AgentStreamEvent) => void;
302
+ 'agent:error': (agentId: string, error: Error) => void;
303
+ 'agent:stopped': (agentId: string, exitCode: number | null) => void;
304
+ 'task:created': (task: Task) => void;
305
+ 'task:updated': (task: Task, changes: TaskUpdate) => void;
306
+ 'task:assigned': (task: Task, agentId: string) => void;
307
+ 'task:completed': (task: Task) => void;
308
+ 'tasks:loaded': (tasks: Task[]) => void;
309
+ 'message:sent': (message: Message) => void;
310
+ 'message:received': (message: Message) => void;
311
+ 'orchestrator:cycle': (stats: OrchestratorStats) => void;
312
+ 'project:completed': (summary: ProjectCompletionSummary) => void;
313
+ 'budget:warning': (currentUsd: number, maxUsd: number) => void;
314
+ 'budget:exceeded': (currentUsd: number, maxUsd: number) => void;
315
+ 'rate-limit': (agentId: string, resetAt: string | null) => void;
316
+ 'architecture:ready': (archTasks: Task[]) => void;
317
+ 'phase:changed': (phase: string) => void;
318
+ 'plan:proposed': (proposal: PlanProposal) => void;
319
+ 'plan:decided': (proposalId: string, decision: 'approved' | 'rejected', modifications?: string) => void;
320
+ 'question:asked': (question: UserQuestion) => void;
321
+ 'question:answered': (questionId: string, answer: string) => void;
322
+ 'progress:report': (report: ProgressReport) => void;
323
+ 'milestone:reached': (milestone: MilestoneEvent) => void;
324
+ 'milestone:acknowledged': (milestoneId: string) => void;
325
+ 'interaction-mode:changed': (mode: InteractionMode) => void;
326
+ 'orchestrator:paused': () => void;
327
+ 'orchestrator:resumed': () => void;
328
+ 'instructions:decomposing': (instructions: string) => void;
329
+ 'instructions:added': (tasks: Task[]) => void;
330
+ 'orchestrator:activity': (activity: OrchestratorActivity) => void;
331
+ }
332
+
333
+ declare class TaskParser {
334
+ parse(content: string): {
335
+ projectName: string;
336
+ tasks: Task[];
337
+ };
338
+ parseLine(line: string, currentPriority: TaskPriority): Task | null;
339
+ }
340
+
341
+ declare class TaskWriter {
342
+ write(projectName: string, tasks: Task[]): string;
343
+ formatTask(task: Task): string;
344
+ }
345
+
346
+ interface TaskManagerOptions {
347
+ filePath: string;
348
+ projectName: string;
349
+ }
350
+ declare class TaskManager extends EventEmitter {
351
+ private readonly filePath;
352
+ private readonly projectName;
353
+ private readonly parser;
354
+ private readonly writer;
355
+ constructor(options: TaskManagerOptions);
356
+ private ensureFile;
357
+ load(): Promise<Task[]>;
358
+ save(tasks: Task[]): Promise<void>;
359
+ getTask(id: string): Promise<Task | undefined>;
360
+ getTasks(filter?: TaskFilter): Promise<Task[]>;
361
+ createTask(data: {
362
+ title: string;
363
+ priority: TaskPriority;
364
+ description?: string;
365
+ dependencies?: string[];
366
+ tags?: string[];
367
+ }): Promise<Task>;
368
+ updateTask(id: string, update: TaskUpdate): Promise<Task>;
369
+ assignTask(id: string, agentId: string): Promise<Task>;
370
+ completeTask(id: string): Promise<Task>;
371
+ private extractMaxTaskNumber;
372
+ }
373
+
374
+ interface AgentProcessEvents {
375
+ 'output': (event: AgentStreamEvent) => void;
376
+ 'status-changed': (oldStatus: AgentStatus, newStatus: AgentStatus) => void;
377
+ 'error': (error: Error) => void;
378
+ 'stopped': (exitCode: number | null) => void;
379
+ }
380
+ declare class AgentProcess extends EventEmitter$1<AgentProcessEvents> {
381
+ private readonly config;
382
+ private subprocess;
383
+ private state;
384
+ private streamBuffer;
385
+ constructor(config: AgentConfig);
386
+ get id(): string;
387
+ get currentState(): AgentState;
388
+ /**
389
+ * Set the current task this agent is working on (task ID + title).
390
+ */
391
+ setCurrentTask(taskInfo: string | null): void;
392
+ /**
393
+ * Spawn a claude CLI process with the given prompt.
394
+ */
395
+ spawn(prompt: string): Promise<void>;
396
+ /**
397
+ * Resume a previous session with a new prompt.
398
+ */
399
+ resume(prompt: string): Promise<void>;
400
+ /**
401
+ * Graceful stop: SIGTERM, wait, then force kill.
402
+ */
403
+ stop(timeoutMs?: number): Promise<void>;
404
+ /**
405
+ * Force kill immediately.
406
+ */
407
+ kill(): Promise<void>;
408
+ /**
409
+ * Build CLI arguments for the claude command.
410
+ * The prompt is piped via stdin, not passed as a positional argument.
411
+ */
412
+ private buildArgs;
413
+ /**
414
+ * Parse NDJSON stream from claude stdout.
415
+ * Reads stdout line by line and emits typed events.
416
+ */
417
+ private processStream;
418
+ /**
419
+ * Read stderr and emit lines as error events so they're visible.
420
+ */
421
+ private processStderr;
422
+ /**
423
+ * Emit a synthetic output event.
424
+ */
425
+ private emitOutput;
426
+ /**
427
+ * Update internal state and emit status change events.
428
+ */
429
+ private setStatus;
430
+ }
431
+
432
+ interface AgentPoolEvents {
433
+ 'agent:spawned': (agentId: string, process: AgentProcess) => void;
434
+ 'agent:output': (event: AgentStreamEvent) => void;
435
+ 'agent:status-changed': (agentId: string, oldStatus: AgentStatus, newStatus: AgentStatus) => void;
436
+ 'agent:error': (agentId: string, error: Error) => void;
437
+ 'agent:stopped': (agentId: string, exitCode: number | null) => void;
438
+ }
439
+ declare class AgentPool extends EventEmitter$1<AgentPoolEvents> {
440
+ private agents;
441
+ /**
442
+ * Spawn a new agent process with the given config and initial prompt.
443
+ */
444
+ spawnAgent(config: AgentConfig, prompt: string): Promise<AgentProcess>;
445
+ /**
446
+ * Stop a specific agent by ID with an optional timeout.
447
+ */
448
+ stopAgent(id: string, timeoutMs?: number): Promise<void>;
449
+ /**
450
+ * Stop all agents concurrently. Uses Promise.allSettled for graceful handling.
451
+ */
452
+ stopAll(timeoutMs?: number): Promise<void>;
453
+ /**
454
+ * Remove a stopped agent from the pool so it can be re-spawned.
455
+ */
456
+ removeAgent(id: string): void;
457
+ /**
458
+ * Get an agent process by ID.
459
+ */
460
+ getAgent(id: string): AgentProcess | undefined;
461
+ /**
462
+ * Get all agents with a specific role.
463
+ */
464
+ getAgentsByRole(role: AgentRole): AgentProcess[];
465
+ /**
466
+ * Get all agents with a specific status.
467
+ */
468
+ getAgentsByStatus(status: AgentStatus): AgentProcess[];
469
+ /**
470
+ * Get all agents in the pool.
471
+ */
472
+ getAllAgents(): AgentProcess[];
473
+ /**
474
+ * Get aggregate statistics across all agents.
475
+ */
476
+ getStats(): {
477
+ total: number;
478
+ running: number;
479
+ idle: number;
480
+ stopped: number;
481
+ totalCostUsd: number;
482
+ };
483
+ /**
484
+ * Attach event forwarding listeners from an agent process to the pool.
485
+ */
486
+ private attachListeners;
487
+ }
488
+
489
+ declare const ROLE_DESCRIPTIONS: Record<AgentRole, string>;
490
+ interface SystemPromptParams {
491
+ role: AgentRole;
492
+ agentId: string;
493
+ projectName: string;
494
+ todoFilePath: string;
495
+ inboxPath: string;
496
+ outboxPath: string;
497
+ workingDirectory: string;
498
+ techStack?: TechStackConfig;
499
+ }
500
+ declare function getDefaultSystemPrompt(params: SystemPromptParams): string;
501
+
502
+ /**
503
+ * Load and generate AgentConfig[] from a ProjectConfig.
504
+ *
505
+ * For each role config:
506
+ * - If count > 1, generates multiple configs with IDs like "developer-1", "developer-2"
507
+ * - If count === 1, uses the role as the ID (e.g., "orchestrator")
508
+ * - Loads system prompts from systemPromptFile if specified, otherwise uses getDefaultSystemPrompt
509
+ */
510
+ declare function loadAgentConfigs(projectConfig: ProjectConfig): AgentConfig[];
511
+
512
+ declare class MessageBroker extends EventEmitter$1 {
513
+ private baseDir;
514
+ private watchers;
515
+ private registeredAgents;
516
+ constructor(baseDir: string);
517
+ /**
518
+ * Initialize directory structure for an agent.
519
+ * Creates inbox/, outbox/, and processed/ directories.
520
+ */
521
+ registerAgent(agentId: string): Promise<void>;
522
+ /**
523
+ * Initialize directories for all agents and start watching.
524
+ * Watches each agent's outbox directory so that messages agents write
525
+ * there are automatically picked up and routed.
526
+ */
527
+ start(agentIds: string[]): Promise<void>;
528
+ /**
529
+ * Send a message to an agent's inbox.
530
+ * If message.to is "*", broadcasts to all registered agents instead.
531
+ */
532
+ sendMessage(message: Message): Promise<void>;
533
+ /**
534
+ * Send a message to all registered agents' inboxes.
535
+ */
536
+ broadcast(message: Message): Promise<void>;
537
+ /**
538
+ * Mark an inbox message as processed and move it to the processed directory.
539
+ * Called when a task completes so the inbox reflects the current state.
540
+ */
541
+ markInboxProcessed(agentId: string, taskId: string): Promise<void>;
542
+ /**
543
+ * Clean up stale inbox messages for a task (e.g., after restart when
544
+ * in-progress tasks are reset). Moves matching messages to processed/.
545
+ */
546
+ cleanInboxForTask(agentId: string, taskId: string): Promise<void>;
547
+ /**
548
+ * Read processed messages for a specific task across all agents.
549
+ * Used to display task completion details in the TUI.
550
+ */
551
+ getProcessedMessagesForTask(taskId: string): Promise<MessageEnvelope[]>;
552
+ /**
553
+ * Move ALL inbox messages to processed/ for every agent directory.
554
+ * Called on startup to ensure a clean slate — agents should not pick up
555
+ * stale task-assignment messages from a previous session.
556
+ */
557
+ cleanAllInboxes(): Promise<void>;
558
+ get messagesBaseDir(): string;
559
+ /**
560
+ * Stop all watchers and clean up.
561
+ */
562
+ stop(): Promise<void>;
563
+ }
564
+
565
+ declare class InboxWatcher extends EventEmitter$1 {
566
+ private watcher;
567
+ private dir;
568
+ private processedDir;
569
+ constructor(inboxDir: string, processedDir: string);
570
+ start(): Promise<void>;
571
+ stop(): Promise<void>;
572
+ private processFile;
573
+ }
574
+
575
+ declare class Orchestrator extends EventEmitter$1 {
576
+ private config;
577
+ private running;
578
+ private paused;
579
+ private intervalId;
580
+ private startedAt;
581
+ private broker;
582
+ private scheduler;
583
+ private planner;
584
+ private pipeline;
585
+ private pmScanner;
586
+ private taskManager;
587
+ private agentPool;
588
+ private agentConfigs;
589
+ private cachedTasks;
590
+ private feedbackLoop;
591
+ private planApprovalPending;
592
+ private phase;
593
+ private architectureApprovalPending;
594
+ constructor(config: ProjectConfig);
595
+ get isActive(): boolean;
596
+ get isPaused(): boolean;
597
+ /**
598
+ * Emit a structured orchestrator activity event.
599
+ * These feed the persistent "Orchestrator" panel in the TUI.
600
+ */
601
+ private emitActivity;
602
+ /**
603
+ * Start the orchestrator:
604
+ * 1. Ensure workspace directories exist
605
+ * 2. Initialize TaskManager, AgentPool, MessageBroker, Scheduler, Planner
606
+ * 3. Load agent configs and register them with the broker
607
+ * 4. If no tasks exist, use Planner to decompose the project description
608
+ * 5. Start the polling loop
609
+ */
610
+ start(): Promise<void>;
611
+ /**
612
+ * Stop the orchestrator gracefully.
613
+ */
614
+ stop(): Promise<void>;
615
+ /**
616
+ * Pause the orchestrator: stop the polling cycle and all running agents.
617
+ * Tasks and state are preserved so work can be resumed later.
618
+ */
619
+ pause(): Promise<void>;
620
+ /**
621
+ * Resume the orchestrator after a pause. Restarts the polling cycle
622
+ * and PM scanner so agents can be re-assigned to pending tasks.
623
+ */
624
+ resume(): Promise<void>;
625
+ /**
626
+ * Add new instructions: decompose them into tasks and append to the
627
+ * existing todo.md without deleting any existing tasks.
628
+ */
629
+ addInstructions(instructions: string): Promise<Task[]>;
630
+ /**
631
+ * A single orchestration cycle:
632
+ * 1. Load current tasks
633
+ * 2. Run scheduler to determine assignments
634
+ * 3. For each assignment: update task, send message, spawn agent
635
+ * 4. Handle pipeline handoffs for completed tasks
636
+ * 5. Check budget limits
637
+ * 6. Emit cycle stats
638
+ */
639
+ private cycle;
640
+ /**
641
+ * Run a single PM scan pass — assess project health, identify gaps and
642
+ * blockers, and surface findings in the orchestrator activity log.
643
+ */
644
+ private runPMScan;
645
+ /**
646
+ * Build a task prompt for an agent.
647
+ */
648
+ private buildTaskPrompt;
649
+ /**
650
+ * Check whether the total cost across all agents exceeds the budget.
651
+ */
652
+ private checkBudget;
653
+ /**
654
+ * Get all current tasks.
655
+ */
656
+ getTasks(): Promise<Task[]>;
657
+ /**
658
+ * Get all agent states.
659
+ */
660
+ getAgentStates(): any[];
661
+ /**
662
+ * Get the pipeline state for a specific task.
663
+ */
664
+ getTaskPipelineState(taskId: string): TaskPipelineState | undefined;
665
+ /**
666
+ * Get current orchestrator statistics.
667
+ */
668
+ getStats(): OrchestratorStats;
669
+ /**
670
+ * Format a token count for display (e.g. 1234567 → "1.23M", 45678 → "45.7k").
671
+ */
672
+ private formatTokenCount;
673
+ /**
674
+ * Build a summary of the completed project for reporting.
675
+ */
676
+ private buildCompletionSummary;
677
+ /**
678
+ * Approve the architecture and advance to development phase.
679
+ */
680
+ approveArchitecture(): void;
681
+ /**
682
+ * Get the current orchestration phase.
683
+ */
684
+ getPhase(): string;
685
+ decidePlan(proposalId: string, decision: 'approved' | 'rejected', modifications?: string): void;
686
+ answerQuestion(questionId: string, answer: string): void;
687
+ acknowledgeMilestone(milestoneId: string): void;
688
+ setInteractionMode(mode: InteractionMode): void;
689
+ getInteractionMode(): InteractionMode;
690
+ getPendingPlan(): PlanProposal | null;
691
+ getPendingQuestions(): UserQuestion[];
692
+ /**
693
+ * Get processed messages for a specific task (for task detail view).
694
+ */
695
+ getTaskMessages(taskId: string): Promise<MessageEnvelope[]>;
696
+ }
697
+
698
+ interface PlannedTask {
699
+ title: string;
700
+ priority: TaskPriority;
701
+ description: string;
702
+ dependencies: string[];
703
+ tags: string[];
704
+ }
705
+ declare class Planner {
706
+ private model;
707
+ private workingDirectory;
708
+ private claudeCommand;
709
+ private claudeEnv?;
710
+ private techStack?;
711
+ constructor(opts: {
712
+ model?: string;
713
+ workingDirectory: string;
714
+ claudeCommand?: string;
715
+ claudeEnv?: Record<string, string>;
716
+ techStack?: TechStackConfig;
717
+ });
718
+ /**
719
+ * Use Claude CLI to decompose a goal into a list of planned tasks.
720
+ */
721
+ decompose(goal: string): Promise<PlannedTask[]>;
722
+ /**
723
+ * Scan a directory recursively and return an indented tree listing.
724
+ */
725
+ private scanDirectory;
726
+ private parseResponse;
727
+ }
728
+
729
+ /**
730
+ * TaskPipeline manages the lifecycle of tasks through a multi-stage pipeline:
731
+ * plan -> develop -> qa -> review
732
+ *
733
+ * Each stage maps to one or more agent roles. When a stage completes, the
734
+ * pipeline advances the task to the next stage and returns handoff information
735
+ * so the orchestrator can delegate to the appropriate agent.
736
+ */
737
+ declare class TaskPipeline {
738
+ private pipelines;
739
+ /**
740
+ * Register a task in the pipeline at a given starting stage.
741
+ * Tasks tagged with 'architecture' or 'planning' start at 'plan'.
742
+ * Tasks tagged with 'testing' or 'qa' start at 'qa'.
743
+ * All others start at 'develop' (they'll skip the plan stage
744
+ * if they were already created from the planner).
745
+ */
746
+ initTask(task: Task, startStage?: PipelineStage): TaskPipelineState;
747
+ /**
748
+ * Get the pipeline state for a task.
749
+ */
750
+ getState(taskId: string): TaskPipelineState | undefined;
751
+ /**
752
+ * Record that an agent has started working on the current stage.
753
+ */
754
+ startStage(taskId: string, agentId: string): void;
755
+ /**
756
+ * Complete the current stage and return the next stage (if any).
757
+ * Returns null if the pipeline is finished.
758
+ */
759
+ completeStage(taskId: string): {
760
+ nextStage: PipelineStage | null;
761
+ requiredRoles: string[];
762
+ handoffMessage: string;
763
+ } | null;
764
+ /**
765
+ * Mark a stage as failed.
766
+ */
767
+ failStage(taskId: string): void;
768
+ /**
769
+ * Get the role(s) needed for the current pipeline stage of a task.
770
+ */
771
+ getRequiredRoles(taskId: string): AgentRole[];
772
+ /**
773
+ * Check if a task has a pipeline registered.
774
+ */
775
+ has(taskId: string): boolean;
776
+ /**
777
+ * Infer the starting pipeline stage from task tags.
778
+ */
779
+ private inferStartStage;
780
+ }
781
+
782
+ interface TaskAssignment {
783
+ taskId: string;
784
+ agentId: string;
785
+ }
786
+ declare class Scheduler {
787
+ /** Optional pipeline reference for pipeline-aware scheduling. */
788
+ private pipeline;
789
+ /**
790
+ * Set a pipeline reference so the scheduler can use pipeline stage
791
+ * information when determining which role should handle a task.
792
+ */
793
+ setPipeline(pipeline: TaskPipeline): void;
794
+ /**
795
+ * Determine which pending tasks should be assigned to which idle agents.
796
+ *
797
+ * Rules:
798
+ * 1. Only consider tasks whose status is 'pending' and whose dependencies are all 'done'.
799
+ * 2. Only consider agents whose status is 'idle'.
800
+ * 3. Match tasks to agents by role:
801
+ * - If a task has a pipeline state, use the pipeline stage to determine role
802
+ * - Otherwise, fall back to tag-based role determination
803
+ * 4. Assign higher-priority tasks first.
804
+ * 5. Each agent receives at most one assignment per scheduling cycle.
805
+ */
806
+ schedule(tasks: Task[], agents: AgentState[]): TaskAssignment[];
807
+ /**
808
+ * Determine the best role for a task.
809
+ *
810
+ * If the task has an active pipeline state, the pipeline stage takes
811
+ * priority over tag-based role determination. This enables the
812
+ * plan -> develop -> qa -> review handoff sequence.
813
+ *
814
+ * Falls back to tag-based determination, then defaults to 'developer'.
815
+ */
816
+ private determineRole;
817
+ }
818
+
819
+ /**
820
+ * Findings from a PM scan cycle — these are deterministic assessments
821
+ * that the orchestrator can act on or surface in the activity log.
822
+ */
823
+ interface PMScanResult {
824
+ timestamp: string;
825
+ findings: PMFinding[];
826
+ summary: string;
827
+ }
828
+ type PMFindingKind = 'blocked-task' | 'stale-task' | 'unassigned-ready-task' | 'agent-idle' | 'agent-errored' | 'dependency-bottleneck' | 'high-priority-waiting' | 'progress-stalled' | 'all-clear';
829
+ interface PMFinding {
830
+ kind: PMFindingKind;
831
+ severity: 'info' | 'warning' | 'critical';
832
+ message: string;
833
+ taskId?: string;
834
+ agentId?: string;
835
+ }
836
+ /**
837
+ * ProjectManagerScanner runs a periodic assessment loop that inspects the
838
+ * current task board and agent pool, identifies gaps, blockers, stalled
839
+ * progress, and idle resources, then reports findings via the orchestrator's
840
+ * activity log and (optionally) sends messages to the relevant agents.
841
+ *
842
+ * This is NOT an LLM call — it's deterministic analysis. It runs the PM
843
+ * role at the *orchestration layer* rather than spawning a Claude subprocess.
844
+ * For deeper analysis that requires reasoning (e.g., "is this architecture
845
+ * design good?"), a real PM agent is spawned via the pipeline's `review` stage.
846
+ */
847
+ declare class ProjectManagerScanner {
848
+ private intervalId;
849
+ private scanIntervalMs;
850
+ private lastScanTasks;
851
+ private cycleCount;
852
+ /** Track tasks that have already received a PM message to avoid duplicates. */
853
+ private messagedTasks;
854
+ constructor(scanIntervalMs?: number);
855
+ /**
856
+ * Start the periodic scan loop.
857
+ * @param scanFn — called each interval; the orchestrator provides context.
858
+ */
859
+ start(scanFn: () => void): void;
860
+ stop(): void;
861
+ /**
862
+ * Run a single scan pass.
863
+ *
864
+ * @param tasks - Current task list
865
+ * @param agents - Current agent states (from pool + virtual)
866
+ * @param phase - Current orchestrator phase
867
+ */
868
+ scan(tasks: Task[], agents: AgentState[], phase: string): PMScanResult;
869
+ /**
870
+ * Build messages from PM findings that should be sent to agents.
871
+ * Only produces messages for actionable findings.
872
+ * Tracks which tasks have already been messaged to avoid flooding inboxes.
873
+ */
874
+ buildMessages(result: PMScanResult): Message[];
875
+ /**
876
+ * Clear tracked messages for a task (e.g., when it moves from in-progress
877
+ * back to pending, allowing a new message if it stalls again later).
878
+ */
879
+ clearTrackedTask(taskId: string): void;
880
+ }
881
+
882
+ declare class FeedbackLoop extends EventEmitter$1 {
883
+ private mode;
884
+ private settings;
885
+ private pendingPlan;
886
+ private planResolver;
887
+ private pendingQuestions;
888
+ private lastProgressReport;
889
+ private progressTracker;
890
+ private reachedMilestones;
891
+ private pendingMilestone;
892
+ constructor(settings?: Partial<FeedbackSettings>);
893
+ get interactionMode(): InteractionMode;
894
+ setMode(mode: InteractionMode): void;
895
+ /**
896
+ * Propose a plan for approval.
897
+ * In unattended mode: auto-approves immediately.
898
+ * In supervised/interactive: emits plan:proposed and waits for decidePlan() call.
899
+ */
900
+ proposePlan(tasks: PlannedTaskSummary[], projectGoal: string): Promise<'approved' | 'rejected'>;
901
+ decidePlan(proposalId: string, decision: 'approved' | 'rejected', modifications?: string): void;
902
+ /**
903
+ * Route a question from an agent to the user.
904
+ * In unattended mode: returns null immediately (agent should handle itself).
905
+ * In interactive: emits question:asked and waits for answerQuestion() call with timeout.
906
+ * In supervised: same as interactive but question is lower priority.
907
+ */
908
+ routeQuestion(fromAgent: string, question: string, opts?: {
909
+ taskId?: string;
910
+ context?: string;
911
+ options?: string[];
912
+ }): Promise<string | null>;
913
+ answerQuestion(questionId: string, answer: string): void;
914
+ /**
915
+ * Called each orchestrator cycle to check progress and emit reports/milestones.
916
+ */
917
+ checkProgress(tasks: Task[], stats: OrchestratorStats): void;
918
+ acknowledgeMilestone(milestoneId: string): void;
919
+ /**
920
+ * Clean up all pending timers and resolvers.
921
+ * Call this during shutdown to prevent leaked timers from blocking process exit.
922
+ */
923
+ cleanup(): void;
924
+ getPendingPlan(): PlanProposal | null;
925
+ getPendingQuestions(): UserQuestion[];
926
+ }
927
+
928
+ declare class ProgressTracker {
929
+ generateReport(tasks: Task[], stats: OrchestratorStats): ProgressReport;
930
+ getCompletionPercentage(tasks: Task[]): number;
931
+ detectPhase(tasks: Task[]): string;
932
+ }
933
+
934
+ /**
935
+ * Load and validate a project configuration from a YAML file.
936
+ *
937
+ * Reads the file at the given path, parses it as YAML, and validates
938
+ * the result against the project config schema.
939
+ */
940
+ declare function loadProjectConfig(filePath: string): Promise<ProjectConfig>;
941
+ /**
942
+ * Validate an unknown value against the project config schema.
943
+ *
944
+ * Returns a fully typed ProjectConfig with defaults applied, or
945
+ * throws a ZodError if validation fails.
946
+ */
947
+ declare function validateProjectConfig(config: unknown): ProjectConfig;
948
+
949
+ /**
950
+ * Manages the runtime directory structure for a Maestro project.
951
+ *
952
+ * Ensures all required directories exist and provides absolute path
953
+ * resolution for todo files, message inboxes/outboxes, and log files.
954
+ */
955
+ declare class WorkspaceManager {
956
+ private baseDir;
957
+ private config;
958
+ constructor(baseDir: string);
959
+ /**
960
+ * Create all runtime directories required by the project.
961
+ *
962
+ * This creates the top-level .maestro directory, the messages directory,
963
+ * the logs directory, and per-agent inbox/outbox directories for every
964
+ * agent defined in the project config.
965
+ */
966
+ initialize(config: ProjectConfig): Promise<void>;
967
+ /**
968
+ * Get the absolute path to the project's todo file.
969
+ */
970
+ getTodoFilePath(): string;
971
+ /**
972
+ * Get the absolute path to the messages directory.
973
+ */
974
+ getMessagesDir(): string;
975
+ /**
976
+ * Get the absolute path to the logs directory.
977
+ */
978
+ getLogsDir(): string;
979
+ /**
980
+ * Get the absolute path to a specific agent's log file.
981
+ */
982
+ getAgentLogPath(agentId: string): string;
983
+ /**
984
+ * Get the absolute path to a specific agent's inbox directory.
985
+ */
986
+ getAgentInboxPath(agentId: string): string;
987
+ /**
988
+ * Get the absolute path to a specific agent's outbox directory.
989
+ */
990
+ getAgentOutboxPath(agentId: string): string;
991
+ }
992
+
993
+ /**
994
+ * Create a pino logger that writes only to a log file (if provided).
995
+ * Console output is intentionally disabled — all user-facing info is
996
+ * surfaced through orchestrator:activity events and the TUI/CLI handlers.
997
+ * This avoids pino output bleeding into the terminal and corrupting the TUI.
998
+ *
999
+ * Uses synchronous file writes to avoid transport/worker thread issues in Electron.
1000
+ */
1001
+ declare function createLogger(name: string, logFile?: string): pino.Logger;
1002
+
1003
+ declare function generateId(): string;
1004
+ declare function generateTaskId(): string;
1005
+ declare function resetTaskCounter(startFrom?: number): void;
1006
+
1007
+ export { type AgentConfig, type AgentInfo, AgentPool, AgentProcess, type AgentRole, type AgentRoleConfig, type AgentState, type AgentStatus, type AgentStreamEvent, FeedbackLoop, type FeedbackSettings, InboxWatcher, type InteractionMode, type MaestroEvents, type Message, MessageBroker, type MessageEnvelope, type MessageType, type MilestoneEvent, Orchestrator, type OrchestratorActivity, type OrchestratorActivityKind, type OrchestratorStats, PIPELINE_STAGE_ORDER, PIPELINE_STAGE_ROLES, type PipelineStage, type PlanProposal, type PlannedTask, type PlannedTaskSummary, Planner, type ProgressReport, ProgressTracker, type ProjectCompletionSummary, type ProjectConfig, ProjectManagerScanner, type ProjectSettings, ROLE_DESCRIPTIONS, Scheduler, type Task, type TaskFilter, TaskManager, TaskParser, TaskPipeline, type TaskPipelineState, type TaskPriority, type TaskStatus, type TaskUpdate, TaskWriter, type TechStackConfig, type UserQuestion, WorkspaceManager, createLogger, generateId, generateTaskId, getDefaultSystemPrompt, loadAgentConfigs, loadProjectConfig, resetTaskCounter, validateProjectConfig };