内容
# 🥞 fln
[](https://github.com/nesvet/fln/actions/workflows/ci.yaml)
[](https://www.npmjs.com/package/fln)
[](https://www.npmjs.com/package/fln)
[](LICENSE)
**本地、可解释的 AI 编程代理上下文编译器。无需嵌入。无需服务器的上下文。**

fln 分析您的代码库,计划包含的内容,并生成单个 AI 就绪文件,并提供诊断信息以解释每个决策。可以将其视为 `tsc` 的 LLM 上下文版本:**分析 → 计划 → 生成**,所有操作均在本地进行。
## 快速开始
```bash
npx fln # 或:npm i -g fln · bunx fln · brew install nesvet/tap/fln
fln # → 当前目录下的 my-app-1.2.0.md
```
```bash
$ fln --no-ansi
✓ my-app-1.2.0.md (42 个文件,12_840 个令牌)
```
一个 Markdown 文件 — 标题、目录树、反引号安全围栏。可以粘贴到 Claude、ChatGPT、Gemini、Grok、Cursor 或 Copilot;通过 CLI LLM 传递(`fln --stdout | llm "..."`);或通过 **MCP** 提供服务。
````markdown
<!-- 🥞 fln 2.0.0 -->
# 代码库快照:demo-app
生成时间:2026-07-06 17:30
文件:6 | 目录:3
---
## 目录树
```text
├── README.md
├── package.json
├── src
│ ├── index.ts
│ ├── helper.ts
│ └── utils.ts
└── tests
└── index.test.ts
```
---
## 源文件
### src/index.ts
```ts
import { helper } from "./helper";
import { format } from "./utils";
export function main(): string {
return format(helper());
}
```
````
[为什么选择 fln](#为什么选择fln) · [比较](#fln与其他工具的比较) · [工作流](#工作流) · [安装](#安装) · [用法](#用法) · [API](#API) · [FAQ](#FAQ)
### 适用人群
- CI 预算守护、重现性快照、离线打包
- 需要计划的、可解释的上下文的 MCP 上下文服务器
- 无嵌入的导入图检索(`--relevant`)
### 不适用人群
- 仅限远程的一次性摘要([gitingest](https://github.com/coderamp-labs/gitingest)、[repomix](https://github.com/yamadashy/repomix) `--remote`)
- IDE 中大型代码库的实时 `@codebase`(Cursor)
- 以 Tree-sitter 压缩为主要目标(repomix `--compress`)
---
## 为什么选择 fln
如果您在实际项目中使用 LLM,您会遇到这些限制:
- **上下文窗口** — 整个项目都无法适应
- **上传摩擦** — 每次会话都选择数十个文件
- **部分理解** — 模型看到的是片段,而不是架构
- **缺乏可解释性** — 为什么排除此文件?过滤了什么秘密?
**fln 将代码库上下文视为 `tsc` 处理 TypeScript 的方式**:分析、计划、生成 — 带有诊断信息(`why`、`doctor`、`plan`、`diff`)和 MCP。无需嵌入,无需服务器的 JIT 代理检索(工具调用、嵌入、实时搜索)非常适合交互式探索。fln 是互补的 **AOT 快照编译器**:它在代理启动前生成确定性的上下文主干 — 基于结构的检索(导入、优先级、令牌预算),无需嵌入,无需服务器。相同的输入 → 相同的快照;CI 友好;离线。
---
## fln 与其他工具的比较
| | **fln** | **repomix** | **code2prompt** | **gitingest** | **Cursor `@codebase`** |
|---|---|---|---|---|---|
| **角色** | 上下文编译器 + 诊断 | 功能丰富的打包工具 | 提示模板 CLI | Web + CLI 摘要 | IDE 检索 |
| **本地优先** | ✓ | ✓ | ✓ | ✓ (CLI) | ✗ 云 |
| **MCP** | ✓ 5 种工具 + 资源 | ✓ | ✓ | ✗ | ✗ |
| **`why` / `doctor` / `plan` / `diff`** | ✓ 一流 CLI | ✗ | ✗ | ✗ | ✗ |
| **导入图(`--relevant`)** | ✓ | ✗ | ✗ | ✗ | ✗ |
| **`--stdin` 管道** | ✓ | ✗ | ✗ | ✗ | ✗ |
| **原生二进制文件** | ✓ | ✗ | ✓ (Rust) | ✗ | n/a |
| **远程仓库** | ✗ | ✓ | ✗ | ✓ | n/a |
| **Tree-sitter 压缩** | ✗ (基于行) | ✓ | ✗ | ✗ | n/a |
| **Web UI** | ✗ | ✓ | ✓ | ✓ | IDE |
### 何时使用什么
- **fln** — CI 预算守护、MCP 上下文服务器、可重现快照、`why`/`doctor`/`plan`/`diff`、 `--relevant`、 `--stdin`
- **repomix** — 远程仓库、Tree-sitter `--compress`、监视模式、Web UI
- **code2prompt** — Handlebars 提示模板和自定义提示管道
- **gitingest** — 快速 Web 摘要 / `hub`→`ingest` URL 技巧
- **Cursor `@codebase`** — 大型仓库的实时 IDE 检索
并非互相排斥:fln 和 repomix 都生成可粘贴的文件;fln 添加编译器/诊断层。
---
## 工作流
### 计划后再压缩
`fln plan` 为每个文件分配保真度,并在您花费预算之前预测令牌:
```bash
$ fln plan --relevant src/cli/index.ts --budget 200000
```
```
# 上下文计划:.
预算:200,000 个令牌
预计:67,149 个令牌
包含的文件:100
省略的文件:1
## 包含的文件
src/api/index.ts — ~239 个令牌(入口点 — 高优先级)
src/cli/index.ts — ~89 个令牌(种子文件)
src/cli/output/index.ts — ~28 个令牌(入口点 — 高优先级)
...
```
完整输出: [`assets/demo-plan.md`](assets/demo-plan.md)。为 CI/代理使用 `--format json`。正式模式: [schema/fln-plan.json](schema/fln-plan.json) (`$id`: `https://fln.nesvet.dev/schema/plan`).
```bash
fln plan --budget 200000
fln plan --relevant src/cli/index.ts --budget 200000
fln plan --format json
```
### 解释、预检、MCP
```bash
fln why .env # 为什么排除 .env?
fln why src/index.ts # 为什么包含 index.ts?
fln why .env --format json # 机器可读的 CI/代理
fln doctor . # 配置、git、扫描统计、令牌估计
fln doctor --max-tokens 200000 # 警告如果超出预算
fln doctor --format json --recommend-budget 200000
fln mcp # 标准输入/输出 MCP 服务器
fln mcp --http --port 3000 # 可流式 HTTP
```
`fln why` 是一个一流的路径决策 CLI,具有稳定的原因(gitignore、安全、大小、允许列表……)和用于代理的 JSON。
| MCP 工具 | 它做什么 |
|---|---|
| `fln_snapshot` | 扁平化 → Markdown/JSON 内联 |
| `fln_plan` | 预算计划 — 每个文件的保真度 |
| `fln_diff` | 比较两个快照 |
| `fln_why` | 解释包含/排除 |
| `fln_doctor` | 预检诊断 |
资源: `fln_file://{path}`、`fln_snapshot://{name}`.
```json
{
"mcpServers": {
"fln": { "command": "fln", "args": ["mcp"] }
}
}
```
### 与您的工具组合
`--stdin` 强制包含管道路径(像 `-i` 一样),然后修剪树为确切的集合。仍然应用安全 — 检测到的秘密永远不会嵌入:
```bash
git ls-files | fln --stdin -o snapshot.md
git ls-files --others | fln --stdin -o untracked.md
git diff --name-only HEAD~1 | fln --stdin --stdout
rg -l TODO | fln --stdin --stdout
git diff --name-only main | fln plan --stdin --budget 50000
```
```bash
fln --copy # 剪贴板(默认 32 MiB;可通过 FLN_COPY_MAX_BYTES 重写)
fln --stdout | llm "这个代码库最大的架构问题是什么?"
fln --stdout | pbcopy # 当 --copy 不可用时作为后备
```
```bash
fln --since main --ext ts,tsx
fln --since main --diff-hunks
fln --relevant src/index.ts --outline
fln --banner-file .prompt.md
fln --banner "审查此代码库是否存在安全漏洞。"
```
---
## 亮点
| | |
|---|---|
| 单次 I/O | 扫描仅读取元数据;渲染执行一次完整内容读取 |
| 诊断 | `why`、`doctor`、`plan`、`diff` — 文本 + JSON 模式 |
| MCP | 五种工具 + 文件/快照资源(标准输入/输出或 HTTP) |
| 导入图 | `--relevant` for TS/JS/Py/Go/Rust/Java/C — 无嵌入 |
| 安全 | 路径模式 + 熵 + 已知秘密格式在头部([SECURITY.md](SECURITY.md)) |
| 原生二进制文件 | 无需 Node(`curl` 安装 / Homebrew / `fln upgrade`) |
| 确定性 | 稳定排序; `--date` 用于可重现构建 |
| 令牌预算 | `--max-tokens` / `plan --budget` 具有优先级排序 |
**性能:** 中型固定装置(5000 个文件)的 linux-x64 CI 基线 — 干运行 ~1.1s,完整扁平化 ~2.4s(中位数;门控 = 基线 +10%)。详情: [`benchmarks/README.md`](benchmarks/README.md).
<details>
<summary>完整功能列表</summary>
- 并行扫描;尊重 `.gitignore`;跳过二进制文件/锁定文件;可配置大小限制
- 目录感知文件顺序(README/入口/配置优先;测试/`vendor/` 降级)
- 每次运行的令牌计数; `--verbose` 扩展分解;自我感知(跳过之前的 fln 输出)
- 反引号安全围栏(适应最大运行 + 安全边距,用于大样本)
- 项目元数据命名来自 `package.json`、`Cargo.toml`、`pyproject.toml`、`pom.xml`、`go.mod`、…
- 输出: `md` / `json`; `--compress` / `--outline` (自定义基于行的签名,而不是 Tree-sitter)
- `--max-total-size` 宽容省略; `--strict-limits` 用于 CI; `doctor --recommend-budget`
- TOCTOU 警告/抛出( `--strict-toctou`); `--annotate-tree`; `--collect-todo` (相同内容传递)
- `--dry-run`; 命名空间 API: `fln()`、 `.inspect()`、 `.explain()`、 `.doctor()`、 `.plan()`、 `.diff()`、 `.mcp()`
- JSON 中的 `omittedFiles` (扁平、封顶、所有原因)
</details>
---
## 隐私
- **正常运行期间无网络**(`flatten`、`why`、`doctor`、`plan`、`diff`、`mcp`)。`fln upgrade` 是明确的例外。
- 本地 `~/.config/fln/usage.json` 可能存储 `runCount` / `lastRun` 仅用于(赞助消息在运行 5 和 25 上)。隐藏: `FLN_NO_SPONSOR=1` 或 `--no-sponsor-message`。跳过写入: `--no-local-state`。
---
## 安装
```bash
npx fln # 运行一次
bunx fln
npm install -g fln
bun add -g fln
# 原生二进制文件 — 无需 Node
curl -fsSL https://fln.nesvet.dev/install | sh
powershell -c "irm fln.nesvet.dev/install.ps1 | iex"
brew install nesvet/tap/fln
# Homebrew 6.0+:在首次使用时信任公式
brew trust --formula nesvet/tap/fln
fln upgrade # 二进制文件自我更新(sha256 + 可选 cosign)
```
<details>
<summary>更多安装选项 · shell 补全</summary>
**固定版本/自定义目录(macOS/Linux):**
```bash
curl -fsSL https://fln.nesvet.dev/install | FLN_VERSION="<version>" INSTALL_DIR="$HOME/.local/bin" sh
```
**Windows:**
```powershell
$env:FLN_VERSION = "<version>"
$env:INSTALL_DIR = "$env:LOCALAPPDATA\fln\bin"
powershell -c "irm fln.nesvet.dev/install.ps1 | iex"
```
**手动 GitHub 发布:
```bash
curl -L "https://github.com/nesvet/fln/releases/latest/download/fln-macos-x64.tar.gz" | tar -xz -C /usr/local/bin
chmod +x /usr/local/bin/fln
```
**补全**(bash/zsh/fish/PowerShell)— 从克隆:`source completions/_fln`(zsh),`source completions/fln.bash`等。在 `npm i -g fln` 之后:`source "$(npm root -g)/fln/completions/_fln"`。重新生成:`bun run generate:completions`。
</details>
---
## 用法
```bash
fln [directory] [...flags]
fln init [--overwrite]
fln why <path> [directory] [...flags]
fln doctor [directory] [...flags]
fln plan [directory] [--budget <n>] [--relevant <seed>] [...flags]
fln diff <before> <after> [...flags]
fln diff --since <ref>
fln mcp [directory]
fln upgrade
```
```bash
fln # → my-app-1.2.0.md
fln . -o context.md
fln src -o . # 扫描 src/,写入项目根目录
fln -e "*.test.ts" -e "fixtures/"
fln -e "*.md" -e '!README.md'
fln --ext ts,tsx --since HEAD~1
fln -i "src/generated/schema.ts" # 强制包含 gitignored 文件
fln --only "**/*.ts"
fln why .env --include-hidden
fln --dry-run --verbose
fln --format json -o snapshot.json
fln mcp
```
### 过滤模型(2.x)
| 机制 | 效果 |
|-----------|--------|
| `-e` / `exclude` | 排除;`!pattern` 在 `.gitignore` 之后取消忽略 |
| `-i` / `include` | 强制包含(绕过忽略 + 隐藏) |
| `--stdin` / `stdinPaths` | 强制包含 + 修剪到管道集 |
| `--only` / `--since` / `--ext` | 白名单 |
| `--include-hidden` | 所有点文件;不适用于 `-i .env` |
| 安全模式 | 强制显示节点树;**永远不会** 嵌入机密 |
超过 `--max-file-size` 的文件将被跳过,除非强制包含(`-i` / `--stdin`);内容在渲染时流式传输。参见 [SECURITY.md](SECURITY.md)。
<details>
<summary>所有 CLI 标志</summary>
规范列表:`fln --help`。配置:[`fln.json`](#config-file) / [schema/fln.json](schema/fln.json)。API:下方。
多词标志接受 **camelCase** 别名(例如 `--maxFileSize`、`--noTree` — 文档使用 kebab-case)。
**子命令**
| 命令 | 描述 |
|---|---|
| `fln init` | 从模板创建 `fln.json` 和 `.mcp.json` |
| `fln why <path>` | 解释包含/排除( `--format text\|json` ) |
| `fln doctor [dir]` | 预检:配置、git、统计、令牌估计( `--format text\|json` ) |
| `fln plan [dir]` | 预算计划 — 每个文件的保真度( `--budget`、`--relevant`、`--format` ) |
| `fln diff <before> <after>` | 快照差异 — 添加/删除/更改、树增量 |
| `fln mcp [dir]` | MCP 服务器(标准输入/输出或 `--http` ) |
| `fln upgrade` | 安装最新二进制文件(需要 sha256;如果在 PATH 上则使用 cosign) |
**输出**
| 标志 | 描述 |
|---|---|
| `-o, --output <path>` | 输出文件或目录。添加 `.md`/`.json` 如果没有扩展名。默认为 `<n>-<version>.md` |
| `-w, --overwrite` | 覆盖而不是数字后缀 |
| `--stdout` | 写入标准输出(意味着 `--quiet` ) |
| `--copy` | 剪贴板复制(意味着 `--quiet` ;不适用于 `-o`、`--stdout`、`--dry-run`、`--output-split` > 1) |
| `--ignore-config` | 跳过 `fln.json` |
| `--format <md\|json>` | 输出格式(默认:`md` ) |
| `--dry-run` | 扫描/报告而不写入 |
| `--output-split <n>` | 按限制分割输出部分(默认:1) |
**过滤**
| 标志 | 描述 |
|---|---|
| `-e, --exclude <glob>` | 排除 — 可重复;`!` 在 `.gitignore` 之后取消忽略 |
| `-i, --include <glob>` | 强制包含(添加;可重复) |
| `--only <glob>` | 白名单(可重复) |
| `--stdin` | 标准输入路径 — 强制包含 + 修剪 |
| `--ext <ext>` | 白名单扩展名,例如 `ts,tsx,js` |
| `--since <ref>` | 白名单:自 git 引用以来更改 |
| `--include-hidden` | 包含隐藏文件/目录 |
| `--no-gitignore` | 忽略 `.gitignore` |
| `--max-file-size <size>` | 最大文件大小,例如 `10mb` |
| `--max-total-size <size>` | 最大输出大小;宽容省略除非 `--strict-limits` |
| `--max-tokens <n>` | 令牌预算(优先级:README/配置在测试之前) |
| `--max-content-tokens <n>` | 仅源部分的令牌预算 |
| `--token-model <model>` | `estimate`、`gpt-4`、`gpt-4o`、`gpt-5`、`claude`、`gemini` (参见 [令牌模型](#token-models)) |
| `--security-check <default\|strict>` | 默认:512B 头;严格:4KiB,扩展模式 |
| `--strict-limits` | 超出限制时抛出 |
| `--follow-symlinks` | 跟随符号链接 |
**内容**
| 标志 | 描述 |
|---|---|
| `--no-contents` | 仅限树 |
| `--no-tree` | 无目录树 |
| `--compress` | 支持的签名;其他地方的完整内容 |
| `--outline` | 仅限签名 |
| `--relevant <path>` | 导入图邻域(可重复) |
| `--strict-toctou` | 如果文件在扫描和渲染之间更改,则抛出 |
| `--diff-hunks` | 与 `--since`:统一的差异而不是完整文件。与 `fln diff`:文件内的块 |
| `--annotate-tree <tokens\|lines\|size>` | 注释树;`tokens`/`lines` 将树延迟到结尾 |
| `--collect-todo` | 收集 TODO/FIXME/… 标记 |
| `--encoding <auto\|utf8\|latin1>` | 文本编码 |
| `--banner` / `--banner-file` | 前置文本/文件 |
| `--footer` / `--footer-file` | 后置文本/文件 |
| `--date <YYYY-MM-DD HH:mm>` | 固定的生成日期 |
**医生:** `--recommend-budget <n>`。**MCP:** `--http`、`--port <n>` (默认 3000)。
**日志记录:** `-q` / `-V` / `--debug` / `--no-ansi` / `--no-sponsor-message` / `--no-local-state` / `-v` / `-h`。
> 引用通配符:`"*.test.ts"`。取消排除:`-e "*.md" -e '!README.md'`。
</details>
---
## 配置文件
```bash
fln init
```
写入具有 JSON 架构智能提示的 `fln.json`( `$schema`: `https://fln.nesvet.dev/schema` )。
<details>
<summary>fln.json 参考</summary>
```json
{
"$schema": "https://fln.nesvet.dev/schema",
"output": "output.md",
"exclude": [],
"include": [],
"only": [],
"includeHidden": false,
"maxFileSize": "10mb",
"maxTotalSize": "0",
"maxTokens": 0,
"maxContentTokens": 0,
"tokenModel": "estimate",
"strictLimits": false,
"encoding": "auto",
"format": "md",
"followSymlinks": false,
"overwrite": false
}
```
其他键(`gitignore`、`banner`、`securityPatterns`、...): [schema/fln.json](schema/fln.json) 和 [API](#api)。模式相对于输入的 gitignore 样式;CLI 合并配置文件( `--ignore-config` 跳过它)。
</details>
---
## 持续集成/持续部署和自动化
每次推送都生成新的 `codebase.md` — 随时下载以了解 `main` 或 PR 的确切状态:
```yaml
# .github/workflows/codebase-snapshot.yaml
name: 快照代码库
on:
push:
branches: ["main"]
pull_request:
jobs:
snapshot:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: 生成快照
run: npx fln . -o codebase.md -w --no-ansi
- uses: actions/upload-artifact@v6
with:
name: codebase-snapshot
path: codebase.md
retention-days: 7
```
预提交预算守护:
```bash
# .husky/pre-commit
npx fln . --dry-run --max-total-size 5mb
```
---
## API
```bash
npm install fln
```
```typescript
import { fln } from "fln";
const result = await fln({
input: "./src",
output: "snapshot.md",
exclude: ["*.test.ts", "fixtures/"],
onProgress: (current, total) => {
process.stdout.write(`\r${current}/${total} files`);
},
});
console.log(`${result.filesIncluded} files → ${result.outputPath}`);
console.log(`~${result.outputTokenCount.toLocaleString()} tokens`);
const { root, stats } = await fln.inspect({ input: "./src", dryRun: true });
const decision = await fln.explain({ path: ".env", input: "./src" });
const report = await fln.doctor({ input: "./src" });
const planResult = await fln.plan({
input: "./src",
budget: 200_000,
relevant: ["src/index.ts"],
});
const diffResult = await fln.diff({ before: "snapshot-v1.md", after: "snapshot-v2.md" });
await fln.mcp({ defaultInput: "./src" });
```
正式的 JSON 模式:[plan](schema/fln-plan.json)(`$id`: `https://fln.nesvet.dev/schema/plan`),[diff](schema/fln-diff.json)(`$id`: `https://fln.nesvet.dev/schema/diff`)。
<details>
<summary>完整的 API 参考</summary>
与包类型中的 `FlnOptions` / `FlnResult` / `FlnInspectResult` / `FlnMcpOptions` 匹配。
**选项(`FlnOptions`)**
| 选项 | 类型 | 默认值(API) | 描述 |
|---|---|---|---|
| `input` | `string` | `process.cwd()` | 要扁平化的目录 |
| `output` | `string` | 自动 | 输出文件或目录;`-` 表示标准输出 |
| `overwrite` | `boolean` | `false` | 覆盖而不是数字后缀 |
| `exclude` | `string[]` | `[]` | 要排除的 glob 模式 |
| `include` | `string[]` | `[]` | 强制包含的路径(累加) |
| `only` | `string[]` | `[]` | 白名单:仅匹配的文件 |
| `onlyMode` | `boolean` | - | 仅在设置为 `only` 时限制扫描(默认为 `only` 非空时为 `true`) |
| `stdinPaths` | `string[]` | - | 通过标准输入管道的文件路径(CLI:`--stdin`)。强制包含(绕过忽略 + 隐藏),然后修剪树为这些文件。安全模式仍然适用。 |
| `relevant` | `string[]` | - | 种子路径 - 仅包含这些文件 transitively 导入的文件 |
| `includeHidden` | `boolean` | `false` | 包括隐藏文件和目录 |
| `gitignore` | `boolean` | `true` | 尊重 `.gitignore` 规则 |
| `maxFileSize` | `number \| string` | `"10mb"` | 最大单个文件大小 |
| `maxTotalSize` | `number \| string` | `0` | 最大输出大小(`0` = 无限制);温和省略除非 `strictLimits` |
| `maxTokens` | `number` | `0` | 输出中的最大估计令牌数(`0` = 无限制) |
| `maxContentTokens` | `number` | `0` | 仅源部分的令牌预算(`0` = 对整个输出使用 `maxTokens`) |
| `tokenModel` | `"estimate" \| "gpt-4" \| "gpt-4o" \| "gpt-5" \| "claude" \| "gemini"` | `"estimate"` | 令牌计数模型 |
| `tree` | `boolean` | `true` | 包括目录树。CLI:`--no-tree` 排除。配置 `"tree": false` 不被 CLI 覆盖(仅退出标志) |
| `contents` | `boolean` | `true` | 包括文件内容。CLI:`--no-contents` 表示仅树形输出 |
| `format` | `"md" \| "json"` | `"md"` | 输出格式 |
| `followSymlinks` | `boolean \| "in-root-only"` | `false` | 遵循符号链接;配置可能使用 `"in-root-only"` |
| `date` | `string` | 当前时间 | 生成的头部固定 `YYYY-MM-DD HH:mm` |
| `banner` | `string` | - | 在头部后添加的文本 |
| `bannerFile` | `string` | - | 添加的文件(相对于输入;从树中排除) |
| `footer` | `string` | - | 在结尾追加的文本 |
| `footerFile` | `string` | - | 追加的文件(相对于输入;从树中排除) |
| `dryRun` | `boolean` | `false` | 仅扫描和统计 - 不输出文件 |
| `copy` | `boolean` | `false` | 写入临时文件,然后复制到系统剪贴板(CLI:`--copy`) |
| `ignoreConfig` | `boolean` | `false` | 跳过 `fln.json`(CLI:`--ignore-config`) |
| `strictLimits` | `boolean` | `false` | 超出限制时抛出而不是温和省略 |
| `strictToctou` | `boolean` | `false` | 抛出文件在扫描和渲染之间更改时(否则警告) |
| `compress` | `boolean` | `false` | 签名提取 - 导入、类型、函数签名(省略正文;完整内容在无提取器处) |
| `outline` | `boolean` | `false` | 仅签名 - 没有实现(意味着 `contents`) |
| `diffHunks` | `boolean` | `false` | 使用 `since`:嵌入统一的 diff hunks 而不是完整文件 |
| `since` | `string` | - | 用于 diff 模式的 Git 引用(通常通过 CLI `--since` 设置) |
| `encoding` | `"auto" \| "utf8" \| "latin1"` | `"auto"` | 文本文件编码 |
| `securityPatterns` | `string[]` | 内置 + 配置 | 敏感路径的额外 glob(检测的内容从不嵌入) |
| `outputSplit` | `number` | `1` | 按限制分割输出的最大部分数 |
| `onProgress` | `(current, total) => void` | - | 进度回调 |
| `logLevel` | `"silent" \| "normal" \| "verbose" \| "debug"` | `"silent"` | 日志级别(CLI 默认在非静默时为 `"normal"`) |
| `ansi` | `boolean` | `false` | 日志输出中的 ANSI 颜色 |
**MCP 选项(`FlnMcpOptions`)**
| 选项 | 类型 | 默认值 | 描述 |
|---|---|---|---|
| `defaultInput` | `string` | `process.cwd()` | 未由工具调用指定的默认输入目录 |
| `maxSnapshotBytes` | `number` | `2 MiB` | `fln_snapshot` 工具的最大内联输出大小 |
| `http` | `boolean` | `false` | 在 Streamable HTTP 上启动 MCP 而不是 stdio |
| `port` | `number` | `3000` | `http` 为 true 时的 HTTP 监听端口 |
使用单独的 `fln.json` 时,配置文件的 `logLevel` 默认值为 `"normal"`。
**诊断:** `fln why <path>` 从 CLI(`--format json` 用于代理/CI;不在 `fln.json` 中)。SDK:`fln.explain()`。
### 医生(预检)
`fln doctor [directory]` 运行一个**干运行扫描**(仅元数据,无扁平文件)。与扁平化相同的过滤标志(`-e`,`-i`,`--only`,`--since`,`--ext`,`--stdin`,...)。
| 退出状态 | 含义 |
|------|---------|
| `0` | 至少有一个文件将被包含 |
| `1` | 无效的 `fln.json` 或配置错误 |
| `2` | 没有文件被包含 |
人为输出包括配置文件路径、git 分支/脏、文件计数、估计大小/令牌(±20% vs 真实扁平)、顶部扩展和警告(超大文件、安全路径在树中、`--max-tokens` 预算)。使用 `--since` 且没有匹配的更改时,打印与 `fln` 相同的早期消息并退出 `0`。
```bash
fln doctor .
fln doctor --format json --max-tokens 500000
fln doctor --format json --recommend-budget 200000
```
JSON 形状:`schemaVersion: 1`,`config`(`loaded`,`path`,可选 `ignored` 当 `--ignore-config`),`git`,`scan`,`estimate`,`extensions`,`warnings`,可选 `recommend`(`exclude`,`projectedTokens`,`omittedCount`)。正式模式:[schema/fln-doctor.json](schema/fln-doctor.json)(`$id`: `https://fln.nesvet.dev/schema/doctor`)。
```typescript
import { fln, toFlnWhyJson } from "fln";
const report = await fln.doctor({
input: projectDir,
recommendBudget: 200_000,
});
const decision = await fln.explain({ path: ".env", input: projectDir });
// why CLI JSON: { schemaVersion: 1, input: "<abs dir>", decision: { relativePath, included, reason, detail? } }
```
`fln.doctor()` 不接受 `--no-local-state` 或 `--no-sponsor-message` - 那些是 CLI 独有的。程序赞助状态反映 `usage.json` 和 `FLN_NO_SPONSOR` 仅限。
### JSON 扁平输出
`--format json` 发出结构化文档。顶级 **`root`** 是 `FileNode` 树; **`options.tree`** / **`options.contents`** 是用于该运行的布尔标志。 **`files`** 数组在设置 `--no-contents` 时被省略。
正式模式:[schema/fln-output.json](schema/fln-output.json)(`$id`: `https://fln.nesvet.dev/schema/output`)。
| 字段 | 描述 |
|-------|-------------|
| `schemaVersion` | 始终为 `2` |
| `version` | fln 发布版本 |
| `generated` | `YYYY-MM-DD HH:mm` 时间戳 |
| `projectName` | 来自项目元数据的 |
| `input` | 扁平化目录的绝对路径 |
| `options` | 有效选项回声(参见模式) |
| `root` | 目录树(`FileNode`) |
| `files` | 文件内容数组(当 `options.contents` 为 true 时) |
| `omittedFiles` | 平坦的、按大小排序的省略文件列表 - `{path, reason, size}` - 限 1000(仅当省略文件时存在) |
| `omittedFilesTotal` | 省略文件总数(在限制之前) |
| `omittedFilesTruncated` | 当 `omittedFiles` 被限制时为 `true`(`omittedFilesTotal` > 1000) |
| `stats` | 扫描计数器(`omittedByReason` 在渲染限制后) |
```bash
fln --format json --max-tokens 200000 -o snap.json
jq '.omittedFiles[] | select(.reason=="tokenLimit") | .path' snap.json
```
使用 `fln why --format json` 时,错误使用 `toFlnFailureJson` 输出到 stderr(`{ ok: false, error: { code, message, hint? } }`)。
**检查(`fln.inspect`)** - 与 `fln()` 相同的选项,仅扫描。返回 `FlnInspectResult`:`projectName`,`root`(带有 `skipReason` 的 `FileNode`),`stats`。
**编程 API 表面:** 命名空间上的操作 - `fln()`,`fln.inspect()`,`fln.explain()`,`fln.doctor()`,`fln.plan()`,`fln.diff()`,`fln.mcp()`。独立:`VERSION`,`toFlnWhyJson`,`toFlnDoctorJson`,`toFlnPlanJson`,`toFlnDiffJson`,`toFlnFailureJson`,`formatPlanText`,`formatDoctorText`,`formatDiffText`,`FlnError`,以及类型。
**结果(`FlnResult`):** `projectName`,`filesIncluded`,`filesScanned`,`directories`,`binary`,`skipped`,`errors`,`totalSizeBytes`,`outputSizeBytes`,`outputTokenCount`,`outputPath`(`"-"` 表示 stdout,`""` 当 `dryRun` 或 `copy`)。
**错误代码(`FlnError`)**
| 代码 | 含义 | CLI 退出状态 |
|------|---------|----------|
| `INPUT_NOT_DIRECTORY` | `input` 不是目录 | 1 |
| `NO_FILES_INCLUDED` | 扫描未找到可包含的文件 | 2 |
| `INVALID_CONFIG` | 无效的大小/令牌限制或不兼容的标志 | 1 |
| `CLIPBOARD_TOO_LARGE` | `--copy` 输出超过剪贴板大小上限 | 1 |
| `CLIPBOARD_UNAVAILABLE` | 没有剪贴板实用程序或复制失败 | 1 |
| `LIMIT_EXCEEDED` | `--strict-limits` 和一个限制被击中 | 3 |
| `GIT_NOT_FOUND` | `git` 不在 PATH(`--since`) | 1 |
| `GIT_REF_INVALID` | 无效引用或不是 git 仓库 | 1 |
| `TOCTOU` | `--strict-toctou` 和文件在扫描和渲染之间更改 | 1 |
| `READ_FAILED` | 保留用于读取失败 | 1 |
| `UPGRADE_FAILED` | `fln upgrade` 失败 | 1 |
```typescript
import { fln, FlnError } from "fln";
try {
await fln({ input: dir });
} catch (error) {
if (error instanceof FlnError)
console.error(error.code, error.hint ?? error.message);
throw error;
}
</details>
---
## 常见问题
**fln 与 repomix 有何不同?**
两者都生成一个可粘贴的文件。repomix 是一个功能丰富的打包器(远程仓库、Tree-sitter 压缩、监视模式)。fln 是一个**编译器**,带有诊断 - `why`,`doctor`,`plan`,`diff`,`relevant`,以及一个 MCP 服务器。选择 repomix 进行一次性 web-chat 粘贴或远程仓库;选择 fln 时,您需要可重复性、CI 保护程序或可解释性。参见 [比较](#how-fln-compares)。
**我需要嵌入或服务器吗?**
不需要。fln 是完全本地的 - 普通运行期间没有网络交互。 `--relevant` 使用基于行的零依赖行解析器(TS/JS/Py/Go/Rust/Java/C)遍历导入图 - 基于结构检索,而不是相似性搜索。
**它与 MCP 代理一起工作吗?**
是的。 `fln mcp` 启动一个 MCP 服务器(默认为 stdio;`--http --port` 为 Streamable HTTP)公开 `fln_snapshot`,`fln_plan`,`fln_diff`,`fln_why` 和 `fln_doctor` 到任何 MCP 感知代理(Claude Code,Cursor,Codex CLI,VS Codex CLI, VS Code)。参见 [工作流](#workflows)。
**管道安全吗?**
检测到的机密绝不会嵌入,即使强制包含。fln 通过模式跳过敏感路径(`.env`,密钥,凭证),并在文件头上运行熵 + 已知机密检测(AWS,Google,GitHub,Stripe,Slack,Azure,GitLab,JWT,PEM)。强制包含的机密文件仍会以 `skipReason: "security"` 的形式保留在树中 - 内容被省略。检测不是保证 - 在共享输出之前请查看。参见 [SECURITY.md](SECURITY.md)。
**`--stdin` 是否会绕过 `.gitignore`?**
是的 - 故意。 `--stdin` 强制包含管道路径(绕过 `.gitignore`,排除和隐藏过滤器,如 `-i`),然后将树修剪为这些文件。安全模式仍然适用;路径解析到输入目录外部的路径将被丢弃。
**为什么选择 AOT 而不是 JIT 检索?**
它们解决不同的问题。 JIT(Cursor `@codebase`,代理搜索)非常适合大型仓库的交互式探索。 AOT(fln)非常适合可复制的快照,CI 上下文保护,预算规划和离线工作流 - 以及可解释性。您可以选择在代理启动前包含 *哪些内容*。它们是互补的;许多堆栈都使用两者。
**如何更新 fln?**
- **npm / Bun:** `npm install -g fln` 或 `bun add -g fln`
- **Homebrew:** `brew upgrade nesvet/tap/fln`
- **二进制安装** (`curl …/install`): `fln upgrade` - 下载最新的 GitHub Release,验证 sha256(必需),可选验证 cosign 如果 `cosign` 在 PATH 上。
---
## 令牌模型
`--token-model` 控制 fln 如何估算令牌计数,用于预算、医生和差异增量。
| 模型 | 方法 | 准确性 |
|---|---|---|
| `gpt-4` | BPE (`cl100k_base`) | GPT-4 家族的高精度 |
| `gpt-4o`,`gpt-5` | BPE (`o200k_base`) | GPT-4o / GPT-5 家族的高精度 |
| `estimate` | 字符启发式(~4 chars/token) | ±~30% 在代码上 |
| `claude`,`gemini` | 与 `estimate` 相同的启发式 | ±~30% - 无公共 BPE 编码器 |
使用 `gpt-4o` 或 `gpt-5` 时,请针对 OpenAI 模型。使用 `estimate` 进行快速检查。 Markdown 快照在头部记录模型;`fln diff` 使用它进行令牌增量。
---
## 预览
来自 [`examples/`](examples/) 的实际输出:
- [TypeScript](examples/ts-app.md)
- [Python](examples/python-app.md)
- [Go](examples/go-app.md)
- [Rust](examples/rust-app.md)
- [Java](examples/java-app.md)
<details>
<summary>运行时兼容性</summary>
**Node.js** - 需要 `>=22.0.0`,仅支持 ESM(`"type": "module"`)。通过 `npm i -g fln` 安装或使用 `npx` 运行。
**Bun** - 需要 `>=1.3.14`。通过 `bun add -g fln` 安装或使用 `bunx` 运行。
**独立二进制文件** - 无需运行时。 通过上述 `curl` / PowerShell 一键安装。
</details>
---
## 从 1.x 迁移
| 1.x | 2.0 |
|---|---|
| `rootDirectory` | `input` |
| `outputFile` | `output` |
| `excludePatterns` | `exclude` |
| `includePatterns` | `include`(强制包含;不再是白名单) |
| `onlyPatterns` | `only` |
| `maximumFileSizeBytes` | `maxFileSize` |
| `maximumTotalSizeBytes` | `maxTotalSize` |
| `generatedDate` | `date` |
| `useGitignore` | `gitignore` |
| `useAnsi` | `ansi` |
| `copyToClipboard` | `copy` |
| `.fln.json` | `fln.json`(不再加载) |
| JSON `rootDirectory` 字段 | `input` |
| `fln({ rootDirectory: dir })` | `fln({ input: dir })` |
| 通过 `-i` / `includePatterns` 的白名单 | `--only` / `only` 在配置中 |
`fln.json` 中的未知旧版键被拒绝,并出现 `Unknown config key` 错误。有关完整的 2.0 变更列表,请参见 [CHANGELOG.md](CHANGELOG.md)。
---
## 支持该项目
**`fln` 由一位开发者维护,免费开源。**
如果它为您节省了时间或改善了您的 AI 工作流程:
- ⭐️ **[Star the repo](https://github.com/nesvet/fln)** - 帮助发现该项目
- 💙 **[在 Patreon 上支持](https://www.patreon.com/nesvet)** - 让开发继续进行
## 贡献
欢迎提出 PR 和问题。本地门控:`bun run verify`(镜像 CI)。参见 [CONTRIBUTING.md](CONTRIBUTING.md) 了解设置,参见 [AGENTS.md](AGENTS.md) 了解架构和不变性。
## 许可
MIT © [Eugene Nesvetaev](https://nesvet.dev)
## 星际历史
[](https://star-history.com/#nesvet/fln)
MCP 配置
以下是此 MCP Server 的配置信息,可直接复制到 Cursor 或其他 MCP 客户端中使用。
mcp.json
连接信息
猜你喜欢
暂无推荐服务器