c456-cli 0.1.6 → 0.3.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.
@@ -0,0 +1,129 @@
1
+ # 私人知识库:用 AI 客户端使用 C456
2
+
3
+ 下文前几节先把 **c456.com 账号**、本机 `**c456` 命令**、以及两个 **Agent 技能**装好,让 **Cursor / OpenCode / Trae / Claude Code** 里的 AI 能按规范代你操作 C456 与本地 Wiki;第 4 节是**第一次**在本文件夹当知识库时的初始化口令。
4
+
5
+ **日常用法**:在客户端里**用对话说明意图**即可;**第一次**把某个文件夹当 C456 知识库用时,须先按第 4 节用口令初始化目录。需要访问 c456.com 时,由 Agent 在本机调用已安装的 `c456`(你不必自己背命令)。**要和线上对齐时,用下面两句口令之一即可**(可按需补充范围,例如「只同步刚改的那几页」)。想深究目录与同步规则,再点开文末技能链接。
6
+
7
+ ---
8
+
9
+ ## 1. 账号(必须)
10
+
11
+ 1. 打开 [https://c456.com](https://c456.com) 注册并登录。
12
+ 2. 在站内创建 **API Key / 访问令牌**,复制保存(一般只显示一次)。
13
+
14
+ ---
15
+
16
+ ## 2. 安装命令行(全局执行即可)
17
+
18
+ ```bash
19
+ npm install -g c456-cli
20
+ ```
21
+
22
+ 写入密钥(把 `<密钥>` 换成上一步复制的):
23
+
24
+ ```bash
25
+ c456 config set-key <密钥>
26
+ ```
27
+
28
+ 检查:
29
+
30
+ ```bash
31
+ c456 config show
32
+ c456 --help
33
+ ```
34
+
35
+ ---
36
+
37
+ ## 3. 安装两个技能(在「知识库项目」文件夹里执行)
38
+
39
+ 先进入你要当知识库根目录的文件夹(没有就 `mkdir` 一个再 `cd` 进去):
40
+
41
+ ```bash
42
+ cd /path/to/your-kb-project
43
+ ```
44
+
45
+ 依次执行(需要本机能跑 `npx`,会用到 [Skills CLI](https://skills.sh/)):
46
+
47
+ ```bash
48
+ npx skills add baklib-tools/skills --skill karpathy-wiki -y
49
+ npx skills add xiaohui-zhangxh/c456-cli --skill c456-llm-wiki -y
50
+ ```
51
+
52
+ ---
53
+
54
+ ## 4. 首次:初始化当前目录(第一次把本文件夹当 C456 知识库时)
55
+
56
+ 技能装好后,**第一次**在本机用某个文件夹承载 C456 知识库时,需要先让 Agent 按 **c456-llm-wiki** 把目录结构初始化好(例如对齐 `raw/`、`wiki/`、`c456-sync/` 等约定,具体以技能正文为准)。
57
+
58
+ 做法:
59
+
60
+ 1. 用 **Cursor / OpenCode / Trae / Claude Code** 打开你的知识库项目根目录(与上一步 `cd` 的文件夹一致)。
61
+ 2. 在 AI 对话里直接说下面这句(可照抄):
62
+
63
+ ```
64
+ 基于 c456-llm-wiki 初始化当前目录
65
+ ```
66
+
67
+ Agent 会按技能在该知识库项目根目录下创建或补齐所需目录与约定;完成后再按第 5 节日常放 `raw/`、对话操作即可。若该目录**早已**按技能初始化过,可跳过本节。
68
+
69
+ ---
70
+
71
+ ## 5. 装好后怎么用
72
+
73
+ 1. 用 **Cursor / OpenCode / Trae / Claude Code** 打开你的知识库项目文件夹(若尚未初始化,先完成第 4 节)。
74
+ 2. 把资料放进 `**raw/`**(路径按技能约定即可)。
75
+ 3. 在对话里直接说你要做什么(见下一节**可复制示例**)。Agent 会按 **karpathy-wiki**、**c456-llm-wiki** 与 **c456-cli** 技能,在本机执行 `c456`、维护 `wiki/` 与 `c456-sync/` 等;你主要负责说清楚意图与确认结果。
76
+ 4. **需要同步内容时**,对 AI 说下面之一即可(字可以照抄):
77
+ - **把本地推到线上**:「**同步内容到 C456。**」
78
+ - **把线上拉回本地**:「**从 C456 同步内容。**」
79
+
80
+ 若你坚持自己敲终端命令,见 [c456-cli README](https://github.com/xiaohui-zhangxh/c456-cli#常用命令)。
81
+
82
+ ---
83
+
84
+ ## 6. 使用例子(复制到 AI 对话里)
85
+
86
+ 以下整段复制到客户端输入框即可(把路径或网址换成你的)。
87
+
88
+ ### 例子 1:收录 `raw/` 里的内容
89
+
90
+ ```
91
+ 整理 raw/articles/我的笔记.md
92
+ ```
93
+
94
+ ### 例子 2:收录 baklib.com 这个产品
95
+
96
+ ```
97
+ 收录 Baklib 这个产品,同步到 C456。
98
+ ```
99
+
100
+ ### 例子 3:记下对 fly.io 界面设计的喜欢
101
+
102
+ ```
103
+ https://fly.io/ 的界面设计我很喜欢,请记下来:写成一条以后做产品可以借鉴的笔记,更新 wiki;同步内容到 C456。
104
+ ```
105
+
106
+ ### 例子 4:只做同步(不说别的)
107
+
108
+ 把本地已整理好的内容推到线上:
109
+
110
+ ```
111
+ 同步内容到 C456。
112
+ ```
113
+
114
+ 把线上最新状态拉回本地镜像与 wiki:
115
+
116
+ ```
117
+ 从 C456 同步内容。
118
+ ```
119
+
120
+ ---
121
+
122
+ ## 7. 链接(想细看再点开)
123
+
124
+ - [c456.com](https://c456.com)
125
+ - [c456-cli 仓库与 README](https://github.com/xiaohui-zhangxh/c456-cli)
126
+ - [Karpathy Wiki 技能(目录与约定)](https://github.com/baklib-tools/skills/tree/main/skills/karpathy-wiki)
127
+ - [c456-llm-wiki 技能(与 C456 双向同步)](https://github.com/xiaohui-zhangxh/c456-cli/tree/main/skills/c456-llm-wiki)
128
+
129
+ 上游安装命令若变更,以对应仓库页面为准。
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "c456-cli",
3
- "version": "0.1.6",
3
+ "version": "0.3.0",
4
4
  "description": "C456 CLI - 内容录入与整理工具",
5
5
  "type": "module",
6
6
  "bin": {
@@ -8,6 +8,8 @@
8
8
  },
9
9
  "files": [
10
10
  "dist",
11
+ "docs",
12
+ "skills",
11
13
  "README.md"
12
14
  ],
13
15
  "scripts": {
@@ -0,0 +1,118 @@
1
+ ---
2
+ name: c456-cli
3
+ description: >-
4
+ Operates C456 via the c456 Node CLI (HTTP API v1): intakes, playbooks,
5
+ assets (media library), search, fetch, and config. Use when the user mentions C456, c456-cli, 收录,
6
+ 打法, intake, playbook, c456.com, or syncing content with a self-hosted C456.
7
+ ---
8
+
9
+ # C456 CLI(c456-cli)
10
+
11
+ 在终端通过 **`c456`** 调用 C456 的 **HTTP API v1**,供 Agent 将内容写入/查询 C456,而无需在对话中手写原始 REST 细节。
12
+
13
+ ## 安装 CLI
14
+
15
+ 未安装时可用 **`npx c456-cli …`** 或 **`bunx c456-cli …`**;已全局安装则直接 **`c456`**。
16
+
17
+ ## 安装本技能(给其他仓库)
18
+
19
+ 在目标项目根目录执行(按需加 `-g` 装到用户目录、`--agent cursor` 指定客户端):
20
+
21
+ ```bash
22
+ npx skills add xiaohui-zhangxh/c456-cli --skill c456-cli -y
23
+ ```
24
+
25
+ 若已克隆 [c456-cli](https://github.com/xiaohui-zhangxh/c456-cli) 仓库,可在该仓库根目录:
26
+
27
+ ```bash
28
+ npx skills add . --skill c456-cli -y
29
+ ```
30
+
31
+ 列出远程包内可用技能而不安装:`npx skills add xiaohui-zhangxh/c456-cli -l`
32
+
33
+ ## 鉴权与站点
34
+
35
+ | 方式 | 说明 |
36
+ | --- | --- |
37
+ | **API Key** | `c456 config set-key <token>` 或环境变量 **`C456_API_KEY`** |
38
+ | **站点根 URL** | 默认 `https://c456.com`;自托管用 **`c456 config set-url <url>`**、**`C456_URL`**,或单次命令 **`c456 -B <url> …`** |
39
+
40
+ **短选项冲突**:子命令里的 **`-k` 表示收录类型(kind)**,**不要**用 `-k` 传 API Key。Key 仅通过 `config` / `C456_API_KEY`。
41
+
42
+ **`-B` 与 `-u`**:根级 **`-B` / `--base-url`** 表示 **C456 站点根地址**;`intake` 等子命令里的 **`-u` 常表示「目标资源 URL」**(如 tool/channel 的链接),不要混用。
43
+
44
+ ## Agent 执行方式
45
+
46
+ 1. 需要真实读写 C456 时,在沙箱/终端中运行 `c456` 子命令,并解析其标准输出(含部分命令附带的 `--- JSON ---` 段)。
47
+ 2. 非交互场景为 `intake delete` 等加 **`-f` / `--force`**,避免等待终端确认(删除前仍应确认用户意图)。
48
+ 3. 勿在日志或回复中回显完整 API Key。
49
+ 4. **严禁编造参数**:只能使用 `c456 <command> --help`(或本仓库源码/文档)明确存在的选项;不确定时先运行 `--help` 再行动。
50
+ 5. **严禁重复创建**:若 `intake new` / `playbook new` 输出了 `ID:` 或 `--- JSON ---`(含 `id`),视为已成功创建,后续只能 `show <id>` / `update <id>`,不得再次 `new` 重试(避免重复发布两条)。
51
+ 6. **内容一律用文件传入**:创建/更新正文等长文本时,不要在命令行直接写内容(避免引号/换行/转义错误)。必须把内容写到**当前工作目录**的 `.tmp/` 下临时文件,再用 `--body-file` / `--summary-file` 传入。
52
+ 7. **自媒体账号默认收录为渠道**:用户要收录 **YouTube / 抖音 / 小红书 / B 站 / 微博** 等**自媒体账号主页或频道**时,**默认使用 `c456 intake new -k channel`**(不要用 `-k tool`),并配合 `-u <主页或频道 URL>`;需要服务端按 URL 自动填资料段时再加 `--auto-resolve-url`。仅做「不落库的 URL 资料预览/抓取」时用 `c456 fetch profile -p social_account -u "<url>"`。
53
+ 8. **渠道(及 tool)必须带至少一条「资料」**:`-k channel` 或 `-k tool` 时,服务端要求 **profile_data 里至少有一条资料段**(例如主页 **URL**、**媒体账号** 等对应 facet),常见做法是 `-u <url>` 并加 **`--auto-resolve-url`** 让服务端生成资料段;如需手写 **`--profile-data-json`**,**必须先阅读** [references/intake-profile-data-json.md](references/intake-profile-data-json.md)(含各 `profile_id`、必填字段与最小 JSON 示例)。**不能只写标题/正文而不提供 URL/资料段**,否则会 **422 校验失败**(提示含「至少添加一个资料段或图标」等)。
54
+ 9. **素材库与列表图标**:上传、插入正文、设置 tool/channel 列表图标(`list_icon_url`)见 [references/media-library-and-icons.md](references/media-library-and-icons.md);CLI:`c456 asset …`、`c456 intake update … --profile-data-json-file`。
55
+
56
+ ## 命令速查
57
+
58
+ **配置**
59
+
60
+ - `c456 config set-key <token>` / `c456 config set-url <url>` / `c456 config show` / `c456 config reset`
61
+
62
+ **收录 `intake`**
63
+
64
+ - 新建:`c456 intake new [-k signal|tool|channel] [-u <url>] [--auto-resolve-url] [--profile-data-json '<json>'] [-t 标题] [--body-file <path>]`(`profile_data` 结构见 [references/intake-profile-data-json.md](references/intake-profile-data-json.md);长 JSON 建议写入 `.tmp/` 再用 `"$(cat .tmp/profile.json)"` 传入)
65
+ - 查看 / 更新 / 删除 / 列表:`c456 intake show <id>` · `c456 intake update <id> …`(支持 **`--profile-data-json`** / **`--profile-data-json-file`** 合并更新 tool/channel 的 `profile_data` 或仅 `list_icon_url`) · `c456 intake delete <id> [-f]` · `c456 intake list [-k] [-q] [-p 页] [-n 每页]`
66
+
67
+ `--auto-resolve-url` 说明:
68
+
69
+ - **默认不解析**:`-u/--url` 只保存为 URL 输入;服务端不会默认生成资料段。
70
+ - **显式开启才解析**:当 `-k tool|channel` 且传入 `--auto-resolve-url` 时,服务端会尝试检测平台并回填 `profile_data`(可能导致校验失败/成功与否不同;会发起网络请求)。
71
+
72
+ **搜索 `search`**
73
+
74
+ - `c456 search signals -q "…" [-k kind] [-l n]`
75
+ - `c456 search playbooks -q "…" [-l n]`
76
+
77
+ **打法 `playbook`**
78
+
79
+ - 新建:`c456 playbook new -t "标题" [--body-file <path>] [--ref-intake id …] [--ref-playbook id …]`
80
+ - 另有 `show` / `list` / `update` / `delete`(与 `c456 playbook --help` 一致)
81
+
82
+ **素材库 `asset`**
83
+
84
+ - `c456 asset upload -f <path>` · `list` · `show <id>` · `update <id> --filename <名>` · `delete <id>` · `refresh-markdown` · `fingerprint`(插图与图标流程见 [references/media-library-and-icons.md](references/media-library-and-icons.md))
85
+
86
+ **资料 `fetch`**
87
+
88
+ - `c456 fetch profile -u <url> -p <profile_id>`(`profile_id` 必填;否则 API 返回「不支持的资料类型」)
89
+
90
+ `profile_id` 类型含义:
91
+
92
+ - `link_product`:产品/官网等普通链接页(解析 name/icon/description)
93
+ - `package_registry`:软件包页(npm、RubyGems 等)
94
+ - `github_origin`:代码仓库(GitHub/GitLab/Gitee)
95
+ - `social_account`:社交账号主页/频道(YouTube/抖音/小红书等)
96
+
97
+ ## 更完整的说明
98
+
99
+ 见各命令的 `--help` 与本仓库 `README.md`、`DEVELOPMENT.md`。
100
+
101
+ ### 分页参数(list 类命令)
102
+
103
+ - `-p, --page`: **1-10000**
104
+ - `-n, --per-page`: **1-100**(默认 20;服务端会截断到最大值)
105
+
106
+ ### 内容语法(富文本)
107
+
108
+ CLI `--help` 中会用 `type: <type_name>` 标注字段类型;Agent 在生成/写入内容时,必须按下表选择语法与约束:
109
+
110
+ - `markdown_kramdown` → [references/content-syntax-kramdown.md](references/content-syntax-kramdown.md)(与 `SKILL.md` 同级目录下,随 `npx skills add` 一并安装)
111
+
112
+ ### 收录最佳实践
113
+
114
+ - **自媒体 / 社交账号**(主页、频道页):**一律按渠道收录** → `-k channel`;抖音场景补充说明见 [references/douyin-channel-intake.md](references/douyin-channel-intake.md)。
115
+ - **渠道 / 工具**:新建时务必带上 **至少一种结构化资料**(常见:`-u` + `--auto-resolve-url`,或 `--profile-data-json`),否则服务端会因缺少资料段而拒绝保存。
116
+ - **`--profile-data-json`**:键名与校验规则与 Web 端一致,**不要编造字段**;完整说明与示例见 [references/intake-profile-data-json.md](references/intake-profile-data-json.md)(优先自动解析,其次再手写)。**仅改列表图标**见 [references/media-library-and-icons.md](references/media-library-and-icons.md)。
117
+ - **软件 / 产品 / 仓库 / 包页**:一般用 `-k tool`(或用户明确要当「工具资料」收录时)。
118
+
@@ -0,0 +1,80 @@
1
+ ## 内容语法(Kramdown Markdown)
2
+
3
+ 本文件定义:通过 **c456 HTTP API v1** 写入的富文本字段(例如 `body`)应使用的**内容语法**。
4
+
5
+ ### 总原则
6
+
7
+ - **一律使用 Markdown 字符串**作为富文本内容(例如 `body`)。
8
+ - **基线语法**:Kramdown 风格 Markdown(与 c456 Web 端编辑器/展示端实现对齐)。
9
+ - **不要依赖任意 HTML** 来实现排版或交互;展示端会做 HTML 净化(sanitize),未在白名单内的标签/属性可能被剥离或失效。
10
+
11
+ ### 支持的 Markdown 能力(白名单)
12
+
13
+ #### 1) GFM(GitHub Flavored Markdown)常见子集
14
+
15
+ 我们支持与 `remark-gfm` / 编辑器常见能力对齐的子集,包括:
16
+
17
+ - 标题:`#` ~ `######`
18
+ - 段落、换行
19
+ - 强调:`**bold**`、`*italic*`
20
+ - 删除线:`~~text~~`
21
+ - 行内代码与代码块:反引号与 fenced code(```)
22
+ - 引用:`>`
23
+ - 列表:有序/无序
24
+ - 链接/图片:`[label](url)`、`![alt](url)`
25
+ - 表格:GFM table
26
+ - 任务列表:`- [ ]` / `- [x]`
27
+ - 裸链:
28
+ - `https://...` 纯文本链接会被识别为可点击链接
29
+ - `<https://...>` 形式也可用
30
+
31
+ #### 2) Kramdown 块级 IAL(Inline Attribute List)
32
+
33
+ 支持 **kramdown 风格块级 IAL**:把属性写在“紧跟某个块之后”的单独一行里,用于对齐与图片尺寸。
34
+
35
+ - 语法:`{: align=center width=120 height=120}`
36
+ - 关键约束:`{` 与 `:` 之间 **不得有空格**(必须是 `{: ...}`)
37
+ - 绑定规则:IAL 行绑定到**上一段/上一标题**
38
+ - 支持的 key:
39
+ - `align`:`left | center | right | justify`
40
+ - `width` / `height`:数字字符串(可带 `px`)
41
+
42
+ 示例:
43
+
44
+ ```markdown
45
+ 这一段将居中。
46
+ {: align=center}
47
+
48
+ ![logo](https://example.com/logo.png)
49
+ {: width=120 height=120}
50
+ ```
51
+
52
+ #### 3) 扩展:`:::walkthrough{...}` 指令块
53
+
54
+ 支持用容器指令在 Markdown 中嵌入 Walkthrough 播放器块:
55
+
56
+ ```markdown
57
+ :::walkthrough{id=42}
58
+ :::
59
+
60
+ :::walkthrough{url="https://asciinema.org/a/abc123"}
61
+ :::
62
+
63
+ :::walkthrough{cast-src="https://example.com/x.cast" title="演示" cols=100 rows=28}
64
+ :::
65
+ ```
66
+
67
+ 属性白名单(其余键会被丢弃,不会注入到 DOM):
68
+
69
+ - `id`:数字(仅标记,渲染时不查库)
70
+ - `url`:仅允许 `https://asciinema.org/a/...`
71
+ - `cast-src`:已解析的 `.cast` URL(`https?://...`)
72
+ - `title` / `summary`:展示文案(会被截断)
73
+ - `cols` / `rows`:终端尺寸(1~4 位数字)
74
+
75
+ ### AI/脚本写入约定
76
+
77
+ - 当字段语义为“富文本/正文/说明”(如 `body`),默认输出 **Markdown(Kramdown + 白名单扩展)**。
78
+ - 不要输出 HTML 作为正文内容(除非是 `:::walkthrough` 这类受控扩展语法的序列化结果)。
79
+ - 需要对齐/尺寸时,优先用 `{: ...}` 块级 IAL,不要用内联 `style`。
80
+
@@ -0,0 +1,65 @@
1
+ # 社交账号(抖音)收录为渠道的最佳路径
2
+
3
+ ## 路径概述
4
+
5
+ 将社交账号(以抖音为例)收录为 `channel` 类型的标准流程。
6
+
7
+ ## 步骤
8
+
9
+ ### 1. 获取准确的账号主页链接
10
+
11
+ 确保拿到的是 **用户主页 URL**,而非单个视频链接。例如:
12
+
13
+ ```
14
+ https://www.douyin.com/user/MS4wLjABAAAAjb1juHnK9tygA0nuoGgSEMW7ZuJzXNnTMx9XwaQh19k
15
+ ```
16
+
17
+ ### 2. 执行创建命令
18
+
19
+ ```bash
20
+ c456 intake new \
21
+ -k channel \
22
+ -u "<抖音主页链接>" \
23
+ --auto-resolve-url \
24
+ -t "<账号昵称>抖音账号"
25
+ ```
26
+
27
+ **参数要点:**
28
+
29
+ | 参数 | 作用 | 建议 |
30
+ |---|---|---|
31
+ | `-k channel` | 指定收录类型为「渠道」 | 社交账号统一用 `channel` |
32
+ | `-u` | 目标资源 URL | 填完整主页链接 |
33
+ | `--auto-resolve-url` | 服务端自动解析账号资料 | **必加**,自动抓取昵称、头像、粉丝数等 |
34
+ | `-t` | 标题 | 建议用「昵称 + 平台」格式 |
35
+
36
+ ### 3. 确认解析结果
37
+
38
+ ```bash
39
+ c456 intake show <ID>
40
+ ```
41
+
42
+ 开启 `--auto-resolve-url` 后,服务端会自动回填 `profile_data`,通常包含:
43
+
44
+ - 昵称、头像、抖音号
45
+ - 粉丝数、获赞数、作品数、关注数
46
+ - 个人简介 / 签名
47
+ - 其他平台信息(如 IP 属地、直播时间等)
48
+
49
+ ### 4. 后续补充正文(按需)
50
+
51
+ 如需补充分析内容、打法或观察笔记:
52
+
53
+ ```bash
54
+ c456 intake update <ID> --body-file /path/to/content.md
55
+ ```
56
+
57
+ 正文内容较长时,请遵循当前技能「内容一律用文件传入」的规范,写入当前工作目录的 `.tmp/` 下临时文件后通过 `--body-file` 传入。
58
+
59
+ ## 最佳实践要点
60
+
61
+ 1. **类型选 `channel`** — 抖音/小红书/B站/YouTube 等社交账号统一用渠道类型收纳。
62
+ 2. **必加 `--auto-resolve-url`** — 省去手动填写资料的麻烦,且数据更准确。
63
+ 3. **标题清晰标识平台** — 如「胡说老王抖音账号」,方便检索和区分多平台矩阵账号。
64
+ 4. **正文按需后补** — 先用自动解析拿到基础资料,再视需要补充分析或打法。
65
+ 5. **避免重复创建** — 若 `intake new` 已返回 `ID:` 或 JSON 中的 `id`,视为成功,后续只能 `update`,禁止再次 `new`。
@@ -0,0 +1,164 @@
1
+ # `profile_data` / `--profile-data-json`(收录 tool / channel)
2
+
3
+ 服务端模型与校验见 C456 仓库 `IntakeProfileRegistry`、`Intake`(`profile_data` 为 JSON)。CLI 创建/更新收录时通过 `**--profile-data-json '<json>'**` 传入**单个 JSON 字符串**(注意 shell 引号;长 JSON 建议写入 `.tmp/*.json` 后再用 `"$(cat .tmp/xxx.json)"` 传入)。
4
+
5
+ **仅改列表图标、不手改整段 facets**:`PATCH /api/v1/intakes/:id` 会与已有 `profile_data` **按键合并**;可只传 `{ "list_icon_url": "<url>" }` 等(详见 [media-library-and-icons.md](media-library-and-icons.md))。CLI:`c456 intake update <id> --profile-data-json-file .tmp/patch.json`。
6
+
7
+ ## 顶层结构
8
+
9
+ ```json
10
+ {
11
+ "facets": [
12
+ {
13
+ "profile_id": "<见下表>",
14
+ "facet_id": "<可选,字符串;不传则由服务端视为空>",
15
+ "data": { }
16
+ }
17
+ ],
18
+ "primary_profile_id": "<与某条 facet 的 profile_id 一致,建议必填>"
19
+ }
20
+ ```
21
+
22
+ - `**facets**`:至少 **1** 条、最多 **5** 条(服务端 `MAX_FACETS = 5`)。
23
+ - `**profile_id`**:必须为下列枚举之一;且必须与 `**kind`(tool/channel)** 匹配(不匹配会报「该资料类型不能用于当前分区」)。
24
+ - **手动录入**:部分 profile 使用 `**_entry_mode`**:`"manual"` 表示手填;省略或为其它值时按 `**resolve`(链接解析路径)** 规则校验(见各小节)。
25
+
26
+ ---
27
+
28
+ ## `profile_id` 与适用 `kind`
29
+
30
+
31
+ | profile_id | `tool` | `channel` | 说明 |
32
+ | ------------------ | ------ | --------- | -------------------------- |
33
+ | `link_product` | ✅ | ✅ | 官网 / 产品页 |
34
+ | `package_registry` | ✅ | ❌ | npm / RubyGems 等包页 |
35
+ | `github_origin` | ✅ | ✅ | GitHub / GitLab / Gitee 仓库 |
36
+ | `social_account` | ❌ | ✅ | 自媒体 / 社交平台账号主页 |
37
+ | `saas_commercial` | ✅ | ✅ | 定价 / 商业信息 |
38
+
39
+
40
+ ---
41
+
42
+ ## 推荐顺序(Agent)
43
+
44
+ 1. **优先** `c456 intake new -k channel|tool -u "<url>" --auto-resolve-url`(由服务端检测平台并合并 `profile_data`,避免手搓 JSON)。
45
+ 2. 仅当不能自动解析或需补 second facet 时,再构造 `**--profile-data-json`**(或先 `c456 fetch profile -p <profile_id> -u "<url>"` 查看解析结果结构,再按需填入 `data`)。
46
+
47
+ ---
48
+
49
+ ## 示例:`social_account`(渠道自媒体,最常见)
50
+
51
+ ### A. 解析路径(等价于「先填账号页 URL 再解析」)
52
+
53
+ `data` 内需能通过校验:`**account_url` 非空**,且 `**platform` 非空**(一般由解析写入;若纯手填且无解析,请改用 B「手动录入」)。
54
+
55
+ ```json
56
+ {
57
+ "facets": [
58
+ {
59
+ "profile_id": "social_account",
60
+ "data": {
61
+ "account_url": "https://www.youtube.com/@example",
62
+ "platform": "YouTube",
63
+ "nickname": "示例频道",
64
+ "handle": "@example"
65
+ }
66
+ }
67
+ ],
68
+ "primary_profile_id": "social_account"
69
+ }
70
+ ```
71
+
72
+ ### B. 手动录入(`_entry_mode`: `manual`)
73
+
74
+ 校验要求(节选):**选择平台或自定义平台**、**平台展示名**,且 `**nickname` / `handle` / `account_url` 至少填一项**。
75
+
76
+ ```json
77
+ {
78
+ "facets": [
79
+ {
80
+ "profile_id": "social_account",
81
+ "data": {
82
+ "_entry_mode": "manual",
83
+ "_dict_key": "p_system_youtube",
84
+ "platform": "YouTube",
85
+ "nickname": "示例频道",
86
+ "handle": "@example",
87
+ "account_url": ""
88
+ }
89
+ }
90
+ ],
91
+ "primary_profile_id": "social_account"
92
+ }
93
+ ```
94
+
95
+ `_dict_key` 为词典项 key(可通过 `GET /api/v1/dictionary/items?category=social_platform` 查找);若无对应项,可使用 `**_custom_platform_label**`(与 `_dict_key` 二选一逻辑见服务端 `validate_facet_error`)。
96
+
97
+ ---
98
+
99
+ ## 示例:`link_product`(官网 / 产品)
100
+
101
+ 必填字段(`required: true`):`**url**`、`**name**`。
102
+
103
+ ```json
104
+ {
105
+ "facets": [
106
+ {
107
+ "profile_id": "link_product",
108
+ "data": {
109
+ "url": "https://example.com/product",
110
+ "name": "示例产品",
111
+ "description": "可选简介"
112
+ }
113
+ }
114
+ ],
115
+ "primary_profile_id": "link_product"
116
+ }
117
+ ```
118
+
119
+ ---
120
+
121
+ ## 示例:`github_origin`(开源仓库)
122
+
123
+ - **解析路径**:需 `**repo_url`**,且解析得到的 `**full_name**` 非空(通常由解析写入)。
124
+ - **手动录入**:`_entry_mode` 为 `manual` 时,需 `**_dict_key`**(托管方)与 `**full_name**`。
125
+
126
+ ```json
127
+ {
128
+ "facets": [
129
+ {
130
+ "profile_id": "github_origin",
131
+ "data": {
132
+ "_entry_mode": "manual",
133
+ "_dict_key": "p_system_github",
134
+ "full_name": "org/repo",
135
+ "repo_url": ""
136
+ }
137
+ }
138
+ ],
139
+ "primary_profile_id": "github_origin"
140
+ }
141
+ ```
142
+
143
+ ---
144
+
145
+ ## 示例:`package_registry`(仅 tool)
146
+
147
+ 手动手填模式需 `**_dict_key**` 与 `**name**`;解析路径需能解析出 `**name**`。细节以服务端 `validate_facet_error` 为准。
148
+
149
+ ---
150
+
151
+ ## 示例:`saas_commercial`(定价补充段)
152
+
153
+ 无 `required: true` 的字段,但整段数据需满足 `coerce_facet_data`;可与其它 facet 并存。
154
+
155
+ ---
156
+
157
+ ## 常见错误(422)
158
+
159
+ - **「请至少添加一个资料段或图标」**:`facets` 为空且未提供图标相关字段(如顶栏 `list_icon_url`)。
160
+ - **「资料类型无效」**:`profile_id` 拼写错误。
161
+ - **「该资料类型不能用于当前分区」**:如对 `channel` 使用 `package_registry`。
162
+ - **社交账号 / 链接产品等**:见各 profile 下 `**validate_facet_error`** 返回的中文提示。
163
+
164
+ 若不确定字段键名,以 C456 仓库 `app/services/intake_profile_registry.rb` 中对应 profile 的 `field_order` / `fields` 为准。
@@ -0,0 +1,46 @@
1
+ # 素材库(Asset)与工具/渠道列表图标(Agent 操作说明)
2
+
3
+ 与 HTTP API v1 及 CLI 行为以 C456 主仓 [`docs/20-engineering/specs/api-v1.md`](https://github.com/xiaohui-zhangxh/c456/blob/main/docs/20-engineering/specs/api-v1.md) 为准。
4
+
5
+ ## 素材 CRUD(CLI)
6
+
7
+ | 操作 | 命令 |
8
+ | --- | --- |
9
+ | 上传 | `c456 asset upload -f <本地图片路径>` |
10
+ | 列表 | `c456 asset list [-p 页] [-n 每页条数]` |
11
+ | 详情 | `c456 asset show <id>`(JSON 含 `markdownSnippet`、`previewUrl`) |
12
+ | 改展示名 | `c456 asset update <id> --filename <展示文件名.webp>`(不替换图片字节,仅 ActiveStorage 文件名) |
13
+ | 删除 | `c456 asset delete <id>`(正文仍引用 `c456:asset/<id>` 时会失败) |
14
+ | 续期正文里的预览链 | `c456 asset refresh-markdown --body-file <.md>`(输出到 stdout) |
15
+
16
+ 上传与服务器「上传前字节」去重一致:完全相同文件会 **422**。
17
+
18
+ ## 把图片插入收录/打法/讲解正文
19
+
20
+ 1. `c456 asset upload -f ./figure.png` → 终端会打印 **`markdownSnippet`**(一行 Markdown 图片,title 内含 `c456:asset/<id>`)。
21
+ 2. 将该行(或经编辑器合并后的段落)写入 **`body`**:创建/更新收录或打法时用 **`--body-file`** 传入整篇 Markdown,**不要**在 shell 里直接塞多行引号。
22
+ 3. 预览 URL 会过期时,对整篇 Markdown 跑 `c456 asset refresh-markdown --body-file note.md > note.new.md` 再写回。
23
+
24
+ 插图以 **title 中的 `c456:asset/<id>`** 为稳定引用;括号内 URL 可续期。
25
+
26
+ ## 工具 / 渠道的「列表图标」(list icon)
27
+
28
+ 列表与卡片上的图标来自收录 **`profile_data`** 顶层的 **`list_icon_url` / `list_icon_url_local`**(以及各资料段解析出的 icon)。Web 端可上传文件;**API / CLI** 常见做法:
29
+
30
+ 1. **先把图标上传到素材库**:`c456 asset upload -f ./logo.png` → 得到 **`previewUrl`**(签名 URL,可作临时图床链)。
31
+ 2. **再 PATCH 收录**(仅 tool / channel),只改图标、不动原有资料段。将 JSON 写入 `.tmp/icon-patch.json` 后执行:
32
+
33
+ ```bash
34
+ c456 intake update <intake_id> --profile-data-json-file .tmp/icon-patch.json
35
+ ```
36
+
37
+ 文件内容示例:`{ "list_icon_url": "<上一步 asset show 或 upload 输出的 previewUrl>" }`。
38
+
39
+ 服务端会将外链 **转存** 为站内 `list_icon_url_local`(与 Web 行为一致);若需清除图标,传 **`"remove_list_icon": true`**(与 `list_icon_url` 二选一逻辑以 API 为准)。
40
+
41
+ 3. **`profile_data` 与 facets 的合并**:`PATCH /api/v1/intakes/:id` 对已有 `profile_data` **按键合并**——请求里**没有** `facets` 键时,不会清空已有资料段;可只传 `list_icon_url`。完整 facets 结构仍见 [intake-profile-data-json.md](intake-profile-data-json.md)。
42
+
43
+ ## 相关 CLI
44
+
45
+ - `c456 tool …` / `c456 channel …`:新建时常用 `-u` + `--auto-resolve-url`,再按需 `intake update` 补图标。
46
+ - `c456 intake update <id> --profile-data-json '…'`:更新 tool/channel 的 `profile_data` 或列表图标。