@chiimagnus/applebookscli 0.1.5 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # AppleBooksCLI
2
2
 
3
- AppleBooksCLI 是一个用于 macOS Apple Books 的命令行工具。你可以直接查询自己的书库、阅读状态、划线与笔记,读取可用的 EPUB/PDF 内容,导出笔记,并在需要时安全地修改笔记或藏书。
3
+ [AppleBooksCLI](https://github.com/chiimagnus/AppleBooksCLI) 是一个用于 macOS Apple Books 的命令行工具。你可以直接查询自己的书库、阅读状态、划线与笔记,读取可用的 EPUB/PDF 内容,导出笔记,并在需要时安全地修改笔记或藏书。
4
4
 
5
5
  ## 主要功能
6
6
 
@@ -10,35 +10,36 @@ AppleBooksCLI 是一个用于 macOS Apple Books 的命令行工具。你可以
10
10
  - 读取可用 EPUB 的目录、章节、元数据与批注上下文。
11
11
  - 提取 PDF 划线与笔记。
12
12
  - 导出 JSON、CSV、Markdown 或 HTML。
13
- - 安全修改笔记、管理藏书,并在写入前自动备份。
14
- - 安装随 CLI 一起分发的 `applebookscli` Skill,供 Codex/AI 直接使用。
13
+ - **安全修改笔记、管理藏书,并在写入前自动备份。**
14
+ - 提供标准 `applebookscli` Agent Skill
15
15
 
16
16
  ## 系统要求
17
17
 
18
- - macOS 12 或更高版本。
19
- - npm 发布的预编译版本目前支持 Apple Silicon(arm64)。
20
18
  - 读取 Apple Books 数据时,macOS 可能要求为终端或调用进程授予 Full Disk Access。
21
19
  - 未下载的 EPUB、DRM 内容或当前系统无法读取的内容会明确提示不可用或能力受限;AppleBooksCLI 不绕过系统保护。
22
20
 
23
21
  ## 安装
24
22
 
25
- 安装稳定版:
26
-
27
23
  ```sh
28
- npm install --global @chiimagnus/applebookscli
29
- applebookscli --version
30
- ```
24
+ # 安装 CLI
25
+ npm install --global @chiimagnus/applebookscli@latest
31
26
 
32
- 如果需要试用 beta:
27
+ # 安装 SKILL.md;首次安装时由 Agent Skills CLI 选择目标 Agent
28
+ CLI_VERSION="$(applebookscli --version)"
29
+ npx -y skills@1.5.23 add "chiimagnus/AppleBooksCLI#v${CLI_VERSION}" --skill applebookscli --global
33
30
 
34
- ```sh
35
- npm install --global @chiimagnus/applebookscli@beta
36
31
  ```
37
32
 
38
- 更新到最新稳定版:
33
+ 之后通过 npm 升级 CLI 时,若该 Skill 仍由 Agent Skills CLI 管理,npm `postinstall` 会把它自动切到相同的 `v<CLI版本>` tag 并调用官方 updater;没有安装 Skill 的用户不会受到影响。使用 `--ignore-scripts` 会显式关闭这条自动联动。此前手工复制的 Skill 没有 source tracking,只需按上面的标准命令重新安装一次即可接入后续自动更新。
34
+
35
+ ## 获取帮助
36
+
37
+ CLI 自带完整帮助,具体命令与参数以当前安装版本为准:
39
38
 
40
39
  ```sh
41
- npm install --global @chiimagnus/applebookscli@latest
40
+ applebookscli --help
41
+ applebookscli <group> --help
42
+ applebookscli <group> <subcommand> --help
42
43
  ```
43
44
 
44
45
  ## 快速开始
@@ -100,7 +101,7 @@ applebookscli pdf list
100
101
  applebookscli pdf highlights --help
101
102
  ```
102
103
 
103
- AppleBooksCLI 只读取本机当前可访问的内容;不会为了检查内容而主动触发 iCloud 下载,也不会绕过 DRM。
104
+ EPUB 在读取正文前会先检查本地 materialization 状态,不主动触发 iCloud hydration,也不会绕过 DRM。PDF 只处理当前可解析为可读本地文件的 source;对 iCloud placeholder 的 non-hydrating 行为尚未建立等价保证。
104
105
 
105
106
  ## 导出
106
107
 
@@ -112,7 +113,7 @@ applebookscli export --format markdown --output ~/Desktop/apple-books.md
112
113
  applebookscli export --format json --output ~/Desktop/apple-books.json
113
114
  ```
114
115
 
115
- 还支持 CSV、HTML、按书分组、筛选划线/笔记、Obsidian 格式、封面与完整笔记归档等选项:
116
+ 还支持 CSV、HTML、按书分组、筛选划线/笔记、Obsidian 格式、封面与完整笔记归档等选项。有 CFI 的 EPUB 批注在 HTML/Markdown 中会把 `Location` 本身做成 Apple Books deep link;无 CFI 时退化为书籍级链接。JSON/CSV 保留对应 `appleBooksURL`:
116
117
 
117
118
  ```sh
118
119
  applebookscli export --help
@@ -128,40 +129,33 @@ applebookscli collections --help
128
129
  applebookscli backups --help
129
130
  ```
130
131
 
131
- ## 安装 AppleBooksCLI Skill
132
-
133
- npm 包中包含配套的 `applebookscli` Skill:
132
+ 单条 collection / annotation mutation 可加 `--sync`,在本地 commit + cloud projection 后等待当前 Mac 的 CloudKit acknowledgement:
134
133
 
135
134
  ```sh
136
- applebookscli skill install
135
+ applebookscli collections create "My Shelf" --sync --json
137
136
  ```
138
137
 
139
- 它会安装到 `${CODEX_HOME:-~/.codex}/skills/applebookscli`。如果目标已经存在,CLI 默认不会覆盖;需要明确替换时使用:
138
+ 连续多条写入时,优先正常提交各 mutation,最后只 flush 一次:
140
139
 
141
140
  ```sh
142
- applebookscli skill install --force
141
+ applebookscli collections create "Shelf A" --json
142
+ applebookscli annotations update-note <annotation-uuid> --note "New note" --json
143
+ applebookscli sync --json
143
144
  ```
144
145
 
146
+ `sync` 只处理已存在的 pending collection/member/annotation cloud records;无 pending 时不触发生命周期。acknowledgement 只证明**当前 Mac** 已完成 Apple Books CloudKit upload,不等于另一台设备已经显示。post-commit `cloud_sync_failed` 不能触发自动重试;BKLibrary restore 也不等同于可逐条 flush 的 cloud mutation。
147
+
145
148
  ## 可选配置
146
149
 
147
150
  大多数用户不需要配置文件。只有需要指定额外的 EPUB 目录,或给历史批注补充书名/作者信息时,才需要 `~/.config/applebookscli/config.json`。
148
151
 
149
152
  示例见 [`Config/applebookscli.example.json`](Config/applebookscli.example.json)。
150
153
 
151
- ## 获取帮助
152
-
153
- CLI 自带完整帮助,具体命令与参数以当前安装版本为准:
154
-
155
- ```sh
156
- applebookscli --help
157
- applebookscli <group> --help
158
- applebookscli <group> <subcommand> --help
159
- ```
160
-
161
154
  ## 开发与维护
162
155
 
163
156
  架构、CLI contract、写入安全、发布流程和其它维护者文档从 [`docs/index.md`](docs/index.md) 开始。
164
157
 
165
158
  ## License
166
159
 
167
- AppleBooksCLI 使用 GNU Affero General Public License v3(AGPLv3)。第三方 notice 与许可证文本见 [`THIRD_PARTY_NOTICES.md`](THIRD_PARTY_NOTICES.md) 和 [`ThirdPartyLicenses/`](ThirdPartyLicenses/)
160
+ AppleBooksCLI 使用 [AGPLv3 LICENSE](LICENSE) 。
161
+ 第三方 notice 与许可证文本见 [`THIRD_PARTY_NOTICES.md`](THIRD_PARTY_NOTICES.md) 和 [`ThirdPartyLicenses/`](ThirdPartyLicenses/)。
package/bin/applebookscli CHANGED
Binary file
@@ -0,0 +1,75 @@
1
+ import { readFile, rename, stat, writeFile } from "node:fs/promises";
2
+ import { homedir } from "node:os";
3
+ import { join } from "node:path";
4
+ import { spawn } from "node:child_process";
5
+
6
+ const skillName = "applebookscli";
7
+ const source = "chiimagnus/AppleBooksCLI";
8
+ const sourceURL = "https://github.com/chiimagnus/AppleBooksCLI.git";
9
+ const skillsVersion = "1.5.23";
10
+
11
+ async function runUpdater() {
12
+ return new Promise((resolve, reject) => {
13
+ const child = spawn(
14
+ "npx",
15
+ ["-y", `skills@${skillsVersion}`, "update", skillName, "-g", "-y"],
16
+ {
17
+ stdio: "ignore",
18
+ env: { ...process.env, DISABLE_TELEMETRY: "1" },
19
+ },
20
+ );
21
+ child.once("error", reject);
22
+ child.once("exit", resolve);
23
+ });
24
+ }
25
+
26
+ async function main() {
27
+ const packageJSON = JSON.parse(
28
+ await readFile(new URL("../../package.json", import.meta.url), "utf8"),
29
+ );
30
+ // ponytail: skills@1.5.23 还没有公开的“只重绑 ref”命令;只改它自己的 source ref,target 更新仍完全交给官方 updater。
31
+ const lockPath = process.env.XDG_STATE_HOME
32
+ ? join(process.env.XDG_STATE_HOME, "skills", ".skill-lock.json")
33
+ : join(homedir(), ".agents", ".skill-lock.json");
34
+
35
+ let rawLock;
36
+ try {
37
+ rawLock = await readFile(lockPath, "utf8");
38
+ } catch {
39
+ return;
40
+ }
41
+
42
+ const lock = JSON.parse(rawLock);
43
+ const entry = lock.skills?.[skillName];
44
+ if (
45
+ !entry ||
46
+ entry.sourceType !== "github" ||
47
+ (entry.source !== source && entry.sourceUrl !== sourceURL)
48
+ ) {
49
+ return;
50
+ }
51
+
52
+ const targetRef = `v${packageJSON.version}`;
53
+ if (entry.ref !== targetRef) {
54
+ const mode = (await stat(lockPath)).mode & 0o777;
55
+ const temporary = `${lockPath}.${process.pid}.tmp`;
56
+ entry.ref = targetRef;
57
+ await writeFile(temporary, `${JSON.stringify(lock, null, 2)}\n`, { mode });
58
+ await rename(temporary, lockPath);
59
+ }
60
+
61
+ const code = await runUpdater();
62
+ if (code !== 0) {
63
+ console.warn(
64
+ `applebookscli: Skill update to ${targetRef} did not complete; Agent Skills CLI can retry later.`,
65
+ );
66
+ }
67
+ }
68
+
69
+ try {
70
+ await main();
71
+ } catch (error) {
72
+ console.warn(
73
+ `applebookscli: optional Skill update skipped: ${error instanceof Error ? error.message : String(error)}`,
74
+ );
75
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@chiimagnus/applebookscli",
3
- "version": "0.1.5",
3
+ "version": "0.2.0",
4
4
  "description": "Native Apple Books CLI for macOS on Apple Silicon.",
5
5
  "license": "AGPL-3.0-only",
6
6
  "repository": {
@@ -17,16 +17,16 @@
17
17
  "cpu": [
18
18
  "arm64"
19
19
  ],
20
- "publishConfig": {
21
- "access": "public"
22
- },
23
20
  "bin": {
24
21
  "applebookscli": "bin/applebookscli"
25
22
  },
23
+ "scripts": {
24
+ "postinstall": "node libexec/applebookscli/sync-installed-skill.mjs"
25
+ },
26
26
  "files": [
27
27
  "bin/applebookscli",
28
28
  "libexec/applebookscli/applebookscli-pdf-worker",
29
- "share/applebookscli/skill/applebookscli/SKILL.md",
29
+ "libexec/applebookscli/sync-installed-skill.mjs",
30
30
  "LICENSE",
31
31
  "THIRD_PARTY_NOTICES.md",
32
32
  "ThirdPartyLicenses"
@@ -1,50 +0,0 @@
1
- ---
2
- name: applebookscli
3
- description: 通过 `applebookscli` 查询、定位、导出或受保护地修改 Apple Books 图书、阅读状态、EPUB/PDF、批注笔记与藏书,以及执行备份恢复或访问诊断时使用。
4
- ---
5
-
6
- # AppleBooksCLI
7
-
8
- 使用已安装的 `applebookscli` 作为 Apple Books 数据操作的唯一入口。用户询问自己的 Apple Books 数据时,实际查询后再回答,不用能力说明代替结果。
9
-
10
- ## 回答前先查阅
11
-
12
- CLI 自身是命令契约。需要确认命令、参数或枚举值时,优先读取当前帮助,不依赖记忆,也不在 Skill 中维护第二份命令手册:
13
-
14
- - `applebookscli --help`
15
- - `applebookscli <group> --help`
16
- - `applebookscli <group> <subcommand> --help`
17
-
18
- 使用完成目标所需的最窄命令;普通查询、写入和状态判断需要结构化结果时优先 `--json`。`export` 的 JSON 输出使用 `--format json`,不要把 operational `--json` 套到 export。`doctor` 只用于诊断请求,或实际出现 permission、unavailable、schema readiness 一类问题时。`--library-db`、`--annotations-db`、`--config` 只用于用户明确指定或 fixture/test,不作为故障 fallback。
19
-
20
- ## Identity
21
-
22
- 优先使用稳定 identity:book asset ID、annotation UUID、collection ID、backup handle。标题、作者和名称只是搜索条件;先 search/list,唯一匹配后再继续。不要静默选择多个候选中的第一项;local PK 只在没有稳定 identity 或用户明确指定时使用。
23
-
24
- 阅读状态以 `reading` 的 canonical 结果为准,不从进度百分比推断 finished/in-progress/unstarted。“最近打开”也不等于“当前正在前台阅读”;用户说“当前这本书”时优先复用已经唯一解析的上下文,若只能得到 recent 结果就按 recent 候选表述。
25
-
26
- ## Annotations
27
-
28
- 用户问“最新笔记”时,只在 `note` 非空的 annotation 中比较;“最新”默认按创建时间,“最近修改”按修改时间。不要把普通高亮误报成笔记。
29
-
30
- 展示一条具体 annotation 时,优先返回高亮文本、note、必要时间和 `appleBooksURL`。不要自行拼接 `ibooks://`,也不要为了生成 deep link 调用 `content locate`。只有用户需要高亮前后正文时才使用 `content context`。
31
-
32
- `annotations update-note` 的 `--note` 是**整段替换文本**。用户要求追加、补充或加评论时,先读取原 note,保留原文构造完整新 note,再用 exact UUID 和 `--json` 写回。`annotations delete` soft-delete 的是整条 annotation,不要用它代替“清空 note 文本”。
33
-
34
- ## 写入与恢复
35
-
36
- 只有用户明确要求修改 annotation、collection 或恢复备份时才执行写操作。CLI 的 guarded mutation rail 已负责安全备份、Books.app 生命周期、事务与 read-back;不要直接读写 Apple Books SQLite,也不要额外手工 quit/launch Books.app。
37
-
38
- `committed=true` 表示事务已经提交,不能因为后续 warning 自动重试;`changed=false` 是成功的幂等 no-op。出现 `read_back_failed`,或调用超时/中断导致结果未知时,先做最窄只读确认,再决定是否还需要写入。CLI 创建的 safety backup 默认保留。
39
-
40
- `backups list/restore` 只面向 library database;不要假定 annotation mutation 返回的 backup handle 可以交给这个恢复面。Restore 以返回的 `changed`、`status`、`verified` 为准;`restored_unverified` 表示恢复已经应用但验证失败,不能自动再 restore。
41
-
42
- ## EPUB、PDF 与导出
43
-
44
- EPUB 内容不可用时,只有需要解释原因才运行 `content status --json`;不要绕过 DRM/encryption,也不要主动触发下载。PDF 没有 exact book/path 时先用 `pdf list --json` 解析唯一 source;worker failure/timeout 与“成功读取但没有 highlights”是不同结果。
45
-
46
- 用户要求完整笔记归档时必须使用 `--complete-notes` 的 fail-closed 路径;完整性校验失败就停止并报告,不能降级为普通 export 后声称归档完整。普通导出遵守用户给定的输出与 overwrite 策略,不擅自覆盖已有文件。
47
-
48
- ## 返回结果
49
-
50
- 不要把 exit 0 当成用户目标已经完成;以实际返回数据证明结果,并区分 empty、not found、unavailable、degraded 和 warning。本地 mutation 成功也不等于已经同步到 iCloud;没有另一设备或其它端到端证据时,只确认本地 Apple Books 状态。