npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

friendaix-core

v0.3.0

Published

Reusable, transactional configuration engine for AI coding clients

Readme

friendaix-core

friendaix-core 是 FriendAIX 提取出的通用配置引擎。它提供 Claude Code、Codex CLI、OpenCode adapter,以及原子写入、事务备份、回滚和恢复能力,不包含 FriendAIX 域名、品牌或交互界面。

安装

npm install friendaix-core

需要 Node.js 20.12 或更高版本。

示例

import { homedir } from 'node:os';
import { join } from 'node:path';
import {
  applyConfiguration,
  createClaudeAdapter,
  restoreOperation,
} from 'friendaix-core';

const context = { homeDir: homedir() };
const adapter = createClaudeAdapter({
  defaultModel: 'claude-sonnet-4-6',
  defaultSmallModel: 'claude-haiku-4-5',
});

const plan = await adapter.plan(
  {
    baseUrl: 'https://gateway.example.com/v1',
    apiKey: process.env.GATEWAY_API_KEY!,
    primaryModel: 'claude-sonnet-4-6',
    smallModel: 'claude-haiku-4-5',
  },
  context,
);

// 应由调用方先展示 plan.writes 和 plan.warnings,并确认破坏性警告。
const backup = await applyConfiguration([plan], {
  backupRoot: join(homedir(), '.my-configurator', 'backups'),
});

// 恢复该次操作开始前的状态。
await restoreOperation(backup.directory, {
  backupRoot: join(homedir(), '.my-configurator', 'backups'),
  allowedPaths: adapter.configFiles(context),
});

如果调用进程需要遵循客户端的自定义配置目录,可显式传入环境快照和平台:

const context = {
  homeDir: homedir(),
  environment: process.env,
  platform: process.platform,
};

内置 adapter 会识别 CLAUDE_CONFIG_DIRCODEX_HOMEOPENCODE_CONFIG_DIRXDG_CONFIG_HOMEXDG_DATA_HOME,以及 Windows 的 LOCALAPPDATA。覆盖目录必须是绝对路径;不传 environment 时不会读取调用进程的环境变量。

安全边界

  • 库不会主动联网,也不收集遥测。
  • adapter 只生成配置计划;调用方决定何时展示、确认和执行。
  • applyConfiguration 会在任何写入前备份全部目标文件。
  • 计划带有 adapter 读取内容的 SHA-256 前置条件;文件在计划后变化时会拒绝覆盖。
  • 写入使用同目录临时文件和原子替换。
  • 任一写入失败会回滚本次已经完成的写入。
  • 恢复必须传入 allowedPaths,恶意或损坏的 manifest 不能写入任意路径。
  • 配置和备份内容必须是普通文件;符号链接、目录和其他特殊文件会被拒绝,避免链接替换与备份源跳转。
  • adapter 会拒绝空密钥、空模型,以及带账号、查询参数或片段的非 HTTP(S) 服务地址。
  • POSIX 上备份文件和 manifest 使用 0600,备份目录使用 0700;Windows 继承用户目录 ACL。

调用方仍需负责:不回显密钥、确认 adapter 的 destructive warning、保护进程环境,以及向用户解释具体服务的数据流。

扩展客户端

实现 ClientAdapter

  • configFiles(context) 返回 adapter 管理的绝对路径。
  • isInstalled(context) 只用于 UX 提示。
  • plan(input, context) 读取现有配置并返回完整 AdapterPlan
  • 不要在 plan 内写文件或调用外部服务。
  • 含密钥的 PlannedWrite 必须设置 containsSecret: true
  • 每个 PlannedWrite.expected 必须对应生成内容时读取的同一份原始字节;文本配置可使用核心库导出的 readOptionalTextFileWithExpectation()

自定义 adapter 读取与计划的关键部分如下:

import { readOptionalTextFileWithExpectation } from 'friendaix-core';

const current = await readOptionalTextFileWithExpectation(configPath);
const nextContent = mergeYourConfig(current.content ?? '');

return {
  clientId: 'my-client',
  clientName: 'My Client',
  warnings: [],
  writes: [
    {
      clientId: 'my-client',
      path: configPath,
      content: nextContent,
      containsSecret: false,
      expected: current.expectation,
    },
  ],
};

完整设计见仓库的 docs/architecture.md

License

MIT © 2026 YouR.AI