文件预览

config.ts

查看 youmind-wordpress-article 技能包中的文件内容。

文件内容

toolkit/src/config.ts

import { existsSync, readFileSync } from 'node:fs';
import { dirname, resolve } from 'node:path';
import { fileURLToPath } from 'node:url';
import { parse as parseYaml } from 'yaml';

const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const SKILL_CONFIG_NAME = 'youmind-wordpress-article';

export const DEFAULT_YOUMIND_OPENAPI_BASE_URL = 'https://youmind.com/openapi/v1';
export const YOUMIND_CONFIG_ERROR_HINT =
  `Set youmind.api_key in ~/.youmind/config.yaml. Optional skill overrides live in ~/.youmind/config/${SKILL_CONFIG_NAME}.yaml.`;

function getHomeDir(): string {
  return process.env.HOME || process.env.USERPROFILE || '';
}

function loadYamlFile(path: string): Record<string, unknown> {
  if (!path || !existsSync(path)) {
    return {};
  }
  return (parseYaml(readFileSync(path, 'utf-8')) ?? {}) as Record<string, unknown>;
}

function isPlainObject(value: unknown): value is Record<string, unknown> {
  return typeof value === 'object' && value !== null && !Array.isArray(value);
}

function hasConfiguredValue(value: unknown): boolean {
  if (value === undefined || value === null) {
    return false;
  }
  if (typeof value === 'string') {
    return value.trim().length > 0;
  }
  return true;
}

function mergeWithFallback(
  primary: Record<string, unknown>,
  fallback: Record<string, unknown>,
): Record<string, unknown> {
  const result: Record<string, unknown> = { ...primary };

  for (const [key, fallbackValue] of Object.entries(fallback)) {
    const currentValue = result[key];

    if (isPlainObject(currentValue) && isPlainObject(fallbackValue)) {
      result[key] = mergeWithFallback(currentValue, fallbackValue);
      continue;
    }

    if (!hasConfiguredValue(currentValue) && hasConfiguredValue(fallbackValue)) {
      result[key] = fallbackValue;
    }
  }

  return result;
}

function loadSharedConfig(): Record<string, unknown> {
  const home = getHomeDir();
  if (!home) {
    return {};
  }
  return loadYamlFile(resolve(home, '.youmind', 'config.yaml'));
}

function loadSkillOverrideConfig(): Record<string, unknown> {
  const home = getHomeDir();
  if (!home) {
    return {};
  }
  return loadYamlFile(resolve(home, '.youmind', 'config', `${SKILL_CONFIG_NAME}.yaml`));
}

export function loadLayeredConfig(): Record<string, unknown> {
  return mergeWithFallback(loadSkillOverrideConfig(), loadSharedConfig());
}

export function normalizeBaseUrl(value: string | undefined): string {
  if (!value) return '';
  const trimmed = value.replace(/\/+$/, '');
  if (trimmed.endsWith('/openapi/v1')) return trimmed;
  if (trimmed.endsWith('/openapi')) return `${trimmed}/v1`;
  return `${trimmed}/openapi/v1`;
}

function getImageYouMindConfig(raw: Record<string, unknown>): Record<string, unknown> {
  const image = raw.image;
  if (!isPlainObject(image)) {
    return {};
  }
  const providers = image.providers;
  if (!isPlainObject(providers)) {
    return {};
  }
  const youmind = providers.youmind;
  return isPlainObject(youmind) ? youmind : {};
}

export function loadYouMindConfig(): {
  apiKey: string;
  baseUrl: string;
  raw: Record<string, unknown>;
} {
  const raw = loadLayeredConfig();
  const youmind = isPlainObject(raw.youmind) ? raw.youmind : {};
  const imageYouMind = getImageYouMindConfig(raw);
  const apiKey =
    (typeof youmind.api_key === 'string' && youmind.api_key) ||
    (typeof imageYouMind.api_key === 'string' && imageYouMind.api_key) ||
    '';
  const configuredBaseUrl =
    typeof youmind.base_url === 'string' ? normalizeBaseUrl(youmind.base_url) : '';

  return {
    raw,
    apiKey,
    baseUrl: configuredBaseUrl || DEFAULT_YOUMIND_OPENAPI_BASE_URL,
  };
}