mirror of
https://github.com/jarrodwatts/claude-hud.git
synced 2026-05-21 15:52:37 +00:00
build: compile dist/ [auto]
This commit is contained in:
2
dist/config-reader.d.ts.map
vendored
2
dist/config-reader.d.ts.map
vendored
@@ -1 +1 @@
|
||||
{"version":3,"file":"config-reader.d.ts","sourceRoot":"","sources":["../src/config-reader.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,YAAY;IAC3B,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;CACpB;AA4GD,wBAAsB,YAAY,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAkHtE"}
|
||||
{"version":3,"file":"config-reader.d.ts","sourceRoot":"","sources":["../src/config-reader.ts"],"names":[],"mappings":"AASA,MAAM,WAAW,YAAY;IAC3B,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;CACpB;AAoXD,wBAAsB,YAAY,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAoCtE"}
|
||||
154
dist/config-reader.js
vendored
154
dist/config-reader.js
vendored
@@ -1,8 +1,9 @@
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import * as os from 'os';
|
||||
import { createHash } from 'node:crypto';
|
||||
import { createDebug } from './debug.js';
|
||||
import { getClaudeConfigDir, getClaudeConfigJsonPath } from './claude-config-dir.js';
|
||||
import { getClaudeConfigDir, getClaudeConfigJsonPath, getHudPluginDir } from './claude-config-dir.js';
|
||||
const debug = createDebug('config');
|
||||
function getMcpServerNames(filePath) {
|
||||
if (!fs.existsSync(filePath))
|
||||
@@ -108,7 +109,124 @@ function pathsReferToSameLocation(pathA, pathB) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
export async function countConfigs(cwd) {
|
||||
function getConfigCachePath(cwd, claudeConfigDir, homeDir) {
|
||||
const identity = JSON.stringify({ cwd, claudeConfigDir });
|
||||
const hash = createHash('sha256').update(identity).digest('hex');
|
||||
return path.join(getHudPluginDir(homeDir), 'config-cache', `${hash}.json`);
|
||||
}
|
||||
function statSentinel(filePath) {
|
||||
try {
|
||||
const stat = fs.statSync(filePath);
|
||||
return { mtimeMs: stat.mtimeMs, size: stat.size };
|
||||
}
|
||||
catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
function buildSentinelPaths(claudeDir, claudeConfigJsonPath, cwd) {
|
||||
// Note: We sentinel CLAUDE.md directly instead of claudeDir because the
|
||||
// cache itself is stored under claudeDir/plugins/, which would change
|
||||
// claudeDir's mtime and immediately invalidate the cache on every write.
|
||||
const paths = [
|
||||
path.join(claudeDir, 'CLAUDE.md'),
|
||||
path.join(claudeDir, 'rules'),
|
||||
path.join(claudeDir, 'settings.json'),
|
||||
claudeConfigJsonPath,
|
||||
];
|
||||
if (cwd) {
|
||||
paths.push(cwd, path.join(cwd, '.claude'), path.join(cwd, '.claude', 'rules'), path.join(cwd, '.mcp.json'), path.join(cwd, '.claude', 'settings.json'), path.join(cwd, '.claude', 'settings.local.json'));
|
||||
}
|
||||
return paths;
|
||||
}
|
||||
function collectRuleDirectorySentinels(rulesDir) {
|
||||
if (!fs.existsSync(rulesDir))
|
||||
return [];
|
||||
const sentinels = [rulesDir];
|
||||
try {
|
||||
const entries = fs.readdirSync(rulesDir, { withFileTypes: true });
|
||||
for (const entry of entries) {
|
||||
if (!entry.isDirectory()) {
|
||||
continue;
|
||||
}
|
||||
sentinels.push(...collectRuleDirectorySentinels(path.join(rulesDir, entry.name)));
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
debug(`Failed to read rule sentinel paths from ${rulesDir}:`, error);
|
||||
}
|
||||
return sentinels;
|
||||
}
|
||||
function statSentinels(paths) {
|
||||
const result = {};
|
||||
for (const p of paths) {
|
||||
result[p] = statSentinel(p);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
function sentinelsMatch(a, b) {
|
||||
const keysA = Object.keys(a);
|
||||
const keysB = Object.keys(b);
|
||||
if (keysA.length !== keysB.length)
|
||||
return false;
|
||||
for (const key of keysA) {
|
||||
const sa = a[key];
|
||||
const sb = b[key];
|
||||
if (sa === null && sb === null)
|
||||
continue;
|
||||
if (sa === null || sb === null)
|
||||
return false;
|
||||
if (sa.mtimeMs !== sb.mtimeMs || sa.size !== sb.size)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
function isConfigCounts(value) {
|
||||
if (!value || typeof value !== 'object') {
|
||||
return false;
|
||||
}
|
||||
const counts = value;
|
||||
return (typeof counts.claudeMdCount === 'number'
|
||||
&& Number.isFinite(counts.claudeMdCount)
|
||||
&& counts.claudeMdCount >= 0
|
||||
&& typeof counts.rulesCount === 'number'
|
||||
&& Number.isFinite(counts.rulesCount)
|
||||
&& counts.rulesCount >= 0
|
||||
&& typeof counts.mcpCount === 'number'
|
||||
&& Number.isFinite(counts.mcpCount)
|
||||
&& counts.mcpCount >= 0
|
||||
&& typeof counts.hooksCount === 'number'
|
||||
&& Number.isFinite(counts.hooksCount)
|
||||
&& counts.hooksCount >= 0);
|
||||
}
|
||||
function readConfigCache(cacheKey, homeDir) {
|
||||
try {
|
||||
const cachePath = getConfigCachePath(cacheKey.cwd, cacheKey.claudeConfigDir, homeDir);
|
||||
const raw = fs.readFileSync(cachePath, 'utf8');
|
||||
const parsed = JSON.parse(raw);
|
||||
if (parsed.key?.cwd !== cacheKey.cwd || parsed.key?.claudeConfigDir !== cacheKey.claudeConfigDir) {
|
||||
return null;
|
||||
}
|
||||
if (!isConfigCounts(parsed.data)) {
|
||||
return null;
|
||||
}
|
||||
return parsed;
|
||||
}
|
||||
catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
function writeConfigCache(key, data, homeDir) {
|
||||
try {
|
||||
const cachePath = getConfigCachePath(key.cwd, key.claudeConfigDir, homeDir);
|
||||
fs.mkdirSync(path.dirname(cachePath), { recursive: true });
|
||||
const payload = { key, data };
|
||||
fs.writeFileSync(cachePath, JSON.stringify(payload), 'utf8');
|
||||
}
|
||||
catch {
|
||||
// Cache write failures are non-fatal.
|
||||
}
|
||||
}
|
||||
function computeConfigCountsFresh(cwd) {
|
||||
let claudeMdCount = 0;
|
||||
let rulesCount = 0;
|
||||
let hooksCount = 0;
|
||||
@@ -201,4 +319,36 @@ export async function countConfigs(cwd) {
|
||||
const mcpCount = userMcpServers.size + projectMcpServers.size;
|
||||
return { claudeMdCount, rulesCount, mcpCount, hooksCount };
|
||||
}
|
||||
export async function countConfigs(cwd) {
|
||||
const homeDir = os.homedir();
|
||||
const claudeDir = getClaudeConfigDir(homeDir);
|
||||
const claudeConfigJsonPath = getClaudeConfigJsonPath(homeDir);
|
||||
const normalizedCwd = cwd ? path.resolve(cwd) : null;
|
||||
const staticSentinelPaths = buildSentinelPaths(claudeDir, claudeConfigJsonPath, normalizedCwd);
|
||||
const cached = readConfigCache({ cwd: normalizedCwd, claudeConfigDir: claudeDir }, homeDir);
|
||||
const cacheValidationPaths = cached
|
||||
? Array.from(new Set([...staticSentinelPaths, ...Object.keys(cached.key.sentinels)]))
|
||||
: staticSentinelPaths;
|
||||
const currentSentinels = statSentinels(cacheValidationPaths);
|
||||
if (cached && sentinelsMatch(cached.key.sentinels, currentSentinels)) {
|
||||
return cached.data;
|
||||
}
|
||||
const result = computeConfigCountsFresh(cwd);
|
||||
const ruleSentinelPaths = collectRuleDirectorySentinels(path.join(claudeDir, 'rules'));
|
||||
const projectClaudeDir = normalizedCwd ? path.join(normalizedCwd, '.claude') : null;
|
||||
const projectClaudeOverlapsUserScope = projectClaudeDir
|
||||
? pathsReferToSameLocation(projectClaudeDir, claudeDir)
|
||||
: false;
|
||||
if (normalizedCwd && !projectClaudeOverlapsUserScope) {
|
||||
ruleSentinelPaths.push(...collectRuleDirectorySentinels(path.join(normalizedCwd, '.claude', 'rules')));
|
||||
}
|
||||
const cacheSentinelPaths = Array.from(new Set([...staticSentinelPaths, ...ruleSentinelPaths]));
|
||||
const cacheKey = {
|
||||
cwd: normalizedCwd,
|
||||
claudeConfigDir: claudeDir,
|
||||
sentinels: statSentinels(cacheSentinelPaths),
|
||||
};
|
||||
writeConfigCache(cacheKey, result, homeDir);
|
||||
return result;
|
||||
}
|
||||
//# sourceMappingURL=config-reader.js.map
|
||||
2
dist/config-reader.js.map
vendored
2
dist/config-reader.js.map
vendored
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user