nx-sk 0.15.3 → 0.16.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 +62 -0
- package/README.md +70 -4
- package/assets/nx-sk/SKILL.md +129 -35
- package/assets/nx-sk/references/00-design.md +77 -85
- package/assets/nx-sk/references/10-sections-entries.md +30 -20
- package/assets/nx-sk/references/20-secrets.md +25 -12
- package/assets/nx-sk/references/30-credentials.md +166 -0
- package/assets/nx-sk/references/40-files.md +10 -10
- package/assets/nx-sk/references/50-deploy.md +34 -10
- package/assets/nx-sk/scripts/render-config.js +106 -0
- package/package.json +1 -1
- package/src/core/fields.js +41 -5
- package/src/modules/entries/service.js +57 -6
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,68 @@
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## 0.16.0 (2026-10-23)
|
|
8
|
+
|
|
9
|
+
**凭据自动化:账号密码跟着场景走,直接渲染成配置文件。**
|
|
10
|
+
|
|
11
|
+
nx-sk 的定位从来不是「另一个密码管理器」,而是**把凭据变成能用的东西**。
|
|
12
|
+
这一版把这条主用途补齐:凭据不再必须绕去「密钥」栏目,agent 可以大胆写、直接出成品配置。
|
|
13
|
+
|
|
14
|
+
### Added
|
|
15
|
+
|
|
16
|
+
- **自动登记的凭据键直接建成密文字段**:键名里出现 密码 / 口令 / 密钥 / 账号 / 帐号 /
|
|
17
|
+
凭据 / token / apiKey / accessKey / secretKey / password / passphrase 等词时,
|
|
18
|
+
新登记的字段就是密文字段 —— 落盘 AES-256-GCM 密文,读出来默认原文。
|
|
19
|
+
于是 `--set 密码=…` 这种「一把写进去」的用法**不需要先声明 schema,也不会明文裸奔**。
|
|
20
|
+
判据刻意宽松:把不是凭据的字段多加密一次只是多几行密文,反过来漏加密的代价是凭据裸奔。
|
|
21
|
+
- **deploy 模板自带「凭据清单」字段**(分组「凭据」):结构清单,一行一组账号,
|
|
22
|
+
密码与令牌列 `sensitive` 密文落盘。**一个场景的凭据写在那个场景的条目里**,
|
|
23
|
+
不再需要为它单开一个密钥栏目。老栏目用 `section sync deploy` 补上。
|
|
24
|
+
- **结构清单的行可以用**列标签**写**(`密码` 与 `pass` 等价),与顶层 `--set` 同一口径 ——
|
|
25
|
+
之前只认列 key,文档里的示例是错的,agent 按文档写就会报错。
|
|
26
|
+
- **渲染脚本 `assets/nx-sk/scripts/render-config.js`**:把条目里的凭据替换进模板正文的
|
|
27
|
+
`${VAR}`,产出成品配置文件(compose / k8s / .env / Dockerfile)。
|
|
28
|
+
跑完报「替换了哪些、哪些没解析」。固化成文件是因为**多行 `node -e` 在 Windows 终端里
|
|
29
|
+
会被吃掉引号**(实测是静默不执行、退出码 0)。
|
|
30
|
+
- **新 ref `30-credentials`**:凭据归属哪个栏目、多组账号怎么建清单、跨栏目台账、
|
|
31
|
+
渲染流程、安全边界与常见场景落位。SKILL.md 与 `10` / `20` / `50` 三个 ref 同步改写,
|
|
32
|
+
整体口径从「怕明文」改成「**模板层与场景层分工**」。
|
|
33
|
+
- **随包 skill 改成「完全客户端」**:只回答「怎么用」与「东西该往哪儿放」,
|
|
34
|
+
不再夹带开发侧知识。`references/00-design.md` **整篇重写**——
|
|
35
|
+
从「代码分层 / action 声明 / 错误契约 / 踩坑记录」改成**用户侧的心智模型**:
|
|
36
|
+
栏目确定结构、条目确定数据、内置字段是建议清单、动态栏目 + 动态条目、
|
|
37
|
+
四个聚合点、密文边界、给 agent 的三条不变量。
|
|
38
|
+
开发侧内容(分层与依赖方向、action 机制、错误契约表、实测踩坑表)**归位到仓库 README**
|
|
39
|
+
的「设计取舍与踩坑记录」——装了包也用不上它,但仓库开发者需要它。
|
|
40
|
+
其余 ref 里的 HTTP 路由列、源码路径也一并清掉。
|
|
41
|
+
|
|
42
|
+
### Changed
|
|
43
|
+
|
|
44
|
+
- **密钥(KV)栏目的定位收窄为「跨场景通用的 key」**:只服务于一个场景的凭据
|
|
45
|
+
(某台服务器的密码、某个平台的账号)改写进场景自己的栏目条目。理由是凭据的寿命跟着场景 ——
|
|
46
|
+
堆在一个 KV 表里,到头来只能靠键名前缀编码场景,等于把结构塞进键名。
|
|
47
|
+
- **`entry keys` 台账的地位明确**:它是「凭据散在各个栏目里」的对账表 ——
|
|
48
|
+
改密码、找入口、迁移机器前先跑一遍。
|
|
49
|
+
- skill 文档补齐了两个漏写的内置模板(`platform` / `thesis`,共 8 个),
|
|
50
|
+
以及 `entrylist` 行的列标签写法。
|
|
51
|
+
|
|
52
|
+
### Fixed
|
|
53
|
+
|
|
54
|
+
- 模板里 `deploy` 的 `content` 字段提示与 `50-deploy` 的口径此前互相矛盾
|
|
55
|
+
(一个说「真值放密钥栏目」、一个说「明文密钥不写在这里」),现在统一为
|
|
56
|
+
「模板正文写占位符、场景真值写凭据清单」。
|
|
57
|
+
- **`entry keys` 台账漏掉结构清单里的凭据**:场景凭据现在住在 entrylist 的行里
|
|
58
|
+
(`creds` 清单),而台账只扫顶层字段 —— 于是「一条命令看全部凭据」恰好看不见
|
|
59
|
+
放在清单里的那些。台账改为展开清单行逐格上报。
|
|
60
|
+
|
|
61
|
+
### 测试
|
|
62
|
+
|
|
63
|
+
- 新增 `tests/unit/credentials.test.mjs`:自动登记的凭据键密文落盘、读回原文、
|
|
64
|
+
`--mask` 打码;不像凭据的键不误加密;清单行可用列标签写;
|
|
65
|
+
deploy 模板自带凭据清单且敏感列密文。
|
|
66
|
+
- 新增断言「随包手册不许出现开发侧知识」(HTTP 路由 / 源码路径 / 构建工具链)——
|
|
67
|
+
已做反向验证:塞进一个路由即红。开发侧内容要进随包手册前,先过这一关。
|
|
68
|
+
|
|
7
69
|
## 0.15.3 (2026-10-20)
|
|
8
70
|
|
|
9
71
|
### Changed
|
package/README.md
CHANGED
|
@@ -104,12 +104,12 @@ CLI 与 API 同源,skill 驱动 agent**。落到具体功能上:
|
|
|
104
104
|
|
|
105
105
|
| 栏目 | id | 内容 |
|
|
106
106
|
| --- | --- | --- |
|
|
107
|
-
| 求职 | `job` | 求职用的个人信息档案:
|
|
107
|
+
| 求职 | `job` | 求职用的个人信息档案:10 个分组 / 80 个字段(姓名、学历、联系方式、求职意向、紧急联系人…)。模板只是**建议清单**,`--set 任意键=值` 直接写 |
|
|
108
108
|
| 项目经历 | `projects` | 一个项目一个条目:名称 / 角色 / 时间 / 技术栈 / 职责与亮点 |
|
|
109
109
|
| 实习/工作经历 | `internships` | 一段经历一个条目:公司 / 岗位 / 时间 / 职责 |
|
|
110
110
|
| 校内职务/实践 | `campus` | 一条职务或实践一个条目:职务 / 组织 / 时间 / 职责 |
|
|
111
|
-
| 密钥 | `secret` | **一张 KV 表**(`kv: true`):面板上就是两列表格(名称 / 值),一行一个键。落盘是 **AES-256-GCM** 密文,读出来默认是原文(`--mask`
|
|
112
|
-
| 部署配置 | `deploy` | **一份配置文件一个条目**(Dockerfile / docker-compose / k8s 清单):正文即文件原文,外加「放哪 / 哪些值要替换 / 何时用」,好让它在别的项目里照着用 |
|
|
111
|
+
| 密钥 | `secret` | **一张 KV 表**(`kv: true`):面板上就是两列表格(名称 / 值),一行一个键。落盘是 **AES-256-GCM** 密文,读出来默认是原文(`--mask` 才打码)。只放**跨场景通用**的 key |
|
|
112
|
+
| 部署配置 | `deploy` | **一份配置文件一个条目**(Dockerfile / docker-compose / k8s 清单):正文即文件原文,外加「放哪 / 哪些值要替换 / **这个场景自己的凭据清单** / 何时用」,好让它在别的项目里照着用 |
|
|
113
113
|
|
|
114
114
|
上表是**首次运行从 6 个内置模板播种出来的默认值,不是固定清单**:栏目不是写死的——
|
|
115
115
|
字段字典是**数据**,加字段(`section update --add-field`,或 `entry update --set 任意键=值` 自动登记)、
|
|
@@ -117,6 +117,9 @@ CLI 与 API 同源,skill 驱动 agent**。落到具体功能上:
|
|
|
117
117
|
模板在实例化时被**深拷贝**,此后各栏目独立演化;模板后来的新增用 `section sync` 补(只增不改不删,
|
|
118
118
|
有差异时会把「模板已改、栏目保留原值」的字段列出来提示)。
|
|
119
119
|
|
|
120
|
+
内置模板共 **8 个**——除上面 6 个外还有 `platform`(容器平台:控制台链接 / 账号 / 密码 / 镜像)
|
|
121
|
+
与 `thesis`(毕业论文规范字段化),需要时 `section add <id> --template platform|thesis` 建。
|
|
122
|
+
|
|
120
123
|
## 三条核心不变量
|
|
121
124
|
|
|
122
125
|
1. **一条 action 同时声明 CLI 与 HTTP。** 面板上能做的,CLI 都能做;参数名与错误码两端一致。
|
|
@@ -200,6 +203,35 @@ nx-sk key remove OPENAI_KEY # 删除,写前自动留快照
|
|
|
200
203
|
状态与栏目一样:`key *` 只是 `entry *` 的语法糖(同模块、同一批 service 函数),
|
|
201
204
|
作用在 `settings.kvSection` 指向的单字段栏目上(默认 `secret`)。
|
|
202
205
|
|
|
206
|
+
### 凭据自动化:账号密码跟着场景走,直接渲染成配置文件
|
|
207
|
+
|
|
208
|
+
**密钥栏目只放跨场景通用的 key**(`OPENAI_KEY` 这种要 `export` 给各种工具用的)。
|
|
209
|
+
**一个场景的账号密码写在那个场景自己的栏目里** —— 场景换了凭据就换,取的时候一眼知道是谁的。
|
|
210
|
+
|
|
211
|
+
```bash
|
|
212
|
+
# 键名像凭据(密码 / 口令 / 密钥 / 账号 / token / apiKey…)→ 自动登记成**密文字段**
|
|
213
|
+
# 不必先声明 schema,也不必绕路;落盘是 AES-256-GCM 密文,读出来默认原文
|
|
214
|
+
nx-sk entry update "阿里云" --section deploy --set 账号=ops@example.com --set 密码='P@ss…'
|
|
215
|
+
|
|
216
|
+
# 一个场景多组账号 → 结构清单(密码 / 令牌列密文落盘;列名用 key 或中文标签都认)
|
|
217
|
+
nx-sk entry update "阿里云" --section deploy --data '{"凭据清单":[{"名称":"registry","账号":"ci","令牌":"tok-…"}]}'
|
|
218
|
+
|
|
219
|
+
# 跨栏目对账:所有栏目里的链接 / 账号 / 密码 / 令牌 / 镜像
|
|
220
|
+
nx-sk entry keys --reveal
|
|
221
|
+
|
|
222
|
+
# 出成品配置:取真值 → 替换模板里的 ${VAR} → 落盘
|
|
223
|
+
nx-sk entry get "阿里云" --section deploy --json > /tmp/e.json
|
|
224
|
+
node assets/nx-sk/scripts/render-config.js /tmp/e.json ./docker-compose.local.yml
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
`deploy` 模板自带「凭据清单」字段;`content` 里只写 `${VAR}` 占位(那份正文是要进 git 的**模板**),
|
|
228
|
+
真值放在**凭据清单**里(**场景数据**,密文落盘)—— 模板与实例本来就是两种东西。
|
|
229
|
+
|
|
230
|
+
**安全边界只有三个出口**:① 推送到 git / 上传云端;② 打进日志或交给第三方;
|
|
231
|
+
③ 导出包外发(包里恒为明文,外发必须 `--passphrase`)。
|
|
232
|
+
除此之外——本机落盘、密文、数据在仓库之外、面板只听 `127.0.0.1`——都是安全的,
|
|
233
|
+
所以「大胆写」不必自我审查密码本身。
|
|
234
|
+
|
|
203
235
|
统一附件管理(简历、头像、成绩单等原件都收进 `~/nx-sk/files/`):
|
|
204
236
|
|
|
205
237
|
```bash
|
|
@@ -382,7 +414,7 @@ nx-sk skill get sk-thesis 10-format # 数值速查
|
|
|
382
414
|
## 开发
|
|
383
415
|
|
|
384
416
|
```bash
|
|
385
|
-
pnpm test # = lint + build +
|
|
417
|
+
pnpm test # = lint + build + 冒烟 + 单测
|
|
386
418
|
```
|
|
387
419
|
|
|
388
420
|
| 目录 | 职责 |
|
|
@@ -399,6 +431,40 @@ pnpm test # = lint + build + 冒烟(109 项断言) + 单测(140 项
|
|
|
399
431
|
agent 手册** —— 它写在创建本项目的脚手架 skill `server-cli-web-scaffold` 的
|
|
400
432
|
`references/A07-extension-loop.md`,`assets/nx-sk/` 里只放「怎么用 nx-sk」。
|
|
401
433
|
|
|
434
|
+
### 设计取舍与踩坑记录(开发侧)
|
|
435
|
+
|
|
436
|
+
> 这节原本在随包分发的 `assets/nx-sk/references/00-design.md` 里。
|
|
437
|
+
> 那份文档随包发到用户机器,而**代码分层、接口路由、lint 规则用户装了也用不上**——
|
|
438
|
+
> 所以开发侧内容归位到仓库,设计思想(栏目=结构 / 条目=数据 / 动态栏目+动态条目 / 聚合所有信息)
|
|
439
|
+
> 留在 `assets/nx-sk/references/00-design.md`,那里只讲心智模型与用法。
|
|
440
|
+
|
|
441
|
+
**错误契约**(映射只写一处,`src/core/errors.js`):
|
|
442
|
+
|
|
443
|
+
| code | 判据 | HTTP |
|
|
444
|
+
| --- | --- | --- |
|
|
445
|
+
| `INVALID_INPUT` | 输入本身不合法 | 400 |
|
|
446
|
+
| `NOT_FOUND` | 指定的目标不存在 | 404 |
|
|
447
|
+
| `CONFLICT` | 目标存在且与期望状态冲突,需要用户选一侧 | 409 |
|
|
448
|
+
| `BLOCKED` | 操作合法但被前置条件挡住(或密钥不一致) | 409 |
|
|
449
|
+
| `EXTERNAL` | 外部命令/端口失败 | 502 |
|
|
450
|
+
| `INTERNAL` | 兜底 | 500 |
|
|
451
|
+
|
|
452
|
+
**实测踩过的坑**(每条都是真实事故,写新代码前对一遍):
|
|
453
|
+
|
|
454
|
+
| 错误操作 | 实际后果 | 正确做法 |
|
|
455
|
+
| --- | --- | --- |
|
|
456
|
+
| 把「读命令的过滤 flag」照抄写命令的 `default` | 参数层无条件注入默认值 → 「不传 = 全部」的分支**永远走不到**,不报错、不崩,只是永远返回半个结果 | 写命令的 flag 可带 `default`;读命令的过滤 flag 一律不带 |
|
|
457
|
+
| 路由只按声明顺序匹配 | `GET /api/sections/templates` 被 `GET /api/sections/:ref` 遮蔽,命中哪条取决于 actions 数组顺序 | 路由按「字面量段优先」排序,让声明顺序无关(`runtime/spec.js` 的 `compareRoutes`) |
|
|
458
|
+
| 把打码值当成新值写回去 | 密钥字段被写成 `sk-1****cdef` 这串掩码,**原凭据永久丢失** | 写入前比对掩码:相等就当成「未改动」保留原密文;含 `******` 的值直接拒绝 |
|
|
459
|
+
| 删条目/栏目没有留退路 | 误删即不可逆;这是用户的**唯一一份**个人信息 | 破坏性写操作一律先 `transfer export` 导出,导出的包就是唯一回退手段 —— 不另设本地备份模块 |
|
|
460
|
+
| store.json 解析失败就当空库继续 | 下一次写入把用户数据永久覆盖 | 先把损坏文件改名为 `store.json.corrupt-<时间>.json`,再降级返回空结构 |
|
|
461
|
+
| 前端 import 了 `node:*` 或 `core/` | Vite 把 Node 侧代码打进浏览器包,dev 模式白屏 | lint 的 `files` 同时覆盖 `view.jsx`,禁掉 `node:*` / `core` / `runtime` / `service.js` |
|
|
462
|
+
| 新增模块忘了往 eslint 互依禁列里补一行 | **静默**:新模块变成「谁都可以依赖」,且规则随模块数增加持续衰减 | 在禁列旁留注释说明它是**逐模块枚举**的、漏补是静默的;加模块前先读 `eslint.config.js` |
|
|
463
|
+
| 代理前缀 `/api` 与前端源码目录 `api/` 撞车 | 只在 dev 模式整页白屏,报错却是 404 / ECONNREFUSED,离根因很远 | vite 代理加 `bypass`,按「是不是前端资源」分流;并用测试钉住 `shouldServeLocally` |
|
|
464
|
+
| 把「上传 / 选择」放到附件中心,再让条目去引用 | 条目里看不到上传入口,用户不知道该在哪儿加文件;附件中心还被迫预定义分类与槽位,跟栏目脱节 | **上传 / 选择发生在栏目条目里**(`file` 字段的值 = 附件 id);附件中心由栏目驱动、只做统一展示与库存管理,**不预定义分类、不做指派** |
|
|
465
|
+
| 字段字典只在模板里、栏目不落盘 | 模板后来新增的字段永远不出现在老栏目里(求职没显示上传框),且没有任何报错 | 栏目实例化时**深拷贝**模板字段;模板演进用 `section sync`(只增不改不删)补 |
|
|
466
|
+
| 清单的行只认列 key | 人写的是「密码」,声明的是 `pass` —— agent 按文档写就报错 | 列名**key 与 label 都认**,与顶层 `--set` 同一口径 |
|
|
467
|
+
|
|
402
468
|
## License
|
|
403
469
|
|
|
404
470
|
MIT
|
package/assets/nx-sk/SKILL.md
CHANGED
|
@@ -1,27 +1,29 @@
|
|
|
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、密文、凭据、账号密码、账号、密码、令牌、token、配置渲染、导出、面板、serve、部署配置、Dockerfile、docker-compose、k8s 清单。不适用:纯问答、不需要落盘的临时讨论;也不适用于把密钥同步/上传到远程服务的场景——nx-sk 只在本机落盘,不做任何上传。
|
|
4
4
|
---
|
|
5
|
-
|
|
6
5
|
# nx-sk · 本机个人资源管理器
|
|
7
6
|
|
|
8
|
-
|
|
7
|
+
一句话:**把「你的信息」按栏目存起来,凭据就放在它该在的地方,CLI 与 Web 面板是同一套业务。**
|
|
9
8
|
|
|
10
|
-
数据落在 `~/nx-sk/`(可用环境变量 `NX_SK_HOME` / `NX_SK_STORE`
|
|
9
|
+
数据落在 `~/nx-sk/`(可用环境变量 `NX_SK_HOME` / `NX_SK_STORE` 覆盖),**永远在仓库之外**。
|
|
10
|
+
首次运行按内置模板播种 6 个栏目:
|
|
11
11
|
|
|
12
|
-
| 栏目
|
|
13
|
-
|
|
|
14
|
-
| 求职
|
|
15
|
-
| 项目经历
|
|
16
|
-
| 实习/工作经历 | `internships` | 一段经历一个条目:公司 / 岗位 / 时间 / 职责
|
|
17
|
-
| 校内职务/实践 | `campus`
|
|
18
|
-
| 密钥
|
|
19
|
-
| 部署配置
|
|
12
|
+
| 栏目 | id | 内容 |
|
|
13
|
+
| ------------- | --------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
14
|
+
| 求职 | `job` | 求职用的个人信息档案(姓名/学历/求职意向/简历头像成绩单附件…约 80 个字段) |
|
|
15
|
+
| 项目经历 | `projects` | 一个项目一个条目:名称 / 角色 / 时间 / 技术栈 / 职责与亮点 |
|
|
16
|
+
| 实习/工作经历 | `internships` | 一段经历一个条目:公司 / 岗位 / 时间 / 职责 |
|
|
17
|
+
| 校内职务/实践 | `campus` | 一条职务或实践一个条目 |
|
|
18
|
+
| 密钥 | `secret` | **一张 KV 表**(`kv: true`):一行一个键值对。**只放跨场景通用的 key**(见下节) |
|
|
19
|
+
| 部署配置 | `deploy` | **一份配置文件一个条目**(Dockerfile / compose / k8s 清单):正文即文件原文 + 放哪 + 哪些值要替换 + **这个场景自己的凭据清单** + 何时用。详见 [[50-deploy]] |
|
|
20
20
|
|
|
21
21
|
**这 6 个只是起点,不是固定清单**:栏目可以新建(`section add`,不给模板就是空栏目全自定义)、
|
|
22
22
|
可以加/删字段(`section update --add-field`,或直接 `entry update --set 任意键=值` 自动登记)、
|
|
23
|
-
也可以删掉整个栏目。内置模板共
|
|
24
|
-
`
|
|
23
|
+
也可以删掉整个栏目。内置模板共 **8 个**——除上面 6 个外还有
|
|
24
|
+
`platform`(容器平台:控制台链接 / 账号 / 密码 / 镜像,一个平台一个条目)与
|
|
25
|
+
`thesis`(毕业论文规范字段化),`section templates` 列出它们;
|
|
26
|
+
模板在栏目实例化时被**深拷贝**,此后各自独立演化,
|
|
25
27
|
模板后来的新增用 `section sync` 补(只增不改不删)。
|
|
26
28
|
|
|
27
29
|
## 核心不变量
|
|
@@ -36,14 +38,100 @@ description: 本机个人资源管理器——栏目化存储个人信息(求
|
|
|
36
38
|
台账的用处是「模板建议 + 你实际写过什么」,不是门禁。
|
|
37
39
|
*违反会怎样*:反过来把它做成门禁,用户每换一个表单就要先改一次 schema ——
|
|
38
40
|
而那正是「只想存个 kv」时最不想付的成本;而不登记就往条目里塞值,存了也看不见。
|
|
39
|
-
|
|
40
|
-
|
|
41
|
+
2. **面板与 CLI 是同一套业务。** 面板上能做的,CLI 都能做;两边参数名、错误码一致。
|
|
42
|
+
所以「让用户在面板上点一下」和「让 agent 敲一条命令」是同一件事的两面。
|
|
41
43
|
*违反会怎样*:只能靠字符串匹配猜错误,无法可靠分支。
|
|
42
|
-
|
|
43
44
|
3. **失败抛异常(退出码 1),业务结果返回 `{ status }`(退出码 0)。**
|
|
44
45
|
`conflict` / `blocked` / `skipped` 都是**正常返回**,agent 要看 `status` 字段而不是退出码。
|
|
45
46
|
*违反会怎样*:把一个「等用户决策」的冲突当成失败去重试。
|
|
46
47
|
|
|
48
|
+
## 凭据自动化(大胆写,别绕路)
|
|
49
|
+
|
|
50
|
+
**这是 nx-sk 的主用途:把账号密码这类东西存在它该在的地方,然后直接拿它产出能用的东西。**
|
|
51
|
+
|
|
52
|
+
### 一条场景的凭据,写在那个场景的栏目里
|
|
53
|
+
|
|
54
|
+
不要为了存「阿里云的密码」去动 `secret` 密钥栏目 —— **凭据跟着场景走**:
|
|
55
|
+
|
|
56
|
+
| 凭据类型 | 放哪 | 为什么 |
|
|
57
|
+
| -------------------------------------------------------- | ------------------------------------------------------------------------ | ---------------------------------------------------------- |
|
|
58
|
+
| 某个平台 / 项目的账号密码 | **那个场景自己的栏目条目**(`deploy` / `platform` / 自建栏目) | 场景换了凭据就换,换的时候只改一处;取的时候一眼知道是谁的 |
|
|
59
|
+
| 到处都要用的通用 key(`OPENAI_KEY`、`GITHUB_TOKEN`) | **`secret` 密钥栏目**(KV 表) | 跨场景复用,抽出来当全局环境变量用 |
|
|
60
|
+
| 简历 / 头像 / 证书 | `job` 栏目的 `file` 字段 | 见「附件」一节 |
|
|
61
|
+
|
|
62
|
+
怎么写(**不需要先声明 schema**,键名像凭据就自动加密):
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
nx-sk entry update "阿里云" --section deploy --set 账号=ops@example.com --set 密码='P@ss…'
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
**键名长得像凭据(密码 / 口令 / 密钥 / 账号 / token / apiKey / accessKey / secretKey…)时,
|
|
69
|
+
自动登记出来的字段直接就是密文字段**:落盘是 AES-256-GCM 密文,读出来默认原文。
|
|
70
|
+
所以「大胆写」不等于「明文裸奔」——**大胆的是操作方式,不是安全性**。
|
|
71
|
+
|
|
72
|
+
> 想要更明确的结构(一个场景多组账号),就声明一个**结构清单**字段,密码列标 `sensitive`:
|
|
73
|
+
>
|
|
74
|
+
> ```bash
|
|
75
|
+
> nx-sk section update mycloud --add-field '{"key":"creds","label":"凭据清单","type":"entrylist","group":"main","fields":[{"key":"name","label":"名称"},{"key":"user","label":"账号"},{"key":"pass","label":"密码","sensitive":true},{"key":"token","label":"令牌","sensitive":true}]}'
|
|
76
|
+
> nx-sk entry update "阿里云" --section mycloud --data '{"凭据清单":[{"名称":"控制台","账号":"ops","密码":"P@ss…"}]}'
|
|
77
|
+
> ```
|
|
78
|
+
>
|
|
79
|
+
> `deploy` 模板**自带**这个字段(`section sync deploy` 能给老栏目补上),自建栏目则要自己声明一次。
|
|
80
|
+
> 清单的行**列名用 key 或中文标签都认**(`名称` / `name` 等价)。
|
|
81
|
+
|
|
82
|
+
### 一条命令看全部凭据(跨栏目台账)
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
nx-sk entry keys # 所有栏目里的 链接/账号/密码/令牌/镜像 —— 值默认打码
|
|
86
|
+
nx-sk entry keys --reveal # 明文(给自己看 / 喂给脚本)
|
|
87
|
+
nx-sk entry keys --section deploy --q 密码 # 只看某栏目、含"密码"的
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
这是「凭据散在各个栏目里」的对账表:改密码、找某个平台的入口,都从这儿过一遍。
|
|
91
|
+
|
|
92
|
+
### 需要配置文件,直接给
|
|
93
|
+
|
|
94
|
+
**nx-sk 的作用就是把凭据变成能用的配置。** 用户要 compose / k8s / .env / Dockerfile 时,
|
|
95
|
+
不要只丢一个模板让他自己填 —— **取真值、渲染、出成品**:
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
# ① 取真值(密文字段自动解密)
|
|
99
|
+
nx-sk entry get "阿里云" --section deploy --json # → .values.creds[] / .values.密码 …
|
|
100
|
+
# ② 用真值渲染模板里的 ${VAR} 占位,产出配置文件
|
|
101
|
+
# ③ 落盘到项目里
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
渲染的机械步骤(`content` 是模板正文,`creds` 是这个场景的凭据):
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
nx-sk entry get "阿里云" --section deploy --json > /tmp/e.json
|
|
108
|
+
node assets/nx-sk/scripts/render-config.js /tmp/e.json ./docker-compose.local.yml
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
脚本把 `creds` 里每行的「名称」当变量名(值取密码 / 令牌 / 账号),
|
|
112
|
+
把条目其它标量字段按字段 key 也当变量,替换正文里的 `${VAR}`(支持 `${VAR:-默认值}`),
|
|
113
|
+
最后报出**替换了哪些、哪些没解析**。已装 skill 的话脚本在
|
|
114
|
+
`~/.claude/skills/nx-sk/scripts/render-config.js`(在 nx-sk 源码仓库里是 `assets/nx-sk/scripts/`)。
|
|
115
|
+
|
|
116
|
+
**成品里带真值是可以的**(本机文件、没人看),但要守住两条:
|
|
117
|
+
|
|
118
|
+
- **别让它进 git** —— 仓库里提交的是**占位符版本**(`docker-compose.yml` 用 `${VAR}`,
|
|
119
|
+
另附 `.env.example`),真值落在本机 `.env` / `*.local.yml`,并确保 `.gitignore` 盖住。
|
|
120
|
+
nx-sk 的数据目录本身就在仓库之外,并且有测试钉住「`store.json` 不许被 git 跟踪」。
|
|
121
|
+
- **别把它打进日志 / issue / 聊天 / 给第三方的输出** —— 这一条才是硬边界。
|
|
122
|
+
|
|
123
|
+
### 「本机 = 安全」的准确口径
|
|
124
|
+
|
|
125
|
+
| 事实 | 依据 |
|
|
126
|
+
| -------------------------- | ------------------------------------------------------------------ |
|
|
127
|
+
| 凭据落盘是密文 | AES-256-GCM,每值独立 IV;`store.json` 里没有明文 |
|
|
128
|
+
| 数据不在任何仓库里 | `~/nx-sk/`,仓库外;仓库有测试钉住「store.json 不许被 git 跟踪」 |
|
|
129
|
+
| 面板只监听本机 | `127.0.0.1` |
|
|
130
|
+
| **风险出口只有三个** | ① 推到 git / 上传云端;② 打印到日志或贴给第三方;③ 导出包外发 |
|
|
131
|
+
|
|
132
|
+
所以口径是:**只要不推送到 git、不把明文交给第三方,剩下都是安全的** ——
|
|
133
|
+
在「本机单人自用」的前提下,这已经足够大胆,不必再自我审查一遍密码本身。
|
|
134
|
+
|
|
47
135
|
## 命令面(先跑这一条)
|
|
48
136
|
|
|
49
137
|
```bash
|
|
@@ -63,21 +151,22 @@ nx-sk section dump job --json # ③ 一个栏目的全部
|
|
|
63
151
|
`--set` 的键**可以用 key 也可以用中文标签**(`--set 电话=138…` 与 `--set phone=138…` 等价)。
|
|
64
152
|
一次写很多字段用 `--data @file.json`(`--data` 也接受内联 JSON)。
|
|
65
153
|
|
|
66
|
-
|
|
154
|
+
存/取**跨场景通用**的 key 走这四条(缺省作用在标了 `kv` 的栏目上,`--section` 可指定):
|
|
67
155
|
|
|
68
156
|
```bash
|
|
69
157
|
nx-sk key set OPENAI_KEY sk-xxxxxxxx # 写入(存在即覆盖,返回 created 告诉你是哪种)
|
|
70
158
|
nx-sk key get OPENAI_KEY # 取值:默认就是原文
|
|
71
|
-
nx-sk key get OPENAI_KEY --mask
|
|
159
|
+
nx-sk key get OPENAI_KEY --mask # 投屏/截图时才打码
|
|
72
160
|
nx-sk key list # 所有键(默认原文)
|
|
73
161
|
nx-sk key remove OPENAI_KEY # 删除,不可撤销 → 先 nx-sk transfer export
|
|
74
162
|
```
|
|
75
163
|
|
|
76
|
-
`key *` 是 `entry *`
|
|
77
|
-
|
|
164
|
+
`key *` 是 `entry *` 的**语法糖**(同一套读写流程)。区别只有一个:
|
|
165
|
+
`key set` 遇到同名是**覆盖**,`entry add` 是报 `CONFLICT`。
|
|
78
166
|
|
|
79
167
|
**KV 栏目不许加字段**:它的形状就是一行一个键值对。想加东西就用 `key set <名称> <值>`
|
|
80
168
|
(在 KV 栏目里 `entry update --set 新键=值` 会被拒绝并告诉你该用哪条命令)。
|
|
169
|
+
**场景级的账号密码不要往这儿塞** —— 见「凭据自动化」。
|
|
81
170
|
|
|
82
171
|
附件(简历、头像、成绩单等二进制原件)走统一附件库,物理文件在 `~/nx-sk/files/`:
|
|
83
172
|
|
|
@@ -126,13 +215,14 @@ nx-sk file get f_bbb # 反查「被引用:求职
|
|
|
126
215
|
|
|
127
216
|
结构清单字段(`type: 'entrylist'`)——一个条目要挂**多组 链接/账号/密码**这类密集结构时用它:
|
|
128
217
|
值 = 行对象的**数组**(变长,空行写入时自动剔除),列在字段定义的 `fields` 里声明;
|
|
129
|
-
声明 `sensitive: true` 的列与顶层敏感字段同一条边界(密文落盘、`--mask`
|
|
218
|
+
声明 `sensitive: true` 的列与顶层敏感字段同一条边界(密文落盘、`--mask` 打码);
|
|
219
|
+
行里的列名**用 key 或中文标签都认**。
|
|
130
220
|
|
|
131
221
|
```bash
|
|
132
222
|
# 建字段:列就是一份小字典(面板「新增字段」选「结构清单」会预填 名称/链接/账号/密码 四列)
|
|
133
223
|
nx-sk section update <栏目> --add-field '{"key":"accounts","label":"账号清单","type":"entrylist","fields":[{"key":"url","label":"链接"},{"key":"pass","label":"密码","sensitive":true}]}'
|
|
134
224
|
# 写入:值是行数组(--data 直接给 JSON;--set 认 JSON 串;行键写错当场报,不静默丢)
|
|
135
|
-
nx-sk entry update 张三 --data '{"账号清单":[{"链接":"https://…","
|
|
225
|
+
nx-sk entry update 张三 --data '{"账号清单":[{"链接":"https://…","密码":"…"}]}'
|
|
136
226
|
```
|
|
137
227
|
|
|
138
228
|
面板渲染成密集迷你表(直接增删行);`entry get` 里清单一行一条、带列标签。口径见 [[10-sections-entries]]。
|
|
@@ -154,8 +244,8 @@ nx-sk source ensure # 给老栏目补上这个字段(模板
|
|
|
154
244
|
|
|
155
245
|
面板上:条目表单底部一条**折叠条**「原始资料 · N 条」,点开是右侧抽屉(左清单、中正文),
|
|
156
246
|
文件可拖进去(也给了「选择文件」按钮与粘贴框——拖拽不能是唯一入口,WCAG 2.2 AA)。
|
|
157
|
-
|
|
158
|
-
|
|
247
|
+
三条纪律:**原文不改写**、**不确定就留空**、**敏感内容不进袋**(袋是明文的;
|
|
248
|
+
密码走场景栏目的密文字段,不进袋)。
|
|
159
249
|
|
|
160
250
|
**把袋子里的东西整理成字段**(agent 侧)有配套 skill:
|
|
161
251
|
|
|
@@ -177,8 +267,8 @@ nx-sk skill get sk-pdf # 外部 agent 直接取全文
|
|
|
177
267
|
不装也能用(脚本零依赖,只需 PyMuPDF):
|
|
178
268
|
|
|
179
269
|
```bash
|
|
180
|
-
python
|
|
181
|
-
python
|
|
270
|
+
python ~/.claude/skills/sk-pdf/scripts/pdf_probe.py <pdf> # 先探查:有没有图、是不是扫描件
|
|
271
|
+
python ~/.claude/skills/sk-pdf/scripts/pdf_extract.py <pdf> --out /tmp/pdf-out
|
|
182
272
|
```
|
|
183
273
|
|
|
184
274
|
`sk-pdf` 里记的是真做一份 52 页手册时踩到的坑(图配错步骤、占位符忘换 id、
|
|
@@ -194,20 +284,22 @@ nx-sk setting set --set 'navGroups=[]' # 清空 = 全部栏目恢复平铺
|
|
|
194
284
|
|
|
195
285
|
## ref 路由表(按需加载)
|
|
196
286
|
|
|
197
|
-
| ref
|
|
198
|
-
|
|
|
199
|
-
| `00-design`
|
|
200
|
-
| `10-sections-entries` | **动手填/改信息时必读**——栏目与条目的完整命令、AI 补全个人信息的推荐流程、字段字典怎么扩、读命令与写命令的参数陷阱
|
|
201
|
-
| `20-secrets`
|
|
202
|
-
| `
|
|
203
|
-
| `
|
|
204
|
-
| `
|
|
287
|
+
| ref | 何时读取 |
|
|
288
|
+
| ----------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
289
|
+
| `00-design` | 想搞懂**心智模型**时——栏目=结构、条目=数据、内置字段是什么、动态栏目 + 动态条目怎么用、四个聚合点在哪儿、密文边界,以及**东西该往哪儿放** |
|
|
290
|
+
| `10-sections-entries` | **动手填/改信息时必读**——栏目与条目的完整命令、AI 补全个人信息的推荐流程、字段字典怎么扩、读命令与写命令的参数陷阱 |
|
|
291
|
+
| `20-secrets` | 密文机制、密钥从哪来(环境变量 vs 本机密钥文件)、KV 表的语义、什么时候会解不开 |
|
|
292
|
+
| `30-credentials` | **做凭据自动化时读**——凭据归属哪个栏目、多组账号怎么建清单、跨栏目台账、把凭据渲染成 compose / k8s / .env 的完整流程与安全边界 |
|
|
293
|
+
| `40-files` | **传/换简历头像成绩单等二进制原件时读**——附件库台账、导入(默认移动)与还原、`file` 字段怎么和条目建立链接、附件中心为什么由栏目驱动、看不到上传字段怎么办 |
|
|
294
|
+
| `50-deploy` | **存/取 Dockerfile、docker-compose、k8s 清单时读**——一份配置一个条目的字段约定、`kind` 取值、复用流程(找 → 取正文 → 替换变量 → 落盘)、模板占位符与场景凭据的分工 |
|
|
295
|
+
| `60-transfer` | **搬栏目 / 分享栏目 / 局部迁移时读**——单栏目与全局 bundle 的 ZIP 结构、`transfer export/import/bundle-*` 怎么用、三种冲突策略、附件按 sha256 复用与引用重映射、凭据打码的边界 |
|
|
205
296
|
|
|
206
297
|
取 ref 全文(外部 agent 用这条,不必进终端翻文件):
|
|
207
298
|
|
|
208
299
|
```bash
|
|
209
300
|
nx-sk skill get nx-sk # SKILL.md 全文
|
|
210
301
|
nx-sk skill get nx-sk 10-sections-entries # 裸名 → references/10-sections-entries.md
|
|
302
|
+
nx-sk skill get nx-sk 30-credentials # 凭据自动化:归属 / 台账 / 渲染配置
|
|
211
303
|
nx-sk skill get nx-sk 40-files # 附件库:导入 / 链接 / 还原
|
|
212
304
|
nx-sk skill get nx-sk 50-deploy # 部署配置:存 / 找 / 复用
|
|
213
305
|
nx-sk skill get nx-sk 60-transfer # 栏目 ZIP:导出 / 预览 / 导入
|
|
@@ -236,3 +328,5 @@ nx-sk skill get nx-sk --json # 四元 JSON:{skillName, ref,
|
|
|
236
328
|
- 导出包里是**明文凭据**(`--no-secrets` 已移除,没有「打码导出」);外发时必须
|
|
237
329
|
`--passphrase` 整包加密,且只发给可信对方。
|
|
238
330
|
- **绝不把密钥明文打进日志、提交进 git、或写进给第三方的输出里。**
|
|
331
|
+
「本机就安全」的豁免只到**本机文件**为止:真值渲染进配置文件是可以的,
|
|
332
|
+
但那份文件要么不进 git(`.gitignore` + `.env`),要么只提交占位符版本。
|