@cxyhhhhh/qqbot-cli 0.1.0-dev.202606011703
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/README.md +239 -0
- package/dist/bin/cli.d.ts +1 -0
- package/dist/bin/cli.js +25 -0
- package/dist/bin/cli.js.map +1 -0
- package/dist/chunk-WRKDI4MF.js +407 -0
- package/dist/chunk-WRKDI4MF.js.map +1 -0
- package/dist/chunk-XIJ6OSLY.js +3654 -0
- package/dist/chunk-XIJ6OSLY.js.map +1 -0
- package/dist/cli-TUC3HG75.js +14 -0
- package/dist/cli-TUC3HG75.js.map +1 -0
- package/dist/src/index.d.ts +1540 -0
- package/dist/src/index.js +11 -0
- package/dist/src/index.js.map +1 -0
- package/package.json +73 -0
- package/templates/bot.cloudagent.yaml +131 -0
- package/templates/bot.echo.yaml +55 -0
- package/templates/bot.galileo.yaml +63 -0
- package/templates/bot.openai.yaml +63 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli.ts","../src/utils/logger.ts","../src/utils/graceful.ts","../src/telemetry/index.ts","../src/version.ts"],"sourcesContent":["/**\n * CLI 命令实现\n */\n\nimport * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport { loadConfig } from \"./config/loader.js\";\nimport { ConfigWatcher } from \"./config/watcher.js\";\nimport { BotRunner } from \"./runner.js\";\nimport { createLogger } from \"./utils/logger.js\";\nimport { setupGracefulShutdown } from \"./utils/graceful.js\";\nimport { initTelemetry, shutdownTelemetry } from \"./telemetry/index.js\";\nimport { APP_VERSION } from \"./version.js\";\n\nexport interface StartOptions {\n config: string;\n env?: string;\n verbose?: boolean;\n}\n\nexport async function startCommand(opts: StartOptions): Promise<void> {\n // 加载 .env\n if (opts.env) {\n const { config } = await import(\"dotenv\");\n config({ path: opts.env });\n } else if (fs.existsSync(\".env\")) {\n const { config } = await import(\"dotenv\");\n config();\n }\n\n const logLevel = opts.verbose ? \"debug\" : undefined;\n let logger = createLogger(undefined, logLevel);\n\n let config;\n try {\n config = await loadConfig(opts.config);\n } catch (err) {\n logger.error(`配置错误: ${err instanceof Error ? err.message : String(err)}`);\n process.exit(2);\n }\n\n // 用配置文件中的 log 配置重建 logger(--verbose 优先级最高)\n const effectiveLevel = logLevel ?? config.log.level;\n config.log.level = effectiveLevel as typeof config.log.level;\n logger = createLogger(config.log, logLevel);\n\n // 初始化 OpenTelemetry(必须在业务代码之前)\n initTelemetry(config.telemetry, logger, { appId: config.qq.appId });\n\n logger.info(`qqbot-cli v${APP_VERSION} 启动中...`);\n logger.info(` 配置: ${opts.config}`);\n logger.info(` 后端: ${config.backend.type}`);\n logger.info(` 传输: ${config.qq.transport}${config.qq.transport === \"webhook\" ? ` (port=${config.qq.webhook.port}, path=${config.qq.webhook.path})` : \"\"}`);\n logger.info(` AppID: ${config.qq.appId}`);\n if (config.telemetry.enabled) {\n logger.info(` Telemetry: ${config.telemetry.endpoint} (sample=${config.telemetry.sampleRate})`);\n }\n\n const runner = new BotRunner(config, logger);\n\n // 配置热更新\n const watcher = new ConfigWatcher({\n configPath: path.resolve(opts.config),\n currentConfig: config,\n logger,\n onChange: (newConfig) => {\n // --verbose 优先级最高,覆盖配置文件的 log.level\n if (logLevel) {\n newConfig.log.level = logLevel as typeof newConfig.log.level;\n }\n runner.applyConfigUpdate(newConfig);\n },\n });\n watcher.start();\n\n // 注入配置写回能力:斜杠指令修改的配置会同步写回 YAML 文件\n runner.setConfigWriter((patches, currentConfig) => watcher.writeBack(patches, currentConfig));\n\n const ac = setupGracefulShutdown(logger, async () => {\n await shutdownTelemetry();\n watcher.stop();\n await runner.stop();\n });\n\n try {\n await runner.start(ac.signal);\n logger.info(\"Bot 已停止。\");\n } catch (err) {\n logger.error(`启动失败: ${err instanceof Error ? err.message : String(err)}`);\n process.exit(1);\n }\n}\n\nexport interface InitOptions {\n template: string;\n output: string;\n}\n\nexport async function initCommand(opts: InitOptions): Promise<void> {\n const templateFile = path.resolve(\n path.dirname(new URL(import.meta.url).pathname),\n `../templates/bot.${opts.template}.yaml`,\n );\n\n if (!fs.existsSync(templateFile)) {\n console.error(`❌ 未知模板: ${opts.template}(可选: cloudagent | openai | echo)`);\n process.exit(2);\n }\n\n if (fs.existsSync(opts.output)) {\n console.error(`⚠️ ${opts.output} 已存在,跳过生成。`);\n process.exit(0);\n }\n\n fs.copyFileSync(templateFile, opts.output);\n console.log(`✅ 已生成 ${opts.output}(模板: ${opts.template})`);\n console.log(`\\n下一步:`);\n console.log(` 1. 编辑 ${opts.output},填入 AppID / AppSecret / API Key`);\n console.log(` 2. 运行 qqbot-cli start --config ${opts.output}`);\n}\n\nexport interface ValidateOptions {\n config: string;\n}\n\nexport async function validateCommand(opts: ValidateOptions): Promise<void> {\n try {\n const config = await loadConfig(opts.config);\n console.log(`✅ 配置文件有效`);\n console.log(` 后端: ${config.backend.type}`);\n console.log(` AppID: ${config.qq.appId}`);\n } catch (err) {\n console.error(`❌ 配置无效: ${err instanceof Error ? err.message : String(err)}`);\n process.exit(2);\n }\n}\n\n// ============ send command ============\n\nexport interface SendOptions {\n config: string;\n env?: string;\n to: string;\n scope: \"c2c\" | \"group\";\n file?: string[];\n filePrefix?: string;\n verbose?: boolean;\n}\n\n/**\n * Send a proactive message (text and/or attachments) to a user or group.\n *\n * Usage:\n * qqbot-cli send --to <openid> --scope c2c \"Hello!\"\n * qqbot-cli send --to <openid> --file photo.png --file report.pdf \"See attached\"\n * qqbot-cli send --to <openid> --file-prefix /host --file /home/user/photo.png\n *\n * In Docker with `-v /:/host:ro`, set FILE_PATH_PREFIX=/host or --file-prefix /host\n * so that `--file /home/user/photo.png` resolves to `/host/home/user/photo.png`.\n */\nexport async function sendCommand(textArgs: string[], opts: SendOptions): Promise<void> {\n // Load .env\n if (opts.env) {\n const { config } = await import(\"dotenv\");\n config({ path: opts.env });\n } else if (fs.existsSync(\".env\")) {\n const { config } = await import(\"dotenv\");\n config();\n }\n\n const logger = createLogger(undefined, opts.verbose ? \"debug\" : \"error\");\n\n let config;\n try {\n config = await loadConfig(opts.config);\n } catch (err) {\n console.error(`❌ Config error: ${err instanceof Error ? err.message : String(err)}`);\n process.exit(2);\n }\n\n if (!opts.to) {\n console.error(\"❌ --to <openid> is required\");\n process.exit(2);\n }\n\n const scope = opts.scope ?? \"c2c\";\n if (scope !== \"c2c\" && scope !== \"group\") {\n console.error(`❌ Invalid scope: ${scope} (must be \"c2c\" or \"group\")`);\n process.exit(2);\n }\n\n const { QQBot, MediaFileType } = await import(\"@tencent/qqbot-nodejs\");\n\n const bot = new QQBot({\n appId: config.qq.appId,\n appSecret: config.qq.appSecret,\n baseUrl: config.qq.baseUrl,\n tokenBaseUrl: config.qq.tokenBaseUrl,\n logger,\n });\n\n const target = { scope, targetId: opts.to } as const;\n const text = textArgs.join(\" \").trim();\n const files = opts.file ?? [];\n const filePrefix = opts.filePrefix ?? process.env.FILE_PATH_PREFIX ?? \"\";\n\n try {\n // Send text message (if provided)\n if (text) {\n const resp = await bot.sendText(target, text);\n console.log(`✅ Text sent (id=${resp.id})`);\n }\n\n // Send attachments\n for (const filePath of files) {\n const resolved = resolveFilePath(filePath, filePrefix);\n if (!fs.existsSync(resolved)) {\n console.error(`❌ File not found: ${resolved}`);\n continue;\n }\n\n const ext = path.extname(resolved).toLowerCase();\n const fileType = inferFileType(ext);\n const fileName = path.basename(resolved);\n const buffer = fs.readFileSync(resolved);\n\n console.log(`📤 Uploading ${fileName} (${formatSize(buffer.length)}, type=${MediaFileType[fileType]}) ...`);\n\n const { upload, message } = await bot.sendMedia({\n target,\n fileType,\n buffer,\n fileName,\n onProgress: (uploaded, total) => {\n const pct = total > 0 ? Math.round((uploaded / total) * 100) : 0;\n process.stdout.write(`\\r Progress: ${pct}% (${formatSize(uploaded)}/${formatSize(total)})`);\n },\n });\n\n process.stdout.write(\"\\n\");\n console.log(`✅ ${fileName} sent (file_uuid=${upload.file_uuid ?? \"-\"}, msg_id=${message?.id ?? \"-\"})`);\n }\n\n if (!text && files.length === 0) {\n console.error(\"❌ Nothing to send. Provide text and/or --file <path>.\");\n process.exit(2);\n }\n } catch (err) {\n console.error(`❌ Send failed: ${err instanceof Error ? err.message : String(err)}`);\n process.exit(1);\n }\n}\n\nconst IMAGE_EXTS = new Set([\".jpg\", \".jpeg\", \".png\", \".gif\", \".webp\", \".bmp\"]);\nconst VIDEO_EXTS = new Set([\".mp4\", \".mov\", \".avi\", \".mkv\", \".webm\"]);\nconst VOICE_EXTS = new Set([\".mp3\", \".wav\", \".ogg\", \".aac\", \".silk\", \".amr\"]);\n\nfunction inferFileType(ext: string): number {\n if (IMAGE_EXTS.has(ext)) return 1; // IMAGE\n if (VIDEO_EXTS.has(ext)) return 2; // VIDEO\n if (VOICE_EXTS.has(ext)) return 3; // VOICE\n return 4; // FILE\n}\n\nfunction formatSize(bytes: number): string {\n if (bytes < 1024) return `${bytes}B`;\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)}KB`;\n return `${(bytes / (1024 * 1024)).toFixed(1)}MB`;\n}\n\n/**\n * Resolve a file path with an optional prefix.\n *\n * When running in Docker with `-v /:/host:ro`, the user passes host paths\n * (e.g. `/home/user/photo.png`) but the file lives at `/host/home/user/photo.png`\n * inside the container. Setting `--file-prefix /host` or `FILE_PATH_PREFIX=/host`\n * handles this transparently.\n *\n * If the file already exists at the original path, the prefix is skipped.\n */\nfunction resolveFilePath(filePath: string, prefix: string): string {\n const resolved = path.resolve(filePath);\n if (!prefix || fs.existsSync(resolved)) {\n return resolved;\n }\n // Prepend prefix: /host + /home/user/file.png → /host/home/user/file.png\n const prefixed = path.join(prefix, resolved);\n return prefixed;\n}\n","/**\n * 统一日志 — 基于 pino 的生产级日志系统\n *\n * 特性:\n * - 异步 I/O(worker thread),不阻塞事件循环\n * - 支持文件滚动(pino-roll)\n * - 控制台 pretty / json 双模式\n * - 敏感信息脱敏(pino redact)\n * - 直接导出 pino Logger 类型,支持结构化日志\n */\n\nimport pino from \"pino\";\nimport { mkdirSync } from \"node:fs\";\nimport { join, resolve } from \"node:path\";\n\n// ============ Public Types ============\n\nexport type Logger = pino.Logger;\n\nexport interface LogConfig {\n level: string;\n console: \"json\" | \"pretty\";\n file: {\n enabled: boolean;\n dir: string;\n maxSize: string;\n maxFiles: number;\n frequency?: \"daily\" | \"hourly\" | \"weekly\";\n dateFormat?: string;\n symlink?: boolean;\n };\n}\n\n// ============ Factory ============\n\n/**\n * 创建 Logger 实例。\n *\n * @param config - 完整日志配置(来自 schema 解析)\n * @param levelOverride - CLI --verbose 等场景的级别覆盖\n */\nexport function createLogger(config?: Partial<LogConfig>, levelOverride?: string): Logger {\n const level = levelOverride ?? config?.level ?? \"info\";\n const consoleMode = config?.console ?? \"pretty\";\n const file = config?.file ?? { enabled: false, dir: \"./logs\", maxSize: \"10m\", maxFiles: 7 };\n\n const targets: pino.TransportTargetOptions[] = [];\n\n // Target 1: 控制台(stderr)\n if (consoleMode === \"pretty\") {\n targets.push({\n target: \"pino-pretty\",\n options: {\n destination: 2,\n colorize: process.stderr.isTTY ?? false,\n translateTime: \"SYS:yyyy-mm-dd HH:MM:ss.l\",\n ignore: \"pid,hostname\",\n },\n level,\n });\n } else {\n targets.push({\n target: \"pino/file\",\n options: { destination: 2 },\n level,\n });\n }\n\n // Target 2: 文件滚动\n if (file.enabled) {\n const dir = resolve(file.dir);\n mkdirSync(dir, { recursive: true });\n\n targets.push({\n target: \"pino-roll\",\n options: {\n file: join(dir, \"qqbot\"),\n size: file.maxSize,\n limit: { count: file.maxFiles },\n mkdir: true,\n ...(file.frequency ? { frequency: file.frequency } : {}),\n ...(file.dateFormat ? { dateFormat: file.dateFormat } : {}),\n ...(file.symlink ? { symlink: true } : {}),\n },\n level,\n });\n }\n\n return pino(\n {\n level,\n redact: {\n paths: [\"req.headers.authorization\", \"access_token\"],\n censor: \"***\",\n },\n },\n pino.transport({ targets }),\n );\n}\n","/**\n * 优雅退出\n */\n\nimport type { Logger } from \"./logger.js\";\n\nexport function setupGracefulShutdown(\n logger: Logger,\n cleanup: () => Promise<void>,\n): AbortController {\n const ac = new AbortController();\n let shuttingDown = false;\n\n const shutdown = async (signal: string) => {\n if (shuttingDown) return;\n shuttingDown = true;\n logger.info(`收到 ${signal},正在停止...`);\n try {\n ac.abort();\n await cleanup();\n } catch (err) {\n logger.warn(`清理出错: ${err instanceof Error ? err.message : String(err)}`);\n }\n process.exit(0);\n };\n\n process.on(\"SIGINT\", () => void shutdown(\"SIGINT\"));\n process.on(\"SIGTERM\", () => void shutdown(\"SIGTERM\"));\n process.on(\"uncaughtException\", (err) => {\n logger.error(`uncaughtException: ${err.stack ?? err.message}`);\n });\n process.on(\"unhandledRejection\", (err: unknown) => {\n logger.error(`unhandledRejection: ${err instanceof Error ? err.stack ?? err.message : String(err)}`);\n });\n\n return ac;\n}\n","/**\n * Telemetry — OpenTelemetry 初始化\n *\n * 统一手动管理 TracerProvider + MeterProvider,职责清晰。\n * telemetry.enabled: false 时不初始化,零开销。\n */\n\nimport { metrics, diag, DiagConsoleLogger, DiagLogLevel } from \"@opentelemetry/api\";\nimport { OTLPTraceExporter } from \"@opentelemetry/exporter-trace-otlp-http\";\nimport { OTLPMetricExporter } from \"@opentelemetry/exporter-metrics-otlp-http\";\nimport {\n MeterProvider,\n PeriodicExportingMetricReader,\n ConsoleMetricExporter,\n AggregationTemporality,\n} from \"@opentelemetry/sdk-metrics\";\nimport { NodeTracerProvider, BatchSpanProcessor } from \"@opentelemetry/sdk-trace-node\";\nimport { Resource } from \"@opentelemetry/resources\";\nimport { W3CTraceContextPropagator, TraceIdRatioBasedSampler } from \"@opentelemetry/core\";\nimport { GALILEO_RESOURCE } from \"./constants.js\";\nimport { setBizDefaultAttrs } from \"./metrics.js\";\nimport { APP_VERSION } from \"../version.js\";\nimport { networkInterfaces } from \"node:os\";\n\nfunction getLocalIp(): string {\n // 优先从环境变量获取(Docker/K8s 场景通过 env 注入)\n const envIp = process.env.POD_IP || process.env.HOST_IP || process.env.INSTANCE_IP;\n if (envIp) return envIp;\n\n const interfaces = networkInterfaces();\n for (const name of Object.keys(interfaces)) {\n for (const iface of interfaces[name] ?? []) {\n if (iface.family === \"IPv4\" && !iface.internal) {\n return iface.address;\n }\n }\n }\n return \"\";\n}\n\n// ============ Config ============\n\nexport interface TelemetryConfig {\n enabled: boolean;\n /** 开启 OTEL 内部诊断日志和控制台指标输出 */\n debug?: boolean;\n serviceName: string;\n endpoint: string;\n protocol: \"http\" | \"grpc\";\n sampleRate: number;\n exportIntervalMs: number;\n attributes: Record<string, string>;\n /** 平台扩展配置(可选) */\n galileo?: {\n platform: string;\n app: string;\n server: string;\n namespace: string;\n envName: string;\n };\n}\n\n// ============ State ============\n\nlet tracerProvider: NodeTracerProvider | null = null;\nlet meterProvider: MeterProvider | null = null;\n\n// ============ Init ============\n\nexport interface InitTelemetryOptions {\n appId?: string;\n}\n\nexport function initTelemetry(config: TelemetryConfig, logger?: { info: (msg: string) => void; debug: (msg: string) => void }, opts?: InitTelemetryOptions): void {\n if (!config.enabled) return;\n\n // 启用 OTEL 内部诊断日志(仅 debug 模式)\n if (config.debug) {\n diag.setLogger(new DiagConsoleLogger(), DiagLogLevel.DEBUG);\n }\n\n const galileo = config.galileo;\n const objectName = galileo ? `${galileo.app}.${galileo.server}` : config.serviceName;\n\n // Resource\n const resourceAttrs: Record<string, string> = {\n \"service.name\": objectName,\n [GALILEO_RESOURCE.SERVICE_NAME]: objectName,\n [GALILEO_RESOURCE.SDK_LANGUAGE]: \"nodejs\",\n [GALILEO_RESOURCE.SDK_NAME]: \"qqbot-cli\",\n [GALILEO_RESOURCE.APP_ID]: opts?.appId ?? \"\",\n ...config.attributes,\n };\n\n if (galileo) {\n resourceAttrs[GALILEO_RESOURCE.TARGET] = `${galileo.platform}.${objectName}`;\n resourceAttrs[GALILEO_RESOURCE.NAMESPACE] = galileo.namespace;\n resourceAttrs[GALILEO_RESOURCE.ENV_NAME] = galileo.envName;\n resourceAttrs[GALILEO_RESOURCE.CONTAINER_NAME] = \"\";\n resourceAttrs[GALILEO_RESOURCE.INSTANCE] = getLocalIp();\n resourceAttrs[GALILEO_RESOURCE.VERSION] = APP_VERSION;\n resourceAttrs[GALILEO_RESOURCE.CON_SETID] = \"\";\n }\n\n const resource = new Resource(resourceAttrs);\n\n // 设置业务指标默认维度(Metric Attributes 级别)\n setBizDefaultAttrs({\n app_id: opts?.appId ?? \"\",\n instance: getLocalIp(),\n version: APP_VERSION,\n });\n\n const metricsUrl = `${config.endpoint}/v1/metrics`;\n const tracesUrl = `${config.endpoint}/v1/traces`;\n\n // ─── TracerProvider ───\n\n tracerProvider = new NodeTracerProvider({\n resource,\n sampler: new TraceIdRatioBasedSampler(config.sampleRate),\n });\n\n tracerProvider.addSpanProcessor(\n new BatchSpanProcessor(new OTLPTraceExporter({ url: tracesUrl })),\n );\n\n tracerProvider.register({\n propagator: new W3CTraceContextPropagator(),\n });\n\n // ─── MeterProvider ───\n\n meterProvider = new MeterProvider({ resource });\n\n meterProvider.addMetricReader(\n new PeriodicExportingMetricReader({\n exporter: new OTLPMetricExporter({\n url: metricsUrl,\n temporalityPreference: AggregationTemporality.DELTA,\n }),\n exportIntervalMillis: config.exportIntervalMs,\n }),\n );\n\n if (config.debug) {\n meterProvider.addMetricReader(\n new PeriodicExportingMetricReader({\n exporter: new ConsoleMetricExporter(),\n exportIntervalMillis: config.exportIntervalMs,\n }),\n );\n }\n\n metrics.setGlobalMeterProvider(meterProvider);\n logger?.info(`[telemetry] ready (metrics=${metricsUrl}, traces=${tracesUrl})`);\n}\n\n// ============ Flush ============\n\nexport async function flushTelemetry(): Promise<void> {\n await Promise.all([\n tracerProvider?.forceFlush(),\n meterProvider?.forceFlush(),\n ]);\n}\n\n// ============ Shutdown ============\n\nexport async function shutdownTelemetry(): Promise<void> {\n await tracerProvider?.shutdown();\n await meterProvider?.shutdown();\n tracerProvider = null;\n meterProvider = null;\n}\n","/**\n * 应用版本号\n *\n * - 生产构建:tsup define 注入 __PKG_VERSION__\n * - 开发模式(tsx):从 package.json 动态读取\n *\n * 使用方式:import { APP_VERSION } from \"./version.js\";\n */\n\nimport { createRequire } from \"node:module\";\n\ndeclare const __PKG_VERSION__: string;\n\nfunction resolveVersion(): string {\n if (typeof __PKG_VERSION__ !== \"undefined\") return __PKG_VERSION__;\n try {\n const req = createRequire(import.meta.url);\n try {\n return (req(\"../package.json\") as { version: string }).version;\n } catch {\n return (req(\"../../package.json\") as { version: string }).version;\n }\n } catch {\n return \"0.0.0-dev\";\n }\n}\n\nexport const APP_VERSION: string = resolveVersion();\n"],"mappings":"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","names":["config"]}
|