@bingran/sbti-cli 0.1.0 → 0.1.1

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/package.json CHANGED
@@ -1,44 +1,12 @@
1
1
  {
2
2
  "name": "@bingran/sbti-cli",
3
- "version": "0.1.0",
4
- "type": "module",
5
- "description": "Native-binary CLI runner for the public SBTI survey.",
3
+ "version": "0.1.1",
4
+ "description": "Standalone CLI runner for the public SBTI survey.",
6
5
  "license": "MIT",
7
- "homepage": "https://github.com/bingran-you/sbti-cli",
8
- "bugs": {
9
- "url": "https://github.com/bingran-you/sbti-cli/issues"
10
- },
11
- "repository": {
12
- "type": "git",
13
- "url": "git+https://github.com/bingran-you/sbti-cli.git"
14
- },
15
- "files": [
16
- "bin",
17
- "lib",
18
- "LICENSE",
19
- "NOTICE",
20
- "README.md",
21
- "README.zh-CN.md"
22
- ],
6
+ "type": "module",
23
7
  "bin": {
24
8
  "sbti-cli": "./bin/sbti-cli.cjs"
25
9
  },
26
- "optionalDependencies": {
27
- "@bingran/sbti-cli-darwin-arm64": "0.1.0",
28
- "@bingran/sbti-cli-darwin-x64": "0.1.0",
29
- "@bingran/sbti-cli-linux-arm64": "0.1.0",
30
- "@bingran/sbti-cli-linux-x64": "0.1.0",
31
- "@bingran/sbti-cli-win32-x64": "0.1.0"
32
- },
33
- "scripts": {
34
- "build:dist": "node scripts/build-dist.mjs",
35
- "build:platform-packages": "node scripts/build-platform-packages.mjs",
36
- "publish:packages": "node scripts/publish-packages.mjs",
37
- "start": "node src/cli.mjs",
38
- "sbti": "node src/cli.mjs",
39
- "export-images": "node scripts/export-type-images.mjs",
40
- "test": "node --test test/*.test.mjs"
41
- },
42
10
  "engines": {
43
11
  "node": ">=18"
44
12
  }
package/README.zh-CN.md DELETED
@@ -1,319 +0,0 @@
1
- <h1 align="center">SBTI CLI · 官网逻辑等效的命令行版</h1>
2
-
3
- <p align="center">
4
- <em>把 SBTI 人格测试搬进终端,同时尽量保留官网同一套运行时与结果资源。</em><br>
5
- 一个支持 <strong>纯离线运行</strong>、<strong>内置题库快照</strong>、<strong>结果图导出</strong> 的 Node.js CLI。
6
- </p>
7
-
8
- <p align="center">
9
- <a href="https://sbti.fancc.de5.net"><img alt="原测试" src="https://img.shields.io/badge/原测试-sbti.fancc.de5.net-4CAF50?style=flat-square"></a>
10
- <img alt="Node.js" src="https://img.shields.io/badge/Node.js-18%2B-339933?style=flat-square">
11
- <img alt="运行模式" src="https://img.shields.io/badge/运行模式-纯离线-blue?style=flat-square">
12
- <img alt="结果图" src="https://img.shields.io/badge/结果图-27%20张-orange?style=flat-square">
13
- <img alt="题目" src="https://img.shields.io/badge/题目-30%20%2B%201%20隐藏-purple?style=flat-square">
14
- <img alt="许可证" src="https://img.shields.io/badge/许可证-MIT-red?style=flat-square">
15
- </p>
16
-
17
- <p align="center">
18
- <a href="./README.md"><img alt="English" src="https://img.shields.io/badge/English-click_to_switch-2563EB?style=for-the-badge"></a>
19
- <a href="./README.zh-CN.md"><img alt="简体中文" src="https://img.shields.io/badge/简体中文-当前-F0522D?style=for-the-badge"></a>
20
- </p>
21
-
22
- <p align="center">
23
- <img src="assets/type-images/CTRL.png" width="130" alt="CTRL">
24
- <img src="assets/type-images/BOSS.png" width="130" alt="BOSS">
25
- <img src="assets/type-images/SEXY.png" width="130" alt="SEXY">
26
- <img src="assets/type-images/MALO.png" width="130" alt="MALO">
27
- <img src="assets/type-images/DRUNK.png" width="130" alt="DRUNK">
28
- <img src="assets/type-images/HHHH.png" width="130" alt="HHHH">
29
- </p>
30
-
31
- ---
32
-
33
- ## 📖 目录
34
-
35
- - [这是什么](#-这是什么)
36
- - [如何安装与设置](#-如何安装与设置)
37
- - [如何使用 CLI](#-如何使用-cli)
38
- - [核心能力一览](#-核心能力一览)
39
- - [结果图与离线资源](#-结果图与离线资源)
40
- - [数据来源与原理](#-数据来源与原理)
41
- - [鸣谢](#-鸣谢)
42
- - [License](#-license)
43
-
44
- ---
45
-
46
- ## 🎯 这是什么
47
-
48
- 本仓库把 [**sbti.fancc.de5.net**](https://sbti.fancc.de5.net) 的 SBTI 人格测试做成了一个可在本地终端运行的 CLI。它不是手写一套“像官网”的逻辑,而是把题库和结果逻辑打包成内置快照,在本地 sandbox 中运行,因此保留了这些关键特性:
49
-
50
- - 🎲 **和官网一致的题目行为**:30 道常规题随机顺序、饮酒分支插入位置、隐藏题触发规则都保持一致
51
- - 📊 **和官网一致的结果计算**:15 维打分、H / M / L 分档、25 个标准人格匹配、`DRUNK` 覆盖、`HHHH` 兜底都保持一致
52
- - 📴 **每次都纯离线运行**:CLI 每次都直接使用仓库内置快照,不依赖 live website
53
- - 🖼️ **结果图可本地整理**:27 张结果海报已随仓库提供,可重建本地 manifest 与画廊
54
- - ✅ **有对齐测试兜底**:除了基础单测,还包含 50 组结果回归测试与离线资源完整性验证
55
-
56
- 如果你想:
57
-
58
- - 在终端里完整做一次 SBTI
59
- - 用脚本研究结果逻辑
60
- - 在完全离线的环境里继续跑测试
61
- - 重建 27 张结果图的本地资源清单
62
-
63
- 这个仓库就是干这个的。
64
-
65
- ---
66
-
67
- ## 🧭 如何安装与设置
68
-
69
- ### 直接从 npm 安装
70
-
71
- 如果只是想让 agent 或普通用户直接跑 CLI,用 npm 安装发布包即可:
72
-
73
- ```bash
74
- npm install -g @bingran/sbti-cli
75
- sbti-cli
76
- ```
77
-
78
- 或者:
79
-
80
- ```bash
81
- npx @bingran/sbti-cli
82
- ```
83
-
84
- npm 安装面现在被刻意收紧了:根包 `@bingran/sbti-cli` 只带一个很小的 launcher,安装时会自动拉取当前平台对应的 native binary 子包。发布到 npm 的内容 **不会** 再带上仓库源码、测试、构建脚本或结果图资源。
85
-
86
- 当前原生包目标平台:
87
-
88
- - macOS `arm64`
89
- - macOS `x64`
90
- - Linux `arm64`
91
- - Linux `x64`
92
- - Windows `x64`
93
-
94
- ### 克隆仓库用于开发
95
-
96
- 如果你需要测试集、结果图导出工具或源码本身,再使用仓库 checkout:
97
-
98
- ```bash
99
- git clone https://github.com/bingran-you/sbti-cli.git
100
- cd sbti-cli
101
- npm install
102
- npm test
103
- ```
104
-
105
- 然后可以用开发入口启动:
106
-
107
- ```bash
108
- npm run sbti
109
- ```
110
-
111
- 或者:
112
-
113
- ```bash
114
- node src/cli.mjs
115
- ```
116
-
117
- > 💡 这个项目不需要数据库、浏览器驱动或 `.env` 配置;只要有 Node.js,就能运行发布版 CLI 或仓库内开发入口。
118
-
119
- ---
120
-
121
- ## 🧪 如何使用 CLI
122
-
123
- ### 常用命令
124
-
125
- | 命令 | 作用 |
126
- |---|---|
127
- | `sbti-cli` | 从 npm 发布包直接开始一次测试 |
128
- | `sbti-cli --seed 42` | 固定随机种子,方便复现题目顺序 |
129
- | `sbti-cli --json` | 直接输出 JSON 结果 |
130
- | `npm run sbti` | 运行仓库内的开发入口 |
131
- | `npm run export-images` | 在仓库 checkout 里重建 manifest 和本地画廊 |
132
-
133
- ### 交互方式
134
-
135
- 运行测试后,CLI 会逐题提问。输入方式和导航规则如下:
136
- 每个答案一旦提交,就会在本轮测试中锁定。
137
-
138
- | 输入 | 作用 |
139
- |---|---|
140
- | `A / B / C / D` | 选择当前题的选项 |
141
- | `q` | 中途退出,不提交结果 |
142
-
143
- ### 一个最常见的流程
144
-
145
- ```bash
146
- sbti-cli
147
- ```
148
-
149
- ```text
150
- SBTI 人格测试 CLI
151
- 题库来源: bundled:sbti-main.js
152
-
153
- 第 1 题 / 31 · 维度已隐藏
154
- ...
155
-
156
- 输入 A/B/C/D 选择,或输入 q 退出。
157
- > C
158
- ```
159
-
160
- ## 🧬 核心能力一览
161
-
162
- <table>
163
- <tr>
164
- <th>模块</th>
165
- <th>能力</th>
166
- <th>说明</th>
167
- </tr>
168
- <tr>
169
- <td><strong>🛟 离线运行时</strong></td>
170
- <td>始终直接加载内置快照</td>
171
- <td>题目顺序、饮酒隐藏题、打分、匹配、特殊分支都走本地内置的同一套逻辑</td>
172
- </tr>
173
- <tr>
174
- <td><strong>🖼️ 结果图资源</strong></td>
175
- <td>27 张已收录海报可本地整理</td>
176
- <td>支持生成 <code>manifest.json</code> 与本地 <code>index.html</code> 画廊</td>
177
- </tr>
178
- <tr>
179
- <td><strong>🧪 回归测试</strong></td>
180
- <td>内置运行时验证</td>
181
- <td>包含 50 组结果回归、图片完整性测试与离线运行路径验证</td>
182
- </tr>
183
- <tr>
184
- <td><strong>📦 原生 npm 发布</strong></td>
185
- <td>小型 launcher + 平台 native binary 子包</td>
186
- <td>通过 npm 安装时,不再把仓库源码、测试或构建脚本连同可运行 CLI 一起发出去</td>
187
- </tr>
188
- </table>
189
-
190
- ---
191
-
192
- ## 🎭 结果图与离线资源
193
-
194
- 这一节是仓库开发资源,不属于发布到 npm 的 CLI 安装面。
195
-
196
- <table>
197
- <tr>
198
- <td align="center" width="33%">
199
- <a href="assets/type-images/index.html"><img src="assets/type-images/CTRL.png" width="180"><br><strong>本地结果图画廊</strong></a><br>
200
- <sub>27 张海报导出后的可浏览 HTML 页面</sub>
201
- </td>
202
- <td align="center" width="33%">
203
- <a href="assets/type-images/manifest.json"><img src="assets/type-images/BOSS.png" width="180"><br><strong>结果图清单</strong></a><br>
204
- <sub>文件名、类型、字节数都收录在 manifest 里</sub>
205
- </td>
206
- <td align="center" width="33%">
207
- <a href="src/bundled-data.mjs"><img src="assets/type-images/SEXY.png" width="180"><br><strong>离线快照</strong></a><br>
208
- <sub>每次 CLI 运行都会直接使用的内置题库与结果数据</sub>
209
- </td>
210
- </tr>
211
- <tr>
212
- <td align="center">
213
- <a href="scripts/export-type-images.mjs"><img src="assets/type-images/MALO.png" width="180"><br><strong>图片导出脚本</strong></a><br>
214
- <sub>基于仓库内已有图片重建 manifest 和本地画廊</sub>
215
- </td>
216
- <td align="center">
217
- <a href="test/runtime.test.mjs"><img src="assets/type-images/HHHH.png" width="180"><br><strong>对齐测试</strong></a><br>
218
- <sub>确保 CLI 的结果分支和内置逻辑保持一致</sub>
219
- </td>
220
- </tr>
221
- </table>
222
-
223
- ### 导出结果图
224
-
225
- ```bash
226
- npm run export-images
227
- ```
228
-
229
- 执行后会生成:
230
-
231
- - [`assets/type-images/index.html`](assets/type-images/index.html) — 本地画廊
232
- - [`assets/type-images/manifest.json`](assets/type-images/manifest.json) — 27 张图片的清单
233
- - [`assets/type-images/`](assets/type-images/) — 全部解码后的 `.png` / `.jpg` 文件
234
-
235
- ## 🔬 数据来源与原理
236
-
237
- ### 为什么能做到和官网行为一致
238
-
239
- 本仓库把题库和结果逻辑存成 [`src/bundled-data.mjs`](src/bundled-data.mjs) 里的内置快照,再通过 [`src/runtime.mjs`](src/runtime.mjs) 用 Node.js 的 `vm` 模块放进一个很小的 sandbox 里运行。
240
-
241
- CLI 不是手写“差不多”的逻辑,而是每次都直接跑这份内置快照里的同一套对象:
242
-
243
- | 运行时对象 | 内容 |
244
- |---|---|
245
- | `dimensionMeta` | 15 个维度的中文名与模型分组 |
246
- | `questions` | 30 道常规题 |
247
- | `specialQuestions` | 饮酒隐藏题与其前置分支 |
248
- | `TYPE_LIBRARY` | 27 个人格的代号、中文名、开场白、完整描述 |
249
- | `NORMAL_TYPES` | 25 个标准人格的 H / M / L 模板 |
250
- | `DIM_EXPLANATIONS` | 15 维 × 3 档的维度文案 |
251
- | `computeResult()` | 官网自己的结果分支逻辑 |
252
-
253
- 因此,CLI 可以和官网保持同一套:
254
-
255
- - 题目 shuffle
256
- - 饮酒题插入与隐藏题显示
257
- - 15 维打分与分档
258
- - 25 个标准人格匹配排序
259
- - `DRUNK` 特殊覆盖
260
- - `HHHH` 低匹配度兜底
261
-
262
- ### 结果图从哪里来
263
-
264
- 27 张人物海报已经随仓库一起存放在 [`assets/type-images/`](assets/type-images/) 中。[`scripts/export-type-images.mjs`](scripts/export-type-images.mjs) 负责根据这些本地文件重建 manifest 和本地画廊。
265
-
266
- ### 本仓库里最关键的文件
267
-
268
- - [`src/cli.mjs`](src/cli.mjs) — 命令行交互入口
269
- - [`src/runtime.mjs`](src/runtime.mjs) — 内置运行时加载、sandbox 运行、结果汇总
270
- - [`src/bundled-data.mjs`](src/bundled-data.mjs) — CLI 使用的内置快照
271
- - [`src/type-images.mjs`](src/type-images.mjs) — 图片工具与本地画廊生成
272
- - [`bin/sbti-cli.cjs`](bin/sbti-cli.cjs) — npm launcher,会解析当前平台对应的 native binary 子包
273
- - [`lib/platform-package.cjs`](lib/platform-package.cjs) — 支持的平台映射与 native package 解析逻辑
274
- - [`dist/sbti-cli.cjs`](dist/sbti-cli.cjs) — 用来生成 native binary 的 CommonJS 单文件入口
275
- - [`scripts/build-dist.mjs`](scripts/build-dist.mjs) — 生成 ESM/CJS 两份单文件 CLI 构建产物
276
- - [`scripts/build-platform-packages.mjs`](scripts/build-platform-packages.mjs) — 生成各平台预编译 native npm 子包
277
- - [`scripts/publish-packages.mjs`](scripts/publish-packages.mjs) — 先发布平台子包,再发布根包 `@bingran/sbti-cli`
278
- - [`scripts/export-type-images.mjs`](scripts/export-type-images.mjs) — 重建结果图 manifest 与画廊
279
- - [`test/runtime.test.mjs`](test/runtime.test.mjs) — 内置运行时对齐测试
280
- - [`test/launcher.test.mjs`](test/launcher.test.mjs) — launcher 与 native package 解析测试
281
- - [`test/package.test.mjs`](test/package.test.mjs) — npm tarball 发布面检查
282
- - [`test/type-images.test.mjs`](test/type-images.test.mjs) — 图片资源完整性测试
283
-
284
- ---
285
-
286
- ## 🙏 鸣谢
287
-
288
- <table>
289
- <tr>
290
- <th>项目</th>
291
- <th>作者</th>
292
- <th>贡献</th>
293
- </tr>
294
- <tr>
295
- <td><a href="https://sbti.fancc.de5.net"><strong>SBTI 人格测试</strong></a></td>
296
- <td>B 站 <a href="https://space.bilibili.com/417038183">@蛆肉儿串儿</a></td>
297
- <td>原测试作者,提供题目、27 个人格文案与角色插画</td>
298
- </tr>
299
- <tr>
300
- <td><a href="https://github.com/serenakeyitan/sbti-wiki"><strong>sbti-wiki</strong></a></td>
301
- <td><a href="https://github.com/serenakeyitan">@serenakeyitan</a></td>
302
- <td>这次 README 改版的版式参考来源:中心 Hero、徽章、图卡与信息分段方式</td>
303
- </tr>
304
- <tr>
305
- <td><strong>sbti-cli</strong></td>
306
- <td><a href="https://github.com/bingran-you">Bingran You (@bingran-you)</a></td>
307
- <td>把题库快照 sandbox 化,补上离线运行、结果图整理与测试体系,提供一个可直接使用的 CLI</td>
308
- </tr>
309
- </table>
310
-
311
- > ⚠️ **仅供娱乐**:原测试首页已经写得很明确了,不要把它当成诊断、面试、相亲、分手、招魂、算命或人生判决书。本仓库也只是一个便于运行、研究和导出资源的工具。
312
-
313
- ---
314
-
315
- ## 📄 License
316
-
317
- 本仓库中由本项目原创的代码与文档采用 [MIT License](LICENSE) 发布。
318
-
319
- 与此同时,来自上游 SBTI 网站的题目文案、结果文案以及角色插画仍然归原作者所有,并不因为放进这个仓库就自动转成 MIT。具体归属说明见 [NOTICE](NOTICE)。
@@ -1,117 +0,0 @@
1
- const path = require('node:path');
2
-
3
- const SUPPORTED_PLATFORMS = [
4
- {
5
- id: 'darwin-arm64',
6
- platform: 'darwin',
7
- arch: 'arm64',
8
- packageName: '@bingran/sbti-cli-darwin-arm64',
9
- pkgTarget: 'node18-macos-arm64',
10
- binaryName: 'sbti-cli'
11
- },
12
- {
13
- id: 'darwin-x64',
14
- platform: 'darwin',
15
- arch: 'x64',
16
- packageName: '@bingran/sbti-cli-darwin-x64',
17
- pkgTarget: 'node18-macos-x64',
18
- binaryName: 'sbti-cli'
19
- },
20
- {
21
- id: 'linux-arm64',
22
- platform: 'linux',
23
- arch: 'arm64',
24
- packageName: '@bingran/sbti-cli-linux-arm64',
25
- pkgTarget: 'node18-linux-arm64',
26
- binaryName: 'sbti-cli'
27
- },
28
- {
29
- id: 'linux-x64',
30
- platform: 'linux',
31
- arch: 'x64',
32
- packageName: '@bingran/sbti-cli-linux-x64',
33
- pkgTarget: 'node18-linux-x64',
34
- binaryName: 'sbti-cli'
35
- },
36
- {
37
- id: 'win32-x64',
38
- platform: 'win32',
39
- arch: 'x64',
40
- packageName: '@bingran/sbti-cli-win32-x64',
41
- pkgTarget: 'node18-win-x64',
42
- binaryName: 'sbti-cli.exe'
43
- }
44
- ];
45
-
46
- function formatSupportedPlatforms() {
47
- return SUPPORTED_PLATFORMS.map(
48
- ({ platform, arch, packageName }) => `- ${platform}/${arch}: ${packageName}`
49
- ).join('\n');
50
- }
51
-
52
- function getPlatformPackageInfo(platform, arch) {
53
- return (
54
- SUPPORTED_PLATFORMS.find(
55
- (entry) => entry.platform === platform && entry.arch === arch
56
- ) ?? null
57
- );
58
- }
59
-
60
- function getCurrentPlatformPackageInfo() {
61
- return getPlatformPackageInfo(process.platform, process.arch);
62
- }
63
-
64
- function getBinaryPath(packageRoot, platformInfo) {
65
- if (!platformInfo) {
66
- throw new Error('A supported platform package definition is required.');
67
- }
68
-
69
- return path.join(packageRoot, 'bin', platformInfo.binaryName);
70
- }
71
-
72
- function resolveInstalledBinaryPath(
73
- resolveRequest,
74
- platform = process.platform,
75
- arch = process.arch
76
- ) {
77
- if (typeof resolveRequest !== 'function') {
78
- throw new TypeError('resolveRequest must be a function.');
79
- }
80
-
81
- const platformInfo = getPlatformPackageInfo(platform, arch);
82
-
83
- if (!platformInfo) {
84
- throw new Error(
85
- `Unsupported platform ${platform}/${arch}.\nSupported native packages:\n${formatSupportedPlatforms()}`
86
- );
87
- }
88
-
89
- let packageJsonPath;
90
-
91
- try {
92
- packageJsonPath = resolveRequest(`${platformInfo.packageName}/package.json`);
93
- } catch (error) {
94
- if (error?.code === 'MODULE_NOT_FOUND') {
95
- throw new Error(
96
- `Missing native binary package ${platformInfo.packageName} for ${platform}/${arch}. ` +
97
- 'Reinstall @bingran/sbti-cli without omitting optional dependencies.'
98
- );
99
- }
100
-
101
- throw error;
102
- }
103
-
104
- return {
105
- platformInfo,
106
- binaryPath: getBinaryPath(path.dirname(packageJsonPath), platformInfo)
107
- };
108
- }
109
-
110
- module.exports = {
111
- SUPPORTED_PLATFORMS,
112
- formatSupportedPlatforms,
113
- getBinaryPath,
114
- getCurrentPlatformPackageInfo,
115
- getPlatformPackageInfo,
116
- resolveInstalledBinaryPath
117
- };