- output-renderer, hashline-edit-diff: replace str += with array join (H2) - auto-slash-command: single-pass Map grouping instead of 6x filter (M1) - comment-checker: hoist Zod schema to module scope (M2) - session-last-agent: reverse iterate sorted array instead of sort+reverse (L2)
91 lines
2.2 KiB
TypeScript
91 lines
2.2 KiB
TypeScript
import pc from "picocolors"
|
|
|
|
export function renderAgentHeader(
|
|
agent: string | null,
|
|
model: string | null,
|
|
variant: string | null,
|
|
agentColorsByName: Record<string, string>,
|
|
): void {
|
|
if (!agent && !model) return
|
|
|
|
const agentLabel = agent
|
|
? pc.bold(colorizeWithProfileColor(agent, agentColorsByName[agent]))
|
|
: ""
|
|
const modelBase = model ?? ""
|
|
const variantSuffix = variant ? ` (${variant})` : ""
|
|
const modelLabel = model ? pc.dim(`${modelBase}${variantSuffix}`) : ""
|
|
|
|
process.stdout.write("\n")
|
|
|
|
if (modelLabel) {
|
|
process.stdout.write(` ${modelLabel} \n`)
|
|
}
|
|
|
|
if (agentLabel) {
|
|
process.stdout.write(` ${pc.dim("└─")} ${agentLabel} \n`)
|
|
}
|
|
|
|
process.stdout.write("\n")
|
|
}
|
|
|
|
export function openThinkBlock(): void {
|
|
process.stdout.write(`\n ${pc.dim("┃ Thinking:")} `)
|
|
}
|
|
|
|
export function closeThinkBlock(): void {
|
|
process.stdout.write(" \n\n")
|
|
}
|
|
|
|
export function writePaddedText(
|
|
text: string,
|
|
atLineStart: boolean,
|
|
): { output: string; atLineStart: boolean } {
|
|
const isGitHubActions = process.env.GITHUB_ACTIONS === "true"
|
|
if (isGitHubActions) {
|
|
return { output: text, atLineStart: text.endsWith("\n") }
|
|
}
|
|
|
|
const parts: string[] = []
|
|
let lineStart = atLineStart
|
|
|
|
for (let i = 0; i < text.length; i++) {
|
|
const ch = text[i]
|
|
if (lineStart) {
|
|
parts.push(" ")
|
|
lineStart = false
|
|
}
|
|
|
|
if (ch === "\n") {
|
|
parts.push(" \n")
|
|
lineStart = true
|
|
continue
|
|
}
|
|
|
|
parts.push(ch)
|
|
}
|
|
|
|
return { output: parts.join(""), atLineStart: lineStart }
|
|
}
|
|
|
|
function colorizeWithProfileColor(text: string, hexColor?: string): string {
|
|
if (!hexColor) return pc.magenta(text)
|
|
|
|
const rgb = parseHexColor(hexColor)
|
|
if (!rgb) return pc.magenta(text)
|
|
|
|
const [r, g, b] = rgb
|
|
return `\u001b[38;2;${r};${g};${b}m${text}\u001b[39m`
|
|
}
|
|
|
|
function parseHexColor(hexColor: string): [number, number, number] | null {
|
|
const cleaned = hexColor.trim()
|
|
const match = cleaned.match(/^#?([A-Fa-f0-9]{6})$/)
|
|
if (!match) return null
|
|
|
|
const hex = match[1]
|
|
const r = Number.parseInt(hex.slice(0, 2), 16)
|
|
const g = Number.parseInt(hex.slice(2, 4), 16)
|
|
const b = Number.parseInt(hex.slice(4, 6), 16)
|
|
return [r, g, b]
|
|
}
|