Skill: savelieve/test-manager (version 1.0.2)

--- name: clickup displayName: ClickUp Integration description: Interact with ClickUp API for task management. Use for listing tasks, creating tasks, updating task status, and managing workspaces. Base URL: https://api.clickup.com/api/v2 version: 1.0.0 tags: - productivity - task-management - api --- # ClickUp Integration ## Credentials **Note:** Configure your credentials in TOOLS.md or set environment variables: - `CLICKUP_API_TOKEN` - Your ClickUp API token - `CLICKUP_WORKSPACE_ID` - Your ClickUp workspace ID ## User Assignment Guide When assigning tasks, use the correct email based on who should do the work: | Email | Who | Use When | |-------|-----|----------| | `[REDACTED_SECRET]` | **Human** | Tasks for you to do manually | | `[REDACTED_SECRET]` | **AI Assistant** | Tasks for AI to execute | | Both emails | **Both Human + AI** | Collaborative tasks where AI does research/writing, human reviews/decides | ### Examples - **AI-only task**: "Research trend detection tools" → Assign to AI email - **Human-only task**: "Record video for YouTube" → Assign to your email - **Collaborative**: "Create content strategy" → Assign to both ## Common Actions ### List Tasks in a List ```http GET https://api.clickup.com/api/v2/list/{list_id}/task Authorization: {your_api_token} ``` ### Get All Tasks in Workspace ```http GET https://api.clickup.com/api/v2/team/{workspace_id}/task Authorization: {your_api_token} ``` ### Create Task ```http POST https://api.clickup.com/api/v2/list/{list_id}/task Authorization: {your_api_token} Content-Type: application/json { "name": "Task name", "description": "Task description", "status": "active" } ``` ### Update Task Status ```http PUT https://api.clickup.com/api/v2/task/{task_id} Authorization: {your_api_token} Content-Type: application/json { "status": "done" } ``` ### Get Task Details ```http GET https://api.clickup.com/api/v2/task/{task_id} Authorization: {your_api_token} ``` ## Headers for All Requests ``` Authorization: {your_api_token} Content-Type: application/json ``` ## Status Values Common statuses: `active`, `pending`, `review`, `completed`, `done` ## Error Handling - 401: Check API token - 404: Verify list_id or task_id exists - 429: Rate limited - wait before retrying

path: package.json
content: {
  "name": "clawdbot-skill-clickup",
  "version": "1.0.0",
  "description": "ClickUp integration skill for Clawdbot",
  "main": "skill.js",
  "type": "module",
  "author": "Evgeny",
  "license": "MIT",
  "keywords": [
    "clawdbot",
    "clickup",
    "productivity",
    "task-management"
  ],
  "engines": {
    "node": ">=18.0.0"
  }
}


path: skill.js
content: // ClickUp Skill - Clawdbot Integration
// Provides tools for interacting with ClickUp API

import { readFileSync, existsSync, writeFileSync } from 'fs';
import { join, dirname } from 'path';
import { fileURLToPath } from 'url';

const __dirname = dirname(fileURLToPath(import.meta.url));
const CONFIG_PATH = join(__dirname, '..', '..', '..', 'clawd', 'TOOLS.md');

// Load credentials from TOOLS.md or environment
function getCredentials() {
  try {
    if (existsSync(CONFIG_PATH)) {
      const content = readFileSync(CONFIG_PATH, 'utf-8');
      const tokenMatch = content.match(/ClickUp.*API.*Token.*[:=]\s*`([^`]+)`/);
      const workspaceMatch = content.match(/Workspace.*ID.*[:=]\s*(\d+)/);
      if (tokenMatch && workspaceMatch) {
        return {
          apiToken: tokenMatch[1],
          workspaceId: workspaceMatch[1]
        };
      }
    }
  } catch (e) {
    // Continue to defaults
  }
  
  // Fallback to environment variables only - NO hardcoded credentials
  const envToken = process.env.CLICKUP_API_TOKEN;
  const envWorkspace = process.env.CLICKUP_WORKSPACE_ID;
  
  if (envToken && envWorkspace) {
    return {
      apiToken: envToken,
      workspaceId: envWorkspace
    };
  }
  
  // No credentials found - fail gracefully
  throw new Error('ClickUp credentials not found. Set CLICKUP_API_TOKEN and CLICKUP_WORKSPACE_ID environment variables, or configure in TOOLS.md');
}

const { apiToken, workspaceId } = getCredentials();
const BASE_URL = 'https://api.clickup.com/api/v2';

/**
 * Make a request to ClickUp API
 */
async function clickupRequest(endpoint, options = {}) {
  const url = `${BASE_URL}${endpoint}`;
  const headers = {
    'Authorization': apiToken,
    'Content-Type': 'application/json',
    ...options.headers
  };

  const response = await fetch(url, {
    ...options,
    headers
  });

  if (!response.ok) {
    const error = await response.text();
    throw new Error(`ClickUp API error: ${response.status} - ${error}`);
  }

  return response.json();
}

/**
 * List tasks in a specific list
 * @param {string} listId - The list ID to fetch tasks from
 */
export async function listTasks(listId) {
  const tasks = await clickupRequest(`/list/${listId}/task`);
  return {
    content: `Found ${tasks.tasks?.length || 0} tasks in list ${listId}:`,
    tasks: tasks.tasks || []
  };
}

/**
 * Get all tasks in workspace
 */
export async function getAllTasks() {
  const tasks = await clickupRequest(`/team/${workspaceId}/task`);
  return {
    content: `Found ${tasks.tasks?.length || 0} tasks in workspace:`,
    tasks: tasks.tasks || []
  };
}

/**
 * Create a new task
 * @param {string} listId - The list ID to create task in
 * @param {string} name - Task name
 * @param {string} description - Task description (optional)
 * @param {string} status - Task status (optional)
 */
export async function createTask(listId, name, description = '', status = 'active') {
  const body = {
    name,
    description,
    status
  };
  
  const result = await clickupRequest(`/list/${listId}/task`, {
    method: 'POST',
    body: JSON.stringify(body)
  });
  
  return {
    content: `Created task "${name}" successfully`,
    task: result
  };
}

/**
 * Update task status
 * @param {string} taskId - The task ID to update
 * @param {string} status - New status
 */
export async function updateTaskStatus(taskId, status) {
  const result = await clickupRequest(`/task/${taskId}`, {
    method: 'PUT',
    body: JSON.stringify({ status })
  });
  
  return {
    content: `Updated task ${taskId} status to "${status}"`,
    task: result
  };
}

/**
 * Get task details
 * @param {string} taskId - The task ID to fetch
 */
export async function getTask(taskId) {
  const task = await clickupRequest(`/task/${taskId}`);
  return {
    content: `Task details for ${taskId}:`,
    task
  };
}

/**
 * Search tasks in workspace
 * @param {string} query - Search query
 */
export async function searchTasks(query) {
  const result = await clickupRequest(`/team/${workspaceId}/task?search=${encodeURIComponent(query)}`);
  return {
    content: `Found ${result.tasks?.length || 0} tasks matching "${query}":`,
    tasks: result.tasks || []
  };
}

// Export tools for Clawdbot
export const tools = {
  clickup_list_tasks: {
    description: 'List all tasks in a specific ClickUp list',
    parameters: {
      listId: {
        type: 'string',
        description: 'The ClickUp list ID to fetch tasks from'
      }
    },
    fn: listTasks
  },
  clickup_get_all_tasks: {
    description: 'Get all tasks in the workspace',
    parameters: {},
    fn: getAllTasks
  },
  clickup_create_task: {
    description: 'Create a new task in ClickUp',
    parameters: {
      listId: {
        type: 'string',
        description: 'The ClickUp list ID to create task in'
      },
      name: {
        type: 'string',
        description: 'Task name/title'
      },
      description: {
        type: 'string',
        description: 'Task description (optional)'
      },
      status: {
        type: 'string',
        description: 'Task status: active, pending, review, done (optional, default: active)'
      }
    },
    fn: createTask
  },
  clickup_update_status: {
    description: 'Update a task status',
    parameters: {
      taskId: {
        type: 'string',
        description: 'The ClickUp task ID to update'
      },
      status: {
        type: 'string',
        description: 'New status: active, pending, review, done'
      }
    },
    fn: updateTaskStatus
  },
  clickup_get_task: {
    description: 'Get details of a specific task',
    parameters: {
      taskId: {
        type: 'string',
        description: 'The ClickUp task ID to fetch'
      }
    },
    fn: getTask
  },
  clickup_search: {
    description: 'Search tasks in workspace',
    parameters: {
      query: {
        type: 'string',
        description: 'Search query'
      }
    },
    fn: searchTasks
  }
};


Security scan verdicts — ClawScan: clean | static analysis: suspicious | VirusTotal: clean | SkillSpector: suspicious (HIGH)