{"version":3,"file":"terminal-title.d.ts","sourceRoot":"","sources":["../../src/core/terminal-title.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAOH;;;GAGG;AACH,MAAM,WAAW,aAAa;IAC7B,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B;AAED;;;;;;;;GAQG;AACH,qBAAa,aAAa;IACzB,OAAO,CAAC,aAAa,CAAS;IAC9B,OAAO,CAAC,QAAQ,CAAgB;IAChC,OAAO,CAAC,YAAY,CAAK;IACzB,OAAO,CAAC,eAAe,CAA6C;IACpE,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,KAAK,CAAU;IAEvB,YAAY,QAAQ,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,EAIzD;IAED;;;;OAIG;IACH,UAAU,CAAC,aAAa,EAAE,MAAM,GAAG,IAAI,CAKtC;IAED;;;;OAIG;IACH,UAAU,CAAC,MAAM,EAAE,OAAO,GAAG,IAAI,CAahC;IAED;;;OAGG;IACH,OAAO,IAAI,IAAI,CAOd;IAED;;OAEG;IACH,OAAO,CAAC,WAAW;IAMnB;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAQzB;;OAEG;IACH,OAAO,CAAC,UAAU;IAQlB,OAAO,CAAC,YAAY;IAapB,OAAO,CAAC,WAAW;CAOnB","sourcesContent":["/**\n * Terminal title manager with animated working indicator.\n *\n * Provides a centralized controller for terminal window/tab titles.\n * - Static title: \"Jensen - <workspace>\"\n * - Working title: \"<spinner> Jensen - <workspace>\" with animated braille spinner\n *\n * The spinner is active during agent work cycles and stops when the agent\n * is idle, waiting for user input, cancelled, or errored.\n */\n\nconst SPINNER_FRAMES = [\"⠋\", \"⠙\", \"⠹\", \"⠸\", \"⠼\", \"⠴\", \"⠦\", \"⠧\", \"⠇\", \"⠏\"];\n\n/** Interval between spinner frame updates in milliseconds */\nconst SPINNER_INTERVAL_MS = 100;\n\n/**\n * Minimal terminal interface for title operations.\n * Accepts any object with a setTitle method.\n */\nexport interface TitleTerminal {\n\tsetTitle(title: string): void;\n}\n\n/**\n * Manages the terminal window/tab title with optional animated spinner.\n *\n * Thread-safe and idempotent:\n * - Multiple setWorking(true) calls create at most one animation interval\n * - setWorking(false) is safe to call repeatedly\n * - dispose() cleans up all timers and prevents further writes\n * - Graceful no-op when stdout is not a TTY\n */\nexport class TerminalTitle {\n\tprivate workspaceName: string;\n\tprivate terminal: TitleTerminal;\n\tprivate spinnerIndex = 0;\n\tprivate spinnerInterval: ReturnType<typeof setInterval> | undefined;\n\tprivate isWorking = false;\n\tprivate isDisposed = false;\n\tprivate isTty: boolean;\n\n\tconstructor(terminal: TitleTerminal, workspaceName: string) {\n\t\tthis.terminal = terminal;\n\t\tthis.workspaceName = workspaceName;\n\t\tthis.isTty = process.stdout.isTTY === true;\n\t}\n\n\t/**\n\t * Set the initial static title.\n\t * Safe to call multiple times — overwrites the workspace name and resets to static title.\n\t * If a spinner is active, it is stopped first.\n\t */\n\tinitialize(workspaceName: string): void {\n\t\tthis.workspaceName = workspaceName;\n\t\tthis.isWorking = false;\n\t\tthis.stopSpinner();\n\t\tthis.writeStatic();\n\t}\n\n\t/**\n\t * Enable or disable the animated spinner.\n\t * When active, the title cycles through spinner frames.\n\t * When inactive, reverts to the static title.\n\t */\n\tsetWorking(active: boolean): void {\n\t\tif (this.isDisposed) return;\n\n\t\tif (active) {\n\t\t\tif (this.isWorking) return; // Already working, no-op\n\t\t\tthis.isWorking = true;\n\t\t\tthis.startSpinner();\n\t\t} else {\n\t\t\tif (!this.isWorking) return; // Already idle, no-op\n\t\t\tthis.isWorking = false;\n\t\t\tthis.stopSpinner();\n\t\t\tthis.writeStatic();\n\t\t}\n\t}\n\n\t/**\n\t * Stop the spinner and prevent any further title writes.\n\t * Safe to call multiple times.\n\t */\n\tdispose(): void {\n\t\tif (this.isDisposed) return;\n\t\tthis.isDisposed = true;\n\t\tthis.isWorking = false;\n\t\tthis.stopSpinner();\n\t\t// Deliberately do NOT restore the title on dispose —\n\t\t// the terminal session is ending and the title will be reclaimed by the shell.\n\t}\n\n\t/**\n\t * Immediately write the static title to the terminal.\n\t */\n\tprivate writeStatic(): void {\n\t\tif (!this.isTty || this.isDisposed) return;\n\t\tconst title = `Jensen - ${this.workspaceName}`;\n\t\tthis.writeTitle(title);\n\t}\n\n\t/**\n\t * Write the current spinner frame to the terminal title.\n\t */\n\tprivate writeSpinnerFrame(): void {\n\t\tif (!this.isTty || this.isDisposed || !this.isWorking) return;\n\t\tconst frame = SPINNER_FRAMES[this.spinnerIndex];\n\t\tthis.spinnerIndex = (this.spinnerIndex + 1) % SPINNER_FRAMES.length;\n\t\tconst title = `${frame} Jensen - ${this.workspaceName}`;\n\t\tthis.writeTitle(title);\n\t}\n\n\t/**\n\t * Write a title to the terminal using OSC sequence.\n\t */\n\tprivate writeTitle(title: string): void {\n\t\ttry {\n\t\t\tthis.terminal.setTitle(title);\n\t\t} catch {\n\t\t\t// Terminal writes may fail if the fd is closed; ignore\n\t\t}\n\t}\n\n\tprivate startSpinner(): void {\n\t\tif (this.spinnerInterval !== undefined) return; // Already running\n\t\t// Write first frame immediately\n\t\tthis.writeSpinnerFrame();\n\t\tthis.spinnerInterval = setInterval(() => {\n\t\t\tthis.writeSpinnerFrame();\n\t\t}, SPINNER_INTERVAL_MS);\n\t\t// Don't let the interval keep the process alive\n\t\tif (this.spinnerInterval && typeof this.spinnerInterval === \"object\" && \"unref\" in this.spinnerInterval) {\n\t\t\tthis.spinnerInterval.unref();\n\t\t}\n\t}\n\n\tprivate stopSpinner(): void {\n\t\tif (this.spinnerInterval !== undefined) {\n\t\t\tclearInterval(this.spinnerInterval);\n\t\t\tthis.spinnerInterval = undefined;\n\t\t}\n\t\tthis.spinnerIndex = 0;\n\t}\n}\n"]}