$ cat node-template.py

L

Lark Create Task

// Creates a new task in Lark Suite. Supports title, description, due/start dates, member assignment, and tasklist placement.

Process
Integration
template.py
1import os2import sys3import json4import traceback56try:7    import requests8except ImportError:9    import subprocess10    subprocess.check_call([sys.executable, "-m", "pip", "install", "requests"])11    import requests1213LARK_BASE_URL = "https://open.larksuite.com/open-apis"141516def get_lark_token():17    # Prefer user token (OAuth — sees user's resources)18    user_token = os.getenv("LARK_USER_TOKEN")19    if user_token:20        return user_token2122    # Fallback to tenant token (app-level — limited visibility)23    app_id = os.getenv("LARK_APP_ID")24    app_secret = os.getenv("LARK_APP_SECRET")25    if not app_id or not app_secret:26        raise ValueError(27            "Lark is not connected. Add LARK_APP_ID and LARK_APP_SECRET as workspace secrets, "28            "then connect via workspace settings to authorize user access."29        )30    resp = requests.post(31        f"{LARK_BASE_URL}/auth/v3/tenant_access_token/internal",32        json={"app_id": app_id, "app_secret": app_secret},33    )34    resp.raise_for_status()35    data = resp.json()36    if data.get("code") != 0:37        raise ValueError(f"Lark auth failed: {data.get('msg')}")38    return data["tenant_access_token"]394041def lark_request(method, path, **kwargs):42    token = get_lark_token()43    headers = {44        "Authorization": f"Bearer {token}",45        "Content-Type": "application/json; charset=utf-8",46    }47    resp = requests.request(48        method, f"{LARK_BASE_URL}{path}", headers=headers, **kwargs49    )50    resp.raise_for_status()51    data = resp.json()52    if data.get("code") != 0:53        raise ValueError(f"Lark API error ({data['code']}): {data.get('msg')}")54    return data555657def parse_members(raw):58    """Parse members from JSON array or comma-separated string."""59    if not raw or not raw.strip():60        return None61    raw = raw.strip()62    # Try JSON array first63    try:64        parsed = json.loads(raw)65        if isinstance(parsed, list):66            members = []67            for item in parsed:68                if isinstance(item, str):69                    members.append({"id": item.strip(), "type": "user", "role": "assignee"})70                elif isinstance(item, dict) and "id" in item:71                    members.append(item)72            return members if members else None73    except (json.JSONDecodeError, TypeError):74        pass75    # Fallback: comma-separated open_ids76    ids = [s.strip() for s in raw.split(",") if s.strip()]77    if ids:78        return [{"id": uid, "type": "user", "role": "assignee"} for uid in ids]79    return None808182def main():83    try:84        inputs = json.loads(sys.stdin.read()).get("inputs", {})8586        summary = inputs.get("summary", "").strip()87        if not summary:88            raise ValueError("summary is required")8990        body = {"summary": summary}9192        description = inputs.get("description", "").strip()93        if description:94            body["description"] = description9596        due = inputs.get("due", "").strip()97        if due:98            body["due"] = {"timestamp": due, "is_all_day": False}99100        start = inputs.get("start", "").strip()101        if start:102            body["start"] = {"timestamp": start, "is_all_day": False}103104        members = parse_members(inputs.get("members"))105        if members:106            body["members"] = members107108        tasklist_guid = inputs.get("tasklistGuid", "").strip()109        if tasklist_guid:110            body["tasklists"] = [{"tasklist_guid": tasklist_guid}]111112        result = lark_request("POST", "/task/v2/tasks", json=body)113114        task = result.get("data", {}).get("task", {})115116        output = {117            "task": task,118            "taskGuid": task.get("guid", ""),119            "success": True,120        }121        print(json.dumps(output, indent=2, ensure_ascii=False))122123    except Exception as e:124        error_output = {125            "error": str(e),126            "errorType": type(e).__name__,127            "traceback": traceback.format_exc(),128        }129        print(json.dumps(error_output), file=sys.stderr)130        sys.exit(1)131132133if __name__ == "__main__":134    main()

$ git log --oneline

v1.0.1
HEAD
2026-05-07
v1.0.02026-04-09