飞行箱
开发时调试的被动因果关系跟踪。
的问题
您要求LLM构建一个功能。它跨多个文件编写代码——处理程序、服务、实用程序。有东西坏了。现在怎么办?
你没有写代码,所以你没有它的心理模型。你不能只是“想清楚”bug在哪里。你把错误粘贴回LLM,它会猜测,你来回走动。也许它修复了它,也许它让它变得更糟。
问题不在于LLM不能调试,而在于它不能 *看见*。它编写了代码,但不知道运行时实际发生了什么。什么叫,什么争论,什么回来了,在哪里爆炸了。
Flightbox做什么
Flightbox记录函数执行情况——参数、返回值、错误、计时、父子关系和对象状态——然后将其写入Parquet文件。MCP服务器读取这些文件并公开工具,使LLM能够遍历执行跟踪、检测模式并跟踪对象状态更改。
不需要繁殖。法学硕士不必猜测发生了什么。它可以看。
Your app (instrumented) Claude / any MCP client
│ │
│ functions run normally │ "why did checkout fail?"
│ spans get recorded │
│ │ calls flightbox_failing
▼ │ → finds the error span
~/.flightbox/traces/*.parquet │ calls flightbox_walk
│ │ → traces up to the root cause
│ DuckDB reads ──────────│ calls flightbox_inspect
│ │ → sees the bad input
│ ▼
│ "the shipping calculator got
│ null instead of an address
│ because fetchUser returned
│ early on line 42"没有守护进程。SDK将Parquet文件写入目录。MCP服务器使用DuckDB读取它们。它们从不相互交谈——它们共享一个文件系统。
快速开始
1.检测你的应用程序
选项A:加载器挂钩(Node.js,推荐) --适用于tsx、ts节点、plain节点。零配置。
npm install @flightbox/register @flightbox/sdk
node --import @flightbox/register ./src/index.ts代码中的每个函数都会自动检测。没有Babel,就没有构建配置。
选项B:Vite插件(浏览器+节点) --自动检测您的代码,并通过WebSocket捕获浏览器跟踪。
npm install @flightbox/unplugin @flightbox/sdk// vite.config.ts
import flightbox from '@flightbox/unplugin/vite'
export default {
plugins: [
flightbox({
include: ['**/renderer/**'],
objects: { types: ['AGENT', 'ROOM', 'ITEM'] },
lineage: { maxHops: 2 },
}),
],
}这做了四件事:
- 范围 通过以下方式检测最近更改的文件
git diff--仅在爆炸半径内追踪代码 - 变换 那些用跟踪来包装函数的文件
- 别名
@flightbox/sdk→@flightbox/sdk/browser因此浏览器获得了轻量级的SDK - 启动WebSocket收集器 在Vite-dev服务器上,将浏览器跨度写入Parquet
选项C:其他捆绑商 --webpack、esbuild、Rollup(仅转换,无浏览器集合)。
// webpack
import flightbox from '@flightbox/unplugin/webpack'
// esbuild
import flightbox from '@flightbox/unplugin/esbuild'
// rollup
import flightbox from '@flightbox/unplugin/rollup'2.添加MCP服务器
{
"mcpServers": {
"flightbox": {
"command": "npx",
"args": ["@flightbox/mcp-server"]
}
}
}3.运行应用程序,然后提问
正常运行您的应用程序。当有什么东西坏了,问LLM:
“为什么结账失败?”
它将使用MCP工具查找错误,跟踪调用链,并检查导致问题的参数。
______________________________________________________________________
接线指南
Flightbox仪器会自动运行,但要充分利用它,您需要连接三件事: 目标跟踪, 注释,以及 跨界血统.
目标跟踪
当您的代码创建、更新或删除域实体时,请注释这些突变点:
import {
trackObjectCreate,
trackObjectUpdate,
trackObjectDelete,
} from '@flightbox/sdk'
// On entity creation — pass the full snapshot
trackObjectCreate('AGENT', agent.id, agent)
// On entity update — pass the current state as snapshot
// The MCP server computes diffs automatically via LAG() at query time
trackObjectUpdate('AGENT', agent.id, undefined, {
x: agent.position.x,
y: agent.position.y,
state: agent.state,
})
// If you already have a diff (e.g. from ECS dirty tracking), pass it as changes
trackObjectUpdate('AGENT', agent.id, {
position: { from: { x: 61, y: 54 }, to: { x: 61, y: 55 } },
state: { from: 'MOVING', to: 'IDLE' },
})
// On entity deletion
trackObjectDelete('AGENT', agent.id, agent)签字: trackObjectUpdate(entityType, entityId?, changes?, snapshot?, dimensions?)
- 快照:实体的当前状态。按原样存储。MCP服务器计算
{field: {from, to}}查询时连续快照之间的差异——您不需要自己计算差异。 - 变化:可选显式diff(如果您已经有)。当存在基于快照的差异时,优先于这些差异。
- 维度:可选的平面键值元数据(例如。
{ zone: "north", frame: 1234 }).
这给出了MCP服务器结构化实体的时间线:
flightbox_object_timeline(object_type: "AGENT", object_id: "marcus", field_filter: "position")
→ [
{ at: 1772150100, action: "update",
snapshot: { x: 61, y: 55, state: "IDLE" },
diff: { x: { from: 62, to: 61 }, state: { from: "MOVING", to: "IDLE" } },
span_id: "abc123", function: "handleMovement" },
...
]这 field_filter param缩小到特定字段发生变化的事件,例如仅位置发生变化,忽略情绪/需求/草稿行噪声。
注释
对于当前span上的轻量级键值元数据——决策分支、评分结果、调试标志:
import { annotate } from '@flightbox/sdk'
// Inside a state machine switch:
annotate('branch', sm.state)
// Inside a scoring function:
annotate('winner', { activity: winner.id, score: winner.score })
// Debug flag:
annotate('cache_hit', false)annotate(key, value) 附加到 span.tags.annotations.无活动跨度时无操作。可通过以下方式查询:
SELECT * FROM spans
WHERE json_extract_string(tags, '$.annotations.branch') = 'IDLE'跨界血统
追踪跨流程边界(服务器)的因果关系→ 客户,服务→ 服务),使用传输适配器:
import { createTransportLineageAdapter } from '@flightbox/sdk'
const lineage = createTransportLineageAdapter()
// Server: stamp outbound messages
ws.send(JSON.stringify(lineage.stamp({ kind: 'tick', delta })))
// Client: inject inbound causality
const msg = JSON.parse(event.data)
lineage.receive(msg, () => {
applyDelta(msg.delta)
})或者直接使用较低级别的图元:
import { withLineage, runWithLineage } from '@flightbox/sdk'
// Sender — stamps lineage metadata into payload
ws.send(JSON.stringify(withLineage({ type: 'pawn:update', delta })))
// Receiver — injects remote context
const msg = JSON.parse(event.data)
runWithLineage(msg, () => {
applyDelta(msg.delta)
})血统附件要求:
- 当前范围必须接触到被跟踪的对象类型。
- 如果
lineage.requireBlastScope=true(默认),当前跨度必须在爆破范围内。 - 缺失或无效的沿袭是一种安全的禁止操作——永远不要破坏你的代码。
______________________________________________________________________
MCP工具
@flightbox/mcp-server --MCP上的15个工具:
跟踪导航
| 工具 | 它做什么 |
|---|---|
flightbox_summary | 入口点。显示跟踪概述——根跨度、总跨度、最慢、错误。 |
flightbox_children | 深入了解span的子女。这个函数调用了什么? |
flightbox_inspect | 一个跨度的全部细节——序列化参数、返回值、错误+堆栈。 |
flightbox_walk | 从任何跨度(称为边+谱系边)向上或向下浏览因果图。 |
flightbox_search | 按函数名、args/output/errors中的文本、持续时间等查找跨度。 |
flightbox_recent | 轮询友好的增量提要。获取光标后的跨度。 |
flightbox_siblings | 所有在同一父级下运行的东西,按执行顺序排列。 |
flightbox_failing | 最近的错误,按错误类型分组。 |
目标跟踪
| 工具 | 它做什么 |
|---|---|
flightbox_objects | 对象级摘要和覆盖率报告(配置类型与观察类型)。 |
flightbox_object_timeline | 具有快照、计算差异、跨度锚和跨进程链接的时间顺序对象突变。支持 field_filter 缩小到特定领域的变化。 |
模式检测
| 工具 | 它做什么 |
|---|---|
flightbox_hotspots | 函数调用最频繁。查找垃圾邮件呼叫和热循环。 |
flightbox_input_stability | 使用相同的输入重复调用函数。发现浪费的工作 |
flightbox_intervals | 连续通话之间的时间。检测分时率不匹配。 |
flightbox_oscillation | 检测状态之间的波动值(A→B→A→B).处理对象快照或原始跨度输入。 |
模式自省
| 工具 | 它做什么 |
|---|---|
flightbox_schema | 从捕获的快照推断被跟踪对象的形状。显示字段名称、类型、频率和样本值。 |
原始SQL
| 工具 | 它做什么 |
|---|---|
flightbox_query | 任意DuckDB SQL spans全功能——聚合、JSON提取、窗口函数、CTE。 |
示例:调试状态机振荡
这是诊断游戏中典当振荡错误的实际工作流程:
1. flightbox_hotspots(last_n_minutes: 1)
→ buildPixelPath at 8K calls/min (should be ~3.6K at 60fps)
2. flightbox_input_stability(name_pattern: "buildPixelPath", last_n_minutes: 1)
→ Same input repeated 27 times — pathChanged firing when nothing changed
3. flightbox_object_timeline(object_type: "AGENT", object_id: "marcus", field_filter: "position")
→ Position alternating between y=54 and y=55 every few frames
4. flightbox_oscillation(object_type: "AGENT", field_path: "position.y")
→ Marcus flagged with 24 flip events — server reassigning jobs that bounce him
5. flightbox_walk(span_id: , direction: "up")
→ progressJob → move_to_agent → ensurePath on every flip______________________________________________________________________
动态爆炸半径
默认情况下,Vite插件只检测最近git提交中更改的文件。要在调试期间临时扩展范围,请执行以下操作:
# Add patterns alongside git scoping
FLIGHTBOX_INCLUDE="**/stateMachineSystem**,**/pathfinding/**" npm run dev
# Replace git scoping entirely with explicit patterns
FLIGHTBOX_ONLY="**/stateMachine**,**/renderer/**" npm run dev这两个env变量也可以与Node加载器挂钩一起使用:
FLIGHTBOX_INCLUDE="**/stateMachine**" node --import @flightbox/register ./app.ts______________________________________________________________________
什么被捕获
每个函数调用都会产生一个span:
- span_id/trace_id/parent_id --呼叫树结构
- 名称、模块、文件行 --在代码中的何处
- 输入 --JSON序列化参数(深度受限,截断)
- 输出 --JSON序列化返回值
- 错误 --JSON序列化错误,带有堆栈跟踪
- 上下文 --JSON序列化
this对于类方法(深度1,基元优先)。null对于非方法调用。 - 标签 --结构化元数据:对象突变、沿袭发送/记录、爆炸范围、注释
- 开始时间/结束时间/持续时间_ms --定时
- git_sha --哪些承诺
序列化
序列化具有深度限制(5个级别)、广度限制(每个对象/数组10个复杂值)和字符串截断(512个字符)。检测到循环引用。无论宽度限制如何,原始值(字符串、数字、布尔值)总是包含在内——只有对象和数组才计入其中。
______________________________________________________________________
配置
装载机挂钩--env变量
FLIGHTBOX_INCLUDE="src/**/*.ts" node --import @flightbox/register ./app.ts
FLIGHTBOX_ONLY="src/systems/**" node --import @flightbox/register ./app.ts
FLIGHTBOX_EXCLUDE="**/*.test.ts" node --import @flightbox/register ./app.tsVite插件——选项
flightbox({
include: ['**/renderer/**'],
exclude: ['**/test/**'],
objects: { types: ['AGENT', 'ROOM', 'ITEM'] },
lineage: { maxHops: 2 },
})SDK——运行时配置
import { configure } from '@flightbox/sdk'
configure({
enabled: true,
tracesDir: '~/.flightbox/traces',
flushIntervalMs: 5000,
objectCatalog: { types: ['AGENT', 'ROOM'] },
lineage: {
maxHops: 2,
requireBlastScope: true,
messageKey: '_fb',
},
})______________________________________________________________________
包裹
| 包 | 什么 | npm |
|---|---|---|
@flightbox/register | Node.js加载钩子 | ](https://www.npmjs.com/package/@flightbox/register) |
@flightbox/unplugin | 构建插件(Vite/webpack/esbuild/Rollup) | ](https://www.npmjs.com/package/@flightbox/unplugin) |
@flightbox/sdk | 运行时SDK(节点+浏览器) | ](https://www.npmjs.com/package/@flightbox/sdk) |
@flightbox/mcp-server | MCP查询工具 | ](https://www.npmjs.com/package/@flightbox/mcp-server) |
@flightbox/core | 共享类型和序列化程序 | ](https://www.npmjs.com/package/@flightbox/core) |
@flightbox/babel-plugin | Babel转换(遗留) | ](https://www.npmjs.com/package/@flightbox/babel-plugin) |
建筑
Browser (main thread) Vite dev server MCP server
│ │ │
│ wrapped fn runs → span recorded │ │
│ buffer.push(span) │ │
│ ...more functions... │ │
│ requestIdleCallback fires │ │
│ JSON.stringify(batch) │ │
│ ws.send(json) ──────────────────→│ JSON.parse │
│ │ batch append (DuckDB) │
│ │ every 500ms: │
│ │ flush → .parquet │
│ │ ~/.flightbox/traces/ │──→ queries许可证
麻省理工学院
