{"version":3,"file":"SubagentOverlay.d.ts","sourceRoot":"","sources":["../../src/components/SubagentOverlay.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAG3C,OAAO,EAAE,aAAa,EAAE,CAAC;AAEzB,MAAM,WAAW,gBAAgB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,SAAS,GAAG,MAAM,GAAG,OAAO,GAAG,QAAQ,CAAC;IAChD,KAAK,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,gBAAgB;IAChC,sEAAsE;IACtE,IAAI,IAAI,gBAAgB,EAAE,CAAC;IAC3B,6DAA6D;IAC7D,SAAS,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC;CAC5C;AAED,yDAAyD;AACzD,eAAO,MAAM,sBAAsB,EAAE,gBAGpC,CAAC;AAEF,MAAM,WAAW,oBAAoB;IACpC,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IACjC,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IACjC,GAAG,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IAC9B,KAAK,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IAChC,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IACjC,KAAK,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;CAChC;AAWD,MAAM,WAAW,sBAAsB;IACtC,QAAQ,CAAC,EAAE,gBAAgB,CAAC;IAC5B,KAAK,CAAC,EAAE,oBAAoB,CAAC;IAC7B,OAAO,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,qBAAa,eAAgB,YAAW,SAAS;IAChD,OAAO,CAAC,QAAQ,CAAmB;IACnC,OAAO,CAAC,KAAK,CAAuB;IACpC,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,WAAW,CAAC,CAAa;IACjC,OAAO,CAAC,MAAM,CAAC,CAAa;IAE5B,YAAY,OAAO,GAAE,sBAA2B,EAI/C;IAED,4EAA4E;IAC5E,WAAW,CAAC,QAAQ,EAAE,gBAAgB,GAAG,IAAI,CAI5C;IAED,yEAAyE;IACzE,UAAU,CAAC,MAAM,EAAE,MAAM,IAAI,GAAG,IAAI,CAKnC;IAED,OAAO,IAAI,IAAI,CAId;IAED,UAAU,IAAI,IAAI,CAEjB;IAED,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAoB9B;IAED,OAAO,CAAC,SAAS;IAWjB,OAAO,CAAC,WAAW;IAanB,OAAO,CAAC,SAAS;IAWjB,OAAO,CAAC,eAAe;IAOvB,OAAO,CAAC,QAAQ;CAKhB","sourcesContent":["/**\n * Subagent observability overlay.\n *\n * F2 toggles a live tree of running subagents (current tool, token spend,\n * elapsed). Until WS6 ships the Task tool + global subagent registry this\n * overlay subscribes to a no-op registry that emits an empty snapshot. Once\n * WS6 lands, `setRegistry()` will receive a real registry and the overlay\n * begins rendering rows.\n */\nimport { formatElapsed } from \"../format-elapsed.js\";\nimport type { Component } from \"../tui.js\";\nimport { visibleWidth } from \"../utils.js\";\n\nexport { formatElapsed };\n\nexport interface SubagentSnapshot {\n\tid: string;\n\tname: string;\n\tcurrentTool?: string;\n\ttokensIn: number;\n\ttokensOut: number;\n\telapsedMs: number;\n\tstatus: \"running\" | \"done\" | \"error\" | \"queued\";\n\tdepth?: number;\n}\n\nexport interface SubagentRegistry {\n\t/** Read current snapshot of every active subagent. WS6 wires this. */\n\tlist(): SubagentSnapshot[];\n\t/** Subscribe to changes. Returns an unsubscribe function. */\n\tsubscribe(listener: () => void): () => void;\n}\n\n/** Empty registry used until WS6 lands the Task tool. */\nexport const NULL_SUBAGENT_REGISTRY: SubagentRegistry = {\n\tlist: () => [],\n\tsubscribe: () => () => {},\n};\n\nexport interface SubagentOverlayTheme {\n\tborder: (text: string) => string;\n\theader: (text: string) => string;\n\trow: (text: string) => string;\n\tmuted: (text: string) => string;\n\taccent: (text: string) => string;\n\terror: (text: string) => string;\n}\n\nconst IDENTITY: SubagentOverlayTheme = {\n\tborder: (s) => s,\n\theader: (s) => s,\n\trow: (s) => s,\n\tmuted: (s) => s,\n\taccent: (s) => s,\n\terror: (s) => s,\n};\n\nexport interface SubagentOverlayOptions {\n\tregistry?: SubagentRegistry;\n\ttheme?: SubagentOverlayTheme;\n\tmaxRows?: number;\n}\n\nexport class SubagentOverlay implements Component {\n\tprivate registry: SubagentRegistry;\n\tprivate theme: SubagentOverlayTheme;\n\tprivate maxRows: number;\n\tprivate unsubscribe?: () => void;\n\tprivate redraw?: () => void;\n\n\tconstructor(options: SubagentOverlayOptions = {}) {\n\t\tthis.registry = options.registry ?? NULL_SUBAGENT_REGISTRY;\n\t\tthis.theme = options.theme ?? IDENTITY;\n\t\tthis.maxRows = options.maxRows ?? 12;\n\t}\n\n\t/** Wire a new registry (e.g. when WS6 lands and registers the real one). */\n\tsetRegistry(registry: SubagentRegistry): void {\n\t\tif (this.unsubscribe) this.unsubscribe();\n\t\tthis.registry = registry;\n\t\tthis.unsubscribe = registry.subscribe(() => this.redraw?.());\n\t}\n\n\t/** Bind a redraw callback so registry events trigger a TUI re-render. */\n\tbindRedraw(redraw: () => void): void {\n\t\tthis.redraw = redraw;\n\t\tif (!this.unsubscribe) {\n\t\t\tthis.unsubscribe = this.registry.subscribe(() => this.redraw?.());\n\t\t}\n\t}\n\n\tdispose(): void {\n\t\tif (this.unsubscribe) this.unsubscribe();\n\t\tthis.unsubscribe = undefined;\n\t\tthis.redraw = undefined;\n\t}\n\n\tinvalidate(): void {\n\t\t// Stateless render — nothing to clear.\n\t}\n\n\trender(width: number): string[] {\n\t\tconst snapshot = this.registry.list();\n\t\tif (snapshot.length === 0) {\n\t\t\treturn [\n\t\t\t\tthis.theme.header(this.padRight(\"Subagents\", width)),\n\t\t\t\tthis.theme.muted(this.padRight(\"(none running — F2 to dismiss)\", width)),\n\t\t\t];\n\t\t}\n\n\t\tconst rows: string[] = [];\n\t\trows.push(this.theme.header(this.padRight(`Subagents (${snapshot.length})`, width)));\n\n\t\tconst visible = snapshot.slice(0, this.maxRows);\n\t\tfor (const sa of visible) {\n\t\t\trows.push(this.formatRow(sa, width));\n\t\t}\n\t\tif (snapshot.length > this.maxRows) {\n\t\t\trows.push(this.theme.muted(this.padRight(`… +${snapshot.length - this.maxRows} more`, width)));\n\t\t}\n\t\treturn rows;\n\t}\n\n\tprivate formatRow(sa: SubagentSnapshot, width: number): string {\n\t\tconst indent = \"  \".repeat(sa.depth ?? 0);\n\t\tconst status = this.statusBadge(sa.status);\n\t\tconst tool = sa.currentTool ? `[${sa.currentTool}]` : \"\";\n\t\tconst tokens = `${sa.tokensIn}/${sa.tokensOut}`;\n\t\tconst elapsed = formatElapsed(sa.elapsedMs);\n\t\tconst left = `${indent}${status} ${sa.name} ${tool}`;\n\t\tconst right = `${tokens} ${elapsed}`;\n\t\treturn this.theme.row(this.layoutRow(left, right, width));\n\t}\n\n\tprivate statusBadge(status: SubagentSnapshot[\"status\"]): string {\n\t\tswitch (status) {\n\t\t\tcase \"running\":\n\t\t\t\treturn this.theme.accent(\"●\");\n\t\t\tcase \"done\":\n\t\t\t\treturn this.theme.muted(\"○\");\n\t\t\tcase \"error\":\n\t\t\t\treturn this.theme.error(\"✗\");\n\t\t\tcase \"queued\":\n\t\t\t\treturn this.theme.muted(\"◌\");\n\t\t}\n\t}\n\n\tprivate layoutRow(left: string, right: string, width: number): string {\n\t\tconst leftW = visibleWidth(left);\n\t\tconst rightW = visibleWidth(right);\n\t\tconst gap = Math.max(1, width - leftW - rightW);\n\t\tif (leftW + rightW + 1 > width) {\n\t\t\t// Truncate left to make room.\n\t\t\treturn `${this.truncateVisible(left, Math.max(0, width - rightW - 1))} ${right}`;\n\t\t}\n\t\treturn `${left}${\" \".repeat(gap)}${right}`;\n\t}\n\n\tprivate truncateVisible(s: string, max: number): string {\n\t\tif (visibleWidth(s) <= max) return s;\n\t\t// Coarse truncation; ANSI-aware truncation lives in utils but for the\n\t\t// overlay row we never embed ANSI (theme is applied to the whole row).\n\t\treturn `${s.slice(0, Math.max(0, max - 1))}…`;\n\t}\n\n\tprivate padRight(s: string, width: number): string {\n\t\tconst w = visibleWidth(s);\n\t\tif (w >= width) return s;\n\t\treturn s + \" \".repeat(width - w);\n\t}\n}\n"]}