/** * FABRIC Type Definitions * * Core types for NEEDLE log parsing and worker state management. */ /** * Schema version for the NEEDLE event wire format. * Bumped when the canonical NeedleEvent shape changes. * Both NEEDLE and FABRIC must agree on this version. */ export const NEEDLE_EVENT_SCHEMA_VERSION = 1; export type LogLevel = 'debug' | 'info' | 'warn' | 'error'; export type WorkerStatus = 'active' | 'idle' | 'error'; /** * NEEDLE worker state machine — first-class states emitted by * worker.state_transition events. These are the canonical states * that replace the coarse WorkerStatus in the UI. * * BOOTING → SELECTING → CLAIMING → WORKING → CLOSING → STOPPED */ export type NeedleState = | 'BOOTING' | 'SELECTING' | 'CLAIMING' | 'WORKING' | 'CLOSING' | 'STOPPED'; /** * All valid state transitions in the NEEDLE worker state machine. * A worker in BOOTING can only go to SELECTING, etc. */ export const VALID_TRANSITIONS: Record = { BOOTING: ['SELECTING'], SELECTING: ['CLAIMING', 'STOPPED'], CLAIMING: ['WORKING', 'SELECTING'], WORKING: ['CLOSING', 'SELECTING'], CLOSING: ['SELECTING', 'STOPPED'], STOPPED: ['BOOTING'], }; /** * Map a NeedleState to the coarser WorkerStatus for backward compatibility. */ export function needleStateToStatus(state: NeedleState): WorkerStatus { switch (state) { case 'BOOTING': case 'SELECTING': case 'CLAIMING': case 'WORKING': return 'active'; case 'CLOSING': return 'active'; case 'STOPPED': return 'idle'; } } /** * All event types emitted by NEEDLE's telemetry pipeline. * Format: category.action — matches NEEDLE's EventKind::event_type() mapping. * * Note: This is a non-exhaustive list of known event types for documentation. * The parser accepts any string for event_type to forward-compat with new NEEDLE versions. */ export type NeedleEventType = // Worker lifecycle | 'worker.booting' | 'worker.started' | 'worker.stopped' | 'worker.errored' | 'worker.exhausted' | 'worker.idle' | 'worker.idle_sleep_completed' | 'worker.idle_sleep_entered' | 'worker.state_transition' | 'worker.queue_empty' | 'worker.boot.timeout' | 'worker.handling.timeout' | 'worker.upgrade.detected' | 'worker.upgrade.completed' // Initialization | 'init.step.started' | 'init.step.completed' // Strand lifecycle | 'strand.evaluated' | 'strand.skipped' // Bead claim lifecycle | 'bead.claim.attempted' | 'bead.claim.succeeded' | 'bead.claim.race_lost' | 'bead.claim.race_lost_skipped' | 'bead.claim.failed' // Bead lifecycle | 'bead.released' | 'bead.release.failed' | 'bead.completed' | 'bead.orphaned' // Bead mitosis | 'bead.mitosis.evaluated' | 'bead.mitosis.split' | 'bead.mitosis.skipped' // Bead unravel (alternatives) | 'bead.unravel.analyzed' | 'bead.unravel.skipped' // Agent lifecycle | 'agent.dispatched' | 'agent.completed' | 'agent.transform.spawned' | 'agent.transform.exited' | 'agent.transform.skipped' // Build lifecycle | 'build.timeout' | 'build.heartbeat' // Outcome handling | 'outcome.classified' | 'outcome.handled' // Heartbeat & peer detection | 'heartbeat.emitted' | 'peer.stale' | 'peer.crashed' // Health checks | 'health.check' // Mend (maintenance cycle) | 'mend.orphaned_lock_removed' | 'mend.dependency_cleaned' | 'mend.db_repaired' | 'mend.db_rebuilt' | 'mend.cycle_summary' | 'mend.trace_cleanup' | 'mend.learning_cleanup' | 'mend.idle_worker_flagged' | 'mend.worker_deregistered' | 'mend.orphaned_heartbeat_removed' | 'mend.dependency_removed' | 'mend.bead_release_failed' | 'mend.dependency_cleanup_failed' | 'mend.lock_remove_failed' | 'mend.rate_limit_cleaned' | 'mend.rate_limit_provider_removed' | 'mend.rate_limit_provider_reset' | 'mend.zero_activity_log_cleaned' // Effort & budget | 'effort.recorded' | 'budget.warning' | 'budget.stop' // Rate limiting | 'rate_limit.wait' | 'rate_limit.allowed' // Verification | 'verification.failed' | 'verification.passed' // Reflect (drift detection & decision mining) | 'reflect.started' | 'reflect.consolidated' | 'reflect.skipped' | 'reflect.transcripts_read' | 'reflect.drift_detected' | 'reflect.drift_promoted' | 'reflect.decision_extracted' | 'reflect.adr_created' | 'reflect.learning_promoted' | 'reflect.learning_deduplicated' | 'reflect.claudemd_written' // Drift detection | 'drift.started' | 'drift.completed' | 'drift.skipped' | 'drift.report_written' // Decision detection | 'decision.started' | 'decision.completed' | 'decision.skipped' // Pulse (health monitoring) | 'pulse.scanner_started' | 'pulse.scanner_completed' | 'pulse.scanner_failed' | 'pulse.bead_created' | 'pulse.skipped' // Rollback | 'rollback.completed' // Canary deployment | 'canary.started' | 'canary.suite_completed' | 'canary.promoted' | 'canary.rejected' // Transform lifecycle | 'transform.started' | 'transform.completed' | 'transform.failed' | 'transform.skipped' // Telemetry internal | 'telemetry.sink_error' | 'telemetry.otlp.dropped' | 'telemetry.otlp.shutdown_timeout'; // ============================================ // Canonical NeedleEvent (wire schema) // ============================================ /** * Canonical event shape emitted by NEEDLE over JSONL and OTLP. * This is the contract between NEEDLE and FABRIC — versioned via NEEDLE_EVENT_SCHEMA_VERSION. * * Ordering: sort by (worker_id, sequence), NOT by timestamp. * Wall clocks skew across hosts; sequence is the worker's monotonic counter. */ export interface NeedleEvent { /** RFC3339 timestamp — display only, NOT authoritative for ordering */ timestamp: string; /** Event taxonomy string, e.g. "worker.started", "bead.claimed" */ event_type: NeedleEventType | string; /** Worker identifier (e.g. "tcb-alpha") */ worker_id: string; /** Session identifier grouping a worker's lifetime events */ session_id: string; /** Per-worker monotonic counter — authoritative for ordering */ sequence: number; /** Present when event pertains to a specific bead */ bead_id?: string; /** Event-specific payload */ data: Record; } // ============================================ // Conversation Event Types // ============================================ /** * Role in a conversation */ export type ConversationRole = 'system' | 'user' | 'assistant' | 'tool'; /** * Type of conversation event */ export type ConversationEventType = | 'prompt' // User input/prompt | 'response' // Assistant response text | 'thinking' // Internal reasoning/thinking block | 'tool_call' // Tool being called with arguments | 'tool_result'; // Result from a tool call /** * Base interface for all conversation events */ export interface ConversationEventBase { /** Unique event identifier */ id: string; /** Type of conversation event */ type: ConversationEventType; /** Role in conversation */ role: ConversationRole; /** Unix timestamp in milliseconds */ ts: number; /** Worker identifier */ worker: string; /** Associated bead/task ID (if any) */ bead?: string; /** Sequence number within the conversation */ sequence: number; /** Token count for this event (if available) */ tokens?: number; } /** * User prompt event */ export interface PromptEvent extends ConversationEventBase { type: 'prompt'; role: 'user'; /** The user's prompt text */ content: string; /** Whether this is a continuation of a previous prompt */ isContinuation?: boolean; } /** * Assistant response event */ export interface ResponseEvent extends ConversationEventBase { type: 'response'; role: 'assistant'; /** The response text */ content: string; /** Whether the response is truncated */ isTruncated?: boolean; /** Model used for this response */ model?: string; /** Stop reason (if available) */ stopReason?: 'end_turn' | 'max_tokens' | 'stop_sequence' | 'tool_use'; } /** * Thinking/reasoning block event */ export interface ThinkingEvent extends ConversationEventBase { type: 'thinking'; role: 'assistant'; /** The thinking content */ content: string; /** Whether thinking is truncated */ isTruncated?: boolean; /** Duration of thinking in ms (if available) */ durationMs?: number; } /** * Tool argument types */ export type ToolArgValue = string | number | boolean | null | ToolArgValue[] | { [key: string]: ToolArgValue }; /** * Tool call event */ export interface ToolCallEvent extends ConversationEventBase { type: 'tool_call'; role: 'assistant'; /** Tool name */ tool: string; /** Tool arguments */ args: Record; /** Tool call ID (for correlating with results) */ toolCallId?: string; /** Human-readable summary of the call */ summary?: string; } /** * Tool result event */ export interface ToolResultEvent extends ConversationEventBase { type: 'tool_result'; role: 'tool'; /** Tool name */ tool: string; /** Tool call ID this is a response to */ toolCallId?: string; /** Result content (may be truncated) */ content: string; /** Whether the tool call succeeded */ success: boolean; /** Error message if failed */ error?: string; /** Duration of tool call in ms */ durationMs?: number; /** Whether the result is truncated */ isTruncated?: boolean; /** Size of full result in bytes (for context) */ resultSize?: number; } /** * Union type for all conversation events */ export type ConversationEvent = | PromptEvent | ResponseEvent | ThinkingEvent | ToolCallEvent | ToolResultEvent; /** * A complete conversation session */ export interface ConversationSession { /** Session identifier */ id: string; /** Worker ID */ workerId: string; /** Associated bead ID (if any) */ beadId?: string; /** Start timestamp */ startTime: number; /** End timestamp (if complete) */ endTime?: number; /** All events in chronological order */ events: ConversationEvent[]; /** Total token count */ totalTokens: number; /** Number of turns */ turnCount: number; /** Tools used in this session */ toolsUsed: string[]; /** Whether the session is still active */ isActive: boolean; } /** * Options for parsing conversation events */ export interface ConversationParseOptions { /** Maximum content length before truncation */ maxContentLength?: number; /** Include thinking blocks */ includeThinking?: boolean; /** Include tool results */ includeToolResults?: boolean; /** Truncate tool results longer than this */ maxToolResultLength?: number; } // ============================================ // Core Log Event Types // ============================================ export interface LogEvent { /** Unix timestamp in milliseconds — display only, NOT authoritative for ordering */ ts: number; /** Worker identifier (e.g., 'w-abc123') */ worker: string; /** Per-worker monotonic counter — authoritative for ordering (from NeedleEvent.sequence) */ sequence?: number; /** Log level */ level: LogLevel; /** Log message */ msg: string; /** Optional: Tool that was called */ tool?: string; /** Optional: File path being operated on */ path?: string; /** Optional: Bead/task identifier */ bead?: string; /** Optional: Duration in milliseconds */ duration_ms?: number; /** Optional: Error details */ error?: string; /** NEEDLE session identifier (e.g. 'needle-claude-anthropic-sonnet-alpha') */ session?: string; /** AI provider extracted from NEEDLE worker string (e.g. 'anthropic', 'openai') */ provider?: string; /** AI model identifier extracted from NEEDLE worker string (e.g. 'sonnet', 'gpt-4o') */ model?: string; /** Any additional fields */ [key: string]: unknown; } /** * Compare two LogEvents by (worker, sequence), falling back to ts. * * Sequence is the authoritative ordering key within a worker (monotonic counter * from NEEDLE). Timestamp is used only as a display fallback for legacy events * that lack a sequence number. */ export function compareEventsBySequence(a: LogEvent, b: LogEvent): number { const seqA = a.sequence != null && a.sequence >= 0 ? a.sequence : null; const seqB = b.sequence != null && b.sequence >= 0 ? b.sequence : null; if (seqA !== null && seqB !== null) { if (a.worker !== b.worker) return a.worker.localeCompare(b.worker); return seqA - seqB; } return a.ts - b.ts; } export interface WorkerInfo { /** Worker identifier */ id: string; /** Current status (coarse — derived from needleState) */ status: WorkerStatus; /** Current NEEDLE state machine state (fine-grained) */ needleState?: NeedleState; /** Timestamp of the last state transition (ms since epoch) */ lastStateTransition?: number; /** Last event received */ lastEvent?: LogEvent; /** Total beads completed */ beadsCompleted: number; /** First seen timestamp */ firstSeen: number; /** Last activity timestamp */ lastActivity: number; /** Files currently being modified by this worker */ activeFiles: string[]; /** Whether this worker is involved in any collisions */ hasCollision: boolean; /** Current bead/task being worked on */ activeBead?: string; /** Current bead from bead.claim.succeeded, cleared on bead.released */ currentBead: string | null; /** Directories this worker is active in */ activeDirectories: string[]; /** All collision types this worker is involved in */ collisionTypes: ('file' | 'bead' | 'task')[]; /** Total number of events received for this worker */ eventCount: number; /** Whether the worker appears stuck (gap-based detection) */ stuck?: boolean; /** Human-readable reason the worker is stuck */ stuckReason?: string; } export interface EventFilter { /** Filter by worker ID */ worker?: string; /** Filter by log level */ level?: LogLevel; /** Filter by bead ID */ bead?: string; /** Filter by event type (glob pattern, e.g. "bead.*") */ eventType?: string; /** Filter by file path */ path?: string; /** Time range start (Unix timestamp) */ since?: number; /** Time range end (Unix timestamp) */ until?: number; } /** * File collision event - when multiple workers modify the same file concurrently */ export interface FileCollision { /** File path being contested */ path: string; /** Workers involved in the collision */ workers: string[]; /** Timestamp when collision was detected */ detectedAt: number; /** Events that triggered the collision */ events: LogEvent[]; /** Whether the collision is still active */ isActive: boolean; } /** * Bead collision - when multiple workers work on the same bead/task */ export interface BeadCollision { /** Bead ID being contested */ beadId: string; /** Workers working on this bead */ workers: string[]; /** Timestamp when collision was detected */ detectedAt: number; /** Events that triggered the collision */ events: LogEvent[]; /** Whether the collision is still active */ isActive: boolean; /** Collision severity based on operation types */ severity: 'warning' | 'critical'; } /** * Task collision - when workers work on tasks that may conflict */ export interface TaskCollision { /** Type of collision */ type: 'directory' | 'related_files' | 'dependency'; /** Human-readable description */ description: string; /** Workers involved */ workers: string[]; /** Affected paths/beads */ affectedResources: string[]; /** Timestamp when collision was detected */ detectedAt: number; /** Whether the collision is still active */ isActive: boolean; /** Risk level */ riskLevel: 'low' | 'medium' | 'high'; } /** * Collision alert for user notification */ export interface CollisionAlert { /** Unique alert ID */ id: string; /** Alert type */ type: 'file' | 'bead' | 'task'; /** Severity level */ severity: 'info' | 'warning' | 'error' | 'critical'; /** Human-readable title */ title: string; /** Detailed description */ description: string; /** Workers involved */ workers: string[]; /** Timestamp when alert was generated */ timestamp: number; /** Whether the alert has been acknowledged */ acknowledged: boolean; /** Related collision data */ collision: FileCollision | BeadCollision | TaskCollision; /** Suggested resolution */ suggestion?: string; } export interface EventStore { /** Add an event to the store */ add(event: LogEvent): void; /** Query events with optional filter */ query(filter?: EventFilter): LogEvent[]; /** Query events sorted by (worker, sequence), falling back to ts */ queryOrdered(filter?: EventFilter): LogEvent[]; /** Get worker info */ getWorker(workerId: string): WorkerInfo | undefined; /** Get all workers */ getWorkers(): WorkerInfo[]; /** Clear all events */ clear(): void; /** Get all active collisions */ getCollisions(): FileCollision[]; /** Get collisions for a specific worker */ getWorkerCollisions(workerId: string): FileCollision[]; } // ============================================ // Error Grouping Types // ============================================ /** * Error fingerprint - used to identify similar errors */ export interface ErrorFingerprint { /** Normalized pattern signature (e.g., "ECONNREFUSED_*:*" for connection errors) */ signature: string; /** Category of error (network, permission, validation, etc.) */ category: ErrorCategory; /** Original error message (first occurrence) */ sampleMessage: string; /** Hash of the signature for quick comparison */ hash: string; } /** * Error categories for grouping */ export type ErrorCategory = | 'network' // Connection errors, timeouts, DNS issues | 'permission' // Auth failures, access denied | 'validation' // Invalid input, schema errors | 'resource' // Out of memory, disk full, quota exceeded | 'not_found' // File not found, 404 errors | 'timeout' // Operation timed out | 'syntax' // Parse errors, malformed data | 'tool' // Tool-specific failures | 'unknown'; // Uncategorized errors /** * Grouped error - clusters similar errors together */ export interface ErrorGroup { /** Unique group ID */ id: string; /** Fingerprint identifying this group */ fingerprint: ErrorFingerprint; /** All error events in this group */ events: LogEvent[]; /** First occurrence timestamp */ firstSeen: number; /** Most recent occurrence timestamp */ lastSeen: number; /** Number of occurrences */ count: number; /** Workers that have encountered this error */ affectedWorkers: string[]; /** Whether this error group is currently active (seen recently) */ isActive: boolean; /** Severity based on frequency and recency */ severity: 'low' | 'medium' | 'high' | 'critical'; } /** * Options for error grouping */ export interface ErrorGroupingOptions { /** Time window to consider errors as active (ms), default 5 minutes */ activeWindowMs?: number; /** Minimum occurrences for high severity */ highSeverityThreshold?: number; /** Minimum occurrences for critical severity */ criticalSeverityThreshold?: number; /** Maximum groups to track */ maxGroups?: number; } // ============================================ // Session Replay Types // ============================================ export type ReplaySpeed = 0.5 | 1 | 2 | 5 | 10; export type ReplayState = 'idle' | 'playing' | 'paused' | 'ended'; export interface ReplaySession { /** Unique session identifier */ id: string; /** Source log file path */ sourcePath: string; /** Total events in the session */ totalEvents: number; /** Current playback position (event index) */ currentIndex: number; /** Playback state */ state: ReplayState; /** Playback speed multiplier */ speed: ReplaySpeed; /** Start timestamp of session (first event) */ startTime: number; /** End timestamp of session (last event) */ endTime: number; /** Filter applied during replay */ filter?: EventFilter; } export interface ReplayControls { /** Start or resume playback */ play(): void; /** Pause playback */ pause(): void; /** Toggle play/pause */ toggle(): void; /** Step to next event */ stepForward(): void; /** Step to previous event */ stepBackward(): void; /** Jump to specific event index */ seekTo(index: number): void; /** Set playback speed */ setSpeed(speed: ReplaySpeed): void; /** Stop and reset replay */ reset(): void; } // ============================================ // File Heatmap Types // ============================================ /** * Heat level for a file based on modification frequency */ export type HeatLevel = 'cold' | 'warm' | 'hot' | 'critical'; /** * Worker contribution to a file's modification history */ export interface WorkerFileContribution { /** Worker ID */ workerId: string; /** Number of modifications by this worker */ modifications: number; /** Last modification timestamp */ lastModified: number; /** Percentage of total modifications (0-100) */ percentage: number; } /** * Single file entry in the heatmap */ export interface FileHeatmapEntry { /** File path */ path: string; /** Total modification count */ modifications: number; /** Heat level based on frequency */ heatLevel: HeatLevel; /** Workers who have modified this file */ workers: WorkerFileContribution[]; /** First modification timestamp */ firstModified: number; /** Most recent modification timestamp */ lastModified: number; /** Whether this file is currently being modified by multiple workers */ hasCollision: boolean; /** Number of workers currently active on this file */ activeWorkers: number; /** Average time between modifications (ms) */ avgModificationInterval: number; } /** * Options for heatmap generation */ export interface HeatmapOptions { /** Minimum modifications to be included in heatmap */ minModifications?: number; /** Maximum entries to return */ maxEntries?: number; /** Sort by: 'modifications' | 'recent' | 'workers' | 'collisions' */ sortBy?: 'modifications' | 'recent' | 'workers' | 'collisions'; /** Filter by directory prefix */ directoryFilter?: string; /** Only show files with collisions */ collisionsOnly?: boolean; } /** * Statistics for the entire file heatmap */ export interface FileHeatmapStats { /** Total files being tracked */ totalFiles: number; /** Total modifications across all files */ totalModifications: number; /** Files with collisions */ collisionFiles: number; /** Files currently being modified */ activeFiles: number; /** Heat level distribution */ heatDistribution: Record; /** Most active directory */ mostActiveDirectory: string; /** Average modifications per file */ avgModificationsPerFile: number; } /** * Heatmap snapshot at a specific point in time */ export interface HeatmapSnapshot { /** Timestamp of this snapshot */ timestamp: number; /** Heatmap entries at this point in time */ entries: FileHeatmapEntry[]; /** Statistics at this point in time */ stats: FileHeatmapStats; } /** * Time-series heatmap data for animation */ export interface HeatmapTimelapse { /** Start timestamp of the timelapse */ startTimestamp: number; /** End timestamp of the timelapse */ endTimestamp: number; /** Time interval between snapshots (ms) */ interval: number; /** Total number of snapshots */ totalSnapshots: number; /** Array of heatmap snapshots */ snapshots: HeatmapSnapshot[]; } /** * Options for generating timelapse data */ export interface TimelapseOptions { /** Start timestamp (defaults to oldest modification) */ startTimestamp?: number; /** End timestamp (defaults to now) */ endTimestamp?: number; /** Number of snapshots to generate (default 30) */ snapshotCount?: number; /** Minimum modifications to be included */ minModifications?: number; /** Maximum entries per snapshot */ maxEntries?: number; /** Sort mode for snapshots */ sortBy?: 'modifications' | 'recent' | 'workers' | 'collisions'; /** Filter by directory prefix */ directoryFilter?: string; /** Only show files with collisions */ collisionsOnly?: boolean; } // ============================================ // File Anomaly Detection Types // ============================================ /** * Types of file activity anomalies */ export type AnomalyType = | 'config_modification' // Config file modified outside expected context | 'high_frequency' // Unusually high modification rate | 'burst_activity' // Sudden burst of modifications | 'unusual_pattern' // Activity pattern outside normal bounds | 'sensitive_file'; // Sensitive file (secrets, credentials) touched /** * Severity level for anomalies */ export type AnomalySeverity = 'info' | 'warning' | 'critical'; /** * Detected file anomaly */ export interface FileAnomaly { /** File path with anomaly */ path: string; /** Type of anomaly detected */ type: AnomalyType; /** Severity level */ severity: AnomalySeverity; /** Human-readable description */ message: string; /** When the anomaly was detected */ detectedAt: number; /** Supporting data for the anomaly */ details: { /** Modification count involved */ modifications?: number; /** Workers involved */ workers?: string[]; /** Time span of anomalous activity (ms) */ timeSpan?: number; /** Expected normal value */ expectedValue?: number; /** Actual observed value */ actualValue?: number; /** Additional context */ context?: Record; }; } /** * Options for anomaly detection */ export interface AnomalyDetectionOptions { /** Minimum modifications to consider for anomaly detection */ minModifications?: number; /** Threshold multiplier for high-frequency detection (e.g., 3 = 3x average) */ frequencyThreshold?: number; /** Time window for burst detection (ms) */ burstWindow?: number; /** Minimum burst count to trigger anomaly */ burstThreshold?: number; /** Custom patterns for sensitive files */ sensitivePatterns?: string[]; } /** * Statistics for anomaly detection */ export interface AnomalyStats { /** Total anomalies detected */ totalAnomalies: number; /** Count by type */ byType: Record; /** Count by severity */ bySeverity: Record; /** Files with most anomalies */ topAnomalyFiles: Array<{ path: string; count: number; types: AnomalyType[]; }>; } // ============================================ // Dependency DAG Types // ============================================ /** * Bead status type */ export type BeadStatus = 'open' | 'in_progress' | 'blocked' | 'completed' | 'closed' | 'deferred'; /** * Single node in the dependency graph */ export interface BeadNode { /** Bead ID (e.g., 'bd-abc123') */ id: string; /** Bead title */ title: string; /** Current status */ status: BeadStatus; /** Priority level (0-4) */ priority: number; /** Depth in the dependency tree (0 = root) */ depth: number; /** Number of dependents (beads that depend on this) */ dependentCount: number; /** Number of dependencies (beads this depends on) */ dependencyCount: number; /** Whether this is on the critical path */ isCriticalPath: boolean; /** Estimated effort (if available) */ estimatedEffort?: number; } /** * Edge in the dependency graph */ export interface DependencyEdge { /** Source bead ID (the one that depends) */ from: string; /** Target bead ID (the dependency) */ to: string; /** Whether this edge is part of the critical path */ isCritical: boolean; } /** * Connected component in the dependency graph */ export interface DagComponent { /** All nodes in this component */ nodes: BeadNode[]; /** All edges in this component */ edges: DependencyEdge[]; /** Root nodes (no incoming edges) */ roots: string[]; /** Whether this component contains cycles */ hasCycle: boolean; /** Critical path through this component (bead IDs) */ criticalPath: string[]; /** Total depth of the component */ maxDepth: number; } /** * Full dependency graph */ export interface DependencyGraph { /** All connected components */ components: DagComponent[]; /** Total nodes across all components */ totalNodes: number; /** Total edges across all components */ totalEdges: number; /** Total components */ totalComponents: number; /** Overall critical path (longest path across all components) */ globalCriticalPath: string[]; /** Timestamp when graph was generated */ generatedAt: number; } /** * Options for DAG visualization */ export interface DagOptions { /** Filter by status */ status?: BeadStatus | 'all'; /** Filter by priority range */ minPriority?: number; maxPriority?: number; /** Show only critical path */ criticalOnly?: boolean; /** Maximum depth to display */ maxDepth?: number; /** Sort order: 'priority' | 'depth' | 'dependents' */ sortBy?: 'priority' | 'depth' | 'dependents'; /** Include closed/completed beads */ includeClosed?: boolean; } /** * Statistics about the dependency graph */ export interface DagStats { /** Total beads tracked */ totalBeads: number; /** Blocked beads count */ blockedCount: number; /** Ready beads (unblocked, open) */ readyCount: number; /** Average dependencies per bead */ avgDependencies: number; /** Average dependents per bead */ avgDependents: number; /** Maximum depth found */ maxDepth: number; /** Number of cycles detected */ cycleCount: number; /** Critical path length */ criticalPathLength: number; /** Beads on critical path */ criticalPathBeads: number; } // ============================================ // Span-based DAG Types (OTLP span hierarchy) // ============================================ /** * A node in the span DAG, built from paired .started/.finished NeedleEvents * derived from OTLP spans. Parent-child relationships come from * parent_span_id rather than bead dependencies. */ export interface SpanNode { /** OTLP span ID */ span_id: string; /** OTLP trace ID */ trace_id: string; /** Parent span ID (undefined for root spans) */ parent_span_id?: string; /** Span name (e.g. "bead.lifecycle", "tool.call", "llm.request") */ name: string; /** Worker that emitted this span */ worker_id: string; /** Associated bead ID (if this is a bead lifecycle span) */ bead_id?: string; /** Start timestamp (ms from .started event) */ start_ts?: number; /** End timestamp (ms from .finished event) */ end_ts?: number; /** Duration in ms */ duration_ms?: number; /** Span completion status */ status: 'ok' | 'error' | 'unknown'; /** Child spans (populated during tree construction) */ children: SpanNode[]; /** Remaining span attributes */ attributes: Record; } /** * A span hierarchy DAG built from OTLP span events. * Unlike the bead DependencyGraph (which uses br graph --json), * the SpanDag is built from the live event stream using parent_span_id * for parent-child linkage. */ export interface SpanDag { /** Root spans (no parent_span_id or orphaned) */ roots: SpanNode[]; /** All spans indexed by span_id */ allSpans: Map; /** Spans grouped by trace_id */ traces: Map; } // ============================================ // Git Event Types // ============================================ /** * Type of git event */ export type GitEventType = | 'status' // Git status output (staged, unstaged, untracked) | 'commit' // Git commit | 'branch' // Branch information | 'diff'; // Git diff output /** * File status in git */ export type GitFileStatus = | 'added' | 'modified' | 'deleted' | 'renamed' | 'copied' | 'untracked' | 'unmerged'; /** * Single file change in git */ export interface GitFileChange { /** File path */ path: string; /** Status of the file */ status: GitFileStatus; /** Original path (for renames) */ originalPath?: string; /** Staging area status */ staged: boolean; } /** * Base interface for all git events */ export interface GitEventBase { /** Unique event identifier */ id: string; /** Type of git event */ type: GitEventType; /** Unix timestamp in milliseconds */ ts: number; /** Worker identifier */ worker: string; /** Associated bead/task ID (if any) */ bead?: string; } /** * Git status event */ export interface GitStatusEvent extends GitEventBase { type: 'status'; /** Current branch name */ branch: string; /** Commit hash (HEAD) */ commit?: string; /** Staged file changes */ staged: GitFileChange[]; /** Unstaged file changes */ unstaged: GitFileChange[]; /** Untracked files */ untracked: string[]; /** Commits ahead of remote */ ahead?: number; /** Commits behind remote */ behind?: number; /** Remote tracking branch */ tracking?: string; } /** * Git commit event */ export interface GitCommitEvent extends GitEventBase { type: 'commit'; /** Commit hash */ hash: string; /** Commit message */ message: string; /** Branch name */ branch?: string; /** Author name */ author?: string; /** Author email */ email?: string; /** Parent commit hash(es) */ parents?: string[]; /** Files changed in this commit */ files?: GitFileChange[]; } /** * Git branch event */ export interface GitBranchEvent extends GitEventBase { type: 'branch'; /** Current branch name */ current: string; /** All local branches */ branches?: string[]; /** Remote tracking branch */ tracking?: string; /** Commits ahead of tracking */ ahead?: number; /** Commits behind tracking */ behind?: number; } /** * Git diff event */ export interface GitDiffEvent extends GitEventBase { type: 'diff'; /** Diff target (e.g., 'HEAD', 'origin/main') */ target: string; /** Files with changes */ files: GitFileChange[]; /** Total lines added */ linesAdded: number; /** Total lines deleted */ linesDeleted: number; /** Diff content (may be truncated) */ content?: string; /** Whether diff content is truncated */ isTruncated?: boolean; } /** * Union type for all git events */ export type GitEvent = | GitStatusEvent | GitCommitEvent | GitBranchEvent | GitDiffEvent; /** * Options for parsing git events */ export interface GitParseOptions { /** Maximum diff content length before truncation */ maxDiffLength?: number; /** Include file change details */ includeFileChanges?: boolean; /** Maximum files to track in a single event */ maxFiles?: number; } // ============================================ // PR Preview Types // ============================================ /** * File change with diff statistics */ export interface PRFileChange extends GitFileChange { /** Lines added in this file */ linesAdded: number; /** Lines deleted in this file */ linesDeleted: number; /** Worker who made the change */ worker?: string; } /** * Upstream commit that might conflict */ export interface UpstreamCommit { /** Commit hash */ hash: string; /** Commit message */ message: string; /** Author name */ author?: string; /** Files changed in this commit */ files: string[]; /** Timestamp */ ts: number; } /** * Potential conflict information */ export interface PotentialConflict { /** Whether there are upstream commits */ hasUpstreamCommits: boolean; /** Number of upstream commits */ upstreamCommitCount: number; /** Upstream commits that might conflict */ upstreamCommits: UpstreamCommit[]; /** Files that might have conflicts */ conflictingFiles: string[]; /** Whether rebase is recommended */ rebaseRecommended: boolean; /** Reason for rebase recommendation */ rebaseReason?: string; } /** * PR Preview data */ export interface PRPreview { /** Generated PR title */ title: string; /** Generated PR description */ description: string; /** Commit message preview */ commitMessage: string; /** All files changed */ files: PRFileChange[]; /** Total lines added */ totalLinesAdded: number; /** Total lines deleted */ totalLinesDeleted: number; /** Number of files changed */ filesChanged: number; /** Potential conflicts with upstream */ conflicts: PotentialConflict; /** Source branch */ sourceBranch: string; /** Target branch (usually main) */ targetBranch: string; /** Number of commits ahead */ ahead: number; /** Number of commits behind */ behind: number; /** Whether there are uncommitted changes */ hasUncommittedChanges: boolean; /** Timestamp when preview was generated */ generatedAt: number; } // ============================================ // Cross-Reference Types // ============================================ /** * Type of entity that can be cross-referenced */ export type CrossReferenceEntityType = 'event' | 'bead' | 'file' | 'worker' | 'session'; /** * A single cross-reference link */ export interface CrossReferenceLink { /** Unique link ID */ id: string; /** Source entity type */ sourceType: CrossReferenceEntityType; /** Source entity ID */ sourceId: string; /** Target entity type */ targetType: CrossReferenceEntityType; /** Target entity ID */ targetId: string; /** Relationship type */ relationship: CrossReferenceRelationship; /** Strength of the relationship (0-1) */ strength: number; /** When this link was detected */ detectedAt: number; /** Optional context about why this link exists */ context?: string; } /** * Types of relationships between entities */ export type CrossReferenceRelationship = | 'same_bead' // Events working on the same bead/task | 'same_file' // Events modifying the same file | 'same_worker' // Events from the same worker | 'temporal_proximity' // Events happening close together in time | 'same_session' // Events in the same worker session | 'dependency' // One bead depends on another | 'collision' // Workers colliding on the same file | 'parent_child' // Hierarchical relationship | 'error_related' // Events related to the same error | 'tool_sequence'; // Tool calls that form a logical sequence /** * A cross-reference entity with its links */ export interface CrossReferenceEntity { /** Entity type */ type: CrossReferenceEntityType; /** Entity ID */ id: string; /** Human-readable label */ label: string; /** All links from this entity */ outgoingLinks: CrossReferenceLink[]; /** All links to this entity */ incomingLinks: CrossReferenceLink[]; /** Related entities grouped by type */ relatedEntities: Map; /** Total link count */ linkCount: number; /** Most recent link timestamp */ lastLinkedAt: number; /** First seen timestamp */ firstSeen: number; /** Number of occurrences */ occurrenceCount: number; } /** * Options for cross-reference queries */ export interface CrossReferenceQueryOptions { /** Filter by source entity type */ sourceType?: CrossReferenceEntityType; /** Filter by target entity type */ targetType?: CrossReferenceEntityType; /** Filter by relationship type */ relationship?: CrossReferenceRelationship; /** Minimum relationship strength */ minStrength?: number; /** Time range start */ since?: number; /** Time range end */ until?: number; /** Maximum results */ limit?: number; } /** Alias for backward compatibility */ export type CrossReferenceFilter = CrossReferenceQueryOptions; /** * Statistics about cross-references */ export interface CrossReferenceStats { /** Total links tracked */ totalLinks: number; /** Total entities tracked */ totalEntities: number; /** Links by relationship type */ byRelationship: Record; /** Entities by type */ byEntityType: Record; /** Most linked entities */ mostLinked: CrossReferenceEntity[]; /** Recent links */ recentLinks: CrossReferenceLink[]; } /** * A navigation path through cross-references */ export interface CrossReferencePath { /** Starting entity */ start: CrossReferenceEntity; /** Ending entity */ end: CrossReferenceEntity; /** Path steps */ steps: CrossReferenceLink[]; /** Total path length */ length: number; /** Path description */ description: string; } // ============================================ // Recovery Playbook Types // ============================================ /** * Priority level for recovery actions */ export type RecoveryPriority = 'immediate' | 'high' | 'normal' | 'low'; /** * Type of recovery action */ export type RecoveryActionType = | 'retry' // Simple retry the operation | 'backoff' // Retry with exponential backoff | 'alternative' // Use alternative approach | 'escalate' // Escalate to human | 'skip' // Skip and continue | 'fix_config' // Fix configuration | 'install_dep' // Install missing dependency | 'fix_permissions' // Fix file permissions | 'cleanup' // Clean up resources | 'restart' // Restart service/process | 'investigate'; // Requires further investigation /** * A single recovery action step */ export interface RecoveryAction { /** Unique action ID */ id: string; /** Action type */ type: RecoveryActionType; /** Human-readable title */ title: string; /** Detailed description of the action */ description: string; /** Priority for ordering actions */ priority: RecoveryPriority; /** Whether this action can be automated */ automated: boolean; /** Command or code snippet to execute (if applicable) */ command?: string; /** Expected outcome */ expectedOutcome?: string; /** Prerequisites before this action */ prerequisites?: string[]; /** Risk level of this action */ riskLevel?: 'safe' | 'moderate' | 'risky'; /** Estimated time to complete (seconds) */ estimatedTime?: number; } /** * A recovery playbook entry mapping error patterns to actions */ export interface RecoveryPlaybookEntry { /** Unique playbook ID */ id: string; /** Error category this applies to */ category: ErrorCategory; /** Title for this recovery playbook */ title: string; /** Description of the error pattern */ description: string; /** Pattern to match error messages */ patterns: RegExp[]; /** Recovery actions in order */ actions: RecoveryAction[]; /** When this playbook was created */ createdAt: number; /** When this playbook was last updated */ updatedAt: number; /** Tags for categorization */ tags: string[]; } /** * A specific recovery suggestion for an error */ export interface RecoverySuggestion { /** Unique suggestion ID */ id: string; /** The error group this suggestion is for */ errorGroupId: string; /** The playbook entry this came from (if any) */ playbookId?: string; /** Error category */ category: ErrorCategory; /** Title for the suggestion */ title: string; /** Summary of the error */ errorSummary: string; /** Recommended actions in order */ actions: RecoveryAction[]; /** When this suggestion was generated */ generatedAt: number; /** Confidence level (0-1) */ confidence: number; /** Related workers affected */ affectedWorkers: string[]; /** Similar past errors (if any) */ relatedErrors?: string[]; /** Whether this is still relevant */ isActive: boolean; } /** * Options for recovery suggestion generation */ export interface RecoveryOptions { /** Maximum actions to include per suggestion */ maxActions?: number; /** Only include automated actions */ automatedOnly?: boolean; /** Minimum confidence threshold */ minConfidence?: number; /** Filter by category */ category?: ErrorCategory; /** Filter by worker */ workerId?: string; } /** * Statistics about recovery suggestions */ export interface RecoveryStats { /** Total suggestions generated */ totalSuggestions: number; /** Active suggestions */ activeSuggestions: number; /** Suggestions by category */ byCategory: Record; /** Automated vs manual actions */ automatedActions: number; manualActions: number; /** Average confidence */ avgConfidence: number; /** Most common recovery action types */ topActionTypes: Array<{ type: RecoveryActionType; count: number }>; } // ============================================ // Session Digest Types // ============================================ /** * Bead completion summary */ export interface BeadCompletion { /** Bead ID */ beadId: string; /** Worker that completed the bead */ workerId: string; /** Completion timestamp */ completedAt: number; /** Duration in milliseconds */ durationMs?: number; } /** * File modification summary */ export interface FileModificationSummary { /** File path */ path: string; /** Number of modifications */ modifications: number; /** Workers who modified this file */ workers: string[]; /** Tools used */ tools: string[]; } /** * Error occurrence in session */ export interface ErrorOccurrence { /** Error message */ message: string; /** Error category */ category: ErrorCategory; /** Worker that encountered the error */ workerId: string; /** Timestamp */ timestamp: number; /** Error fingerprint */ fingerprint?: string; } /** * Worker session summary */ export interface WorkerSessionSummary { /** Worker ID */ workerId: string; /** Beads completed */ beadsCompleted: number; /** Files modified */ filesModified: number; /** Errors encountered */ errorsEncountered: number; /** Total events */ totalEvents: number; /** Active time in milliseconds */ activeTimeMs: number; /** First activity timestamp */ firstActivity: number; /** Last activity timestamp */ lastActivity: number; } /** * Complete session digest */ export interface SessionDigest { /** Session ID or identifier */ sessionId: string; /** Session start timestamp */ startTime: number; /** Session end timestamp */ endTime: number; /** Total duration in milliseconds */ durationMs: number; /** Beads completed */ beadsCompleted: BeadCompletion[]; /** Files modified */ filesModified: FileModificationSummary[]; /** Errors encountered */ errors: ErrorOccurrence[]; /** Worker summaries */ workers: WorkerSessionSummary[]; /** Token usage and cost */ cost: { totalTokens: number; inputTokens: number; outputTokens: number; estimatedCostUsd: number; }; /** Overall statistics */ stats: { totalEvents: number; totalWorkers: number; totalBeads: number; totalFiles: number; totalErrors: number; avgEventsPerWorker: number; avgBeadsPerWorker: number; }; } /** * Options for session digest generation */ export interface SessionDigestOptions { /** Start time filter */ startTime?: number; /** End time filter */ endTime?: number; /** Include only specific workers */ workers?: string[]; /** Include error details */ includeErrors?: boolean; /** Include cost breakdown */ includeCost?: boolean; /** Maximum files to list */ maxFiles?: number; /** Maximum errors to list */ maxErrors?: number; } // ============================================ // Worker Analytics Types // ============================================ /** * Time window for aggregation */ export type TimeWindow = 'hour' | 'day' | 'week' | 'all'; /** * Worker analytics metrics for a specific time period */ export interface WorkerMetrics { /** Worker ID */ workerId: string; /** Time period start (Unix timestamp) */ periodStart: number; /** Time period end (Unix timestamp) */ periodEnd: number; /** Total beads completed in this period */ beadsCompleted: number; /** Beads per hour (rate) */ beadsPerHour: number; /** Average completion time per bead (milliseconds) */ avgCompletionTimeMs: number; /** Total errors encountered */ errorCount: number; /** Error rate (errors per bead) */ errorRate: number; /** Total cost incurred (USD) */ totalCostUsd: number; /** Cost per bead (USD) */ costPerBead: number; /** Total active time (milliseconds) */ activeTimeMs: number; /** Total idle time (milliseconds) */ idleTimeMs: number; /** Idle percentage (0-100) */ idlePercentage: number; /** Total events processed */ totalEvents: number; /** Total tokens used */ totalTokens: number; /** Tokens per bead */ tokensPerBead: number; /** Efficiency score (0-1, calculated from active time vs idle time) */ efficiencyScore: number; /** Performance trend data */ trend?: { direction: 'improving' | 'declining' | 'stable'; confidence: number; factors: string[]; }; } /** * Time-series data point for worker metrics */ export interface MetricsDataPoint { /** Timestamp of this data point */ timestamp: number; /** Worker ID */ workerId: string; /** Metrics snapshot at this time */ metrics: Partial; } /** * Worker performance trend */ export interface PerformanceTrend { /** Worker ID */ workerId: string; /** Metric being tracked */ metric: keyof WorkerMetrics; /** Time-series data points */ dataPoints: MetricsDataPoint[]; /** Trend direction: 'improving' | 'declining' | 'stable' */ trend: 'improving' | 'declining' | 'stable'; /** Percentage change from first to last data point */ changePercent: number; /** Average value across all data points */ average: number; /** Minimum value */ min: number; /** Maximum value */ max: number; } /** * Aggregated analytics across all workers */ export interface AggregatedAnalytics { /** Time period covered */ periodStart: number; periodEnd: number; /** Total workers tracked */ totalWorkers: number; /** Total beads completed */ totalBeadsCompleted: number; /** Average beads per hour across all workers */ avgBeadsPerHour: number; /** Average completion time across all workers */ avgCompletionTimeMs: number; /** Total errors across all workers */ totalErrors: number; /** Overall error rate */ overallErrorRate: number; /** Total cost across all workers */ totalCostUsd: number; /** Average cost per bead */ avgCostPerBead: number; /** Top performers (sorted by beads completed) */ topPerformers: WorkerMetrics[]; /** Workers with highest error rates */ highErrorRateWorkers: WorkerMetrics[]; /** Most cost-efficient workers (lowest cost per bead) */ costEfficientWorkers: WorkerMetrics[]; /** Number of currently active workers */ activeWorkerCount: number; /** Total tokens used across all workers */ totalTokens: number; /** Average efficiency across all workers */ avgEfficiency: number; /** Underperforming workers (high error rate or low efficiency) */ underperformers: WorkerMetrics[]; } /** * Options for worker analytics */ export interface WorkerAnalyticsOptions { /** Time window for aggregation */ timeWindow?: TimeWindow; /** Custom start time (overrides timeWindow) */ startTime?: number; /** Custom end time (overrides timeWindow) */ endTime?: number; /** Filter by specific worker IDs */ workerIds?: string[]; /** Minimum beads completed to be included */ minBeadsCompleted?: number; /** Maximum workers to return in rankings */ maxWorkers?: number; /** Include time-series data */ includeTimeSeries?: boolean; /** Time-series data point interval (milliseconds) */ timeSeriesInterval?: number; } /** * Worker analytics store interface */ export interface WorkerAnalyticsStore { /** Process an event and update analytics */ processEvent(event: LogEvent): void; /** Get metrics for a specific worker */ getWorkerMetrics(workerId: string, options?: WorkerAnalyticsOptions): WorkerMetrics | undefined; /** Get metrics for all workers */ getAllWorkerMetrics(options?: WorkerAnalyticsOptions): WorkerMetrics[]; /** Get aggregated analytics */ getAggregatedAnalytics(options?: WorkerAnalyticsOptions): AggregatedAnalytics; /** Get performance trends */ getPerformanceTrends(workerId: string, metric: keyof WorkerMetrics, options?: WorkerAnalyticsOptions): PerformanceTrend; /** Get time-series data */ getTimeSeriesData(workerId: string, options?: WorkerAnalyticsOptions): MetricsDataPoint[]; /** Clear all analytics data */ clear(): void; /** Get analytics summary as formatted string */ getSummary(options?: WorkerAnalyticsOptions): string; } /** * Worker comparison result - side-by-side comparison of two workers */ export interface WorkerComparison { /** First worker metrics */ worker1: WorkerMetrics; /** Second worker metrics */ worker2: WorkerMetrics; /** Metric differences (worker1 - worker2, positive means worker1 is higher) */ differences: { beadsCompleted: number; beadsPerHour: number; avgCompletionTimeMs: number; errorRate: number; costPerBead: number; efficiencyScore: number; }; /** Percentage differences (worker1 relative to worker2) */ percentDifferences: { beadsCompleted: number; beadsPerHour: number; avgCompletionTimeMs: number; errorRate: number; costPerBead: number; efficiencyScore: number; }; /** Which worker is better for each metric */ betterWorker: { beadsCompleted: 'worker1' | 'worker2' | 'tie'; beadsPerHour: 'worker1' | 'worker2' | 'tie'; avgCompletionTimeMs: 'worker1' | 'worker2' | 'tie'; errorRate: 'worker1' | 'worker2' | 'tie'; costPerBead: 'worker1' | 'worker2' | 'tie'; efficiencyScore: 'worker1' | 'worker2' | 'tie'; }; /** Overall winner based on majority of metrics */ overallWinner: 'worker1' | 'worker2' | 'tie'; /** Score tally for determining overall winner */ score: { worker1: number; worker2: number }; } // ============================================ // Semantic Narrative Types // ============================================ /** * Narrative style for summarization */ export type NarrativeStyle = 'brief' | 'detailed' | 'timeline' | 'technical'; /** * Event pattern types that drive narrative generation */ export type EventPattern = | 'bead_started' // Worker started working on a bead | 'bead_completed' // Worker completed a bead | 'file_editing' // Editing files | 'file_created' // Creating new files | 'testing' // Running tests | 'debugging' // Debugging errors | 'git_operations' // Git commits, pushes, etc. | 'dependency_install' // Installing dependencies | 'collision_detected' // Workers colliding | 'error_recovery' // Recovering from errors | 'iteration' // Iterative refinement | 'investigation' // Investigating/researching | 'tool_usage' // Tool usage patterns | 'error_handling' // Error handling patterns | 'task_completion' // Task completion patterns | 'exploration' // Exploration patterns | 'planning' // Planning patterns | 'research'; // Research patterns /** * A single narrative segment describing a sequence of events */ export interface NarrativeSegment { /** Unique segment ID */ id: string; /** Event pattern this segment describes */ pattern: EventPattern; /** Natural language summary */ summary: string; /** Detailed narrative (if available) */ details?: string; /** Start timestamp */ startTime: number; /** End timestamp */ endTime: number; /** Duration in milliseconds */ durationMs: number; /** Worker ID */ workerId: string; /** Associated bead (if any) */ beadId?: string; /** Events that comprise this segment */ events: LogEvent[]; /** Key entities mentioned (files, tools, etc.) */ entities: { files?: string[]; tools?: string[]; beads?: string[]; errors?: string[]; }; /** Confidence in pattern detection (0-1) */ confidence: number; /** Whether this segment is still active/ongoing */ isActive: boolean; } /** * A complete narrative for a worker session or time period */ export interface SemanticNarrative { /** Narrative ID */ id: string; /** Worker ID (or 'all' for multi-worker narratives) */ workerId: string; /** Narrative title */ title: string; /** High-level summary (1-2 sentences) */ summary: string; /** All narrative segments in chronological order */ segments: NarrativeSegment[]; /** Full narrative text */ fullNarrative: string; /** Timeline of key events */ timeline: string[]; /** Start timestamp */ startTime: number; /** End timestamp */ endTime: number; /** Total duration */ durationMs: number; /** Key accomplishments */ accomplishments: string[]; /** Challenges encountered */ challenges: string[]; /** Overall sentiment: 'productive' | 'struggling' | 'mixed' | 'idle' */ sentiment: 'productive' | 'struggling' | 'mixed' | 'idle'; /** Statistics */ stats: { totalEvents: number; segmentCount: number; beadsWorked: number; filesModified: number; errorsEncountered: number; toolsUsed: number; }; /** When this narrative was generated */ generatedAt: number; /** Whether this narrative is still being updated */ isLive: boolean; } /** * Options for narrative generation */ export interface NarrativeOptions { /** Narrative style */ style?: NarrativeStyle; /** Filter by worker ID */ workerId?: string; /** Filter by bead ID */ beadId?: string; /** Time range start */ startTime?: number; /** Time range end */ endTime?: number; /** Minimum confidence for pattern detection */ minConfidence?: number; /** Maximum segments to generate */ maxSegments?: number; /** Include technical details */ includeTechnicalDetails?: boolean; /** Include timeline */ includeTimeline?: boolean; /** Group events by time window (ms) */ segmentWindowMs?: number; /** Minimum events per segment */ minEventsPerSegment?: number; } /** * Narrative update event - emitted when narrative changes */ export interface NarrativeUpdate { /** Narrative ID */ narrativeId: string; /** Update type */ type: 'segment_added' | 'segment_updated' | 'segment_completed' | 'narrative_completed'; /** Updated segment (if applicable) */ segment?: NarrativeSegment; /** Timestamp of update */ timestamp: number; /** New summary text */ summary?: string; } /** * Semantic narrative manager interface */ export interface SemanticNarrativeManager { /** Process an event and update narratives */ processEvent(event: LogEvent): void; /** Generate narrative for a worker */ generateNarrative(workerId: string, options?: NarrativeOptions): SemanticNarrative; /** Generate narrative for all workers */ generateAggregatedNarrative(options?: NarrativeOptions): SemanticNarrative; /** Get current active narratives */ getActiveNarratives(): SemanticNarrative[]; /** Get narrative by ID */ getNarrative(narrativeId: string): SemanticNarrative | undefined; /** Subscribe to narrative updates */ onUpdate(callback: (update: NarrativeUpdate) => void): () => void; /** Clear all narratives */ clear(): void; /** Get narrative as formatted string */ formatNarrative(narrative: SemanticNarrative, style?: NarrativeStyle): string; } // ============================================ // Worker Fleet Analytics Types // ============================================ /** * Duration bucket for bead completion histogram */ export type DurationBucket = '<5s' | '5-30s' | '30-120s' | '2-10m' | '10m+'; /** * Model performance metrics */ export interface ModelPerformanceMetrics { /** Model identifier (e.g., 'sonnet', 'glm-4.7', 'gpt-4o') */ model: string; /** Provider (e.g., 'anthropic', 'openai', 'glm') */ provider: string; /** Total beads completed */ beadsCompleted: number; /** Average bead duration in ms */ avgDurationMs: number; /** Median bead duration in ms */ medianDurationMs: number; /** Duration distribution histogram */ durationDistribution: Record; /** Success rate (0-1) */ successRate: number; /** Total errors */ errorCount: number; /** Total cost in USD */ totalCostUsd: number; /** Average cost per bead */ avgCostPerBead: number; } /** * Strand utilization metrics */ export interface StrandMetrics { /** Strand name (pluck, mend, explore, weave, pulse, unravel, knot) */ strand: string; /** Number of invocations */ invocations: number; /** Number of successful invocations (found work) */ successCount: number; /** Success rate (0-1) */ successRate: number; /** Total time spent in ms */ totalTimeMs: number; /** Average time per invocation in ms */ avgTimeMs: number; /** Beads created by this strand (for weave, explore, etc.) */ beadsCreated?: number; } /** * Completion quality indicator */ export interface CompletionQualityIndicator { /** Bead ID */ beadId: string; /** Worker that completed */ workerId: string; /** Model used */ model: string; /** Duration in ms */ durationMs: number; /** Quality flags */ flags: { /** Completed in <10s - suspicious shallow */ isShallow: boolean; /** Had git commits */ hadCommits: boolean; /** Was reopened after closure */ wasReopened: boolean; /** Was claimed by multiple workers (race) */ hadClaimRace: boolean; }; /** Completion timestamp */ completedAt: number; } /** * Fleet time series data point */ export interface FleetTimeSeriesPoint { /** Timestamp */ ts: number; /** Active worker count */ activeWorkers: number; /** Beads completed in this bucket */ beadsCompleted: number; /** Errors in this bucket */ errors: number; /** Cost in this bucket */ costUsd: number; } /** * Workspace coverage info */ export interface WorkspaceCoverage { /** Workspace path */ path: string; /** Active workers in this workspace */ activeWorkers: number; /** Total beads worked on */ beadsWorked: number; /** Last activity timestamp */ lastActivity: number; /** Worker IDs */ workers: string[]; } /** * Complete fleet analytics data */ export interface FleetAnalytics { /** Time range covered */ timeRange: { start: number; end: number; windowLabel: string; }; /** Model performance breakdown */ modelPerformance: ModelPerformanceMetrics[]; /** Strand utilization */ strandMetrics: StrandMetrics[]; /** Quality indicators */ qualityIndicators: { /** Total shallow completions (<10s) */ shallowCompletions: number; /** Completions with git commits */ completionsWithCommits: number; /** Reopened beads */ reopenedBeads: number; /** Claim races */ claimRaces: number; /** Recent suspicious completions */ suspiciousCompletions: CompletionQualityIndicator[]; }; /** Fleet overview */ fleetOverview: { /** Total unique workers seen */ totalWorkers: number; /** Currently active workers */ activeWorkers: number; /** Total beads completed */ totalBeadsCompleted: number; /** Total errors */ totalErrors: number; /** Bead throughput per hour */ beadsPerHour: number; /** Watchdog relaunch count */ watchdogRelaunchCount: number; /** Workspace coverage */ workspaces: WorkspaceCoverage[]; }; /** Time series data */ timeSeries: FleetTimeSeriesPoint[]; } /** * Options for fleet analytics queries */ export interface FleetAnalyticsOptions { /** Time window */ timeWindow?: TimeWindow; /** Custom start time */ startTime?: number; /** Custom end time */ endTime?: number; /** Include time series data */ includeTimeSeries?: boolean; /** Time series bucket size in minutes */ timeSeriesBucketMinutes?: number; /** Filter by model */ modelFilter?: string; /** Maximum suspicious completions to return */ maxSuspiciousCompletions?: number; }