create-napukettoqq 0.0.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/LICENSE +21 -0
- package/dist/index.d.mts +1 -0
- package/dist/index.mjs +248 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +21 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 睦 <oppenheymu@gmail.com>
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {}
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import process$1 from "node:process";
|
|
3
|
+
import { createInterface } from "node:readline/promises";
|
|
4
|
+
import { mkdir, readdir, writeFile } from "node:fs/promises";
|
|
5
|
+
import { homedir } from "node:os";
|
|
6
|
+
import path from "node:path";
|
|
7
|
+
//#region src/scaffold.ts
|
|
8
|
+
/**
|
|
9
|
+
* create-napukettoqq 脚手架核心:模板 + 目标目录创建 + 文件写入。
|
|
10
|
+
*
|
|
11
|
+
* 零依赖(仅 node:fs/promises / node:os / node:path / node:process),
|
|
12
|
+
* 一次性工具保持自包含。生成的用户项目依赖发布版的 @napuketto/cli,
|
|
13
|
+
* 用户 install 后经 cli → loader 自建宿主启动。
|
|
14
|
+
*/
|
|
15
|
+
/** 生成的用户项目所依赖的 @napuketto/cli 版本范围(发布新版时统一改)。 */
|
|
16
|
+
const CLI_VERSION = "^0.0.1";
|
|
17
|
+
/** Windows 路径非法字符(项目文件夹名校验用)。 */
|
|
18
|
+
const ILLEGAL_NAME = /[\\/:*?"<>|]/;
|
|
19
|
+
/** 校验文件夹名:非空、非 . / ..、不含 Windows 非法字符。 */
|
|
20
|
+
function validateProjectName(raw) {
|
|
21
|
+
const name = raw.trim();
|
|
22
|
+
if (name === "" || name === "." || name === "..") throw new Error("文件夹名不能为空或为 . / ..");
|
|
23
|
+
if (ILLEGAL_NAME.test(name)) throw new Error(`文件夹名含非法字符:${name}(不允许 \\ / : * ? " < > |)`);
|
|
24
|
+
return name;
|
|
25
|
+
}
|
|
26
|
+
/** 由文件夹名派生 npm 包名(小写、空格 → -)。 */
|
|
27
|
+
function derivePackageName(dirName) {
|
|
28
|
+
return dirName.toLowerCase().replace(/\s+/g, "-");
|
|
29
|
+
}
|
|
30
|
+
/** 生成 package.json(用户项目,JSON.stringify 保证合法)。 */
|
|
31
|
+
function packageJsonTemplate(packageName) {
|
|
32
|
+
return `${JSON.stringify({
|
|
33
|
+
name: packageName,
|
|
34
|
+
version: "0.0.1",
|
|
35
|
+
private: true,
|
|
36
|
+
type: "module",
|
|
37
|
+
description: "NapukettoQQ 机器人项目(OneBot 11)",
|
|
38
|
+
scripts: { start: "napuketto" },
|
|
39
|
+
dependencies: { "@napuketto/cli": CLI_VERSION }
|
|
40
|
+
}, null, 4)}\n`;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* 生成 napuketto.toml:与 cli configTemplate(apps/cli/src/config-cmds.ts)同款内容,
|
|
44
|
+
* dataDir 按当前用户主目录插值(JSON.stringify 转义反斜杠 → TOML 基本字符串合法写法)。
|
|
45
|
+
*/
|
|
46
|
+
function tomlTemplate() {
|
|
47
|
+
return `# ============================================================
|
|
48
|
+
# NapukettoQQ 全局配置文件(由 create-napukettoqq 生成)
|
|
49
|
+
# ============================================================
|
|
50
|
+
# 本文件与项目 napuketto.toml.example 内容一致(参考模板)。
|
|
51
|
+
# 数据(账号目录/日志/缓存/QQ 数据)不在此文件,按数据根组织:
|
|
52
|
+
# 优先级:--data-dir <dir> > NAPKETTO_DATA 环境变量 > ~/.napuketto
|
|
53
|
+
# 配置文件路径解析:NAPKETTO_CONFIG > 项目根探测 > cwd > 数据根兜底。
|
|
54
|
+
#
|
|
55
|
+
# 单账号启动每次读取本文件;修改后重启生效。
|
|
56
|
+
|
|
57
|
+
# ------------------------------------------------------------
|
|
58
|
+
# 基础配置
|
|
59
|
+
# ------------------------------------------------------------
|
|
60
|
+
|
|
61
|
+
# 数据根目录:账号目录/日志/缓存/QQ 数据存放位置(绝对路径)
|
|
62
|
+
dataDir = ${JSON.stringify(path.join(homedir(), ".napuketto"))}
|
|
63
|
+
|
|
64
|
+
# 多账号(supervisor)模式下,账号进程崩溃是否自动重启
|
|
65
|
+
autoRestart = true
|
|
66
|
+
|
|
67
|
+
# 崩溃后自动重启的延迟(毫秒)
|
|
68
|
+
restartDelayMs = 2000
|
|
69
|
+
|
|
70
|
+
# 多账号列表(留空 = 单账号模式:启动后自动快速登录/扫码)
|
|
71
|
+
# [[accounts]]
|
|
72
|
+
# qq = "123456" # QQ 号(必填)
|
|
73
|
+
# enabled = true # 是否启用(可选,缺省 true)
|
|
74
|
+
|
|
75
|
+
# ------------------------------------------------------------
|
|
76
|
+
# OneBot 11 协议段
|
|
77
|
+
# ------------------------------------------------------------
|
|
78
|
+
[onebot11]
|
|
79
|
+
|
|
80
|
+
# 鉴权 token(全局默认):HTTP/WS 连接必须携带。
|
|
81
|
+
# 校验方式:Authorization: Bearer <token> / 裸 token / URL 参数 ?access_token=<token>
|
|
82
|
+
# 每个网络实例可单独覆盖(见下文各实例的 token 字段)。
|
|
83
|
+
# 留空 = 不鉴权(仅本机调试推荐)。
|
|
84
|
+
# token = ""
|
|
85
|
+
|
|
86
|
+
# 心跳 meta 事件间隔(毫秒);0 = 关闭心跳事件
|
|
87
|
+
heartbeatInterval = 3000
|
|
88
|
+
|
|
89
|
+
# 是否上报机器人自己发的消息(OB11 规范默认不上报)
|
|
90
|
+
reportSelfMessage = false
|
|
91
|
+
|
|
92
|
+
# 消息内容格式:array = 消息段数组(标准 OneBot 11),string = CQ 码字符串
|
|
93
|
+
messagePostFormat = "array"
|
|
94
|
+
|
|
95
|
+
# ---- HTTP 反向服务器(接收第三方 POST 指令),可配置多个 ----
|
|
96
|
+
[[onebot11.httpServers]]
|
|
97
|
+
enabled = true
|
|
98
|
+
host = "127.0.0.1" # 监听地址;0.0.0.0 = 监听所有网卡(局域网可连)
|
|
99
|
+
port = 3000
|
|
100
|
+
# token = "abc" # 可选:覆盖全局 token
|
|
101
|
+
|
|
102
|
+
# ---- HTTP 正向上报(Webhook:把事件 POST 到第三方地址),可配置多个 ----
|
|
103
|
+
# [[onebot11.httpPostUrls]]
|
|
104
|
+
# enabled = true
|
|
105
|
+
# url = "http://127.0.0.1:8080/onebot" # 第三方接收地址
|
|
106
|
+
# token = "abc" # 可选:覆盖全局 token
|
|
107
|
+
# timeoutMs = 5000 # 可选:上报超时(毫秒),缺省不超时
|
|
108
|
+
|
|
109
|
+
# ---- WS 反向服务器(外部 WS 客户端主动连入),可配置多个 ----
|
|
110
|
+
[[onebot11.wsServers]]
|
|
111
|
+
enabled = true
|
|
112
|
+
host = "127.0.0.1"
|
|
113
|
+
port = 3001
|
|
114
|
+
# token = "abc" # 可选:覆盖全局 token
|
|
115
|
+
# heartbeatInterval = 30000 # 可选:WS ping 间隔(毫秒)
|
|
116
|
+
|
|
117
|
+
# ---- WS 正向客户端(主动连接外部 WS,双向),可配置多个 ----
|
|
118
|
+
# [[onebot11.wsReverseUrls]]
|
|
119
|
+
# enabled = true
|
|
120
|
+
# url = "ws://127.0.0.1:8081/ws" # 第三方 WS 地址(ws:// 或 wss://)
|
|
121
|
+
# token = "abc" # 可选:覆盖全局 token
|
|
122
|
+
# reconnectDelayMs = 5000 # 可选:断线重连延迟(毫秒)
|
|
123
|
+
# maxReconnectAttempts = 10 # 可选:最大重连次数(缺省无限)
|
|
124
|
+
# rejectUnauthorized = true # 可选:wss:// 是否校验证书(自签证书设 false)
|
|
125
|
+
# heartbeatInterval = 30000 # 可选:WS ping 间隔(毫秒)
|
|
126
|
+
`;
|
|
127
|
+
}
|
|
128
|
+
/** 生成 readme.md(用户项目使用说明)。 */
|
|
129
|
+
function readmeTemplate(dirName) {
|
|
130
|
+
return `# ${dirName}
|
|
131
|
+
|
|
132
|
+
基于 **NapukettoQQ** 的 QQ 机器人项目(OneBot 11 协议),由 \`create-napukettoqq\` 生成。
|
|
133
|
+
|
|
134
|
+
## 快速开始
|
|
135
|
+
|
|
136
|
+
\`\`\`bash
|
|
137
|
+
pnpm install
|
|
138
|
+
pnpm start -q 123456 # 换成你的 QQ 号
|
|
139
|
+
\`\`\`
|
|
140
|
+
|
|
141
|
+
启动后按终端提示快速登录或扫码;登录成功后 OneBot 11 接口生效
|
|
142
|
+
(默认 HTTP \`127.0.0.1:3000\` + WS \`127.0.0.1:3001\`,见 \`napuketto.toml\`)。
|
|
143
|
+
|
|
144
|
+
## 前置要求
|
|
145
|
+
|
|
146
|
+
- 已安装 **QQ NT**(Windows,机器人所需的 \`wrapper.node\` 来自 QQ 安装目录,
|
|
147
|
+
未自动探测到时用 \`pnpm start --qq-path <QQ安装目录>\` 指定)
|
|
148
|
+
- Node.js 20+ 与 pnpm
|
|
149
|
+
|
|
150
|
+
## 常用命令
|
|
151
|
+
|
|
152
|
+
| 命令 | 说明 |
|
|
153
|
+
|---|---|
|
|
154
|
+
| \`pnpm start -q <QQ号>\` | 单账号启动(走自建宿主) |
|
|
155
|
+
| \`pnpm napuketto config init\` | 重新生成默认配置 |
|
|
156
|
+
| \`pnpm napuketto supervisor\` | 多账号模式(按 \`napuketto.toml\` 的 \`accounts\`) |
|
|
157
|
+
|
|
158
|
+
## 目录
|
|
159
|
+
|
|
160
|
+
- \`napuketto.toml\` — 全局配置(QQ 号、OneBot 端口、token 等,修改后重启生效)
|
|
161
|
+
- QQ 数据(账号目录/日志/缓存)默认在 \`~/.napuketto/\`
|
|
162
|
+
|
|
163
|
+
## 升级
|
|
164
|
+
|
|
165
|
+
\`\`\`bash
|
|
166
|
+
pnpm update @napuketto/cli
|
|
167
|
+
\`\`\`
|
|
168
|
+
`;
|
|
169
|
+
}
|
|
170
|
+
/** 生成 .gitignore(用户项目)。 */
|
|
171
|
+
const GITIGNORE = `node_modules/
|
|
172
|
+
dist/
|
|
173
|
+
*.log
|
|
174
|
+
napuketto-data/
|
|
175
|
+
`;
|
|
176
|
+
/**
|
|
177
|
+
* 生成 NapukettoQQ 项目骨架到当前目录下的 <dirName>/。
|
|
178
|
+
* 目标目录已存在且非空 → 抛错(提示换名字或先清空)。
|
|
179
|
+
*/
|
|
180
|
+
async function scaffoldProject(dirName) {
|
|
181
|
+
const name = validateProjectName(dirName);
|
|
182
|
+
const packageName = derivePackageName(name);
|
|
183
|
+
const dir = path.resolve(process.cwd(), name);
|
|
184
|
+
let existing = [];
|
|
185
|
+
try {
|
|
186
|
+
existing = await readdir(dir);
|
|
187
|
+
} catch {}
|
|
188
|
+
if (existing.length > 0) throw new Error(`目录已存在且非空:${dir}\n请换一个文件夹名,或先清空该目录。`);
|
|
189
|
+
await mkdir(dir, { recursive: true });
|
|
190
|
+
await writeFile(path.join(dir, "package.json"), packageJsonTemplate(packageName), "utf8");
|
|
191
|
+
await writeFile(path.join(dir, "napuketto.toml"), tomlTemplate(), "utf8");
|
|
192
|
+
await writeFile(path.join(dir, "readme.md"), readmeTemplate(name), "utf8");
|
|
193
|
+
await writeFile(path.join(dir, ".gitignore"), GITIGNORE, "utf8");
|
|
194
|
+
return {
|
|
195
|
+
dir,
|
|
196
|
+
packageName
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
//#endregion
|
|
200
|
+
//#region src/index.ts
|
|
201
|
+
/**
|
|
202
|
+
* create-napukettoqq 入口(2026-08-07)。
|
|
203
|
+
*
|
|
204
|
+
* 用法:
|
|
205
|
+
* create-napukettoqq # 交互问部署文件夹名(默认 NapukettoQQ)
|
|
206
|
+
* create-napukettoqq my-bot # 位置参数指定文件夹名,跳过交互
|
|
207
|
+
*
|
|
208
|
+
* 在当前目录下生成 NapukettoQQ 机器人项目骨架(package.json / napuketto.toml /
|
|
209
|
+
* readme.md / .gitignore),随后打印下一步指引(pnpm install && pnpm start)。
|
|
210
|
+
*/
|
|
211
|
+
/** 交互询问部署文件夹名(回车取默认值)。 */
|
|
212
|
+
async function askProjectName() {
|
|
213
|
+
const rl = createInterface({
|
|
214
|
+
input: process$1.stdin,
|
|
215
|
+
output: process$1.stdout
|
|
216
|
+
});
|
|
217
|
+
try {
|
|
218
|
+
return (await rl.question(`? 部署文件夹名(默认 NapukettoQQ): `)).trim() || "NapukettoQQ";
|
|
219
|
+
} finally {
|
|
220
|
+
rl.close();
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
/** 打印生成结果与下一步指引(功能输出,不经日志框架)。 */
|
|
224
|
+
function printNextSteps(dir) {
|
|
225
|
+
console.log("\n========================================");
|
|
226
|
+
console.log(" NapukettoQQ 项目已生成");
|
|
227
|
+
console.log(` 位置:${dir}`);
|
|
228
|
+
console.log("========================================");
|
|
229
|
+
console.log("下一步:");
|
|
230
|
+
console.log(` cd ${dir}`);
|
|
231
|
+
console.log(" pnpm install");
|
|
232
|
+
console.log(" pnpm start -q <你的QQ号>");
|
|
233
|
+
console.log("");
|
|
234
|
+
console.log("前置要求:本机已安装 QQ NT(wrapper.node 来自 QQ 安装目录)。");
|
|
235
|
+
console.log("详细说明见项目内 readme.md 与 napuketto.toml。");
|
|
236
|
+
}
|
|
237
|
+
async function main() {
|
|
238
|
+
printNextSteps((await scaffoldProject(process$1.argv[2] ?? await askProjectName())).dir);
|
|
239
|
+
}
|
|
240
|
+
main().catch((err) => {
|
|
241
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
242
|
+
console.error(`创建失败:${message}`);
|
|
243
|
+
process$1.exitCode = 1;
|
|
244
|
+
});
|
|
245
|
+
//#endregion
|
|
246
|
+
export {};
|
|
247
|
+
|
|
248
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["process"],"sources":["../src/scaffold.ts","../src/index.ts"],"sourcesContent":["/**\n * create-napukettoqq 脚手架核心:模板 + 目标目录创建 + 文件写入。\n *\n * 零依赖(仅 node:fs/promises / node:os / node:path / node:process),\n * 一次性工具保持自包含。生成的用户项目依赖发布版的 @napuketto/cli,\n * 用户 install 后经 cli → loader 自建宿主启动。\n */\n\nimport { mkdir, readdir, writeFile } from \"node:fs/promises\";\nimport { homedir } from \"node:os\";\nimport path from \"node:path\";\n\n/** 生成的用户项目所依赖的 @napuketto/cli 版本范围(发布新版时统一改)。 */\nexport const CLI_VERSION = \"^0.0.1\";\n\n/** 默认部署文件夹名(用户交互回车缺省值)。 */\nexport const DEFAULT_PROJECT_NAME = \"NapukettoQQ\";\n\n/** Windows 路径非法字符(项目文件夹名校验用)。 */\nconst ILLEGAL_NAME = /[\\\\/:*?\"<>|]/;\n\n/** 脚手架生成结果。 */\nexport interface ScaffoldResult {\n /** 目标目录绝对路径。 */\n dir: string;\n /** 派生出的 npm 包名(小写、空格 → -)。 */\n packageName: string;\n}\n\n/** 校验文件夹名:非空、非 . / ..、不含 Windows 非法字符。 */\nexport function validateProjectName(raw: string): string {\n const name = raw.trim();\n if (name === \"\" || name === \".\" || name === \"..\") {\n throw new Error(\"文件夹名不能为空或为 . / ..\");\n }\n if (ILLEGAL_NAME.test(name)) {\n throw new Error(`文件夹名含非法字符:${name}(不允许 \\\\ / : * ? \" < > |)`);\n }\n return name;\n}\n\n/** 由文件夹名派生 npm 包名(小写、空格 → -)。 */\nexport function derivePackageName(dirName: string): string {\n return dirName.toLowerCase().replace(/\\s+/g, \"-\");\n}\n\n/** 生成 package.json(用户项目,JSON.stringify 保证合法)。 */\nfunction packageJsonTemplate(packageName: string): string {\n const pkg = {\n name: packageName,\n version: \"0.0.1\",\n private: true,\n type: \"module\",\n description: \"NapukettoQQ 机器人项目(OneBot 11)\",\n scripts: {\n start: \"napuketto\",\n },\n dependencies: {\n \"@napuketto/cli\": CLI_VERSION,\n },\n };\n return `${JSON.stringify(pkg, null, 4)}\\n`;\n}\n\n/**\n * 生成 napuketto.toml:与 cli configTemplate(apps/cli/src/config-cmds.ts)同款内容,\n * dataDir 按当前用户主目录插值(JSON.stringify 转义反斜杠 → TOML 基本字符串合法写法)。\n */\nfunction tomlTemplate(): string {\n const dataDirLiteral = JSON.stringify(path.join(homedir(), \".napuketto\"));\n return `# ============================================================\n# NapukettoQQ 全局配置文件(由 create-napukettoqq 生成)\n# ============================================================\n# 本文件与项目 napuketto.toml.example 内容一致(参考模板)。\n# 数据(账号目录/日志/缓存/QQ 数据)不在此文件,按数据根组织:\n# 优先级:--data-dir <dir> > NAPKETTO_DATA 环境变量 > ~/.napuketto\n# 配置文件路径解析:NAPKETTO_CONFIG > 项目根探测 > cwd > 数据根兜底。\n#\n# 单账号启动每次读取本文件;修改后重启生效。\n\n# ------------------------------------------------------------\n# 基础配置\n# ------------------------------------------------------------\n\n# 数据根目录:账号目录/日志/缓存/QQ 数据存放位置(绝对路径)\ndataDir = ${dataDirLiteral}\n\n# 多账号(supervisor)模式下,账号进程崩溃是否自动重启\nautoRestart = true\n\n# 崩溃后自动重启的延迟(毫秒)\nrestartDelayMs = 2000\n\n# 多账号列表(留空 = 单账号模式:启动后自动快速登录/扫码)\n# [[accounts]]\n# qq = \"123456\" # QQ 号(必填)\n# enabled = true # 是否启用(可选,缺省 true)\n\n# ------------------------------------------------------------\n# OneBot 11 协议段\n# ------------------------------------------------------------\n[onebot11]\n\n# 鉴权 token(全局默认):HTTP/WS 连接必须携带。\n# 校验方式:Authorization: Bearer <token> / 裸 token / URL 参数 ?access_token=<token>\n# 每个网络实例可单独覆盖(见下文各实例的 token 字段)。\n# 留空 = 不鉴权(仅本机调试推荐)。\n# token = \"\"\n\n# 心跳 meta 事件间隔(毫秒);0 = 关闭心跳事件\nheartbeatInterval = 3000\n\n# 是否上报机器人自己发的消息(OB11 规范默认不上报)\nreportSelfMessage = false\n\n# 消息内容格式:array = 消息段数组(标准 OneBot 11),string = CQ 码字符串\nmessagePostFormat = \"array\"\n\n# ---- HTTP 反向服务器(接收第三方 POST 指令),可配置多个 ----\n[[onebot11.httpServers]]\nenabled = true\nhost = \"127.0.0.1\" # 监听地址;0.0.0.0 = 监听所有网卡(局域网可连)\nport = 3000\n# token = \"abc\" # 可选:覆盖全局 token\n\n# ---- HTTP 正向上报(Webhook:把事件 POST 到第三方地址),可配置多个 ----\n# [[onebot11.httpPostUrls]]\n# enabled = true\n# url = \"http://127.0.0.1:8080/onebot\" # 第三方接收地址\n# token = \"abc\" # 可选:覆盖全局 token\n# timeoutMs = 5000 # 可选:上报超时(毫秒),缺省不超时\n\n# ---- WS 反向服务器(外部 WS 客户端主动连入),可配置多个 ----\n[[onebot11.wsServers]]\nenabled = true\nhost = \"127.0.0.1\"\nport = 3001\n# token = \"abc\" # 可选:覆盖全局 token\n# heartbeatInterval = 30000 # 可选:WS ping 间隔(毫秒)\n\n# ---- WS 正向客户端(主动连接外部 WS,双向),可配置多个 ----\n# [[onebot11.wsReverseUrls]]\n# enabled = true\n# url = \"ws://127.0.0.1:8081/ws\" # 第三方 WS 地址(ws:// 或 wss://)\n# token = \"abc\" # 可选:覆盖全局 token\n# reconnectDelayMs = 5000 # 可选:断线重连延迟(毫秒)\n# maxReconnectAttempts = 10 # 可选:最大重连次数(缺省无限)\n# rejectUnauthorized = true # 可选:wss:// 是否校验证书(自签证书设 false)\n# heartbeatInterval = 30000 # 可选:WS ping 间隔(毫秒)\n`;\n}\n\n/** 生成 readme.md(用户项目使用说明)。 */\nfunction readmeTemplate(dirName: string): string {\n return `# ${dirName}\n\n基于 **NapukettoQQ** 的 QQ 机器人项目(OneBot 11 协议),由 \\`create-napukettoqq\\` 生成。\n\n## 快速开始\n\n\\`\\`\\`bash\npnpm install\npnpm start -q 123456 # 换成你的 QQ 号\n\\`\\`\\`\n\n启动后按终端提示快速登录或扫码;登录成功后 OneBot 11 接口生效\n(默认 HTTP \\`127.0.0.1:3000\\` + WS \\`127.0.0.1:3001\\`,见 \\`napuketto.toml\\`)。\n\n## 前置要求\n\n- 已安装 **QQ NT**(Windows,机器人所需的 \\`wrapper.node\\` 来自 QQ 安装目录,\n 未自动探测到时用 \\`pnpm start --qq-path <QQ安装目录>\\` 指定)\n- Node.js 20+ 与 pnpm\n\n## 常用命令\n\n| 命令 | 说明 |\n|---|---|\n| \\`pnpm start -q <QQ号>\\` | 单账号启动(走自建宿主) |\n| \\`pnpm napuketto config init\\` | 重新生成默认配置 |\n| \\`pnpm napuketto supervisor\\` | 多账号模式(按 \\`napuketto.toml\\` 的 \\`accounts\\`) |\n\n## 目录\n\n- \\`napuketto.toml\\` — 全局配置(QQ 号、OneBot 端口、token 等,修改后重启生效)\n- QQ 数据(账号目录/日志/缓存)默认在 \\`~/.napuketto/\\`\n\n## 升级\n\n\\`\\`\\`bash\npnpm update @napuketto/cli\n\\`\\`\\`\n`;\n}\n\n/** 生成 .gitignore(用户项目)。 */\nconst GITIGNORE = `node_modules/\ndist/\n*.log\nnapuketto-data/\n`;\n\n/**\n * 生成 NapukettoQQ 项目骨架到当前目录下的 <dirName>/。\n * 目标目录已存在且非空 → 抛错(提示换名字或先清空)。\n */\nexport async function scaffoldProject(dirName: string): Promise<ScaffoldResult> {\n const name = validateProjectName(dirName);\n const packageName = derivePackageName(name);\n const dir = path.resolve(process.cwd(), name);\n\n // 目录已存在且非空 → 拒绝(避免覆盖用户文件)\n let existing: string[] = [];\n try {\n existing = await readdir(dir);\n } catch {\n // 目录不存在,可直接创建\n }\n if (existing.length > 0) {\n throw new Error(`目录已存在且非空:${dir}\\n请换一个文件夹名,或先清空该目录。`);\n }\n\n await mkdir(dir, { recursive: true });\n await writeFile(path.join(dir, \"package.json\"), packageJsonTemplate(packageName), \"utf8\");\n await writeFile(path.join(dir, \"napuketto.toml\"), tomlTemplate(), \"utf8\");\n await writeFile(path.join(dir, \"readme.md\"), readmeTemplate(name), \"utf8\");\n await writeFile(path.join(dir, \".gitignore\"), GITIGNORE, \"utf8\");\n\n return { dir, packageName };\n}\n","#!/usr/bin/env node\n\n/**\n * create-napukettoqq 入口(2026-08-07)。\n *\n * 用法:\n * create-napukettoqq # 交互问部署文件夹名(默认 NapukettoQQ)\n * create-napukettoqq my-bot # 位置参数指定文件夹名,跳过交互\n *\n * 在当前目录下生成 NapukettoQQ 机器人项目骨架(package.json / napuketto.toml /\n * readme.md / .gitignore),随后打印下一步指引(pnpm install && pnpm start)。\n */\n\nimport process from \"node:process\";\nimport { createInterface } from \"node:readline/promises\";\nimport { DEFAULT_PROJECT_NAME, scaffoldProject } from \"./scaffold.js\";\n\n/** 交互询问部署文件夹名(回车取默认值)。 */\nasync function askProjectName(): Promise<string> {\n const rl = createInterface({ input: process.stdin, output: process.stdout });\n try {\n const answer = await rl.question(`? 部署文件夹名(默认 ${DEFAULT_PROJECT_NAME}): `);\n return answer.trim() || DEFAULT_PROJECT_NAME;\n } finally {\n rl.close();\n }\n}\n\n/** 打印生成结果与下一步指引(功能输出,不经日志框架)。 */\nfunction printNextSteps(dir: string): void {\n console.log(\"\\n========================================\");\n console.log(\" NapukettoQQ 项目已生成\");\n console.log(` 位置:${dir}`);\n console.log(\"========================================\");\n console.log(\"下一步:\");\n console.log(` cd ${dir}`);\n console.log(\" pnpm install\");\n console.log(\" pnpm start -q <你的QQ号>\");\n console.log(\"\");\n console.log(\"前置要求:本机已安装 QQ NT(wrapper.node 来自 QQ 安装目录)。\");\n console.log(\"详细说明见项目内 readme.md 与 napuketto.toml。\");\n}\n\nasync function main(): Promise<void> {\n const dirArg = process.argv[2];\n const dirName = dirArg ?? (await askProjectName());\n const result = await scaffoldProject(dirName);\n printNextSteps(result.dir);\n}\n\nmain().catch((err: unknown) => {\n const message = err instanceof Error ? err.message : String(err);\n console.error(`创建失败:${message}`);\n process.exitCode = 1;\n});\n"],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "create-napukettoqq",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "一键生成 NapukettoQQ 机器人项目(yarn/pnpm/npm create napukettoqq)",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"files": [
|
|
7
|
+
"dist"
|
|
8
|
+
],
|
|
9
|
+
"main": "./dist/index.mjs",
|
|
10
|
+
"bin": {
|
|
11
|
+
"create-napukettoqq": "./dist/index.mjs"
|
|
12
|
+
},
|
|
13
|
+
"devDependencies": {
|
|
14
|
+
"tsdown": "^0.22.14"
|
|
15
|
+
},
|
|
16
|
+
"license": "MIT",
|
|
17
|
+
"scripts": {
|
|
18
|
+
"dev": "tsdown --watch",
|
|
19
|
+
"build": "tsdown"
|
|
20
|
+
}
|
|
21
|
+
}
|