nx-sk 0.15.2 → 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 +75 -0
- package/README.md +75 -5
- 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/core/serve-port.js +139 -0
- package/src/modules/entries/service.js +57 -6
- package/src/runtime/cli.js +34 -10
|
@@ -1,117 +1,109 @@
|
|
|
1
|
-
# 00 ·
|
|
1
|
+
# 00 · 设计思想(栏目 / 条目 / 字段)
|
|
2
2
|
|
|
3
|
-
>
|
|
3
|
+
> 归属 `nx-sk` skill 主文档。**想搞懂「这个工具为什么这么设计、东西该往哪儿放」时读这篇。**
|
|
4
|
+
> 怎么调命令看 `10-sections-entries` / `20-secrets` / `30-credentials` / `40-files` / `50-deploy` / `60-transfer`。
|
|
4
5
|
|
|
5
|
-
##
|
|
6
|
+
## 一、一句话:栏目确定结构,条目确定数据
|
|
6
7
|
|
|
7
8
|
```
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
└───────────────┬──────────────────────────┘
|
|
11
|
-
│ 静态面板 + /api
|
|
12
|
-
┌───────────────┴──────────────┬────────────┐
|
|
13
|
-
▼ ▼ │
|
|
14
|
-
Web 面板 HTTP API │
|
|
15
|
-
└──────────────┬───────────────┘ │
|
|
16
|
-
▼ │
|
|
17
|
-
action 声明(唯一真相源) │
|
|
18
|
-
▼ ▼
|
|
19
|
-
service 层(业务) CLI(同一条链)
|
|
20
|
-
▼ │
|
|
21
|
-
core(存储 / 密文 / 字段字典 / 附件 / 渲染) │
|
|
22
|
-
▼
|
|
23
|
-
skill install ──► ~/.claude/skills ──► agent
|
|
9
|
+
栏目(section) = 一张表的**表头**:分组 + 字段(key / 中文标签 / 类型 / 是否密文 / 填写策略)
|
|
10
|
+
条目(entry) = 表里的**一行**:values{ 字段 key: 值 }
|
|
24
11
|
```
|
|
25
12
|
|
|
26
|
-
|
|
13
|
+
- **结构归栏目**:这个栏目有哪些字段,永远只有一个答案,在栏目里。
|
|
14
|
+
- **值归条目**:具体填了什么,只在条目里。
|
|
27
15
|
|
|
28
|
-
|
|
29
|
-
|
|
16
|
+
分开的好处是**结构改一次,所有条目跟着变**(加一个「证书」字段,八十个条目一起多一格,
|
|
17
|
+
不用挨个去补);反过来,**填值永远不需要先改结构**——这是本工具的手感所在。
|
|
30
18
|
|
|
31
|
-
##
|
|
19
|
+
## 二、内置字段:开箱即用的建议清单
|
|
32
20
|
|
|
33
|
-
|
|
34
|
-
core/ 零业务语义:paths / errors / store / fsx / crypto / vault / fields / attachments / render / ids / open
|
|
35
|
-
modules/ 功能域,每个自包含:index.js(声明) + service.js(业务) + view.jsx(面板)
|
|
36
|
-
runtime/ 装配层:registry / spec / cli / api / server —— 不写业务
|
|
37
|
-
web/frontend/ React 壳,只 import 各模块的 view.jsx
|
|
38
|
-
```
|
|
21
|
+
新栏目不从零开始:内置模板直接给出一套**该填什么**的建议字段。
|
|
39
22
|
|
|
40
|
-
|
|
|
23
|
+
| 模板 | 给你的建议字段 |
|
|
41
24
|
| --- | --- |
|
|
42
|
-
| `
|
|
43
|
-
| `
|
|
44
|
-
|
|
|
45
|
-
| `
|
|
25
|
+
| `job` 求职 / 个人信息 | 姓名 / 学历 / 联系方式 / 求职意向 / 附件资料(约 80 个字段,10 个分组) |
|
|
26
|
+
| `projects` / `internships` / `campus` | 一段经历 = 一个条目,角色 / 时间 / 技术栈 / 职责各自独立成字段 |
|
|
27
|
+
| `secret` 密钥 | **只有一列**:键名 → 值(一行一个键值对) |
|
|
28
|
+
| `deploy` 部署配置 | 一份配置文件 = 一个条目:正文 / 放哪 / 哪些值要替换 / **凭据清单** / 何时用 |
|
|
29
|
+
| `platform` 容器平台 | 一个平台 = 一个条目:控制台链接 / 账号 / 密码 / 镜像 / 命名空间 |
|
|
30
|
+
| `thesis` 毕业论文 | 规范里的每条硬指标 = 一个字段(页边距 / 字号 / 图表规范 / 参考文献…) |
|
|
46
31
|
|
|
47
|
-
|
|
48
|
-
|
|
32
|
+
**模板是建议,不是合同**:字段可以改标签、可以删、可以加;栏目建出来之后就**独立演化**,
|
|
33
|
+
模板再变也不会偷偷改你的栏目。模板后来新增的字段用 `nx-sk section sync <栏目>` 补进来
|
|
34
|
+
(**只增不改不删**;面板上是「栏目 → 编辑 → 同步模板字段」)。
|
|
49
35
|
|
|
50
|
-
|
|
51
|
-
|
|
36
|
+
首次运行会**播种 6 个栏目**(求职 / 项目 / 实习 / 校内 / 密钥 / 部署配置),
|
|
37
|
+
另外两个模板(platform / thesis)需要时自己建。
|
|
52
38
|
|
|
53
|
-
##
|
|
39
|
+
## 三、动态栏目 + 动态条目:任何东西都能存
|
|
54
40
|
|
|
55
|
-
|
|
41
|
+
这个工具不预设「你的信息」长什么样。三层都是动态的:
|
|
56
42
|
|
|
57
|
-
|
|
58
|
-
|
|
43
|
+
| 层 | 能做什么 |
|
|
44
|
+
| --- | --- |
|
|
45
|
+
| 栏目 | 想加就加(`section add`),想删就删(`section remove`),能改标题、分组、顺序 |
|
|
46
|
+
| 字段 | 能加(`section update --add-field`)、能删、能改标签与提示 |
|
|
47
|
+
| 条目 | 能加、能改、能删;**每条栏目里的条目形状不同也没关系** |
|
|
59
48
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
- `--set` 的键同时接受 `key` 与中文 `label`,人机都顺手。
|
|
49
|
+
**台账不拦写入**:`entry update --set 任意键=值` 一律能存,字典里没有的键会**自动登记**
|
|
50
|
+
(键名就是它本身,中文也可以,类型按值推断)。
|
|
63
51
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
52
|
+
> 但有一个**义务**:自动登记只保证「值存进去了」,**面板按字段字典渲染**——
|
|
53
|
+
> 没进字典的字段在界面上看不见。所以写完新键,要么让它自动登记成功(看返回里的
|
|
54
|
+
> `createdFields`),要么显式 `section update --add-field` 声明一次。
|
|
67
55
|
|
|
68
|
-
|
|
56
|
+
例外只有一处:**KV 栏目不许加字段**(`secret` 与它的同类)。它的形状就是「一行一个键值对」,
|
|
57
|
+
要加东西就用 `key set <名称> <值>`——见 `20-secrets`。
|
|
69
58
|
|
|
70
|
-
|
|
71
|
-
{ id: 'entry.update', cli: ['entry','update'], http: ['PATCH','/api/entries/:ref'], run, render }
|
|
72
|
-
```
|
|
59
|
+
## 四、值的三种形状(外加附件)
|
|
73
60
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
61
|
+
| 形状 | 什么时候用 | 长什么样 |
|
|
62
|
+
| --- | --- | --- |
|
|
63
|
+
| 标量字段 | 一个值 | 文本 / 数字 / 日期 / 是否 / 多值标签 |
|
|
64
|
+
| **结构清单** `entrylist` | 一个条目挂**多组**结构(多组账号、多条链接) | 行数组,列在字段定义里声明;密码列标 `sensitive` 即密文落盘 |
|
|
65
|
+
| **原始资料袋** `source` | 还没整理的杂乱资料(邮件 / 截图 / 摘录) | 一袋资料条目,**先乱入、后整理** |
|
|
66
|
+
| **附件** `file` | 二进制原件(简历 / 头像 / 证书) | 附件 id 列表,原件在 `~/nx-sk/files/` |
|
|
77
67
|
|
|
78
|
-
|
|
68
|
+
「先乱入、后整理」是刻意留的:真实数据几乎不是一次填对的,没有这个袋子,
|
|
69
|
+
用户只有两个坏选择——把乱数据硬塞进结构化字段(把结构搞脏),或者干脆不存(信息丢了)。
|
|
79
70
|
|
|
80
|
-
|
|
71
|
+
## 五、聚合所有信息
|
|
81
72
|
|
|
82
|
-
|
|
73
|
+
结构可以无限动态,但**信息要能一眼看全**。所以有四个聚合点:
|
|
83
74
|
|
|
84
|
-
|
|
|
75
|
+
| 聚合点 | 命令 | 用途 |
|
|
85
76
|
| --- | --- | --- |
|
|
86
|
-
|
|
|
87
|
-
|
|
|
77
|
+
| 一个栏目的全貌 | `nx-sk section dump <栏目>` | 字段字典 + 全部条目 + 每个条目的完整度与**未填清单** |
|
|
78
|
+
| 跨栏目的凭据台账 | `nx-sk entry keys [--reveal]` | 所有栏目里的 链接 / 账号 / 密码 / 令牌 / 镜像 |
|
|
79
|
+
| 跨栏目的关键字段 | `nx-sk entry fields` | 模板给了什么 + 你实际写过什么(哪些键在用、哪些是死字段) |
|
|
80
|
+
| 整库搬家 | `nx-sk transfer export` / `import` | 一份 ZIP 带全部栏目、条目与附件引用 |
|
|
88
81
|
|
|
89
|
-
|
|
90
|
-
|
|
82
|
+
另外,**头部导航分组**(`settings.navGroups`)把同域栏目收成一个入口——
|
|
83
|
+
但它**只是显示配置**,不动任何栏目与条目数据。
|
|
91
84
|
|
|
92
|
-
##
|
|
85
|
+
## 六、密文边界
|
|
93
86
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
| `INVALID_INPUT` | 输入本身不合法 | 400 |
|
|
97
|
-
| `NOT_FOUND` | 指定的目标不存在 | 404 |
|
|
98
|
-
| `CONFLICT` | 目标存在且与期望状态冲突,需要用户选一侧 | 409 |
|
|
99
|
-
| `BLOCKED` | 操作合法但被前置条件挡住(或密钥不一致) | 409 |
|
|
100
|
-
| `EXTERNAL` | 外部命令/端口失败 | 502 |
|
|
101
|
-
| `INTERNAL` | 兜底 | 500 |
|
|
87
|
+
不是所有字段都一样:**标了 `secret` / `sensitive` 的字段落盘是 AES-256-GCM 密文**,
|
|
88
|
+
读出来默认是原文(自己看的东西不先拦一道),`--mask` 才打码。
|
|
102
89
|
|
|
103
|
-
|
|
90
|
+
- 键名像凭据(密码 / 口令 / 密钥 / 账号 / token / apiKey / accessKey…)时,
|
|
91
|
+
**自动登记出来的字段直接就是密文字段**——「大胆写」不等于「明文裸奔」。
|
|
92
|
+
- 一条场景的凭据写在**那个场景的栏目**里;跨场景通用的 key 才进 `secret` 密钥栏目。详见 `30-credentials`。
|
|
104
93
|
|
|
105
|
-
##
|
|
94
|
+
## 七、给 agent 的三条不变量
|
|
106
95
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
96
|
+
1. **台账不拦写入,但必须登记。** `--set 任意键=值` 一律能存;没见过的键自动进字典,
|
|
97
|
+
否则面板看不见(像「存了却没生效」)。
|
|
98
|
+
2. **面板与 CLI 是同一套业务。** 面板上能做的,CLI 都能做,参数名与错误码两端一致——
|
|
99
|
+
所以「让用户在面板上点一下」和「让 agent 敲一条命令」是同一件事的两面。
|
|
100
|
+
3. **失败抛异常(退出码 1),业务结果返回 `{ status }`(退出码 0)。**
|
|
101
|
+
`conflict` / `blocked` / `skipped` 都是**正常返回**——agent 要看 `status` 字段,
|
|
102
|
+
而不是拿退出码判断失败。把「等用户决策」的冲突当成失败去重试,是这里最容易犯的错。
|
|
103
|
+
|
|
104
|
+
## 八、这份文档不写什么
|
|
105
|
+
|
|
106
|
+
代码怎么分层、接口长什么样、构建怎么跑、工具链怎么配——**那些是开发这个项目的事**,
|
|
107
|
+
装了包也用不上,所以不在这里(它们在项目仓库的 README 里)。
|
|
108
|
+
|
|
109
|
+
这里只回答两件事:**这个工具的心智模型是什么**,以及**你的东西该往哪儿放**。
|
|
@@ -23,16 +23,16 @@ store.json(~/nx-sk/store.json 或 $NX_SK_STORE)
|
|
|
23
23
|
|
|
24
24
|
## 二、栏目命令(集合资源,五操作齐备)
|
|
25
25
|
|
|
26
|
-
| 操作 | 命令 |
|
|
27
|
-
| --- | --- |
|
|
28
|
-
| 列表 | `nx-sk section list` |
|
|
29
|
-
| 单条 | `nx-sk section get <id或标题>` |
|
|
30
|
-
| 新增 | `nx-sk section add <id> --title <标题> --template job` |
|
|
31
|
-
| 修改 | `nx-sk section update <id> [--title …] [--add-field '{…}'] [--remove-field a --remove-field b]` |
|
|
32
|
-
| 删除 | `nx-sk section remove <id> [--force]` |
|
|
33
|
-
| **全量** | `nx-sk section dump <id> [--mask]` |
|
|
34
|
-
| **同步模板** | `nx-sk section sync <id> [--dry-run]` |
|
|
35
|
-
| 模板 | `nx-sk section templates` |
|
|
26
|
+
| 操作 | 命令 |
|
|
27
|
+
| --- | --- |
|
|
28
|
+
| 列表 | `nx-sk section list` |
|
|
29
|
+
| 单条 | `nx-sk section get <id或标题>` |
|
|
30
|
+
| 新增 | `nx-sk section add <id> --title <标题> --template job` |
|
|
31
|
+
| 修改 | `nx-sk section update <id> [--title …] [--add-field '{…}'] [--remove-field a --remove-field b]` |
|
|
32
|
+
| 删除 | `nx-sk section remove <id> [--force]` |
|
|
33
|
+
| **全量** | `nx-sk section dump <id> [--mask]` |
|
|
34
|
+
| **同步模板** | `nx-sk section sync <id> [--dry-run]` |
|
|
35
|
+
| 模板 | `nx-sk section templates` |
|
|
36
36
|
|
|
37
37
|
- **`remove` 在栏目非空时会被 `blocked` 挡住**(除非 `--force`)——防止一键抹掉全部档案。
|
|
38
38
|
- `remove` 目标不存在时**报 `NOT_FOUND`**(不静默成功),就是为了让「打错一个字」当场暴露。
|
|
@@ -45,18 +45,21 @@ store.json(~/nx-sk/store.json 或 $NX_SK_STORE)
|
|
|
45
45
|
这是**只提示、不动手**——因为定义归栏目,你可能就是刻意改过。要换成模板的新定义得手动来:
|
|
46
46
|
`section update <id> --fields '<整份字段数组>'`,或先 `--remove-field` 再 `--add-field`(`--add-field` 遇到同名会报冲突)。
|
|
47
47
|
|
|
48
|
-
内置模板
|
|
48
|
+
内置模板 8 个:`job`(求职 / 个人信息,约 80 字段 / 10 分组——含「附件资料」组:简历附件 / 头像图片 / 成绩单 / 证书扫描件)、`projects`(项目经历)、`internships`(实习/工作经历)、`campus`(校内职务/实践)、`secret`(密钥,**单字段 KV**——细节见 `20-secrets`)、`deploy`(部署配置:Dockerfile / compose / k8s 清单,**一份文件一个条目**,自带「凭据清单」——细节见 `50-deploy`)、`platform`(容器平台:控制台链接 / 账号 / 密码 / 镜像,一个平台一个条目)、`thesis`(毕业论文规范字段化)。三类经历栏目(projects / internships / campus)**一个项目 / 一段经历 = 一个条目**,角色、时间、技术栈都是独立字段——不要往 job 栏目里塞经历。
|
|
49
|
+
|
|
50
|
+
首次运行只**播种 6 个**(job / projects / internships / campus / secret / deploy),
|
|
51
|
+
platform 与 thesis 需要时用 `section add <id> --template platform|thesis` 建。
|
|
49
52
|
|
|
50
53
|
## 三、条目命令
|
|
51
54
|
|
|
52
|
-
| 操作 | 命令 |
|
|
53
|
-
| --- | --- |
|
|
54
|
-
| 列表 | `nx-sk entry list [--section job] [--q 关键字]` |
|
|
55
|
-
| 字段字典 | `nx-sk entry fields [--section job]` |
|
|
56
|
-
| 单条 | `nx-sk entry get <id或名字> [--mask] [--section job]` |
|
|
57
|
-
| 新增 | `nx-sk entry add --section job --set 姓名=张三 [--set 电话=…]` |
|
|
58
|
-
| 修改 | `nx-sk entry update <ref> --set 期望城市=北京、上海 [--unset 微信]` |
|
|
59
|
-
| 删除 | `nx-sk entry remove <ref>` |
|
|
55
|
+
| 操作 | 命令 |
|
|
56
|
+
| --- | --- |
|
|
57
|
+
| 列表 | `nx-sk entry list [--section job] [--q 关键字]` |
|
|
58
|
+
| 字段字典 | `nx-sk entry fields [--section job]` |
|
|
59
|
+
| 单条 | `nx-sk entry get <id或名字> [--mask] [--section job]` |
|
|
60
|
+
| 新增 | `nx-sk entry add --section job --set 姓名=张三 [--set 电话=…]` |
|
|
61
|
+
| 修改 | `nx-sk entry update <ref> --set 期望城市=北京、上海 [--unset 微信]` |
|
|
62
|
+
| 删除 | `nx-sk entry remove <ref>` |
|
|
60
63
|
|
|
61
64
|
### 参数要点
|
|
62
65
|
|
|
@@ -112,6 +115,12 @@ nx-sk entry update 张三 --set 期望行业=互联网 --set 技术博客=https:
|
|
|
112
115
|
|
|
113
116
|
**刻意不推 number**:18 位身份证号这类长数字超过 2^53,推成数字会静默丢精度。
|
|
114
117
|
|
|
118
|
+
**键名像凭据的,自动登记成密文字段**:密码 / 口令 / 密钥 / 账号 / 帐号 / 凭据 / 凭证 /
|
|
119
|
+
token / apiKey / accessKey / secretKey / password / passphrase… 这些词出现在键名里,
|
|
120
|
+
新登记的字段就直接是密文字段(落盘 AES-256-GCM 密文,读出来默认原文)。
|
|
121
|
+
所以「直接写账号密码」是安全的——不必先声明 schema,也不会明文躺在 `store.json` 里。
|
|
122
|
+
完整口径与凭据归属见 `30-credentials`。
|
|
123
|
+
|
|
115
124
|
需要给字段配上候选值 / 提示文案 / 密文标记时,再显式声明:
|
|
116
125
|
|
|
117
126
|
```bash
|
|
@@ -152,6 +161,7 @@ nx-sk section update job --fields @fields.json
|
|
|
152
161
|
> ```
|
|
153
162
|
>
|
|
154
163
|
> 规矩:全空行写入时自动剔除;行里的键必须是声明的清单列(写错当场报,不静默丢);
|
|
164
|
+
> **列名用 key 或中文标签都认**(`密码` 与 `pass` 等价,与顶层 `--set` 同一口径);
|
|
155
165
|
> 没登记过的键直接写行数组会**自动登记**成 entrylist 并从行推断列。`entry get` 里清单一行一条:
|
|
156
166
|
> `名称=主控台 · 链接=https://… · 账号=ops · 密码=…`(--mask 时密码列打码)。
|
|
157
167
|
|
|
@@ -164,7 +174,7 @@ nx-sk section update job --fields @fields.json
|
|
|
164
174
|
> 左清单、中间正文,文件可拖进去(也给了「选择文件」按钮与粘贴框:拖拽不能是唯一入口)。
|
|
165
175
|
> - CLI:`nx-sk source list / get / add / update / remove / ensure`(细节见 `sk-source` skill)。
|
|
166
176
|
> - 三条纪律:**原文不改写**(整理结果写进字段或新的一条)、**不确定就留空**、
|
|
167
|
-
>
|
|
177
|
+
> **敏感内容不进袋**(袋是明文的;密码走**场景栏目里的密文字段**,不进袋也不进密钥栏目)。
|
|
168
178
|
> - 袋**不计完整度**(`fill: optional`):它是暂存区,不是「该填的格子」。
|
|
169
179
|
> - **冲突以新的为准,旧的留痕**:同名即冲突,时间新的那条是「当前版本」,
|
|
170
180
|
> 旧的标「已被取代」但**不删**(原始证据要能翻回去看);`--at` 记资料自身的时间
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# 20 · 密钥(KV)与密文
|
|
2
2
|
|
|
3
3
|
> 归属 `nx-sk` skill 主文档。存/取大模型 API Key、排查「解不开」时读这篇。
|
|
4
|
+
> **场景级的账号密码不在这条线上**——它们写在场景自己的栏目里,见 `30-credentials`。
|
|
4
5
|
|
|
5
6
|
## 一、模型:一张 KV 表
|
|
6
7
|
|
|
@@ -22,6 +23,15 @@
|
|
|
22
23
|
「这个 key 干什么用」写进键名里就够了 —— 存一个 key 不该先填一张表。
|
|
23
24
|
(早期版本有 8 个字段:服务商 / 接口地址 / 模型 / 用途 / 有效期 / 额度 / 备注。实测是负担,已删。)
|
|
24
25
|
|
|
26
|
+
### 这张表放什么、不放什么
|
|
27
|
+
|
|
28
|
+
| 放这儿 | 不放这儿 |
|
|
29
|
+
| --- | --- |
|
|
30
|
+
| **跨场景复用的通用 key**:`OPENAI_KEY`、`GITHUB_TOKEN`、`NPM_TOKEN`…(要 `export` 给各种工具用的那种) | **只服务于一个场景的凭据**:某台服务器的密码、某个平台的账号、某个 compose 的数据库口令 —— 它们写在**那个场景自己的栏目条目**里(密文落盘,读的时候顺带知道是谁的) |
|
|
31
|
+
|
|
32
|
+
判断口径:**处处要用 → 这张表;只属于一个场景 → 场景栏目**。
|
|
33
|
+
完整口径与「场景凭据怎么写、怎么渲染成配置文件」见 `30-credentials`。
|
|
34
|
+
|
|
25
35
|
## 二、四条命令(日常只用这四条)
|
|
26
36
|
|
|
27
37
|
```bash
|
|
@@ -32,20 +42,19 @@ nx-sk key list # 列出所有键(默认原文
|
|
|
32
42
|
nx-sk key remove OPENAI_KEY # 删除(不可撤销,删前先 transfer export)
|
|
33
43
|
```
|
|
34
44
|
|
|
35
|
-
| 命令 |
|
|
36
|
-
| --- | --- |
|
|
37
|
-
| `key list [--mask]` |
|
|
38
|
-
| `key get <名称> [--mask]` |
|
|
39
|
-
| `key set <名称> <值>` |
|
|
40
|
-
| `key remove <名称>` |
|
|
45
|
+
| 命令 | 说明 |
|
|
46
|
+
| --- | --- |
|
|
47
|
+
| `key list [--mask]` | 全部键,按写入顺序 |
|
|
48
|
+
| `key get <名称> [--mask]` | 单个键的值 |
|
|
49
|
+
| `key set <名称> <值>` | **SET 语义**:存在即覆盖 |
|
|
50
|
+
| `key remove <名称>` | 不存在报 `NOT_FOUND`;不可撤销 |
|
|
41
51
|
|
|
42
|
-
四条都接受 `--section
|
|
43
|
-
缺省作用在**标了 `kv` 的那个栏目**上。
|
|
52
|
+
四条都接受 `--section <栏目>`,缺省作用在**标了 `kv` 的那个栏目**上。
|
|
44
53
|
|
|
45
54
|
### 与 `entry` 的关系(重要)
|
|
46
55
|
|
|
47
56
|
`key *` **不是第二套实现**,是 `entry *` 的语法糖:它把「哪个栏目 + 哪个值字段」定好,
|
|
48
|
-
|
|
57
|
+
再走同一套读写流程。所以加解密、`--dry-run` 的行为只有一种,不可能分叉。
|
|
49
58
|
|
|
50
59
|
等价关系:
|
|
51
60
|
|
|
@@ -130,7 +139,7 @@ Git Bash 下裸参数已经能用,但脚本里要可移植的话,仍然推
|
|
|
130
139
|
|
|
131
140
|
## 三、密文机制
|
|
132
141
|
|
|
133
|
-
- 算法 **AES-256-GCM
|
|
142
|
+
- 算法 **AES-256-GCM**。每个值独立 IV,带认证标签。
|
|
134
143
|
- 落盘的密文对象(**明文绝不进 store.json**):
|
|
135
144
|
|
|
136
145
|
```json
|
|
@@ -188,8 +197,12 @@ nx-sk key set OPENAI_KEY sk-xxxxxxxx
|
|
|
188
197
|
|
|
189
198
|
## 五、纪律(写给 agent)
|
|
190
199
|
|
|
191
|
-
-
|
|
192
|
-
|
|
200
|
+
- 默认原文是给**你自己看**的,也是给**你写的脚本**用的(渲染配置、导出模板时要用真值)。
|
|
201
|
+
一旦要把输出交给别人(日志、issue、截图、贴给第三方),先加 `--mask`。
|
|
202
|
+
(`--no-secrets` 已移除:导出包里恒为明文,要防「包被人拿走」用 `--passphrase` 整包加密。)
|
|
203
|
+
- **本机落盘 + 不推送 git = 安全**,不必再自我审查一遍密码本身。
|
|
204
|
+
真正的边界只有三个出口:① 推送到 git / 上传云端;② 打进日志或交给第三方;
|
|
205
|
+
③ 导出包外发(包是明文)。见 `30-credentials` 第五节。
|
|
193
206
|
- 导出文件里 `withSecrets` 字段会明确标出这份文件含不含明文 —— **外发前先看这个字段**。
|
|
194
207
|
- 用户想「把密钥同步到云端」——做不到,也别假装能做到。nx-sk 只在本机落盘与本地导出。
|
|
195
208
|
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
# 30 · 凭据自动化(场景凭据 → 可用配置)
|
|
2
|
+
|
|
3
|
+
> 归属 `nx-sk` skill 主文档。**要存账号密码、要把凭据变成配置文件时读这篇。**
|
|
4
|
+
> 密文机制本身见 `20-secrets`,字段与命令见 `10-sections-entries`。
|
|
5
|
+
|
|
6
|
+
## 一、模型:凭据跟着场景走
|
|
7
|
+
|
|
8
|
+
**一条原则**:凭据存在**它所属的场景**里,不要为了存它去动全局「密钥」栏目。
|
|
9
|
+
|
|
10
|
+
| 凭据 | 归属 | 形状 |
|
|
11
|
+
| --- | --- | --- |
|
|
12
|
+
| 某个云平台 / 容器平台的账号密码 | 该平台所在的栏目条目(`platform` 模板,或自建栏目) | 普通字段(密码列密文) |
|
|
13
|
+
| 某个部署场景的仓库令牌 / 数据库密码 | 该场景的 `deploy` 条目(自带「凭据清单」字段) | 结构清单(一行一组) |
|
|
14
|
+
| 跨场景复用的 API Key(`OPENAI_KEY`…) | `secret` 密钥栏目(KV 表) | 一行一个键值对 |
|
|
15
|
+
| 简历 / 证书原件 | `job` 栏目的 `file` 字段 | 附件 id 列表 |
|
|
16
|
+
|
|
17
|
+
为什么这么分:**凭据的寿命跟着场景**。场景下线了凭据跟着删;场景换了凭据只改一处。
|
|
18
|
+
把所有凭据堆进一个 KV 表,时间一长就分不清「这条是给谁的」——
|
|
19
|
+
到那时唯一的办法是给键名加前缀(`aliyun_prod_password`),那等于把场景结构塞进了键名里。
|
|
20
|
+
|
|
21
|
+
**KV 表仍然有用**:它的定位是「环境变量表」——那些要 `export OPENAI_KEY=…` 的通用 key。
|
|
22
|
+
判断口径:**这条凭据只服务于一个场景 → 场景栏目;处处要用 → 密钥栏目。**
|
|
23
|
+
|
|
24
|
+
## 二、三种写法(按需要挑,不必都学)
|
|
25
|
+
|
|
26
|
+
### 1. 直接写(最常用)——键名像凭据就自动加密
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
nx-sk entry update "阿里云" --section deploy --set 账号=ops@example.com --set 密码='P@ss…'
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
- 键名**在台账里没有**就自动登记;**键名像凭据**(密码 / 口令 / 密钥 / 账号 / 帐号 / 凭据 /
|
|
33
|
+
token / apiKey / accessKey / secretKey / password / passphrase…)就**建成密文字段**。
|
|
34
|
+
- 结果:落盘是 AES-256-GCM 密文(`store.json` 里看不到明文),读出来默认原文。
|
|
35
|
+
- 不像凭据的键(`技术博客`、`端口`)仍然是普通文本字段 —— 不会把整个栏目加密成噪音。
|
|
36
|
+
|
|
37
|
+
**这就是「大胆写」的实现方式**:不需要先声明 schema,密码也不会明文裸奔。
|
|
38
|
+
|
|
39
|
+
### 2. 显式声明密文字段(要固定形状、要出现在面板表单上时)
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
nx-sk section update deploy --add-field '{"key":"registryToken","label":"仓库令牌","type":"secret","group":"cred","hint":"推镜像用的 token"}'
|
|
43
|
+
nx-sk entry update "阿里云" --section deploy --set registryToken=xxxxxxxx
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
`type: 'secret'` 与 `sensitive: true` 等价(后者可用于任意类型)。
|
|
47
|
+
面板会把它渲染成密码框并默认显示原文,可勾选「打码显示」。
|
|
48
|
+
|
|
49
|
+
### 3. 结构清单(一个场景多组账号 / 一份配置多套凭据)
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
# 自建栏目:先建栏目,再声明「凭据清单」字段
|
|
53
|
+
nx-sk section add mycloud --title "我的云平台"
|
|
54
|
+
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},{"key":"note","label":"备注"}]}'
|
|
55
|
+
|
|
56
|
+
nx-sk entry update "阿里云" --section mycloud --data '{"凭据清单":[{"名称":"控制台","账号":"ops","密码":"P@ss…"},{"名称":"镜像仓库","账号":"ci","令牌":"tok-…"}]}'
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
> `deploy` 模板**自带**这个字段(分组「凭据」),直接用即可;
|
|
60
|
+
> 老栏目用 `nx-sk section sync deploy` 补上。`--add-field` 遇到**同名**字段会报冲突 ——
|
|
61
|
+
> 那说明这个栏目已经有了,换个 key 或删了重加。
|
|
62
|
+
|
|
63
|
+
- 行里的列名**用 key 或中文标签都认**(`密码` 与 `pass` 等价);写错的列当场报错,不静默丢。
|
|
64
|
+
- 声明 `sensitive: true` 的列与顶层敏感字段同一条边界:密文落盘、`--mask` 打码。
|
|
65
|
+
|
|
66
|
+
## 三、跨栏目台账
|
|
67
|
+
|
|
68
|
+
凭据散在各个栏目里,用这一条命令对账:
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
nx-sk entry keys # 全部栏目;值默认打码
|
|
72
|
+
nx-sk entry keys --reveal # 明文(喂脚本 / 给自己看)
|
|
73
|
+
nx-sk entry keys --section deploy # 限定栏目
|
|
74
|
+
nx-sk entry keys --q 密码 # 关键字过滤(栏目/条目/字段/值)
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
命中规则:字段 key / label 命中「链接 / 账号 / 密码 / 令牌 / 镜像」启发式,
|
|
78
|
+
或字段类型是 `secret` / 标了 `sensitive`。值策略:链接类明文、账号密码令牌类打码(`--reveal` 才出原文)。
|
|
79
|
+
|
|
80
|
+
**改密码 / 找入口 / 迁移机器前,先跑一遍 `entry keys`** —— 少一把就少一个惊喜。
|
|
81
|
+
|
|
82
|
+
## 四、把凭据渲染成配置文件(主用途)
|
|
83
|
+
|
|
84
|
+
用户要 compose / k8s / .env / Dockerfile 时,**直接给成品**,不要只给模板让人自己填。
|
|
85
|
+
|
|
86
|
+
### 标准流程
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
# ① 取真值(密文字段自动解密;--mask 反而会挡住你)
|
|
90
|
+
nx-sk entry get "阿里云" --section deploy --json > /tmp/e.json
|
|
91
|
+
|
|
92
|
+
# ② 渲染:模板正文里的 ${VAR} 用这个场景的凭据替换
|
|
93
|
+
node assets/nx-sk/scripts/render-config.js /tmp/e.json ./docker-compose.local.yml
|
|
94
|
+
|
|
95
|
+
# ③ 真值副本另存一份 .env(同样不进 git)
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
脚本的规则:`creds` 里每行的**「名称」= 变量名**(值取密码 / 令牌 / 账号);
|
|
99
|
+
条目其它**标量**字段按**字段 key** 也当变量;正文取 `content`;
|
|
100
|
+
占位符支持 `${VAR}` 与 `${VAR:-默认值}`。跑完会报**替换了哪些、哪些没解析**
|
|
101
|
+
(没解析通常是「名称」与占位符名没对齐)。已装 skill 的话脚本在
|
|
102
|
+
`~/.claude/skills/nx-sk/scripts/render-config.js`。
|
|
103
|
+
|
|
104
|
+
> 为什么是脚本而不是一行 `node -e`:**多行 `node -e` 在 Windows 终端里会被吃掉引号**
|
|
105
|
+
> (实测是「静默不执行、退出码 0」)。渲染这段逻辑固化成文件才跑得稳 ——
|
|
106
|
+
> 跟 20-secrets 里「多行值走 stdin / @文件」是同一个坑的两面。
|
|
107
|
+
|
|
108
|
+
### 模板(进 git)与实例(不进 git)的分工
|
|
109
|
+
|
|
110
|
+
| | 内容 | 去处 |
|
|
111
|
+
| --- | --- | --- |
|
|
112
|
+
| **模板** | `content` 正文里写 `${VAR}` 占位;`vars` 列出每个变量该填什么 | 可复用、可分享、进仓库 |
|
|
113
|
+
| **实例** | 占位符换成本场景真值 | 本机文件,**不进仓库** |
|
|
114
|
+
|
|
115
|
+
`content` 是**会被复制进别人项目**的东西,所以里面只放占位符;
|
|
116
|
+
真值放在同一个条目的「凭据清单」里(密文落盘),出实例时现场替换。
|
|
117
|
+
这不是「怕明文」,是**模板与实例本来就是两种东西**。
|
|
118
|
+
|
|
119
|
+
### 仓库里该怎么提交
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
# 提交的:占位符版本 + 示例
|
|
123
|
+
docker-compose.yml # 里 ${REGISTRY_TOKEN} / ${DB_PASSWORD}
|
|
124
|
+
.env.example # 键名齐全,值留空
|
|
125
|
+
# 不提交的(.gitignore 里盖住)
|
|
126
|
+
.env
|
|
127
|
+
docker-compose.local.yml
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
`.gitignore` 至少盖住:`.env`、`.env.*`(但放行 `.env.example`)、`*.local.yml`、
|
|
131
|
+
以及 nx-sk 自己的 `store.json` / `.vaultkey` / `.vaultsalt`。
|
|
132
|
+
|
|
133
|
+
## 五、安全边界:只有三个出口
|
|
134
|
+
|
|
135
|
+
本机单人工具,密文落盘、面板只听 `127.0.0.1`、数据在仓库之外。
|
|
136
|
+
所以「敢不敢大胆写」的答案取决于**这三个出口有没有开**:
|
|
137
|
+
|
|
138
|
+
| 出口 | 判断 | 动作 |
|
|
139
|
+
| --- | --- | --- |
|
|
140
|
+
| **推送到 git / 上传云端** | 真值进了版本库 = 凭据公开 | 仓库里只放占位符 + `.env.example`;真值文件加进 `.gitignore` |
|
|
141
|
+
| **打进日志 / issue / 聊天 / 给第三方的输出** | 明文离开本机 | 输出前 `--mask`,或手工替换;导出包外发必须 `--passphrase` |
|
|
142
|
+
| **导出包外发** | 包里是**明文凭据**(没有打码导出选项) | `nx-sk transfer export <栏目> --passphrase 口令` 整包加密,只发给可信对方 |
|
|
143
|
+
|
|
144
|
+
没开这三个出口时,**不必再自我审查一遍密码本身**:
|
|
145
|
+
本机文件里带真值是正常的,`--mask` 是给「投屏 / 截图 / 贴给别人看」用的,不是给「自己用」用的。
|
|
146
|
+
|
|
147
|
+
## 六、常见场景怎么放
|
|
148
|
+
|
|
149
|
+
| 场景 | 放哪 | 大致写法 |
|
|
150
|
+
| --- | --- | --- |
|
|
151
|
+
| 云平台(阿里云 / 腾讯云 / AWS) | 自建栏目「云平台」,或 `platform` 模板 | `--set 账号=… --set 密码=… --set AccessKeyId=… --set AccessKeySecret=…`(后两个自动加密) |
|
|
152
|
+
| 容器平台(KubeSphere / Rancher) | `platform` 模板 | 控制台链接 / 账号 / 密码 / 命名空间 / 镜像 |
|
|
153
|
+
| 镜像仓库 | `deploy` 条目的凭据清单 | 名称 `registry`、账号、令牌 |
|
|
154
|
+
| 数据库 / 中间件 | `deploy` 条目的凭据清单 | 名称 `mysql`、账号、密码 |
|
|
155
|
+
| 大模型 API | `secret` 密钥栏目 | `nx-sk key set OPENAI_KEY sk-…`(跨场景复用) |
|
|
156
|
+
| CI / 发布凭据 | `deploy` 条目的凭据清单 | 名称 `ci`、账号、令牌 |
|
|
157
|
+
|
|
158
|
+
## 七、排查
|
|
159
|
+
|
|
160
|
+
| 症状 | 原因 | 处理 |
|
|
161
|
+
| --- | --- | --- |
|
|
162
|
+
| 写进去的值在 `store.json` 里能搜到明文 | 键名不像凭据(`pwd` 之外的自由词) | 声明一个密文字段重写,或把键名改成带 `密码/token/口令` 的 |
|
|
163
|
+
| `BLOCKED 当前密钥与写入时的密钥不一致` | 换了口令 / 删了 `.vaultkey` | 见 `20-secrets` 第四节 |
|
|
164
|
+
| 值被拒:「收到的是打码占位而非明文」 | 把 `--mask` 后的串写回去了 | 传完整值,或什么都不传(= 不修改) |
|
|
165
|
+
| 面板里看不到刚写的字段 | 字段没进台账(老栏目 + 模板后加) | `nx-sk section sync <栏目>` |
|
|
166
|
+
| 渲染出来的配置里 `${VAR}` 没替换 | 凭据清单里的「名称」与占位符名不一致 | 名称对齐(`${REGISTRY_TOKEN}` ↔ 名称 `REGISTRY_TOKEN`) |
|
|
@@ -20,16 +20,16 @@
|
|
|
20
20
|
|
|
21
21
|
## 二、命令
|
|
22
22
|
|
|
23
|
-
| 操作 | 命令 |
|
|
24
|
-
| --- | --- |
|
|
25
|
-
| 列表 | `nx-sk file list [--section job] [--q 关键字]` |
|
|
26
|
-
| 单条 | `nx-sk file get <id>` |
|
|
27
|
-
| 导入 | `nx-sk file add --path <本机文件>` |
|
|
28
|
-
| 改属性 | `nx-sk file update <id> [--name …] [--tags …] [--note …]` |
|
|
29
|
-
| 取本体 | `nx-sk file content <id> [--download]` |
|
|
30
|
-
| 打开 | `nx-sk file open <id>`(本机默认程序) |
|
|
31
|
-
| 还原 | `nx-sk file restore <id> [--to DIR] [--copy]` |
|
|
32
|
-
| 删除 | `nx-sk file remove <id>` |
|
|
23
|
+
| 操作 | 命令 |
|
|
24
|
+
| --- | --- |
|
|
25
|
+
| 列表 | `nx-sk file list [--section job] [--q 关键字]` |
|
|
26
|
+
| 单条 | `nx-sk file get <id>` |
|
|
27
|
+
| 导入 | `nx-sk file add --path <本机文件>` |
|
|
28
|
+
| 改属性 | `nx-sk file update <id> [--name …] [--tags …] [--note …]` |
|
|
29
|
+
| 取本体 | `nx-sk file content <id> [--download]` |
|
|
30
|
+
| 打开 | `nx-sk file open <id>`(本机默认程序) |
|
|
31
|
+
| 还原 | `nx-sk file restore <id> [--to DIR] [--copy]` |
|
|
32
|
+
| 删除 | `nx-sk file remove <id>` |
|
|
33
33
|
|
|
34
34
|
- `file list --section <栏目>` 只看「被某栏目引用」的附件;`--section none` 只看**还没有任何条目引用**的。
|
|
35
35
|
- `file content` 是浏览器链接:内联预览,加 `--download` 强制下载;CLI 侧打印物理路径与链接。
|