版本:
v0.3.9+
根路径: 所有模块相对路径均以仓库根目录或~/.codebuddy/codebuddy-hud-runtime/为基准。
runtime/bin/codebuddy-hud.js— CLI 统一入口与执行调度器runtime/parser.js— 宿主输入 JSON 解析与边界清洗runtime/config.js— 多层配置合并与主题调色板引擎runtime/renderer.js— 3 行看板装配与布局编排器runtime/renderer/format.js— 格式化、进度条与 Cache 徽标runtime/renderer/diff-render.js— 代码变更、Credits 与耗时渲染器runtime/renderer/agents-render.js— 工具活动频次聚合渲染器runtime/model-info.js— 推理强度归一化与额度回退runtime/lang.js— 多语言国际化字典与探测器runtime/transcript.js— 逆向滑窗遥测与增量 Checkpoint 状态机runtime/session-stats.js— 会话基线捕获与/clear重置状态机runtime/git.js— Git 分支与 Dirty 状态非阻塞探测器runtime/encoding.js— 终端字符集探测与 Windows 代码页缓存runtime/sanitize.js— 终端文本安全清洗与 ANSI/Bidi 注入防御runtime/paths.js— 跨平台路径解析与状态目录管理runtime/settings-file.js— JSONC 安全解析与配置原子写入runtime/statusline-installer.js— 状态栏注册与 Windows Shim 烘焙器runtime/doctor.js— 环境体检与排障诊断子系统runtime/theme-selector.js— 交互式终端主题选择器runtime/uninstall.js— 卸载还原与状态深度清理器runtime/update-checker.js— 用户主动更新与版本解析scripts/bootstrap.js— 跨平台原子安装引导程序scripts/run-tests.js— 跨平台测试分发驱动脚本scripts/verify-display.js— 看板端到端验证scripts/verify-install.js— 隔离宿主生命周期验证scripts/install.ps1&install.sh— 一键在线安装脚本skills/hud-config/SKILL.md— HUD 配置技能
职责: 状态栏执行入口,注册为 statusLine.command。负责命令行参数分发、stdin 管道超时竞争与异常诊断日志记录、顶层错误捕获与自然 Drain 退出。
--setup [--theme <name>]: 执行安装,写入settings.json、生成 Windows.cmdshim 并自动挂载hud-config技能至~/.codebuddy/skills/(在 TTY 终端运行自动唤起交互主题选择器,也可带--theme <name>直接指定跳过交互;PATH 注册由一键安装脚本完成,--setup不修改 PATH)。--uninstall: 仅当当前statusLine仍指向本 HUD 时按备份还原或移除;清理技能挂载、缓存、PATH 注册及 shim,保留其他 settings 与用户主题配置(详见 §20)。--theme [name|list]: 交互式切换、指定主题或列出主题(如--theme cyberpunk、--theme list)。--doctor [--json],-d: 运行全面诊断体检报告(-d为短参数别名,支持--json输出结构化数据)。--status: 冒烟探测当前状态栏能否正常渲染(3 行输出与 exit 0)。--update: 用户主动更新(检查 + 升级二合一);解析最新 Release tag,落后时下载该 tag 的 bootstrap 并派生后台自举进程,渲染路径零网络契约不受影响。--version, -v: 输出当前 HUD 版本号并退出。--help, -h: 输出命令行全部子命令与参数选项帮助信息并退出。
分发顺序:--version/-v → --help/-h → 其余子命令,查询不读取 stdin、不会执行安装或卸载。--theme --help 或 --theme -h 只列出预设(TTY 下也不交互);与 --setup 同用时显示全局帮助。
const TIMEOUT_MS = 800; // Stdin 安全超时,预留 700ms 给渲染与 stdout 刷新
const LOG_MAX_BYTES = 1024 * 1024; // 错误日志 1MB 自动轮转上限
const MAX_STDIN_SIZE = 1024 * 1024;// Stdin 接收上限 1MB(stdin 管道分支内的局部常量)process.stdout.on('error', () => {})静默吞掉EPIPE;退出一律process.exitCode = 0+ 关闭 stdin 句柄,由事件循环自然排空,禁用process.exit()。设计动机见 architecture §7 与 §8。
职责: 从 CodeBuddy 传入的原始 stdin JSON 字符串中安全提取会话、Token、变更与消费指标。
export function parseCodeBuddyInput(rawStdin: string | null | undefined): CodeBuddyPayload | null;
export function extractTokenData(cbData: CodeBuddyPayload): {
inTokens: number;
outTokens: number;
cacheRead: number;
cacheWrite: number;
totalInput: number;
totalOutput: number;
ctxSize: number;
ctxPercent: number;
} | null;
export function resolveContextInputTokens(cw: ContextWindow): number | null;
export function extractDiffStats(cbData: CodeBuddyPayload): {
linesAdded: number;
linesRemoved: number;
};
export function extractCostData(cbData: CodeBuddyPayload): {
totalCostUsd: number;
totalDurationMs: number;
apiDurationMs: number;
} | null;
export function num(val: any): number;Token 占用还原与仲裁:
input_tokens被宿主扣减为 0 时(DeepSeek 等把 miss 记为 creation),extractTokenData以combined = rawInput + cacheRead + cacheCreation还原总占用(与used_percentage同基底);未扣减提示词与缓存并存时,比对combined与rawInput相对used_percentage理论占用的残差距离仲裁,防止翻倍。该还原值同时供session-stats.js作 /clear 信号(与 Line 2 同源)。
// CodeBuddyPayload 基础形态
{
cwd?: string,
workspace?: { current_dir?: string },
permission_mode?: string,
version?: string,
session_id?: string,
model?: { id: string; display_name?: string },
reasoning_effort?: string,
transcript_path?: string,
context_window?: {
total_input_tokens?: number,
total_output_tokens?: number,
context_window_size?: number,
used_percentage?: number,
current_usage?: {
input_tokens?: number,
output_tokens?: number,
cache_read_input_tokens?: number,
cache_creation_input_tokens?: number
}
},
cost?: {
total_cost_usd?: number,
total_duration_ms?: number,
total_api_duration_ms?: number,
total_lines_added?: number,
total_lines_removed?: number,
credits?: number
}
}职责: 按「默认 → 随包 → 用户 → 项目」4 层执行 deepMerge,再经 resolveTheme 后处理。loadConfig() 返回前会把 config.theme 替换为调色板对象 { ...palette, name, mode },调用方不能再把它当作预设名字符串比较。
export function loadConfig(cwd?: string): ResolvedConfig;
export function deepMerge<T extends object>(target: T, source: object, depth?: number): T;
export function resolveTheme(config: ResolvedConfig): ThemePalette;
export function detectThemeMode(config: ResolvedConfig): 'dark' | 'light';
export function isPresetName(name: string): boolean;
export const DEFAULT_CONFIG: ResolvedConfig;
export const THEME_PRESETS: Record<string, ThemePreset>;ocean(默认): 深海青蓝科技风 (dark:cyan/gray, light:blue/gray)emerald: 翡翠绿清新护眼 (dark:brightGreen(256 色114柔和浅绿)/gray, light:green/gray)cyberpunk: 赛博朋克炫酷粉紫 (dark:brightMagenta(256 色183柔和粉紫)/gray, light:magenta/gray;模型、分支、项目名及 out Token 使用同一主题主色)amber: 琥珀金耀眼质感 (dark/light:gold(标准 16 色高亮金\x1b[93m)/gray)monochrome: 黑白极简经典终端 (dark:white/gray, light:gray/gray)
设计动机见 architecture §5.5。HUD 配置文件每次加载前检查大小,超过 256 KiB 或不是普通文件时跳过该层,保留其他层配置;--theme <name> 写入用户配置,不是运行时覆盖层;resolveTheme 是后处理而非合并层。
deepMerge() 内部跳过 __proto__ 键并将递归深度限制为 64,阻断恶意配置污染 V8 原型链与爆栈。主题覆盖值另经白名单校验:仅保留调色板已有关键字;值必须是严格 SGR 序列(^\x1b\[[0-9;:]{0,48}m$)或长度 ≤32 且不含 C0/C1 的字符串;非字符串值被丢弃。未知颜色名不会回退预设,而是由 color() 原样输出为无样式文本。
职责: 核心布局引擎,协调各子渲染器装配 3 行看板,执行空行智能裁剪与终端安全转义。
export function renderHUD(
cbData: CodeBuddyPayload | null,
config: ResolvedConfig
): string;说明:必须传入完整解析后的
config配置对象。当config省略或未提供时,渲染器首行守卫将直接返回空字符串''。
- Line 1 (Identity):
[ModelName] [EffortIcon][EffortLabel] │ [Branch*] │ [Workspace] │ [Permission](模型名称加粗;权限模式统一使用标准 16 色高亮紫brightPurple;ASCII 模式下图标为空,仅保留级别文本) - Line 2 (Tokens):
Context Token 249k/1M [███░░░░░░░] 25% │ out 1.1k │ cache 96.8%;Context Token 标题加粗,占用分子支持高缓存扣减还原与防翻倍仲裁;compact 压缩后若宿主仍提供旧 usage,则显示等待提示与--占位。 - Line 3 (Diff/Cost/Tools):
Δ +1.7k -161 │ 82.04 credits │ ⏱ 2h47m │ ◐ Edit: parser.js ✓ Read ×3 ✓ Grep ×2(全空自动隐藏)
fresh:完整展示进度条与out。stale(/compact后待刷新):分子显示--,隐藏进度条与out。unknown:显示分子、隐藏进度条、提示上次上报。- 缓存徽标:≥
excellent纯绿、≥partial纯黄,低命中率与 0% 追加细体(细节见 §5)。设计动机见 architecture §5.6。
职责: 基础文本格式化、用量进度条与 Prompt Cache 徽标渲染。
formatTokens(num: number): string: 格式化数字为1.2k、3.5M;>= 999950直接进入M分支,999.5边界处理防止四舍五入溢出为1000k。formatDurationMs(ms: number): string: 格式化毫秒数为12s、5m20s、2h15m、10h、1d5h、10d。createProgressBar(pct: number, width: number, thresholds: object, glyphs: object): string: 生成自适应色阶进度条(宽度限制 4–40)。calculateTurnCacheMetrics(usage: object | null): TurnCacheMetrics | { available: false } | null: 从单条 usage 计算缓存命中指标,字段缺失或总 prompt 为 0 时返回{ available: false },无 usage 时返回null。该函数仅用于测试/辅助路径,生产渲染使用metricsFromPromptCache聚合 transcript 遥测。metricsFromPromptCache(hitTokens: number, promptTokens: number): TurnCacheMetrics | null: 从本轮聚合命中数与 prompt 数构建缓存指标(调用方在返回null时兜底为{ available: false }并渲染cache --)。formatTurnCacheBadge(metrics, label, isCompact, thresholds): string: 渲染缓存徽标。命中率 ≥excellent时为纯绿、≥partial时为纯黄;仅0 < rate < partial与 0% 时追加DIM。isCompact为保留形参,当前实现未使用。- 辅助导出与调色常量:
ANSI_COLORS(含brightPurple: '\x1b[95m'等)、RESET、BOLD、DIM样式常量,以及color/bold/dim三个样式辅助函数。 - 调色与清洗接口:
export function themeColor(config: ResolvedConfig, key: string, text: string, fallback?: string): string;
export function getThemeColor(config: ResolvedConfig, key: string, fallback?: string): string;
export function normalizeTokenCount(v: any): number | null;
export function sumCachedTokens(details?: Array<{ cached_tokens?: number }>): number | null;职责: 装配 Line 3 代码增删指标、累计实际 Credits 扣费与耗时。
export function renderDiffSegment(
diffStats: { linesAdded: number; linesRemoved: number },
costData: { totalCostUsd?: number; totalDurationMs?: number; apiDurationMs?: number },
config: ResolvedConfig,
glyphs: GlyphSet,
creditSpend?: number | null,
toolSegment?: string
): string;
export function formatCreditSpend(creditSpend?: number | null): string; // 合法非负数(含 0)返回 "X.XX credits",非法或缺失返回 ""职责: 将 transcript.js 已聚合好的工具活动格式化为 Line 3 尾部片段(聚合本身不在本模块)。
export function renderToolActivity(activity: ToolActivity, glyphs: GlyphSet): string;多个已完成工具每个独立带有 doneIcon(✓),以双空格分隔;仅显示前 3 名,×N 仅在 count > 1 时出现:
◐ RunCommand: npm test ✓ Edit ×3 ✓ View ×12
职责: 对会话推理强度(effort)做白名单归一化与多级解析,为 Line 1 的 effort 图标提供取值;并从 payload 提取明示的实际 Credits 消费。
export function resolveEffortLevel(cbData: CodeBuddyPayload, config?: ResolvedConfig): string | null;
export function resolveCreditSpend(cbData: CodeBuddyPayload): number | null;
export function resetModelInfoCache(): void;- 白名单归一化:仅接受
low/medium/high/xhigh/max/ultracode(含med、extra-high、maximum、ultra等别名映射);未知值视为不可信输入,沿解析链下探。 - effort 解析链:
cbData.reasoning_effort→cbData.model.reasoning_effort→cbData.model.effort→ transcript 会话信号(按 transcript 哈希持久化于会话状态目录)→settings.json的reasoningEffort(仅进程内缓存)→ 模型名推断 →config.defaultEffortLevel。 - Credits 回退:仅提取 payload
cost.credits明示的实际消费;缺失返回null,不基于模型费率元数据推算。
职责: 提供集中化中英双语词典,自动探测系统环境语言并提供 t() 翻译辅助函数。
export function detectLanguage(config?: { language?: string }): 'zh' | 'en';
export function getI18n(config?: ResolvedConfig): {
lang: 'zh' | 'en';
t: (key: string, fallback?: string) => string;
dict: Record<string, string>;
};
export const DICTIONARY: Record<'zh' | 'en', Record<string, string>>;职责: 高性能逆向滑窗读取 transcript.jsonl,聚合当前轮次 API Usage,并以增量 Checkpoint 计算累计 Credits。
export function getTurnUsageMetrics(
transcriptPath: string | null,
opts?: { cwd?: string; tailBytes?: number }
): {
hitTokens: number;
promptTokens: number;
callCount: number;
credits: number | null;
creditCallCount: number;
source: 'turn';
} | null;
export function getSessionUsageMetrics(
transcriptPath: string | null,
opts?: { statePath?: string; cwd?: string }
): {
complete: boolean;
credits: number | null;
creditCallCount: number | null;
offset: number;
source: 'session';
} | null;
export function getTurnToolActivity(
transcriptPath: string | null,
opts?: { cwd?: string; tailBytes?: number }
): {
active?: { tool: string; detail?: string };
completed: Array<{ tool: string; count: number }>;
totalCompleted: number;
} | null;
export function getTurnMetricsAndActivity(
transcriptPath: string | null,
opts?: { cwd?: string; tailBytes?: number; contextWindow?: object }
): {
turnUsage: ReturnType<typeof getTurnUsageMetrics>;
toolActivity: ReturnType<typeof getTurnToolActivity>;
contextStatus?: 'fresh' | 'stale' | 'unknown';
};设计动机见 architecture §5.1 与 §5.4。
getTurnMetricsAndActivity()共享本轮 usage 与工具活动的一次逆向扫描;回扫自 EOF 向前,滑窗边界切断的 JSONL 行跨块拼装,遇到最近的role: 'user'即停;超出MAX_TURN_SCAN_LINES/MAX_TOTAL_BYTES时止于最近调用,口径变为sum(hitTokens) / sum(promptTokens)。- Cache 字段优先级:
rawUsage.prompt_tokens有效时取prompt_cache_hit_tokens→prompt_tokens_details.cached_tokens→cached_tokens→ 0;否则usage.inputTokens有效时取sum(usage.inputTokensDetails[].cached_tokens)。 - 会话 Credits 另用前向 checkpoint 扫描(状态 schema 见 §15),分块循环预算 100ms,从
offset续读,未写完的尾行不提交。complete: false表示预算耗尽、短读或尾行未完成:累计值与调用数为null,checkpoint 仍可续扫;渲染层隐藏 Credits,禁止 payload 兜底。 contextStatus:/compact产生压缩摘要而宿主尚未返回新 usage 时为stale;判据见下。
createContextTracker(contextWindow)(内部辅助函数,未在 module.exports 导出):沿消息parentId逆向回溯历史链。检测到完成的 compact 压缩摘要(isCompacted: true且isSummary: true或isCompactInternal: true)即置stale;检测到普通活跃 API usage 时,通过resolveReportedInputs(usage)进行双向遥测比对(matchesInput = reportedInput === input || rawReportedInput === input),并且只有同时满足!sawUsage、输入/输出均为有限非负数、reportedOutput === output时才置fresh;一旦本链已发现更早的普通 usage,则不再用旧 payload 反证。getCompactContextStatus(transcriptPath, contextWindow, opts)(内部辅助函数,未在 module.exports 导出):当宿主未在边界完整保留 parent 关联时的尾窗回退——压缩摘要位于最新普通 usage 之后则为stale。resolveReportedInputs(usage)(内部辅助函数,未在 module.exports 导出):提取{ combined, raw },统一还原基准(combined = input_tokens + cache_read_input_tokens + cache_creation_input_tokens)。
- 辅助扫描函数:
getRecentToolActivity(transcriptPath, opts)返回{ status: 'active' | 'done', tool, detail } | null(renderer 在无turnActivity时兜底调用);getRecentUsageMetrics(path, opts)、extractUsageMetrics(entry: object)。 - 滑窗预算常数:
DEFAULT_TAIL_BYTES(16384)、MAX_TOTAL_BYTES(262144)、MAX_SCAN_LINES(40)、MAX_TURN_SCAN_LINES(200);MIN_TAIL_BYTES为 64,小于该值的display.toolActivityTailBytes会被normalizeTailBytes重置为 16384,大于MAX_TOTAL_BYTES时钳制至该上限;各逆向扫描同时按剩余字节预算限制读取。
职责: 监控上下文与指标单调性,识别 /clear 场景并扣除历史基线。
export function getLogicalSessionCostData(
cbData: CodeBuddyPayload,
rawCostData: CostData,
opts?: { statePath?: string; cwd?: string }
): {
linesAdded: number;
linesRemoved: number;
totalDurationMs: number;
apiDurationMs: number;
};
export function getSessionIdentity(cbData: CodeBuddyPayload, cwd?: string): string | null;
export function getResetSignal(cbData: CodeBuddyPayload): {
totalInputTokens: number | null;
currentInputTokens: number | null;
};
export const SESSION_STATS_VERSION: number;状态落盘于 ~/.codebuddy/codebuddy-hud-session-state/<hash>.json(schema 见 §15),设计动机见 architecture §5.3。
重置判定(任一命中即重建基线):
- Cliff Drop:当前上下文占用相对降幅 ≥50% 且绝对降幅 ≥3000;
- Return to Initial:当前占用 ≤4096 且此前 ≥6000(相对降幅 ≥35%);
- 累计
total_input_tokens下降; - 同一 transcript 的
session_id变化、transcript 物理截断(本次正整数 size 小于上次有效记录),或宿主显式clear_signal/is_clear; - 代码增删或耗时计数低于已存基线(此时 cost 基线归零)。
cwd 用于相对 transcript_path 的解析(identity 派生);identity miss 即视为新会话,直接以当前 payload 累计为新基线。getSessionIdentity() 有 transcript 时返回 transcript:<normalizePlatformPath(path)>,否则返回 session:<session_id>,该字符串作为状态文件哈希键。getResetSignal 的 currentInputTokens 取 parser.resolveContextInputTokens 的还原占用(与 Line 2 同源):有 context_window_size/used_percentage 时缓存命中/扣除不改变该值;两者缺失时退回原始 input_tokens(缓存残差形态仍可能触发断崖);input_tokens 缺失且 cache 计数为 0 时为 null,不参与断崖比较。
transcriptSize 保存最近一次有效的正整数尺寸;单独增长也触发写回。stat 失败或尺寸为 0 时保留上次有效记录,即使其他信号触发写回;无重置且状态、尺寸均不变时不写盘。0 表示尚无有效尺寸,空文件本身不触发截断。
职责: 单次 git status --porcelain -b 快速获取分支名与脏文件标记(*)。
export function getGitStatus(
cwd?: string,
timeoutMs?: number // 默认 200ms 超时保底
): {
branch: string;
dirty: boolean | null;
} | null;
export function findGitInfo(cwd?: string): { gitDir: string; workTree: string } | null;
export function readDirectBranch(gitDir: string): string | null;
export function parseGitStatusOutput(output: string): { branch: string; dirty: boolean };设计动机见 architecture §5.2。读取 .git/HEAD 直接得到分支名或 7 位游离态 commit(零派生);需要脏状态时 execFileSync('git', ['status', '--porcelain', '-b'], ...) 免 shell,硬超时 200ms,windowsHide: true,GIT_OPTIONAL_LOCKS: '0';child_process 仅在缓存未命中时懒加载。
正常结果缓存 10 秒,HEAD/index mtime 变化可提前失效;未暂存的工作树编辑可能延迟显示。git status 失败但 HEAD 可读时写入 10 秒正缓存 { branch, dirty: null };只有无 HEAD 可回退时才写 60 秒失败负缓存(GIT_FAILURE_TTL_MS),并以 headMtime 变化自失效。非 git 目录不会派生 git 进程,仅有 5 秒进程内 _nonGitDirs 负缓存(一次性进程跨帧无效)。CODEBUDDY_HUD_NO_GIT_CACHE=1 绕过持久化缓存,但不影响该进程内 5 秒负缓存。返回 null 表示无仓库/无 HEAD;dirty: null 表示探测失败但分支可读。
职责: 探测终端 Unicode/NerdFonts 支持,Windows 下自动探测 chcp 65001 并缓存。
export function supportsUnicode(): boolean;
export function detectUnicodeSupport(platform: string, env: Record<string, string | undefined>): boolean;
export function selectGlyphs(useNerdFonts: boolean, unicodeSupported: boolean): GlyphSet;
export function resetCache(): void;设计动机见 architecture §8。Windows 下通过直连 spawnSync('chcp.com') 免壳探测(硬超时 300ms);代码页探测结果缓存于 ~/.codebuddy/codebuddy-hud-cache-state.json 保持 1 小时,探测超时或派生失败当帧安全降级 ASCII 且仅缓存 60 秒(probeTtlMs: 60000)防抖,避免因系统偶发尖刺锁死 1 小时;CODEBUDDY_HUD_FORCE_ASCII / CODEBUDDY_HUD_FORCE_UNICODE 优先于缓存。
职责: 剥离外部输入中的 ANSI CSI/OSC 控制序列、DCS/APC/PM/SOS 串式控制串(含 C1 单字节形式)、Unicode Bidi 伪装字符与 C0/C1 控制符。
export function sanitizeTerminalText(text: any, maxLen?: number): string;职责: 统一定位 CodeBuddy 配置目录(优先支持 CODEBUDDY_HOME 与 CODEBUDDY_SETTINGS_PATH 环境变量),并提供跨平台文件哈希与状态路径解析。
getCodeBuddyHome(): string: 返回~/.codebuddy或覆盖路径。getSettingsPath(): string: 返回settings.json绝对路径。getUserConfigPath(): string: 返回codebuddy-hud.config.json路径。getErrorLogPath(): string: 返回codebuddy-hud-error.log路径。getCacheStatePath(): string: 返回codebuddy-hud-cache-state.json路径。getCreditStatePath(): string: 存量清理接口——返回旧版codebuddy-hud-credit-state.json路径。Credits 遥测已整体迁移至 usage checkpoint,仅供 uninstall 清理历史文件。getUpdateStatusPath(): string: 存量清理接口——返回旧版codebuddy-hud-update-status.json路径。遵循渲染路径零网络契约已整体退役,仅供 uninstall 清理历史文件。getGitCachePath(): string: 返回codebuddy-hud-git-cache.json路径。getTranscriptUsageStateDir(): string: 返回codebuddy-hud-usage-state/目录。getTranscriptUsageStatePath(transcriptPath: string): string: 按 transcript 绝对路径 SHA-256 哈希隔离的增量遥测 checkpoint 路径。getSessionStatsStateDir(): string: 返回codebuddy-hud-session-state/目录。getSessionStatsStatePath(identity: string): string: 按会话 identity 哈希隔离的基线状态路径。getSessionStatsHandoffPath(cwd: string): string: 存量清理接口——旧版/clearhandoff 状态路径(handoff-<sha256(cwd)>.json)。handoff 机制已退役(identity miss 直接锚定当前累计),现无运行时引用;函数保留以便定位/清理存量文件,uninstall 按整目录 rmSync 兜底覆盖。getSessionEffortStatePath(transcriptPath: string): string: 返回按 transcript 路径哈希寻址的会话 effort 状态文件codebuddy-hud-session-state/effort-<sha256>.json。resolveCodeBuddyPath(...segments: string[]): string: 将相对路径解析为基于CODEBUDDY_HOME的绝对路径。getUserSkillsDir(): string: 返回用户级技能根目录(~/.codebuddy/skills/)。getHudSkillTargetDir(): string: 返回hud-config技能部署目标目录(~/.codebuddy/skills/hud-config/)。normalizePlatformPath(p: string): string: 平台感知路径归一化——Windows 下 resolve 后整体小写(消除盘符d:/D:哈希分裂),POSIX 保留大小写语义。
codebuddy-hud-session-state/<identity-sha256>.json(会话基线与 /clear 重置信号状态):
{
"version": 1,
"identityHash": "string (sha256)",
"sessionIdHash": "string | null (sha256)",
"baseline": {
"linesAdded": 0,
"linesRemoved": 0,
"totalDurationMs": 0,
"apiDurationMs": 0
},
"signal": {
"totalInputTokens": null,
"currentInputTokens": null
},
"transcriptSize": 12345,
"updatedAt": 1729670000000
}codebuddy-hud-session-state/effort-<transcript-sha256>.json(会话推理深度 Effort 状态):
{
"version": 1,
"effort": "max",
"updatedAt": 1729670000000
}codebuddy-hud-usage-state/<transcript-sha256>.json(transcript Credits checkpoint, version 5):
{
"version": 5,
"path": "absolute transcript path",
"identity": { "dev": 0, "ino": 0, "birthtimeMs": 0 },
"headHash": "sha256",
"offset": 0,
"credits": 0,
"creditCallCount": 0,
"checkpointHash": "sha256",
"sourceSize": 0,
"sourceMtimeNs": "0",
"sourceCtimeNs": "0",
"sourceContentHash": "sha256 | null",
"updatedAt": 1729670000000
}失效条件:size < sourceSize(截断/轮转)、size === sourceSize 但 mtime/ctime 变化或 sourceContentHash 变化(原地覆写)、identity 变化、checkpoint/head 哈希不匹配。
-
codebuddy-hud-cache-state.json(终端编码缓存):{ unicodeSupported: boolean, savedAt: number, probeTtlMs?: number };成功结果默认保留 1 小时,失败结果写probeTtlMs: 60000。 -
codebuddy-hud-git-cache.json(Git 探测缓存): 以 workTree 为键,每项{ branch, dirty, headMtime, indexMtime, failed?, timestamp };failed: true为 60 秒负缓存。
职责: 针对宿主 settings.json 进行安全读取、注释剥离、符号链接目标解析、原子写盘与权限保全。
export function parseSettingsJson(raw: string): object;
export function getSettingsProperty(raw: string, key: string): string | undefined;
export function editSettingsProperty(raw: string, key: string, valueRaw: string | undefined): string;
export function atomicWriteSettingsFile(targetPath: string, content: string): void;
export function resolveWriteTarget(targetPath: string): string;
export function isSettingsObject(value: unknown): boolean;
export function writePrivateFileIfAbsent(filePath: string, content: string): boolean;- 局部文本修改:
getSettingsProperty()读取对象直接成员的原文值;editSettingsProperty()仅替换、插入或删除该成员,保留未涉及的注释、BOM、空白及换行。undefined表示删除,重复键按 JSON 的末项生效规则读取,删除时清除所有同名项以免旧命令重新生效。 - 严格保护字符串内容:
stripJsonComments()仅剔除双引号字符串外的单行//与块级/* */注释,保留换行符与空格以确保 JSON 语法报错行号对齐;绝不误改字符串内部的路径或 URL。parseSettingsJson()还会剥离 UTF-8 BOM、清除字符串外的尾随逗号;空内容返回{}。 - 符号链接解析跟随:
resolveWriteTarget()循环解引用符号链接(上限 40 层防环),确保写操作直接作用于最终真实目标文件。 - 原子替换与硬链接保护:通过临时文件(
.tmp-<pid>-<time>)写入后执行fs.renameSync()原子替换;检测到硬链接数nlink > 1时主动拒绝原子替换,防止意外破坏硬链接。 - POSIX 权限保全:继承目标文件原有的 mode/uid/gid;新创建的配置文件与首次备份默认赋予严格的
0600私有权限。
职责: 将 HUD 注册进 CodeBuddy settings.json 的 statusLine 配置项,并在 Windows 平台生成固化 Node 绝对路径的 .cmd shim 启动脚本。
export function setup(options?: {
settingsPath?: string;
runtimeDir?: string;
hudBin?: string;
platform?: string;
nodeExe?: string;
theme?: string;
rootDir?: string;
sourceSkillDir?: string;
targetSkillDir?: string;
}): void;
export function deploySkill(options?: {
rootDir?: string;
sourceSkillDir?: string;
targetSkillDir?: string;
}, hudBin?: string, platform?: string): void;
export function buildStatusLineCommand(platform: string, hudBin: string, nodeExe: string): string;
export function removeManagedSkill(targetDir: string, sourceDir: string): void;
export function buildCmdShimContent(nodeExe: string, hudBin?: string): string;
export function parseSettingsJson(content: string): object;
export function isSettingsObject(val: unknown): val is Record<string, unknown>;- 技能自动挂载:
setup()时通过deploySkill()将skills/hud-config/挂载至~/.codebuddy/skills/hud-config/(Windows 优先 Junction,POSIX 优先目录软链接,失败时降级递归复制)。仅替换/卸载指向本次源目录的链接或含.codebuddy-hud-managed标记(内容为codebuddy-hud\n)的复制目录;未知目录与链接警告并保留,旧版无标记副本也按未知目录处理。标记仅写入复制目录,不写入链接目标;源目录本身禁止删除。 - Windows Shim:烘焙
process.execPath、%→%%、非 ASCII 路径的 8.3 短路径与@chcp 65001 >nul、宿主引号兼容规则见 architecture §8.1。 - settings.statusLine 形状:局部更新
type: 'command'与command,保留已有 padding 和额外字段;padding 缺失时才补 0。Windows.cmdshim 以"%~dp0codebuddy-hud.js"转发同目录入口,doctor按该转发约定校验健康度。 - 无损配置恢复保障:首次安装前将原始
settings.json备份为settings.json.bak.codebuddy-hud(同一安装周期只备份一次),通过settings-file.js局部编辑后原子写回,不重新序列化整份 JSONC。--setup --theme遇到换肤失败时中止,不继续写入 statusLine。
职责: 采集 Node、CodeBuddy 配置、终端编码、Git 与 Transcript 状态,执行物理路径真实存在性校验。
export function runDoctor(options?: { cwd?: string }): DoctorReport;
export function printDoctorReport(report: DoctorReport, isJson?: boolean, options?: { cwd?: string }): void;node: Node.js 版本($\ge 18$)、架构与可执行文件路径。codebuddy:CODEBUDDY_HOME、settings.json与statusLine.command指向的目标物理文件存在性校验(含 shim 转发路径)。codebuddy / hostRefreshProtocol: 宿主事件驱动刷新架构契约说明(长任务期间宿主不派发更新属正常现象)。terminal: Windows 代码页(chcp 65001)、Unicode 支持与明暗色调。terminal / windowsPathNormalization: Windows 路径大小写规范化检查。git: Git PATH 可达性、当前仓库分支与探测延迟。transcript: 遥测状态目录创建与可写性校验,并回显错误日志路径。
命令路径在 POSIX 下按原样与 shell 反转义两种形式校验;Windows 只按字面路径校验,保留 UNC 与 \$,避免把不存在的路径反转义成另一个有效文件。引号内尾反斜杠造成分词歧义时回退非转义分词。
职责: 终端 Raw 模式下方向键交互式选择主题,实时动态刷新 ANSI 看板预览,退出时释放 stdin 句柄。
export function selectThemeInteractive(opts?: { initialTheme?: string; config?: ResolvedConfig }): Promise<string | null>;
export function saveUserTheme(themeName: string): string;
export function getActiveThemeName(): string;
export function renderThemePreview(themeName: string, mode?: 'dark' | 'light'): string[];
export function printThemesList(config?: ResolvedConfig): void;
export const THEMES: Array<{ name: string; label: string }>;界面文案(列表标题、用法提示、选择器标题/快捷键提示、预览框标题)通过 lang.js 字典输出,config.language 生效;预览框顶边按显示宽度(CJK 双列)计算,与底边对齐。
saveUserTheme() 与配置加载保持严格 JSON 口径;仅文件不存在时新建。读取/解析失败或根节点不是对象时中止,原文件不变;成功写入复用 atomicWriteSettingsFile(),保留既有权限和软链接,新文件默认 0600。
职责: 从首次备份局部还原非本 HUD 的 statusLine(且仅当当前 statusLine 仍指向本 HUD;用户装后替换或删除的项保留)——备份记录的命令含 codebuddy-hud 时改为移除该项;保留其他 settings 原文及用户主题配置,仅清理可确认归属的技能部署(见 §17);移除对应 runtime 的 Windows shim 与用户缓存;清理系统级 PATH 注册(CODEBUDDY_HOME 已设置时跳过)。成功处理后,若当前文件与备份原文不同,先以私有权限留存 settings.json.bak.codebuddy-hud.retained-<time>-<pid>,再回收活动备份,避免后续安装误用旧快照;解析、写入或留存失败时保留活动备份。
仅当逐字比对确认 statusLine 以外的原文未变,且备份不指向旧 HUD 时,直接恢复备份原文,使新增/删除该字段也能精确往返;其他情况只修改该字段,不覆盖安装后的其他修改。
export function uninstall(options?: object): void;
export function stripBinDirFromUserPath(rawPath: string, binDir: string): { changed: boolean; value: string };stripBinDirFromUserPath() 从原始 HKCU Path 值中移除 runtime bin 目录:比较前不展开 %VAR%,并按平台归一化(Windows 忽略大小写,去除包裹引号与路径尾分隔符),避免误删或漏删;写回时沿用原注册表值类型(保留 REG_EXPAND_SZ)。
职责: 为 --update 命令提供版本解析、比较与自举升级能力。是「渲染路径零网络」契约下唯一的联网入口:仅在用户显式调用 --update 时发起请求,无后台巡逻、无状态文件写入、无状态栏提示元素。
export function parseSemverDetail(v: string): { numbers: [number, number, number], prerelease: string[] };
export function compareVersions(v1: string, v2: string): -1 | 0 | 1;
export function getLocalVersion(): string | null;
export function getReleaseVersion(release: object): string | null;
export async function resolveLatestTag(options?: object): Promise<string>;
export function fetchLatestTagVia302(url: string): Promise<string>;
export function rawBaseForTag(tag: string): string;
export async function runUpdate(options?: object): Promise<{ ok: boolean, message: string, latest?: string, local?: string, bootstrapPath?: string }>;- tag 单一形态:
resolveLatestTag返回 GitHub 原始 ref(trim 后原样返回),下载 URL、子进程CODEBUDDY_HUD_VERSION、比较与消息全程原样使用(compareVersions自兼容v前缀)——不存在第二种归一化形态,结构上杜绝混用导致的 raw 404 与双前缀。 - getLocalVersion:读 runtime 上级
package.json;不可读返回null(不伪造版本),此时runUpdate提示重跑安装脚本。 - tag 解析三级策略(resolveLatestTag):显式
CODEBUDDY_HUD_LATEST_RELEASE_URL(兼容旧名CODEBUDDY_HUD_REMOTE_PKG_URL)→github.com/releases/latest302 Location(免 API 限流)→api.github.comREST 兜底(仅直连 host 附带GITHUB_TOKEN/GH_TOKEN,镜像不带);超时 8s。 - 白名单校验(rawBaseForTag):tag 必须匹配
^v?\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$才允许拼入下载 URL,拒绝路径注入。 - 环境变量:
CODEBUDDY_HUD_MIRROR(镜像前缀,语义与 bootstrap.js 一致:镜像候选优先、直连兜底)、CODEBUDDY_HUD_BOOTSTRAP_URL(覆盖 bootstrap 下载源)、CODEBUDDY_HUD_VERSION(派生子进程时钉住 tag,bootstrap 免二次解析)、CODEBUDDY_HUD_LATEST_RELEASE_URL(兼容旧名CODEBUDDY_HUD_REMOTE_PKG_URL,覆盖 Latest Release 查询 URL)。 - 自举升级流程(runUpdate):解析原始 ref 并预校验 tag 形态(畸形即失败,不落入假 "up to date")→ 落后判定(
compareVersions > 0,自兼容v前缀)→ 下载该原始 ref 的scripts/bootstrap.js至os.tmpdir()→ detached 派生node <tmp> --delay-start(stdio: 'inherit',windowsHide,CODEBUDDY_HUD_VERSION钉原始 ref);bootstrap 延迟 1s 等父进程完全退出后再原子重装 runtime,规避 Windows 文件锁。--update分支恒exit 0,失败信息走 stderr。
职责: 支持本地与 GitHub Raw 远程安装,通过临时目录 .tmp-<pid> + 原子重命名完成覆盖。本地安装直接复制仓库文件;远程安装解析 Release 的 tag_name 后从对应不可变 tag 下载。下载源优先级:CODEBUDDY_HUD_RAW_BASE → CODEBUDDY_HUD_VERSION → Latest Release 查询;前两者跳过查询。CODEBUDDY_HUD_MIRROR 为默认 GitHub URL 加镜像前缀,查询失败可回退直连,runtime 文件经镜像下载。--delay-start 延迟 1s 开始重装,供 --update 等待父进程退出以规避 Windows 文件锁。
RUNTIME_FILES: string[]: 远端下载清单,覆盖 runtime 所需文件、技能与 LICENSE;本地复制同样包含 LICENSE,测试检查清单完整性。install(): Promise<void>: 核心安装入口,支持本地复制与远端下载,通过临时目录 + 原子重命名完成安装。getTargetDir(): string: 返回运行时目标安装目录路径(受CODEBUDDY_HUD_DIR环境变量影响)。checkNodeVersion(): void: 校验当前 Node.js 版本 ≥18;不满足时向 stderr 打印错误并process.exit(1)(不抛异常,调用方无法 catch)。rawBaseForTag(tag: string): string: 返回指定 Release tag 的 GitHub Raw 基础地址。resolveRemoteRawBase(options?: object): Promise<string>: 解析CODEBUDDY_HUD_RAW_BASE、CODEBUDDY_HUD_VERSION或 Latest Release 后的下载源(含CODEBUDDY_HUD_MIRROR前缀)。fetchLatestTagVia302(url?: string): Promise<string>: 从releases/latest的 302Location解析不可变 tag;省略url时使用镜像前缀后的默认地址。fetchLatestRelease(options?: { candidates302?: string[]; apiCandidates?: string[] }): Promise<object>: 显式CODEBUDDY_HUD_LATEST_RELEASE_URL(兼容旧名CODEBUDDY_HUD_REMOTE_PKG_URL,两者同设时新名优先)独占查询,按原 URL 请求,失败即报错;未设置时才按 302 候选链 → API 候选链解析。fetchUrlWithRetry(url: string, maxAttempts?: number): Promise<Buffer>: 内部辅助实现(未在 module.exports 导出),网络下载重试包装(默认 3 次,1s/2s 指数退避)。mirrorPrefix(): string: 解析CODEBUDDY_HUD_MIRROR环境变量并归一化为 URL 前缀。
职责: npm test 底层执行驱动。遍历 tests/unit/ 目录下全部 *.test.mjs 单元测试文件的绝对路径,直接向 node --test 喂入全量文件参数,彻底规避 Node 18/20 glob 在 Windows 路径反斜杠下的跨平台匹配陷阱与 MODULE_NOT_FOUND 假阳性。额外 CLI 参数会原样转发给 node --test(例如 npm test -- --test-name-pattern=...)。
职责: 执行 npm run verify 的 10 个 CLI、payload 与边界场景,验证看板行数(严格
职责: 执行 npm run verify:install,在全隔离的临时沙箱中验证真实环境下的安装与卸载闭环。必须同时三重隔离 CODEBUDDY_HOME、CODEBUDDY_SETTINGS_PATH 与运行时目录,防止测试执行污染或误删工作区开发中的真实 .cmd shim。
职责: 面向终端用户的零配置一键安装管道。
scripts/install.ps1(PowerShell):支持CODEBUDDY_HUD_MIRROR代理;通过注册表 API 读写 HKCUPath追加 runtime bin 目录(保留%VAR%间接引用,不破坏REG_EXPAND_SZ);从 master 下载bootstrap.js执行部署(runtime 版本由 bootstrap 后续解析并固定到 Release tag)。支持CODEBUDDY_HUD_NO_PATH=1跳过 PATH 修改。scripts/install.sh(POSIX Shell):支持 macOS 与 Linux;当用户 PATH 包含~/.local/bin时自动创建指向 runtime bin 的软链接;支持CODEBUDDY_HUD_MIRROR镜像前缀下载与部署,支持CODEBUDDY_HUD_NO_PATH=1跳过 PATH 修改。
职责: 为 AI Agent 提供主题、图标与显示项配置的交互式引导,并将选择写入项目或全局 codebuddy-hud.config.json。