chore: import upstream snapshot with attribution
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
Publish CLI Package / publish-npm (push) Has been cancelled
Publish Python SDK / publish-pypi (push) Has been cancelled
Publish TypeScript SDK / publish-npm (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
+84
View File
@@ -0,0 +1,84 @@
import type { AsanaAddCommentParams, AsanaAddCommentResponse } from '@/tools/asana/types'
import type { ToolConfig } from '@/tools/types'
export const asanaAddCommentTool: ToolConfig<AsanaAddCommentParams, AsanaAddCommentResponse> = {
id: 'asana_add_comment',
name: 'Asana Add Comment',
description: 'Add a comment (story) to an Asana task',
version: '1.0.0',
oauth: {
required: true,
provider: 'asana',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'OAuth access token for Asana',
},
taskGid: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Asana task GID (numeric string)',
},
text: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The text content of the comment',
},
},
request: {
url: '/api/tools/asana/add-comment',
method: 'POST',
headers: () => ({
'Content-Type': 'application/json',
}),
body: (params) => ({
accessToken: params.accessToken,
taskGid: params.taskGid,
text: params.text,
}),
},
transformResponse: async (response: Response) => {
const responseText = await response.text()
if (!responseText) {
return {
success: false,
output: {},
error: 'Empty response from Asana',
}
}
const data = JSON.parse(responseText)
const { success, error, ...output } = data
return {
success: success ?? true,
output,
error,
}
},
outputs: {
success: { type: 'boolean', description: 'Operation success status' },
ts: { type: 'string', description: 'Timestamp of the response' },
gid: { type: 'string', description: 'Comment globally unique identifier' },
text: { type: 'string', description: 'Comment text content' },
created_at: { type: 'string', description: 'Comment creation timestamp' },
created_by: {
type: 'object',
description: 'Comment author details',
properties: {
gid: { type: 'string', description: 'Author GID' },
name: { type: 'string', description: 'Author name' },
},
},
},
}
+87
View File
@@ -0,0 +1,87 @@
import type { AsanaAddFollowersParams, AsanaAddFollowersResponse } from '@/tools/asana/types'
import type { ToolConfig } from '@/tools/types'
export const asanaAddFollowersTool: ToolConfig<AsanaAddFollowersParams, AsanaAddFollowersResponse> =
{
id: 'asana_add_followers',
name: 'Asana Add Followers',
description: 'Add one or more followers to an Asana task',
version: '1.0.0',
oauth: {
required: true,
provider: 'asana',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'OAuth access token for Asana',
},
taskGid: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'GID of the Asana task (numeric string)',
},
followers: {
type: 'array',
required: true,
visibility: 'user-or-llm',
description: 'Array of user GIDs to add as followers to the task',
},
},
request: {
url: '/api/tools/asana/add-followers',
method: 'POST',
headers: () => ({
'Content-Type': 'application/json',
}),
body: (params) => ({
accessToken: params.accessToken,
taskGid: params.taskGid,
followers: params.followers,
}),
},
transformResponse: async (response: Response) => {
const responseText = await response.text()
if (!responseText) {
return {
success: false,
output: { ts: new Date().toISOString(), gid: '', name: '', followers: [] },
error: 'Empty response from Asana',
}
}
const data = JSON.parse(responseText)
const { success, error, ...output } = data
return {
success: success ?? true,
output,
error,
}
},
outputs: {
success: { type: 'boolean', description: 'Operation success status' },
ts: { type: 'string', description: 'Timestamp of the response' },
gid: { type: 'string', description: 'Task globally unique identifier' },
name: { type: 'string', description: 'Task name' },
followers: {
type: 'array',
description: 'Current followers on the task after the update',
items: {
type: 'object',
properties: {
gid: { type: 'string', description: 'Follower GID' },
name: { type: 'string', description: 'Follower name' },
},
},
},
},
}
+91
View File
@@ -0,0 +1,91 @@
import type { AsanaCreateProjectParams, AsanaProjectRecordResponse } from '@/tools/asana/types'
import type { ToolConfig } from '@/tools/types'
export const asanaCreateProjectTool: ToolConfig<
AsanaCreateProjectParams,
AsanaProjectRecordResponse
> = {
id: 'asana_create_project',
name: 'Asana Create Project',
description: 'Create a new project in an Asana workspace',
version: '1.0.0',
oauth: {
required: true,
provider: 'asana',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'OAuth access token for Asana',
},
workspace: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Asana workspace GID (numeric string) where the project will be created',
},
name: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Name of the project',
},
notes: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Notes or description for the project',
},
},
request: {
url: '/api/tools/asana/create-project',
method: 'POST',
headers: () => ({
'Content-Type': 'application/json',
}),
body: (params) => ({
accessToken: params.accessToken,
workspace: params.workspace,
name: params.name,
notes: params.notes,
}),
},
transformResponse: async (response: Response) => {
const responseText = await response.text()
if (!responseText) {
return {
success: false,
output: { ts: new Date().toISOString(), gid: '', name: '', notes: '' },
error: 'Empty response from Asana',
}
}
const data = JSON.parse(responseText)
const { success, error, ...output } = data
return {
success: success ?? true,
output,
error,
}
},
outputs: {
success: { type: 'boolean', description: 'Operation success status' },
ts: { type: 'string', description: 'Timestamp of the response' },
gid: { type: 'string', description: 'Project globally unique identifier' },
name: { type: 'string', description: 'Project name' },
notes: { type: 'string', description: 'Project notes or description' },
archived: { type: 'boolean', description: 'Whether the project is archived' },
color: { type: 'string', description: 'Project color' },
created_at: { type: 'string', description: 'Project creation timestamp' },
modified_at: { type: 'string', description: 'Project last modified timestamp' },
permalink_url: { type: 'string', description: 'URL to the project in Asana' },
},
}
+76
View File
@@ -0,0 +1,76 @@
import type { AsanaCreateSectionParams, AsanaSectionResponse } from '@/tools/asana/types'
import type { ToolConfig } from '@/tools/types'
export const asanaCreateSectionTool: ToolConfig<AsanaCreateSectionParams, AsanaSectionResponse> = {
id: 'asana_create_section',
name: 'Asana Create Section',
description: 'Create a new section in an Asana project',
version: '1.0.0',
oauth: {
required: true,
provider: 'asana',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'OAuth access token for Asana',
},
projectGid: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'GID of the Asana project (numeric string) to add the section to',
},
name: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Name of the section',
},
},
request: {
url: '/api/tools/asana/create-section',
method: 'POST',
headers: () => ({
'Content-Type': 'application/json',
}),
body: (params) => ({
accessToken: params.accessToken,
projectGid: params.projectGid,
name: params.name,
}),
},
transformResponse: async (response: Response) => {
const responseText = await response.text()
if (!responseText) {
return {
success: false,
output: { ts: new Date().toISOString(), gid: '', name: '' },
error: 'Empty response from Asana',
}
}
const data = JSON.parse(responseText)
const { success, error, ...output } = data
return {
success: success ?? true,
output,
error,
}
},
outputs: {
success: { type: 'boolean', description: 'Operation success status' },
ts: { type: 'string', description: 'Timestamp of the response' },
gid: { type: 'string', description: 'Section globally unique identifier' },
name: { type: 'string', description: 'Section name' },
created_at: { type: 'string', description: 'Section creation timestamp' },
},
}
+109
View File
@@ -0,0 +1,109 @@
import type { AsanaCreateSubtaskParams, AsanaCreateTaskResponse } from '@/tools/asana/types'
import type { ToolConfig } from '@/tools/types'
export const asanaCreateSubtaskTool: ToolConfig<AsanaCreateSubtaskParams, AsanaCreateTaskResponse> =
{
id: 'asana_create_subtask',
name: 'Asana Create Subtask',
description: 'Create a subtask under an existing Asana task',
version: '1.0.0',
oauth: {
required: true,
provider: 'asana',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'OAuth access token for Asana',
},
taskGid: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'GID of the parent Asana task (numeric string)',
},
name: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Name of the subtask',
},
notes: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Notes or description for the subtask',
},
assignee: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'User GID to assign the subtask to',
},
due_on: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Due date in YYYY-MM-DD format',
},
},
request: {
url: '/api/tools/asana/create-subtask',
method: 'POST',
headers: () => ({
'Content-Type': 'application/json',
}),
body: (params) => ({
accessToken: params.accessToken,
taskGid: params.taskGid,
name: params.name,
notes: params.notes,
assignee: params.assignee,
due_on: params.due_on,
}),
},
transformResponse: async (response: Response) => {
const responseText = await response.text()
if (!responseText) {
return {
success: false,
output: {
ts: new Date().toISOString(),
gid: '',
name: '',
notes: '',
completed: false,
created_at: new Date().toISOString(),
permalink_url: '',
},
error: 'Empty response from Asana',
}
}
const data = JSON.parse(responseText)
const { success, error, ...output } = data
return {
success: success ?? true,
output,
error,
}
},
outputs: {
success: { type: 'boolean', description: 'Operation success status' },
ts: { type: 'string', description: 'Timestamp of the response' },
gid: { type: 'string', description: 'Subtask globally unique identifier' },
name: { type: 'string', description: 'Subtask name' },
notes: { type: 'string', description: 'Subtask notes or description' },
completed: { type: 'boolean', description: 'Whether the subtask is completed' },
created_at: { type: 'string', description: 'Subtask creation timestamp' },
permalink_url: { type: 'string', description: 'URL to the subtask in Asana' },
},
}
+107
View File
@@ -0,0 +1,107 @@
import type { AsanaCreateTaskParams, AsanaCreateTaskResponse } from '@/tools/asana/types'
import type { ToolConfig } from '@/tools/types'
export const asanaCreateTaskTool: ToolConfig<AsanaCreateTaskParams, AsanaCreateTaskResponse> = {
id: 'asana_create_task',
name: 'Asana Create Task',
description: 'Create a new task in Asana',
version: '1.0.0',
oauth: {
required: true,
provider: 'asana',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'OAuth access token for Asana',
},
workspace: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Asana workspace GID (numeric string) where the task will be created',
},
name: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Name of the task',
},
notes: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Notes or description for the task',
},
assignee: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'User GID to assign the task to',
},
due_on: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Due date in YYYY-MM-DD format',
},
},
request: {
url: '/api/tools/asana/create-task',
method: 'POST',
headers: () => ({
'Content-Type': 'application/json',
}),
body: (params) => ({
accessToken: params.accessToken,
workspace: params.workspace,
name: params.name,
notes: params.notes,
assignee: params.assignee,
due_on: params.due_on,
}),
},
transformResponse: async (response: Response) => {
const responseText = await response.text()
if (!responseText) {
return {
success: true,
output: {
ts: new Date().toISOString(),
gid: 'unknown',
name: 'Task created successfully',
notes: '',
completed: false,
created_at: new Date().toISOString(),
permalink_url: '',
},
}
}
const data = JSON.parse(responseText)
const { success, error, ...output } = data
return {
success: success ?? true,
output,
error,
}
},
outputs: {
success: { type: 'boolean', description: 'Operation success status' },
ts: { type: 'string', description: 'Timestamp of the response' },
gid: { type: 'string', description: 'Task globally unique identifier' },
name: { type: 'string', description: 'Task name' },
notes: { type: 'string', description: 'Task notes or description' },
completed: { type: 'boolean', description: 'Whether the task is completed' },
created_at: { type: 'string', description: 'Task creation timestamp' },
permalink_url: { type: 'string', description: 'URL to the task in Asana' },
},
}
+68
View File
@@ -0,0 +1,68 @@
import type { AsanaDeleteTaskParams, AsanaDeleteTaskResponse } from '@/tools/asana/types'
import type { ToolConfig } from '@/tools/types'
export const asanaDeleteTaskTool: ToolConfig<AsanaDeleteTaskParams, AsanaDeleteTaskResponse> = {
id: 'asana_delete_task',
name: 'Asana Delete Task',
description: 'Delete an Asana task by its GID (moves it to the trash)',
version: '1.0.0',
oauth: {
required: true,
provider: 'asana',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'OAuth access token for Asana',
},
taskGid: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'GID of the Asana task to delete (numeric string)',
},
},
request: {
url: '/api/tools/asana/delete-task',
method: 'POST',
headers: () => ({
'Content-Type': 'application/json',
}),
body: (params) => ({
accessToken: params.accessToken,
taskGid: params.taskGid,
}),
},
transformResponse: async (response: Response) => {
const responseText = await response.text()
if (!responseText) {
return {
success: false,
output: { ts: new Date().toISOString(), gid: '', deleted: true },
error: 'Empty response from Asana',
}
}
const data = JSON.parse(responseText)
const { success, error, ...output } = data
return {
success: success ?? true,
output,
error,
}
},
outputs: {
success: { type: 'boolean', description: 'Operation success status' },
ts: { type: 'string', description: 'Timestamp of the response' },
gid: { type: 'string', description: 'GID of the deleted task' },
deleted: { type: 'boolean', description: 'Whether the task was deleted' },
},
}
+74
View File
@@ -0,0 +1,74 @@
import type { AsanaGetProjectParams, AsanaProjectRecordResponse } from '@/tools/asana/types'
import type { ToolConfig } from '@/tools/types'
export const asanaGetProjectTool: ToolConfig<AsanaGetProjectParams, AsanaProjectRecordResponse> = {
id: 'asana_get_project',
name: 'Asana Get Project',
description: 'Retrieve a single Asana project by its GID',
version: '1.0.0',
oauth: {
required: true,
provider: 'asana',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'OAuth access token for Asana',
},
projectGid: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Asana project GID (numeric string) to retrieve',
},
},
request: {
url: '/api/tools/asana/get-project',
method: 'POST',
headers: () => ({
'Content-Type': 'application/json',
}),
body: (params) => ({
accessToken: params.accessToken,
projectGid: params.projectGid,
}),
},
transformResponse: async (response: Response) => {
const responseText = await response.text()
if (!responseText) {
return {
success: false,
output: { ts: new Date().toISOString(), gid: '', name: '', notes: '' },
error: 'Empty response from Asana',
}
}
const data = JSON.parse(responseText)
const { success, error, ...output } = data
return {
success: success ?? true,
output,
error,
}
},
outputs: {
success: { type: 'boolean', description: 'Operation success status' },
ts: { type: 'string', description: 'Timestamp of the response' },
gid: { type: 'string', description: 'Project globally unique identifier' },
name: { type: 'string', description: 'Project name' },
notes: { type: 'string', description: 'Project notes or description' },
archived: { type: 'boolean', description: 'Whether the project is archived' },
color: { type: 'string', description: 'Project color' },
created_at: { type: 'string', description: 'Project creation timestamp' },
modified_at: { type: 'string', description: 'Project last modified timestamp' },
permalink_url: { type: 'string', description: 'URL to the project in Asana' },
},
}
+78
View File
@@ -0,0 +1,78 @@
import type { AsanaGetProjectsParams, AsanaGetProjectsResponse } from '@/tools/asana/types'
import type { ToolConfig } from '@/tools/types'
export const asanaGetProjectsTool: ToolConfig<AsanaGetProjectsParams, AsanaGetProjectsResponse> = {
id: 'asana_get_projects',
name: 'Asana Get Projects',
description: 'Retrieve all projects from an Asana workspace',
version: '1.0.0',
oauth: {
required: true,
provider: 'asana',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'OAuth access token for Asana',
},
workspace: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Asana workspace GID (numeric string) to retrieve projects from',
},
},
request: {
url: '/api/tools/asana/get-projects',
method: 'POST',
headers: () => ({
'Content-Type': 'application/json',
}),
body: (params) => ({
accessToken: params.accessToken,
workspace: params.workspace,
}),
},
transformResponse: async (response: Response) => {
const responseText = await response.text()
if (!responseText) {
return {
success: false,
output: {},
error: 'Empty response from Asana',
}
}
const data = JSON.parse(responseText)
const { success, error, ...output } = data
return {
success: success ?? true,
output,
error,
}
},
outputs: {
success: { type: 'boolean', description: 'Operation success status' },
ts: { type: 'string', description: 'Timestamp of the response' },
projects: {
type: 'array',
description: 'Array of projects',
items: {
type: 'object',
properties: {
gid: { type: 'string', description: 'Project GID' },
name: { type: 'string', description: 'Project name' },
resource_type: { type: 'string', description: 'Resource type (project)' },
},
},
},
},
}
+126
View File
@@ -0,0 +1,126 @@
import type { AsanaGetTaskParams, AsanaGetTaskResponse } from '@/tools/asana/types'
import type { ToolConfig } from '@/tools/types'
export const asanaGetTaskTool: ToolConfig<AsanaGetTaskParams, AsanaGetTaskResponse> = {
id: 'asana_get_task',
name: 'Asana Get Task',
description: 'Retrieve a single task by GID or get multiple tasks with filters',
version: '1.0.0',
oauth: {
required: true,
provider: 'asana',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'OAuth access token for Asana',
},
taskGid: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'The globally unique identifier (GID) of the task. If not provided, will get multiple tasks.',
},
workspace: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Asana workspace GID (numeric string) to filter tasks (required when not using taskGid)',
},
project: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Asana project GID (numeric string) to filter tasks',
},
limit: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Maximum number of tasks to return (default: 50)',
},
},
request: {
url: '/api/tools/asana/get-task',
method: 'POST',
headers: () => ({
'Content-Type': 'application/json',
}),
body: (params) => ({
accessToken: params.accessToken,
taskGid: params.taskGid,
workspace: params.workspace,
project: params.project,
limit: params.limit,
}),
},
transformResponse: async (response: Response) => {
const responseText = await response.text()
if (!responseText) {
return {
success: false,
output: {},
error: 'Empty response from Asana',
}
}
const data = JSON.parse(responseText)
const { success, error, ...output } = data
return {
success: success ?? true,
output,
error,
}
},
outputs: {
success: { type: 'boolean', description: 'Operation success status' },
ts: { type: 'string', description: 'Timestamp of the response' },
gid: { type: 'string', description: 'Task globally unique identifier' },
resource_type: { type: 'string', description: 'Resource type (task)' },
resource_subtype: { type: 'string', description: 'Resource subtype' },
name: { type: 'string', description: 'Task name' },
notes: { type: 'string', description: 'Task notes or description' },
completed: { type: 'boolean', description: 'Whether the task is completed' },
assignee: {
type: 'object',
description: 'Assignee details',
properties: {
gid: { type: 'string', description: 'Assignee GID' },
name: { type: 'string', description: 'Assignee name' },
},
},
created_by: {
type: 'object',
description: 'Creator details',
properties: {
gid: { type: 'string', description: 'Creator GID' },
name: { type: 'string', description: 'Creator name' },
},
},
due_on: { type: 'string', description: 'Due date (YYYY-MM-DD)' },
created_at: { type: 'string', description: 'Task creation timestamp' },
modified_at: { type: 'string', description: 'Task last modified timestamp' },
tasks: {
type: 'array',
description: 'Array of tasks (when fetching multiple)',
items: {
type: 'object',
properties: {
gid: { type: 'string', description: 'Task GID' },
name: { type: 'string', description: 'Task name' },
completed: { type: 'boolean', description: 'Completion status' },
},
},
},
},
}
+29
View File
@@ -0,0 +1,29 @@
import { asanaAddCommentTool } from '@/tools/asana/add_comment'
import { asanaAddFollowersTool } from '@/tools/asana/add_followers'
import { asanaCreateProjectTool } from '@/tools/asana/create_project'
import { asanaCreateSectionTool } from '@/tools/asana/create_section'
import { asanaCreateSubtaskTool } from '@/tools/asana/create_subtask'
import { asanaCreateTaskTool } from '@/tools/asana/create_task'
import { asanaDeleteTaskTool } from '@/tools/asana/delete_task'
import { asanaGetProjectTool } from '@/tools/asana/get_project'
import { asanaGetProjectsTool } from '@/tools/asana/get_projects'
import { asanaGetTaskTool } from '@/tools/asana/get_task'
import { asanaListSectionsTool } from '@/tools/asana/list_sections'
import { asanaListWorkspacesTool } from '@/tools/asana/list_workspaces'
import { asanaSearchTasksTool } from '@/tools/asana/search_tasks'
import { asanaUpdateTaskTool } from '@/tools/asana/update_task'
export { asanaGetTaskTool }
export { asanaCreateTaskTool }
export { asanaUpdateTaskTool }
export { asanaGetProjectsTool }
export { asanaSearchTasksTool }
export { asanaAddCommentTool }
export { asanaCreateProjectTool }
export { asanaGetProjectTool }
export { asanaListWorkspacesTool }
export { asanaCreateSubtaskTool }
export { asanaDeleteTaskTool }
export { asanaAddFollowersTool }
export { asanaCreateSectionTool }
export { asanaListSectionsTool }
+79
View File
@@ -0,0 +1,79 @@
import type { AsanaListSectionsParams, AsanaListSectionsResponse } from '@/tools/asana/types'
import type { ToolConfig } from '@/tools/types'
export const asanaListSectionsTool: ToolConfig<AsanaListSectionsParams, AsanaListSectionsResponse> =
{
id: 'asana_list_sections',
name: 'Asana List Sections',
description: 'List all sections in an Asana project',
version: '1.0.0',
oauth: {
required: true,
provider: 'asana',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'OAuth access token for Asana',
},
projectGid: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'GID of the Asana project (numeric string) to list sections from',
},
},
request: {
url: '/api/tools/asana/list-sections',
method: 'POST',
headers: () => ({
'Content-Type': 'application/json',
}),
body: (params) => ({
accessToken: params.accessToken,
projectGid: params.projectGid,
}),
},
transformResponse: async (response: Response) => {
const responseText = await response.text()
if (!responseText) {
return {
success: false,
output: { ts: new Date().toISOString(), sections: [] },
error: 'Empty response from Asana',
}
}
const data = JSON.parse(responseText)
const { success, error, ...output } = data
return {
success: success ?? true,
output,
error,
}
},
outputs: {
success: { type: 'boolean', description: 'Operation success status' },
ts: { type: 'string', description: 'Timestamp of the response' },
sections: {
type: 'array',
description: 'Array of sections in the project',
items: {
type: 'object',
properties: {
gid: { type: 'string', description: 'Section GID' },
name: { type: 'string', description: 'Section name' },
resource_type: { type: 'string', description: 'Resource type (section)' },
},
},
},
},
}
+74
View File
@@ -0,0 +1,74 @@
import type { AsanaListWorkspacesParams, AsanaListWorkspacesResponse } from '@/tools/asana/types'
import type { ToolConfig } from '@/tools/types'
export const asanaListWorkspacesTool: ToolConfig<
AsanaListWorkspacesParams,
AsanaListWorkspacesResponse
> = {
id: 'asana_list_workspaces',
name: 'Asana List Workspaces',
description: 'List all Asana workspaces and organizations the authenticated user belongs to',
version: '1.0.0',
oauth: {
required: true,
provider: 'asana',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'OAuth access token for Asana',
},
},
request: {
url: '/api/tools/asana/list-workspaces',
method: 'POST',
headers: () => ({
'Content-Type': 'application/json',
}),
body: (params) => ({
accessToken: params.accessToken,
}),
},
transformResponse: async (response: Response) => {
const responseText = await response.text()
if (!responseText) {
return {
success: false,
output: { ts: new Date().toISOString(), workspaces: [] },
error: 'Empty response from Asana',
}
}
const data = JSON.parse(responseText)
const { success, error, ...output } = data
return {
success: success ?? true,
output,
error,
}
},
outputs: {
success: { type: 'boolean', description: 'Operation success status' },
ts: { type: 'string', description: 'Timestamp of the response' },
workspaces: {
type: 'array',
description: 'Array of workspaces',
items: {
type: 'object',
properties: {
gid: { type: 'string', description: 'Workspace GID' },
name: { type: 'string', description: 'Workspace name' },
resource_type: { type: 'string', description: 'Resource type (workspace)' },
},
},
},
},
}
+129
View File
@@ -0,0 +1,129 @@
import type { AsanaSearchTasksParams, AsanaSearchTasksResponse } from '@/tools/asana/types'
import type { ToolConfig } from '@/tools/types'
export const asanaSearchTasksTool: ToolConfig<AsanaSearchTasksParams, AsanaSearchTasksResponse> = {
id: 'asana_search_tasks',
name: 'Asana Search Tasks',
description: 'Search for tasks in an Asana workspace',
version: '1.0.0',
oauth: {
required: true,
provider: 'asana',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'OAuth access token for Asana',
},
workspace: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Asana workspace GID (numeric string) to search tasks in',
},
text: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Text to search for in task names',
},
assignee: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Filter tasks by assignee user GID',
},
projects: {
type: 'array',
required: false,
visibility: 'user-or-llm',
description: 'Array of Asana project GIDs (numeric strings) to filter tasks by',
},
completed: {
type: 'boolean',
required: false,
visibility: 'user-or-llm',
description: 'Filter by completion status',
},
},
request: {
url: '/api/tools/asana/search-tasks',
method: 'POST',
headers: () => ({
'Content-Type': 'application/json',
}),
body: (params) => ({
accessToken: params.accessToken,
workspace: params.workspace,
text: params.text,
assignee: params.assignee,
projects: params.projects,
completed: params.completed,
}),
},
transformResponse: async (response: Response) => {
const responseText = await response.text()
if (!responseText) {
return {
success: false,
output: {},
error: 'Empty response from Asana',
}
}
const data = JSON.parse(responseText)
const { success, error, ...output } = data
return {
success: success ?? true,
output,
error,
}
},
outputs: {
success: { type: 'boolean', description: 'Operation success status' },
ts: { type: 'string', description: 'Timestamp of the response' },
tasks: {
type: 'array',
description: 'Array of matching tasks',
items: {
type: 'object',
properties: {
gid: { type: 'string', description: 'Task GID' },
resource_type: { type: 'string', description: 'Resource type' },
resource_subtype: { type: 'string', description: 'Resource subtype' },
name: { type: 'string', description: 'Task name' },
notes: { type: 'string', description: 'Task notes' },
completed: { type: 'boolean', description: 'Completion status' },
assignee: {
type: 'object',
description: 'Assignee details',
properties: {
gid: { type: 'string', description: 'Assignee GID' },
name: { type: 'string', description: 'Assignee name' },
},
},
due_on: { type: 'string', description: 'Due date' },
created_at: { type: 'string', description: 'Creation timestamp' },
modified_at: { type: 'string', description: 'Modified timestamp' },
},
},
},
next_page: {
type: 'object',
description: 'Pagination info',
properties: {
offset: { type: 'string', description: 'Offset token' },
path: { type: 'string', description: 'API path' },
uri: { type: 'string', description: 'Full URI' },
},
},
},
}
+328
View File
@@ -0,0 +1,328 @@
import type { ToolResponse } from '@/tools/types'
export interface AsanaGetTaskParams {
accessToken: string
taskGid?: string
workspace?: string
project?: string
limit?: number
}
export interface AsanaGetTaskResponse extends ToolResponse {
output: {
ts: string
gid?: string
resource_type?: string
resource_subtype?: string
name?: string
notes?: string
completed?: boolean
assignee?: {
gid: string
name: string
}
created_by?: {
gid: string
resource_type: string
name: string
}
due_on?: string
created_at?: string
modified_at?: string
tasks?: Array<{
gid: string
resource_type: string
resource_subtype: string
name: string
notes?: string
completed: boolean
assignee?: {
gid: string
name: string
}
created_by?: {
gid: string
resource_type: string
name: string
}
due_on?: string
created_at: string
modified_at: string
}>
next_page?: {
offset: string
path: string
uri: string
}
}
}
export interface AsanaCreateTaskParams {
accessToken: string
workspace: string
name: string
notes?: string
assignee?: string
due_on?: string
}
export interface AsanaCreateTaskResponse extends ToolResponse {
output: {
ts: string
gid: string
name: string
notes: string
completed: boolean
created_at: string
permalink_url: string
}
}
export interface AsanaUpdateTaskParams {
accessToken: string
taskGid: string
name?: string
notes?: string
assignee?: string
completed?: boolean
due_on?: string
}
export interface AsanaUpdateTaskResponse extends ToolResponse {
output: {
ts: string
gid: string
name: string
notes: string
completed: boolean
modified_at: string
}
}
export interface AsanaGetProjectsParams {
accessToken: string
workspace: string
}
export interface AsanaGetProjectsResponse extends ToolResponse {
output: {
ts: string
projects: Array<{
gid: string
name: string
resource_type: string
}>
}
}
export interface AsanaSearchTasksParams {
accessToken: string
workspace: string
text?: string
assignee?: string
projects?: string[]
completed?: boolean
}
export interface AsanaSearchTasksResponse extends ToolResponse {
output: {
ts: string
tasks: Array<{
gid: string
resource_type: string
resource_subtype: string
name: string
notes?: string
completed: boolean
assignee?: {
gid: string
name: string
}
created_by?: {
gid: string
resource_type: string
name: string
}
due_on?: string
created_at: string
modified_at: string
}>
next_page?: {
offset: string
path: string
uri: string
}
}
}
interface AsanaTask {
gid: string
resource_type: string
resource_subtype: string
name: string
notes?: string
completed: boolean
assignee?: {
gid: string
name: string
}
created_by?: {
gid: string
resource_type: string
name: string
}
due_on?: string
created_at: string
modified_at: string
}
interface AsanaProject {
gid: string
name: string
resource_type: string
}
export interface AsanaAddCommentParams {
accessToken: string
taskGid: string
text: string
}
export interface AsanaAddCommentResponse extends ToolResponse {
output: {
ts: string
gid: string
text: string
created_at: string
created_by: {
gid: string
name: string
}
}
}
export interface AsanaCreateProjectParams {
accessToken: string
workspace: string
name: string
notes?: string
}
export interface AsanaProjectRecordResponse extends ToolResponse {
output: {
ts: string
gid: string
name: string
notes: string
archived?: boolean
color?: string | null
created_at?: string
modified_at?: string
permalink_url?: string
}
}
export interface AsanaGetProjectParams {
accessToken: string
projectGid: string
}
export interface AsanaListWorkspacesParams {
accessToken: string
}
export interface AsanaListWorkspacesResponse extends ToolResponse {
output: {
ts: string
workspaces: Array<{
gid: string
name: string
resource_type?: string
}>
}
}
export interface AsanaCreateSubtaskParams {
accessToken: string
taskGid: string
name: string
notes?: string
assignee?: string
due_on?: string
}
export interface AsanaDeleteTaskParams {
accessToken: string
taskGid: string
}
export interface AsanaDeleteTaskResponse extends ToolResponse {
output: {
ts: string
gid: string
deleted: true
}
}
export interface AsanaAddFollowersParams {
accessToken: string
taskGid: string
followers: string[]
}
export interface AsanaAddFollowersResponse extends ToolResponse {
output: {
ts: string
gid: string
name: string
followers: Array<{
gid: string
name: string
}>
}
}
export interface AsanaCreateSectionParams {
accessToken: string
projectGid: string
name: string
}
export interface AsanaSectionResponse extends ToolResponse {
output: {
ts: string
gid: string
name: string
created_at?: string
}
}
export interface AsanaListSectionsParams {
accessToken: string
projectGid: string
}
export interface AsanaListSectionsResponse extends ToolResponse {
output: {
ts: string
sections: Array<{
gid: string
name: string
resource_type?: string
}>
}
}
export type AsanaResponse =
| AsanaGetTaskResponse
| AsanaCreateTaskResponse
| AsanaUpdateTaskResponse
| AsanaGetProjectsResponse
| AsanaSearchTasksResponse
| AsanaAddCommentResponse
| AsanaProjectRecordResponse
| AsanaListWorkspacesResponse
| AsanaDeleteTaskResponse
| AsanaAddFollowersResponse
| AsanaSectionResponse
| AsanaListSectionsResponse
+112
View File
@@ -0,0 +1,112 @@
import type { AsanaUpdateTaskParams, AsanaUpdateTaskResponse } from '@/tools/asana/types'
import type { ToolConfig } from '@/tools/types'
export const asanaUpdateTaskTool: ToolConfig<AsanaUpdateTaskParams, AsanaUpdateTaskResponse> = {
id: 'asana_update_task',
name: 'Asana Update Task',
description: 'Update an existing task in Asana',
version: '1.0.0',
oauth: {
required: true,
provider: 'asana',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'OAuth access token for Asana',
},
taskGid: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Asana task GID (numeric string) of the task to update',
},
name: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Updated name for the task',
},
notes: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Updated notes or description for the task',
},
assignee: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Updated assignee user GID',
},
completed: {
type: 'boolean',
required: false,
visibility: 'user-or-llm',
description: 'Mark task as completed or not completed',
},
due_on: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Updated due date in YYYY-MM-DD format',
},
},
request: {
url: '/api/tools/asana/update-task',
method: 'PUT',
headers: () => ({
'Content-Type': 'application/json',
}),
body: (params) => ({
accessToken: params.accessToken,
taskGid: params.taskGid,
name: params.name,
notes: params.notes,
assignee: params.assignee,
completed: params.completed,
due_on: params.due_on,
}),
},
transformResponse: async (response: Response) => {
const responseText = await response.text()
if (!responseText) {
return {
success: true,
output: {
ts: new Date().toISOString(),
gid: 'unknown',
name: 'Task updated successfully',
notes: '',
completed: false,
modified_at: new Date().toISOString(),
},
}
}
const data = JSON.parse(responseText)
const { success, error, ...output } = data
return {
success: success ?? true,
output,
error,
}
},
outputs: {
success: { type: 'boolean', description: 'Operation success status' },
ts: { type: 'string', description: 'Timestamp of the response' },
gid: { type: 'string', description: 'Task globally unique identifier' },
name: { type: 'string', description: 'Task name' },
notes: { type: 'string', description: 'Task notes or description' },
completed: { type: 'boolean', description: 'Whether the task is completed' },
modified_at: { type: 'string', description: 'Task last modified timestamp' },
},
}