nx-sk 0.10.0 → 0.12.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/CHANGELOG.md +214 -0
- package/README.md +76 -20
- package/assets/nx-sk/SKILL.md +19 -5
- package/assets/nx-sk/references/00-design.md +2 -2
- package/assets/nx-sk/references/10-sections-entries.md +14 -4
- package/assets/nx-sk/references/20-secrets.md +5 -5
- package/assets/nx-sk/references/40-files.md +2 -2
- package/assets/nx-sk/references/50-deploy.md +129 -0
- package/assets/nx-sk/references/60-transfer.md +115 -0
- package/package.json +6 -2
- package/src/core/attachments.js +1 -1
- package/src/core/fields.js +117 -3
- package/src/core/mdimages.js +65 -0
- package/src/core/paths.js +4 -2
- package/src/core/securezip.js +72 -0
- package/src/core/store.js +4 -40
- package/src/core/zip.js +198 -0
- package/src/modules/entries/kvTable.jsx +1 -1
- package/src/modules/entries/service.js +53 -32
- package/src/modules/entries/view.jsx +294 -8
- package/src/modules/export/view.jsx +12 -151
- package/src/modules/files/index.js +2 -0
- package/src/modules/files/service.js +17 -13
- package/src/modules/files/view.jsx +27 -1
- package/src/modules/sections/index.js +3 -3
- package/src/modules/sections/service.js +41 -19
- package/src/modules/sections/view.jsx +129 -11
- package/src/modules/settings/service.js +29 -6
- package/src/modules/settings/view.jsx +18 -18
- package/src/modules/system/service.js +8 -3
- package/src/modules/transfer/index.js +113 -0
- package/src/modules/transfer/service.js +911 -0
- package/src/runtime/api.js +30 -0
- package/src/runtime/registry.js +2 -2
- package/src/web/frontend/App.jsx +25 -20
- package/src/web/frontend/activeView.js +42 -0
- package/src/web/frontend/api/files.js +22 -1
- package/src/web/frontend/api/zip.js +34 -0
- package/src/web/frontend/components/fieldEditor.jsx +321 -12
- package/src/web/frontend/components/lightbox.jsx +96 -0
- package/src/web/frontend/components/mdView.jsx +193 -0
- package/src/web/frontend/components/navModel.js +10 -0
- package/src/web/frontend/components/readableExport.jsx +159 -0
- package/src/web/frontend/components/transferPanel.jsx +494 -0
- package/src/web/frontend/components/ui.jsx +13 -7
- package/src/web/frontend/mdInline.js +185 -0
- package/src/web/frontend/mdSmart.js +164 -0
- package/src/web/frontend/mdSource.js +41 -0
- package/src/web/frontend/registry.js +1 -4
- package/src/web/frontend/store.jsx +17 -3
- package/src/web/frontend/styles.css +398 -0
- package/src/web/public/assets/files-DA6DHa6W.js +1 -0
- package/src/web/public/assets/{index-Ct3dc5ej.css → index-C0soQxz7.css} +1 -1
- package/src/web/public/assets/index-DyvN6UVw.js +41 -0
- package/src/web/public/assets/view-2fmPzM-r.js +38 -0
- package/src/web/public/assets/view-B20jmlM1.js +1 -0
- package/src/web/public/assets/view-BEKkVrl1.js +7 -0
- package/src/web/public/assets/view-BiFJZZ7R.js +1 -0
- package/src/web/public/assets/view-DkM8Ts0E.js +1 -0
- package/src/web/public/assets/zip-gQ69BVQr.js +1 -0
- package/src/web/public/index.html +2 -2
- package/assets/nx-sk/references/30-export-backup.md +0 -104
- package/src/modules/backup/index.js +0 -46
- package/src/modules/backup/service.js +0 -678
- package/src/modules/backup/view.jsx +0 -251
- package/src/web/public/assets/files-CKVPmP4G.js +0 -1
- package/src/web/public/assets/index-kQO8dtPe.js +0 -41
- package/src/web/public/assets/view-B42kcpAF.js +0 -5
- package/src/web/public/assets/view-BQ3gMKb_.js +0 -1
- package/src/web/public/assets/view-Bbkm0Bxx.js +0 -7
- package/src/web/public/assets/view-BhJ6-5dc.js +0 -1
- package/src/web/public/assets/view-D3M0DBhP.js +0 -7
- package/src/web/public/assets/view-Do8zYTlC.js +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,220 @@
|
|
|
2
2
|
|
|
3
3
|
本文件格式参考 [Keep a Changelog](https://keepachangelog.com/),中文正文。
|
|
4
4
|
|
|
5
|
+
## [Unreleased]
|
|
6
|
+
|
|
7
|
+
## [0.12.0] - 2026-10-18
|
|
8
|
+
|
|
9
|
+
> **BREAKING**:`nx-sk backup *` 命令与 `.nxskbak` 格式已移除。改用 `nx-sk transfer export` /
|
|
10
|
+
> `transfer import-new`。旧的 `.nxskbak` 文件不再可导入,请在本版发布前用 0.11.x 导出一份。
|
|
11
|
+
> 详见 [Removed](#removed)。
|
|
12
|
+
|
|
13
|
+
### Added
|
|
14
|
+
|
|
15
|
+
- **导出包可设口令加密**(按栏目 ZIP 与全局 bundle 都支持):导出选项里填口令(输两次),
|
|
16
|
+
下载的包整体 AES-256-GCM 加密。密钥由口令经 scrypt 派生,与密钥库同一套参数;
|
|
17
|
+
每次导出盐与 IV 都重新随机 —— 同一个包加密两次密文不同。
|
|
18
|
+
- 导入是同一个入口:自动识别加密包,**先问口令**再预览 —— 不会把「缺口令」
|
|
19
|
+
误报成「包坏了」。口令错 / 内容被改都在 GCM 认证阶段报错,不会解出垃圾。
|
|
20
|
+
- CLI:`--passphrase`,也认环境变量 `NX_SK_TRANSFER_PASSPHRASE`(命令行口令会进进程列表)。
|
|
21
|
+
- **导入预览列出冲突明细**:哪条撞上哪条(同 id / 同标题)、另存会变成什么标题
|
|
22
|
+
(选「另存」后实时显示 `→ 甲(导入)」)。单栏目与整库预览口径一致。
|
|
23
|
+
- **零依赖 ZIP 实现**(`src/core/zip.js`:store/deflate、CRC32、路径安全校验),
|
|
24
|
+
不引第三方压缩库就能产出合法的跨平台 ZIP。
|
|
25
|
+
- **图文(`md`)正文改用 markdown 组件渲染**(新增依赖 `react-markdown` + `remark-gfm` + `remark-breaks`,
|
|
26
|
+
新组件 `web/frontend/components/mdView.jsx`):标题、有序/无序列表、表格、代码块、引用、删除线、
|
|
27
|
+
裸网址自动链接都按标准 markdown 渲染。此前手写解析只认图片与链接,SOP 里的结构在预览里全是字面量。
|
|
28
|
+
- **待办可点**:`- [ ] 步骤` 在预览里就是勾选框,点一下写回正文的 `[x]`(`mdSource.toggleTaskAtLine`)。
|
|
29
|
+
按解析器给的**行号**定位,不是「第几个勾选框」——嵌套列表与有序列表都不会串行;
|
|
30
|
+
勾选状态只有正文一份,不另存,所以导出、CLI 读到的就是勾完的样子。
|
|
31
|
+
- **图片与链接的行为保持不变**:`` 仍走附件库 + 放大镜(`[说明](f_xxx)` 直接打开附件);
|
|
32
|
+
只放行 http(s) 与能查到的附件 id,其余按普通文字渲染,`javascript:` 不会被执行。
|
|
33
|
+
- **裸地址自动识别**(`web/frontend/mdSmart.js`,remark 插件,排在 gfm 之后):
|
|
34
|
+
`125.67.197.2:7443`、`10.0.0.1`、`localhost:7866` 渲染成虚下划线的「点击即复制」;
|
|
35
|
+
`qcloud.sicau.edu.cn/login`、`example.com:8080/a?b=1` 自动补 `http://` 后点击打开。
|
|
36
|
+
宁可严:TLD 黑名单(`config.json`、`README.md` 这类文件名不会被当成域名)、端口 1–65535 校验、
|
|
37
|
+
前面是字母/数字/`@`/`/`/`:` 时不算起点(不在已有 URL、邮箱、路径里再识别一次);
|
|
38
|
+
代码块与行内代码原样保留。工具栏统计同步区分「链接」与「IP」。
|
|
39
|
+
- **补掉解析器带进来的两个坑**:GFM 自动链接一直吃到空白,中文句子又不用空格,
|
|
40
|
+
`见 https://a.com。另见` 会被整段算进 href(点开 404)—— `cleanHttpUrl` / `linkTextParts`
|
|
41
|
+
按「解码后遇到中文标点即断」截断,断下来的标点回到正文;`remark-breaks` 把单个换行渲染成 `<br>`,
|
|
42
|
+
保住手写那版 `pre-wrap` 的「一行一步」手感,已有 SOP 不会挤成一整段。
|
|
43
|
+
- 统计与下方图库仍走 `mdInline.js`(只读解析,不参与渲染);新增 `tests/unit/md-source.test.mjs`,
|
|
44
|
+
`md-inline.test.mjs` 补了 URL 截断的用例。
|
|
45
|
+
|
|
46
|
+
### Changed
|
|
47
|
+
|
|
48
|
+
- **加密包改为「内部数据先加密,再套合法 ZIP」**:之前整个文件是密文,Windows 会报
|
|
49
|
+
「压缩(zipped)文件夹错误」。现在外层始终是标准 ZIP(内含 `payload.enc` + `README.txt`),
|
|
50
|
+
系统压缩工具能正常打开,只看到一个看不懂的文件;判定是否加密也只需看条目名,
|
|
51
|
+
不用嗅探 magic。旧 `NXSKENC1` 整文件密文**仍可导入**,只是不再产出。
|
|
52
|
+
- **去掉「打码 / 明文」二选,口令即保护**(BREAKING,flag 层):`--no-secrets` 移除。
|
|
53
|
+
要分享就设口令,不设口令的包自己收好。读取侧仍兼容 0.11.0 及更早的打码包
|
|
54
|
+
(遇到 `******` 跳过该字段并计数,不会把打码串当新密码存进去)。
|
|
55
|
+
- **「按栏目 / 整库备份」两个 tab 合并成一个面板**:栏目的全选就是整库导出,
|
|
56
|
+
「整库」按钮只是全选的快捷方式,产物与逐栏勾选是同一个包、同一套导入逻辑。
|
|
57
|
+
- **导出包支持 `--no-files`**:只带元数据不带附件原件,跨机传配置时省体积。
|
|
58
|
+
- **`transfer import-new` 自动识别包结构**:不用手动挑单栏目导入还是整库导入。
|
|
59
|
+
- **面板重排(UI)**:左右两栏(左 = 选内容 + 设口令,右 = 解密导入);
|
|
60
|
+
栏目横向 chips,**指针移上去自动展开该栏目条目**(点击/键盘同样可用,不只靠悬浮),
|
|
61
|
+
「整库 / 清空」预设;口令与「导出 ZIP」提到卡片头部常驻,条目再多也不用滚动找按钮。
|
|
62
|
+
chips 用原生 `<button>` + `aria-pressed`/`aria-expanded`,长标题省略号 + title 兜底。
|
|
63
|
+
- **附件中心分页**:面板每页 24 个,避免一次加载全部图片把浏览器撑爆;
|
|
64
|
+
CLI 默认仍全量返回。
|
|
65
|
+
|
|
66
|
+
### Fixed
|
|
67
|
+
|
|
68
|
+
- **头部导航的分组角标显示成了条目数之和**:「求职资料」分组只有 6 个栏目,角标却是 16 ——
|
|
69
|
+
那是组内所有栏目的条目数加总。角标紧挨组名,本该回答「这一坨里有多少个栏目」;
|
|
70
|
+
加总出来的数字看着像「这个分组本身是个栏目、底下挂着 16 条记录」,而展开后每行
|
|
71
|
+
又各有自己的条目数,既冗余又误导。现在显示**栏目数**,并给 button 补了
|
|
72
|
+
`title="求职资料:6 个栏目"`。平铺 tab 不变(它的角标本就是该栏目的条目数)。
|
|
73
|
+
- **`entryIds` 在路由层没透传**:服务层单测是绿的,但 ZIP 仍打全量。
|
|
74
|
+
修复后浏览器解包确认只含所选条目。
|
|
75
|
+
- **group 回落不一致**:多处各自兜底成不同栏目名,统一到一处。
|
|
76
|
+
- **阅读态下没有图片的 `md` 字段不再显示空的图片区**:纯文字字段(上线检查清单、常用链接)
|
|
77
|
+
底下会多出「图片(0)」和一句「正文里还没有图片」,纯噪音。现在只有正文真有图、
|
|
78
|
+
或正在编辑时才渲染那块;编辑态保留,因为它是「贴进来的图会出现在这里」的落点提示。
|
|
79
|
+
- **「另存」的标题在极端情况下会重复加「(导入)」**:`uniqueTitle` 的基准原本传的是
|
|
80
|
+
`标题(导入)`,二次重名会变成 `A(导入)(导入)`,与预览里算给用户看的 `copyTitle` 也对不上。
|
|
81
|
+
现在基准统一用原标题,预览与实际落盘一致。
|
|
82
|
+
- **空栏目被整库选中时,chip 的 `aria-pressed` 是 false**:选中态原先按条目数推导
|
|
83
|
+
(`!!n`),0 条目的栏目于是即使用户勾了也读成「未选」—— 读屏用户得到错误状态。
|
|
84
|
+
选中态现在与条目数无关。
|
|
85
|
+
|
|
86
|
+
### Removed
|
|
87
|
+
|
|
88
|
+
- **备份模块整体删除**(BREAKING):`nx-sk backup *` 命令、`.nxskbak` 格式、
|
|
89
|
+
`src/modules/backup/` 与 `references/30-export-backup.md` 全部移除。
|
|
90
|
+
有文件导出就够了,本地快照备份是重复的第二套回退机制,而且两边口径必然漂移。
|
|
91
|
+
- 删条目 / 栏目 / 附件**不再留快照** —— 改为「先导出再删」,`transfer export`
|
|
92
|
+
出来的包就是唯一回退手段。
|
|
93
|
+
- 跨机敏感字段的重新加密逻辑迁到 `transfer`:导入后用**本机 vaultKey** 重加密落盘,
|
|
94
|
+
与手填字段没有区别。
|
|
95
|
+
- 面板里可读的 JSON / Markdown 导出移到**设置**页(人读副本,不参与导入)。
|
|
96
|
+
- 导航名由「导出与备份」改为「导出导入」;旧书签 `#/backup` 自动落到「设置」。
|
|
97
|
+
- 旧命令 `nx-sk backup export|import` 报「未知命令」,请改用 `transfer export` /
|
|
98
|
+
`transfer import-new`(旧 `.nxskbak` 文件不再可导入)。
|
|
99
|
+
|
|
100
|
+
## [0.11.0] - 2026-10-18
|
|
101
|
+
|
|
102
|
+
### Added
|
|
103
|
+
|
|
104
|
+
- **栏目导出 / 导入 ZIP(局部迁移)**:栏目页右上角「更多」里有四项 ——
|
|
105
|
+
导出 ZIP(含凭据)、导出 ZIP(打码)、导入 ZIP…、导出 JSON/Markdown。
|
|
106
|
+
导入支持**整页拖入**,先出预览(来源/目标栏目、条目新增与冲突、将补字段、附件新增/复用、
|
|
107
|
+
凭据是否打码),再选冲突策略(跳过 / 另存 / 覆盖)确认后才写盘。
|
|
108
|
+
- 包结构:`manifest.json`(栏目定义 + 条目 + 附件清单 sha256)+ `attachments/<id><ext>` + `README.txt`;
|
|
109
|
+
纯 Node 实现 ZIP 读写(store/deflate),零依赖,拒绝绝对路径与 `..`。
|
|
110
|
+
- 附件按 sha256 **去重复用**;正文 / 附件字段里的旧 file id 自动重映射到新 id。
|
|
111
|
+
- 导出的凭据默认明文(与 export 模块一致);`--no-secrets` 打码,导入侧识别 `******` 并跳过该字段,
|
|
112
|
+
不会把打码串当新密码存进去。
|
|
113
|
+
- CLI:`nx-sk transfer export <栏目> --out x.zip [--no-secrets]`、
|
|
114
|
+
`nx-sk transfer import <栏目> --file x.zip [--dry-run] [--on-conflict skip|copy|overwrite]`。
|
|
115
|
+
- HTTP:`GET /api/sections/:ref/export.zip`、`POST /api/sections/:ref/import.zip`(原始二进制 body,
|
|
116
|
+
不走 base64/JSON,避免大包膨胀 1/3 与 32MB 上限)。
|
|
117
|
+
- **精确导出**:条目列表可勾选(表头全选 / 清空),选中后只打包这些条目与**它们引用到的附件**;
|
|
118
|
+
`--entries` 接受 id 或标题(逗号分隔)。
|
|
119
|
+
- **零配置导入**:`POST /api/import.zip`(栏目页「导入 ZIP」/ 拖入)按包内结构**新建栏目** ——
|
|
120
|
+
字段字典、分组、KV 标记、附件一起建好;id 冲突自动加序号、标题加「(导入)」,
|
|
121
|
+
同一份包可反复导入成多份,不会静默并进现有栏目。
|
|
122
|
+
|
|
123
|
+
- **统一的全局导出 / 导入面板**:「导出与备份」页顶部是栏目树(栏目/条目多选、全选/清空),
|
|
124
|
+
导出为一个多栏目 bundle(`bundle.json` + 每栏目同构 `sections/<id>.zip`);
|
|
125
|
+
下方拖入/点击选择 ZIP,先预览将产生的变更(栏目、条目新增/冲突、补字段、附件新增/复用、凭据),
|
|
126
|
+
再选冲突策略应用。全局导入逐栏目复用单栏目逻辑,行为与栏目页一致。
|
|
127
|
+
CLI:`transfer bundle-export --sections ...`、`transfer bundle-import --file ...`。
|
|
128
|
+
- **附件中心分页**:`GET /api/files` 支持 `limit` / `offset` 并返回 `page` 信息;面板每页 24 个,
|
|
129
|
+
避免一次性把整库图片加载进浏览器导致 OOM;CLI 不传 limit 时仍是全量(行为不变)。
|
|
130
|
+
|
|
131
|
+
- **新字段类型 `md`(图文)**:值是一段 markdown 正文,可用 `` 引用附件库里的图片 ——
|
|
132
|
+
为「说明 + 截屏」混排的内容(部署 SOP、报错复现步骤)准备的。
|
|
133
|
+
- 编辑器(`fieldEditor.jsx`):**Ctrl+V 直接粘截图** / 拖图片进来 / 选文件 / 从附件库插入,
|
|
134
|
+
都会先上传到附件库,再把 `` 插到**光标处**;批量先收齐再一次性插入,
|
|
135
|
+
避免连续插入跟光标位置打架。纯文字粘贴不拦截,仍走浏览器默认行为。
|
|
136
|
+
- **图片统一下方成组**:正文里引用到的图片去重列成缩略图,点击开大图 —— 滚轮缩放、
|
|
137
|
+
拖动平移、双击或「适应」复位、Esc 关闭(新增 `components/lightbox.jsx`)。
|
|
138
|
+
截屏里的一行小字因此看得清,又不必跳到新标签页丢掉上下文。
|
|
139
|
+
- 正文下方就地预览(图片内联渲染),贴完立刻能确认是不是要的那张。
|
|
140
|
+
- **正文里的 http(s) 链接在预览里可直接点开**(新标签页):裸网址与 `[文字](https://…)` 都识别。
|
|
141
|
+
网址尾巴上的中文标点(`。`、`)`)会留在正文里不被吞进 href,括号按成对判断 ——
|
|
142
|
+
维基式 `…/Foo_(bar)` 不会被截断。只认 http/https:`www.`、`ftp://`、文件路径一律按原文,
|
|
143
|
+
否则文件名和包名会满屏变成可点链接。解析抽到 `web/frontend/mdInline.js`(纯函数,有单测),
|
|
144
|
+
图片与链接共用一次扫描,`` 不会再被拆成「图片缺失 + 一条网址」。
|
|
145
|
+
- **外链图片 `` 直接显示**(不进附件库、需要联网),CLI 侧输出
|
|
146
|
+
「[外链图片: 说明] 地址」而不是误报「图片缺失」——误报会让人以为附件被删了又重传一遍。
|
|
147
|
+
- 图片走附件库(`~/nx-sk/files/`),同内容去重;正文里只留 id,所以这段文字导出成 md、
|
|
148
|
+
贴进仓库 README 都能直接渲染(标准 markdown,不是自家方言)。
|
|
149
|
+
- 读侧:`entry get` 把 `` 还原成「[图片: 说明] 本地路径」,并把内嵌图片一并放进
|
|
150
|
+
返回的 `files` 表 —— 否则 CLI / agent 只能拿到一串 `f_xxx`。为此 `getEntry` 多回一个
|
|
151
|
+
`fieldTypes`(键 → 类型),渲染据此决定要不要做这层还原。
|
|
152
|
+
- 面板的类型下拉框改为「中文名(id)」,如「图文(可贴图)(md)」——此前只显示内部 id。
|
|
153
|
+
- **`deploy` 模板同时新增 `sop` 字段**(`md` 类型,`fill: optional`):部署资源的「操作步骤(图文)」。
|
|
154
|
+
已建的 `deploy` 栏目不会自动回溯,用 `nx-sk section sync deploy` 补上(只增不改);
|
|
155
|
+
`references/50-deploy.md` 同步补了「写操作步骤」一节(含「截屏里有 token 先打码」)。
|
|
156
|
+
|
|
157
|
+
- **新栏目模板 `deploy`(部署配置)**:把 Dockerfile / docker-compose / k8s 清单存成**可复用资源**。
|
|
158
|
+
一份文件一个条目 —— `content`(文件原文)+ `path`(建议落盘路径)+ `vars`(复用前要替换的变量)
|
|
159
|
+
+ `usage`(何时用、坑在哪)+ `kind` / `stack` / `tags` / `files`。
|
|
160
|
+
只有正文、没有后三项的配置是「没有上下文的 YAML」,下次没法照着用,所以它们不是可选装饰。
|
|
161
|
+
首次运行随其余 5 个模板一起播种(内置模板共 6 个);**已有 store 不会自动回溯**,用
|
|
162
|
+
`nx-sk section add deploy --template deploy` 补上。
|
|
163
|
+
- 约定:`content` 里**只写 `${VAR}` 占位**,真值放「密钥」栏目(密文落盘)。
|
|
164
|
+
配置文件是最容易被整份复制粘贴分享的东西(发同事 / 贴 issue / 进聊天记录),
|
|
165
|
+
两者混在一起等于给凭据开了一条最宽的出口。这条写进字段 hint 和 `references/50-deploy.md`。
|
|
166
|
+
- 新增 ref 文档 `50-deploy`:为什么单开一个栏目(vs 附件库 / git)、`kind` 取值约定、
|
|
167
|
+
复用四步(找 → 取正文 → 替换变量 → 落盘)、什么时候不该放这里。SKILL.md 的 ref 路由表已登记。
|
|
168
|
+
|
|
169
|
+
### Fixed
|
|
170
|
+
|
|
171
|
+
- **正文预览整篇「图片缺失」,下方图库却正常**:图片 token 只带 `src`,而渲染层按 `id`
|
|
172
|
+
去附件表里查记录 —— 查表键成了 `undefined`,于是每张图都判定为「不存在」。
|
|
173
|
+
图库走的是 `imageRefs`(输出 `id`),所以缩略图反而全都正常,形成「下面 18 张都在、
|
|
174
|
+
正文说一张都没有」的怪象。现在 token 同时带 `id` / `src`,`recordOf` 两个都认,
|
|
175
|
+
并用真实浏览器验证:`imgs=18 / missing=0 / thumbs=18`,另加 token 形状的回归测试。
|
|
176
|
+
- **CLI / 另一个标签页导入的附件,面板里整篇显示「图片缺失」**:附件列表缓存没有失效时机,
|
|
177
|
+
页面一直按进入时那份渲染。整份 SOP 的 18 张图是 CLI 导入的,因此正文全部报缺失
|
|
178
|
+
(附件中心却能看到)。现在缓存加了 1.5s TTL,且图文字段 / 附件字段在挂载时**强制刷新一次**;
|
|
179
|
+
图片还没拉回来时显示「正在加载图片…」,不再把「未加载」误报成「不存在」。
|
|
180
|
+
- **「不填」提示把已填值的可选字段也算进去**:`excluded` 是**策略标记**(`fill: optional/avoid`),
|
|
181
|
+
不代表字段空着。于是「容器平台」这种把可选字段也填满的条目,会被报成「另有 7 项已标不填」,
|
|
182
|
+
与事实相反。现在 CLI(`entry list` / `entry get`)与面板都只列**真的空着**的可选字段。
|
|
183
|
+
- **图文字段刚粘贴的图不显示预览,一直显示「图片缺失」**:附件列表带缓存,上传成功后
|
|
184
|
+
`listAttachments()` 返回的仍是进入页面时那份,新 id 不在表里;而预览是按 id 查表渲染的,
|
|
185
|
+
于是图明明已经进了附件中心,字段里却查不到。现在上传后先把返回的记录**就地并进列表**
|
|
186
|
+
(`mergeFiles`,按 id 去重)再强制刷新服务端台账 —— 预览不再依赖列表是否刷新过。
|
|
187
|
+
另外「图片缺失」的悬停提示写清了原因:指向的附件可能已在附件中心被删除,重新粘贴会得到新 id。
|
|
188
|
+
|
|
189
|
+
- **`entry get` 按行渲染多行正文**:此前 `[String(v)]` 把整段塞进第一行,只有首行带键名列宽,
|
|
190
|
+
后面每一行都从第 0 列开始 —— 一段 40 行的清单打印出来像「掉出了表格」,人眼没法对。
|
|
191
|
+
现在续行统一缩进到内容列(对长 YAML / Dockerfile 尤其明显)。
|
|
192
|
+
- **`settings.defaultSection` 不再是死配置**。此前它只是被落盘,**没有任何读取方**:
|
|
193
|
+
面板初始 tab 来自 `DEFAULT_UI.view = 'job'`(写死),CLI 也不读它 ——
|
|
194
|
+
于是「默认栏目」改完毫无反应,删掉 `job` 栏目还会让首屏停在一个不存在的 id 上。
|
|
195
|
+
- 面板当前 tab 的解析规则抽成纯函数 `src/web/frontend/activeView.js`:
|
|
196
|
+
**地址栏深链 → 本次选择 → `settings.defaultSection` → 第一个 tab**,
|
|
197
|
+
并由 `tests/unit/active-view.test.mjs` 覆盖两条最容易回归的分支
|
|
198
|
+
(boot 之前不许兜底,否则深链被第一个工具页顶掉;默认栏目指向已删栏目要优雅降级)。
|
|
199
|
+
- 当前 tab 不再写 localStorage:它归地址栏管。两个记忆源并存时,
|
|
200
|
+
落盘的那个会永远压住默认栏目,这正是「改了设置看不到效果」的来源。
|
|
201
|
+
- 写入 `defaultSection` 时校验栏目真实存在(写标题也认,归一成 id),
|
|
202
|
+
失败会列出可选项而不是静默存一个永远不生效的值;设置页改成下拉选择,不再手打 id。
|
|
203
|
+
`setting get` 仍然列出这一项(带校验器的标量项,不是「结构化项」)。
|
|
204
|
+
- **`section sync` 会报告「模板漂移」**:同名字段在「栏目 vs 模板」之间哪些属性不同
|
|
205
|
+
(label / type / group / hint / options / maxItems / sensitive / fill),`--dry-run` 也报。
|
|
206
|
+
仍然**只增不改** —— 定义归栏目,你可能就是刻意改过的;提示里给出真正能跟进的命令
|
|
207
|
+
(`--fields` 整份替换,或先 `--remove-field` 再 `--add-field`)。
|
|
208
|
+
`upToDate` 仍只看「有没有可补的」,否则改过一个标签就会永远报「不是最新」。
|
|
209
|
+
|
|
210
|
+
### Changed
|
|
211
|
+
|
|
212
|
+
- **字段类型清单单一来源**:`bootstrap` 下发 `fieldTypes`,面板「新增字段」的类型下拉框据此渲染。
|
|
213
|
+
此前 `modules/sections/view.jsx` 自己抄了一份 10 项清单 —— 后端加一种类型时下拉框永远看不到它。
|
|
214
|
+
- **文案修正**:内置模板是 **6 个**(`job` / `secret` / `projects` / `internships` / `campus` / `deploy`),
|
|
215
|
+
而 `section templates` / `section add` 的摘要与 `--template` 的提示一直只写「求职 / 密钥」,
|
|
216
|
+
会把人引向「只有两个模板」的误解。README 与 `assets/nx-sk/SKILL.md` 的栏目表同步补齐,
|
|
217
|
+
并说明「这 6 个是首次运行播种的默认值,不是固定清单」。
|
|
218
|
+
|
|
5
219
|
## [0.10.0] - 2026-10-15
|
|
6
220
|
|
|
7
221
|
### Added
|
package/README.md
CHANGED
|
@@ -74,6 +74,23 @@ ln -s "$(pwd)/assets/nx-sk" "$HOME/.workbuddy/skills/nx-sk"
|
|
|
74
74
|
> nx-sk skill install --force # 改了 assets/nx-sk/ 之后必须重装,否则是旧版
|
|
75
75
|
> nx-sk skill get nx-sk --json # 外部 agent 一键拿全上下文(四元:skillName/ref/content/contentBytes/install)
|
|
76
76
|
|
|
77
|
+
## 从 0.11.x 升级
|
|
78
|
+
|
|
79
|
+
**0.12.0 有不兼容变更:备份模块已删除。**
|
|
80
|
+
|
|
81
|
+
| 原来 | 现在 |
|
|
82
|
+
| --- | --- |
|
|
83
|
+
| `nx-sk backup export --password 口令` | `nx-sk transfer export <栏目> --passphrase 口令 --out x.zip` |
|
|
84
|
+
| `nx-sk backup import --file x.nxskbak` | `nx-sk transfer import-new --file x.zip` |
|
|
85
|
+
| 面板「导出与备份」 | 面板「导出导入」(栏目全选即整库) |
|
|
86
|
+
|
|
87
|
+
- **旧的 `.nxskbak` 文件不再可导入。** 升级前请先在 0.11.x 下导出一份
|
|
88
|
+
(`nx-sk transfer bundle-export --out x.zip`),升级后用 `transfer import-new --file x.zip` 导回。
|
|
89
|
+
- 破坏性删除(删栏目 / 条目 / 附件)**不再自动留快照** —— 删之前先导一份。
|
|
90
|
+
- `transfer export --no-secrets` 移除:包里恒为明文,保护只靠 `--passphrase`。
|
|
91
|
+
- 加密包格式变了(外层是合法 ZIP、内含 `payload.enc`),旧包仍可导入;
|
|
92
|
+
但 Windows 上不再报「压缩文件夹错误」了。
|
|
93
|
+
|
|
77
94
|
## 它是什么
|
|
78
95
|
|
|
79
96
|
一个「本机工具类」项目的标准骨架实现(server-cli-web):**serve 驱动 CLI 与 Web,
|
|
@@ -82,9 +99,17 @@ CLI 与 API 同源,skill 驱动 agent**。落到具体功能上:
|
|
|
82
99
|
| 栏目 | id | 内容 |
|
|
83
100
|
| --- | --- | --- |
|
|
84
101
|
| 求职 | `job` | 求职用的个人信息档案:9 个分组 / 75 个字段(姓名、学历、联系方式、求职意向、紧急联系人…)。模板只是**建议清单**,`--set 任意键=值` 直接写 |
|
|
102
|
+
| 项目经历 | `projects` | 一个项目一个条目:名称 / 角色 / 时间 / 技术栈 / 职责与亮点 |
|
|
103
|
+
| 实习/工作经历 | `internships` | 一段经历一个条目:公司 / 岗位 / 时间 / 职责 |
|
|
104
|
+
| 校内职务/实践 | `campus` | 一条职务或实践一个条目:职务 / 组织 / 时间 / 职责 |
|
|
85
105
|
| 密钥 | `secret` | **一张 KV 表**(`kv: true`):面板上就是两列表格(名称 / 值),一行一个键。落盘是 **AES-256-GCM** 密文,读出来默认是原文(`--mask` 才打码) |
|
|
106
|
+
| 部署配置 | `deploy` | **一份配置文件一个条目**(Dockerfile / docker-compose / k8s 清单):正文即文件原文,外加「放哪 / 哪些值要替换 / 何时用」,好让它在别的项目里照着用 |
|
|
86
107
|
|
|
87
|
-
|
|
108
|
+
上表是**首次运行从 6 个内置模板播种出来的默认值,不是固定清单**:栏目不是写死的——
|
|
109
|
+
字段字典是**数据**,加字段(`section update --add-field`,或 `entry update --set 任意键=值` 自动登记)、
|
|
110
|
+
加栏目(`section add`,不给模板就是空栏目全自定义)、删栏目都不用改代码。
|
|
111
|
+
模板在实例化时被**深拷贝**,此后各栏目独立演化;模板后来的新增用 `section sync` 补(只增不改不删,
|
|
112
|
+
有差异时会把「模板已改、栏目保留原值」的字段列出来提示)。
|
|
88
113
|
|
|
89
114
|
## 三条核心不变量
|
|
90
115
|
|
|
@@ -112,7 +137,7 @@ CLI 与 API 同源,skill 驱动 agent**。落到具体功能上:
|
|
|
112
137
|
| `nx-sk routes [--module M] [--http "POST /api/entries"]` | 命令 ↔ 路由双向对照 |
|
|
113
138
|
| `nx-sk section list \| get \| add \| update \| remove` | 栏目 CRUD |
|
|
114
139
|
| `nx-sk section dump <id> [--mask]` | **一个栏目的全部信息**:字段台账 + 全部条目 + 每个条目的未填清单 |
|
|
115
|
-
| `nx-sk section templates` | 内置模板(job / secret) |
|
|
140
|
+
| `nx-sk section templates` | 内置模板(job / secret / projects / internships / campus / deploy) |
|
|
116
141
|
| `nx-sk section sync <id> [--dry-run]` | 按模板**补齐**本栏目缺的分组与字段(只增不改不删)——模板演进后让老栏目追上 |
|
|
117
142
|
| `nx-sk entry list \| get \| add \| update \| remove` | 条目 CRUD(PATCH 语义) |
|
|
118
143
|
| `nx-sk entry fields [--section job]` | 字段字典 —— 填之前先看这个,别猜字段名 |
|
|
@@ -124,8 +149,12 @@ CLI 与 API 同源,skill 驱动 agent**。落到具体功能上:
|
|
|
124
149
|
| `nx-sk file open <id>` | 用系统默认程序打开原件 |
|
|
125
150
|
| `nx-sk export run [--format json\|md\|both] [--section id] [--with-secrets] [--out DIR] [--dry-run]` | 整体导出 |
|
|
126
151
|
| `nx-sk export list` | 历次导出与目录内文件 |
|
|
127
|
-
| `nx-sk
|
|
128
|
-
| `nx-sk
|
|
152
|
+
| `nx-sk transfer export <栏目> [--entries 条目,条目] [--passphrase 口令] [--out 文件]` | 栏目/选中条目 + 引用附件打成 ZIP,可设口令加密(栏目页「更多」里同源下载) |
|
|
153
|
+
| `nx-sk transfer import <栏目> [--file ZIP] [--on-conflict skip\|copy\|overwrite] [--dry-run]` | 预览/导入到指定栏目;附件按 sha256 复用 |
|
|
154
|
+
| `nx-sk transfer import-new [--file ZIP] [--dry-run]` | **零配置**:按包内结构新建栏目(id 冲突加序号) |
|
|
155
|
+
| `nx-sk transfer bundle-export [--sections 栏目,栏目] [--passphrase 口令] [--no-files] [--out 文件]` | 多栏目/整库打包成 ZIP(`bundle.json + sections/<id>.zip`),可设口令加密 |
|
|
156
|
+
| `nx-sk transfer bundle-import [--file ZIP] [--on-conflict skip\|copy\|overwrite] [--dry-run]` | 整库包解密导入;缺省「合并」只增补不覆盖 |
|
|
157
|
+
| `nx-sk transfer import-new [--file ZIP] [--dry-run]` | **零配置**:自动识别单栏目包 / 整库包,按包内结构新建(id 冲突加序号) |
|
|
129
158
|
| `nx-sk setting get \| set` | 全局设置 |
|
|
130
159
|
| `nx-sk skill list \| install \| get` | 把内置 skill 装给 agent / 给外部 agent 取上下文 |
|
|
131
160
|
|
|
@@ -211,31 +240,58 @@ nx-sk setting set --set 'navGroups=[]' # 清空 = 全部栏目恢复平铺
|
|
|
211
240
|
|
|
212
241
|
分组只是**显示配置**(存在 `settings.navGroups`):不动栏目与条目的数据,删掉栏目时头部自动略过。
|
|
213
242
|
|
|
214
|
-
|
|
243
|
+
整体导出(落到本机目录的**人可读副本**,凭据默认含明文):
|
|
215
244
|
|
|
216
245
|
```bash
|
|
217
246
|
nx-sk export run --format both --out D:/备份/nx-sk
|
|
218
247
|
nx-sk export list
|
|
219
248
|
```
|
|
220
249
|
|
|
221
|
-
|
|
250
|
+
### 全局导出 / 导入(多栏目)
|
|
251
|
+
|
|
252
|
+
**项目里只有一个导出导入模块,没有独立的「备份」模块。** 导出的包就是唯一回退手段:
|
|
253
|
+
删栏目 / 条目 / 附件之前先导一份。
|
|
254
|
+
|
|
255
|
+
「导出导入」页顶部:栏目横向排成 chips,悬浮或点击展开条目可逐条勾选;
|
|
256
|
+
顶部「整库」按钮 = 所有栏目全选。选好内容 → 输两次口令(可留空)→「导出 ZIP」浏览器直接下载。
|
|
257
|
+
把 ZIP 拖进右侧框即预览(栏目、条目新增/冲突、附件新增/复用),选冲突策略后确认。
|
|
258
|
+
|
|
259
|
+
口令用**对称加密(AES-256-GCM)**:实现是「内部数据先加密,再套一层合法 ZIP」,
|
|
260
|
+
所以外层始终能正常打开(只看到一个 `payload.enc`),不会报「文件夹无效」;
|
|
261
|
+
缺口令时明确提示要口令,不会误报成坏包。
|
|
262
|
+
|
|
263
|
+
整库包结构 `bundle.json + sections/<id>.zip`,与单栏目包同构;导入时逐栏目复用同一套逻辑。
|
|
264
|
+
|
|
265
|
+
```bash
|
|
266
|
+
nx-sk transfer bundle-export --sections job,projects --out all.zip
|
|
267
|
+
nx-sk transfer bundle-import --file all.zip --dry-run
|
|
268
|
+
nx-sk transfer bundle-import --file all.zip --on-conflict copy
|
|
269
|
+
nx-sk transfer import-new --file all.zip # 零配置:自动识别单栏目包 / 整库包
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
### 只搬一个栏目:ZIP 导出 / 导入
|
|
273
|
+
|
|
274
|
+
栏目也可以单独打包(含条目、栏目定义、实际引用到的附件):
|
|
222
275
|
|
|
223
276
|
```bash
|
|
224
|
-
nx-sk
|
|
225
|
-
nx-sk
|
|
226
|
-
nx-sk
|
|
227
|
-
nx-sk
|
|
228
|
-
nx-sk
|
|
229
|
-
|
|
277
|
+
nx-sk transfer export deploy --out D:/tmp/deploy.zip # 含凭据明文
|
|
278
|
+
nx-sk transfer export deploy --passphrase 口令 --out D:/tmp/share.zip # 设口令再给别人
|
|
279
|
+
nx-sk transfer export deploy --entries "k8s-deployment,compose" --out D:/tmp/part.zip # 只导选中条目
|
|
280
|
+
nx-sk transfer bundle-export --sections job,deploy --passphrase 口令 --out D:/tmp/enc.zip # 整包加密
|
|
281
|
+
nx-sk transfer import deploy2 --file D:/tmp/deploy.zip --dry-run # 先预览:新增/冲突/补字段/附件
|
|
282
|
+
nx-sk transfer import deploy2 --file D:/tmp/deploy.zip # 栏目不存在就新建
|
|
283
|
+
nx-sk transfer import deploy2 --file D:/tmp/deploy.zip --on-conflict copy # 另存
|
|
284
|
+
nx-sk transfer import deploy2 --file D:/tmp/deploy.zip --on-conflict overwrite # 覆盖字段
|
|
285
|
+
nx-sk transfer import-new --file D:/tmp/deploy.zip # 零配置:按包内结构新建
|
|
230
286
|
```
|
|
231
287
|
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
288
|
+
面板里是栏目页右上角「更多」:导出 ZIP、导入 ZIP…;
|
|
289
|
+
条目列表可勾选(表头全选/清空),选中后导出**只带这些条目及其附件**。
|
|
290
|
+
把 zip **拖到栏目页任意位置**会导入当前栏目;拖到「栏目」tab 则**零配置新建一个栏目**。
|
|
291
|
+
预览会显示来源栏目、目标栏目、条目冲突、将补的字段、附件新增/复用与凭据是否打码,
|
|
292
|
+
选好冲突策略再确认。
|
|
236
293
|
|
|
237
|
-
|
|
238
|
-
导入选择文件并输入口令、报告以弹窗呈现;口令错误或文件损坏会明确报错、不改动当前数据。
|
|
294
|
+
附件按 sha256 去重(本机已有就复用);`file` 字段与 `md` 图文里的旧 id 会自动重映射。
|
|
239
295
|
|
|
240
296
|
## 数据与安全
|
|
241
297
|
|
|
@@ -244,10 +300,10 @@ Web 面板的「导出与备份」页同样支持:导出在浏览器下载 `.n
|
|
|
244
300
|
| 数据目录 | `~/nx-sk/`,可用 `NX_SK_HOME` 覆盖 |
|
|
245
301
|
| 状态文件 | `~/nx-sk/store.json`,可用 `NX_SK_STORE` 覆盖;**原子写**(临时文件 + rename) |
|
|
246
302
|
| 密文密钥 | 环境变量 `NX_SK_PASSPHRASE`(scrypt 派生 + 盐)优先,否则 `~/nx-sk/.vaultkey`(32 字节随机,0600) |
|
|
247
|
-
|
|
|
303
|
+
| 迁移 | 破坏性删除**不留本地快照**:先 `nx-sk transfer export` 导一份,导出的包就是唯一回退手段 |
|
|
248
304
|
| 导出 | `~/nx-sk/export/`,默认不含凭据明文 |
|
|
249
305
|
| 附件 | `~/nx-sk/files/` 存二进制原件,元数据在 `store.json` 的 `files`(sha256 去重;条目 `file` 字段存附件 id 即建立链接;`file restore` 可逆) |
|
|
250
|
-
|
|
|
306
|
+
| 加密导出 | `transfer` 的 `--passphrase`:内部数据经 scrypt(口令)+AES-256-GCM 加密成 `payload.enc`,再套一层**合法 ZIP**(外层能正常打开,不会报「文件夹无效」);口令不落盘,导入时缺口令明确提示 |
|
|
251
307
|
| 服务绑定 | 默认 `127.0.0.1`,不暴露到局域网;写操作校验 `Origin` |
|
|
252
308
|
| 数据损坏 | `store.json` 解析失败会先被改名为 `.corrupt-<时间戳>.json`,不会静默覆盖 |
|
|
253
309
|
|
package/assets/nx-sk/SKILL.md
CHANGED
|
@@ -1,18 +1,28 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: nx-sk
|
|
3
|
-
description:
|
|
3
|
+
description: 本机个人资源管理器——栏目化存储个人信息(求职档案等)、大模型 API Key、以及可复用的 Dockerfile / docker-compose / k8s 清单,CLI 与 Web 面板同源,敏感字段密文落盘。当用户要"记录/更新我的个人信息"、"填一份求职档案"、"存一个大模型 key"、"管理我的密钥"、"存一份 Dockerfile / compose / k8s 配置"、"找一份可复用的部署配置"、"导出我的资料"、"起一个个人资料面板",或需要在填表单/网申时批量取用个人字段、用 CLI 快速设置某个栏目内容时使用。触发词:nx-sk、个人资源管理器、个人信息、求职档案、栏目、条目、密钥、API key、密文、导出、面板、serve、部署配置、Dockerfile、docker-compose、k8s 清单。不适用:纯问答、不需要落盘的临时讨论;也不适用于把密钥同步/上传到远程服务的场景——nx-sk 只在本机落盘,不做任何上传。
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# nx-sk · 本机个人资源管理器
|
|
7
7
|
|
|
8
8
|
一句话:**把「你的信息」按栏目存起来,CLI 与 Web 面板是同一套业务,敏感字段密文落盘。**
|
|
9
9
|
|
|
10
|
-
数据落在 `~/nx-sk/`(可用环境变量 `NX_SK_HOME` / `NX_SK_STORE`
|
|
10
|
+
数据落在 `~/nx-sk/`(可用环境变量 `NX_SK_HOME` / `NX_SK_STORE` 覆盖)。首次运行按内置模板播种 6 个栏目:
|
|
11
11
|
|
|
12
12
|
| 栏目 | id | 内容 |
|
|
13
13
|
| --- | --- | --- |
|
|
14
14
|
| 求职 | `job` | 求职用的个人信息档案(姓名/学历/求职意向/简历头像成绩单附件…约 80 个字段) |
|
|
15
|
+
| 项目经历 | `projects` | 一个项目一个条目:名称 / 角色 / 时间 / 技术栈 / 职责与亮点 |
|
|
16
|
+
| 实习/工作经历 | `internships` | 一段经历一个条目:公司 / 岗位 / 时间 / 职责 |
|
|
17
|
+
| 校内职务/实践 | `campus` | 一条职务或实践一个条目 |
|
|
15
18
|
| 密钥 | `secret` | **一张 KV 表**(`kv: true`):一行一个键值对。面板渲染成表格,值以 AES-256-GCM 密文落盘 |
|
|
19
|
+
| 部署配置 | `deploy` | **一份配置文件一个条目**(Dockerfile / compose / k8s 清单):正文即文件原文 + 放哪 + 哪些值要替换 + 何时用。详见 [[50-deploy]] |
|
|
20
|
+
|
|
21
|
+
**这 6 个只是起点,不是固定清单**:栏目可以新建(`section add`,不给模板就是空栏目全自定义)、
|
|
22
|
+
可以加/删字段(`section update --add-field`,或直接 `entry update --set 任意键=值` 自动登记)、
|
|
23
|
+
也可以删掉整个栏目。内置模板共 6 个(`job` / `secret` / `projects` / `internships` / `campus` / `deploy`),
|
|
24
|
+
`section templates` 列出它们;模板在栏目实例化时被**深拷贝**,此后各自独立演化,
|
|
25
|
+
模板后来的新增用 `section sync` 补(只增不改不删)。
|
|
16
26
|
|
|
17
27
|
## 核心不变量
|
|
18
28
|
|
|
@@ -60,7 +70,7 @@ nx-sk key set OPENAI_KEY sk-xxxxxxxx # 写入(存在即覆盖,返回 cre
|
|
|
60
70
|
nx-sk key get OPENAI_KEY # 取值:默认就是原文
|
|
61
71
|
nx-sk key get OPENAI_KEY --mask # 投屏/截图时才打码
|
|
62
72
|
nx-sk key list # 所有键(默认原文)
|
|
63
|
-
nx-sk key remove OPENAI_KEY #
|
|
73
|
+
nx-sk key remove OPENAI_KEY # 删除,不可撤销 → 先 nx-sk transfer export
|
|
64
74
|
```
|
|
65
75
|
|
|
66
76
|
`key *` 是 `entry *` 的**语法糖**(同模块、同一批 service 函数),缺省作用在标了 `kv` 的栏目上
|
|
@@ -114,8 +124,9 @@ nx-sk setting set --set 'navGroups=[]' # 清空 = 全部栏目恢复平铺
|
|
|
114
124
|
| `00-design` | 想搞清楚「为什么这么设计」、分层与依赖方向、错误码与 `{status}` 的分工时 |
|
|
115
125
|
| `10-sections-entries` | **动手填/改信息时必读**——栏目与条目的完整命令、AI 补全个人信息的推荐流程、字段字典怎么扩、读命令与写命令的参数陷阱 |
|
|
116
126
|
| `20-secrets` | 存/读大模型 key、密文机制、密钥来源(环境变量 vs 本机密钥文件)、什么时候会解不开 |
|
|
117
|
-
| `30-export-backup` | 整体导出、只导出某个栏目、快照与回滚、明文密钥的取舍 |
|
|
118
127
|
| `40-files` | **传/换简历头像成绩单等二进制原件时读**——附件库台账、导入(默认移动)与还原、`file` 字段怎么和条目建立链接、附件中心为什么由栏目驱动、看不到上传字段怎么办 |
|
|
128
|
+
| `50-deploy` | **存/取 Dockerfile、docker-compose、k8s 清单时读**——一份配置一个条目的字段约定、`kind` 取值、复用流程(找 → 取正文 → 替换变量 → 落盘)、为什么明文密钥不写在这里 |
|
|
129
|
+
| `60-transfer` | **搬栏目 / 分享栏目 / 局部迁移时读**——单栏目与全局 bundle 的 ZIP 结构、`transfer export/import/bundle-*` 怎么用、三种冲突策略、附件按 sha256 复用与引用重映射、凭据打码的边界 |
|
|
119
130
|
|
|
120
131
|
取 ref 全文(外部 agent 用这条,不必进终端翻文件):
|
|
121
132
|
|
|
@@ -123,6 +134,8 @@ nx-sk setting set --set 'navGroups=[]' # 清空 = 全部栏目恢复平铺
|
|
|
123
134
|
nx-sk skill get nx-sk # SKILL.md 全文
|
|
124
135
|
nx-sk skill get nx-sk 10-sections-entries # 裸名 → references/10-sections-entries.md
|
|
125
136
|
nx-sk skill get nx-sk 40-files # 附件库:导入 / 链接 / 还原
|
|
137
|
+
nx-sk skill get nx-sk 50-deploy # 部署配置:存 / 找 / 复用
|
|
138
|
+
nx-sk skill get nx-sk 60-transfer # 栏目 ZIP:导出 / 预览 / 导入
|
|
126
139
|
nx-sk skill get nx-sk references/20-secrets.md # 也可写完整路径
|
|
127
140
|
nx-sk skill get nx-sk --json # 四元 JSON:{skillName, ref, content, contentBytes, install}
|
|
128
141
|
```
|
|
@@ -137,7 +150,8 @@ nx-sk skill get nx-sk --json # 四元 JSON:{skillName, ref,
|
|
|
137
150
|
|
|
138
151
|
## 硬约束(动手前先记住)
|
|
139
152
|
|
|
140
|
-
- 所有写命令都有 `--dry-run
|
|
153
|
+
- 所有写命令都有 `--dry-run`,先试运行再落盘;**删除不可撤销** —— 删栏目/条目/附件前先
|
|
154
|
+
`nx-sk transfer export`(或面板「导出导入」→ 选中范围 → 导出),这是唯一的回退手段。
|
|
141
155
|
- 密文字段**落盘是密文,读出来默认是原文** —— 本机单人工具,自己看的东西不先拦一道。
|
|
142
156
|
要打码形态(投屏 / 截图)显式加 `--mask`。
|
|
143
157
|
- 把打码后的值(含 `******`)当新值写回去会被拒绝 —— 那通常意味着「不修改」,什么都不传即可。
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# 00 · 设计思想
|
|
2
2
|
|
|
3
|
-
> 骨架级文档:回答「为什么这么设计」。**不放场景级 SOP** —— 怎么调命令看 `10-sections-entries` / `20-secrets` / `
|
|
3
|
+
> 骨架级文档:回答「为什么这么设计」。**不放场景级 SOP** —— 怎么调命令看 `10-sections-entries` / `20-secrets` / `60-transfer`。
|
|
4
4
|
|
|
5
5
|
## 一、驱动关系
|
|
6
6
|
|
|
@@ -109,7 +109,7 @@ CLI 侧这四个取值分别渲染成不同的可读提示,退出码只有「
|
|
|
109
109
|
| 把「读命令的过滤 flag」照抄写命令的 `default` | 参数层无条件注入默认值 → 「不传 = 全部」的分支**永远走不到**,不报错、不崩,只是永远返回半个结果 | 写命令的 flag 可带 `default`;读命令的过滤 flag 一律不带 |
|
|
110
110
|
| 路由只按声明顺序匹配 | `GET /api/sections/templates` 被 `GET /api/sections/:ref` 遮蔽,命中哪条取决于 actions 数组顺序 | 路由按「字面量段优先」排序,让声明顺序无关(`runtime/spec.js` 的 `compareRoutes`) |
|
|
111
111
|
| 把打码值当成新值写回去 | 密钥字段被写成 `sk-1****cdef` 这串掩码,**原凭据永久丢失** | 写入前比对掩码:相等就当成「未改动」保留原密文;含 `******` 的值直接拒绝 |
|
|
112
|
-
|
|
|
112
|
+
| 删条目/栏目没有留退路 | 误删即不可逆;这是用户的**唯一一份**个人信息 | 破坏性写操作一律先 `transfer export` 导出(面板「导出导入」同理),导出的包就是唯一回退手段 —— 不另设本地备份模块 |
|
|
113
113
|
| store.json 解析失败就当空库继续 | 下一次写入把用户数据永久覆盖 | 先把损坏文件改名为 `store.json.corrupt-<时间>.json`,再降级返回空结构 |
|
|
114
114
|
| 前端 import 了 `node:*` 或 `core/` | Vite 把 Node 侧代码打进浏览器包,dev 模式白屏 | lint 的 `files` 同时覆盖 `view.jsx`,禁掉 `node:*` / `core` / `runtime` / `service.js` |
|
|
115
115
|
| 新增模块忘了往 eslint 互依禁列里补一行 | **静默**:新模块变成「谁都可以依赖」,且规则随模块数增加持续衰减 | 在禁列旁留注释说明它是**逐模块枚举**的、漏补是静默的;加模块前先读 `eslint.config.js` |
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
```
|
|
8
8
|
store.json(~/nx-sk/store.json 或 $NX_SK_STORE)
|
|
9
|
-
├─ settings
|
|
9
|
+
├─ settings 全局配置(可读 JSON/Markdown 导出见 60-transfer)
|
|
10
10
|
├─ sections[] 栏目:id / title / order / template / titleField / groups[] / fields[]
|
|
11
11
|
└─ entries[] 条目:id(e_xxx) / section / title / tags[] / values{字段key: 值} / 时间戳
|
|
12
12
|
```
|
|
@@ -40,9 +40,12 @@ store.json(~/nx-sk/store.json 或 $NX_SK_STORE)
|
|
|
40
40
|
- **`sync` 按模板补齐字段**:栏目字段字典是**持久化数据**——实例化时深拷贝模板字段,此后独立演化,
|
|
41
41
|
所以模板**后来**新增的分组与字段不会自动出现在老栏目里(典型症状:求职没显示附件上传框)。
|
|
42
42
|
`section sync <id>` 把模板有、本栏目还缺的分组与字段补进来(**只增不改不删**,保持模板顺序;
|
|
43
|
-
已有字段含改过的 label / hint / fill
|
|
43
|
+
已有字段含改过的 label / hint / fill 原样保留),带 `--dry-run`;面板侧是「栏目 → 编辑 → 同步模板字段」。
|
|
44
|
+
- **它还会报告「漂移」**:同名字段在「栏目 vs 模板」之间哪些属性不同(`changedFields`,含 diff 属性名)。
|
|
45
|
+
这是**只提示、不动手**——因为定义归栏目,你可能就是刻意改过。要换成模板的新定义得手动来:
|
|
46
|
+
`section update <id> --fields '<整份字段数组>'`,或先 `--remove-field` 再 `--add-field`(`--add-field` 遇到同名会报冲突)。
|
|
44
47
|
|
|
45
|
-
内置模板
|
|
48
|
+
内置模板 6 个:`job`(求职 / 个人信息,79 字段 / 10 分组——含「附件资料」组:简历附件 / 头像图片 / 成绩单 / 证书扫描件)、`projects`(项目经历)、`internships`(实习/工作经历)、`campus`(校内职务/实践)、`secret`(密钥,**单字段 KV**——细节见 `20-secrets`)、`deploy`(部署配置:Dockerfile / compose / k8s 清单,**一份文件一个条目**——细节见 `50-deploy`)。三类经历栏目(projects / internships / campus)**一个项目 / 一段经历 = 一个条目**,角色、时间、技术栈都是独立字段——不要往 job 栏目里塞经历。
|
|
46
49
|
|
|
47
50
|
## 三、条目命令
|
|
48
51
|
|
|
@@ -121,12 +124,19 @@ nx-sk section update job --remove-field blog
|
|
|
121
124
|
nx-sk section update job --fields @fields.json
|
|
122
125
|
```
|
|
123
126
|
|
|
124
|
-
字段定义支持:`key`(字母开头)、`label`、`type`(`text|textarea|number|date|month|bool|select|tags|secret|file`)、
|
|
127
|
+
字段定义支持:`key`(字母开头)、`label`、`type`(`text|textarea|number|date|month|bool|select|tags|secret|file|md`)、
|
|
125
128
|
`group`、`hint`、`options`(候选项)、`sensitive`(true 则密文落盘)、`maxItems`(tags / file 上限)、
|
|
126
129
|
`fill`(填写策略,见下)。
|
|
127
130
|
|
|
128
131
|
> `type: 'file'` 是**附件字段**:值 = 附件 id 的**列表**(一个字段可挂多个;不是路径),
|
|
129
132
|
> 导入原件、附件库台账、以及「文件统一放 `~/nx-sk/files/`」的完整口径见 `40-files`。
|
|
133
|
+
>
|
|
134
|
+
> `type: 'md'` 是**图文字段**:值是一段 markdown 正文,里面用 `` 引用附件库里的图片。
|
|
135
|
+
> 面板里可以直接 Ctrl+V 粘截图 / 拖入 / 从库里选,图片统一列在正文下方、点开可缩放拖动看细节;
|
|
136
|
+
> 正文里的 `http(s)` 网址(裸网址或 `[文字](https://…)`)在预览里会变成**可直接点开的链接**
|
|
137
|
+
> (新标签页打开),便于把控制台、文档地址嵌进 SOP;`` 这样的外链图片也会直接显示
|
|
138
|
+
> (不进附件库,需要联网)。`entry get` 会把本地图片引用还原成「[图片: 说明] 本地路径」,
|
|
139
|
+
> 外链图片则给「[外链图片: 说明] 地址」。写部署 SOP 这类「说明 + 截屏」的内容用它,口径见 `50-deploy`。
|
|
130
140
|
|
|
131
141
|
> `select` 的 `options` 是**候选项不是白名单**:真实值(如某个少数民族)不在候选里也允许写入。
|
|
132
142
|
|
|
@@ -29,7 +29,7 @@ nx-sk key set OPENAI_KEY sk-xxxxxxxx # 写入:不存在则新建,
|
|
|
29
29
|
nx-sk key get OPENAI_KEY # 取值:默认就是原文
|
|
30
30
|
nx-sk key get OPENAI_KEY --mask # 投屏/截图时才打码
|
|
31
31
|
nx-sk key list # 列出所有键(默认原文)
|
|
32
|
-
nx-sk key remove OPENAI_KEY #
|
|
32
|
+
nx-sk key remove OPENAI_KEY # 删除(不可撤销,删前先 transfer export)
|
|
33
33
|
```
|
|
34
34
|
|
|
35
35
|
| 命令 | 接口 | 说明 |
|
|
@@ -37,7 +37,7 @@ nx-sk key remove OPENAI_KEY # 删除(删前自动留快照
|
|
|
37
37
|
| `key list [--mask]` | `GET /api/keys[?mask=1]` | 全部键,按写入顺序 |
|
|
38
38
|
| `key get <名称> [--mask]` | `GET /api/keys/:name[?mask=1]` | 单个键的值 |
|
|
39
39
|
| `key set <名称> <值>` | `PUT /api/keys/:name` | **SET 语义**:存在即覆盖 |
|
|
40
|
-
| `key remove <名称>` | `DELETE /api/keys/:name` | 不存在报 `NOT_FOUND
|
|
40
|
+
| `key remove <名称>` | `DELETE /api/keys/:name` | 不存在报 `NOT_FOUND`;不可撤销 |
|
|
41
41
|
|
|
42
42
|
四条都接受 `--section <栏目>`(HTTP 侧是 `?section=` 或 body 里的 `section`),
|
|
43
43
|
缺省作用在**标了 `kv` 的那个栏目**上。
|
|
@@ -45,7 +45,7 @@ nx-sk key remove OPENAI_KEY # 删除(删前自动留快照
|
|
|
45
45
|
### 与 `entry` 的关系(重要)
|
|
46
46
|
|
|
47
47
|
`key *` **不是第二套实现**,是 `entry *` 的语法糖:它把「哪个栏目 + 哪个值字段」定好,
|
|
48
|
-
再调同一批 service
|
|
48
|
+
再调同一批 service 函数。所以加解密、`--dry-run` 只有一份实现,不可能分叉。
|
|
49
49
|
|
|
50
50
|
等价关系:
|
|
51
51
|
|
|
@@ -89,7 +89,7 @@ nx-sk section list # 列表里 KV 栏目带 [KV 表]
|
|
|
89
89
|
- **值以 `-` 开头时**用 `--value=<值>`(`key set K --value=--x`)——`--x` 会被当成 flag。
|
|
90
90
|
显式 flag 覆盖位置参数,两种写法等价。
|
|
91
91
|
- **重复写同一个值不会重写密文**:返回 `{ status: 'skipped', unchanged: true }`。
|
|
92
|
-
每次加密都用新 IV
|
|
92
|
+
每次加密都用新 IV,无脑重写只会产生一堆无意义的新密文。
|
|
93
93
|
|
|
94
94
|
### 多行值:走 stdin 或 `@文件`(真实事故)
|
|
95
95
|
|
|
@@ -200,7 +200,7 @@ nx-sk key set OPENAI_KEY sk-xxxxxxxx
|
|
|
200
200
|
| 症状 | 原因 | 处理 |
|
|
201
201
|
| --- | --- | --- |
|
|
202
202
|
| `BLOCKED 当前密钥与写入时的密钥不一致` | 换了口令,或删了 `.vaultkey` | 改回原来的来源(旧口令 / 恢复密钥文件) |
|
|
203
|
-
| `BLOCKED 解密失败:密文已损坏,或密钥不正确` | store.json 被手工改过 / GCM 认证失败 |
|
|
203
|
+
| `BLOCKED 解密失败:密文已损坏,或密钥不正确` | store.json 被手工改过 / GCM 认证失败 | 从之前 `transfer export` 出来的包重新导入 |
|
|
204
204
|
| `.vaultkey` 不见了 | 被系统清理或误删 | 有口令模式的盐文件 `.vaultsalt` 与口令还能救;否则密文不可逆 |
|
|
205
205
|
|
|
206
206
|
**密文不可逆是特性,不是缺陷** —— 代价是「忘记密钥 = 数据丢失」,
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
|
|
34
34
|
- `file list --section <栏目>` 只看「被某栏目引用」的附件;`--section none` 只看**还没有任何条目引用**的。
|
|
35
35
|
- `file content` 是浏览器链接:内联预览,加 `--download` 强制下载;CLI 侧打印物理路径与链接。
|
|
36
|
-
- 所有写命令都支持 `--dry-run`;`file remove`
|
|
36
|
+
- 所有写命令都支持 `--dry-run`;`file remove` 连物理原件一起删**不可撤销**——
|
|
37
37
|
只想「拿出原件、库里留着」应该用 `file restore --copy`。
|
|
38
38
|
|
|
39
39
|
## 三、导入:默认移动,`--copy` 才复制
|
|
@@ -87,7 +87,7 @@ nx-sk file restore f_xxxx --to "D:\资料" # Web 上传件没有原始
|
|
|
87
87
|
| `restore --copy` | 只**导出副本**到目标目录,库中原件与台账**都保留** |
|
|
88
88
|
|
|
89
89
|
- Web 上传进来的附件没有「原始位置」,还原时必须给 `--to`。
|
|
90
|
-
-
|
|
90
|
+
- 还原/删除都不留本地备份;删之前先 `transfer export` 导一份——见 `60-transfer`。
|
|
91
91
|
|
|
92
92
|
## 六、Web 面板
|
|
93
93
|
|