ai-dispatch 10.40.0

Multi-AI CLI team orchestrator
// Canvas-drawn mission state marks — star, cross, play, pause.
// Exports: StateMark.

import SwiftUI

struct StateMark: View {
    @Environment(\.theme) private var theme
    let state: MissionDisplayState
    var size: CGFloat = 13

    var body: some View {
        markPath
            .stroke(color, style: StrokeStyle(lineWidth: strokeWidth, lineCap: .round, lineJoin: .round))
            .frame(width: size, height: size)
            .modifier(GlyphQuantizer(enabled: theme.motion.stepped))
    }

    private var color: Color {
        switch state {
        case .run: return theme.run
        case .done: return theme.done
        case .fail: return theme.fail
        case .stop: return theme.stop
        }
    }

    private var strokeWidth: CGFloat {
        theme.motion.stepped ? 2 : 1.5
    }

    private var markPath: Path {
        let box = CGRect(x: 0, y: 0, width: size, height: size)
        switch state {
        case .run:
            return play(in: box)
        case .done:
            return star(in: box)
        case .fail:
            return cross(in: box)
        case .stop:
            return pause(in: box)
        }
    }

    private func play(in box: CGRect) -> Path {
        Path { path in
            let inset = box.width * 0.18
            path.move(to: CGPoint(x: box.minX + inset, y: box.minY + inset))
            path.addLine(to: CGPoint(x: box.maxX - inset, y: box.midY))
            path.addLine(to: CGPoint(x: box.minX + inset, y: box.maxY - inset))
            path.closeSubpath()
        }
    }

    private func star(in box: CGRect) -> Path {
        Path { path in
            let cx = box.midX
            let cy = box.midY
            let outer = box.width * 0.46
            let inner = box.width * 0.14
            path.move(to: CGPoint(x: cx, y: cy - outer))
            path.addLine(to: CGPoint(x: cx + inner, y: cy - inner))
            path.addLine(to: CGPoint(x: cx + outer, y: cy))
            path.addLine(to: CGPoint(x: cx + inner, y: cy + inner))
            path.addLine(to: CGPoint(x: cx, y: cy + outer))
            path.addLine(to: CGPoint(x: cx - inner, y: cy + inner))
            path.addLine(to: CGPoint(x: cx - outer, y: cy))
            path.addLine(to: CGPoint(x: cx - inner, y: cy - inner))
            path.closeSubpath()
        }
    }

    private func cross(in box: CGRect) -> Path {
        Path { path in
            let inset = box.width * 0.22
            path.move(to: CGPoint(x: box.minX + inset, y: box.minY + inset))
            path.addLine(to: CGPoint(x: box.maxX - inset, y: box.maxY - inset))
            path.move(to: CGPoint(x: box.maxX - inset, y: box.minY + inset))
            path.addLine(to: CGPoint(x: box.minX + inset, y: box.maxY - inset))
        }
    }

    private func pause(in box: CGRect) -> Path {
        Path { path in
            let barW = box.width * 0.22
            let inset = box.width * 0.18
            let top = box.minY + inset
            let bottom = box.maxY - inset
            path.addRect(CGRect(x: box.minX + inset, y: top, width: barW, height: bottom - top))
            path.addRect(CGRect(x: box.maxX - inset - barW, y: top, width: barW, height: bottom - top))
        }
    }
}