const fs = require('fs'); const path = require('path'); const os = require('os'); function readJsonMaybe(filePath) { try { if (!filePath || !fs.existsSync(filePath)) return {}; return JSON.parse(fs.readFileSync(filePath, 'utf8').replace(/^\uFEFF/, '')); } catch { return {}; } } function firstNonEmpty(values) { return values.find(value => typeof value === 'string' && value.trim()) || ''; } function readEnvFileMaybe(filePath) { try { if (!filePath || !fs.existsSync(filePath)) return {}; const env = {}; const content = fs.readFileSync(filePath, 'utf8').replace(/^\uFEFF/, ''); for (const rawLine of content.split(/\r?\n/)) { const line = rawLine.trim(); if (!line || line.startsWith('#')) continue; const match = line.match(/^([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(.*)$/); if (!match) continue; let value = match[2].trim(); if ((value.startsWith('"') && value.endsWith('"')) || (value.startsWith("'") && value.endsWith("'"))) { value = value.slice(1, -1); } env[match[1]] = value; } return env; } catch { return {}; } } function readWorkspaceEnvLocal() { return readEnvFileMaybe(path.join(process.cwd(), '.env.local')); } function envLocalCandidates() { const candidates = []; let current = process.cwd(); while (current && !candidates.includes(path.join(current, '.env.local'))) { candidates.push(path.join(current, '.env.local')); const parent = path.dirname(current); if (parent === current) break; current = parent; } candidates.push(path.resolve(__dirname, '..', '..', '..', '.env.local')); return [...new Set(candidates)]; } function readEnvLocalFiles() { return envLocalCandidates().reduce((merged, filePath) => { const next = readEnvFileMaybe(filePath); for (const [key, value] of Object.entries(next)) { if (!merged[key]) merged[key] = value; } return merged; }, {}); } function readVocToken(input = {}) { const workspaceEnv = readEnvLocalFiles(); const claudeCreds = readJsonMaybe(path.join(os.homedir(), '.claude', 'voc-credentials.json')); return firstNonEmpty([ input.vocToken, input.xiaohongshuToken, input.douyinToken, input['voc-token'], input['xiaohongshu-token'], input['douyin-token'], input.token, input.apiToken, input['api-token'], workspaceEnv.VOC_TOKEN, workspaceEnv.VOC_SOCIAL_TOKEN, process.env.VOC_TOKEN, process.env.VOC_SOCIAL_TOKEN, claudeCreds.vocToken, claudeCreds.token, ]); } function readXiaohongshuToken(input = {}) { return readVocToken(input); } module.exports = { readVocToken, readXiaohongshuToken, readEnvFileMaybe, readWorkspaceEnvLocal, envLocalCandidates };