{"version":3,"file":"formatters.d.ts","sourceRoot":"","sources":["../../../src/shared/formatters.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAE/C,OAAO,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAEtD;;GAEG;AACH,wBAAgB,YAAY,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAE9C;AAED,wBAAgB,mBAAmB,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAU7E;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAU5D;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAIjD;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAChC,KAAK,EAAE,SAAS,EAAE,EAClB,OAAO,EAAE,YAAY,EAAE,EACvB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,WAAW,GAAG,QAAQ,EAC9B,UAAU,CAAC,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAC3C,MAAM,CAoCR;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,QAAQ,UAAQ,GAAG,MAAM,CAoBpG;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAM7C","sourcesContent":["/**\n * Formatting utilities for display output\n */\n\nimport * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport { splitKnownThinkingSuffix, THINKING_LEVELS } from \"./model-info.ts\";\nimport type { ChainStep } from \"./settings.ts\";\nimport { isDynamicParallelStep, isParallelStep } from \"./settings.ts\";\nimport type { SingleResult, Usage } from \"./types.ts\";\n\n/**\n * Format token count with k suffix for large numbers\n */\nexport function formatTokens(n: number): string {\n\treturn n < 1000 ? String(n) : n < 10000 ? `${(n / 1000).toFixed(1)}k` : `${Math.round(n / 1000)}k`;\n}\n\nexport function formatModelThinking(model?: string, thinking?: string): string {\n\tconst parsed = model ? splitKnownThinkingSuffix(model) : undefined;\n\tlet displayModel = parsed?.baseModel ?? model;\n\tconst explicitThinking = THINKING_LEVELS.find((level) => level === thinking?.trim());\n\tconst displayThinking = parsed?.thinkingSuffix ? parsed.thinkingSuffix.slice(1) : explicitThinking;\n\tif (displayModel) {\n\t\tconst slashIdx = displayModel.lastIndexOf(\"/\");\n\t\tif (slashIdx !== -1) displayModel = displayModel.slice(slashIdx + 1);\n\t}\n\treturn [displayModel, displayThinking ? `thinking ${displayThinking}` : undefined].filter(Boolean).join(\" · \");\n}\n\n/**\n * Format usage statistics into a compact string\n */\nexport function formatUsage(u: Usage, model?: string): string {\n\tconst parts: string[] = [];\n\tif (u.turns) parts.push(`${u.turns} turn${u.turns > 1 ? \"s\" : \"\"}`);\n\tif (u.input) parts.push(`in:${formatTokens(u.input)}`);\n\tif (u.output) parts.push(`out:${formatTokens(u.output)}`);\n\tif (u.cacheRead) parts.push(`R${formatTokens(u.cacheRead)}`);\n\tif (u.cacheWrite) parts.push(`W${formatTokens(u.cacheWrite)}`);\n\tif (u.cost) parts.push(`$${u.cost.toFixed(4)}`);\n\tif (model) parts.push(model);\n\treturn parts.join(\" \");\n}\n\n/**\n * Format duration in human-readable form\n */\nexport function formatDuration(ms: number): string {\n\tif (ms < 1000) return `${ms}ms`;\n\tif (ms < 60000) return `${(ms / 1000).toFixed(1)}s`;\n\treturn `${Math.floor(ms / 60000)}m${Math.floor((ms % 60000) / 1000)}s`;\n}\n\n/**\n * Build a summary string for a completed/failed chain\n */\nexport function buildChainSummary(\n\tsteps: ChainStep[],\n\tresults: SingleResult[],\n\tchainDir: string,\n\tstatus: \"completed\" | \"failed\",\n\tfailedStep?: { index: number; error: string },\n): string {\n\tconst stepNames = steps\n\t\t.map((step) =>\n\t\t\tisParallelStep(step)\n\t\t\t\t? `parallel[${step.parallel.length}]`\n\t\t\t\t: isDynamicParallelStep(step)\n\t\t\t\t\t? `expand:${step.parallel.agent}`\n\t\t\t\t\t: step.agent,\n\t\t)\n\t\t.join(\" → \");\n\n\tconst totalDuration = results.reduce((sum, r) => sum + (r.progress?.durationMs || 0), 0);\n\tconst durationStr = formatDuration(totalDuration);\n\n\tconst progressPath = path.join(chainDir, \"progress.md\");\n\tconst hasProgress = fs.existsSync(progressPath);\n\tconst allSkills = new Set<string>();\n\tfor (const r of results) {\n\t\tif (r.skills) r.skills.forEach((s) => allSkills.add(s));\n\t}\n\tconst skillsLine = allSkills.size > 0 ? `🔧 Skills: ${[...allSkills].join(\", \")}` : \"\";\n\n\tif (status === \"completed\") {\n\t\tconst stepWord = results.length === 1 ? \"step\" : \"steps\";\n\t\treturn `✅ Chain completed: ${stepNames} (${results.length} ${stepWord}, ${durationStr})${skillsLine ? `\\n${skillsLine}` : \"\"}\n\n📋 Progress: ${hasProgress ? progressPath : \"(none)\"}\n📁 Artifacts: ${chainDir}`;\n\t} else {\n\t\tconst stepInfo = failedStep ? ` at step ${failedStep.index + 1}` : \"\";\n\t\tconst errorInfo = failedStep?.error ? `: ${failedStep.error}` : \"\";\n\t\treturn `❌ Chain failed${stepInfo}${errorInfo}${skillsLine ? `\\n${skillsLine}` : \"\"}\n\n📋 Progress: ${hasProgress ? progressPath : \"(none)\"}\n📁 Artifacts: ${chainDir}`;\n\t}\n}\n\n/**\n * Format a tool call for display\n */\nexport function formatToolCall(name: string, args: Record<string, unknown>, expanded = false): string {\n\tswitch (name) {\n\t\tcase \"bash\": {\n\t\t\tconst command = typeof args.command === \"string\" ? args.command : \"\";\n\t\t\tconst maxLength = expanded ? 240 : 60;\n\t\t\treturn `$ ${command.slice(0, maxLength)}${command.length > maxLength ? \"...\" : \"\"}`;\n\t\t}\n\t\tcase \"read\":\n\t\tcase \"write\":\n\t\tcase \"edit\": {\n\t\t\tconst target =\n\t\t\t\ttypeof args.path === \"string\" ? args.path : typeof args.file_path === \"string\" ? args.file_path : \"\";\n\t\t\treturn `${name} ${shortenPath(target)}`;\n\t\t}\n\t\tdefault: {\n\t\t\tconst s = JSON.stringify(args);\n\t\t\tconst maxLength = expanded ? 160 : 40;\n\t\t\treturn `${name} ${s.slice(0, maxLength)}${s.length > maxLength ? \"...\" : \"\"}`;\n\t\t}\n\t}\n}\n\n/**\n * Shorten a path by replacing home directory with ~\n */\nexport function shortenPath(p: string): string {\n\tconst home = process.env.HOME;\n\tif (home && p.startsWith(home)) {\n\t\treturn `~${p.slice(home.length)}`;\n\t}\n\treturn p;\n}\n"]}