{
  "name": "03 - Command Handler",
  "nodes": [
    {
      "parameters": {},
      "name": "Execute Workflow Trigger",
      "type": "n8n-nodes-base.executeWorkflowTrigger",
      "typeVersion": 1,
      "position": [
        250,
        300
      ]
    },
    {
      "parameters": {
        "jsCode": "// Parse command and arguments\nconst text = $input.first().json.text;\nconst parts = text.split(' ');\nconst command = parts[0].toLowerCase();\nconst args = parts.slice(1).join(' ');\n\n// Extract command name without /\nconst commandName = command.replace('/', '');\n\nreturn [{\n  json: {\n    command: commandName,\n    args: args,\n    fullText: text,\n    chatId: $input.first().json.chatId,\n    userId: $input.first().json.userId,\n    username: $input.first().json.username\n  }\n}];"
      },
      "name": "Parse Command",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        450,
        300
      ]
    },
    {
      "parameters": {
        "rules": {
          "rules": [
            {
              "value": "help",
              "output": 0
            },
            {
              "value": "status",
              "output": 1
            },
            {
              "value": "remember",
              "output": 2
            },
            {
              "value": "recall",
              "output": 3
            },
            {
              "value": "clear",
              "output": 4
            },
            {
              "value": "read",
              "output": 5
            },
            {
              "value": "list",
              "output": 6
            },
            {
              "value": "exec",
              "output": 7
            },
            {
              "value": "email",
              "output": 8
            },
            {
              "value": "system",
              "output": 9
            },
            {
              "value": "todo",
              "output": 10
            }
          ]
        }
      },
      "name": "Route Command",
      "type": "n8n-nodes-base.switch",
      "typeVersion": 2,
      "position": [
        650,
        300
      ]
    },
    {
      "parameters": {
        "chatId": "={{ $json.chatId }}",
        "text": "\ud83d\udc4b Hey there! Here are the things I can help you with:\\n\\n\ud83d\udcac **Chat** - Just message me naturally\\n\ud83d\udcca **/status** - Check your Mac's system status\\n\ud83e\udde0 **/remember [fact]** - I'll remember something for you\\n\ud83d\udcad **/recall** - Show what I remember\\n\ud83d\uddd1\ufe0f **/clear** - Clear conversation history\\n\ud83d\udcc1 **/read [filepath]** - Read a text file\\n\ud83d\udcc2 **/list [directory]** - List directory contents\\n\u26a1 **/exec [command]** - Run a safe command\\n\\n\u2705 **Todo Commands:**\\n`/todo` - List your active todos\\n`/todo add <task> [due:YYYY-MM-DD] [recur:daily|weekly|monthly]` - Add a todo\\n`/todo done <id>` - Mark a todo complete\\n`/todo delete <id>` - Delete a todo\\n\\n\ud83d\udce7 **Email Commands:**\\n`/email auth` - Connect your Gmail account\\n`/email check` - Check unread emails\\n`/email read [id]` - Read a specific email\\n`/email reply [id]` - AI-powered reply drafts\\n`/email send` - Compose a new email\\n`/email search [query]` - Search your emails\\n\\n\ud83d\udd27 **System Control (owner only):**\\n`/system status` - Check if bot is running\\n`/system restart` - Restart ronkbot\\n`/system stop` - Stop ronkbot\\n`/system wake` - Check power/sleep status\\n\\nJust chat naturally or use any command above! \ud83d\ude0a",
        "additionalFields": {
          "parse_mode": "Markdown"
        }
      },
      "name": "Help Response",
      "type": "n8n-nodes-base.telegram",
      "typeVersion": 1.1,
      "position": [
        850,
        100
      ],
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "command": "df -h",
        "cwd": "/Users/ronkuwonku"
      },
      "name": "Get Disk Usage",
      "type": "n8n-nodes-base.executeCommand",
      "typeVersion": 1,
      "position": [
        850,
        200
      ]
    },
    {
      "parameters": {
        "command": "vm_stat | head -5",
        "cwd": "/Users/ronkuwonku"
      },
      "name": "Get Memory",
      "type": "n8n-nodes-base.executeCommand",
      "typeVersion": 1,
      "position": [
        850,
        300
      ]
    },
    {
      "parameters": {
        "jsCode": "// Format status response\nconst diskOutput = $('Get Disk Usage').first().json.stdout || 'N/A';\nconst memOutput = $('Get Memory').first().json.stdout || 'N/A';\n\nconst message = `\ud83d\udcca **System Status**\\n\\n\ud83d\udcbe **Disk Usage:**\\n\\`\\`\\`\\n${diskOutput}\\`\\`\\`\\n\\n\ud83e\udde0 **Memory:**\\n\\`\\`\\`\\n${memOutput}\\`\\`\\`\\n\\n\u23f1\ufe0f Last updated: ${new Date().toLocaleString()}`;\n\nreturn [{\n  json: {\n    message: message,\n    chatId: $input.first().json.chatId\n  }\n}];"
      },
      "name": "Format Status",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1050,
        250
      ]
    },
    {
      "parameters": {
        "chatId": "={{ $json.chatId }}",
        "text": "={{ $json.message }}",
        "additionalFields": {
          "parse_mode": "Markdown"
        }
      },
      "name": "Send Status",
      "type": "n8n-nodes-base.telegram",
      "typeVersion": 1.1,
      "position": [
        1250,
        250
      ],
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "operation": "executeQuery",
        "query": "INSERT INTO memory (user_id, username, fact, timestamp) VALUES ($1, $2, $3, datetime('now'))",
        "additionalFields": {
          "parameters": [
            {
              "name": "user_id",
              "value": "={{ $json.userId }}"
            },
            {
              "name": "username",
              "value": "={{ $json.username }}"
            },
            {
              "name": "fact",
              "value": "={{ $json.args }}"
            }
          ]
        }
      },
      "name": "Save Memory",
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2.2,
      "position": [
        850,
        400
      ],
      "credentials": {
        "postgres": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "chatId": "={{ $json.chatId }}",
        "text": "\u2705 Got it! I'll remember that:\\\\n\\\\n\\\"{{ $json.args }}\\\"\\\\n\\\\n\ud83d\udca1 Use /recall to see everything I remember!",
        "additionalFields": {}
      },
      "name": "Confirm Remember",
      "type": "n8n-nodes-base.telegram",
      "typeVersion": 1.1,
      "position": [
        1050,
        400
      ],
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "operation": "executeQuery",
        "query": "SELECT fact FROM memory WHERE user_id = $1 ORDER BY timestamp DESC",
        "additionalFields": {
          "parameters": [
            {
              "name": "user_id",
              "value": "={{ $json.userId }}"
            }
          ]
        }
      },
      "name": "Get All Memory",
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2.2,
      "position": [
        850,
        500
      ],
      "credentials": {
        "postgres": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "// Format memory list\nconst items = $('Get All Memory').all();\n\nif (!items || items.length === 0) {\n  return [{\n    json: {\n      message: '\ud83e\udde0 I don\\'t remember anything yet!\\n\\nUse /remember to tell me things I should remember. \ud83d\ude0a',\n      chatId: $input.first().json.chatId\n    }\n  }];\n}\n\nlet message = '\ud83e\udde0 **Here\\'s what I remember about you:**\\n\\n';\nitems.forEach((item, index) => {\n  message += `${index + 1}. ${item.json.fact}\\n`;\n});\n\nmessage += '\\n\ud83d\udca1 Use /remember to add more!';\n\nreturn [{\n  json: {\n    message: message,\n    chatId: $input.first().json.chatId\n  }\n}];"
      },
      "name": "Format Memory List",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1050,
        500
      ]
    },
    {
      "parameters": {
        "chatId": "={{ $json.chatId }}",
        "text": "={{ $json.message }}",
        "additionalFields": {
          "parse_mode": "Markdown"
        }
      },
      "name": "Send Memory",
      "type": "n8n-nodes-base.telegram",
      "typeVersion": 1.1,
      "position": [
        1250,
        500
      ],
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "operation": "executeQuery",
        "query": "DELETE FROM conversations WHERE user_id = $1",
        "additionalFields": {
          "parameters": [
            {
              "name": "user_id",
              "value": "={{ $json.userId }}"
            }
          ]
        }
      },
      "name": "Clear History",
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2.2,
      "position": [
        850,
        600
      ],
      "credentials": {
        "postgres": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "chatId": "={{ $json.chatId }}",
        "text": "\ud83e\uddf9 **Conversation history cleared!**\\\\n\\\\nI'm starting fresh. What would you like to talk about? \ud83d\ude0a",
        "additionalFields": {
          "parse_mode": "Markdown"
        }
      },
      "name": "Confirm Clear",
      "type": "n8n-nodes-base.telegram",
      "typeVersion": 1.1,
      "position": [
        1050,
        600
      ],
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "// Parse email subcommand from args\n// Format: /email <subcommand> [args...]\n// e.g.  /email check\n//        /email read abc123\n//        /email reply abc123\n//        /email send\n//        /email search invoice\n//        /email auth\n\nconst args = $input.first().json.args || '';\nconst parts = args.trim().split(' ');\nconst subcommand = (parts[0] || 'check').toLowerCase();\nconst subArgs = parts.slice(1).join(' ');\n\nreturn [{\n  json: {\n    ...$input.first().json,\n    subcommand: subcommand,\n    subArgs: subArgs\n  }\n}];"
      },
      "name": "Parse Email Subcommand",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        850,
        750
      ]
    },
    {
      "parameters": {
        "rules": {
          "rules": [
            {
              "value": "auth",
              "output": 0
            },
            {
              "value": "check",
              "output": 1
            },
            {
              "value": "read",
              "output": 2
            },
            {
              "value": "reply",
              "output": 3
            },
            {
              "value": "send",
              "output": 4
            },
            {
              "value": "search",
              "output": 5
            }
          ]
        }
      },
      "name": "Route Email Subcommand",
      "type": "n8n-nodes-base.switch",
      "typeVersion": 2,
      "position": [
        1050,
        750
      ]
    },
    {
      "parameters": {
        "chatId": "={{ $json.chatId }}",
        "text": "\ud83d\udd10 **Connect Your Gmail Account**\\n\\nClick the link below to authorize ronkbot:\\n\\n`http://localhost:5678/gmail-auth`\\n\\n**Steps:**\\n1. Click the link above (open in browser)\\n2. Sign in with your Google account\\n3. Grant the requested permissions\\n4. You'll see a success message\\n\\nAfter connecting, use `/email check` to see your emails! \ud83d\udce7\\n\\n\u26a0\ufe0f Make sure you've set up Gmail credentials in your `.env` file first. See `docs/EMAIL_SETUP.md` for details.",
        "additionalFields": {
          "parse_mode": "Markdown"
        }
      },
      "name": "Email Auth Message",
      "type": "n8n-nodes-base.telegram",
      "typeVersion": 1.1,
      "position": [
        1300,
        550
      ],
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "workflowId": "05 - Email Reader",
        "workflowInputs": {
          "values": [
            {
              "name": "chatId",
              "stringValue": "={{ $json.chatId }}"
            },
            {
              "name": "userId",
              "stringValue": "={{ $json.userId }}"
            },
            {
              "name": "username",
              "stringValue": "={{ $json.username }}"
            },
            {
              "name": "mode",
              "stringValue": "check"
            },
            {
              "name": "limit",
              "stringValue": "10"
            },
            {
              "name": "label",
              "stringValue": "INBOX"
            },
            {
              "name": "searchQuery",
              "stringValue": "is:unread"
            }
          ]
        }
      },
      "name": "Check Emails",
      "type": "n8n-nodes-base.executeWorkflow",
      "typeVersion": 1.1,
      "position": [
        1300,
        650
      ]
    },
    {
      "parameters": {
        "workflowId": "05 - Email Reader",
        "workflowInputs": {
          "values": [
            {
              "name": "chatId",
              "stringValue": "={{ $json.chatId }}"
            },
            {
              "name": "userId",
              "stringValue": "={{ $json.userId }}"
            },
            {
              "name": "username",
              "stringValue": "={{ $json.username }}"
            },
            {
              "name": "mode",
              "stringValue": "read"
            },
            {
              "name": "emailId",
              "stringValue": "={{ $json.subArgs }}"
            }
          ]
        }
      },
      "name": "Read Email",
      "type": "n8n-nodes-base.executeWorkflow",
      "typeVersion": 1.1,
      "position": [
        1300,
        750
      ]
    },
    {
      "parameters": {
        "workflowId": "06 - Email Sender",
        "workflowInputs": {
          "values": [
            {
              "name": "chatId",
              "stringValue": "={{ $json.chatId }}"
            },
            {
              "name": "userId",
              "stringValue": "={{ $json.userId }}"
            },
            {
              "name": "username",
              "stringValue": "={{ $json.username }}"
            },
            {
              "name": "mode",
              "stringValue": "reply"
            },
            {
              "name": "emailId",
              "stringValue": "={{ $json.subArgs }}"
            }
          ]
        }
      },
      "name": "Reply Email",
      "type": "n8n-nodes-base.executeWorkflow",
      "typeVersion": 1.1,
      "position": [
        1300,
        850
      ]
    },
    {
      "parameters": {
        "workflowId": "06 - Email Sender",
        "workflowInputs": {
          "values": [
            {
              "name": "chatId",
              "stringValue": "={{ $json.chatId }}"
            },
            {
              "name": "userId",
              "stringValue": "={{ $json.userId }}"
            },
            {
              "name": "username",
              "stringValue": "={{ $json.username }}"
            },
            {
              "name": "mode",
              "stringValue": "compose"
            }
          ]
        }
      },
      "name": "Send Email",
      "type": "n8n-nodes-base.executeWorkflow",
      "typeVersion": 1.1,
      "position": [
        1300,
        950
      ]
    },
    {
      "parameters": {
        "workflowId": "05 - Email Reader",
        "workflowInputs": {
          "values": [
            {
              "name": "chatId",
              "stringValue": "={{ $json.chatId }}"
            },
            {
              "name": "userId",
              "stringValue": "={{ $json.userId }}"
            },
            {
              "name": "username",
              "stringValue": "={{ $json.username }}"
            },
            {
              "name": "mode",
              "stringValue": "search"
            },
            {
              "name": "limit",
              "stringValue": "10"
            },
            {
              "name": "searchQuery",
              "stringValue": "={{ $json.subArgs }}"
            }
          ]
        }
      },
      "name": "Search Emails",
      "type": "n8n-nodes-base.executeWorkflow",
      "typeVersion": 1.1,
      "position": [
        1300,
        1050
      ]
    },
    {
      "parameters": {
        "jsCode": "// Security: only the owner can run /system commands\nconst ownerUsername = $env.TELEGRAM_OWNER_USERNAME || '';\nconst callerUsername = $input.first().json.username || '';\n\nif (!ownerUsername || callerUsername.toLowerCase() !== ownerUsername.toLowerCase()) {\n  return [{\n    json: {\n      ...$input.first().json,\n      accessDenied: true,\n      message: '\u26d4 Access denied. System commands are owner-only.'\n    }\n  }];\n}\n\nconst args = $input.first().json.args || '';\nconst parts = args.trim().split(' ');\nconst subcommand = (parts[0] || 'status').toLowerCase();\nconst subArgs = parts.slice(1).join(' ');\n\nreturn [{\n  json: {\n    ...$input.first().json,\n    accessDenied: false,\n    subcommand: subcommand,\n    subArgs: subArgs\n  }\n}];"
      },
      "name": "System Owner Check",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        850,
        1200
      ]
    },
    {
      "parameters": {
        "chatId": "={{ $json.chatId }}",
        "text": "={{ $json.message }}",
        "additionalFields": {}
      },
      "name": "System Access Denied",
      "type": "n8n-nodes-base.telegram",
      "typeVersion": 1.1,
      "position": [
        1050,
        1100
      ],
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "rules": {
          "rules": [
            {
              "value": "access_denied",
              "output": 0
            },
            {
              "value": "status",
              "output": 1
            },
            {
              "value": "restart",
              "output": 2
            },
            {
              "value": "stop",
              "output": 3
            },
            {
              "value": "wake",
              "output": 4
            }
          ]
        },
        "dataType": "string",
        "value1": "={{ $json.accessDenied ? 'access_denied' : $json.subcommand }}"
      },
      "name": "Route System Subcommand",
      "type": "n8n-nodes-base.switch",
      "typeVersion": 2,
      "position": [
        1050,
        1200
      ]
    },
    {
      "parameters": {
        "command": "docker ps --filter name=ronkbot --format 'table {{.Names}}\\t{{.Status}}\\t{{.Ports}}' 2>&1"
      },
      "name": "Docker Status",
      "type": "n8n-nodes-base.executeCommand",
      "typeVersion": 1,
      "position": [
        1250,
        1150
      ]
    },
    {
      "parameters": {
        "jsCode": "const output = $input.first().json.stdout || 'No output';\nconst running = output.includes('Up');\nconst icon = running ? '\u2705' : '\u26a0\ufe0f';\nconst msg = `${icon} *ronkbot Container Status*\\n\\n\\`\\`\\`\\n${output.trim()}\\`\\`\\``;\nreturn [{ json: { message: msg, chatId: $('System Owner Check').first().json.chatId } }];"
      },
      "name": "Format Docker Status",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1450,
        1150
      ]
    },
    {
      "parameters": {
        "chatId": "={{ $json.chatId }}",
        "text": "={{ $json.message }}",
        "additionalFields": {
          "parse_mode": "Markdown"
        }
      },
      "name": "Send System Status",
      "type": "n8n-nodes-base.telegram",
      "typeVersion": 1.1,
      "position": [
        1650,
        1150
      ],
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "command": "docker restart ronkbot-n8n 2>&1 && echo 'RESTART_OK' || echo 'RESTART_FAILED'"
      },
      "name": "Docker Restart",
      "type": "n8n-nodes-base.executeCommand",
      "typeVersion": 1,
      "position": [
        1250,
        1250
      ]
    },
    {
      "parameters": {
        "chatId": "={{ $('System Owner Check').first().json.chatId }}",
        "text": "\ud83d\udd04 *Restarting ronkbot...*\\n\\nI'll be back in ~30 seconds! Use `/system status` to check.",
        "additionalFields": {
          "parse_mode": "Markdown"
        }
      },
      "name": "Send Restart Confirm",
      "type": "n8n-nodes-base.telegram",
      "typeVersion": 1.1,
      "position": [
        1450,
        1250
      ],
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "command": "docker stop ronkbot-n8n 2>&1 && echo 'STOP_OK' || echo 'STOP_FAILED'"
      },
      "name": "Docker Stop",
      "type": "n8n-nodes-base.executeCommand",
      "typeVersion": 1,
      "position": [
        1250,
        1350
      ]
    },
    {
      "parameters": {
        "chatId": "={{ $('System Owner Check').first().json.chatId }}",
        "text": "\ud83d\uded1 *ronkbot stopped.*\\n\\nTo restart from your iPhone, tap the *Start ronkbot* Shortcut or run:\\n`docker start ronkbot-n8n`",
        "additionalFields": {
          "parse_mode": "Markdown"
        }
      },
      "name": "Send Stop Confirm",
      "type": "n8n-nodes-base.telegram",
      "typeVersion": 1.1,
      "position": [
        1450,
        1350
      ],
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "command": "pmset -g batt 2>&1; echo '---'; pmset -g assertions 2>&1 | grep -E '(PreventSleep|PreventUserIdleSystem|NoIdleSleepAssertion)' | head -5"
      },
      "name": "Get Power Status",
      "type": "n8n-nodes-base.executeCommand",
      "typeVersion": 1,
      "position": [
        1250,
        1450
      ]
    },
    {
      "parameters": {
        "jsCode": "const output = $input.first().json.stdout || '';\nconst hasACPower = output.includes('AC Power') || output.includes('charged');\nconst hasSleepPrevention = output.includes('PreventSleep') || output.includes('NoIdleSleep');\nconst battLine = output.split('\\n').find(l => l.includes('%')) || 'Unknown';\n\nlet wakeStatus;\nif (hasACPower && hasSleepPrevention) {\n  wakeStatus = '\u2705 Mac is plugged in and sleep prevention is active. Bot will stay awake!';\n} else if (hasACPower) {\n  wakeStatus = '\u26a0\ufe0f On AC power but no sleep prevention detected.\\n\\nInstall *Amphetamine* (free) to stay awake with lid closed:\\nhttps://apps.apple.com/us/app/amphetamine/id937984704';\n} else {\n  wakeStatus = '\ud83d\udd0b On battery \u2014 Mac may sleep!\\n\\nPlug in + install *Amphetamine* (free) for always-on use:\\nhttps://apps.apple.com/us/app/amphetamine/id937984704';\n}\n\nconst msg = `\ud83d\udcf1 *Wake / Power Status*\\n\\n${wakeStatus}\\n\\n*Battery:* ${battLine.trim()}`;\nreturn [{ json: { message: msg, chatId: $('System Owner Check').first().json.chatId } }];"
      },
      "name": "Format Wake Status",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1450,
        1450
      ]
    },
    {
      "parameters": {
        "chatId": "={{ $json.chatId }}",
        "text": "={{ $json.message }}",
        "additionalFields": {
          "parse_mode": "Markdown"
        }
      },
      "name": "Send Wake Status",
      "type": "n8n-nodes-base.telegram",
      "typeVersion": 1.1,
      "position": [
        1650,
        1450
      ],
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "// Parse todo subcommand from args\n// Format: /todo [subcommand] [args...]\n// e.g.  /todo\n//        /todo list\n//        /todo add Buy milk due:2026-03-15 recur:weekly\n//        /todo done 12\n//        /todo delete 12\n\nconst args = $input.first().json.args || '';\nconst trimmedArgs = args.trim();\nconst firstSpaceIndex = trimmedArgs.indexOf(' ');\n\nlet subcommand;\nlet subArgs;\n\nif (firstSpaceIndex === -1) {\n  subcommand = trimmedArgs || 'list';\n  subArgs = '';\n} else {\n  subcommand = trimmedArgs.substring(0, firstSpaceIndex);\n  subArgs = trimmedArgs.substring(firstSpaceIndex + 1).trim();\n}\n\nsubcommand = subcommand.toLowerCase();\n\nreturn [{\n  json: {\n    ...$input.first().json,\n    subcommand: subcommand,\n    subArgs: subArgs\n  }\n}];"
      },
      "name": "Parse Todo Subcommand",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        850,
        1600
      ]
    },
    {
      "parameters": {
        "rules": {
          "rules": [
            {
              "value": "list",
              "output": 0
            },
            {
              "value": "add",
              "output": 1
            },
            {
              "value": "done",
              "output": 2
            },
            {
              "value": "delete",
              "output": 3
            }
          ]
        },
        "dataType": "string",
        "value1": "={{ $json.subcommand }}"
      },
      "name": "Route Todo Subcommand",
      "type": "n8n-nodes-base.switch",
      "typeVersion": 2,
      "position": [
        1050,
        1600
      ]
    },
    {
      "parameters": {
        "method": "GET",
        "url": "=http://host.docker.internal:4242/brain/todos?chat_id={{ $json.chatId }}&completed=false",
        "options": {}
      },
      "name": "Fetch Todos",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.1,
      "position": [
        1250,
        1500
      ]
    },
    {
      "parameters": {
        "jsCode": "const resp = $input.first().json;\nconst todos = resp.todos || [];\nconst chatId = $('Parse Todo Subcommand').first().json.chatId;\n\nif (todos.length === 0) {\n  return [{ json: { chatId, message: '\\u2705 No active todos! Use `/todo add <task>` to create one.' } }];\n}\n\nlet msg = `\\u2705 *Your Todos (${todos.length})*\\n`;\ntodos.forEach((t, i) => {\n  msg += `\\n${i + 1}. [#${t.id}] ${t.task}`;\n  const parts = [];\n  if (t.due_at) parts.push(`\\ud83d\\udcc5 Due: ${t.due_at.slice(0, 10)}`);\n  if (t.recurrence) parts.push(`\\ud83d\\udd01 Recurrence: ${t.recurrence}`);\n  if (parts.length) msg += `\\n   ${parts.join(' | ')}`;\n});\n\nreturn [{ json: { chatId, message: msg } }];"
      },
      "name": "Format Todo List",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1450,
        1500
      ]
    },
    {
      "parameters": {
        "chatId": "={{ $json.chatId }}",
        "text": "={{ $json.message }}",
        "additionalFields": {
          "parse_mode": "Markdown"
        }
      },
      "name": "Send Todo List",
      "type": "n8n-nodes-base.telegram",
      "typeVersion": 1.1,
      "position": [
        1650,
        1500
      ],
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "// Parse: /todo add Buy milk due:2026-03-15 recur:weekly\nconst raw = $input.first().json.subArgs || '';\nconst chatId = $input.first().json.chatId;\n\nlet task = raw;\nlet due_at = null;\nlet recurrence = null;\n\n// Match and remove due date from anywhere in the string\nconst dueRegex = /\\s*due:\\s*(\\d{4}-\\d{2}-\\d{2})\\s*/;\nconst dueMatch = task.match(dueRegex);\nif (dueMatch) {\n  const parsed = new Date(dueMatch[1] + 'T00:00:00Z');\n  const [y, m, d] = dueMatch[1].split('-').map(Number);\n  if (isNaN(parsed.getTime()) || parsed.getUTCFullYear() !== y || parsed.getUTCMonth() + 1 !== m || parsed.getUTCDate() !== d) {\n    return [{ json: { chatId, error: true, message: '\\u26a0\\ufe0f Invalid date. Use format: `due:YYYY-MM-DD` (e.g. `due:2026-03-15`)' } }];\n  }\n  due_at = dueMatch[1] + 'T00:00:00+00:00';\n  task = task.replace(dueMatch[0], ' ').trim();\n}\n\n// Match and remove recurrence from anywhere in the string\nconst recurRegex = /\\s*recur:\\s*(daily|weekly|monthly)\\s*/i;\nconst recurMatch = task.match(recurRegex);\nif (recurMatch) {\n  recurrence = recurMatch[1].toLowerCase();\n  task = task.replace(recurMatch[0], ' ').trim();\n}\n\ntask = task.trim();\n\nif (!task) {\n  return [{ json: { chatId, error: true, message: '\\u26a0\\ufe0f Usage: `/todo add <task> [due:YYYY-MM-DD] [recur:daily|weekly|monthly]`' } }];\n}\n\nreturn [{ json: { chatId, error: false, task, due_at, recurrence } }];"
      },
      "name": "Parse Todo Add Args",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1250,
        1600
      ]
    },
    {
      "parameters": {
        "conditions": {
          "boolean": [
            {
              "value1": "={{ $json.error }}",
              "value2": true
            }
          ]
        }
      },
      "name": "Todo Add Error?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 1,
      "position": [
        1450,
        1600
      ]
    },
    {
      "parameters": {
        "chatId": "={{ $json.chatId }}",
        "text": "={{ $json.message }}",
        "additionalFields": {
          "parse_mode": "Markdown"
        }
      },
      "name": "Send Todo Add Error",
      "type": "n8n-nodes-base.telegram",
      "typeVersion": 1.1,
      "position": [
        1650,
        1550
      ],
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "method": "POST",
        "url": "http://host.docker.internal:4242/brain/todo",
        "sendBody": true,
        "bodyParameters": {
          "parameters": [
            {
              "name": "chat_id",
              "value": "={{ $json.chatId }}"
            },
            {
              "name": "task",
              "value": "={{ $json.task }}"
            },
            {
              "name": "due_at",
              "value": "={{ $json.due_at }}"
            },
            {
              "name": "recurrence",
              "value": "={{ $json.recurrence }}"
            }
          ]
        },
        "options": {}
      },
      "name": "Create Todo",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.1,
      "position": [
        1650,
        1650
      ]
    },
    {
      "parameters": {
        "jsCode": "const resp = $input.first().json;\nconst chatId = $('Parse Todo Add Args').first().json.chatId;\nconst parts = [`\\u2705 *Todo created!*\\n\\n#${resp.id} \\u2014 ${resp.task}`];\nif (resp.due_at) parts.push(`\\ud83d\\udcc5 Due: ${resp.due_at.slice(0, 10)}`);\nif (resp.recurrence) parts.push(`\\ud83d\\udd01 Recurrence: ${resp.recurrence}`);\nreturn [{ json: { chatId, message: parts.join('\\n') } }];"
      },
      "name": "Format Todo Created",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1850,
        1650
      ]
    },
    {
      "parameters": {
        "chatId": "={{ $json.chatId }}",
        "text": "={{ $json.message }}",
        "additionalFields": {
          "parse_mode": "Markdown"
        }
      },
      "name": "Send Todo Created",
      "type": "n8n-nodes-base.telegram",
      "typeVersion": 1.1,
      "position": [
        2050,
        1650
      ],
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "method": "PATCH",
        "url": "=http://host.docker.internal:4242/brain/todo/{{ $json.subArgs }}",
        "sendBody": true,
        "bodyParameters": {
          "parameters": [
            {
              "name": "completed",
              "value": "={{true}}"
            }
          ]
        },
        "options": {
          "response": {
            "neverError": true
          }
        }
      },
      "name": "Complete Todo",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.1,
      "position": [
        1250,
        1700
      ]
    },
    {
      "parameters": {
        "jsCode": "const input = $input.first().json;\nconst chatId = $('Parse Todo Subcommand').first().json.chatId;\n\nif (input.statusCode && input.statusCode >= 400) {\n  return [{ json: { chatId, message: '\\u26a0\\ufe0f Todo not found. Check the ID and try again.' } }];\n}\n\nconst resp = input;\nlet msg = '\\u2705 *Todo completed!*';\nif (resp.next_todo) {\n  const nxt = resp.next_todo;\n  msg += `\\n\\n\\ud83d\\udd01 Next instance created:\\n#${nxt.id} \\u2014 ${nxt.task}`;\n  if (nxt.due_at) msg += `\\n\\ud83d\\udcc5 Due: ${nxt.due_at.slice(0, 10)}`;\n}\n\nreturn [{ json: { chatId, message: msg } }];"
      },
      "name": "Format Todo Done",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1450,
        1700
      ]
    },
    {
      "parameters": {
        "chatId": "={{ $json.chatId }}",
        "text": "={{ $json.message }}",
        "additionalFields": {
          "parse_mode": "Markdown"
        }
      },
      "name": "Send Todo Done",
      "type": "n8n-nodes-base.telegram",
      "typeVersion": 1.1,
      "position": [
        1650,
        1700
      ],
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "method": "DELETE",
        "url": "=http://host.docker.internal:4242/brain/todo/{{ $json.subArgs }}",
        "options": {
          "response": {
            "neverError": true
          }
        }
      },
      "name": "Delete Todo",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.1,
      "position": [
        1250,
        1800
      ]
    },
    {
      "parameters": {
        "jsCode": "const input = $input.first().json;\nconst chatId = $('Parse Todo Subcommand').first().json.chatId;\nconst todoId = $('Parse Todo Subcommand').first().json.subArgs;\n\nif (input.statusCode && input.statusCode >= 400) {\n  return [{ json: { chatId, message: '\\u26a0\\ufe0f Todo not found. Check the ID and try again.' } }];\n}\n\nreturn [{ json: { chatId, message: `\\ud83d\\uddd1\\ufe0f Todo #${todoId} deleted.` } }];"
      },
      "name": "Format Todo Deleted",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1450,
        1800
      ]
    },
    {
      "parameters": {
        "chatId": "={{ $json.chatId }}",
        "text": "={{ $json.message }}",
        "additionalFields": {
          "parse_mode": "Markdown"
        }
      },
      "name": "Send Todo Deleted",
      "type": "n8n-nodes-base.telegram",
      "typeVersion": 1.1,
      "position": [
        1650,
        1800
      ],
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      }
    }
  ],
  "connections": {
    "Execute Workflow Trigger": {
      "main": [
        [
          {
            "node": "Parse Command",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse Command": {
      "main": [
        [
          {
            "node": "Route Command",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Route Command": {
      "main": [
        [
          {
            "node": "Help Response",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Get Disk Usage",
            "type": "main",
            "index": 0
          },
          {
            "node": "Get Memory",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Save Memory",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Get All Memory",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Clear History",
            "type": "main",
            "index": 0
          }
        ],
        [],
        [],
        [],
        [
          {
            "node": "Parse Email Subcommand",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "System Owner Check",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Parse Todo Subcommand",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Disk Usage": {
      "main": [
        [
          {
            "node": "Format Status",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Memory": {
      "main": [
        [
          {
            "node": "Format Status",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Format Status": {
      "main": [
        [
          {
            "node": "Send Status",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Save Memory": {
      "main": [
        [
          {
            "node": "Confirm Remember",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get All Memory": {
      "main": [
        [
          {
            "node": "Format Memory List",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Format Memory List": {
      "main": [
        [
          {
            "node": "Send Memory",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Clear History": {
      "main": [
        [
          {
            "node": "Confirm Clear",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse Email Subcommand": {
      "main": [
        [
          {
            "node": "Route Email Subcommand",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Route Email Subcommand": {
      "main": [
        [
          {
            "node": "Email Auth Message",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Check Emails",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Read Email",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Reply Email",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Send Email",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Search Emails",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "System Owner Check": {
      "main": [
        [
          {
            "node": "Route System Subcommand",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Route System Subcommand": {
      "main": [
        [
          {
            "node": "System Access Denied",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Docker Status",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Docker Restart",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Docker Stop",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Get Power Status",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Docker Status": {
      "main": [
        [
          {
            "node": "Format Docker Status",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Format Docker Status": {
      "main": [
        [
          {
            "node": "Send System Status",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Docker Restart": {
      "main": [
        [
          {
            "node": "Send Restart Confirm",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Docker Stop": {
      "main": [
        [
          {
            "node": "Send Stop Confirm",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Power Status": {
      "main": [
        [
          {
            "node": "Format Wake Status",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Format Wake Status": {
      "main": [
        [
          {
            "node": "Send Wake Status",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse Todo Subcommand": {
      "main": [
        [
          {
            "node": "Route Todo Subcommand",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Route Todo Subcommand": {
      "main": [
        [
          {
            "node": "Fetch Todos",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Parse Todo Add Args",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Complete Todo",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Delete Todo",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch Todos": {
      "main": [
        [
          {
            "node": "Format Todo List",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Format Todo List": {
      "main": [
        [
          {
            "node": "Send Todo List",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse Todo Add Args": {
      "main": [
        [
          {
            "node": "Todo Add Error?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Todo Add Error?": {
      "main": [
        [
          {
            "node": "Send Todo Add Error",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Create Todo",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Create Todo": {
      "main": [
        [
          {
            "node": "Format Todo Created",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Format Todo Created": {
      "main": [
        [
          {
            "node": "Send Todo Created",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Complete Todo": {
      "main": [
        [
          {
            "node": "Format Todo Done",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Format Todo Done": {
      "main": [
        [
          {
            "node": "Send Todo Done",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Delete Todo": {
      "main": [
        [
          {
            "node": "Format Todo Deleted",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Format Todo Deleted": {
      "main": [
        [
          {
            "node": "Send Todo Deleted",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "executionOrder": "v1"
  },
  "staticData": null,
  "tags": [
    "ronku-bot",
    "commands"
  ]
}