npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

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

About

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

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

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

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

Open Software & Tools

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

© 2026 – Pkg Stats / Ryan Hefner

@fanhefeng/file-tidy

v0.5.2

Published

Organize files into prefixed category folders with byte-level dedup, near-duplicate and similar-image detection, and one-step undo

Readme

File Tidy

归档文件、去重、挑出坏文件,一步撤销。

一个杂乱的 Downloads、桌面、或者刚倒出来的存储卡目录,整理成这样:

归档目录/
├── ft_Images/2026-07/…
├── ft_Images/Screenshots/2026-07/…
├── ft_Documents/Ebooks/2025/…
├── ft_Archives/Installers/…        # 安装包不按日期分——下载日期没有意义
├── ft_Duplicates/                  # 内容完全相同的文件,附 manifest.md 说明留下了谁
├── ft_Review/empty|corrupt|junk/   # 0 字节、坏文件、系统垃圾——移走但绝不删
└── .tidy/runs/                     # 每次运行的记录,撤销靠它

生成的目录一律带 ft_ 前缀,一眼能和你自己建的目录区分开。前缀可在配置里改,设成 "" 就是旧行为;目标目录里已经有无前缀的旧归档目录时会自动沿用,不会把一份档案劈成两套。

核心行为:

  • 两级分类:先按扩展名进 Images / Videos / Audios / Documents / Archives / Fonts,再按文件名规则细分出 Screenshots、Ebooks、Invoices、Installers 等子目录。规则全在配置里,可改可删。
  • 日期粒度按类型定:照片视频按 年-月(EXIF 拍摄时间),文档按 年,安装包和字体不按日期——它们只有下载日期,按月拆只会把一套东西撒进十几个目录。
  • 字节级去重:先比大小,再比头尾哈希,最后全文件 SHA-256,跟文件名无关。和归档目录里已有文件重复的也会被拦下。
  • 疑似重复(只标注,照常归档):文件名归一化后同名(剥掉来源水印、副本标记、日期戳)、同名不同格式、同一软件的不同版本号。
  • 相似图片(只标注):感知哈希,抓连拍、换分辨率重新导出、聊天软件压缩过的版本——这些字节哈希一个都抓不到。
  • 坏文件与垃圾:0 字节文件、内容与扩展名不符的文件、.DS_Store 之类,移进 ft_Review/ 分类存放,从不删除。
  • 动手前先给完整预览,确认后才移动。
  • 可撤销:每次运行在目标目录下写 .tidy/runs 清单,撤销时逐条还原并清掉建出来的空目录。

疑似重复和相似图片是启发式判断,不是内容相同的证明,所以只在预览里标注、照常归档,删不删由你决定。只有字节级完全相同的才会被隔离。

两种用法

CLI

npm i -g @fanhefeng/file-tidy       # 装完命令名是 tidy
tidy ~/Downloads --dest ~/Archive   # 整理到指定目录
tidy ~/Downloads --in-place         # 就地整理,分类目录建在源文件夹内
tidy ~/Downloads --dry-run          # 只看计划,不动文件
tidy ~/Downloads --plain            # 关掉疑似重复/坏文件/相似图片检测,只做基础归档与字节去重
tidy undo --dest ~/Archive          # 撤销上一次

不传源文件夹会弹出系统文件夹选择框(macOS 用 osascript,Windows 用 PowerShell,Linux 用 zenity/kdialog)。完整选项见 tidy --help。

需要 Node.js >= 20.12(CLI 用到的 node:util styleText 是这个版本才有的)。

Raycast 扩展

两个命令:Tidy Folder 和 Undo Last Tidy,能力与 CLI 一致,带表单和预览界面。源码在 raycast/。

配置

共享配置文件,首次运行时生成默认值:

  • macOS / Linux:~/.config/tidy/config.json
  • Windows:%APPDATA%\tidy\config.json

CLI 和 Raycast 扩展读的是同一份配置。可调的键:

| 键 | 作用 | | --------------------- | -------------------------------------------------------------------------- | | dest | 固定默认归档目录 | | categories | 类别 → 扩展名映射 | | fallbackCategory | 认不出扩展名时的兜底类别 | | folderPrefix | 生成目录的前缀,默认 "ft_";设成 "" 恢复旧命名 | | granularity | 每个类别的日期粒度:"month" / "year" / "none" | | subCategories | 二级分类规则,match 是正则、exts 是扩展名,自上而下首个命中生效 | | detect | 检测开关:similar / health / perceptual,或整体设为 false 全部关闭 | | perceptualThreshold | 图片相似度阈值(汉明距离),默认 5,调大更宽松 |

categories 和 subCategories 是整体替换语义——这样你才能删掉不想要的类别。副作用是:升级后新增的默认类别不会自动进你已有的配置文件。检测到这种情况时会提示一行,让你自己决定加不加,工具不会擅自改你的配置。

其余键是合并语义,只写你关心的那个即可。

仓库结构

src/core/        ★ 唯一真源:纯逻辑,不含面向用户文案(附 .d.ts 类型声明)
  config.js        配置、目录前缀、类别与规则编译
  scan.js          遍历源/目标目录,一二级分类
  dedup.js         字节级去重(大小 → 头尾哈希 → SHA-256)
  similar.js       疑似重复(文件名归一化、同名异格式、版本号)
  phash.js         图片感知哈希与聚簇(纯 JS 解码,无原生依赖)
  health.js        0 字节、魔数校验、系统垃圾
  date.js          日期解析与粒度
  plan.js          汇总成移动计划(唯一决定目标路径的地方)
  analyze.js       编排上述各步,两个适配层共用
  execute.js       执行移动 + 运行清单
  move.js          单个文件的移动,含跨卷复制回退
  undo.js          撤销
bin/tidy.js      CLI 适配层:终端文案与交互
raycast/src/     Raycast 适配层:表单与列表 UI
raycast/src/core 生成物 —— 由 sync 从 src/core 原样复制,勿手改
raycast/tests    生成物 —— 由 sync 从 test/ 原样复制,勿手改
scripts/sync.js  同步脚本
test/            核心逻辑测试(node:test)

core 只返回数据、抛带 code 的错误,所有"说话"都在各自适配层,因此两份 core 字节相同,同步就是复制:

pnpm test        # 跑测试 + 校验 raycast 副本未漂移
pnpm sync        # src/core → raycast/src/core,test → raycast/tests
pnpm sync:fork   # 再把 raycast/ 镜像到 Store fork

分层约定、commit 规范、Raycast Store 提交流程与检查清单见 CONTRIBUTING.md。

Raycast 扩展

已上架 Raycast Store(PR #29437,2026-07-31 合并)。Store 要求扩展目录自包含、不能 import 目录外的文件,raycast/src/core/ 这份复制正是为此存在。

更新记录

见 CHANGELOG.md。raycast/CHANGELOG.md 是另一份,格式由 Raycast Store 规定,只记面向扩展用户的变更。