JSON-Rohbericht maschinenlesbar
{
"data": {
"repo": {
"topics": [],
"is_fork": false,
"size_kb": 2347,
"has_wiki": true,
"homepage": null,
"languages": {
"Go": 822692,
"CSS": 107208,
"HTML": 1507,
"NSIS": 8490,
"Shell": 32698,
"Dockerfile": 4569,
"JavaScript": 6717,
"PowerShell": 1699,
"TypeScript": 595638
},
"pushed_at": "2026-07-20T11:37:19Z",
"created_at": "2026-06-05T06:38:05Z",
"owner_type": "User",
"updated_at": "2026-07-20T11:37:56Z",
"description": "Code anywhere — npx control+terminal server for Claude Code (tmux) + @ccfly/react; self-hosted /term WS, no ttyd.",
"is_archived": false,
"is_disabled": false,
"license_spdx": "MIT",
"default_branch": "main",
"license_spdx_raw": "MIT",
"primary_language": "Go",
"significant_languages": [
"Go",
"TypeScript"
]
},
"owner": {
"blog": null,
"name": null,
"type": "User",
"login": "jsdvjx",
"company": null,
"location": null,
"followers": 1,
"avatar_url": "https://avatars.githubusercontent.com/u/12291665?v=4",
"created_at": "2015-05-07T07:36:04Z",
"is_verified": null,
"public_repos": 5,
"account_age_days": 4097
},
"license": {
"state": "standard",
"spdx_id": "MIT",
"raw_spdx": "MIT",
"file_present": true,
"scorecard_found": true,
"profile_has_license": true
},
"activity": {
"releases": [
{
"tag": "v0.3.10",
"kind": "patch",
"published_at": "2026-06-06T15:51:33Z"
},
{
"tag": "v0.3.9",
"kind": "patch",
"published_at": "2026-06-06T10:02:04Z"
},
{
"tag": "v0.3.8",
"kind": "patch",
"published_at": "2026-06-06T09:50:29Z"
}
],
"recent_commits": [
{
"oid": "a4ba628519d56bdcb35911778eaa7a38b43d67cd",
"body": null,
"is_bot": false,
"headline": "chore(release): ccfly 0.18.0",
"author_name": "Jin",
"author_login": "jsdvjx",
"committed_at": "2026-07-19T14:48:01Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "316a7a3fea5ddccff8e2de1b1e352ff372ab6069",
"body": "- 新增 dnsPolicyService(dnspolicy.go):DNS 服务自己周期拉 OSS domainlist、热重载 CoreDNS,\n 三端同一份;首拉失败用编译期兜底,坏拉取保留旧版\n- Windows:hosts 精确钉 → 网卡 DNS 指 127.0.0.1 + 次级上游(备份/恢复,fail-open);\n 删除 hosts 写块路径(保留旧块剥离用于卸载清理)\n- macOS:root helper 常驻自持策略服务,arm 只传 relay_port;清单热更新自动重写\n /etc/resolver(不再需要 agent 下发/重装);arm 应答携带清单版本\n- agent 不再拉取/分发域名清单;sameSNI 不再比较 intercept/upstream(与 cloud 解耦);\n 版本上报:linux/windows 读进程内服务,darwin 读 resolver 实况 + HEAD 观测 ETag",
"is_bot": false,
"headline": "feat(mesh): 三端统一 SNI 拦截为内嵌 DNS on :53,策略服务自持 OSS 清单",
"author_name": "Jin",
"author_login": "jsdvjx",
"committed_at": "2026-07-19T14:47:42Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "2fe53134ac7b896280948e62ce9ee8742f46c848",
"body": null,
"is_bot": false,
"headline": "chore(release): ccfly 0.17.0",
"author_name": "Jin",
"author_login": "jsdvjx",
"committed_at": "2026-07-19T11:17:18Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "fc7dd5a712bb5c9645137c56ed5a257424abd062",
"body": "refreshConfig 与 runSNIPolicyRefresher 均触发 OSS 清单独立收敛:已有 arm 立即重装,\n新连接只预热缓存;兑现 ec8303d revert 时『随 sni.go 一起落地』的承诺。",
"is_bot": false,
"headline": "fix(mesh): 接上 SNI 域名清单刷新(refreshDomainListAndRearm 两处调用点)",
"author_name": "Jin",
"author_login": "jsdvjx",
"committed_at": "2026-07-19T11:15:53Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "8c2ec13db1d5107cc683ab26d241ccc5b5cee9bc",
"body": "- 本机 claude auth login 持有完整 OAuth,BROWSER 指回 ccfly 自身吞掉授权 URL\n- URL 发云端 /api/device/login/cdp/*,eu-control manual-oauth 固定身份云浏览器过授权\n- 一次性 code#state 回填本地落盘;不带 email 生成 30min 网页选号票据\n- 旧库存凭据模式保留为显式 --credential,--auto 不变,--cdp 兼容别名",
"is_bot": false,
"headline": "feat(login): claude login 默认改 Cloud-CDP OAuth(云浏览器代授权)",
"author_name": "Jin",
"author_login": "jsdvjx",
"committed_at": "2026-07-19T11:14:06Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "7857dd07fdfea8298f472e10bbe9b1557a005ce8",
"body": null,
"is_bot": false,
"headline": "chore(release): ccfly 0.16.0 — mesh 有序多入口 failover(回填隔离发布树的版本号)",
"author_name": "Jin",
"author_login": "jsdvjx",
"committed_at": "2026-07-19T11:13:28Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "0d43d0d40fbf9380ccefd2cfa73d222ae00d009a",
"body": "- MeshEndpoint{url,dial_addr}:url 作 WS Host 与证书身份,dial_addr 可选改 TCP 目的\n- CCFLY_MESH_ENDPOINTS 环境列表优先,云端 mesh_url 永远作最终兼容回退\n- State/connectResp/deviceConfig 增加 mesh_endpoints,入网与配置刷新下发即更新\n- 拨号覆写克隆独立 HTTP Transport 并禁用代理,避免覆写被 CONNECT 旁路、token 泄漏",
"is_bot": false,
"headline": "feat(mesh): 有序多入口 failover,TLS 身份 URL 与实际拨号地址分离",
"author_name": "Jin",
"author_login": "jsdvjx",
"committed_at": "2026-07-19T11:10:41Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "992a1189c9b8c4304b628c01940bf2d49fb3b28f",
"body": "…ckfile)",
"is_bot": false,
"headline": "fix(release): 同步 pnpm-lock 与 cli 0.15.5 平台包钉版(修 release.yml frozen-lo…",
"author_name": "Jin",
"author_login": "jsdvjx",
"committed_at": "2026-07-19T10:01:33Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "70d0d899016621bc8dd1bbbd59d5f5454bea10f5",
"body": "数据面:进程内 CoreDNS(仅 bind/template/forward)接管 :53,intercept 域合成\nloopback、其余转 OSS 上游;macOS 改 scoped /etc/resolver + root helper 持租约\n(控制连接 EOF 即撤 resolver/停 CoreDNS/关 :443,拒绝覆盖用户已有 resolver);\nWindows 仍 hosts 精确钉、Linux resolv.conf 备份恢复。OSS 域名清单 ETag 热更新,\ndeploy-device.sh 按「先 helper 后 agent」重启。\n\n检测:拆「组件自检」\n[…]\nlved_addresses 与 error_code。\n检测调度:arm 即检、正常 30s、失败退避 2/5/10/30s、WG 与配置变化立即重检、\n45s 过期按 checking 不标记健康。\n\n同时修正三个被本机 /etc/hosts 残留钉死记录骗坏的测试(探测名换用不在 hosts\n里的拦截子域、TestDarwinResolverScoped 打桩 unixHostsPath)。",
"is_bot": false,
"headline": "feat(mesh): SNI 数据面 — CoreDNS scoped 拦截、helper 租约与真实应用路径检测",
"author_name": "Jin",
"author_login": "jsdvjx",
"committed_at": "2026-07-19T09:31:50Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "ec8303d59116a178d9e67936fc1175da336d8d18",
"body": "Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "revert(mesh): 摘除误入 e785d8a 的 SNI domainlist WIP 调用点(随 sni.go 一起落地)",
"author_name": "Jin",
"author_login": "jsdvjx",
"committed_at": "2026-07-18T01:44:58Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "cb2bb34f659c6dae51e5efdd33be8c1c4304993c",
"body": "Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "chore(release): ccfly 0.15.5 — agent 云端链路免疫环境代理",
"author_name": "Jin",
"author_login": "jsdvjx",
"committed_at": "2026-07-18T01:40:50Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "e785d8a27ebd81250dc5f9334e36cdc3e955b2f7",
"body": "配对/控制面/mesh WSS/会话同步/claude login 全部换用 internal/cloudhttp\n的无环境代理客户端。Windows 客户注册表残留的持久代理变量会把计划任务里\n的 connect 导进已退出的本地代理(交互 shell 配对成功、任务却稳定 EOF),\n且任务环境从注册表重建、与 shell 不同步,极难排查。\n\n确需经代理接入云端的部署用 CCFLY_PROXY=<url> 显式指定;UI 包下载(npm\nregistry)等非云端链路仍走环境代理。\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "fix(mesh): agent 云端链路不再吃 HTTP(S)_PROXY 环境变量,一律直连",
"author_name": "Jin",
"author_login": "jsdvjx",
"committed_at": "2026-07-18T01:38:30Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "25c034d8571907c3a4580d7eac5f07eadd973d97",
"body": "- svc: Linux install 检测不到 systemd(容器/精简系统)时不再硬失败,\n 改为 setsid 后台直启 agent 并提示如何持久化;Windows/unix 各自补齐\n startDetachedAgent 实现\n- hostagent: 新增 POST /clear-data,清实例工作区/Claude 会话/上传缓存\n 后重启容器(保留接入身份,同 device id 干净重上线),附 agent_test.go\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "feat(svc): 无 systemd 环境安装回退 + hostagent clear-data",
"author_name": "Jin",
"author_login": "jsdvjx",
"committed_at": "2026-07-18T00:40:29Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "c1db5e4001b287c4a8262240cbdab54423a64c1d",
"body": null,
"is_bot": false,
"headline": "fix(release): reuse committed webdist in clean builds",
"author_name": "Jin",
"author_login": "jsdvjx",
"committed_at": "2026-07-16T01:05:29Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "6752a22ec79bfce9832ab942e83500747357c742",
"body": null,
"is_bot": false,
"headline": "chore(release): ccfly 0.15.4 browser handoff",
"author_name": "Jin",
"author_login": "jsdvjx",
"committed_at": "2026-07-16T01:01:46Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "630d8a173457cee483413e7151aa7dd5cf2f9d13",
"body": null,
"is_bot": false,
"headline": "feat(claude): add browser auto-login handoff",
"author_name": "Jin",
"author_login": "jsdvjx",
"committed_at": "2026-07-15T15:09:17Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "05bc3d6d85364cdde542e8ff8d14f27787c05b6a",
"body": null,
"is_bot": false,
"headline": "chore(release): ccfly 0.15.3 SNI hardening",
"author_name": "Jin",
"author_login": "jsdvjx",
"committed_at": "2026-07-15T12:17:16Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "440ad80a7499309609e299eb37a2311326f8017a",
"body": "0.11.0 之后累积的 npm 发版(0.13.0 内置 tmux、0.15.x SNI helper/\n邀请组真机验证等)版本号与 CHANGELOG 对齐到已发布的 0.15.2;\n内嵌 web 资产同步为 0.1.0 构建产物。\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "chore(release): ccfly 0.15.2 版本与 changelog + webdist 0.1.0",
"author_name": "Jin",
"author_login": "jsdvjx",
"committed_at": "2026-07-14T23:10:34Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "b3fdb5a32b2e449da3b42a2f4edd8b17e9ccf2b7",
"body": "两处 flap 根因修复:\n- WG bind 每帧收发盖 lastAct 时间戳;keepalive pong 超时且 45s 内有真实\n 流量则不自杀——设备大流量上传时自己的 ping 会饿死在 WS 写锁后面,\n 误判半开把活隧道拆掉正是 2026-07 的规律闪断。Send 自带 10s 写超时\n 仍兜底真卡死的 socket。\n- 存活超 1 分钟的连接断开视为稳定连接闪断,退避重置 1s 立即重连;\n 此前退避从不重置,晚高峰跨境限速被踢一次就固定吃满 30s 掉线体感。\n 短命连接照常翻倍退避,重连风暴保护不变。\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "fix(mesh): keepalive 以真实流量判活 + 长命连接闪断快速重连",
"author_name": "Jin",
"author_login": "jsdvjx",
"committed_at": "2026-07-14T23:10:34Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "42fb3131041c01c6eb455796b7625840ca54e936",
"body": "macOS 用 makensis 交叉构建 ccfly-setup-x64.exe:安装器只铺文件+PATH\n(服务注册仍靠 ccfly install,升级须重跑);deploy 脚本推 cc.hn/dl/。\n图标由 webdist PNG 构建期生成,进 .gitignore。\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "feat(win): NSIS 安装包构建/部署脚本",
"author_name": "Jin",
"author_login": "jsdvjx",
"committed_at": "2026-07-14T23:10:15Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "c2269a906f71936758783dc224b00608fd4ca9c6",
"body": "macOS 上 claude-code 以登录钥匙串(非 ~/.claude/.credentials.json)为\nOAuth 主源,文件凭据会被钥匙串旧凭据遮蔽。写凭据时放一次性\nkeychain-seed-pending 标记,下次起/重载 claude 会话时经 wrapClaudeCmd\n在已解锁的 tmux 用户上下文把凭据写进钥匙串(keychain_darwin.go);\n非 darwin 全程 no-op。\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "feat(darwin): claude 订阅凭据 seed 进登录钥匙串",
"author_name": "Jin",
"author_login": "jsdvjx",
"committed_at": "2026-07-14T23:10:15Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "904c1b7b6efceb750d90cfd7f660682f3ec12041",
"body": "macOS 非 root agent 绑不了 :443/写不了 /etc/hosts,SNI 本质起不来:\n- 拆双进程:root helper LaunchDaemon(com.ccfly.sni-helper,隐藏子命令\n ccfly sni-helper)只绑 :443 splice 回 agent 非特权 relay 端口 + 写\n /etc/hosts 免 :53;overlay 拨号仍留 agent 进程(netstack 不可跨进程)。\n- install/uninstall 硬闸门:macOS 要求 root 且 agent 装成 system\n LaunchDaemon\n[…]\nnthropic.com 主动探测),mesh 摘要推送带 sni 状态\n (未 arm 也上报,云端可分「未生效」vs「从未上报」)。\n\ninstall 侧顺带接上内置 tmux 落盘(servicePATH bundled 分支→EnsureAt)。\n三平台编译+真机集成测试通过。\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "feat(sni): macOS root helper 双进程 + 三平台解析指向 + arm 状态自检/上报",
"author_name": "Jin",
"author_login": "jsdvjx",
"committed_at": "2026-07-14T23:10:01Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "a97f03365fb3547410498e0e12661728e6293700",
"body": "internal/tmuxbin 把可移植 tmux(libevent/ncursesw 静态链,blob 由\nscripts/build-tmux-macos.sh 生成并提交进仓库)go:embed 进 darwin 构建。\n运行时 ensureToolPath 尾部找不到系统 tmux 才释放到 ~/.ccfly/bin 并前置\nPATH;系统 tmux 永远优先(跨版本 client/server protocol mismatch,不能\n抢用户在跑的 server)。default-terminal 编译期定为 screen-256color。\nLinux 不内嵌(Bundled()=false 空操作);Windows 另有 psmux 路径。\n\ninstall 侧的 servicePATH bundled 分支随后续 svc.go 变更一并提交。\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "feat(darwin): 内置静态 tmux 3.5a,系统未装 tmux 时自动兜底",
"author_name": "Jin",
"author_login": "jsdvjx",
"committed_at": "2026-07-14T23:09:33Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "64d1f221a4c368787b97221d0bdc21656adb17ac",
"body": "…→ byway-sni)\n\n已发布 npm:主包 ccfly@0.11.0 + 5 平台子包(darwin/linux arm64+x64, win32-x64)。\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
"is_bot": false,
"headline": "chore(release): ccfly@0.11.0 — SNI 客户端(DNS 三平台指向 + 本地 :443 → overlay …",
"author_name": "Jin",
"author_login": "jsdvjx",
"committed_at": "2026-07-13T06:54:07Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "ec7067970e9f08a35147553ecb59be9f90adc1d0",
"body": "Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "chore(sni): 更新 changeset——DNS 指向三平台已全实现",
"author_name": "Jin",
"author_login": "jsdvjx",
"committed_at": "2026-07-13T06:36:50Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "690f8848f254f8523b13fdb6db85f37837fa45f1",
"body": "…solv.conf)\n\n之前只 Linux 改 resolv.conf、mac/win 留 no-op;现三平台都真正把系统解析指向本地 SNI DNS:\n- macOS:/etc/resolver/<域> scoped —— 每个 intercept apex 域一个文件(nameserver 127.0.0.1\n + ccfly 标记),只把这些域(含子域)路由到本地,不动全局 resolver;卸载按标记精确清理\n (保留用户自己的 resolver 文件,能清重启遗留)。\n- Windows:NRPT scoped —— 每个域一条 `.<域>` 规则(-NameServers \n[…]\nlver/restoreResolver 统一接口。\nsetupLocked 对所有平台统一调 pointResolver(intercept,upstream),不再按 GOOS 分支 no-op。\ndarwin scoped 逻辑单测(临时目录,免 root);5 平台交叉编译全过。\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "feat(sni): DNS 指向三平台全实现(macOS /etc/resolver + Windows NRPT + Linux re…",
"author_name": "Jin",
"author_login": "jsdvjx",
"committed_at": "2026-07-13T06:36:22Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "48ca5cb5a4f36ca48eb92529f907223e7866f1c2",
"body": "Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "chore(sni): changeset for client SNI arm (minor)",
"author_name": "Jin",
"author_login": "jsdvjx",
"committed_at": "2026-07-13T06:25:10Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "bafdd4f73ea77afc290ec1e171f1a925e56db8d6",
"body": "据云端 GET /api/device/config 的 sni 段驱动(有段→装,无段→幂等卸载):\n- 内嵌极小 DNS(127.0.0.1:53):intercept 域(含子域)→ A=127.0.0.1/AAAA=::1,\n 其余原样转上游阿里 —— 比外部 SmartDNS 轻,ccfly 本就是 Go 进程。\n- 本地 :443 双栈监听 → 经当前 WG 会话 netstack 透传到账号出口 byway-sni\n (activeNet 由 bringUpWG 发布;overlay 未就绪则丢连接 fail-open)。\n- Linux 改 resolv.conf 指向本地\n[…]\n接前 refreshConfig+applyMeshProxy+applyMeshSNI:登录后\n 云端新绑 sni 账号无需重启即生效;进程退出 defer 卸载(恢复 resolv.conf)。\n- 未收到 sni 段 → 完全 dormant,零回归。DNS 协议层逻辑单测全绿。\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "feat(sni): 第⑥步 客户端 SNI arm(内嵌 DNS 拦截 + 本地 :443 经 overlay 透传)",
"author_name": "Jin",
"author_login": "jsdvjx",
"committed_at": "2026-07-13T06:16:59Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "52bf305d54ca26b9b680af4a97bc6d11c7e05f67",
"body": "Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "Version Packages 0.10.12",
"author_name": "Jin",
"author_login": "jsdvjx",
"committed_at": "2026-07-11T08:05:59Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "28ba2f8e9afb97d4dfd4651743d18f71e9bf1bd2",
"body": "/sessions 扫描过去对每个变动会话重读整个 jsonl:几百 MB 的活跃会话每 20s 被\nsyncer + 每个 /sessions 请求各重读一遍(~756MB/分钟),是 ccfly connect CPU 常驻\n30%+ 的根因(james 机实测)。\n\n改为增量:scanCacheEntry 加 off(已消费到的行边界偏移),append-only 文件增长时\n只读新尾 [off, EOF) 并从上次快照累进(scanOneSession 拆成 scanSession/scanFrom/\napplyEvent;readLineCapped→readLineAt 追踪字节偏移)。成本从「读全文」降到「读新增\n几 KB」,不再随会话变大恶化。增量与全量逐字段一致、半截行不重不漏(新增回归测试)。\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "perf(control): 会话扫描增量化,消除活跃大会话每轮重读整文件的 CPU 开销",
"author_name": "Jin",
"author_login": "jsdvjx",
"committed_at": "2026-07-11T08:05:37Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "7831a865050c13c6d6ce311e35ebe38a62d705ed",
"body": "Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>",
"is_bot": false,
"headline": "Version Packages 0.10.11",
"author_name": "Jin",
"author_login": "jsdvjx",
"committed_at": "2026-07-09T09:05:08Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "d5019a209c3de8ac9902d241dc5698c3ed042bf1",
"body": "新增 POST /close 端点:接受 {sessions:[sid...], force:bool},逐个\nkill tmux 会话释放 CPU/内存;非 force 时守卫活跃(attached)、生成中\n(busy)、交互菜单(select)的会话,返回 closed/skipped 明细。\n/sessions 新增 bytes 字段(零额外 syscall,复用 scan 已有 size)。\n\nmesh 接收云端 can_use_claude/proxy/mesh 三态准入标志,nil=放行;\nclaude_login 在命令行层面门控(真正鉴权仍在云端 403)。\n\nCo-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>",
"is_bot": false,
"headline": "feat(control): POST /close 批量关闭会话 + 内部功能准入闸",
"author_name": "Jin",
"author_login": "jsdvjx",
"committed_at": "2026-07-09T09:04:25Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "02e049e1a7509132940df1e6786edac52f2b87f6",
"body": "根因:claude 官方原生安装器把二进制装在 ~/.local/bin,不在系统 PATH。\nccfly 守护跑在 launchd 下无 tty,ensureToolPath 的 `zsh -ilc` 交互探测\n失败 → 回落到缺 ~/.local/bin 的兜底 PATH → exec.LookPath(\"claude\") 与\ntmux 起会话都找不到 claude:/new 直起的 claude 秒退、/term·/start 的\n--resume 退化成裸 shell,前端屏判不出 → 会话恒「连接中」。\n\n修复:\n- 探测由单一 `-ilc` 改为 `-ilc`(有 tty 最全)失\n[…]\ntest.go(prepend / 幂等)。\n\n验证:去掉临时软链后接管离线会话仍 `claude --resume` 成功,证明守护自身\nPATH 已含 ~/.local/bin;已 build 0.10.10 装到本机守护并重启,网页新建/接管\n恢复正常。\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "fix(control): 守护进程 PATH 补 ~/.local/bin,claude 找得到会话才起得来",
"author_name": "Jin",
"author_login": "jsdvjx",
"committed_at": "2026-07-07T06:33:13Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "76d99fda24ee9358577f52f17a22aadf20a9453e",
"body": "发布 single-flight 会话扫描 + 单行上限补丁(消除 /sessions 缓存踩踏 OOM)。\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "Version Packages 0.10.10",
"author_name": "Jin",
"author_login": "jsdvjx",
"committed_at": "2026-07-06T11:27:17Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "f4fbb1f856fa4b097a944e4abdf3c040ffed1be4",
"body": "设备控制服务 /sessions 每个请求都全量扫描所有会话 jsonl;高并发下数百请求\n各自把全部 transcript 解析进内存,峰值 ×并发数 放大到数 GB(实测单机 315 并发\n把 ccfly 顶到 8G、swap 抖动拖垮整机)。\n\n- scanClaudeSessions 加 single-flight:一轮扫描进行中,并发调用等待并共享结果,\n 不再各扫一遍(抽出 doScanClaudeSessions + scanCall;scanBarrier 为测试 seam)。\n- scanOneSession 改用 jsonlLinesCapped 给单行设 1 MiB 上限:超大行截断跳过但不丢\n 后续行;全文渲染(transcript/subagents/图片)仍走 jsonlLines 无上限,不受影响。\n- 新增回归 claudescan_stampede_test.go:N 并发只跑一次真扫描 + 大行跳过保后续行。\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "fix(control): single-flight 会话扫描 + 单行上限,消除 /sessions 缓存踩踏 OOM",
"author_name": "Jin",
"author_login": "jsdvjx",
"committed_at": "2026-07-06T11:04:33Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "4e57aad713b81c9ce60ba215c84d1cbe829aaafb",
"body": "Windows 平台落地:\n- svc: Task Scheduler 安装(wrapper .cmd + vbs 隐藏阻塞启动、5 分钟自愈重复触发、\n RestartOnFailure 生效);install 前强杀游离旧实例\n- npm 新增 ccfly-win32-x64 平台子包,build-binaries 捆绑 psmux(tmux for Windows)\n- /term 走 ConPTY 且隔离在 _termpty 桥子进程(ClosePseudoConsole 的 CTRL_CLOSE\n 连坐会静默杀死宿主服务,实测)\n- exec/signal/flock/proce\n[…]\ncript 未落盘的新会话\n 200 挂住轮询,消灭「连接中」死锁\n\n稳定性:\n- connect 单例:文件锁 + Windows 整机级命名互斥(跨用户 profile)\n- 服务态忽略 console interrupt;claude login 后台化 + status 子命令\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "feat: Windows 全面支持 + 会话代理/稳定性根治(0.7.1 → 0.10.9)",
"author_name": "Jin",
"author_login": "jsdvjx",
"committed_at": "2026-07-03T01:52:49Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "56c54a87871238d71c922f24204185851237b058",
"body": null,
"is_bot": false,
"headline": "release: ccfly 0.7.1",
"author_name": "Jin",
"author_login": "jsdvjx",
"committed_at": "2026-06-27T14:07:49Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "f6573d5cd15f86a721651f661224bc8323dd5fd6",
"body": "Published ccfly@0.7.0 + ccfly-{darwin,linux}-{arm64,x64}@0.7.0 to npm (lockstep fixed group).\n- feat(control): attn detection (permission/plan/choice → session attn_kind)\n- fix(control): canonical cc-<sid8> tmux naming + orphan-claude guard\n- fix(claudescan): recompute state on cache hit (working de\n[…]\nre: Go module → github.com/jsdvjx/ccfly; device deploy script + CI\n(@ccfly/react 0.4.5 + ccfly-webdist 0.1.0 unchanged → skipped.)\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "release: ccfly 0.7.0",
"author_name": "Jin",
"author_login": "jsdvjx",
"committed_at": "2026-06-27T08:22:02Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "6e7aac10a28807aa6450557cdbac82280dd607a7",
"body": "scripts/deploy-device.sh: build current-platform binary stamped with the packages/cli version, install over the LaunchDaemon agent, kickstart (fixes the 0.5.6->repo drift); --print-only/--no-restart. CI: go + TS build/test on PRs (npm publish stays in release.yml).\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
"is_bot": false,
"headline": "chore(deploy): add device deploy script + CI",
"author_name": "Jin",
"author_login": "jsdvjx",
"committed_at": "2026-06-25T09:44:56Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "7ca74f1675968d1371182a9228e56e44003d60e1",
"body": "Replace the placeholder github.com/ccfly/ccfly with the real remote github.com/jsdvjx/ccfly across go.mod, all internal imports, the two Dockerfiles' -ldflags profile.defaultMode path, and the doc notes. go build/vet/test all pass under the new path.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
"is_bot": false,
"headline": "refactor: rename Go module path to github.com/jsdvjx/ccfly",
"author_name": "Jin",
"author_login": "jsdvjx",
"committed_at": "2026-06-25T09:44:56Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "9f6d256db7f36a4f72c3346312325f959ba3bdcc",
"body": "项目已统一搬入 ~/ccfly-workspace/ 作为一级工作区;同步 CLAUDE.md 内的跨仓引用与系列总览路径。\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "docs(CLAUDE.md): 路径迁移到 ~/ccfly-workspace",
"author_name": "Jin",
"author_login": "jsdvjx",
"committed_at": "2026-06-25T05:19:17Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "9d667445cd6c06566a4b9ca447b8751ad581c805",
"body": "- cmd/ccfly-hostd + internal/hostagent: 受 cloud 经 overlay 指挥 docker run 每用户实例\n\n- internal/profile: full/instance/host/restricted 能力档(只能加严)\n\n- docker/: 受限镜像 + 实例镜像与启动脚本; 根 Dockerfile/.dockerignore\n\n- mesh/forward/proxyenv/uisync/svc 配套调整\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "feat: ccfly-hostd 主机代理 + 能力档 profile + 受限 Docker 实例镜像 + CLAUDE.md",
"author_name": "Jin",
"author_login": "jsdvjx",
"committed_at": "2026-06-25T05:11:09Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "597f1da559b5f1413dda2db56892621782e25077",
"body": "根因:handleNew 用随机名 cc-<rand8> 起会话,前端按 sid 算 cc-<sid8> 连 /term,两者全靠\npanemap 真值表桥接。同 cwd 会话一多,真值表 miss 时启发式「n≥2 不猜」→ 解析不到 live →\nterm.go 的 cmd=\"claude\" 兜底就在 ccfly 进程 cwd(HOME)起个错目录的裸 claude,且不可被\nscanner 回收 → 雪崩堆积(实测 top.pm:/root 与 /root/assistant 各十余个孤儿 claude)。\n\n修复:\n- handleNew:拿到真 sid 后把 tmux 从随机名 re\n[…]\n回收的孤儿壳变成不可回收的孤儿 claude);保留\n claudeResumeCmd(离线会话按原 cwd resume,单实例、不重复)。\n\n实测 top.pm:/new→cc-<sid8> 规范名 ✅ panemap 同步 ✅ /term 精确 attach 不再新增孤儿 ✅。\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
"is_bot": false,
"headline": "fix(control): 新建会话规范 tmux 名为 cc-<sid8> + 撤裸 claude 兜底(根治接错会话/目录错/孤儿雪崩)",
"author_name": "Jin",
"author_login": "jsdvjx",
"committed_at": "2026-06-24T11:50:14Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "d7412bdf4acd6def1131d36ea10c2b32889979be",
"body": "…cays\n\ncachedScanOne cached the whole snapshot including the time-dependent State/AgeSec\nkeyed by file (mtime,size). A session that stops mid-\"working\" freezes its file,\nso the cache never re-ran classify and it reported \"working\" forever (both\n/sessions and the cloud syncer; AgeSec also froze into a fake \"just now\").\nRecompute classify/age on every cache hit using the cached parse — cheap, no\nextra file reads.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
"is_bot": false,
"headline": "fix(claudescan): recompute session state on cache hit so \"working\" de…",
"author_name": "Jin",
"author_login": "jsdvjx",
"committed_at": "2026-06-22T05:42:40Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "56dcabfd771fb97398ccf8b453973bb093bd2bc5",
"body": "Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "release: ccfly 0.6.1 (tmux 会话设终端标题,多窗口可区分内容)",
"author_name": "Jin",
"author_login": "jsdvjx",
"committed_at": "2026-06-18T12:13:43Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "146f2e3d18e2804e1941f59001d37834df4786e6",
"body": "ccfly a / new 启动会话时只 new-session,从不开 set-titles,外层终端标题\n全是 tmux 默认值 —— 开多个窗口根本分不清哪个跑哪个会话。\n\nattach 与 new 两条路径都在 new-session 命令串尾部内联(`;` 分隔,exec 直传\ntmux 无需 shell)两条 set-option:\n - set-titles on 外层标题交给 tmux\n - set-titles-string '#S' 标题=会话名;claude 设了 pane 标题再缀上 ` · <标题>`\n\n作用域限定到本会话(set-option -t <name>,非 -g),不动用户别处的 tmux;\npane_title 默认等于主机名时只显示会话名,避免缀上无意义的主机名。\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "fix(ccfly): 给 tmux 会话设外层终端标题,多窗口可区分内容",
"author_name": "Jin",
"author_login": "jsdvjx",
"committed_at": "2026-06-18T12:12:56Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "d33f1abd4c3f027181ad7c43df42b87df7b3c932",
"body": null,
"is_bot": false,
"headline": "release: ccfly 0.6.0 (claude login 无 email 选号 + 按账号路由 + logout)",
"author_name": "Jin",
"author_login": "jsdvjx",
"committed_at": "2026-06-18T02:36:49Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "df7501c7c909dea78e6695d6ac8699dd8a75d7b4",
"body": "ccfly claude logout 现在除清本地路由上下文外,还 POST /api/device/login/route/clear\n(对每个/指定云端),让云端清掉本设备的 sing-box 源路由 → 后续 claude 会话回退默认出网。\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "feat(ccfly): claude logout 通知云端清按账号源路由",
"author_name": "Jin",
"author_login": "jsdvjx",
"committed_at": "2026-06-17T16:55:08Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "cbe13a3a1276d87c02cfe6de9f591a226de2e379",
"body": "对接云端「账号共享 + 配额选号」:\n- claude login:--email 改可选(省略 → 云端在你可访问的共享账号里按 claude 用量+分配次数自动选号);\n 解析并展示分配结果(account_email/egress_v6/out_node_ip);403/503/409/401 中文提示。\n- 按账号 /128 路由:登录成功后把分配结果 + 云端下发的 account_proxy_url 落盘\n ~/.ccfly/claude-login-<host>.json(0600);mesh.EnsureTmuxProxyEnv 改成优先级链 ——\n 有按账号代理 URL\n[…]\noverlay 代理;用户显式设的最优先。\n- ccfly claude logout:清路由上下文(不删 ~/.claude 凭证)。\n- 新增 mesh ClaudeLoginContext 存取 + 6 个测试;go build/vet/test 全过。\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "feat(ccfly): claude login 无 email 选号 + 按账号 /128 路由 + logout",
"author_name": "Jin",
"author_login": "jsdvjx",
"committed_at": "2026-06-17T16:12:06Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "f872c324d63f979a4738f592717bc529260d1a21",
"body": "Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
"is_bot": false,
"headline": "release: ccfly 0.5.9, @ccfly/react 0.4.5",
"author_name": "Jin",
"author_login": "jsdvjx",
"committed_at": "2026-06-16T16:51:01Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "52b20897f7b4966c81e042e50b50615a4645bc26",
"body": "Background syncer riding the mesh control plane (not the WG tunnel): scan\n~/.claude jsonl, push summary docs + the appended tail to the cloud. The\ncloud's per-session byte high-water mark is the cursor, so the client keeps\nno local state. control exposes a read-only digest accessor; the uploader\nlives in mesh (control stays free of report logic).\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
"is_bot": false,
"headline": "feat(sync): push local Claude sessions to the cloud",
"author_name": "Jin",
"author_login": "jsdvjx",
"committed_at": "2026-06-16T16:51:01Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "1bc0e40d0135544e3f111761ac1ab4bd41f78407",
"body": "Decouple the web UI from the binary so UI changes ship via npm (publish ccfly-webdist) without rebuilding/republishing the platform binaries.\n\n- uisync.go: background checker (startup + hourly) queries registry.npmjs.org for ccfly-webdist; if newer than the embedded VERSION, downloads the tarball, v\n[…]\nkage version) + stages the npm publish source.\n- uisync_test.go: integrity, tar path-traversal, semver downgrade tests.\n\nTrust boundary = npm account + published SRI over HTTPS (same as the binaries).",
"is_bot": false,
"headline": "feat(ui): serve web UI from npm at runtime, embed only a fallback",
"author_name": "Jin",
"author_login": "jsdvjx",
"committed_at": "2026-06-16T16:33:35Z",
"body_truncated": true,
"is_coding_agent": false
},
{
"oid": "2b53aa7b0a90d08c4c9dd473c0345bda28515fe3",
"body": "… title\n\nMake the read-screen → classify pipeline testable and pin its behavior, per\ndocs/state-engine.md §7/F6 (it previously had zero tests).\n\n- Extract the pure parser from engine.ts into pre.ts (zero xterm/React) and add\n a pure classify(frame) seam, so detection is unit-testable and the tested\n[…]\nl\n (\"--model.\") instead of the real title (\"Select model\").\n\nScope: @ccfly/react only; no Go / binary changes. Changeset: patch (0.4.4→0.4.5).\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
"is_bot": false,
"headline": "test(engine): vitest harness for the screen-state engine + fix /model…",
"author_name": "Jin",
"author_login": "jsdvjx",
"committed_at": "2026-06-16T14:39:46Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "61dc9cf23c5053998b84121f63669bb5150824af",
"body": null,
"is_bot": false,
"headline": "release: ccfly 0.5.8",
"author_name": "Jin",
"author_login": "jsdvjx",
"committed_at": "2026-06-16T10:05:53Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "8b8de7fc8d1f20fc8a88f1cfeaf377c8e89c8c39",
"body": "- Inject IS_SANDBOX=1 into a new session's tmux env when --dangerously-skip-\n permissions is used and ccfly runs as root (uid 0); Claude Code otherwise\n refuses skip-permissions under root. Covers ccfly new / picker, POST /new,\n and offline resume (CLIAttachArgs). Non-root unchanged.\n- Pre-set ha\n[…]\nder\" dialog (which otherwise\n blocks SessionStart and leaves the web /new without a session id). Defensive:\n atomic write, no-op on any error.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "fix(new): IS_SANDBOX for root + pre-trust chosen directory",
"author_name": "Jin",
"author_login": "jsdvjx",
"committed_at": "2026-06-16T10:05:40Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "e2b4aee4191d645abc692ab1b14cc45d85e88b85",
"body": null,
"is_bot": false,
"headline": "release: ccfly 0.5.7",
"author_name": "Jin",
"author_login": "jsdvjx",
"committed_at": "2026-06-16T09:26:39Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "3b2d9205e044f8c53e73bc9191f9baaac451042f",
"body": "`ccfly a` picker and `ccfly new` (no arg) now open a directory browser to pick\nthe new session's cwd (↑↓ / Enter / ← parent / n create-here / q cancel),\ncarrying the permission options. Two new local control endpoints back the web\nUI's new-session dialog: GET /dirs (list subdirectories) and POST /new (start a\nfresh claude detached in a cwd, poll the panemap, return the real session id).\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "feat(new): choose directory via filesystem browser (a / new / web)",
"author_name": "Jin",
"author_login": "jsdvjx",
"committed_at": "2026-06-16T09:26:24Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "f5f5c22cf30796ae20517ccdf8995c48a630464f",
"body": null,
"is_bot": false,
"headline": "release: ccfly 0.5.6",
"author_name": "Jin",
"author_login": "jsdvjx",
"committed_at": "2026-06-16T04:21:13Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "35285809b6e76e70008ba50065fa7a1577f028f1",
"body": "Re-embeds ccfly-ttyd-ui so AskUserQuestion renders as an unfolded card\n(question + options + selected answer inline) instead of a collapsed generic\nJSON dump. No Go changes — webdist refresh + changeset only.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "feat(web): dedicated AskUserQuestion card (re-embed web UI)",
"author_name": "Jin",
"author_login": "jsdvjx",
"committed_at": "2026-06-16T04:21:12Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "d93a831c73be67fb5f7cdc9b4e6b58484c40424f",
"body": null,
"is_bot": false,
"headline": "release: ccfly 0.5.5",
"author_name": "Jin",
"author_login": "jsdvjx",
"committed_at": "2026-06-16T03:35:05Z",
"body_truncated": false,
"is_coding_agent": false
},
{
"oid": "7d34c37cdc6ac0888c63c8d4a3ca093539701330",
"body": "ccfly new and ccfly a now accept --permission-mode <default|acceptEdits|plan|\nbypassPermissions> and --dangerously-skip-permissions (alias --yolo), passed\nthrough to the launched claude. They apply on new sessions and offline resume;\nattaching to a live session leaves its mode untouched.\n\nThe intera\n[…]\nsid/dir,opts}; CLIAttachArgs/newSession thread\nthe claude args.\n\nAlso re-embeds the web UI so `!command` bash echoes render as IN/OUT/ERR cards.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "feat(cli): new-session + permission options in new/attach/picker",
"author_name": "Jin",
"author_login": "jsdvjx",
"committed_at": "2026-06-16T03:34:52Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "86ddd3d08f2634ed4c36cd298454c3eb786367b5",
"body": "refreshConfig silently returned on HTTP error / non-200 / bad JSON, which made\nit hard to diagnose why cloud-advertised config (proxy_port, proxy_ca) wasn't\napplying. Log each failure path; behaviour is unchanged (still degrades\ngracefully and keeps existing State). Changeset queued for the next release.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "fix(mesh): log device-config refresh failures instead of swallowing",
"author_name": "Jin",
"author_login": "jsdvjx",
"committed_at": "2026-06-15T15:10:20Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "d6930227f002f9071d89ed3a5172b4327380e64b",
"body": "…0.5.4\n\nWhen the cloud advertises a TLS-bumping proxy exit (byway -bump), ccfly now\nreceives the exit's CA bundle in its device config (proxy_ca), writes it to\n~/.ccfly/proxy-ca.pem, and injects NODE_EXTRA_CA_CERTS into ccfly-created tmux\nsessions. Claude in a session then reaches AI endpoints throu\n[…]\n on the\ncenter heartbeat; ccfly-cloud stores it per out-node (out_config.ca_pem) and\nbundles all exit CAs into the device-config proxy_ca field.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "feat(proxy): auto-trust mesh exit MITM CA in sessions; release ccfly …",
"author_name": "Jin",
"author_login": "jsdvjx",
"committed_at": "2026-06-15T14:19:02Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "7b3c3f018ebe369ee5047311e344c6444be3be6f",
"body": "设备连接时拉云端动态配置(/api/device/config):保存身份重连的设备也能拿到云端下发的出网代理\n策略与轮换后的云公钥,升级重启即零配置生效(不必改 State / 重新配对)。\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "release: ccfly 0.5.3",
"author_name": "Jin",
"author_login": "jsdvjx",
"committed_at": "2026-06-15T04:15:17Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "5fbb654ce5d3b23bf6a0475ac2b9d1f9dd0e3ae7",
"body": "runTunnel 起步先 GET /api/device/config(凭 mesh_token)刷新 cloud_public_key/overlay_ip\n与 proxy_port/scheme,落盘 State,再 applyMeshProxy。这样保存身份重连的设备(不重新 enroll)\n也能拿到云端后来才下发的代理策略、轮换后的云公钥 —— 升级二进制重启即生效,无需手动改 State\n或重新配对,真正做到「默认就启动、不需显式操作」。云端老版本/失败 → 沿用现有 State。\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "feat(mesh): 连接时拉云端动态配置(refreshConfig)→ 代理策略真正零配置生效",
"author_name": "Jin",
"author_login": "jsdvjx",
"committed_at": "2026-06-15T04:14:59Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "f1b010234a754cc38f6b9ef3a2061383b83f97d2",
"body": "云端下发出网代理策略 → 设备零配置自动起本地转发 + 给 ccfly 创建的会话注入代理 + 局域网 bypass\n环境(claude 起的 localhost 服务、局域网其它机器不被全局代理吞掉)。\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "release: ccfly 0.5.2",
"author_name": "Jin",
"author_login": "jsdvjx",
"committed_at": "2026-06-15T03:58:33Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "274e56323055f572c7d6d3753418f7d3b76e8e0e",
"body": "承接 696b4d7(会话代理环境注入):让「默认就启动、不需显式操作」真正成立。\n\n云端在入网响应里下发 proxy_port/proxy_scheme(运维设一次 CCFLY_CLOUD_PROXY_PORT 即全设备生效);\n设备(applyMeshProxy,入网/重连前一次性)据此零配置自动:\n 1) 起 127.0.0.1:<port> → <cloud_overlay_ip>:<port> 转发(addAutoForward,同 localPort 已配则跳过,\n 不覆盖用户 --overlay-forward);\n 2) 设 CCFLY_TMUX_PROXY=<sc\n[…]\ncfly 创建的会话默认带好\n 代理 + 局域网 bypass。\nProxyPort 持久化进 State:CLI(ccfly new/a,EnsureTmuxProxyEnv)与下次重连都据此自动配。\n云端未下发(ProxyPort==0)→ 全程 no-op,默认部署零影响。\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "feat(mesh): 云端下发出网代理策略,设备零配置自动起转发 + 会话注入",
"author_name": "Jin",
"author_login": "jsdvjx",
"committed_at": "2026-06-15T03:56:42Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "696b4d7f4b1affc0291334a8a714a8f59e9c56ac",
"body": "场景:出网流量经 ccfly 本地 forward(如 127.0.0.1:2080 → mesh 出口)代理。但全局代理会把\nclaude 起的 localhost 服务、局域网其它机器的请求也吞进 mesh → 够不到。\n\n让 ccfly 创建会话(new / attach / /term / /start 四处)时,默认经 tmux new-session -e 注入\nhttp(s)_proxy/all_proxy(大小写两套)+ no_proxy(loopback + RFC1918 私网 + link-local +\n*.local 直连),会话里 claude 及其子进程、用户手敲命令自动「出网走代理、本机/局域网直连」。\n\n开关:仅 CCFLY_TMUX_PROXY 配了代理 URL 才注入(未配零行为变化);CCFLY_TMUX_NO_PROXY 覆盖\nbypass 列表。需 tmux ≥ 3.2(-e)。\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "feat(tmux): ccfly 创建的会话默认注入代理 + 局域网 bypass 环境",
"author_name": "Jin",
"author_login": "jsdvjx",
"committed_at": "2026-06-15T03:37:34Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "ef0ce352fca2b0b2b0f10de236ec4e1ca2a9cb7e",
"body": "mesh 数据面加固(根治「控制面在线、数据面静默死」复发):gateway Transport 重连淘汰 +\n上游超时、WG peer 删除 current 守卫、Send 写超时、presence 绑 AddPeer 成功。\ncontrol 包:并发图片 buffer 唯一名、网页终端粘贴读上限、jsonl 超大行不截断。\n内嵌 UI 同步 ttyd-ui(select/状态检测修复)。\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "release: ccfly 0.5.1",
"author_name": "Jin",
"author_login": "jsdvjx",
"committed_at": "2026-06-15T02:44:18Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "eda659e3d2969b2327424f6390331d510633904d",
"body": "clientWSBind.Send 原用 context.Background():TCP 发送缓冲写满 + 云端卡住时 c.Write 永久阻塞,\ncoder/websocket 写串行化 → 一个卡死的 Send 堵死后续所有 WG 握手/keepalive/数据 → WS 在线、\noverlay 数据不流(「在线却不通」)。改 10s 有界写超时 + 超时即 CloseNow 触发 pump 出错重连。\n与 ccfly-cloud 侧同一修复对称。\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "fix(mesh): 设备侧 Send 有界写超时(M3)",
"author_name": "Jin",
"author_login": "jsdvjx",
"committed_at": "2026-06-15T02:39:09Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "e9b0000cc1302a9a5b97f8b3d9d80418f6431ac1",
"body": "A1 图片粘贴用全局共享 tmux buffer \"ccfly-img\"(写死名、无锁):两个会话/标签页\n 并发带图提交时互相覆盖 buffer → 粘成别人的图,或 -d 删后另一个 paste-buffer\n 报 no buffer 500 且输入行半填。改为每次请求生成唯一名 imgBufferName()(crypto/rand,\n 熵源故障回退进程内自增+纳秒),消除跨请求竞争。\n\nA6 /term WebSocket 沿用 coder/websocket 默认 32KiB 单帧读上限:网页终端粘贴一大段\n (代码块/路径列表)超 32KiB 即触发读错误 → 读循环退出 \n[…]\n,go1.25 range-over-func),scanOneSession /\n readSessionInfo / findMessageImage / scanRunningAgentsFrom 统一改用。\n\n回归测试覆盖超大行不截断 + 边界(空行/\\r\\n/半截行/早停)。\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "fix(control): 并发图片 buffer 竞争 / 网页终端粘贴上限 / jsonl 超大行截断",
"author_name": "Jin",
"author_login": "jsdvjx",
"committed_at": "2026-06-15T01:59:58Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "059bf9c5f061b2082a8e6df1040f4ac47bae4ec0",
"body": "panemap 真值表(根治消息错发)· stale 防护 · /sse/jsonl + follow 愈合 ·\nccfly ls/a/new/attach(交互式选择器)· takeover 防双写 · ccfly-mesh 组网\n客户端与 overlay 端口桥 · 内嵌 UI 切换为 ccfly-ttyd-ui。\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "release: ccfly 0.5.0",
"author_name": "Jin",
"author_login": "jsdvjx",
"committed_at": "2026-06-13T01:02:26Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "7e3794daeb7e88e6848a42dd1a5354b2e89e86a5",
"body": "节点端 go:embed 的 SPA 从旧 examples/web(React)切到 ccfly-ttyd-ui\n(Vue 双模:节点直连 base='';Hub 下 base='/x/<device>'),与 ccfly-cloud\n共用同一份构建产物。scripts/build-web.sh 改为从同级 ../ccfly-ttyd-ui 构建\n(CCFLY_TTYD_UI_DIR 可覆盖);examples/web 退役留档。\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "feat(web): 内嵌 UI 切换为 ccfly-ttyd-ui",
"author_name": "Jin",
"author_login": "jsdvjx",
"committed_at": "2026-06-13T01:01:42Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "7aa37eebbbcabbdbe58bb2d7a63d5b844457a741",
"body": "- ccfly-mesh:仅组网的精简客户端(sing-box 中心 / byway 出口等服务器用):\n 同一套网页配对入网、held WireGuard 隧道,不链入控制服务(无 tmux 依赖)。\n- overlay 端口桥:EXPOSE(<overlayIP>:<port> → 本机服务,带来源 overlay\n 前缀白名单)与 FORWARD(127.0.0.1:<port> → 远端 overlay 服务)。\n- 控制面代理可关(SetControlProxyEnabled):纯组网节点不暴露 7699 代理。\n- kernel tun 支持与 svc 安装适配。\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "feat(mesh): ccfly-mesh 最小组网客户端 + overlay 端口桥 + kernel tun",
"author_name": "Jin",
"author_login": "jsdvjx",
"committed_at": "2026-06-13T01:01:42Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "d73a19fafacae479034a061ab846c664ad3d01df",
"body": "- ccfly ls [-a]:以目录为核心的会话总览——按 cwd 分组、组内最近活动倒序,\n 每行给出可直接复制执行的接管命令(live → tmux a -t <真 pane 名>,离线 →\n ccfly attach <sid8>);默认每目录 5 条,live 恒全展示。\n- ccfly a / attach:无参进入两级 TUI(选项目 → 选会话 → Enter 接管),\n 纯 ANSI + raw mode(x/term),备用屏进出;带参直连。live → attach 镜像;\n 离线 → takeover 杀残留进程后 tmux 里 claude --resume(防双写唯一入口)。\n- ccfly new [dir]:新 tmux 会话起全新 claude。\n- ccfly panemap-hook:SessionStart hook 入口(最先短路,不付登录壳探测开销)。\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "feat(cli): ccfly ls / a(交互式选择器)/ attach / new",
"author_name": "Jin",
"author_login": "jsdvjx",
"committed_at": "2026-06-13T01:01:29Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "f2fc99a7a427b34b95ef42313e250da92344df89",
"body": "- GET /sse/jsonl:把会话 jsonl 以原始行 + 字节 offset 推给表世界(fsnotify\n 驱动,id=offset 断线续传);跟随 pane 锚,/clear 换文件发 switched。\n- follow 愈合:客户端带 Last-Event-ID / ?follow=1 重连且请求的 sid 已死时,\n 经真值表 prev 轨迹锚回原 pane、直接续其当前会话——断线窗口里错过的\n /clear 在重连时跟上;主动浏览历史(无 follow)仍静态渲染绝不跳走。\n- GET /jsonl/before:向上翻页(headStart 之前一窗更老原始行)。\n- POST /takeover:确定性杀掉会话既有 claude 进程(防双写),供 attach/web\n 重建进 tmux。\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "feat(control): /sse/jsonl 原始事件流(follow 愈合 + 分页)与 takeover",
"author_name": "Jin",
"author_login": "jsdvjx",
"committed_at": "2026-06-13T01:01:29Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "44a98318331f2807863f33217ddd9f6db96b6552",
"body": "根治「webui 消息错发到别的会话」:pane 里跑着的 sid 会被 /clear、里世界\n/resume 换掉,而 tmux 名永不变;同 cwd 多 pane 时旧的 cwd+最近活动启发式\n取 list 第一个 = 抽奖错发。现在:\n\n- SessionStart hook(ccfly panemap-hook)在每次会话开始时把「pane → 当前\n sid」写进 ~/.ccfly/panemap.json 真值表;安装幂等且自愈(临时实例劫持\n hook 路径、其二进制被删后,巡检 ≤1 拍修复——实案教训)。\n- 解析分层:真值表(确定性)→ 精确同名 → fail-clo\n[…]\nsessions 的 rows 按「客户端视口」报(窗口 + tmux 状态栏行数),否则\n web 隐藏终端矮一行裁掉 idle footer,读屏检测全灭(卡死「生成中」实案)。\n- 扫描缓存(mtime+size 逐文件 + 短整轮 memo)与后台巡检(cc-* 孤儿壳回收)。\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "feat(control): pane↔sid 真值表(panemap)与会话解析全面加固",
"author_name": "Jin",
"author_login": "jsdvjx",
"committed_at": "2026-06-13T01:01:10Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "c783ca83cd86767dc72fe8949cca7a38623a6e3f",
"body": "Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>",
"is_bot": false,
"headline": "chore: gitignore .claude/",
"author_name": "Jin",
"author_login": "jsdvjx",
"committed_at": "2026-06-13T01:01:10Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "c3e4244bf2fb8d057a504c5fc48c7ae5bca67d1d",
"body": "Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
"is_bot": false,
"headline": "release: ccfly 0.4.10, @ccfly/react 0.4.4",
"author_name": "Jin",
"author_login": "jsdvjx",
"committed_at": "2026-06-08T05:17:29Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "4ae8025230fd7eae373f58bdd77b033e7e0e33d1",
"body": "Device (control.go): waited zero time after the last bracketed image\npaste before Enter, so Enter landed in Claude Code's async paste-ingest\nwindow and was swallowed — text + [Image #N] sat unsent. Now poll\ncapture-pane for the [Image #N] placeholders (baseline-delta, ~1.4s\ntimeout fallback) before \n[…]\n.is-pressed), visible+tappable not-ready state (.is-off) that flashes\nthe reason, and long-press with image-only now sends instead of dropping.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
"is_bot": false,
"headline": "fix: image submit reliability (device Enter race + compose send-button)",
"author_name": "Jin",
"author_login": "jsdvjx",
"committed_at": "2026-06-08T05:16:22Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "af2e74f7c92316f3d497914d462b8332142f36d0",
"body": "附图改走终端「拖拽文件」的底层机制:tmux set-buffer + paste-buffer -p(括号粘贴)把上传图\n的绝对路径粘进里世界输入框,Claude 原生嵌成 [Image #N]。纯 tmux 往 PTY 注字节、与 GUI/剪贴板\n无关 → --system / headless 一样能用,不再需要 0.4.8 的 CCFLY_IMAGE_PATHS 特判,移除 darwin\nosascript 剪贴板通道(及 imgClip/pngfClassForExt/appleScriptQuote)。\n\n实测(v2.1.168):文本 + 多图 → [Image #1] [Image #2] 原生嵌入、序号正确、buffer 不残留(-d),\nClaude 正确读出两张。优雅降级:某版 Claude 不再自动嵌图时路径落框 → Claude 仍 Read 取图。\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "fix(image): 括号粘贴路径原生附图,全平台统一(含 --system);release ccfly 0.4.9",
"author_name": "Jin",
"author_login": "jsdvjx",
"committed_at": "2026-06-08T03:19:18Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "4ddeabfa07306b6af800b12e7e72dd7ca9e148fe",
"body": "--system(LaunchDaemon)跑在系统上下文、拿不到 GUI 登录会话的剪贴板:osascript 写的剪贴板\n与里世界 Claude(tmux 里)读的不是同一块,launchctl asuser 也注入不进 → 截图粘不进消息。\n改为安装 --system 时在 plist 注入 CCFLY_IMAGE_PATHS=1,控制服务据此走与 Linux 相同的回退:\n把图片绝对路径拼进输入框文本,Claude 用 Read 工具读图(上传落在会话 cwd 内的 .ccfly-uploads/,\nRead 默认放行、不弹权限,实测可正确读出图片内容)。用户级安装无此 env、仍走剪贴板原生粘贴\n(干净的 [Image #N])。移除上一版失败的 launchctl asuser 尝试。\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "fix(image): --system 改走「路径拼文本」回退,绕开它没有的 GUI 剪贴板;release ccfly 0.4.8",
"author_name": "Jin",
"author_login": "jsdvjx",
"committed_at": "2026-06-08T02:53:40Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "ca46bfc19d82612ec39d2f5eb29cc31c5f5ffa95",
"body": "Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "release: ccfly 0.4.7 — image paste under --system via launchctl asuser",
"author_name": "Jin",
"author_login": "jsdvjx",
"committed_at": "2026-06-08T02:13:22Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "8a0c8042a0f8bf187c9c133827c91c9242083a03",
"body": "Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "release: ccfly 0.4.6 — stable machine-id pairing dedup",
"author_name": "Jin",
"author_login": "jsdvjx",
"committed_at": "2026-06-07T18:36:40Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "32ca6045e0f98978707ffb9f251c2d3900d0b18a",
"body": "ccfly install accepts flags in any position; prompts for host (default\ncc.hn) when omitted instead of erroring on a leading --system.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "release: ccfly 0.4.5 — install flag-order + interactive host",
"author_name": "Jin",
"author_login": "jsdvjx",
"committed_at": "2026-06-07T18:11:33Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "bf65aa0fa745069e4354bab6c1b2335b5455144c",
"body": "Screen-state engine + all rich selects ported; cc.hn Hub & Node branding.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "release: ccfly 0.4.4 · @ccfly/react 0.4.3",
"author_name": "Jin",
"author_login": "jsdvjx",
"committed_at": "2026-06-07T17:56:06Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "97421e2f301d99b6c7fed2916dd41f5399217c46",
"body": "permission / effort / confirm / multi / sessionScope / list — each a\nState<Info> subclass + View in one self-registering file, on the new\nattribute-aware engine. Shared pre gains title + options[].checked.\nCentral states/index dispatches kind->View (EngineControl); ControlBar's\nselect branch now defers to the engine live, old cards kept only as the\nWS-degraded fallback.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "feat(react): port remaining rich selects to the screen-state engine",
"author_name": "Jin",
"author_login": "jsdvjx",
"committed_at": "2026-06-07T17:03:57Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "601a81a22093b43b6d5f3cd68550ea3b5fbec291",
"body": "New read-screen pipeline in @ccfly/react: attribute-aware Frame (cur from\ninverse/bg highlight, not just ❯ glyph — fixes glyphless /model picker),\none-time pre features, decentralized State registry by weight, and\nclosed-loop command primitives (send + waitFor). modelSelect is the first\nstate on it:\n[…]\n refactoring the remaining rich selects. Rollback: `git\ncheckout main` (pre-engine) or reset to this commit (working modelSelect).\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "feat(react): screen-state engine + modelSelect on it (checkpoint)",
"author_name": "Jin",
"author_login": "jsdvjx",
"committed_at": "2026-06-07T16:46:43Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "5997952800b8978efdb4fb30505da9f68ad11153",
"body": "Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "release: ccfly 0.4.3 (no-code device pairing CLI)",
"author_name": "Jin",
"author_login": "jsdvjx",
"committed_at": "2026-06-07T13:14:04Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "cbaf8847fb56ff891df0e3de9a643adca9b2e223",
"body": "… approve → bind\n\nDevice CLI: when the connect/install target has no /<code>, run a device-authorization flow — POST /api/pair/start, print + auto-open the approval link, poll (Authorization: Bearer pollToken) until approved, then enroll from the returned creds and hold the tunnel. Saved-state reconnect skips re-pairing (installed service runs plain 'connect <host>'). The <host>/<code> flow is unchanged.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "feat(pair): no-code device pairing — 'ccfly install <host>' → browser…",
"author_name": "Jin",
"author_login": "jsdvjx",
"committed_at": "2026-06-07T13:08:53Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "6ecbd553c636021b92389af01769aab4e6640ee2",
"body": "…/false-positive fixes)\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "release: ccfly + @ccfly/react 0.4.2 (native image embed + busy de-dup…",
"author_name": "Jin",
"author_login": "jsdvjx",
"committed_at": "2026-06-07T11:20:34Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "51a0bb3aea6a3f4a3c440f4fe4b4a65aeddf6b5d",
"body": "- AgentDock no longer renders a main-busy row (duplicated ControlBar BusyLine); it now shows only running subagents/workflows. BusyLine is the single main-busy source.\n- detectState (ctrlstate.go + livestate.ts, lockstep): a clear numbered select pre-empts busy — Claude Code keeps the 'esc to interr\n[…]\nents stop showing as 'running' (a busy misreport in AgentDock).\n- tests: F8/F9 (select-vs-busy footer) + terminal-status coverage.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "fix(busy): de-dup busy panel (drop AgentDock main row) + stop false busy",
"author_name": "Jin",
"author_login": "jsdvjx",
"committed_at": "2026-06-07T08:30:26Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "66cd3c441dd2bbb1d972c566545f51725e616368",
"body": "…ile paths\n\nReal Claude Code image messages are base64 image blocks ([Image #N]), never paths. So instead of appending the uploaded path to the message text, the device now sets the image on the system clipboard and sends C-v to the session — Claude Code embeds [Image #N] natively. /sendkeys gains a\n[…]\n+ exec args, no shell; reuses upload.go containment); non-darwin falls back to appending paths. Mechanism verified live on-device.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "feat(upload): embed images natively via clipboard+Ctrl+V paste, not f…",
"author_name": "Jin",
"author_login": "jsdvjx",
"committed_at": "2026-06-07T08:14:43Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "43728042d0f2d7b162f437077af5a7f4d97b7649",
"body": "Device sends its build version in the /connect enroll body; cloud stores it on the Device record and the web shows it, so 'did this device pick up the new build?' is visible at a glance.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "feat(mesh): device reports client version on enroll; release ccfly 0.4.1",
"author_name": "Jin",
"author_login": "jsdvjx",
"committed_at": "2026-06-07T07:23:24Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "13a83349862bb06cbe4e15a1ee2a6e176ec0cfc3",
"body": "…/react 0.4.1\n\nBare '\\n' in the submit payload is typed literally via tmux send-keys -l, where it = Enter = submit — so 'text<newline>path' submitted on the text alone and the path lines orphaned (uploaded image never reached the message). Join text + device paths with a space (paths are UUID filenames, no spaces) so it's one line, no premature submit.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "fix(react): merge uploaded paths with space, not newline; bump @ccfly…",
"author_name": "Jin",
"author_login": "jsdvjx",
"committed_at": "2026-06-07T07:23:24Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "b866847b71a13a1c1523200057485cb8fc861c25",
"body": "…clear tmux resolve, /compact percent)\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "release: ccfly 0.4.0 (device binary — upload handler, server floor, /…",
"author_name": "Jin",
"author_login": "jsdvjx",
"committed_at": "2026-06-07T06:18:26Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "0ca7173fd9c257e30697dc93a471afc6d4ce85b6",
"body": "…ST /upload; add @ccfly/react package README\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "docs: README — rich selects, image/file upload, /compact progress, PO…",
"author_name": "Jin",
"author_login": "jsdvjx",
"committed_at": "2026-06-07T05:53:18Z",
"body_truncated": false,
"is_coding_agent": true
},
{
"oid": "bfc0b06e7a45cd144381bd46446fe81580d55fb7",
"body": "…/clear tmux resolve, file upload\n\n- control.go: /sendkeys 'clear' flag -> C-a C-k clear primitive + server floor (re-capture + detectState, 409 when kind != input); POST /upload route\n- upload.go (new): hardened multipart upload — MaxBytesReader (env cap) before parse, server-generated UUID name, s\n[…]\nux by cwd+recency (fixes /clear rebinding); wired into sessions/term/control\n- sessions.go / term.go: session-resolution touch-ups\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "feat(control): guarded-atomic-submit server floor, /compact percent, …",
"author_name": "Jin",
"author_login": "jsdvjx",
"committed_at": "2026-06-07T05:16:13Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "0f6391168b94e514fb13d8527132548f4b39bad8",
"body": "…& workflow cards\n\n- select/: Rich{Model,Permission,Effort,Confirm,SessionScope,Multi,List}Select + selectKind classifier\n- AttachmentBar: image/file upload (paste/picker/drag-drop), upload-on-add, thumbnails, predict hint\n- ControlBar: guarded atomic submit funnel (clear + certain gate + 409 re-syn\n[…]\nkingBlock TUI style\n- api/sendkeys: SendResult {ok,kind}; clear flag; uploadFile (XHR progress)\n- bump @ccfly/react 0.3.3 -> 0.4.0\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>",
"is_bot": false,
"headline": "feat(react): rich selects, file upload, compose redesign, compaction …",
"author_name": "Jin",
"author_login": "jsdvjx",
"committed_at": "2026-06-07T05:16:00Z",
"body_truncated": true,
"is_coding_agent": true
},
{
"oid": "cac34a61d86a862ec37f198ee9b87e69c525445e",
"body": "Ships the recent web-UI work into the device's embedded SPA + npm:\n- /cost panel sweep-all-tabs (instant tab switching)\n- /context as a jsonl-notification card\n- AgentDock /subagents polling gated by live state (no idle polling)\n- livestate shellEvidence fix (no offline misclassification)\n- LiveTerm frozen-mirror watchdog (busy stuck-state recovery)\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>",
"is_bot": false,
"headline": "release: ccfly 0.3.10 · @ccfly/react 0.3.3",
"author_name": "Jin",
"author_login": "jsdvjx",
"committed_at": "2026-06-06T15:51:33Z",
"body_truncated": false,
"is_coding_agent": true
}
],
"releases_count": 3,
"commits_last_year": 129,
"latest_release_at": "2026-06-06T15:51:33Z",
"latest_release_tag": "v0.3.10",
"releases_from_tags": true,
"days_since_last_push": 5,
"active_weeks_last_year": 8,
"days_since_latest_release": 48,
"mean_days_between_releases": 0.1
},
"community": {
"has_readme": true,
"has_license": true,
"has_description": true,
"has_contributing": false,
"health_percentage": 42,
"has_issue_template": false,
"has_code_of_conduct": false,
"has_pull_request_template": false
},
"ecosystem": {
"packages": [
{
"name": "github.com/jsdvjx/ccfly",
"exists": true,
"license": null,
"keywords": [],
"ecosystem": "go",
"matches_repo": true,
"registry_url": "https://pkg.go.dev/github.com/jsdvjx/ccfly",
"is_deprecated": false,
"latest_version": "v0.3.10",
"repository_url": "https://github.com/jsdvjx/ccfly",
"versions_count": 3,
"total_downloads": null,
"dependents_count": null,
"deprecation_note": null,
"maintainers_count": null,
"monthly_downloads": null,
"first_published_at": null,
"latest_published_at": "2026-06-06T15:51:33Z",
"latest_version_yanked": null,
"days_since_latest_publish": 48
}
]
},
"popularity": {
"forks": 0,
"stars": 1,
"watchers": 0,
"fork_history": {
"days": [],
"complete": true,
"collected": 0,
"total_forks": 0
},
"star_history": null,
"open_issues_and_prs": 0
},
"ai_readiness": {
"has_nix": false,
"example_dirs": [
"examples"
],
"has_llms_txt": false,
"has_dockerfile": true,
"has_mcp_signal": false,
"bootstrap_files": [],
"api_schema_files": [],
"has_devcontainer": false,
"typecheck_configs": [
"examples/web/tsconfig.json",
"packages/react/tsconfig.json"
],
"toolchain_manifests": [
"go/go.mod"
],
"largest_source_bytes": 51187,
"source_files_sampled": 226,
"oversized_source_files": 0,
"agent_instruction_files": [
"CLAUDE.md"
],
"agent_instruction_max_bytes": 10363
},
"dependencies": {
"manifests": [
"go/go.mod",
"package.json"
],
"advisories": {
"error": null,
"scope": null,
"source": null,
"findings": [],
"collected": false,
"malicious": [],
"truncated": false,
"by_severity": {},
"advisory_count": 0,
"affected_count": 0,
"assessed_count": 0,
"malicious_count": 0,
"assessed_package": null,
"unassessed_count": 0,
"direct_affected_count": 0
},
"ecosystems": [
"go",
"npm"
],
"dependencies": [
{
"name": "github.com/UserExistsError/conpty",
"manifest": "go/go.mod",
"ecosystem": "go",
"version_constraint": "v0.1.4"
},
{
"name": "github.com/coder/websocket",
"manifest": "go/go.mod",
"ecosystem": "go",
"version_constraint": "v1.8.14"
},
{
"name": "github.com/coredns/caddy",
"manifest": "go/go.mod",
"ecosystem": "go",
"version_constraint": "v1.1.4-0.20250930002214-15135a999495"
},
{
"name": "github.com/coredns/coredns",
"manifest": "go/go.mod",
"ecosystem": "go",
"version_constraint": "v1.14.6"
},
{
"name": "github.com/creack/pty",
"manifest": "go/go.mod",
"ecosystem": "go",
"version_constraint": "v1.1.24"
},
{
"name": "github.com/fsnotify/fsnotify",
"manifest": "go/go.mod",
"ecosystem": "go",
"version_constraint": "v1.10.1"
},
{
"name": "github.com/miekg/dns",
"manifest": "go/go.mod",
"ecosystem": "go",
"version_constraint": "v1.1.72"
},
{
"name": "golang.org/x/crypto",
"manifest": "go/go.mod",
"ecosystem": "go",
"version_constraint": "v0.53.0"
},
{
"name": "golang.org/x/sys",
"manifest": "go/go.mod",
"ecosystem": "go",
"version_constraint": "v0.47.0"
},
{
"name": "golang.org/x/term",
"manifest": "go/go.mod",
"ecosystem": "go",
"version_constraint": "v0.44.0"
},
{
"name": "golang.zx2c4.com/wireguard",
"manifest": "go/go.mod",
"ecosystem": "go",
"version_constraint": "v0.0.0-20260522210424-ecfc5a8d5446"
}
],
"all_dependencies": {
"error": "GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository",
"source": null,
"packages": [],
"collected": false,
"truncated": false,
"total_count": null,
"direct_count": null,
"indirect_count": null
}
},
"maintainership": {
"issues": {
"open_prs": 0,
"merged_prs": 0,
"open_issues": 0,
"closed_ratio": null,
"closed_issues": 0,
"closed_unmerged_prs": 0
},
"bus_factor": 1,
"bot_contributors": 0,
"top_contributors": [
{
"type": "User",
"login": "jsdvjx",
"commits": 129,
"avatar_url": "https://avatars.githubusercontent.com/u/12291665?v=4"
}
],
"contributors_sampled": 1,
"top_contributor_share": 1
},
"quality_signals": {
"has_ci": true,
"has_tests": true,
"ci_workflows": [
"ci.yml",
"release.yml"
],
"has_docs_dir": false,
"linter_configs": [],
"has_editorconfig": false,
"has_linter_config": false,
"has_precommit_config": false
},
"security_signals": {
"lockfiles": [
"go.sum",
"pnpm-lock.yaml"
],
"scorecard": {
"checks": [
{
"name": "Binary-Artifacts",
"score": 10,
"reason": "no binaries found in the repo",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#binary-artifacts"
},
{
"name": "Branch-Protection",
"score": 0,
"reason": "branch protection not enabled on development/release branches",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#branch-protection"
},
{
"name": "CI-Tests",
"score": null,
"reason": "no pull request found",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#ci-tests"
},
{
"name": "CII-Best-Practices",
"score": 0,
"reason": "no effort to earn an OpenSSF best practices badge detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#cii-best-practices"
},
{
"name": "Code-Review",
"score": 0,
"reason": "Found 0/30 approved changesets -- score normalized to 0",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#code-review"
},
{
"name": "Contributors",
"score": 0,
"reason": "project has 0 contributing companies or organizations -- score normalized to 0",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#contributors"
},
{
"name": "Dangerous-Workflow",
"score": 10,
"reason": "no dangerous workflow patterns detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#dangerous-workflow"
},
{
"name": "Dependency-Update-Tool",
"score": 0,
"reason": "no update tool detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#dependency-update-tool"
},
{
"name": "Fuzzing",
"score": 0,
"reason": "project is not fuzzed",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#fuzzing"
},
{
"name": "License",
"score": 10,
"reason": "license file detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#license"
},
{
"name": "Maintained",
"score": 0,
"reason": "project was created within the last 90 days. Please review its contents carefully",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#maintained"
},
{
"name": "Packaging",
"score": null,
"reason": "packaging workflow not detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#packaging"
},
{
"name": "Pinned-Dependencies",
"score": 0,
"reason": "dependency not pinned by hash detected -- score normalized to 0",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#pinned-dependencies"
},
{
"name": "SAST",
"score": 0,
"reason": "no SAST tool detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#sast"
},
{
"name": "Security-Policy",
"score": 0,
"reason": "security policy file not detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#security-policy"
},
{
"name": "Signed-Releases",
"score": null,
"reason": "no releases found",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#signed-releases"
},
{
"name": "Token-Permissions",
"score": 0,
"reason": "detected GitHub workflow tokens with excessive permissions",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#token-permissions"
},
{
"name": "Vulnerabilities",
"score": 3,
"reason": "7 existing vulnerabilities detected",
"documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#vulnerabilities"
}
],
"commit": "a4ba628519d56bdcb35911778eaa7a38b43d67cd",
"ran_at": "2026-07-25T12:41:21Z",
"aggregate_score": 2.5,
"scorecard_version": "v5.5.0"
},
"has_codeql_workflow": false,
"has_security_policy": false,
"has_dependabot_config": false
},
"contribution_flow": {
"collected": true,
"ci_last_run_at": "2026-07-20T11:37:44Z",
"oldest_open_prs": [],
"last_merged_pr_at": null,
"ci_last_conclusion": "FAILURE",
"oldest_open_issues": []
}
},
"config": {
"disabled_metrics": [],
"disabled_categories": [],
"disabled_components": {}
},
"source": {
"url": "https://github.com/jsdvjx/ccfly",
"host": "github.com",
"name": "ccfly",
"owner": "jsdvjx"
},
"metrics": {
"overall": {
"key": "overall",
"band": "at_risk",
"name": "Overall health",
"note": null,
"notes": [],
"value": 43,
"inputs": {
"security": 25,
"vitality": 71,
"community": 24,
"governance": 31,
"engineering": 56
},
"components": []
},
"categories": [
{
"key": "vitality",
"band": "good",
"name": "Vitality",
"value": 71,
"weight": 0.22,
"metrics": [
{
"key": "development_activity",
"band": "moderate",
"name": "Development activity",
"note": null,
"notes": [],
"value": 60,
"inputs": {
"commits_last_year": 129,
"human_commit_share": 1,
"days_since_last_push": 5,
"active_weeks_last_year": 8
},
"components": [
{
"key": "push_recency",
"name": "Push recency",
"detail": "last push 5 days ago",
"points": 36,
"status": "met",
"details": [
{
"code": "push_recency",
"params": {
"days": 5
}
}
],
"max_points": 36
},
{
"key": "commit_cadence",
"name": "Commit cadence",
"detail": "8/52 weeks with commits",
"points": 5.5,
"status": "partial",
"details": [
{
"code": "commit_cadence_weeks",
"params": {
"weeks": 8
}
}
],
"max_points": 36
},
{
"key": "commit_volume",
"name": "Commit volume",
"detail": "129 commits in the last year",
"points": 18,
"status": "met",
"details": [
{
"code": "commits_last_year",
"params": {
"count": 129
}
}
],
"max_points": 18
},
{
"key": "openssf_scorecard_maintained",
"name": "OpenSSF Scorecard: Maintained",
"detail": "project was created within the last 90 days. Please review its contents carefully",
"points": 0,
"status": "missed",
"details": [],
"max_points": 10
}
]
},
{
"key": "release_discipline",
"band": "excellent",
"name": "Release discipline",
"note": "Excluded from scoring (no data or not applicable): OpenSSF Scorecard: Signed-Releases. Remaining weights renormalized.",
"notes": [
{
"code": "excluded_no_data",
"params": {
"components": [
"openssf_scorecard_signed_releases"
]
}
},
{
"code": "weights_renormalized",
"params": {}
}
],
"value": 88,
"inputs": {
"releases_count": 3,
"latest_release_tag": "v0.3.10",
"releases_from_tags": true,
"days_since_latest_release": 48,
"mean_days_between_releases": 0.1
},
"components": [
{
"key": "ships_releases",
"name": "Ships releases",
"detail": "3 version tags (no GitHub releases)",
"points": 16.2,
"status": "partial",
"details": [
{
"code": "version_tags_no_releases",
"params": {
"count": 3
}
}
],
"max_points": 27
},
{
"key": "release_recency",
"name": "Release recency",
"detail": "latest release 48 days ago",
"points": 36,
"status": "met",
"details": [
{
"code": "release_recency",
"params": {
"days": 48
}
}
],
"max_points": 36
},
{
"key": "release_cadence",
"name": "Release cadence",
"detail": "a release every ~0.1 days",
"points": 27,
"status": "met",
"details": [
{
"code": "release_cadence",
"params": {
"gap": 0.1
}
}
],
"max_points": 27
},
{
"key": "openssf_scorecard_signed_releases",
"name": "OpenSSF Scorecard: Signed-Releases",
"detail": "no releases found",
"points": 0,
"status": "excluded",
"details": [
{
"code": "no_data",
"params": {}
}
],
"max_points": 10
}
]
},
{
"key": "abandonment",
"band": "excellent",
"name": "Abandonment",
"note": null,
"notes": [],
"value": 100,
"inputs": {
"cap": null,
"state": "unverified",
"guards": [],
"signals": [],
"red_flag": false,
"multiplier_pct": 100,
"declared_reason": null,
"unverified_reason": "repository_too_young",
"unanswered_open_prs": null,
"unanswered_open_issues": null,
"days_since_last_merged_pr": null,
"days_since_last_human_commit": null,
"days_since_last_human_commit_is_floor": false
},
"components": [
{
"key": "project_is_still_maintained",
"name": "Project is still maintained",
"detail": "maintenance record not established from the collected data",
"points": 100,
"status": "met",
"details": [
{
"code": "abandonment_unverified",
"params": {}
}
],
"max_points": 100
}
]
}
],
"description": "Is the project alive — is code being written and are releases shipping?"
},
{
"key": "community",
"band": "critical",
"name": "Community & Adoption",
"value": 24,
"weight": 0.18,
"metrics": [
{
"key": "popularity",
"band": "critical",
"name": "Popularity & adoption",
"note": null,
"notes": [],
"value": 1,
"inputs": {
"forks": 0,
"stars": 1,
"watchers": 0,
"growth_state": "unverified",
"growth_factor_pct": 100,
"growth_unverified_reason": "no_history"
},
"components": [
{
"key": "stars",
"name": "Stars",
"detail": "1 stars",
"points": 0,
"status": "missed",
"details": [
{
"code": "stars",
"params": {
"count": 1
}
}
],
"max_points": 60
},
{
"key": "forks",
"name": "Forks",
"detail": "0 forks",
"points": 0,
"status": "missed",
"details": [
{
"code": "forks",
"params": {
"count": 0
}
}
],
"max_points": 25
},
{
"key": "watchers",
"name": "Watchers",
"detail": "0 watchers",
"points": 0,
"status": "missed",
"details": [
{
"code": "watchers",
"params": {
"count": 0
}
}
],
"max_points": 15
}
]
},
{
"key": "community_health",
"band": "moderate",
"name": "Community health",
"note": null,
"notes": [],
"value": 50,
"inputs": {
"has_readme": true,
"has_license": true,
"has_contributing": false,
"has_issue_template": false,
"has_code_of_conduct": false,
"has_pull_request_template": false
},
"components": [
{
"key": "readme",
"name": "README",
"detail": null,
"points": 22.5,
"status": "met",
"details": [],
"max_points": 22.5
},
{
"key": "license",
"name": "License",
"detail": "recognized license (MIT)",
"points": 22.5,
"status": "met",
"details": [
{
"code": "license_standard",
"params": {}
},
{
"code": "license_spdx",
"params": {
"spdx": "MIT"
}
}
],
"max_points": 22.5
},
{
"key": "contributing_guide",
"name": "CONTRIBUTING guide",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 18
},
{
"key": "code_of_conduct",
"name": "Code of conduct",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 13.5
},
{
"key": "issue_template",
"name": "Issue template",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 7.2
},
{
"key": "pr_template",
"name": "PR template",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 6.3
}
]
}
],
"description": "Does the project have users, downloads, attention, and a welcoming setup for contributors?"
},
{
"key": "governance",
"band": "at_risk",
"name": "Sustainability & Governance",
"value": 31,
"weight": 0.24,
"metrics": [
{
"key": "maintainer_resilience",
"band": "critical",
"name": "Maintainer resilience (bus factor)",
"note": null,
"notes": [],
"value": 10,
"inputs": {
"bus_factor": 1,
"contributors_sampled": 1,
"top_contributor_share": 1
},
"components": [
{
"key": "bus_factor",
"name": "Bus factor",
"detail": "1 contributor(s) cover half of all commits",
"points": 9,
"status": "partial",
"details": [
{
"code": "bus_factor",
"params": {
"count": 1
}
}
],
"max_points": 54
},
{
"key": "commit_distribution",
"name": "Commit distribution",
"detail": "top contributor authored 100% of commits",
"points": 0,
"status": "missed",
"details": [
{
"code": "top_contributor_share",
"params": {
"share": 100
}
}
],
"max_points": 22.5
},
{
"key": "contributor_breadth",
"name": "Contributor breadth",
"detail": "1 contributors",
"points": 1.4,
"status": "partial",
"details": [
{
"code": "contributors_sampled",
"params": {
"count": 1
}
}
],
"max_points": 13.5
},
{
"key": "openssf_scorecard_contributors",
"name": "OpenSSF Scorecard: Contributors",
"detail": "project has 0 contributing companies or organizations -- score normalized to 0",
"points": 0,
"status": "missed",
"details": [],
"max_points": 10
}
]
},
{
"key": "responsiveness",
"band": "critical",
"name": "Issue & PR responsiveness",
"note": "Excluded from scoring (no data or not applicable): Issue resolution, PR acceptance. Remaining weights renormalized.",
"notes": [
{
"code": "excluded_no_data",
"params": {
"components": [
"issue_resolution",
"pr_acceptance"
]
}
},
{
"code": "weights_renormalized",
"params": {}
}
],
"value": 1,
"inputs": {
"merged_prs": 0,
"open_issues": 0,
"closed_issues": 0,
"issue_closed_ratio": null,
"closed_unmerged_prs": 0
},
"components": [
{
"key": "issue_resolution",
"name": "Issue resolution",
"detail": "no issues or no data",
"points": 0,
"status": "excluded",
"details": [
{
"code": "no_issues_or_data",
"params": {}
}
],
"max_points": 46.75
},
{
"key": "pr_acceptance",
"name": "PR acceptance",
"detail": "no decided pull requests or no data",
"points": 0,
"status": "excluded",
"details": [
{
"code": "no_decided_prs_or_data",
"params": {}
}
],
"max_points": 38.25
},
{
"key": "openssf_scorecard_code_review",
"name": "OpenSSF Scorecard: Code-Review",
"detail": "Found 0/30 approved changesets -- score normalized to 0",
"points": 0,
"status": "missed",
"details": [],
"max_points": 15
}
]
},
{
"key": "stewardship",
"band": "at_risk",
"name": "Ownership & stewardship",
"note": "Excluded from scoring (no data or not applicable): Verified domain. Remaining weights renormalized.",
"notes": [
{
"code": "excluded_no_data",
"params": {
"components": [
"verified_domain"
]
}
},
{
"code": "weights_renormalized",
"params": {}
}
],
"value": 37,
"inputs": {
"followers": 1,
"owner_type": "User",
"is_verified": null,
"owner_login": "jsdvjx",
"public_repos": 5,
"account_age_days": 4097
},
"components": [
{
"key": "ownership_backing",
"name": "Ownership backing",
"detail": "personal (user) account",
"points": 10,
"status": "partial",
"details": [
{
"code": "owner_personal",
"params": {}
}
],
"max_points": 30
},
{
"key": "verified_domain",
"name": "Verified domain",
"detail": "not applicable to user accounts",
"points": 0,
"status": "excluded",
"details": [
{
"code": "not_applicable_to_user_accounts",
"params": {}
}
],
"max_points": 20
},
{
"key": "owner_reach",
"name": "Owner reach",
"detail": "1 followers of jsdvjx",
"points": 2.2,
"status": "partial",
"details": [
{
"code": "owner_followers",
"params": {
"count": 1,
"login": "jsdvjx"
}
}
],
"max_points": 25
},
{
"key": "track_record",
"name": "Track record",
"detail": "5 public repos, account ~11 yr old",
"points": 17.7,
"status": "partial",
"details": [
{
"code": "public_repos",
"params": {
"count": 5
}
},
{
"code": "account_age_years",
"params": {
"years": 11
}
}
],
"max_points": 25
}
]
},
{
"key": "package_maintenance",
"band": "excellent",
"name": "Package maintenance",
"note": null,
"notes": [],
"value": 92,
"inputs": {
"packages": [
"github.com/jsdvjx/ccfly"
],
"ecosystems": "go",
"any_deprecated": false,
"min_days_since_publish": 48
},
"components": [
{
"key": "published_resolvable",
"name": "Published & resolvable",
"detail": "1 package(s) on go",
"points": 25,
"status": "met",
"details": [
{
"code": "packages_published",
"params": {
"count": 1,
"ecosystems": "go"
}
}
],
"max_points": 25
},
{
"key": "publish_recency",
"name": "Publish recency",
"detail": "latest publish 48 days ago",
"points": 35,
"status": "met",
"details": [
{
"code": "publish_recency",
"params": {
"days": 48
}
}
],
"max_points": 35
},
{
"key": "version_history",
"name": "Version history",
"detail": "3 published versions",
"points": 12,
"status": "partial",
"details": [
{
"code": "published_versions",
"params": {
"count": 3
}
}
],
"max_points": 20
},
{
"key": "not_deprecated",
"name": "Not deprecated",
"detail": "active, not deprecated or yanked",
"points": 20,
"status": "met",
"details": [
{
"code": "package_not_deprecated",
"params": {}
}
],
"max_points": 20
}
]
}
],
"description": "Will the project survive its people — bus factor, responsiveness, who backs it, and package upkeep?"
},
{
"key": "engineering",
"band": "moderate",
"name": "Engineering Quality",
"value": 56,
"weight": 0.2,
"metrics": [
{
"key": "engineering_practices",
"band": "moderate",
"name": "Engineering practices",
"note": "Excluded from scoring (no data or not applicable): OpenSSF Scorecard: CI-Tests. Remaining weights renormalized.",
"notes": [
{
"code": "excluded_no_data",
"params": {
"components": [
"openssf_scorecard_ci_tests"
]
}
},
{
"code": "weights_renormalized",
"params": {}
}
],
"value": 60,
"inputs": {
"has_ci": true,
"has_tests": true,
"has_editorconfig": false,
"has_linter_config": false,
"has_precommit_config": false
},
"components": [
{
"key": "ci_workflows",
"name": "CI workflows",
"detail": "2 workflow(s)",
"points": 24,
"status": "met",
"details": [
{
"code": "ci_workflows",
"params": {
"count": 2
}
}
],
"max_points": 24
},
{
"key": "tests_present",
"name": "Tests present",
"detail": null,
"points": 24,
"status": "met",
"details": [],
"max_points": 24
},
{
"key": "linter_config",
"name": "Linter config",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 16
},
{
"key": "pre_commit_hooks",
"name": "Pre-commit hooks",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 9.6
},
{
"key": "editorconfig",
"name": ".editorconfig",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 6.4
},
{
"key": "openssf_scorecard_ci_tests",
"name": "OpenSSF Scorecard: CI-Tests",
"detail": "no pull request found",
"points": 0,
"status": "excluded",
"details": [
{
"code": "no_data",
"params": {}
}
],
"max_points": 20
}
]
},
{
"key": "documentation",
"band": "moderate",
"name": "Documentation",
"note": null,
"notes": [],
"value": 50,
"inputs": {
"topics": [],
"has_wiki": true,
"homepage": null,
"has_readme": true,
"has_docs_dir": false,
"has_description": true
},
"components": [
{
"key": "readme",
"name": "README",
"detail": null,
"points": 30,
"status": "met",
"details": [],
"max_points": 30
},
{
"key": "documentation_directory",
"name": "Documentation directory",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 25
},
{
"key": "documentation_homepage_site",
"name": "Documentation / homepage site",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 15
},
{
"key": "repository_description",
"name": "Repository description",
"detail": null,
"points": 10,
"status": "met",
"details": [],
"max_points": 10
},
{
"key": "topics",
"name": "Topics",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 10
},
{
"key": "wiki",
"name": "Wiki",
"detail": null,
"points": 10,
"status": "met",
"details": [],
"max_points": 10
}
]
}
],
"description": "Are baseline engineering and documentation practices in place?"
},
{
"key": "security",
"band": "critical",
"name": "Security",
"value": 25,
"weight": 0.16,
"metrics": [
{
"key": "security_posture",
"band": "critical",
"name": "Security posture",
"note": "Excluded from scoring (no data or not applicable): CI-Tests, Packaging, Signed-Releases. Remaining weights renormalized.",
"notes": [
{
"code": "excluded_no_data",
"params": {
"components": [
"ci_tests",
"packaging",
"signed_releases"
]
}
},
{
"code": "weights_renormalized",
"params": {}
}
],
"value": 25,
"inputs": {
"source": "openssf_scorecard",
"checks_evaluated": 15,
"scorecard_version": "v5.5.0",
"checks_inconclusive": 3,
"scorecard_aggregate": 2.5
},
"components": [
{
"key": "binary_artifacts",
"name": "Binary-Artifacts",
"detail": "no binaries found in the repo",
"points": 7.5,
"status": "met",
"details": [],
"max_points": 7.5
},
{
"key": "branch_protection",
"name": "Branch-Protection",
"detail": "branch protection not enabled on development/release branches",
"points": 0,
"status": "missed",
"details": [],
"max_points": 7.5
},
{
"key": "ci_tests",
"name": "CI-Tests",
"detail": "no pull request found",
"points": 0,
"status": "excluded",
"details": [
{
"code": "no_data",
"params": {}
}
],
"max_points": 2.5
},
{
"key": "cii_best_practices",
"name": "CII-Best-Practices",
"detail": "no effort to earn an OpenSSF best practices badge detected",
"points": 0,
"status": "missed",
"details": [],
"max_points": 2.5
},
{
"key": "code_review",
"name": "Code-Review",
"detail": "Found 0/30 approved changesets -- score normalized to 0",
"points": 0,
"status": "missed",
"details": [],
"max_points": 7.5
},
{
"key": "contributors",
"name": "Contributors",
"detail": "project has 0 contributing companies or organizations -- score normalized to 0",
"points": 0,
"status": "missed",
"details": [],
"max_points": 2.5
},
{
"key": "dangerous_workflow",
"name": "Dangerous-Workflow",
"detail": "no dangerous workflow patterns detected",
"points": 10,
"status": "met",
"details": [],
"max_points": 10
},
{
"key": "dependency_update_tool",
"name": "Dependency-Update-Tool",
"detail": "no update tool detected",
"points": 0,
"status": "missed",
"details": [],
"max_points": 7.5
},
{
"key": "fuzzing",
"name": "Fuzzing",
"detail": "project is not fuzzed",
"points": 0,
"status": "missed",
"details": [],
"max_points": 5
},
{
"key": "license",
"name": "License",
"detail": "license file detected",
"points": 2.5,
"status": "met",
"details": [],
"max_points": 2.5
},
{
"key": "maintained",
"name": "Maintained",
"detail": "project was created within the last 90 days. Please review its contents carefully",
"points": 0,
"status": "missed",
"details": [],
"max_points": 7.5
},
{
"key": "packaging",
"name": "Packaging",
"detail": "packaging workflow not detected",
"points": 0,
"status": "excluded",
"details": [
{
"code": "no_data",
"params": {}
}
],
"max_points": 5
},
{
"key": "pinned_dependencies",
"name": "Pinned-Dependencies",
"detail": "dependency not pinned by hash detected -- score normalized to 0",
"points": 0,
"status": "missed",
"details": [],
"max_points": 5
},
{
"key": "sast",
"name": "SAST",
"detail": "no SAST tool detected",
"points": 0,
"status": "missed",
"details": [],
"max_points": 5
},
{
"key": "security_policy",
"name": "Security-Policy",
"detail": "security policy file not detected",
"points": 0,
"status": "missed",
"details": [],
"max_points": 5
},
{
"key": "signed_releases",
"name": "Signed-Releases",
"detail": "no releases found",
"points": 0,
"status": "excluded",
"details": [
{
"code": "no_data",
"params": {}
}
],
"max_points": 7.5
},
{
"key": "token_permissions",
"name": "Token-Permissions",
"detail": "detected GitHub workflow tokens with excessive permissions",
"points": 0,
"status": "missed",
"details": [],
"max_points": 7.5
},
{
"key": "vulnerabilities",
"name": "Vulnerabilities",
"detail": "7 existing vulnerabilities detected",
"points": 2.2,
"status": "partial",
"details": [],
"max_points": 7.5
}
]
}
],
"description": "Are visible security and supply-chain practices strong, with no malicious dependency and no unresolved high-risk jurisdiction exposure?"
},
{
"key": "ai_readiness",
"band": "good",
"name": "AI Readiness",
"value": 73,
"weight": 0,
"metrics": [
{
"key": "ai_agent_context",
"band": "excellent",
"name": "Agent context & guidance",
"note": null,
"notes": [],
"value": 85,
"inputs": {
"has_llms_txt": false,
"legible_history_share": 0.98,
"agent_instruction_files": [
"CLAUDE.md"
],
"agent_instruction_max_bytes": 10363
},
"components": [
{
"key": "agent_instructions",
"name": "Agent instructions",
"detail": "CLAUDE.md",
"points": 45,
"status": "met",
"details": [
{
"code": "file_list",
"params": {
"files": "CLAUDE.md"
}
}
],
"max_points": 45
},
{
"key": "machine_readable_docs_llms_txt",
"name": "Machine-readable docs (llms.txt)",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 15
},
{
"key": "legible_commit_history",
"name": "Legible commit history",
"detail": "98 of 100 human commits state their intent (structured subject or explanatory body)",
"points": 40,
"status": "met",
"details": [
{
"code": "legible_history",
"params": {
"legible": 98,
"sampled": 100
}
}
],
"max_points": 40
}
]
},
{
"key": "ai_verify_loop",
"band": "moderate",
"name": "Verify loop (build / test / typecheck)",
"note": null,
"notes": [],
"value": 66,
"inputs": {
"has_nix": false,
"has_tests": true,
"lockfiles": [
"go.sum",
"pnpm-lock.yaml"
],
"has_dockerfile": true,
"typed_language": true,
"bootstrap_files": [],
"has_devcontainer": false,
"has_linter_config": false,
"typecheck_configs": [
"examples/web/tsconfig.json",
"packages/react/tsconfig.json"
],
"agent_commit_share": 0.8,
"toolchain_manifests": [
"go/go.mod"
],
"dependency_bot_commit_share": 0
},
"components": [
{
"key": "one_command_bootstrap",
"name": "One-command bootstrap",
"detail": "go/go.mod (toolchain convention, no task runner)",
"points": 12.6,
"status": "partial",
"details": [
{
"code": "toolchain_convention",
"params": {
"files": "go/go.mod"
}
}
],
"max_points": 18
},
{
"key": "automated_tests",
"name": "Automated tests",
"detail": null,
"points": 22,
"status": "met",
"details": [],
"max_points": 22
},
{
"key": "lint_format_config",
"name": "Lint / format config",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 11
},
{
"key": "static_type_checking",
"name": "Static type checking",
"detail": "examples/web/tsconfig.json, packages/react/tsconfig.json",
"points": 11,
"status": "met",
"details": [
{
"code": "file_list",
"params": {
"files": "examples/web/tsconfig.json, packages/react/tsconfig.json"
}
}
],
"max_points": 11
},
{
"key": "reproducible_environment",
"name": "Reproducible environment",
"detail": "Dockerfile, lockfile",
"points": 10,
"status": "met",
"details": [
{
"code": "file_list",
"params": {
"files": "Dockerfile, lockfile"
}
}
],
"max_points": 10
},
{
"key": "demonstrated_agent_practice",
"name": "Demonstrated agent practice",
"detail": "80 of the last 100 commits agent-authored or agent-credited",
"points": 10,
"status": "met",
"details": [
{
"code": "agent_authored_commits",
"params": {
"count": 80,
"sampled": 100
}
}
],
"max_points": 10
},
{
"key": "automated_maintenance",
"name": "Automated maintenance",
"detail": "no automated dependency updates observed",
"points": 0,
"status": "missed",
"details": [
{
"code": "no_dependency_automation",
"params": {}
}
],
"max_points": 8
},
{
"key": "openssf_scorecard_pinned_dependencies",
"name": "OpenSSF Scorecard: Pinned-Dependencies",
"detail": "dependency not pinned by hash detected -- score normalized to 0",
"points": 0,
"status": "missed",
"details": [],
"max_points": 10
}
]
},
{
"key": "ai_code_legibility",
"band": "excellent",
"name": "Code legibility for models",
"note": null,
"notes": [],
"value": 100,
"inputs": {
"primary_language": "Go",
"largest_source_bytes": 51187,
"source_files_sampled": 226,
"oversized_source_files": 0
},
"components": [
{
"key": "type_checkable_code",
"name": "Type-checkable code",
"detail": "Go (statically typed)",
"points": 45,
"status": "met",
"details": [
{
"code": "statically_typed_language",
"params": {
"language": "Go"
}
}
],
"max_points": 45
},
{
"key": "manageable_file_sizes",
"name": "Manageable file sizes",
"detail": "0/226 source files over 60KB",
"points": 55,
"status": "met",
"details": [
{
"code": "oversized_source_files",
"params": {
"kb": 60,
"sampled": 226,
"oversized": 0
}
}
],
"max_points": 55
}
]
},
{
"key": "ai_interfaces",
"band": "at_risk",
"name": "Machine-readable interfaces",
"note": null,
"notes": [],
"value": 40,
"inputs": {
"example_dirs": [
"examples"
],
"has_mcp_signal": false,
"api_schema_files": []
},
"components": [
{
"key": "api_schema_openapi_graphql_proto",
"name": "API schema (OpenAPI/GraphQL/proto)",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 40
},
{
"key": "mcp_server",
"name": "MCP server",
"detail": null,
"points": 0,
"status": "missed",
"details": [],
"max_points": 20
},
{
"key": "runnable_examples",
"name": "Runnable examples",
"detail": "examples",
"points": 40,
"status": "met",
"details": [
{
"code": "file_list",
"params": {
"files": "examples"
}
}
],
"max_points": 40
}
]
}
],
"description": "How well is the repo equipped to be developed and maintained with AI coding agents? An independent, experimental badge — weight 0.0, so it is surfaced on its own and does not affect the overall health score."
}
],
"metrics_version": "1.13.0"
},
"warnings": [
"Star history unavailable: GitHub GraphQL error: Resource not accessible by personal access token",
"GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository"
],
"report_type": "repository",
"generated_at": "2026-07-25T12:41:26.636570Z",
"schema_version": "0.27.0",
"badge_url": "https://raw.githubusercontent.com/inspect-software/badges/main/v1/j/jsdvjx/ccfly.svg",
"full_name": "jsdvjx/ccfly",
"license_state": "standard",
"license_spdx": "MIT"
}