Skip to content

/instances returns unbounded list of historical known instances #36

Description

@NorveraFlorent

~/.forge-hub/state/_hub/instance-identities.json 持久化所有曾连 Hub 的 instance,每个新 forked PID 都是新 ID 写一条(instance-manager.ts:194 register、:219 ready、:242 ws-close、setTag/setDescription/setChannels 等共 8 个 saveIdentity callsite),永不剔除

routes/instances.ts:9 handleInstancesroutes/health.ts:35 buildInstanceListinstance-manager.ts:117 listKnownInstances 把保存的 identities 全量 union 当前 in-memory instances 返回,无 filter,无 query 参数支持。

实测累积

时间 条目 响应大小
2026-05-12 258 15 KB
2026-05-27 645 67 KB

单用户机器累积速度 ~26 entries/day。

影响

  1. 响应跨过下游消费者 pipe buffer 阈值会触发死锁(见 forge-launcher 配套 issue)
  2. 即使消费者没 bug,每次 enrichScanResults 都全量 fetch 也是 IO + JSON 解析的线性浪费
  3. 历史 stale 条目里 ~85% 没 description/tag(645 → 99 有标识 = 546 是纯噪声)

建议修法

默认行为不要改(避免破坏现有客户端契约),走 query 参数:

GET /instances              → 现有行为(all known,含 stale)
GET /instances?include=live → 只返当前在线
GET /instances?include=tagged → 在线 + 有 description/tag 的离线(供 menubar 之类的回放)

配套:长期可在 hub 启动时 GC instance-identities.json——剔除 >30 天 lastSeenAt 且无 description/tag 的条目。

临时绕过

python3 -c "
import json
p='$HOME/.forge-hub/state/_hub/instance-identities.json'
d=json.load(open(p))
kept={k:v for k,v in d.items() if v.get('description') or v.get('tag')}
json.dump(kept, open(p,'w'), indent=2, ensure_ascii=False)
print(f'{len(d)} -> {len(kept)}')
"
launchctl kickstart -k gui/$(id -u)/com.forge-hub

listKnownInstances 只读不写,trim 不会被自动回填。

环境

  • forge-hub: HEAD-19628bb
  • Bun 1.3.14
  • macOS 25.5.0

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions