New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

koishi-plugin-teach

Package Overview
Dependencies
Maintainers
1
Versions
145
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

koishi-plugin-teach - npm Package Compare versions

Comparing version 0.1.0 to 0.1.1

dist/database.d.ts

23

package.json
{
"name": "koishi-plugin-teach",
"version": "0.1.0",
"version": "0.1.1",
"main": "dist/index.js",

@@ -8,6 +8,23 @@ "typings": "dist/index.d.ts",

"license": "MIT",
"scripts": {
"build": "tsc -b",
"lint": "eslint src --ext .ts"
},
"repository": {
"type": "git",
"url": "git+https://github.com/koishijs/koishi.git"
},
"bugs": {
"url": "https://github.com/koishijs/koishi/issues"
},
"homepage": "https://github.com/koishijs/koishi/packages/plugin-teach#readme",
"devDependencies": {
"koishi-database-level": "^1.0.0-alpha.5",
"koishi-database-mysql": "^1.0.0-alpha.5"
},
"dependencies": {
"koishi-core": "^0.1.0",
"koishi-utils": "^0.1.0"
"fast-deep-equal": "^3.1.1",
"koishi-core": "^1.0.0-alpha.5",
"koishi-utils": "^1.0.0-alpha.1"
}
}

6

README.md

@@ -1,2 +0,4 @@

# plugin-teach
# [koishi-plugin-teach](https://koishijs.github.io/plugins/teach.html)
[![npm](https://img.shields.io/npm/v/koishi-plugin-teach?style=flat-square)](https://www.npmjs.com/package/koishi-plugin-teach)

@@ -1,4 +0,4 @@

import { GroupContext } from 'koishi-core'
import { Context } from 'koishi-core'
import info from './info'
import parseOptions from './utils'
import parseOptions, { TeachConfig } from './utils'
import receiver from './receiver'

@@ -9,38 +9,22 @@ import search from './search'

import './dialogue'
export * from './database'
export { TeachConfig }
export function apply (ctx: GroupContext) {
ctx.plugin(receiver)
export function apply (ctx: Context, config: TeachConfig = {}) {
ctx.plugin(receiver, config)
ctx.command('teach <question> <answer>', '教四季酱说话', { authority: 2 })
const command = ctx.command('teach <question> <answer>', '教四季酱说话', { authority: 2, checkUnknown: true, ...config })
.alias('教学')
.shortcut('教学信息', { options: { info: true } })
.shortcut('全局教学信息', { options: { info: true, allEnv: true } })
.config({
maxUsage: ({ authority: auth }) => auth < 3 ? 10 : auth < 4 ? 30 : Infinity
})
.option('-q, --question <question>', '搜索或修改已有问题', { notUsage: true, type: String })
.option('-a, --answer <answer>', '搜索或修改已有回答', { notUsage: true, type: String })
.option('-q, --question <question>', '搜索或修改已有问题', { notUsage: true, isString: true })
.option('-a, --answer <answer>', '搜索或修改已有回答', { notUsage: true, isString: true })
.option('--all', '搜索全部问答')
.option('-f, --frozen', '锁定这个问答', { authority: 4 })
.option('-F, --no-frozen', '解锁这个问答', { authority: 4, noNagated: true })
.option('-k, --keyword', '使用关键词匹配')
.option('-c, --chance <value>', '设置问题的触发概率')
.option('-u, --update <id>', '查看或修改已有问题', { notUsage: true, type: String })
.option('-d, --disable', '在当前环境下禁用问题或回答')
.option('-u, --update <id>', '查看或修改已有问题', { notUsage: true, isString: true })
.option('-D, --delete', '彻底删除问题或回答')
.option('-e, --env <environment>', '设置问题的生效环境', { type: String })
.option('-E, --all-env', '搜索所有环境中的问答')
.option('-g, --global-env', '设置全局生效环境,相当于 -e=*')
.option('-n, --no-env', '设置无生效环境,相当于 -e=""', { noNagated: true })
.option('-w, --writer <qq>', '添加或设置问题的作者', { type: Number })
.option('-W, --anonymous', '添加或设置匿名问题')
.option('-s, --add-successor <id>', '设置后继问题', { type: String })
.option('-S, --remove-successor <id>', '取消后继问题', { type: String })
.option('-p, --add-predecessor <id>', '设置前置问题', { type: String })
.option('-P, --remove-predecessor <id>', '取消前置问题', { type: String })
.option('-i, --info', '查看教学信息', { notUsage: true })
.usage('详细的使用方法请参考:https://shiki.shigma.xyz/manual/teach.html')
.action(async (parsedArgv, question: string, answer: string) => {
const parsedOptions = await parseOptions(ctx, parsedArgv)
const parsedOptions = await parseOptions(ctx, config, parsedArgv)
if (!parsedOptions) return

@@ -55,2 +39,23 @@

})
if (config.useWriter) {
command
.option('-w, --writer <qq>', '添加或设置问题的作者')
.option('-W, --anonymous', '添加或设置匿名问题')
}
if (config.useFrozen) {
command
.option('-f, --frozen', '锁定这个问答', { authority: 4 })
.option('-F, --no-frozen', '解锁这个问答', { authority: 4, noNegated: true })
}
if (config.useEnvironment) {
command
.option('-d, --disable', '在当前环境下禁用问题或回答')
.option('-e, --env <environment>', '设置问题的生效环境', { isString: true })
.option('-E, --all-env', '搜索所有环境中的问答')
.option('-g, --global-env', '设置全局生效环境,相当于 -e=*')
.option('-n, --no-env', '设置无生效环境,相当于 -e=""', { noNegated: true })
}
}
import { TeachOptions } from './utils'
export default async function apply (config: TeachOptions) {
if (config.options.info) {
let { envMode, groups, ctx, meta, options } = config
if (!envMode && !options.allEnv) {
envMode = 1
groups = [meta.groupId]
}
const test = ctx.database.getDialogueTest({ envMode, groups })
const {
'COUNT(DISTINCT `question`)': questions,
'COUNT(*)': answers
} = await ctx.database.query('SELECT COUNT(DISTINCT `question`), COUNT(*) FROM `dialogues`' + test)
return meta.$send(`共收录了 ${questions} 个问题和 ${answers} 个回答。`)
export default async function apply ({ envMode, groups, ctx, meta, options, config }: TeachOptions) {
if (config.useEnvironment && !envMode && !options.allEnv) {
envMode = 1
groups = [meta.groupId]
}
const { questions, answers } = await ctx.database.getDialogueCount({ envMode, groups })
return meta.$send(`共收录了 ${questions} 个问题和 ${answers} 个回答。`)
}

@@ -1,14 +0,6 @@

import { GroupContext, updateActivity } from 'koishi-core'
import { randomPick, cqCode, sleep } from 'koishi-utils'
import { simplifyQuestion, splitIds } from './utils'
import { updateActivity, Context } from 'koishi-core'
import { randomPick, CQCode, sleep } from 'koishi-utils'
import { simplifyQuestion, TeachConfig } from './utils'
import { DialogueTest } from './database'
interface State {
currentUser: number
currentCount: number
predecessors: Record<number, number>
}
const states: Record<number, State> = {}
const MAX_CONSECUTIVE = 5
function escapeAnswer (message: string) {

@@ -18,23 +10,15 @@ return message.replace(/\$/g, '@@__DOLLARS_PLACEHOLDER__@@')

export default function (ctx: GroupContext) {
ctx.middleware(async (meta, next) => {
export default function (ctx: Context, config: TeachConfig) {
ctx.intersect(ctx.app.groups).middleware(async (meta, next) => {
const { groupId } = meta
if (!states[groupId]) states[groupId] = { currentUser: 0, currentCount: 0, predecessors: {} }
const state = states[groupId]
const question = simplifyQuestion(meta.message)
if (!question) return next()
if (state.currentUser !== meta.userId) {
state.currentUser = meta.userId
state.currentCount = 0
} else if (state.currentCount >= MAX_CONSECUTIVE) {
return next()
const test: DialogueTest = { question }
if (config.useEnvironment) {
test.envMode = 1
test.groups = [groupId]
}
const items = await ctx.database.getDialogues({
question,
envMode: 1,
groups: [groupId],
extraIds: Object.keys(state.predecessors),
})
const items = await ctx.database.getDialogues(test)
if (!items.length) return next()

@@ -45,6 +29,5 @@

state.currentCount += 1
const { interactiveness, name } = meta.$user
updateActivity(interactiveness, groupId)
await meta.$user.update()
await meta.$user._update()

@@ -54,4 +37,4 @@ const answers = dialogue.answer

.replace(/\$a/g, `[CQ:at,qq=${meta.userId}]`)
.replace(/\$A/g, `[CQ:at,qq=all]`)
.replace(/\$m/g, cqCode('at', { qq: meta.selfId }))
.replace(/\$A/g, '[CQ:at,qq=all]')
.replace(/\$m/g, CQCode.stringify('at', { qq: meta.selfId }))
.replace(/\$s/g, escapeAnswer(name === String(meta.userId) ? meta.sender.card || meta.sender.nickname : name))

@@ -66,17 +49,3 @@ .replace(/\$0/g, escapeAnswer(meta.message))

}
const successors = await ctx.database.getDialogues(splitIds(dialogue.successors))
if (!successors.length) return
const time = Date.now()
for (const successor of successors) {
state.predecessors[successor.id] = time
}
setTimeout(() => {
const { predecessors } = states[meta.groupId]
for (const successor of successors) {
if (predecessors[successor.id] === time) {
delete predecessors[successor.id]
}
}
}, 20000)
})
}

@@ -10,3 +10,3 @@ import { TeachOptions } from './utils'

export default async function (parsedOptions: TeachOptions) {
const { ctx, meta, options } = parsedOptions
const { ctx, meta, options, config } = parsedOptions
const question = options.all ? undefined : options.question

@@ -16,16 +16,25 @@ const answer = options.all ? undefined : options.answer

const { keyword } = options
if (!envMode && !options.allEnv) {
if (config.useEnvironment && !envMode && !options.allEnv) {
envMode = 1
groups = [meta.groupId]
}
const dialogues = await ctx.database.getDialogues({
writer, keyword, question, answer, envMode, groups,
writer,
keyword,
question,
answer,
envMode,
groups,
frozen: options.unFrozen ? false : options.frozen,
})
if (!options.question && !options.answer) {
if (!dialogues.length) return meta.$send(`没有搜索到任何回答,尝试切换到其他环境。`)
if (!dialogues.length) return meta.$send('没有搜索到任何回答,尝试切换到其他环境。')
const output = dialogues.map(({ id, question, answer }) => `${id}. 问题:“${question}”,回答:“${formatAnswer(answer)}”`)
output.unshift(`全部问答如下:`)
output.unshift('全部问答如下:')
return meta.$send(output.join('\n'))
}
if (!options.keyword) {

@@ -32,0 +41,0 @@ if (!options.question) {

@@ -1,6 +0,6 @@

import { DialogueFlag } from './dialogue'
import { simplifyQuestion, simplifyAnswer, processAnswer, TeachOptions } from './utils'
import { DialogueFlag, Dialogue } from './database'
import { simplifyQuestion, simplifyAnswer, TeachOptions } from './utils'
export default async function (parsedOptions: TeachOptions, question: string, answer: string) {
const { argc, meta, ctx, options } = parsedOptions
const { argc, meta, ctx, options, config } = parsedOptions
if (String(question).includes('[CQ:image,')) return meta.$send('问题不能包含图片。')

@@ -13,9 +13,8 @@ question = simplifyQuestion(question)

answer = await processAnswer(answer, ctx.app.options.imageServerKey)
const [dialogue] = await ctx.database.getDialogues({ question, answer })
if (dialogue) return meta.$send(`问答已存在,编号为 ${dialogue.id},如要修改请尝试使用 -u 指令。`)
const [dialogue] = await ctx.database.getDialogues({ question, answer })
if (dialogue) {
return meta.$send(`问答已存在,编号为 ${dialogue.id},如要修改请尝试使用 -u 指令。`)
} else {
let { envMode, groups, writer } = parsedOptions
let { envMode, groups, writer } = parsedOptions
if (config.useEnvironment) {
if (!envMode) {

@@ -25,22 +24,22 @@ envMode = 2

} else if (Math.abs(envMode) === 1) {
return meta.$send(`参数 -e, --env 错误,请检查指令语法。`)
return meta.$send('参数 -e, --env 错误,请检查指令语法。')
}
if (writer === undefined) {
writer = meta.userId
}
const { minAffinity, maxAffinity, chance: probability = 1 } = options
const successors = (parsedOptions.addSuccessor || []).join(',')
const flag = Number(!!options.frozen) * DialogueFlag.frozen
+ Number(!!options.regexp) * DialogueFlag.regexp
const dialogue = await ctx.database.createDialogue({
groups: (envMode === 2 ? '' : '*') + groups.join(','),
question,
answer,
writer,
flag,
successors,
probability,
})
return meta.$send(`问答已添加,编号为 ${dialogue.id}。`)
}
if (config.useWriter && writer === undefined) {
writer = meta.userId
}
const { chance: probability = 1 } = options
const flag = Number(!!options.frozen) * DialogueFlag.frozen
+ Number(!!options.regexp) * DialogueFlag.regexp
+ Number(!!options.keyword) * DialogueFlag.keyword
+ Number(!!options.appellation) * DialogueFlag.appellation
const data = { question, answer, writer, flag, probability } as Dialogue
data.groups = config.useEnvironment ? (envMode === 2 ? '' : '*') + groups.join(',') : '*'
const { id } = await ctx.database.createDialogue(data)
return meta.$send(`问答已添加,编号为 ${id}。`)
}

@@ -1,9 +0,9 @@

import { getUserName } from 'koishi-core'
import { Dialogue, DialogueFlag } from './dialogue'
import { splitIds, processAnswer, TeachOptions } from './utils'
import { Dialogue, DialogueFlag } from './database'
import { splitIds, TeachOptions } from './utils'
export default async function (parsedOptions: TeachOptions) {
const { ctx, meta, argc, options } = parsedOptions
const { ctx, meta, argc, options, config } = parsedOptions
if (argc) return meta.$send('存在多余的参数,请检查指令语法或将含有空格或换行的问答置于一对引号内。')
if (!/^\d+(,\d+)*$/.exec(options.update)) return meta.$send(`参数 -u, --update 错误,请检查指令语法。`)
if (!/^\d+(,\d+)*$/.exec(options.update)) return meta.$send('参数 -u, --update 错误,请检查指令语法。')
const ids: number[] = splitIds(options.update)

@@ -21,4 +21,4 @@ const dialogues = await ctx.database.getDialogues(ids)

meta.$user.authority > 3 ? () => false :
meta.$user.authority > 2 ? d => !!(d.flag & DialogueFlag.frozen) :
d => !!(d.flag & DialogueFlag.frozen) || d.writer !== meta.userId
meta.$user.authority > 2 ? d => !!(d.flag & DialogueFlag.frozen) :
d => !!(d.flag & DialogueFlag.frozen) || d.writer !== meta.userId
const removable = dialogues.filter(d => !predicate(d)).map(d => d.id)

@@ -38,3 +38,3 @@ const unremovable = dialogues.filter(predicate).map(d => d.id)

let hasUpdates = Object.keys(parsedOptions).length - 5
const hasUpdates = Object.keys(parsedOptions).length - 6
|| options.answer

@@ -47,4 +47,4 @@ || options.question

if (hasUpdates) {
let updateSet = new Set<number>()
let skipSet = new Set<number>()
const updateSet = new Set<number>()
const skipSet = new Set<number>()

@@ -60,2 +60,3 @@ for (const dialogue of dialogues) {

function updateValue <K extends keyof Dialogue> (key: K, type: 'string' | 'number', value: Dialogue[K]) {
// eslint-disable-next-line valid-typeof
if (typeof value === type && value !== dialogue[key]) {

@@ -66,2 +67,3 @@ updates[key] = value

updateValue('answer', 'string', options.answer)
updateValue('question', 'string', options.question)

@@ -71,6 +73,2 @@ updateValue('writer', 'number', parsedOptions.writer)

if (typeof options.answer === 'string' && options.answer !== dialogue.answer) {
updates.answer = await processAnswer(options.answer, ctx.app.options.imageServerKey)
}
let newFlag = dialogue.flag

@@ -108,14 +106,2 @@ if (options.frozen) {

if (parsedOptions.addSuccessor || parsedOptions.removeSuccessor) {
const { addSuccessor = [], removeSuccessor = [] } = parsedOptions
const oldSuccessors = splitIds(dialogue.successors)
const newSuccessors = Array
.from(new Set([...oldSuccessors, ...addSuccessor]))
.filter(id => !removeSuccessor.includes(id))
.sort().join(',')
if (newSuccessors !== dialogue.successors) updates.successors = newSuccessors
}
// TODO: predecessor
if (Object.keys(updates).length) {

@@ -147,19 +133,22 @@ try {

]
if (dialogue.writer) {
if (config.useWriter && dialogue.writer) {
const user = await ctx.database.getUser(dialogue.writer, 0, ['id', 'name'])
output.push(`来源:${getUserName(user)}`)
output.push(`来源:${user.name}`)
}
output.push(`生效环境:${dialogue.groups.startsWith('*')
? groups.includes(meta.groupId)
? groups.length - 1 ? `除本群等 ${groups.length} 个群外的所有群` : '除本群'
: groups.length ? `除 ${groups.length} 个群外的所有群` : '全局'
: groups.includes(meta.groupId)
? groups.length - 1 ? `本群等 ${groups.length} 个群` : '本群'
: groups.length ? `${groups.length} 个群` : '全局禁止'}`)
if (config.useEnvironment) {
output.push(`生效环境:${dialogue.groups.startsWith('*')
? groups.includes(meta.groupId)
? groups.length - 1 ? `除本群等 ${groups.length} 个群外的所有群` : '除本群'
: groups.length ? `除 ${groups.length} 个群外的所有群` : '全局'
: groups.includes(meta.groupId)
? groups.length - 1 ? `本群等 ${groups.length} 个群` : '本群'
: groups.length ? `${groups.length} 个群` : '全局禁止'}`)
}
if (dialogue.probability < 1) output.push(`触发概率:${dialogue.probability}`)
if (dialogue.successors) output.push(`后继问题:${dialogue.successors}`)
if (dialogue.flag & DialogueFlag.frozen) output.push('此问题已锁定')
await meta.$send(output.join('\n'))
}
return
}

@@ -1,30 +0,12 @@

import { Context, ParsedArgv, Meta } from 'koishi-core'
import { simplify, isInteger, randomId } from 'koishi-utils'
import { createHash } from 'crypto'
import axios from 'axios'
import { Context, ParsedCommandLine, Meta, CommandConfig } from 'koishi-core'
import { simplify, isInteger } from 'koishi-utils'
const imageRE = /\[CQ:image,file=([^,]+),url=([^\]]+)\]/
export const IMAGE_SERVER = 'https://shiki.shigma.xyz/img'
export const UPLOAD_SERVER = 'https://shiki.shigma.xyz/upload'
export async function processAnswer (source: string, key: string) {
let temp = ''
let capture = source.match(imageRE)
while (capture) {
const [text, file, url] = capture
temp += source.slice(0, capture.index)
source = source.slice(capture.index + text.length)
const salt = randomId()
const sign = createHash('md5').update(file + salt + key).digest('hex')
await axios.get(UPLOAD_SERVER, {
params: { salt, sign, url, file },
})
temp += `[CQ:image,file=${IMAGE_SERVER}/${file}]`
capture = source.match(imageRE)
}
return temp + source
export interface TeachConfig extends CommandConfig {
useWriter?: boolean
useFrozen?: boolean
useEnvironment?: boolean
}
const prefixPunctuation = /^([()\]]|\[(?!cq:))*/
const suffixPunctuation = /([\.,?!()\[~]|(?<!\[cq:[^\]]+)\])*$/
const suffixPunctuation = /([.,?!()[~]|(?<!\[cq:[^\]]+)\])*$/

@@ -67,19 +49,12 @@ export function stripPunctuation (source: string) {

options: Record<string, any>
config: TeachConfig
writer?: number
groups?: number[]
envMode?: -2 | -1 | 0 | 1 | 2
addSuccessor?: number[]
addPredecessor?: number[]
removeSuccessor?: number[]
removePredecessor?: number[]
}
export default function parseOptions (ctx: Context, parsedArgv: ParsedArgv) {
const { options, meta, args } = parsedArgv
let argc = args.length
export default async function parseOptions (ctx: Context, config: TeachConfig, argv: ParsedCommandLine) {
const { options, meta, args } = argv
const argc = args.length
if (options.addPredecessor || options.removePredecessor || options.regexp) {
return meta.$send('本功能目前处于维护中,暂时停止访问。')
}
if (typeof options.chance === 'number' && (options.chance <= 0 || options.chance > 1)) {

@@ -89,77 +64,40 @@ return meta.$send('参数 -c, --chance 应为不超过 1 的正数。')

const parsedOptions: TeachOptions = { ctx, meta, argc, args, options }
const parsedOptions: TeachOptions = { ctx, meta, argc, args, options, config }
if (options.noWriter) {
parsedOptions.writer = 0
} else if (options.writer) {
if (isInteger(options.writer) && options.writer > 0) {
parsedOptions.writer = options.writer
} else {
return meta.$send(`参数 -w, --writer 错误,请检查指令语法。`)
if (config.useWriter) {
if (options.noWriter) {
parsedOptions.writer = 0
} else if (options.writer) {
if (isInteger(options.writer) && options.writer > 0) {
parsedOptions.writer = options.writer
} else {
return meta.$send('参数 -w, --writer 错误,请检查指令语法。')
}
}
}
if (options.minAffinity !== undefined) {
if (!isInteger(options.minAffinity) || options.minAffinity < 0 || options.minAffinity >= 32768) {
return meta.$send(`参数 -m, --min-affinity 错误,请检查指令语法。`)
if (config.useEnvironment) {
if (options.globalEnv) {
parsedOptions.envMode = -2
parsedOptions.groups = []
} else if (options.noEnv) {
parsedOptions.envMode = 2
parsedOptions.groups = []
} else if (typeof options.env === 'string') {
if (options.env.match(/^(\*?(\d{9}(,\d{9})*)?|[#~]\d{9}(,\d{9})*)$/)) {
parsedOptions.groups = splitIds(options.env.replace(/^[#~*]/, '')).sort()
parsedOptions.envMode = options.env.startsWith('*') ? -2
: options.env.startsWith('#') ? 1
: options.env.startsWith('~') ? -1
: 2
} else {
return meta.$send('参数 -e, --env 错误,请检查指令语法。')
}
}
}
if (options.maxAffinity !== undefined) {
if (!isInteger(options.maxAffinity) || options.maxAffinity <= 0 || options.maxAffinity > 32768) {
return meta.$send(`参数 -m, --max-affinity 错误,请检查指令语法。`)
}
if (String(options.question).includes('[CQ:image,')) {
return meta.$send('问题不能包含图片。')
}
if (options.globalEnv) {
parsedOptions.envMode = -2
parsedOptions.groups = []
} else if (options.noEnv) {
parsedOptions.envMode = 2
parsedOptions.groups = []
} else if (typeof options.env === 'string') {
if (options.env.match(/^(\*?(\d{9}(,\d{9})*)?|[#~]\d{9}(,\d{9})*)$/)) {
parsedOptions.groups = splitIds(options.env.replace(/^[#~*]/, '')).sort()
parsedOptions.envMode = options.env.startsWith('*') ? -2
: options.env.startsWith('#') ? 1
: options.env.startsWith('~') ? -1
: 2
} else {
return meta.$send(`参数 -e, --env 错误,请检查指令语法。`)
}
}
if (options.addSuccessor) {
if (options.addSuccessor.match(/^\d+(,\d+)*$/)) {
parsedOptions.addSuccessor = splitIds(options.addSuccessor)
} else {
return meta.$send(`参数 -s, --add-successor 错误,请检查指令语法。`)
}
}
if (options.removeSuccessor) {
if (options.removeSuccessor.match(/^\d+(,\d+)*$/)) {
parsedOptions.removeSuccessor = splitIds(options.removeSuccessor)
} else {
return meta.$send(`参数 -S, --remove-successor 错误,请检查指令语法。`)
}
}
if (options.addPredecessor) {
if (options.addPredecessor.match(/^\d+(,\d+)*$/)) {
parsedOptions.addPredecessor = splitIds(options.addPredecessor)
} else {
return meta.$send(`参数 -p, --add-predecessor 错误,请检查指令语法。`)
}
}
if (options.removePredecessor) {
if (options.removePredecessor.match(/^\d+(,\d+)*$/)) {
parsedOptions.removePredecessor = splitIds(options.removePredecessor)
} else {
return meta.$send(`参数 -P, --remove-predecessor 错误,请检查指令语法。`)
}
}
if (String(options.question).includes('[CQ:image,')) return meta.$send('问题不能包含图片。')
options.question = simplifyQuestion(options.question)

@@ -166,0 +104,0 @@ if (!options.question) delete options.question

{
"extends": "../tsconfig.base",
"compilerOptions": {
"target": "esnext",
"module": "commonjs",
"incremental": true,
"esModuleInterop": true,
"moduleResolution": "node",
"declaration": true,
"outDir": "dist"
"outDir": "dist",
"rootDir": "src",
},
"include": [
"src"
]
"src",
],
}
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc