chore: import upstream snapshot with attribution
Publish CLI Package / publish-npm (push) Waiting to run
Publish Python SDK / publish-pypi (push) Waiting to run
Publish TypeScript SDK / publish-npm (push) Waiting to run
CI / Migrate Dev DB (push) Has been skipped
CI / Detect Version (push) Has been cancelled
CI / Migrate DB (push) Has been cancelled
CI / Build Dev ECR (./docker/app.Dockerfile, ECR_APP) (push) Has been cancelled
CI / Build Dev ECR (./docker/db.Dockerfile, ECR_MIGRATIONS) (push) Has been cancelled
CI / Build Dev ECR (./docker/pii.Dockerfile, ECR_PII) (push) Has been cancelled
CI / Build Dev ECR (./docker/realtime.Dockerfile, ECR_REALTIME) (push) Has been cancelled
CI / Deploy Trigger.dev (Dev) (push) Has been cancelled
CI / Build AMD64 (./docker/app.Dockerfile, ECR_APP, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build AMD64 (./docker/db.Dockerfile, ECR_MIGRATIONS, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build AMD64 (./docker/pii.Dockerfile, ECR_PII, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build AMD64 (./docker/realtime.Dockerfile, ECR_REALTIME, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/app.Dockerfile, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/db.Dockerfile, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/pii.Dockerfile, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/realtime.Dockerfile, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Check Docs Changes (push) Has been cancelled
CI / Process Docs (push) Has been cancelled
CI / Create GitHub Release (push) Has been cancelled
CI / Test and Build (push) Has been cancelled

This commit is contained in:
wehub-resource-sync
2026-07-13 13:20:55 +08:00
commit d25d482dc2
13754 changed files with 4996608 additions and 0 deletions
+136
View File
@@ -0,0 +1,136 @@
import { getErrorMessage } from '@sim/utils/errors'
import { env } from '@/lib/core/config/env'
import {
extractTrelloErrorMessage,
mapTrelloChecklist,
TRELLO_API_BASE_URL,
} from '@/tools/trello/shared'
import type { TrelloAddChecklistParams, TrelloAddChecklistResponse } from '@/tools/trello/types'
import type { ToolConfig } from '@/tools/types'
export const trelloAddChecklistTool: ToolConfig<
TrelloAddChecklistParams,
TrelloAddChecklistResponse
> = {
id: 'trello_add_checklist',
name: 'Trello Add Checklist',
description: 'Add a checklist to a Trello card',
version: '1.0.0',
oauth: {
required: true,
provider: 'trello',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'Trello OAuth access token',
},
cardId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Trello card ID to add the checklist to (24-character hex string)',
},
name: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Name of the checklist',
},
pos: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Position of the checklist (top, bottom, or positive float)',
},
},
request: {
url: (params) => {
if (!params.cardId) {
throw new Error('Card ID is required')
}
if (!params.name) {
throw new Error('Checklist name is required')
}
const apiKey = env.TRELLO_API_KEY
if (!apiKey) {
throw new Error('TRELLO_API_KEY environment variable is not set')
}
const url = new URL(`${TRELLO_API_BASE_URL}/cards/${params.cardId.trim()}/checklists`)
url.searchParams.set('key', apiKey)
url.searchParams.set('token', params.accessToken)
url.searchParams.set('name', params.name.trim())
if (params.pos) url.searchParams.set('pos', params.pos)
return url.toString()
},
method: 'POST',
headers: () => ({
Accept: 'application/json',
}),
},
transformResponse: async (response) => {
const data = await response.json().catch(() => null)
if (!response.ok) {
const error = extractTrelloErrorMessage(response, data, 'Failed to add checklist')
return {
success: false,
output: {
error,
},
error,
}
}
try {
const checklist = mapTrelloChecklist(data)
return {
success: true,
output: {
checklist,
},
}
} catch (error) {
const message = getErrorMessage(error, 'Failed to parse created checklist')
return {
success: false,
output: {
error: message,
},
error: message,
}
}
},
outputs: {
checklist: {
type: 'json',
description: 'Created checklist (id, name, idCard, idBoard, pos)',
optional: true,
properties: {
id: { type: 'string', description: 'Checklist ID' },
name: { type: 'string', description: 'Checklist name' },
idCard: { type: 'string', description: 'Card ID containing the checklist' },
idBoard: {
type: 'string',
description: 'Board ID containing the checklist',
optional: true,
},
pos: { type: 'number', description: 'Checklist position on the card' },
},
},
},
}
+148
View File
@@ -0,0 +1,148 @@
import { getErrorMessage } from '@sim/utils/errors'
import { env } from '@/lib/core/config/env'
import {
extractTrelloErrorMessage,
mapTrelloChecklistItem,
TRELLO_API_BASE_URL,
} from '@/tools/trello/shared'
import type {
TrelloAddChecklistItemParams,
TrelloAddChecklistItemResponse,
} from '@/tools/trello/types'
import type { ToolConfig } from '@/tools/types'
export const trelloAddChecklistItemTool: ToolConfig<
TrelloAddChecklistItemParams,
TrelloAddChecklistItemResponse
> = {
id: 'trello_add_checklist_item',
name: 'Trello Add Checklist Item',
description: 'Add an item to a Trello checklist',
version: '1.0.0',
oauth: {
required: true,
provider: 'trello',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'Trello OAuth access token',
},
checklistId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Trello checklist ID to add the item to (24-character hex string)',
},
name: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Name of the checklist item',
},
pos: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Position of the item (top, bottom, or positive float)',
},
checked: {
type: 'boolean',
required: false,
visibility: 'user-or-llm',
description: 'Whether the item should start checked off',
},
},
request: {
url: (params) => {
if (!params.checklistId) {
throw new Error('Checklist ID is required')
}
if (!params.name) {
throw new Error('Checklist item name is required')
}
const apiKey = env.TRELLO_API_KEY
if (!apiKey) {
throw new Error('TRELLO_API_KEY environment variable is not set')
}
const url = new URL(
`${TRELLO_API_BASE_URL}/checklists/${params.checklistId.trim()}/checkItems`
)
url.searchParams.set('key', apiKey)
url.searchParams.set('token', params.accessToken)
url.searchParams.set('name', params.name.trim())
if (params.pos) url.searchParams.set('pos', params.pos)
if (params.checked !== undefined) url.searchParams.set('checked', String(params.checked))
return url.toString()
},
method: 'POST',
headers: () => ({
Accept: 'application/json',
}),
},
transformResponse: async (response) => {
const data = await response.json().catch(() => null)
if (!response.ok) {
const error = extractTrelloErrorMessage(response, data, 'Failed to add checklist item')
return {
success: false,
output: {
error,
},
error,
}
}
try {
const item = mapTrelloChecklistItem(data)
return {
success: true,
output: {
item,
},
}
} catch (error) {
const message = getErrorMessage(error, 'Failed to parse created checklist item')
return {
success: false,
output: {
error: message,
},
error: message,
}
}
},
outputs: {
item: {
type: 'json',
description: 'Created checklist item (id, name, state, pos, idChecklist)',
optional: true,
properties: {
id: { type: 'string', description: 'Checklist item ID' },
name: { type: 'string', description: 'Checklist item name' },
state: { type: 'string', description: 'Item state (complete or incomplete)' },
pos: { type: 'number', description: 'Item position on the checklist' },
idChecklist: {
type: 'string',
description: 'Checklist ID containing the item',
optional: true,
},
},
},
},
}
+194
View File
@@ -0,0 +1,194 @@
import { getErrorMessage } from '@sim/utils/errors'
import { env } from '@/lib/core/config/env'
import {
extractTrelloErrorMessage,
mapTrelloComment,
TRELLO_API_BASE_URL,
} from '@/tools/trello/shared'
import type { TrelloAddCommentParams, TrelloAddCommentResponse } from '@/tools/trello/types'
import type { ToolConfig } from '@/tools/types'
export const trelloAddCommentTool: ToolConfig<TrelloAddCommentParams, TrelloAddCommentResponse> = {
id: 'trello_add_comment',
name: 'Trello Add Comment',
description: 'Add a comment to a Trello card',
version: '1.0.0',
oauth: {
required: true,
provider: 'trello',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'Trello OAuth access token',
},
cardId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Trello card ID (24-character hex string)',
},
text: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Comment text',
},
},
request: {
url: (params) => {
if (!params.cardId) {
throw new Error('Card ID is required')
}
if (!params.text) {
throw new Error('Comment text is required')
}
const apiKey = env.TRELLO_API_KEY
if (!apiKey) {
throw new Error('TRELLO_API_KEY environment variable is not set')
}
const url = new URL(`${TRELLO_API_BASE_URL}/cards/${params.cardId.trim()}/actions/comments`)
url.searchParams.set('key', apiKey)
url.searchParams.set('token', params.accessToken)
url.searchParams.set('text', params.text)
return url.toString()
},
method: 'POST',
headers: () => ({
Accept: 'application/json',
}),
},
transformResponse: async (response) => {
const data = await response.json().catch(() => null)
if (!response.ok) {
const error = extractTrelloErrorMessage(response, data, 'Failed to add comment')
return {
success: false,
output: {
error,
},
error,
}
}
try {
const comment = mapTrelloComment(data)
return {
success: true,
output: {
comment,
},
}
} catch (error) {
const message = getErrorMessage(error, 'Failed to parse created comment')
return {
success: false,
output: {
error: message,
},
error: message,
}
}
},
outputs: {
comment: {
type: 'json',
description:
'Created comment action (id, type, date, idMemberCreator, text, memberCreator, card, board, list)',
optional: true,
properties: {
id: { type: 'string', description: 'Action ID' },
type: { type: 'string', description: 'Action type' },
date: { type: 'string', description: 'Action timestamp' },
idMemberCreator: {
type: 'string',
description: 'ID of the member who created the comment',
},
text: {
type: 'string',
description: 'Comment text',
optional: true,
},
memberCreator: {
type: 'object',
description: 'Member who created the comment',
optional: true,
properties: {
id: { type: 'string', description: 'Member ID' },
fullName: {
type: 'string',
description: 'Member full name',
optional: true,
},
username: {
type: 'string',
description: 'Member username',
optional: true,
},
},
},
card: {
type: 'object',
description: 'Card referenced by the comment',
optional: true,
properties: {
id: { type: 'string', description: 'Card ID' },
name: { type: 'string', description: 'Card name' },
shortLink: {
type: 'string',
description: 'Short card link',
optional: true,
},
idShort: {
type: 'number',
description: 'Board-local card number',
optional: true,
},
due: {
type: 'string',
description: 'Card due date',
optional: true,
},
},
},
board: {
type: 'object',
description: 'Board referenced by the comment',
optional: true,
properties: {
id: { type: 'string', description: 'Board ID' },
name: { type: 'string', description: 'Board name' },
shortLink: {
type: 'string',
description: 'Short board link',
optional: true,
},
},
},
list: {
type: 'object',
description: 'List referenced by the comment',
optional: true,
properties: {
id: { type: 'string', description: 'List ID' },
name: { type: 'string', description: 'List name' },
},
},
},
},
},
}
+99
View File
@@ -0,0 +1,99 @@
import { env } from '@/lib/core/config/env'
import { extractTrelloErrorMessage, getIdArray, TRELLO_API_BASE_URL } from '@/tools/trello/shared'
import type { TrelloAddLabelParams, TrelloAddLabelResponse } from '@/tools/trello/types'
import type { ToolConfig } from '@/tools/types'
export const trelloAddLabelTool: ToolConfig<TrelloAddLabelParams, TrelloAddLabelResponse> = {
id: 'trello_add_label',
name: 'Trello Add Label',
description: 'Attach an existing label to a Trello card',
version: '1.0.0',
oauth: {
required: true,
provider: 'trello',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'Trello OAuth access token',
},
cardId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Trello card ID to attach the label to (24-character hex string)',
},
labelId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'ID of the label to attach (24-character hex string)',
},
},
request: {
url: (params) => {
if (!params.cardId) {
throw new Error('Card ID is required')
}
if (!params.labelId) {
throw new Error('Label ID is required')
}
const apiKey = env.TRELLO_API_KEY
if (!apiKey) {
throw new Error('TRELLO_API_KEY environment variable is not set')
}
const url = new URL(`${TRELLO_API_BASE_URL}/cards/${params.cardId.trim()}/idLabels`)
url.searchParams.set('key', apiKey)
url.searchParams.set('token', params.accessToken)
url.searchParams.set('value', params.labelId.trim())
return url.toString()
},
method: 'POST',
headers: () => ({
Accept: 'application/json',
}),
},
transformResponse: async (response) => {
const data = await response.json().catch(() => null)
if (!response.ok) {
const error = extractTrelloErrorMessage(response, data, 'Failed to add label')
return {
success: false,
output: {
labelIds: [],
error,
},
error,
}
}
return {
success: true,
output: {
labelIds: getIdArray(data),
},
}
},
outputs: {
labelIds: {
type: 'array',
description: 'Label IDs now applied to the card',
items: {
type: 'string',
description: 'A Trello label ID',
},
},
},
}
+99
View File
@@ -0,0 +1,99 @@
import { env } from '@/lib/core/config/env'
import { extractTrelloErrorMessage, getIdArray, TRELLO_API_BASE_URL } from '@/tools/trello/shared'
import type { TrelloAddMemberParams, TrelloAddMemberResponse } from '@/tools/trello/types'
import type { ToolConfig } from '@/tools/types'
export const trelloAddMemberTool: ToolConfig<TrelloAddMemberParams, TrelloAddMemberResponse> = {
id: 'trello_add_member',
name: 'Trello Add Member',
description: 'Assign a member to a Trello card',
version: '1.0.0',
oauth: {
required: true,
provider: 'trello',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'Trello OAuth access token',
},
cardId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Trello card ID to assign the member to (24-character hex string)',
},
memberId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'ID of the member to assign (24-character hex string)',
},
},
request: {
url: (params) => {
if (!params.cardId) {
throw new Error('Card ID is required')
}
if (!params.memberId) {
throw new Error('Member ID is required')
}
const apiKey = env.TRELLO_API_KEY
if (!apiKey) {
throw new Error('TRELLO_API_KEY environment variable is not set')
}
const url = new URL(`${TRELLO_API_BASE_URL}/cards/${params.cardId.trim()}/idMembers`)
url.searchParams.set('key', apiKey)
url.searchParams.set('token', params.accessToken)
url.searchParams.set('value', params.memberId.trim())
return url.toString()
},
method: 'POST',
headers: () => ({
Accept: 'application/json',
}),
},
transformResponse: async (response) => {
const data = await response.json().catch(() => null)
if (!response.ok) {
const error = extractTrelloErrorMessage(response, data, 'Failed to add member')
return {
success: false,
output: {
memberIds: [],
error,
},
error,
}
}
return {
success: true,
output: {
memberIds: getIdArray(data),
},
}
},
outputs: {
memberIds: {
type: 'array',
description: 'Member IDs now assigned to the card',
items: {
type: 'string',
description: 'A Trello member ID',
},
},
},
}
+143
View File
@@ -0,0 +1,143 @@
import { getErrorMessage } from '@sim/utils/errors'
import { env } from '@/lib/core/config/env'
import {
extractTrelloErrorMessage,
mapTrelloBoard,
TRELLO_API_BASE_URL,
} from '@/tools/trello/shared'
import type { TrelloCreateBoardParams, TrelloCreateBoardResponse } from '@/tools/trello/types'
import type { ToolConfig } from '@/tools/types'
export const trelloCreateBoardTool: ToolConfig<TrelloCreateBoardParams, TrelloCreateBoardResponse> =
{
id: 'trello_create_board',
name: 'Trello Create Board',
description: 'Create a new Trello board',
version: '1.0.0',
oauth: {
required: true,
provider: 'trello',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'Trello OAuth access token',
},
name: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Name of the board',
},
desc: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Description of the board',
},
idOrganization: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'ID or name of the workspace/organization the board belongs to',
},
defaultLists: {
type: 'boolean',
required: false,
visibility: 'user-or-llm',
description: 'Whether to create the default lists (To Do, Doing, Done) on the new board',
},
},
request: {
url: (params) => {
if (!params.name) {
throw new Error('Board name is required')
}
const apiKey = env.TRELLO_API_KEY
if (!apiKey) {
throw new Error('TRELLO_API_KEY environment variable is not set')
}
const url = new URL(`${TRELLO_API_BASE_URL}/boards`)
url.searchParams.set('key', apiKey)
url.searchParams.set('token', params.accessToken)
url.searchParams.set('name', params.name.trim())
if (params.desc) url.searchParams.set('desc', params.desc)
if (params.idOrganization)
url.searchParams.set('idOrganization', params.idOrganization.trim())
if (params.defaultLists !== undefined) {
url.searchParams.set('defaultLists', String(params.defaultLists))
}
return url.toString()
},
method: 'POST',
headers: () => ({
Accept: 'application/json',
}),
},
transformResponse: async (response) => {
const data = await response.json().catch(() => null)
if (!response.ok) {
const error = extractTrelloErrorMessage(response, data, 'Failed to create board')
return {
success: false,
output: {
error,
},
error,
}
}
try {
const board = mapTrelloBoard(data)
return {
success: true,
output: {
board,
},
}
} catch (error) {
const message = getErrorMessage(error, 'Failed to parse created board')
return {
success: false,
output: {
error: message,
},
error: message,
}
}
},
outputs: {
board: {
type: 'json',
description: 'Created board (id, name, desc, url, closed, idOrganization)',
optional: true,
properties: {
id: { type: 'string', description: 'Board ID' },
name: { type: 'string', description: 'Board name' },
desc: { type: 'string', description: 'Board description' },
url: { type: 'string', description: 'Full board URL' },
closed: { type: 'boolean', description: 'Whether the board is closed' },
idOrganization: {
type: 'string',
description: 'ID of the workspace/organization the board belongs to',
optional: true,
},
},
},
},
}
+218
View File
@@ -0,0 +1,218 @@
import { getErrorMessage } from '@sim/utils/errors'
import { env } from '@/lib/core/config/env'
import {
extractTrelloErrorMessage,
mapTrelloCard,
TRELLO_API_BASE_URL,
} from '@/tools/trello/shared'
import type { TrelloCreateCardParams, TrelloCreateCardResponse } from '@/tools/trello/types'
import type { ToolConfig } from '@/tools/types'
export const trelloCreateCardTool: ToolConfig<TrelloCreateCardParams, TrelloCreateCardResponse> = {
id: 'trello_create_card',
name: 'Trello Create Card',
description: 'Create a new card in a Trello list',
version: '1.0.0',
oauth: {
required: true,
provider: 'trello',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'Trello OAuth access token',
},
listId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Trello list ID (24-character hex string)',
},
name: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Name/title of the card',
},
desc: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Description of the card',
},
pos: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Position of the card (top, bottom, or positive float)',
},
due: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Due date (ISO 8601 format)',
},
dueComplete: {
type: 'boolean',
required: false,
visibility: 'user-or-llm',
description: 'Whether the due date should be marked complete',
},
labelIds: {
type: 'array',
required: false,
visibility: 'user-or-llm',
description: 'Label IDs to attach to the card',
items: {
type: 'string',
description: 'A Trello label ID',
},
},
memberIds: {
type: 'array',
required: false,
visibility: 'user-or-llm',
description: 'Member IDs to assign to the card',
items: {
type: 'string',
description: 'A Trello member ID',
},
},
},
request: {
url: (params) => {
const apiKey = env.TRELLO_API_KEY
if (!apiKey) {
throw new Error('TRELLO_API_KEY environment variable is not set')
}
const url = new URL(`${TRELLO_API_BASE_URL}/cards`)
url.searchParams.set('key', apiKey)
url.searchParams.set('token', params.accessToken)
return url.toString()
},
method: 'POST',
headers: () => ({
'Content-Type': 'application/json',
Accept: 'application/json',
}),
body: (params) => {
if (!params.name) {
throw new Error('Card name is required')
}
if (!params.listId) {
throw new Error('List ID is required')
}
const body: Record<string, unknown> = {
idList: params.listId.trim(),
name: params.name,
}
if (params.desc) body.desc = params.desc
if (params.pos) body.pos = params.pos
if (params.due) body.due = params.due
if (params.dueComplete !== undefined) body.dueComplete = params.dueComplete
if (params.labelIds?.length) body.idLabels = params.labelIds
if (params.memberIds?.length) body.idMembers = params.memberIds
return body
},
},
transformResponse: async (response) => {
const data = await response.json().catch(() => null)
if (!response.ok) {
const error = extractTrelloErrorMessage(response, data, 'Failed to create card')
return {
success: false,
output: {
error,
},
error,
}
}
try {
const card = mapTrelloCard(data)
return {
success: true,
output: {
card,
},
}
} catch (error) {
const message = getErrorMessage(error, 'Failed to parse created card')
return {
success: false,
output: {
error: message,
},
error: message,
}
}
},
outputs: {
card: {
type: 'json',
description:
'Created card (id, name, desc, url, idBoard, idList, closed, labelIds, labels, due, dueComplete)',
optional: true,
properties: {
id: { type: 'string', description: 'Card ID' },
name: { type: 'string', description: 'Card name' },
desc: { type: 'string', description: 'Card description' },
url: { type: 'string', description: 'Full card URL' },
idBoard: { type: 'string', description: 'Board ID containing the card' },
idList: { type: 'string', description: 'List ID containing the card' },
closed: { type: 'boolean', description: 'Whether the card is archived' },
labelIds: {
type: 'array',
description: 'Label IDs applied to the card',
items: {
type: 'string',
description: 'A Trello label ID',
},
},
labels: {
type: 'array',
description: 'Labels applied to the card',
items: {
type: 'object',
properties: {
id: { type: 'string', description: 'Label ID' },
name: { type: 'string', description: 'Label name' },
color: {
type: 'string',
description: 'Label color',
optional: true,
},
},
},
},
due: {
type: 'string',
description: 'Card due date in ISO 8601 format',
optional: true,
},
dueComplete: {
type: 'boolean',
description: 'Whether the due date is complete',
optional: true,
},
},
},
},
}
+130
View File
@@ -0,0 +1,130 @@
import { getErrorMessage } from '@sim/utils/errors'
import { env } from '@/lib/core/config/env'
import {
extractTrelloErrorMessage,
mapTrelloList,
TRELLO_API_BASE_URL,
} from '@/tools/trello/shared'
import type { TrelloCreateListParams, TrelloCreateListResponse } from '@/tools/trello/types'
import type { ToolConfig } from '@/tools/types'
export const trelloCreateListTool: ToolConfig<TrelloCreateListParams, TrelloCreateListResponse> = {
id: 'trello_create_list',
name: 'Trello Create List',
description: 'Create a new list on a Trello board',
version: '1.0.0',
oauth: {
required: true,
provider: 'trello',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'Trello OAuth access token',
},
boardId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Trello board ID the list belongs to (24-character hex string)',
},
name: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Name of the list',
},
pos: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Position of the list (top, bottom, or positive float)',
},
},
request: {
url: (params) => {
if (!params.name) {
throw new Error('List name is required')
}
if (!params.boardId) {
throw new Error('Board ID is required')
}
const apiKey = env.TRELLO_API_KEY
if (!apiKey) {
throw new Error('TRELLO_API_KEY environment variable is not set')
}
const url = new URL(`${TRELLO_API_BASE_URL}/lists`)
url.searchParams.set('key', apiKey)
url.searchParams.set('token', params.accessToken)
url.searchParams.set('name', params.name.trim())
url.searchParams.set('idBoard', params.boardId.trim())
if (params.pos) url.searchParams.set('pos', params.pos)
return url.toString()
},
method: 'POST',
headers: () => ({
Accept: 'application/json',
}),
},
transformResponse: async (response) => {
const data = await response.json().catch(() => null)
if (!response.ok) {
const error = extractTrelloErrorMessage(response, data, 'Failed to create list')
return {
success: false,
output: {
error,
},
error,
}
}
try {
const list = mapTrelloList(data)
return {
success: true,
output: {
list,
},
}
} catch (error) {
const message = getErrorMessage(error, 'Failed to parse created list')
return {
success: false,
output: {
error: message,
},
error: message,
}
}
},
outputs: {
list: {
type: 'json',
description: 'Created list (id, name, closed, pos, idBoard)',
optional: true,
properties: {
id: { type: 'string', description: 'List ID' },
name: { type: 'string', description: 'List name' },
closed: { type: 'boolean', description: 'Whether the list is archived' },
pos: { type: 'number', description: 'List position on the board' },
idBoard: { type: 'string', description: 'Board ID containing the list' },
},
},
},
}
+85
View File
@@ -0,0 +1,85 @@
import { env } from '@/lib/core/config/env'
import { extractTrelloErrorMessage, TRELLO_API_BASE_URL } from '@/tools/trello/shared'
import type { TrelloDeleteCardParams, TrelloDeleteCardResponse } from '@/tools/trello/types'
import type { ToolConfig } from '@/tools/types'
export const trelloDeleteCardTool: ToolConfig<TrelloDeleteCardParams, TrelloDeleteCardResponse> = {
id: 'trello_delete_card',
name: 'Trello Delete Card',
description: 'Permanently delete a Trello card',
version: '1.0.0',
oauth: {
required: true,
provider: 'trello',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'Trello OAuth access token',
},
cardId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Trello card ID to permanently delete (24-character hex string)',
},
},
request: {
url: (params) => {
if (!params.cardId) {
throw new Error('Card ID is required')
}
const apiKey = env.TRELLO_API_KEY
if (!apiKey) {
throw new Error('TRELLO_API_KEY environment variable is not set')
}
const url = new URL(`${TRELLO_API_BASE_URL}/cards/${params.cardId.trim()}`)
url.searchParams.set('key', apiKey)
url.searchParams.set('token', params.accessToken)
return url.toString()
},
method: 'DELETE',
headers: () => ({
Accept: 'application/json',
}),
},
transformResponse: async (response) => {
const data = await response.json().catch(() => null)
if (!response.ok) {
const error = extractTrelloErrorMessage(response, data, 'Failed to delete card')
return {
success: false,
output: {
success: false,
error,
},
error,
}
}
return {
success: true,
output: {
success: true,
},
}
},
outputs: {
success: {
type: 'boolean',
description: 'Whether the card was deleted',
},
},
}
+271
View File
@@ -0,0 +1,271 @@
import { getErrorMessage } from '@sim/utils/errors'
import { env } from '@/lib/core/config/env'
import {
extractTrelloErrorMessage,
mapTrelloAction,
TRELLO_API_BASE_URL,
} from '@/tools/trello/shared'
import type { TrelloGetActionsParams, TrelloGetActionsResponse } from '@/tools/trello/types'
import type { ToolConfig } from '@/tools/types'
export const trelloGetActionsTool: ToolConfig<TrelloGetActionsParams, TrelloGetActionsResponse> = {
id: 'trello_get_actions',
name: 'Trello Get Actions',
description: 'Get activity/actions from a board or card',
version: '1.0.0',
oauth: {
required: true,
provider: 'trello',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'Trello OAuth access token',
},
boardId: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Trello board ID (24-character hex string). Either boardId or cardId required',
},
cardId: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Trello card ID (24-character hex string). Either boardId or cardId required',
},
filter: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Filter actions by type (e.g., "commentCard,updateCard,createCard" or "all")',
},
limit: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Maximum number of board actions to return',
},
page: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Page number for action results',
},
since: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Only return actions after this date (ISO 8601 timestamp) or action ID, for paging through long histories',
},
before: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Only return actions before this date (ISO 8601 timestamp) or action ID, for paging through long histories',
},
},
request: {
url: (params) => {
if (!params.boardId && !params.cardId) {
throw new Error('Either boardId or cardId is required')
}
if (params.boardId && params.cardId) {
throw new Error('Provide either boardId or cardId, not both')
}
const apiKey = env.TRELLO_API_KEY
if (!apiKey) {
throw new Error('TRELLO_API_KEY environment variable is not set')
}
const path = params.boardId
? `/boards/${params.boardId.trim()}/actions`
: `/cards/${params.cardId?.trim()}/actions`
const url = new URL(`${TRELLO_API_BASE_URL}${path}`)
url.searchParams.set('key', apiKey)
url.searchParams.set('token', params.accessToken)
if (params.filter) {
url.searchParams.set('filter', params.filter)
}
if (params.limit !== undefined) {
url.searchParams.set('limit', String(params.limit))
}
if (params.page !== undefined) {
url.searchParams.set('page', String(params.page))
}
if (params.since) {
url.searchParams.set('since', params.since)
}
if (params.before) {
url.searchParams.set('before', params.before)
}
return url.toString()
},
method: 'GET',
headers: () => ({
Accept: 'application/json',
}),
},
transformResponse: async (response) => {
const data = await response.json().catch(() => null)
if (!response.ok) {
const error = extractTrelloErrorMessage(response, data, 'Failed to get Trello actions')
return {
success: false,
output: {
actions: [],
count: 0,
error,
},
error,
}
}
if (!Array.isArray(data)) {
const error = 'Trello returned an invalid action collection'
return {
success: false,
output: {
actions: [],
count: 0,
error,
},
error,
}
}
try {
const actions = data.map((item) => mapTrelloAction(item))
return {
success: true,
output: {
actions,
count: actions.length,
},
}
} catch (error) {
const message = getErrorMessage(error, 'Failed to parse Trello actions')
return {
success: false,
output: {
actions: [],
count: 0,
error: message,
},
error: message,
}
}
},
outputs: {
actions: {
type: 'array',
description:
'Action items (id, type, date, idMemberCreator, text, memberCreator, card, board, list)',
items: {
type: 'object',
properties: {
id: { type: 'string', description: 'Action ID' },
type: { type: 'string', description: 'Action type' },
date: { type: 'string', description: 'Action timestamp' },
idMemberCreator: {
type: 'string',
description: 'ID of the member who created the action',
},
text: {
type: 'string',
description: 'Comment text when present',
optional: true,
},
memberCreator: {
type: 'object',
description: 'Member who created the action',
optional: true,
properties: {
id: { type: 'string', description: 'Member ID' },
fullName: {
type: 'string',
description: 'Member full name',
optional: true,
},
username: {
type: 'string',
description: 'Member username',
optional: true,
},
},
},
card: {
type: 'object',
description: 'Card referenced by the action',
optional: true,
properties: {
id: { type: 'string', description: 'Card ID' },
name: { type: 'string', description: 'Card name' },
shortLink: {
type: 'string',
description: 'Short card link',
optional: true,
},
idShort: {
type: 'number',
description: 'Board-local card number',
optional: true,
},
due: {
type: 'string',
description: 'Card due date',
optional: true,
},
},
},
board: {
type: 'object',
description: 'Board referenced by the action',
optional: true,
properties: {
id: { type: 'string', description: 'Board ID' },
name: { type: 'string', description: 'Board name' },
shortLink: {
type: 'string',
description: 'Short board link',
optional: true,
},
},
},
list: {
type: 'object',
description: 'List referenced by the action',
optional: true,
properties: {
id: { type: 'string', description: 'List ID' },
name: { type: 'string', description: 'List name' },
},
},
},
},
},
count: { type: 'number', description: 'Number of actions returned' },
},
}
+116
View File
@@ -0,0 +1,116 @@
import { getErrorMessage } from '@sim/utils/errors'
import { env } from '@/lib/core/config/env'
import {
extractTrelloErrorMessage,
mapTrelloBoard,
TRELLO_API_BASE_URL,
} from '@/tools/trello/shared'
import type { TrelloGetBoardParams, TrelloGetBoardResponse } from '@/tools/trello/types'
import type { ToolConfig } from '@/tools/types'
export const trelloGetBoardTool: ToolConfig<TrelloGetBoardParams, TrelloGetBoardResponse> = {
id: 'trello_get_board',
name: 'Trello Get Board',
description: 'Retrieve a single Trello board by ID',
version: '1.0.0',
oauth: {
required: true,
provider: 'trello',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'Trello OAuth access token',
},
boardId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Trello board ID (24-character hex string)',
},
},
request: {
url: (params) => {
if (!params.boardId) {
throw new Error('Board ID is required')
}
const apiKey = env.TRELLO_API_KEY
if (!apiKey) {
throw new Error('TRELLO_API_KEY environment variable is not set')
}
const url = new URL(`${TRELLO_API_BASE_URL}/boards/${params.boardId.trim()}`)
url.searchParams.set('key', apiKey)
url.searchParams.set('token', params.accessToken)
return url.toString()
},
method: 'GET',
headers: () => ({
Accept: 'application/json',
}),
},
transformResponse: async (response) => {
const data = await response.json().catch(() => null)
if (!response.ok) {
const error = extractTrelloErrorMessage(response, data, 'Failed to get board')
return {
success: false,
output: {
error,
},
error,
}
}
try {
const board = mapTrelloBoard(data)
return {
success: true,
output: {
board,
},
}
} catch (error) {
const message = getErrorMessage(error, 'Failed to parse board')
return {
success: false,
output: {
error: message,
},
error: message,
}
}
},
outputs: {
board: {
type: 'json',
description: 'Board (id, name, desc, url, closed, idOrganization)',
optional: true,
properties: {
id: { type: 'string', description: 'Board ID' },
name: { type: 'string', description: 'Board name' },
desc: { type: 'string', description: 'Board description' },
url: { type: 'string', description: 'Full board URL' },
closed: { type: 'boolean', description: 'Whether the board is closed' },
idOrganization: {
type: 'string',
description: 'ID of the workspace/organization the board belongs to',
optional: true,
},
},
},
},
}
+148
View File
@@ -0,0 +1,148 @@
import { getErrorMessage } from '@sim/utils/errors'
import { env } from '@/lib/core/config/env'
import {
extractTrelloErrorMessage,
mapTrelloCard,
TRELLO_API_BASE_URL,
} from '@/tools/trello/shared'
import type { TrelloGetCardParams, TrelloGetCardResponse } from '@/tools/trello/types'
import type { ToolConfig } from '@/tools/types'
export const trelloGetCardTool: ToolConfig<TrelloGetCardParams, TrelloGetCardResponse> = {
id: 'trello_get_card',
name: 'Trello Get Card',
description: 'Retrieve a single Trello card by ID',
version: '1.0.0',
oauth: {
required: true,
provider: 'trello',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'Trello OAuth access token',
},
cardId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Trello card ID (24-character hex string)',
},
},
request: {
url: (params) => {
if (!params.cardId) {
throw new Error('Card ID is required')
}
const apiKey = env.TRELLO_API_KEY
if (!apiKey) {
throw new Error('TRELLO_API_KEY environment variable is not set')
}
const url = new URL(`${TRELLO_API_BASE_URL}/cards/${params.cardId.trim()}`)
url.searchParams.set('key', apiKey)
url.searchParams.set('token', params.accessToken)
return url.toString()
},
method: 'GET',
headers: () => ({
Accept: 'application/json',
}),
},
transformResponse: async (response) => {
const data = await response.json().catch(() => null)
if (!response.ok) {
const error = extractTrelloErrorMessage(response, data, 'Failed to get card')
return {
success: false,
output: {
error,
},
error,
}
}
try {
const card = mapTrelloCard(data)
return {
success: true,
output: {
card,
},
}
} catch (error) {
const message = getErrorMessage(error, 'Failed to parse card')
return {
success: false,
output: {
error: message,
},
error: message,
}
}
},
outputs: {
card: {
type: 'json',
description:
'Card (id, name, desc, url, idBoard, idList, closed, labelIds, labels, due, dueComplete)',
optional: true,
properties: {
id: { type: 'string', description: 'Card ID' },
name: { type: 'string', description: 'Card name' },
desc: { type: 'string', description: 'Card description' },
url: { type: 'string', description: 'Full card URL' },
idBoard: { type: 'string', description: 'Board ID containing the card' },
idList: { type: 'string', description: 'List ID containing the card' },
closed: { type: 'boolean', description: 'Whether the card is archived' },
labelIds: {
type: 'array',
description: 'Label IDs applied to the card',
items: {
type: 'string',
description: 'A Trello label ID',
},
},
labels: {
type: 'array',
description: 'Labels applied to the card',
items: {
type: 'object',
properties: {
id: { type: 'string', description: 'Label ID' },
name: { type: 'string', description: 'Label name' },
color: {
type: 'string',
description: 'Label color',
optional: true,
},
},
},
},
due: {
type: 'string',
description: 'Card due date in ISO 8601 format',
optional: true,
},
dueComplete: {
type: 'boolean',
description: 'Whether the due date is complete',
optional: true,
},
},
},
},
}
+47
View File
@@ -0,0 +1,47 @@
import { trelloAddChecklistTool } from '@/tools/trello/add_checklist'
import { trelloAddChecklistItemTool } from '@/tools/trello/add_checklist_item'
import { trelloAddCommentTool } from '@/tools/trello/add_comment'
import { trelloAddLabelTool } from '@/tools/trello/add_label'
import { trelloAddMemberTool } from '@/tools/trello/add_member'
import { trelloCreateBoardTool } from '@/tools/trello/create_board'
import { trelloCreateCardTool } from '@/tools/trello/create_card'
import { trelloCreateListTool } from '@/tools/trello/create_list'
import { trelloDeleteCardTool } from '@/tools/trello/delete_card'
import { trelloGetActionsTool } from '@/tools/trello/get_actions'
import { trelloGetBoardTool } from '@/tools/trello/get_board'
import { trelloGetCardTool } from '@/tools/trello/get_card'
import { trelloListCardsTool } from '@/tools/trello/list_cards'
import { trelloListListsTool } from '@/tools/trello/list_lists'
import { trelloListMembersTool } from '@/tools/trello/list_members'
import { trelloRemoveLabelTool } from '@/tools/trello/remove_label'
import { trelloRemoveMemberTool } from '@/tools/trello/remove_member'
import { trelloSearchTool } from '@/tools/trello/search'
import { trelloUpdateCardTool } from '@/tools/trello/update_card'
import { trelloUpdateChecklistItemTool } from '@/tools/trello/update_checklist_item'
import { trelloUpdateListTool } from '@/tools/trello/update_list'
export {
trelloListListsTool,
trelloListCardsTool,
trelloCreateCardTool,
trelloUpdateCardTool,
trelloDeleteCardTool,
trelloGetActionsTool,
trelloAddCommentTool,
trelloCreateBoardTool,
trelloGetBoardTool,
trelloCreateListTool,
trelloUpdateListTool,
trelloGetCardTool,
trelloAddChecklistTool,
trelloAddChecklistItemTool,
trelloUpdateChecklistItemTool,
trelloAddLabelTool,
trelloRemoveLabelTool,
trelloAddMemberTool,
trelloRemoveMemberTool,
trelloListMembersTool,
trelloSearchTool,
}
export * from '@/tools/trello/types'
+192
View File
@@ -0,0 +1,192 @@
import { getErrorMessage } from '@sim/utils/errors'
import { env } from '@/lib/core/config/env'
import {
extractTrelloErrorMessage,
mapTrelloCard,
TRELLO_API_BASE_URL,
} from '@/tools/trello/shared'
import type { TrelloListCardsParams, TrelloListCardsResponse } from '@/tools/trello/types'
import type { ToolConfig } from '@/tools/types'
export const trelloListCardsTool: ToolConfig<TrelloListCardsParams, TrelloListCardsResponse> = {
id: 'trello_list_cards',
name: 'Trello List Cards',
description: 'List cards from a Trello board or list',
version: '1.0.0',
oauth: {
required: true,
provider: 'trello',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'Trello OAuth access token',
},
boardId: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Trello board ID to list open cards from. Provide either boardId or listId',
},
listId: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Trello list ID to list cards from. Provide either boardId or listId',
},
filter: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Which cards to return: open, closed, or all (defaults to open)',
},
},
request: {
url: (params) => {
const apiKey = env.TRELLO_API_KEY
if (!apiKey) {
throw new Error('TRELLO_API_KEY environment variable is not set')
}
if (params.boardId && params.listId) {
throw new Error('Provide either a board ID or list ID, not both')
}
if (!params.listId && !params.boardId) {
throw new Error('Either a board ID or list ID is required')
}
const path = params.listId
? `/lists/${params.listId.trim()}/cards`
: `/boards/${params.boardId?.trim()}/cards`
const url = new URL(`${TRELLO_API_BASE_URL}${path}`)
url.searchParams.set('key', apiKey)
url.searchParams.set('token', params.accessToken)
if (params.filter) {
url.searchParams.set('filter', params.filter)
}
return url.toString()
},
method: 'GET',
headers: () => ({
Accept: 'application/json',
}),
},
transformResponse: async (response) => {
const data = await response.json().catch(() => null)
if (!response.ok) {
const error = extractTrelloErrorMessage(response, data, 'Failed to list Trello cards')
return {
success: false,
output: {
cards: [],
count: 0,
error,
},
error,
}
}
if (!Array.isArray(data)) {
const error = 'Trello returned an invalid card collection'
return {
success: false,
output: {
cards: [],
count: 0,
error,
},
error,
}
}
try {
const cards = data.map((item) => mapTrelloCard(item))
return {
success: true,
output: {
cards,
count: cards.length,
},
}
} catch (error) {
const message = getErrorMessage(error, 'Failed to parse Trello cards')
return {
success: false,
output: {
cards: [],
count: 0,
error: message,
},
error: message,
}
}
},
outputs: {
cards: {
type: 'array',
description: 'Cards returned from the selected Trello board or list',
items: {
type: 'object',
properties: {
id: { type: 'string', description: 'Card ID' },
name: { type: 'string', description: 'Card name' },
desc: { type: 'string', description: 'Card description' },
url: { type: 'string', description: 'Full card URL' },
idBoard: { type: 'string', description: 'Board ID containing the card' },
idList: { type: 'string', description: 'List ID containing the card' },
closed: { type: 'boolean', description: 'Whether the card is archived' },
labelIds: {
type: 'array',
description: 'Label IDs applied to the card',
items: {
type: 'string',
description: 'A Trello label ID',
},
},
labels: {
type: 'array',
description: 'Labels applied to the card',
items: {
type: 'object',
properties: {
id: { type: 'string', description: 'Label ID' },
name: { type: 'string', description: 'Label name' },
color: {
type: 'string',
description: 'Label color',
optional: true,
},
},
},
},
due: {
type: 'string',
description: 'Card due date in ISO 8601 format',
optional: true,
},
dueComplete: {
type: 'boolean',
description: 'Whether the due date is complete',
optional: true,
},
},
},
},
count: { type: 'number', description: 'Number of cards returned' },
},
}
+147
View File
@@ -0,0 +1,147 @@
import { getErrorMessage } from '@sim/utils/errors'
import { env } from '@/lib/core/config/env'
import {
extractTrelloErrorMessage,
mapTrelloList,
TRELLO_API_BASE_URL,
} from '@/tools/trello/shared'
import type { TrelloListListsParams, TrelloListListsResponse } from '@/tools/trello/types'
import type { ToolConfig } from '@/tools/types'
export const trelloListListsTool: ToolConfig<TrelloListListsParams, TrelloListListsResponse> = {
id: 'trello_list_lists',
name: 'Trello Get Lists',
description: 'List all lists on a Trello board',
version: '1.0.0',
oauth: {
required: true,
provider: 'trello',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'Trello OAuth access token',
},
boardId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Trello board ID (24-character hex string)',
},
filter: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Which lists to return: open, closed, or all (defaults to open)',
},
},
request: {
url: (params) => {
if (!params.boardId) {
throw new Error('Board ID is required')
}
const apiKey = env.TRELLO_API_KEY
if (!apiKey) {
throw new Error('TRELLO_API_KEY environment variable is not set')
}
if (!params.accessToken) {
throw new Error('Trello access token is missing')
}
const url = new URL(`${TRELLO_API_BASE_URL}/boards/${params.boardId.trim()}/lists`)
url.searchParams.set('key', apiKey)
url.searchParams.set('token', params.accessToken)
if (params.filter) {
url.searchParams.set('filter', params.filter)
}
return url.toString()
},
method: 'GET',
headers: () => ({
Accept: 'application/json',
}),
},
transformResponse: async (response) => {
const data = await response.json().catch(() => null)
if (!response.ok) {
const error = extractTrelloErrorMessage(response, data, 'Failed to list Trello lists')
return {
success: false,
output: {
lists: [],
count: 0,
error,
},
error,
}
}
if (!Array.isArray(data)) {
const error = 'Trello returned an invalid list collection'
return {
success: false,
output: {
lists: [],
count: 0,
error,
},
error,
}
}
try {
const lists = data.map((item) => mapTrelloList(item))
return {
success: true,
output: {
lists,
count: lists.length,
},
}
} catch (error) {
const message = getErrorMessage(error, 'Failed to parse Trello lists')
return {
success: false,
output: {
lists: [],
count: 0,
error: message,
},
error: message,
}
}
},
outputs: {
lists: {
type: 'array',
description: 'Lists on the selected board',
items: {
type: 'object',
properties: {
id: { type: 'string', description: 'List ID' },
name: { type: 'string', description: 'List name' },
closed: { type: 'boolean', description: 'Whether the list is archived' },
pos: { type: 'number', description: 'List position on the board' },
idBoard: { type: 'string', description: 'Board ID containing the list' },
},
},
},
count: { type: 'number', description: 'Number of lists returned' },
},
}
+134
View File
@@ -0,0 +1,134 @@
import { getErrorMessage } from '@sim/utils/errors'
import { env } from '@/lib/core/config/env'
import {
extractTrelloErrorMessage,
mapTrelloMember,
TRELLO_API_BASE_URL,
} from '@/tools/trello/shared'
import type { TrelloListMembersParams, TrelloListMembersResponse } from '@/tools/trello/types'
import type { ToolConfig } from '@/tools/types'
export const trelloListMembersTool: ToolConfig<TrelloListMembersParams, TrelloListMembersResponse> =
{
id: 'trello_list_members',
name: 'Trello List Members',
description: 'List members of a Trello board',
version: '1.0.0',
oauth: {
required: true,
provider: 'trello',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'Trello OAuth access token',
},
boardId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Trello board ID (24-character hex string)',
},
},
request: {
url: (params) => {
if (!params.boardId) {
throw new Error('Board ID is required')
}
const apiKey = env.TRELLO_API_KEY
if (!apiKey) {
throw new Error('TRELLO_API_KEY environment variable is not set')
}
const url = new URL(`${TRELLO_API_BASE_URL}/boards/${params.boardId.trim()}/members`)
url.searchParams.set('key', apiKey)
url.searchParams.set('token', params.accessToken)
return url.toString()
},
method: 'GET',
headers: () => ({
Accept: 'application/json',
}),
},
transformResponse: async (response) => {
const data = await response.json().catch(() => null)
if (!response.ok) {
const error = extractTrelloErrorMessage(response, data, 'Failed to list board members')
return {
success: false,
output: {
members: [],
count: 0,
error,
},
error,
}
}
if (!Array.isArray(data)) {
const error = 'Trello returned an invalid member collection'
return {
success: false,
output: {
members: [],
count: 0,
error,
},
error,
}
}
try {
const members = data
.map((item) => mapTrelloMember(item))
.filter((member): member is NonNullable<typeof member> => member !== null)
return {
success: true,
output: {
members,
count: members.length,
},
}
} catch (error) {
const message = getErrorMessage(error, 'Failed to parse board members')
return {
success: false,
output: {
members: [],
count: 0,
error: message,
},
error: message,
}
}
},
outputs: {
members: {
type: 'array',
description: 'Members on the selected board',
items: {
type: 'object',
properties: {
id: { type: 'string', description: 'Member ID' },
fullName: { type: 'string', description: 'Member full name', optional: true },
username: { type: 'string', description: 'Member username', optional: true },
},
},
},
count: { type: 'number', description: 'Number of members returned' },
},
}
+97
View File
@@ -0,0 +1,97 @@
import { env } from '@/lib/core/config/env'
import { extractTrelloErrorMessage, TRELLO_API_BASE_URL } from '@/tools/trello/shared'
import type { TrelloRemoveLabelParams, TrelloRemoveLabelResponse } from '@/tools/trello/types'
import type { ToolConfig } from '@/tools/types'
export const trelloRemoveLabelTool: ToolConfig<TrelloRemoveLabelParams, TrelloRemoveLabelResponse> =
{
id: 'trello_remove_label',
name: 'Trello Remove Label',
description: 'Detach a label from a Trello card',
version: '1.0.0',
oauth: {
required: true,
provider: 'trello',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'Trello OAuth access token',
},
cardId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Trello card ID to detach the label from (24-character hex string)',
},
labelId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'ID of the label to detach (24-character hex string)',
},
},
request: {
url: (params) => {
if (!params.cardId) {
throw new Error('Card ID is required')
}
if (!params.labelId) {
throw new Error('Label ID is required')
}
const apiKey = env.TRELLO_API_KEY
if (!apiKey) {
throw new Error('TRELLO_API_KEY environment variable is not set')
}
const url = new URL(
`${TRELLO_API_BASE_URL}/cards/${params.cardId.trim()}/idLabels/${params.labelId.trim()}`
)
url.searchParams.set('key', apiKey)
url.searchParams.set('token', params.accessToken)
return url.toString()
},
method: 'DELETE',
headers: () => ({
Accept: 'application/json',
}),
},
transformResponse: async (response) => {
const data = await response.json().catch(() => null)
if (!response.ok) {
const error = extractTrelloErrorMessage(response, data, 'Failed to remove label')
return {
success: false,
output: {
success: false,
error,
},
error,
}
}
return {
success: true,
output: {
success: true,
},
}
},
outputs: {
success: {
type: 'boolean',
description: 'Whether the label was removed from the card',
},
},
}
+99
View File
@@ -0,0 +1,99 @@
import { env } from '@/lib/core/config/env'
import { extractTrelloErrorMessage, TRELLO_API_BASE_URL } from '@/tools/trello/shared'
import type { TrelloRemoveMemberParams, TrelloRemoveMemberResponse } from '@/tools/trello/types'
import type { ToolConfig } from '@/tools/types'
export const trelloRemoveMemberTool: ToolConfig<
TrelloRemoveMemberParams,
TrelloRemoveMemberResponse
> = {
id: 'trello_remove_member',
name: 'Trello Remove Member',
description: 'Unassign a member from a Trello card',
version: '1.0.0',
oauth: {
required: true,
provider: 'trello',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'Trello OAuth access token',
},
cardId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Trello card ID to unassign the member from (24-character hex string)',
},
memberId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'ID of the member to unassign (24-character hex string)',
},
},
request: {
url: (params) => {
if (!params.cardId) {
throw new Error('Card ID is required')
}
if (!params.memberId) {
throw new Error('Member ID is required')
}
const apiKey = env.TRELLO_API_KEY
if (!apiKey) {
throw new Error('TRELLO_API_KEY environment variable is not set')
}
const url = new URL(
`${TRELLO_API_BASE_URL}/cards/${params.cardId.trim()}/idMembers/${params.memberId.trim()}`
)
url.searchParams.set('key', apiKey)
url.searchParams.set('token', params.accessToken)
return url.toString()
},
method: 'DELETE',
headers: () => ({
Accept: 'application/json',
}),
},
transformResponse: async (response) => {
const data = await response.json().catch(() => null)
if (!response.ok) {
const error = extractTrelloErrorMessage(response, data, 'Failed to remove member')
return {
success: false,
output: {
success: false,
error,
},
error,
}
}
return {
success: true,
output: {
success: true,
},
}
},
outputs: {
success: {
type: 'boolean',
description: 'Whether the member was removed from the card',
},
},
}
+195
View File
@@ -0,0 +1,195 @@
import { getErrorMessage } from '@sim/utils/errors'
import { isRecordLike } from '@sim/utils/object'
import { env } from '@/lib/core/config/env'
import {
extractTrelloErrorMessage,
mapTrelloBoard,
mapTrelloCard,
TRELLO_API_BASE_URL,
} from '@/tools/trello/shared'
import type { TrelloSearchParams, TrelloSearchResponse } from '@/tools/trello/types'
import type { ToolConfig } from '@/tools/types'
export const trelloSearchTool: ToolConfig<TrelloSearchParams, TrelloSearchResponse> = {
id: 'trello_search',
name: 'Trello Search',
description: 'Search Trello cards and boards by keyword',
version: '1.0.0',
oauth: {
required: true,
provider: 'trello',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'Trello OAuth access token',
},
query: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Search text, supports Trello search operators (e.g. board:, list:, due:)',
},
idBoards: {
type: 'array',
required: false,
visibility: 'user-or-llm',
description: 'Restrict the search to these board IDs',
items: {
type: 'string',
description: 'A Trello board ID',
},
},
modelTypes: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Comma-separated result types to search: cards, boards, or all (default all)',
},
cardsLimit: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Maximum number of cards to return (1-1000, default 10)',
},
},
request: {
url: (params) => {
if (!params.query) {
throw new Error('Search query is required')
}
const apiKey = env.TRELLO_API_KEY
if (!apiKey) {
throw new Error('TRELLO_API_KEY environment variable is not set')
}
const url = new URL(`${TRELLO_API_BASE_URL}/search`)
url.searchParams.set('key', apiKey)
url.searchParams.set('token', params.accessToken)
url.searchParams.set('query', params.query)
url.searchParams.set('modelTypes', params.modelTypes || 'all')
if (params.idBoards?.length) {
url.searchParams.set('idBoards', params.idBoards.join(','))
}
if (params.cardsLimit !== undefined) {
url.searchParams.set('cards_limit', String(params.cardsLimit))
}
return url.toString()
},
method: 'GET',
headers: () => ({
Accept: 'application/json',
}),
},
transformResponse: async (response) => {
const data = await response.json().catch(() => null)
if (!response.ok) {
const error = extractTrelloErrorMessage(response, data, 'Failed to search Trello')
return {
success: false,
output: {
cards: [],
boards: [],
count: 0,
error,
},
error,
}
}
if (!isRecordLike(data)) {
const error = 'Trello returned an invalid search result'
return {
success: false,
output: {
cards: [],
boards: [],
count: 0,
error,
},
error,
}
}
try {
const rawCards = Array.isArray(data.cards) ? data.cards : []
const rawBoards = Array.isArray(data.boards) ? data.boards : []
const cards = rawCards.map((item) => mapTrelloCard(item))
const boards = rawBoards.map((item) => mapTrelloBoard(item))
return {
success: true,
output: {
cards,
boards,
count: cards.length + boards.length,
},
}
} catch (error) {
const message = getErrorMessage(error, 'Failed to parse Trello search results')
return {
success: false,
output: {
cards: [],
boards: [],
count: 0,
error: message,
},
error: message,
}
}
},
outputs: {
cards: {
type: 'array',
description: 'Cards matching the search query',
items: {
type: 'object',
properties: {
id: { type: 'string', description: 'Card ID' },
name: { type: 'string', description: 'Card name' },
desc: { type: 'string', description: 'Card description' },
url: { type: 'string', description: 'Full card URL' },
idBoard: { type: 'string', description: 'Board ID containing the card' },
idList: { type: 'string', description: 'List ID containing the card' },
closed: { type: 'boolean', description: 'Whether the card is archived' },
},
},
},
boards: {
type: 'array',
description: 'Boards matching the search query',
items: {
type: 'object',
properties: {
id: { type: 'string', description: 'Board ID' },
name: { type: 'string', description: 'Board name' },
desc: { type: 'string', description: 'Board description' },
url: { type: 'string', description: 'Full board URL' },
closed: { type: 'boolean', description: 'Whether the board is archived' },
idOrganization: {
type: 'string',
description: 'Workspace/organization ID that owns the board',
optional: true,
},
},
},
},
count: { type: 'number', description: 'Total number of cards and boards returned' },
},
}
+277
View File
@@ -0,0 +1,277 @@
import { isRecordLike } from '@sim/utils/object'
import type {
TrelloAction,
TrelloActionBoardTarget,
TrelloActionCardTarget,
TrelloActionListTarget,
TrelloBoard,
TrelloCard,
TrelloChecklist,
TrelloChecklistItem,
TrelloComment,
TrelloLabel,
TrelloList,
TrelloMember,
} from '@/tools/trello/types'
export const TRELLO_API_BASE_URL = 'https://api.trello.com/1'
function getRequiredString(value: unknown, field: string): string {
if (typeof value === 'string' && value.trim().length > 0) {
return value
}
throw new Error(`Trello response is missing required field: ${field}`)
}
function getOptionalString(value: unknown): string | null {
return typeof value === 'string' ? value : null
}
function getOptionalBoolean(value: unknown): boolean | null {
return typeof value === 'boolean' ? value : null
}
function getNumber(value: unknown): number {
if (typeof value === 'number' && Number.isFinite(value)) {
return value
}
if (typeof value === 'string' && value.trim().length > 0) {
const parsed = Number(value)
if (Number.isFinite(parsed)) {
return parsed
}
}
return 0
}
function getOptionalNumber(value: unknown): number | null {
if (typeof value === 'number' && Number.isFinite(value)) {
return value
}
return null
}
export function getIdArray(value: unknown): string[] {
if (!Array.isArray(value)) {
return []
}
return value.flatMap((item) => {
if (typeof item === 'string' && item.trim().length > 0) {
return [item]
}
if (isRecordLike(item) && typeof item.id === 'string' && item.id.trim().length > 0) {
return [item.id]
}
return []
})
}
function mapTrelloLabel(value: unknown): TrelloLabel | null {
if (!isRecordLike(value) || typeof value.id !== 'string') {
return null
}
return {
id: value.id,
name: typeof value.name === 'string' ? value.name : '',
color: getOptionalString(value.color),
}
}
export function mapTrelloMember(value: unknown): TrelloMember | null {
if (!isRecordLike(value) || typeof value.id !== 'string') {
return null
}
return {
id: value.id,
fullName: getOptionalString(value.fullName),
username: getOptionalString(value.username),
}
}
function mapActionCardTarget(value: unknown): TrelloActionCardTarget | null {
if (!isRecordLike(value) || typeof value.id !== 'string' || typeof value.name !== 'string') {
return null
}
return {
id: value.id,
name: value.name,
shortLink: getOptionalString(value.shortLink),
idShort: getOptionalNumber(value.idShort),
due: getOptionalString(value.due),
}
}
function mapActionBoardTarget(value: unknown): TrelloActionBoardTarget | null {
if (!isRecordLike(value) || typeof value.id !== 'string' || typeof value.name !== 'string') {
return null
}
return {
id: value.id,
name: value.name,
shortLink: getOptionalString(value.shortLink),
}
}
function mapActionListTarget(value: unknown): TrelloActionListTarget | null {
if (!isRecordLike(value) || typeof value.id !== 'string' || typeof value.name !== 'string') {
return null
}
return {
id: value.id,
name: value.name,
}
}
export function mapTrelloList(value: unknown): TrelloList {
if (!isRecordLike(value)) {
throw new Error('Trello returned an invalid list object')
}
return {
id: getRequiredString(value.id, 'id'),
name: getRequiredString(value.name, 'name'),
closed: typeof value.closed === 'boolean' ? value.closed : false,
pos: getNumber(value.pos),
idBoard: getRequiredString(value.idBoard, 'idBoard'),
}
}
export function mapTrelloCard(value: unknown): TrelloCard {
if (!isRecordLike(value)) {
throw new Error('Trello returned an invalid card object')
}
const rawLabels = Array.isArray(value.labels) ? value.labels : []
const labels = rawLabels
.map((label) => mapTrelloLabel(label))
.filter((label): label is TrelloLabel => label !== null)
const labelIds = getIdArray(value.idLabels)
if (labelIds.length === 0) {
labelIds.push(...rawLabels.filter((label): label is string => typeof label === 'string'))
}
return {
id: getRequiredString(value.id, 'id'),
name: getRequiredString(value.name, 'name'),
desc: typeof value.desc === 'string' ? value.desc : '',
url: getRequiredString(value.url, 'url'),
idBoard: getRequiredString(value.idBoard, 'idBoard'),
idList: getRequiredString(value.idList, 'idList'),
closed: typeof value.closed === 'boolean' ? value.closed : false,
labelIds,
labels,
due: getOptionalString(value.due),
dueComplete: getOptionalBoolean(value.dueComplete),
}
}
export function mapTrelloBoard(value: unknown): TrelloBoard {
if (!isRecordLike(value)) {
throw new Error('Trello returned an invalid board object')
}
return {
id: getRequiredString(value.id, 'id'),
name: getRequiredString(value.name, 'name'),
desc: typeof value.desc === 'string' ? value.desc : '',
url: getRequiredString(value.url, 'url'),
closed: typeof value.closed === 'boolean' ? value.closed : false,
idOrganization: getOptionalString(value.idOrganization),
}
}
export function mapTrelloChecklist(value: unknown): TrelloChecklist {
if (!isRecordLike(value)) {
throw new Error('Trello returned an invalid checklist object')
}
return {
id: getRequiredString(value.id, 'id'),
name: getRequiredString(value.name, 'name'),
idCard: getRequiredString(value.idCard, 'idCard'),
idBoard: getOptionalString(value.idBoard),
pos: getNumber(value.pos),
}
}
export function mapTrelloChecklistItem(value: unknown): TrelloChecklistItem {
if (!isRecordLike(value)) {
throw new Error('Trello returned an invalid checklist item object')
}
return {
id: getRequiredString(value.id, 'id'),
name: getRequiredString(value.name, 'name'),
state: getRequiredString(value.state, 'state'),
pos: getNumber(value.pos),
idChecklist: getOptionalString(value.idChecklist),
}
}
export function mapTrelloAction(value: unknown): TrelloAction {
if (!isRecordLike(value)) {
throw new Error('Trello returned an invalid action object')
}
const data = isRecordLike(value.data) ? value.data : null
return {
id: getRequiredString(value.id, 'id'),
type: getRequiredString(value.type, 'type'),
date: getRequiredString(value.date, 'date'),
idMemberCreator: getRequiredString(value.idMemberCreator, 'idMemberCreator'),
text: data ? getOptionalString(data.text) : null,
memberCreator: mapTrelloMember(value.memberCreator),
card: data ? mapActionCardTarget(data.card) : null,
board: data ? mapActionBoardTarget(data.board) : null,
list: data ? mapActionListTarget(data.list) : null,
}
}
export function mapTrelloComment(value: unknown): TrelloComment {
return mapTrelloAction(value)
}
export function extractTrelloErrorMessage(
response: Response,
data: unknown,
fallback: string
): string {
const parts: string[] = []
if (isRecordLike(data)) {
const message = data.message
const error = data.error
if (typeof message === 'string' && message.trim().length > 0) {
parts.push(message)
}
if (typeof error === 'string' && error.trim().length > 0 && error !== message) {
parts.push(error)
}
}
if (parts.length > 0) {
return `${fallback}: ${parts.join(' - ')}`
}
if (response.statusText) {
return `${fallback}: ${response.status} ${response.statusText}`
}
return fallback
}
+421
View File
@@ -0,0 +1,421 @@
import type { ToolResponse } from '@/tools/types'
export interface TrelloBoard {
id: string
name: string
desc: string
url: string
closed: boolean
idOrganization: string | null
}
export interface TrelloChecklist {
id: string
name: string
idCard: string
idBoard: string | null
pos: number
}
export interface TrelloLabel {
id: string
name: string
color: string | null
}
export interface TrelloMember {
id: string
fullName: string | null
username: string | null
}
export interface TrelloList {
id: string
name: string
closed: boolean
pos: number
idBoard: string
}
export interface TrelloCard {
id: string
name: string
desc: string
url: string
idBoard: string
idList: string
closed: boolean
labelIds: string[]
labels: TrelloLabel[]
due: string | null
dueComplete: boolean | null
}
export interface TrelloActionCardTarget {
id: string
name: string
shortLink: string | null
idShort: number | null
due: string | null
}
export interface TrelloActionBoardTarget {
id: string
name: string
shortLink: string | null
}
export interface TrelloActionListTarget {
id: string
name: string
}
export interface TrelloAction {
id: string
type: string
date: string
idMemberCreator: string
text: string | null
memberCreator: TrelloMember | null
card: TrelloActionCardTarget | null
board: TrelloActionBoardTarget | null
list: TrelloActionListTarget | null
}
export interface TrelloComment extends TrelloAction {}
export interface TrelloListListsParams {
accessToken: string
boardId: string
filter?: string
}
export interface TrelloListCardsParams {
accessToken: string
boardId?: string
listId?: string
filter?: string
}
export interface TrelloCreateCardParams {
accessToken: string
listId: string
name: string
desc?: string
pos?: string
due?: string
dueComplete?: boolean
labelIds?: string[]
memberIds?: string[]
}
export interface TrelloUpdateCardParams {
accessToken: string
cardId: string
name?: string
desc?: string
closed?: boolean
idList?: string
due?: string
dueComplete?: boolean
}
export interface TrelloDeleteCardParams {
accessToken: string
cardId: string
}
export interface TrelloGetActionsParams {
accessToken: string
boardId?: string
cardId?: string
filter?: string
limit?: number
page?: number
since?: string
before?: string
}
export interface TrelloAddCommentParams {
accessToken: string
cardId: string
text: string
}
export interface TrelloCreateBoardParams {
accessToken: string
name: string
desc?: string
idOrganization?: string
defaultLists?: boolean
}
export interface TrelloGetBoardParams {
accessToken: string
boardId: string
}
export interface TrelloCreateListParams {
accessToken: string
boardId: string
name: string
pos?: string
}
export interface TrelloGetCardParams {
accessToken: string
cardId: string
}
export interface TrelloAddChecklistParams {
accessToken: string
cardId: string
name: string
pos?: string
}
export interface TrelloAddChecklistItemParams {
accessToken: string
checklistId: string
name: string
pos?: string
checked?: boolean
}
export interface TrelloUpdateChecklistItemParams {
accessToken: string
cardId: string
checkItemId: string
state?: 'complete' | 'incomplete'
name?: string
}
export interface TrelloAddLabelParams {
accessToken: string
cardId: string
labelId: string
}
export interface TrelloRemoveLabelParams {
accessToken: string
cardId: string
labelId: string
}
export interface TrelloAddMemberParams {
accessToken: string
cardId: string
memberId: string
}
export interface TrelloRemoveMemberParams {
accessToken: string
cardId: string
memberId: string
}
export interface TrelloListMembersParams {
accessToken: string
boardId: string
}
export interface TrelloUpdateListParams {
accessToken: string
listId: string
name?: string
closed?: boolean
idBoard?: string
pos?: string
}
export interface TrelloSearchParams {
accessToken: string
query: string
idBoards?: string[]
modelTypes?: string
cardsLimit?: number
}
export interface TrelloListListsResponse extends ToolResponse {
output: {
lists: TrelloList[]
count: number
error?: string
}
}
export interface TrelloListCardsResponse extends ToolResponse {
output: {
cards: TrelloCard[]
count: number
error?: string
}
}
export interface TrelloCreateCardResponse extends ToolResponse {
output: {
card?: TrelloCard
error?: string
}
}
export interface TrelloUpdateCardResponse extends ToolResponse {
output: {
card?: TrelloCard
error?: string
}
}
export interface TrelloGetActionsResponse extends ToolResponse {
output: {
actions: TrelloAction[]
count: number
error?: string
}
}
export interface TrelloAddCommentResponse extends ToolResponse {
output: {
comment?: TrelloComment
error?: string
}
}
export interface TrelloCreateBoardResponse extends ToolResponse {
output: {
board?: TrelloBoard
error?: string
}
}
export interface TrelloGetBoardResponse extends ToolResponse {
output: {
board?: TrelloBoard
error?: string
}
}
export interface TrelloCreateListResponse extends ToolResponse {
output: {
list?: TrelloList
error?: string
}
}
export interface TrelloGetCardResponse extends ToolResponse {
output: {
card?: TrelloCard
error?: string
}
}
export interface TrelloAddChecklistResponse extends ToolResponse {
output: {
checklist?: TrelloChecklist
error?: string
}
}
export interface TrelloChecklistItem {
id: string
name: string
state: string
pos: number
idChecklist: string | null
}
export interface TrelloAddChecklistItemResponse extends ToolResponse {
output: {
item?: TrelloChecklistItem
error?: string
}
}
export interface TrelloUpdateChecklistItemResponse extends ToolResponse {
output: {
item?: TrelloChecklistItem
error?: string
}
}
export interface TrelloAddLabelResponse extends ToolResponse {
output: {
labelIds: string[]
error?: string
}
}
export interface TrelloRemoveLabelResponse extends ToolResponse {
output: {
success: boolean
error?: string
}
}
export interface TrelloAddMemberResponse extends ToolResponse {
output: {
memberIds: string[]
error?: string
}
}
export interface TrelloRemoveMemberResponse extends ToolResponse {
output: {
success: boolean
error?: string
}
}
export interface TrelloListMembersResponse extends ToolResponse {
output: {
members: TrelloMember[]
count: number
error?: string
}
}
export interface TrelloUpdateListResponse extends ToolResponse {
output: {
list?: TrelloList
error?: string
}
}
export interface TrelloDeleteCardResponse extends ToolResponse {
output: {
success: boolean
error?: string
}
}
export interface TrelloSearchResponse extends ToolResponse {
output: {
cards: TrelloCard[]
boards: TrelloBoard[]
count: number
error?: string
}
}
export type TrelloResponse =
| TrelloListListsResponse
| TrelloListCardsResponse
| TrelloCreateCardResponse
| TrelloUpdateCardResponse
| TrelloDeleteCardResponse
| TrelloGetActionsResponse
| TrelloAddCommentResponse
| TrelloCreateBoardResponse
| TrelloGetBoardResponse
| TrelloCreateListResponse
| TrelloUpdateListResponse
| TrelloGetCardResponse
| TrelloAddChecklistResponse
| TrelloAddChecklistItemResponse
| TrelloUpdateChecklistItemResponse
| TrelloAddLabelResponse
| TrelloRemoveLabelResponse
| TrelloAddMemberResponse
| TrelloRemoveMemberResponse
| TrelloListMembersResponse
| TrelloSearchResponse
+201
View File
@@ -0,0 +1,201 @@
import { getErrorMessage } from '@sim/utils/errors'
import { env } from '@/lib/core/config/env'
import {
extractTrelloErrorMessage,
mapTrelloCard,
TRELLO_API_BASE_URL,
} from '@/tools/trello/shared'
import type { TrelloUpdateCardParams, TrelloUpdateCardResponse } from '@/tools/trello/types'
import type { ToolConfig } from '@/tools/types'
export const trelloUpdateCardTool: ToolConfig<TrelloUpdateCardParams, TrelloUpdateCardResponse> = {
id: 'trello_update_card',
name: 'Trello Update Card',
description: 'Update an existing card on Trello',
version: '1.0.0',
oauth: {
required: true,
provider: 'trello',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'Trello OAuth access token',
},
cardId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Trello card ID (24-character hex string)',
},
name: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'New name/title of the card',
},
desc: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'New description of the card',
},
closed: {
type: 'boolean',
required: false,
visibility: 'user-or-llm',
description: 'Archive/close the card (true) or reopen it (false)',
},
idList: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Trello list ID to move card to (24-character hex string)',
},
due: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Due date (ISO 8601 format)',
},
dueComplete: {
type: 'boolean',
required: false,
visibility: 'user-or-llm',
description: 'Mark the due date as complete',
},
},
request: {
url: (params) => {
if (!params.cardId) {
throw new Error('Card ID is required')
}
const apiKey = env.TRELLO_API_KEY
if (!apiKey) {
throw new Error('TRELLO_API_KEY environment variable is not set')
}
const url = new URL(`${TRELLO_API_BASE_URL}/cards/${params.cardId.trim()}`)
url.searchParams.set('key', apiKey)
url.searchParams.set('token', params.accessToken)
return url.toString()
},
method: 'PUT',
headers: () => ({
'Content-Type': 'application/json',
Accept: 'application/json',
}),
body: (params) => {
const body: Record<string, unknown> = {}
if (params.name !== undefined) body.name = params.name
if (params.desc !== undefined) body.desc = params.desc
if (params.closed !== undefined) body.closed = params.closed
if (params.idList !== undefined) body.idList = params.idList.trim()
if (params.due !== undefined) body.due = params.due
if (params.dueComplete !== undefined) body.dueComplete = params.dueComplete
if (Object.keys(body).length === 0) {
throw new Error('At least one field must be provided to update')
}
return body
},
},
transformResponse: async (response) => {
const data = await response.json().catch(() => null)
if (!response.ok) {
const error = extractTrelloErrorMessage(response, data, 'Failed to update card')
return {
success: false,
output: {
error,
},
error,
}
}
try {
const card = mapTrelloCard(data)
return {
success: true,
output: {
card,
},
}
} catch (error) {
const message = getErrorMessage(error, 'Failed to parse updated card')
return {
success: false,
output: {
error: message,
},
error: message,
}
}
},
outputs: {
card: {
type: 'json',
description:
'Updated card (id, name, desc, url, idBoard, idList, closed, labelIds, labels, due, dueComplete)',
optional: true,
properties: {
id: { type: 'string', description: 'Card ID' },
name: { type: 'string', description: 'Card name' },
desc: { type: 'string', description: 'Card description' },
url: { type: 'string', description: 'Full card URL' },
idBoard: { type: 'string', description: 'Board ID containing the card' },
idList: { type: 'string', description: 'List ID containing the card' },
closed: { type: 'boolean', description: 'Whether the card is archived' },
labelIds: {
type: 'array',
description: 'Label IDs applied to the card',
items: {
type: 'string',
description: 'A Trello label ID',
},
},
labels: {
type: 'array',
description: 'Labels applied to the card',
items: {
type: 'object',
properties: {
id: { type: 'string', description: 'Label ID' },
name: { type: 'string', description: 'Label name' },
color: {
type: 'string',
description: 'Label color',
optional: true,
},
},
},
},
due: {
type: 'string',
description: 'Card due date in ISO 8601 format',
optional: true,
},
dueComplete: {
type: 'boolean',
description: 'Whether the due date is complete',
optional: true,
},
},
},
},
}
@@ -0,0 +1,150 @@
import { getErrorMessage } from '@sim/utils/errors'
import { env } from '@/lib/core/config/env'
import {
extractTrelloErrorMessage,
mapTrelloChecklistItem,
TRELLO_API_BASE_URL,
} from '@/tools/trello/shared'
import type {
TrelloUpdateChecklistItemParams,
TrelloUpdateChecklistItemResponse,
} from '@/tools/trello/types'
import type { ToolConfig } from '@/tools/types'
export const trelloUpdateChecklistItemTool: ToolConfig<
TrelloUpdateChecklistItemParams,
TrelloUpdateChecklistItemResponse
> = {
id: 'trello_update_checklist_item',
name: 'Trello Update Checklist Item',
description: 'Check off, uncheck, or rename a Trello checklist item',
version: '1.0.0',
oauth: {
required: true,
provider: 'trello',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'Trello OAuth access token',
},
cardId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Trello card ID that owns the checklist item (24-character hex string)',
},
checkItemId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Checklist item ID to update (24-character hex string)',
},
state: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Set the item state to complete or incomplete',
},
name: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'New name for the checklist item',
},
},
request: {
url: (params) => {
if (!params.cardId) {
throw new Error('Card ID is required')
}
if (!params.checkItemId) {
throw new Error('Checklist item ID is required')
}
if (!params.state && !params.name) {
throw new Error('At least one of state or name must be provided to update')
}
const apiKey = env.TRELLO_API_KEY
if (!apiKey) {
throw new Error('TRELLO_API_KEY environment variable is not set')
}
const url = new URL(
`${TRELLO_API_BASE_URL}/cards/${params.cardId.trim()}/checkItem/${params.checkItemId.trim()}`
)
url.searchParams.set('key', apiKey)
url.searchParams.set('token', params.accessToken)
if (params.state) url.searchParams.set('state', params.state)
if (params.name) url.searchParams.set('name', params.name.trim())
return url.toString()
},
method: 'PUT',
headers: () => ({
Accept: 'application/json',
}),
},
transformResponse: async (response) => {
const data = await response.json().catch(() => null)
if (!response.ok) {
const error = extractTrelloErrorMessage(response, data, 'Failed to update checklist item')
return {
success: false,
output: {
error,
},
error,
}
}
try {
const item = mapTrelloChecklistItem(data)
return {
success: true,
output: {
item,
},
}
} catch (error) {
const message = getErrorMessage(error, 'Failed to parse updated checklist item')
return {
success: false,
output: {
error: message,
},
error: message,
}
}
},
outputs: {
item: {
type: 'json',
description: 'Updated checklist item (id, name, state, pos, idChecklist)',
optional: true,
properties: {
id: { type: 'string', description: 'Checklist item ID' },
name: { type: 'string', description: 'Checklist item name' },
state: { type: 'string', description: 'Item state (complete or incomplete)' },
pos: { type: 'number', description: 'Item position on the checklist' },
idChecklist: {
type: 'string',
description: 'Checklist ID containing the item',
optional: true,
},
},
},
},
}
+150
View File
@@ -0,0 +1,150 @@
import { getErrorMessage } from '@sim/utils/errors'
import { env } from '@/lib/core/config/env'
import {
extractTrelloErrorMessage,
mapTrelloList,
TRELLO_API_BASE_URL,
} from '@/tools/trello/shared'
import type { TrelloUpdateListParams, TrelloUpdateListResponse } from '@/tools/trello/types'
import type { ToolConfig } from '@/tools/types'
export const trelloUpdateListTool: ToolConfig<TrelloUpdateListParams, TrelloUpdateListResponse> = {
id: 'trello_update_list',
name: 'Trello Update List',
description: 'Rename, move, archive, or reopen a Trello list',
version: '1.0.0',
oauth: {
required: true,
provider: 'trello',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'Trello OAuth access token',
},
listId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Trello list ID (24-character hex string)',
},
name: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'New name of the list',
},
closed: {
type: 'boolean',
required: false,
visibility: 'user-or-llm',
description: 'Archive the list (true) or reopen it (false)',
},
idBoard: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Board ID to move the list to (24-character hex string)',
},
pos: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'New position of the list (top, bottom, or positive float)',
},
},
request: {
url: (params) => {
if (!params.listId) {
throw new Error('List ID is required')
}
const apiKey = env.TRELLO_API_KEY
if (!apiKey) {
throw new Error('TRELLO_API_KEY environment variable is not set')
}
const url = new URL(`${TRELLO_API_BASE_URL}/lists/${params.listId.trim()}`)
url.searchParams.set('key', apiKey)
url.searchParams.set('token', params.accessToken)
return url.toString()
},
method: 'PUT',
headers: () => ({
'Content-Type': 'application/json',
Accept: 'application/json',
}),
body: (params) => {
const body: Record<string, unknown> = {}
if (params.name !== undefined) body.name = params.name
if (params.closed !== undefined) body.closed = params.closed
if (params.idBoard !== undefined) body.idBoard = params.idBoard.trim()
if (params.pos !== undefined) body.pos = params.pos
if (Object.keys(body).length === 0) {
throw new Error('At least one field must be provided to update')
}
return body
},
},
transformResponse: async (response) => {
const data = await response.json().catch(() => null)
if (!response.ok) {
const error = extractTrelloErrorMessage(response, data, 'Failed to update list')
return {
success: false,
output: {
error,
},
error,
}
}
try {
const list = mapTrelloList(data)
return {
success: true,
output: {
list,
},
}
} catch (error) {
const message = getErrorMessage(error, 'Failed to parse updated list')
return {
success: false,
output: {
error: message,
},
error: message,
}
}
},
outputs: {
list: {
type: 'json',
description: 'Updated list (id, name, closed, pos, idBoard)',
optional: true,
properties: {
id: { type: 'string', description: 'List ID' },
name: { type: 'string', description: 'List name' },
closed: { type: 'boolean', description: 'Whether the list is archived' },
pos: { type: 'number', description: 'List position on the board' },
idBoard: { type: 'string', description: 'Board ID containing the list' },
},
},
},
}