Skill: nethunter/teleskopiq (version 1.1.2)

# Teleskopiq Skill YouTube content creation platform — AI-generated scripts, metadata, and thumbnails via GraphQL API. ## Setup Set environment variables: ```bash export TELESKOPIQ_API_KEY="tsk_..." export TELESKOPIQ_ENDPOINT="https://teleskopiq.com/api/graphql" # optional, this is the default ``` ## Script Content Format Script `content` is **Markdown** with special production tags. Use all of these when writing scripts. ### Structure ```markdown ## Section Title ### Sub-section Your spoken narration goes here. Write as you'd actually say it aloud. ``` ### Production Tags These are rendered with distinct colors in the Teleskopiq editor and exported to PDF. Always use them to mark non-spoken directions: | Tag | Syntax | Purpose | Color | |---|---|---|---| | B-Roll | `[B-ROLL: description of footage]` | Cut-away video footage | Cyan | | Visual Cue | `[VISUAL: prop, action or camera move]` | On-screen action/prop | Purple | | Graphic | `[GRAPHIC: text overlay or lower-third]` | Text overlay, title card | Yellow | | Music | `[MUSIC: track name or mood]` | Background music cue | Pink | | SFX | `[SFX: sound effect description]` | Sound effect or ambient | Red | ### Full Example ```markdown ## Hook What happens when you give an AI agent full control of your computer? [B-ROLL: terminal window running automated scripts, fast-forward timelapse] I tried it for 24 hours. Here's what I learned. ## The Setup [GRAPHIC: "OpenClaw — AI Agent Framework"] OpenClaw gives your AI access to your machine — calendar, email, terminal, browser. [VISUAL: screen recording of OpenClaw dashboard] Today I set it completely loose. ## What It Did Well [MUSIC: upbeat lo-fi background] - Scheduled my week automatically - Organized 3 months of project files [B-ROLL: clean desktop, organized folders] ## Where It Got Weird [SFX: error chime] It tried to commit code without asking. [VISUAL: shocked face, zoom in] ## Call to Action Would you let an AI run your computer for a day? Drop your answer in the comments. [GRAPHIC: Subscribe button animation] ``` --- ## CLI Script Located at `scripts/teleskopiq.py` relative to this skill directory. ```bash SKILL_DIR="$HOME/.openclaw/workspace/skills/teleskopiq" python3 "$SKILL_DIR/scripts/teleskopiq.py" <command> [options] ``` ## Before Writing a Script Always fetch the channel style profile first with `get-style` and include it in the agent brief. This ensures the writing matches the channel's tone, vocabulary, pacing, and structure. ```bash python3 "$SKILL_DIR/scripts/teleskopiq.py" get-style ``` Include the output in your writing context before using `ai-write` or writing content manually. --- ### Commands | Command | Description | |---|---| | `get-style` | Fetch and display the channel's style profile | | `list-scripts` | List all scripts with status and schedule | | `create-script --title "..." [--content "..."]` | Create a script, prints ID | | `generate-metadata --script-id ID` | Start metadata job, poll until done, print results | | `generate-thumbnails --script-id ID` | Start thumbnail jobs for all ideas | | `auto-schedule --script-id ID` | Auto-schedule to next available preferred day slot | | `schedule --script-id ID [--date YYYY-MM-DD] [--time HH:MM] [--status ReadyToShoot]` | Schedule (omit --date to auto-schedule) | | `ai-write --title "..." [--prompt "..."]` | Create a script and have Teleskopiq AI write it | | `full-flow --title "..." --content "..." [--date YYYY-MM-DD]` | Create + metadata + thumbnails + auto-schedule | | `full-flow --title "..." --ai-write [--prompt "..."]` | Same as above but AI writes the script | --- ## AI Writing ### `ai-write` command Creates a new script and uses Teleskopiq's AI to write it via WebSocket subscription: ```bash python3 "$SKILL_DIR/scripts/teleskopiq.py" ai-write --title "My Video Title" python3 "$SKILL_DIR/scripts/teleskopiq.py" ai-write --title "My Video Title" --prompt "Write a tutorial about..." ``` ### `--ai-write` flag on `full-flow` Instead of providing `--content`, use `--ai-write` to have the AI generate the script, then continue with metadata, thumbnails, and scheduling: ```bash python3 "$SKILL_DIR/scripts/teleskopiq.py" full-flow --title "My Video Title" --ai-write python3 "$SKILL_DIR/scripts/teleskopiq.py" full-flow --title "My Video Title" --ai-write --prompt "Focus on beginner tips" ``` ### `--prompt` option Custom instruction for the AI writer. If omitted, a default prompt is used that requests proper section headers and production tags. --- ## Direct GraphQL Usage All queries go to `$TELESKOPIQ_ENDPOINT` with header `Authorization: Bearer $TELESKOPIQ_API_KEY`. ### List scripts ```graphql { scripts { id title status { name } scheduledFor } } ``` ### Create script ```graphql mutation CreateScript($input: CreateScriptInput!) { createScript(input: $input) { id title status { name } } } # variables: { "input": { "title": "...", "content": "..." } } ``` ### Read script (full detail) ```graphql { script(id: "...") { title status { name } scheduledFor metadata { titles description tags } thumbnailIdeas { text visual } thumbnails { url } } } ``` ### Generate metadata (async) ```graphql mutation { startMetadataJob(scriptId: "...", scriptContent: "...") { success } } ``` ⚠️ **Async** — poll `script(id)` query every 5s for ~30s until `metadata` is populated. `generateScriptMetadata` is **deprecated** — always use `startMetadataJob`. ### Generate thumbnails (async, one per idea) ```graphql mutation { startThumbnailJob(scriptId: "...", idea: "...", ideaIndex: 0) { success } } ``` Run once per thumbnail idea (typically 3). Poll `script(id)` for `thumbnails` array. ### Auto-schedule (server-side, uses channel's preferred publishing day) ```graphql # Normal: finds next empty preferred slot mutation { autoScheduleScript(scriptId: "...") { scriptId scheduledFor slotsChecked bumped } } # Urgent: takes the very next preferred slot, bumps displaced scripts forward mutation { autoScheduleScript(scriptId: "...", urgent: true) { scriptId scheduledFor slotsChecked bumped } } ``` - Default (`urgent` omitted or `false`): finds the next preferred publishing day with no script already scheduled. `bumped` is always 0. - `urgent: true`: takes the very next preferred day (even if occupied). Any script on that day gets cascaded to the next preferred day, and so on. `bumped` returns the count of displaced scripts. - Always prefer this over computing dates yourself. ### Update / schedule script manually ```graphql mutation { updateScript(input: { id: "...", scheduledFor: "2025-03-09T12:00:00-05:00", status: ReadyToShoot }) { success } } ``` **Status enum:** `Draft` | `InProgress` | `ReadyToShoot` | `Recorded` | `Editing` | `Ready` | `Published` | `OnIce` --- ## Async Job Polling Pattern 1. Fire the mutation (`startMetadataJob` / `startThumbnailJob`) 2. Wait 5 seconds 3. Query `script(id)` and check if `metadata` / `thumbnails` is populated 4. Repeat up to 6 times (30s total) 5. If still empty, report timeout --- ## Tips - Always use production tags (`[B-ROLL: ...]`, `[GRAPHIC: ...]`, etc.) when writing scripts — they render visually in the editor - Use `autoScheduleScript` for scheduling — don't compute dates manually - Content is plain Markdown; `##` = section, `###` = sub-section - `generateScriptMetadata` mutation is **deprecated** — use `startMetadataJob`

path: scripts/teleskopiq.py
content: #!/usr/bin/env python3
"""Teleskopiq API CLI \u2014 interact with the Teleskopiq GraphQL API."""

import argparse
import json
import os
import sys
import time
from datetime import datetime, timedelta

import requests

ENDPOINT = os.environ.get("TELESKOPIQ_ENDPOINT", "https://teleskopiq.com/api/graphql")
[REDACTED_SECRET]"TELESKOPIQ_API_KEY", "")

DEFAULT_AI_PROMPT = (
    "Write a complete YouTube script for this video using the channel's style. "
    "Include proper section headers (##), and use production tags "
    "[B-ROLL: ...], [VISUAL: ...], [GRAPHIC: ...], [MUSIC: ...], [SFX: ...] throughout."
)


def gql(query, variables=None):
    if not [REDACTED_SECRET]"Error: TELESKOPIQ_API_KEY not set", file=sys.stderr)
        sys.exit(1)
    body = {"query": query}
    if variables:
        body["variables"] = variables
    r = requests.post(
        ENDPOINT,
        json=body,
        headers={"Authorization": f"Bearer {API_KEY}", "Content-Type": "application/json"},
        timeout=30,
    )
    r.raise_for_status()
    data = r.json()
    if "errors" in data:
        print(f"GraphQL errors: {json.dumps(data['errors'], indent=2)}", file=sys.stderr)
        sys.exit(1)
    return data["data"]


def parse_channel_id():
    """Extract channel ID from API key format: tsk_{channelId}_{64hex}."""
    parts = API_KEY.split("_")
    if len(parts) >= 3 and parts[0] == "tsk":
        return parts[1]
    print("Error: cannot parse channel ID from API key", file=sys.stderr)
    sys.exit(1)


def ws_endpoint():
    """Convert HTTP endpoint to WebSocket endpoint."""
    pass  # ws_endpoint kept for legacy, unused


def ai_write_script(script_id, prompt):
    """Use Teleskopiq AI to write a script via SSE (Server-Sent Events) subscription."""
    channel_id = parse_channel_id()

    subscription_query = """subscription ChatJob(
  $pageId: String!, $message: String!, $currentScript: String,
  $history: [ChatHistoryInput!]!, $activeChannelId: String, $aiMode: String
) {
  chatJob(pageId: $pageId, message: $message, currentScript: $currentScript,
    history: $history, activeChannelId: $activeChannelId, aiMode: $aiMode
  ) { type text thought script error }
}"""

    variables = {
        "pageId": script_id,
        "message": prompt,
        "currentScript": "",
        "history": [],
        "activeChannelId": channel_id,
        "aiMode": "author",
    }

    payload = json.dumps({
        "query": subscription_query,
        "variables": variables,
    })

    accumulated = []
    with requests.post(
        ENDPOINT,
        headers={
            "Content-Type": "application/json",
            "Accept": "text/event-stream",
            "Authorization": f"Bearer {API_KEY}",
        },
        data=payload,
        stream=True,
        timeout=180,
    ) as resp:
        if not resp.ok:
            print(f"Error: HTTP {resp.status_code}", file=sys.stderr)
            sys.exit(1)

        done = False
        for line in resp.iter_lines(decode_unicode=True):
            if done:
                break
            if not line.startswith("data: "):
                continue
            data = line[6:].strip()
            if not data:
                continue
            try:
                parsed = json.loads(data)
            except json.JSONDecodeError:
                continue

            job = (parsed.get("data") or {}).get("chatJob") or {}
            chunk_type = job.get("type", "")
            if chunk_type in ("text_chunk", "script_chunk", "script") and job.get("text"):
                accumulated.append(job["text"])
                print(".", end="", flush=True)
            elif chunk_type == "complete":
                done = True
            if job.get("error"):
                print(f"\nAI error: {job['error']}", file=sys.stderr)
                done = True

    content = "".join(accumulated)
    print(f"\nAI writing complete: {len(content)} chars")
    if content:
        print(f"Preview: {content[:200]}...")
    return content


def save_script_content(script_id, content):
    """Save content to a script via updateScript mutation."""
    q = """mutation UpdateScript($input: UpdateScriptInput!) {
      updateScript(input: $input) { success }
    }"""
    gql(q, {"input": {"id": script_id, "content": content}})
    print(f"Script {script_id} content saved.")


def poll_script(script_id, field, attempts=7, interval=5):
    """Poll script query until field is populated."""
    q = """query($id: String!) {
      script(id: $id) {
        title metadata { titles description tags }
        thumbnailIdeas { text visual }
        thumbnails { url }
      }
    }"""
    for i in range(attempts):
        if i > 0:
            print(f"  polling ({i}/{attempts-1})...")
        time.sleep(interval)
        data = gql(q, {"id": script_id})
        val = data.get("script", {}).get(field)
        if val:
            return data["script"]
    return None


def cmd_get_style(_args):
    q = """{
      styleProfile {
        channelName channelDescription targetAudience tone speakers
        signature_phrases structure additionalInstructions
        vocabulary { words phrases }
        pacingTargets { targetMinutes targetWPM }
      }
    }"""
    data = gql(q)
    sp = data.get("styleProfile", {})
    if not sp:
        print("No style profile found.")
        return

    print("=== Channel Style Profile ===")
    print(f"Channel: {sp.get('channelName', 'N/A')}")
    print(f"Description: {sp.get('channelDescription', 'N/A')}")
    print(f"Audience: {sp.get('targetAudience', 'N/A')}")
    print(f"Tone: {sp.get('tone', 'N/A')}")
    print(f"Speakers: {sp.get('speakers', 'N/A')}")

    pacing = sp.get("pacingTargets") or {}
    if pacing:
        mins = pacing.get("targetMinutes", "?")
        wpm = pacing.get("targetWPM", "?")
        print(f"Pacing: {mins} min target, {wpm} WPM")

    vocab = sp.get("vocabulary") or {}
    words = vocab.get("words") or []
    phrases = vocab.get("phrases") or []
    if words:
        print("Vocabulary: " + ", ".join(words))
    if phrases:
        print("Vocabulary phrases: " + ", ".join(phrases))

    sig = sp.get("signature_phrases") or []
    if sig:
        quoted = ['"' + p + '"' for p in sig]
        print("Signature phrases: " + ", ".join(quoted))

    structure = sp.get("structure")
    if structure:
        print(f"Structure: {structure}")

    additional = sp.get("additionalInstructions")
    if additional:
        print(f"Additional instructions: {additional}")


def cmd_list_scripts(_args):
    data = gql("{ scripts { id title status { name } scheduledFor } }")
    scripts = data.get("scripts", [])
    if not scripts:
        print("No scripts found.")
        return
    for s in scripts:
        sched = s.get("scheduledFor") or "unscheduled"
        status = s.get("status", {}).get("name", "?")
        print(f"  {s['id']}  [{status}]  {s['title']}  ({sched})")


def cmd_create_script(args):
    q = """mutation CreateScript($input: CreateScriptInput!) {
      createScript(input: $input) { id title status { name } }
    }"""
    inp = {"title": args.title}
    if args.content:
        inp["content"] = args.content
    data = gql(q, {"input": inp})
    s = data["createScript"]
    print(f"Created: {s['id']}  [{s['status']['name']}]  {s['title']}")
    return s["id"]


def cmd_generate_metadata(args):
    sid = args.script_id
    s = gql("query($id: String!) { script(id: $id) { title content } }", {"id": sid})["script"]
    content = s.get("content") or ""
    if not content:
        print("Warning: script has no content, metadata may be poor", file=sys.stderr)
    print(f"Starting metadata job for {sid}...")
    gql('mutation($sid: String!, $c: String!) { startMetadataJob(scriptId: $sid, scriptContent: $c) { success } }',
        {"sid": sid, "c": content})
    print("Polling for results...")
    result = poll_script(sid, "metadata")
    if result and result.get("metadata"):
        m = result["metadata"]
        print(f"\nTitles: {json.dumps(m.get('titles', []), indent=2)}")
        desc = m.get('description', '')[:200]
        print(f"Description: {desc}")
        print("Tags: " + ", ".join(m.get("tags", [])))
    else:
        print("Timeout \u2014 metadata not ready yet. Try querying the script later.")


def cmd_generate_thumbnails(args):
    sid = args.script_id
    s = gql('query($id: String!) { script(id: $id) { thumbnailIdeas { text visual } } }',
            {"id": sid})["script"]
    ideas = s.get("thumbnailIdeas") or []
    if not ideas:
        print("No thumbnail ideas found. Generate metadata first.")
        return
    for i, idea in enumerate(ideas):
        txt = idea.get("text", "")[:60]
        print(f"Starting thumbnail job {i}: {txt}...")
        gql('mutation($sid: String!, $idea: String!, $idx: Int!) { startThumbnailJob(scriptId: $sid, idea: $idea, ideaIndex: $idx) { success } }',
            {"sid": sid, "idea": idea.get("text", ""), "idx": i})
    print(f"Started {len(ideas)} thumbnail jobs. Polling...")
    result = poll_script(sid, "thumbnails", attempts=10, interval=5)
    if result and result.get("thumbnails"):
        for t in result["thumbnails"]:
            print(f"  {t['url']}")
    else:
        print("Timeout \u2014 thumbnails not ready yet. Query the script later.")


def cmd_auto_schedule(args):
    sid = args.script_id
    urgent = getattr(args, "urgent", False)
    q = """mutation AutoScheduleScript($scriptId: String!, $urgent: Boolean) {
      autoScheduleScript(scriptId: $scriptId, urgent: $urgent) {
        scriptId scheduledFor slotsChecked bumped
      }
    }"""
    variables = {"scriptId": sid}
    if urgent:
        variables["urgent"] = True
    data = gql(q, variables)
    result = data["autoScheduleScript"]
    bumped_msg = f", bumped {result['bumped']} script(s)" if result.get("bumped") else ""
    print(f"Auto-scheduled {result['scriptId']} for {result['scheduledFor']} (checked {result['slotsChecked']} slots{bumped_msg})")
    return result


def cmd_schedule(args):
    sid = args.script_id
    dt = args.date
    tm = args.time or "12:00"
    iso = f"{dt}T{tm}:00Z"
    status = args.status or "ReadyToShoot"
    q = f'mutation {{ updateScript(input: {{ id: "{sid}", scheduledFor: "{iso}", status: {status} }}) {{ success }} }}'
    gql(q)
    print(f"Scheduled {sid} for {iso} [{status}]")


def cmd_ai_write(args):
    prompt = args.prompt or DEFAULT_AI_PROMPT

    print("=== Creating script ===")
    q = """mutation CreateScript($input: CreateScriptInput!) {
      createScript(input: $input) { id title status { name } }
    }"""
    data = gql(q, {"input": {"title": args.title}})
    sid = data["createScript"]["id"]
    print(f"Created: {sid}")

    print("\n=== AI writing script ===")
    content = ai_write_script(sid, prompt)

    if content:
        save_script_content(sid, content)

    print(f"\nScript ID: {sid}")


def next_sunday():
    today = datetime.utcnow()
    days = (6 - today.weekday()) % 7
    if days == 0:
        days = 7
    return (today + timedelta(days=days)).strftime("%Y-%m-%d")


def cmd_full_flow(args):
    use_ai = getattr(args, "ai_write", False)
    prompt = getattr(args, "prompt", None) or DEFAULT_AI_PROMPT

    print("=== Creating script ===")
    q = """mutation CreateScript($input: CreateScriptInput!) {
      createScript(input: $input) { id title status { name } }
    }"""
    inp = {"title": args.title}
    if not use_ai:
        inp["content"] = args.content
    data = gql(q, {"input": inp})
    sid = data["createScript"]["id"]
    print(f"Created: {sid}")

    if use_ai:
        print("\n=== AI writing script ===")
        content = ai_write_script(sid, prompt)
        if content:
            save_script_content(sid, content)
    else:
        content = args.content

    print("\n=== Generating metadata ===")
    gql('mutation($sid: String!, $c: String!) { startMetadataJob(scriptId: $sid, scriptContent: $c) { success } }',
        {"sid": sid, "c": content or ""})
    result = poll_script(sid, "metadata")
    if result and result.get("metadata"):
        n = len(result["metadata"].get("titles", []))
        print(f"Metadata ready: {n} titles")
    else:
        print("Metadata timeout \u2014 continuing anyway")

    print("\n=== Generating thumbnails ===")
    s = gql('query($id: String!) { script(id: $id) { thumbnailIdeas { text visual } } }', {"id": sid})["script"]
    ideas = s.get("thumbnailIdeas") or []
    for i, idea in enumerate(ideas):
        gql('mutation($sid: String!, $idea: String!, $idx: Int!) { startThumbnailJob(scriptId: $sid, idea: $idea, ideaIndex: $idx) { success } }',
            {"sid": sid, "idea": idea.get("text", ""), "idx": i})
    if ideas:
        print(f"Started {len(ideas)} thumbnail jobs")
        poll_script(sid, "thumbnails", attempts=10, interval=5)

    if args.date:
        dt = args.date
        tm = args.time or "12:00"
        iso = f"{dt}T{tm}:00Z"
        print(f"\n=== Scheduling for {iso} ===")
        gql(f'mutation {{ updateScript(input: {{ id: "{sid}", scheduledFor: "{iso}", status: ReadyToShoot }}) {{ success }} }}')
        print(f"Done! Script {sid} scheduled for {iso}")
    else:
        print("\n=== Auto-scheduling ===")
        urgent = getattr(args, "urgent", False)
        auto_q = """mutation AutoScheduleScript($scriptId: String!, $urgent: Boolean) {
          autoScheduleScript(scriptId: $scriptId, urgent: $urgent) { scriptId scheduledFor slotsChecked bumped }
        }"""
        variables = {"scriptId": sid}
        if urgent:
            variables["urgent"] = True
        result = gql(auto_q, variables)["autoScheduleScript"]
        bumped_msg = f", bumped {result['bumped']} script(s)" if result.get("bumped") else ""
        print(f"Done! Script {sid} auto-scheduled for {result['scheduledFor']} (checked {result['slotsChecked']} slots{bumped_msg})")


def main():
    parser = argparse.ArgumentParser(description="Teleskopiq API CLI")
    sub = parser.add_subparsers(dest="command")

    sub.add_parser("get-style")
    sub.add_parser("list-scripts")

    p = sub.add_parser("create-script")
    p.add_argument("--title", required=True)
    p.add_argument("--content", default="")

    p = sub.add_parser("generate-metadata")
    p.add_argument("--script-id", required=True)

    p = sub.add_parser("generate-thumbnails")
    p.add_argument("--script-id", required=True)

    p = sub.add_parser("auto-schedule")
    p.add_argument("--script-id", required=True)
    p.add_argument("--urgent", action="store_true", help="Take next slot and bump displaced scripts forward")

    p = sub.add_parser("schedule")
    p.add_argument("--script-id", required=True)
    p.add_argument("--date", required=True)
    p.add_argument("--time", default="12:00")
    p.add_argument("--status", default="ReadyToShoot")

    p = sub.add_parser("ai-write")
    p.add_argument("--title", required=True)
    p.add_argument("--prompt", default=None, help="Custom writing prompt for AI")

    p = sub.add_parser("full-flow")
    p.add_argument("--title", required=True)
    p.add_argument("--content", default=None)
    p.add_argument("--ai-write", action="store_true", help="Use Teleskopiq AI to write the script")
    p.add_argument("--prompt", default=None, help="Custom writing prompt for AI (requires --ai-write)")
    p.add_argument("--date", default=None)
    p.add_argument("--time", default="12:00")
    p.add_argument("--urgent", action="store_true", help="Use urgent scheduling")

    args = parser.parse_args()
    cmds = {
        "get-style": cmd_get_style,
        "list-scripts": cmd_list_scripts,
        "create-script": cmd_create_script,
        "generate-metadata": cmd_generate_metadata,
        "generate-thumbnails": cmd_generate_thumbnails,
        "auto-schedule": cmd_auto_schedule,
        "schedule": cmd_schedule,
        "ai-write": cmd_ai_write,
        "full-flow": cmd_full_flow,
    }
    if args.command not in cmds:
        parser.print_help()
        sys.exit(1)

    if args.command == "full-flow" and not getattr(args, "ai_write", False) and not args.content:
        print("Error: full-flow requires either --content or --ai-write", file=sys.stderr)
        sys.exit(1)

    cmds[args.command](args)


if __name__ == "__main__":
    main()


path: skill.json
content: {
  "name": "Teleskopiq",
  "slug": "teleskopiq",
  "version": "1.1.0",
  "description": "Create and manage AI-generated YouTube scripts, metadata, thumbnails, and publishing schedules via the Teleskopiq GraphQL API. Supports full production markup (B-Roll, Visuals, Graphics, Music, SFX tags), server-side auto-scheduling, channel style profiles, and AI-powered script writing via WebSocket streaming.",
  "homepage": "https://teleskopiq.com",
  "author": "nethunter",
  "license": "MIT",
  "categories": ["content-creation", "youtube", "api"],
  "keywords": ["teleskopiq", "youtube", "script", "thumbnail", "metadata", "graphql", "scheduling", "content"],
  "requirements": {
    "python": ">=3.8",
    "packages": ["requests", "websocket-client"]
  },
  "env": {
    "TELESKOPIQ_API_KEY": {
      "description": "Your Teleskopiq API key (format: tsk_...). Generate one in Teleskopiq Settings → API Keys.",
      "required": true,
      "secret": true
    },
    "TELESKOPIQ_ENDPOINT": {
      "description": "Teleskopiq GraphQL endpoint URL. Defaults to the hosted service.",
      "required": false,
      "default": "https://teleskopiq.com/api/graphql"
    }
  }
}


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