chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,35 @@
|
||||
import * as sdk from '@botpress/sdk'
|
||||
import * as genenv from './.genenv'
|
||||
import chat from './bp_modules/chat'
|
||||
import linear from './bp_modules/linear'
|
||||
import synchronizer from './bp_modules/synchronizer'
|
||||
|
||||
export default new sdk.BotDefinition({})
|
||||
.addIntegration(linear, {
|
||||
enabled: true,
|
||||
configurationType: 'apiKey',
|
||||
configuration: {
|
||||
apiKey: genenv.SINLIN_LINEAR_API_KEY,
|
||||
webhookSigningSecret: genenv.SINLIN_LINEAR_WEBHOOK_SIGNING_SECRET,
|
||||
},
|
||||
})
|
||||
.addIntegration(chat, {
|
||||
enabled: true,
|
||||
configuration: {},
|
||||
})
|
||||
.addPlugin(synchronizer, {
|
||||
alias: 'linear',
|
||||
configuration: {
|
||||
tableName: 'linearIssuesTable',
|
||||
},
|
||||
dependencies: {
|
||||
listable: {
|
||||
integrationAlias: 'linear',
|
||||
integrationInterfaceAlias: 'listable<issue>',
|
||||
},
|
||||
deletable: {
|
||||
integrationAlias: 'linear',
|
||||
integrationInterfaceAlias: 'deletable<issue>',
|
||||
},
|
||||
},
|
||||
})
|
||||
@@ -0,0 +1,13 @@
|
||||
import rootConfig from '../../eslint.config.mjs'
|
||||
|
||||
export default [
|
||||
...rootConfig,
|
||||
{
|
||||
languageOptions: {
|
||||
parserOptions: {
|
||||
project: ['./tsconfig.json'],
|
||||
tsconfigRootDir: import.meta.dirname,
|
||||
},
|
||||
},
|
||||
},
|
||||
]
|
||||
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"name": "@bp-bots/sinlin",
|
||||
"description": "A bot that syncs issues from Linear to Botpress tables",
|
||||
"scripts": {
|
||||
"postinstall": "genenv -o ./.genenv/index.ts -e SINLIN_LINEAR_API_KEY -e SINLIN_LINEAR_WEBHOOK_SIGNING_SECRET",
|
||||
"check:type": "tsc --noEmit",
|
||||
"check:bplint": "bp lint",
|
||||
"build": "bp add -y && bp build"
|
||||
},
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@botpress/client": "workspace:*",
|
||||
"@botpress/sdk": "workspace:*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@botpress/cli": "workspace:*",
|
||||
"@botpress/common": "workspace:*",
|
||||
"@botpress/sdk": "workspace:*",
|
||||
"@botpresshub/chat": "workspace:*",
|
||||
"@botpresshub/linear": "workspace:*",
|
||||
"@botpresshub/synchronizer": "workspace:*",
|
||||
"@bpinternal/genenv": "0.0.1",
|
||||
"@types/lodash": "^4.14.191"
|
||||
},
|
||||
"bpDependencies": {
|
||||
"chat": "../../integrations/chat",
|
||||
"linear": "../../integrations/linear",
|
||||
"synchronizer": "../../plugins/synchronizer"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
import { Client } from '@botpress/client'
|
||||
import * as bp from '.botpress'
|
||||
|
||||
const { tableName } = bp.linear.configuration
|
||||
|
||||
const getVanillaClient = (props: bp.EventHandlerProps | bp.MessageHandlerProps): Client => props.client._inner
|
||||
|
||||
const summarize = (str: string, maxLength: number = 1000): string =>
|
||||
str.length > maxLength ? str.substring(0, maxLength) + '...' : str
|
||||
|
||||
const reply = async (props: bp.MessageHandlerProps, text: string) => {
|
||||
await props.client.createMessage({
|
||||
type: 'text',
|
||||
payload: {
|
||||
text,
|
||||
},
|
||||
conversationId: props.message.conversationId,
|
||||
userId: props.ctx.botId,
|
||||
tags: {},
|
||||
})
|
||||
}
|
||||
|
||||
const bot = new bp.Bot({ actions: {} })
|
||||
|
||||
type Command = {
|
||||
description: string
|
||||
handler: bp.MessageHandlers['*']
|
||||
}
|
||||
const commands: Record<string, Command> = {
|
||||
'/sync': {
|
||||
description: 'Sync issues',
|
||||
handler: async (props: bp.MessageHandlerProps) => {
|
||||
await bot.actionHandlers['linear#clear']({ ...props, input: {} })
|
||||
await reply(props, 'Issues synced')
|
||||
},
|
||||
},
|
||||
'/list': {
|
||||
description: 'List issues',
|
||||
handler: async (props: bp.MessageHandlerProps) => {
|
||||
const tableState = await props.client
|
||||
.getOrSetState({ type: 'bot', id: props.ctx.botId, name: 'linear#table', payload: { tableCreated: false } })
|
||||
.then((r) => r.state.payload)
|
||||
|
||||
if (!tableState.tableCreated) {
|
||||
await reply(props, 'Table does not exist')
|
||||
return
|
||||
}
|
||||
|
||||
const { rows } = await getVanillaClient(props).findTableRows({
|
||||
table: tableName,
|
||||
filter: {},
|
||||
limit: 10,
|
||||
})
|
||||
|
||||
const issues: string[] = rows
|
||||
.map(({ computed: _computed, stale: _stale, similarity: _similarity, ...r }) =>
|
||||
Object.entries(r)
|
||||
.map(([k, v]) => `${k}: ${v}`)
|
||||
.join('; ')
|
||||
)
|
||||
.map((r) => `- ${r}`)
|
||||
|
||||
const response = issues.join('\n\n') || 'No issues found'
|
||||
await reply(props, summarize(response))
|
||||
},
|
||||
},
|
||||
'/clear': {
|
||||
description: 'Clear issues',
|
||||
handler: async (props: bp.MessageHandlerProps) => {
|
||||
await bot.actionHandlers['linear#clear']({ ...props, input: {} })
|
||||
await reply(props, 'Table cleared')
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
bot.on.message('*', async (props) => {
|
||||
const { message } = props
|
||||
|
||||
if (message.type !== 'text') {
|
||||
await reply(props, 'I only understand text messages')
|
||||
return
|
||||
}
|
||||
|
||||
const query = message.payload.text.trim()
|
||||
const command = commands[query]
|
||||
if (command) {
|
||||
const now = Date.now()
|
||||
props.logger.info(`[${now}:START] command "${query}"`)
|
||||
await command.handler(props)
|
||||
props.logger.info(`[${now}:STOP] command "${query}"`)
|
||||
return
|
||||
}
|
||||
|
||||
const helpMessage = Object.entries(commands)
|
||||
.map(([cmd, { description }]) => `${cmd}: ${description}`)
|
||||
.join('\n')
|
||||
await reply(props, 'Please use one of the following commands:\n' + helpMessage)
|
||||
})
|
||||
|
||||
export default bot
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"paths": { "*": ["./*"] },
|
||||
"outDir": "dist"
|
||||
},
|
||||
"include": [".botpress/**/*", "src/**/*", "*.ts"]
|
||||
}
|
||||
Reference in New Issue
Block a user