linkany
v0.0.3
Published
`linkany` 是一个 **macOS/Linux** 上的“安全 symlink 管理器”,围绕一个 `manifest` 文件维护一组“source ↔ target”的链接关系,并提供四个高层 API:
Readme
linkany
linkany 是一个 macOS/Linux 上的“安全 symlink 管理器”,围绕一个 manifest 文件维护一组“source ↔ target”的链接关系,并提供四个高层 API:
add(manifestPath, { source, target, ... })remove(manifestPath, key, opts?)install(manifestPath, opts?)uninstall(manifestPath, opts?)
它的设计原则是:安全第一、可追溯、默认拒绝任何可能导致数据丢失的行为。
CLI(命令行)
linkany 同时提供 库 API 与 CLI。CLI 的核心设计是:支持设置一个“全局默认 manifest”,让你后续无需重复传 --manifest。
设置/查看默认 manifest
- 设置默认 manifest(写入全局配置,路径会被 resolve 成绝对路径):
linkany manifest set ./linkany.manifest.json
- 查看当前默认 manifest:
linkany manifest show
- 清空默认 manifest:
linkany manifest clear
在命令中使用 manifest(优先级)
- 优先级:
-m/--manifest <path>(单次覆盖) > 全局默认 manifest - 示例:
- 使用默认 manifest:
linkany install - 单次覆盖:
linkany install -m ./other.manifest.json
- 使用默认 manifest:
常用命令
linkany add --source <path> --target <path> [--kind file|dir] [--atomic|--no-atomic] [-m <manifest>] [--dry-run] [--plan]linkany remove <key> [--keep-link] [-m <manifest>] [--dry-run] [--plan]linkany install [-m <manifest>] [--dry-run] [--plan]linkany uninstall [-m <manifest>] [--dry-run] [--plan]
全局配置文件路径(XDG)
- 若设置了
XDG_CONFIG_HOME:$XDG_CONFIG_HOME/linkany/config.json - 否则:
~/.config/linkany/config.json - 格式:
{ "manifestPath": "/abs/path/to/manifest.json" }能力概览
- 仅使用 symlink:如果 symlink 失败(权限/文件系统限制等),直接报错,不会退化为 copy 安装。
- 文件 & 目录:同时支持文件和目录链接。
- 安全策略:
add:当source和target同时存在(且target不是指向source的 symlink)时 拒绝。remove/uninstall:只会删除target的 symlink,绝不删除 source。install:如果发现某个target存在但不是 symlink,会 整体 abort,避免误伤真实文件/目录。
- 原子性(尽力而为):
- 创建/替换 symlink 时优先使用
target.tmp.<rand>,再rename到位。 - 替换已有 symlink 时会优先把旧 target 移到
target.bak.<timestamp>.<rand>(便于恢复)。
- 创建/替换 symlink 时优先使用
- 审计记录(有记录的):每次调用都会把
Result追加写入 JSONL 文件,默认路径为${manifestPath}.log.jsonl。 - dry-run / plan 输出:
opts.dryRun=true时不触发任何文件系统写操作(不 symlink/rename/unlink),只返回计划与结果结构。opts.includePlanText=true时会在Result.planText中附带可读的 plan 文本。
- rollback 协议(best-effort):
Result.rollbackSteps会尽力给出“可逆步骤”的回滚计划(例如 move/symlink 的逆操作)。目前是协议与数据结构,未提供一键 rollback API。
Manifest 格式(v1)
{
"version": 1,
"installs": [
{
"id": "optional-stable-id",
"source": "path/to/source",
"target": "path/to/target",
"kind": "file",
"atomic": true
}
]
}说明:
source/target支持绝对路径或相对路径;相对路径以 manifest 文件所在目录 为基准。id可选;如果没有id,内部默认以target作为该条目的 identity(用于 remove)。kind可选:file | dir。不写时,add会尽力推断;install会从 source 的实际类型推断。atomic默认true。- 允许存在额外字段(
linkany会尽量保留并写回)。
API
linkany 的 API 支持两种输入方式,合并为同一个入口:
- 文件模式:
manifest传入 manifest 文件路径(string) - in-memory 模式:
manifest直接传入 manifest JSON/对象
四个核心 API 的返回值统一为:
{ result, manifest }(result为本次操作结果,manifest为操作后的 manifest 对象)
add(manifest, { source, target, kind?, atomic? }, opts?)
用途:把一条映射写入 manifest,并把 target 收敛为指向 source 的 symlink。
核心语义:
- source 不存在:自动创建空 source(文件:空文件;目录:空目录)。
- target 已存在且不是 symlink、source 不存在:会执行一次“安全迁移”:
- copy
target -> source - 将原
target移到target.bak.<timestamp>.<rand> - 再把
target改成指向source的 symlink
- copy
- source 与 target 同时存在:拒绝(error),要求用户手动处理冲突。
remove(manifest, key, opts?)
用途:从 manifest 移除一条映射,并且 默认删除 target 的 symlink。
key:优先匹配id,否则匹配target。opts.keepLink=true可仅移除 manifest 记录,不删除 target symlink。- 永远不删除 source。
install(manifest, opts?)
用途:按 manifest 全量落地,确保每个 target 都是指向 source 的 symlink。
安全策略:
- 任意一条出现以下情况,都会 abort 且不做任何变更:
- source 不存在
- target 存在但不是 symlink
uninstall(manifest, opts?)
用途:按 manifest 全量撤销,只删除 target 的 symlink;永远不删除 source。
in-memory 模式的额外 options
当 manifest 传入 JSON/对象(而不是路径)时,opts 额外支持:
baseDir?: string:用于解析相对路径(默认process.cwd())manifestPath?: string:仅用于Result.manifestPath与 audit 默认路径推导(不会触发读写 manifest 文件)
审计日志(Audit Log)
- 默认写入:
${manifestPath}.log.jsonl - 每行是一条 JSON(完整
Result),包含:执行步骤、错误、耗时、变更摘要。 - 可通过
opts.auditLogPath指定自定义路径。 - 如需完全关闭审计(由上层自行处理),传
opts.audit=false;CLI 对应--no-audit。
Options(opts)
适用于四个 API 的通用 options(CommonOptions):
auditLogPath?: string:覆盖默认审计日志路径。dryRun?: boolean:只返回计划/结果,不写文件系统。includePlanText?: boolean:在Result.planText中包含可读 plan 文本。logger?: { info/warn/error }:注入日志实现(可选)。
目录结构(维护者)
src/
api/ # 4 个对外操作,分别一个文件
core/ # 执行引擎:plan/apply/fs/audit/runner/backup
manifest/ # manifest 类型与读写(写回保持未知字段)
cli/ # CLI 相关模块(全局配置等)
cli.ts # CLI 入口(argv 解析与命令分发)
index.ts # 对外统一导出
types.ts # 公共类型(Result/Step/Options)更详细的维护说明见 KNOWLEDGE_BASE.md。
