Skip to content

Instantly share code, notes, and snippets.

@mp3fbf
Last active January 15, 2026 03:24
Show Gist options
  • Select an option

  • Save mp3fbf/4d417c6f6acd838a425d4bcf2b07e64b to your computer and use it in GitHub Desktop.

Select an option

Save mp3fbf/4d417c6f6acd838a425d4bcf2b07e64b to your computer and use it in GitHub Desktop.
reminders-cli for Apple Reminders
#!/bin/bash
# reminders-cli - CLI para Apple Reminders via JXA
# Versão com código inline (uma linha)
set -e
json_error() {
echo "{\"success\": false, \"data\": null, \"error\": \"$1\"}"
exit 1
}
ALLOWED_COMMANDS="lists list all add complete delete search help"
validate_command() {
local cmd="$1"
for allowed in $ALLOWED_COMMANDS; do
[ "$cmd" = "$allowed" ] && return 0
done
json_error "Comando não permitido: $cmd"
}
cmd_lists() {
osascript -l JavaScript -e 'JSON.stringify({success: true, data: Application("Reminders").lists().map(function(l) { return {id: l.id(), name: l.name(), count: l.reminders().length, pendingCount: l.reminders().filter(function(r) { return !r.completed(); }).length}; }), error: null})'
}
cmd_list() {
local listName="$1"
local pendingOnly="$2"
[ -z "$listName" ] && json_error "Nome da lista é obrigatório"
local filter="true"
[ "$pendingOnly" = "--pending" ] && filter="!r.completed()"
osascript -l JavaScript -e "var ls = Application('Reminders').lists.whose({name: '$listName'}); if (ls.length === 0) { JSON.stringify({success: false, data: null, error: 'Lista não encontrada'}); } else { JSON.stringify({success: true, data: ls[0].reminders().filter(function(r) { return $filter; }).map(function(r) { return {id: r.id(), name: r.name(), body: r.body() || null, completed: r.completed(), dueDate: r.dueDate() ? r.dueDate().toISOString() : null, priority: r.priority()}; }), error: null}); }"
}
cmd_all() {
local pendingOnly="$1"
local filter="true"
[ "$pendingOnly" = "--pending" ] && filter="!r.completed()"
osascript -l JavaScript -e "var result = []; Application('Reminders').lists().forEach(function(list) { list.reminders().filter(function(r) { return $filter; }).forEach(function(r) { result.push({id: r.id(), name: r.name(), body: r.body() || null, completed: r.completed(), dueDate: r.dueDate() ? r.dueDate().toISOString() : null, listName: list.name()}); }); }); JSON.stringify({success: true, data: result, error: null});"
}
cmd_add() {
local listName="$1"
local title="$2"
local body="${3:-}"
[ -z "$listName" ] || [ -z "$title" ] && json_error "Lista e título são obrigatórios"
osascript -l JavaScript -e "var app = Application('Reminders'); var ls = app.lists.whose({name: '$listName'}); if (ls.length === 0) { JSON.stringify({success: false, data: null, error: 'Lista não encontrada'}); } else { var r = app.Reminder({name: '$title', body: '$body'}); ls[0].reminders.push(r); JSON.stringify({success: true, data: {id: r.id(), name: r.name(), listName: '$listName'}, error: null}); }"
}
cmd_complete() {
local listName="$1"
local identifier="$2"
[ -z "$listName" ] || [ -z "$identifier" ] && json_error "Lista e nome do reminder são obrigatórios"
osascript -l JavaScript -e "var app = Application('Reminders'); var ls = app.lists.whose({name: '$listName'}); if (ls.length === 0) { JSON.stringify({success: false, data: null, error: 'Lista não encontrada'}); } else { var r = ls[0].reminders().find(function(x) { return x.name().toLowerCase() === '$identifier'.toLowerCase(); }); if (!r) { JSON.stringify({success: false, data: null, error: 'Reminder não encontrado'}); } else { r.completed = true; JSON.stringify({success: true, data: {name: r.name(), completed: true}, error: null}); } }"
}
cmd_delete() {
local listName="$1"
local identifier="$2"
[ -z "$listName" ] || [ -z "$identifier" ] && json_error "Lista e nome do reminder são obrigatórios"
osascript -l JavaScript -e "var app = Application('Reminders'); var ls = app.lists.whose({name: '$listName'}); if (ls.length === 0) { JSON.stringify({success: false, data: null, error: 'Lista não encontrada'}); } else { var r = ls[0].reminders().find(function(x) { return x.name().toLowerCase() === '$identifier'.toLowerCase(); }); if (!r) { JSON.stringify({success: false, data: null, error: 'Reminder não encontrado'}); } else { var n = r.name(); app.delete(r); JSON.stringify({success: true, data: {name: n, deleted: true}, error: null}); } }"
}
cmd_search() {
local searchTerm="$1"
[ -z "$searchTerm" ] && json_error "Termo de busca é obrigatório"
osascript -l JavaScript -e "var term = '$searchTerm'.toLowerCase(); var result = []; Application('Reminders').lists().forEach(function(list) { list.reminders().forEach(function(r) { if (r.name().toLowerCase().indexOf(term) >= 0 || (r.body() || '').toLowerCase().indexOf(term) >= 0) { result.push({id: r.id(), name: r.name(), body: r.body() || null, completed: r.completed(), listName: list.name()}); } }); }); JSON.stringify({success: true, data: result, error: null});"
}
cmd_help() {
echo "reminders-cli - CLI para Apple Reminders"
echo ""
echo "COMANDOS:"
echo " lists Lista todas as listas"
echo " list <lista> [--pending] Lista reminders de uma lista"
echo " all [--pending] Lista todos os reminders"
echo " add <lista> <titulo> Adiciona um reminder"
echo " complete <lista> <nome> Marca como completo"
echo " delete <lista> <nome> Deleta um reminder"
echo " search <termo> Busca em todas as listas"
echo " help Mostra esta ajuda"
}
validate_command "${1:-help}"
case "${1:-help}" in
lists) cmd_lists ;;
list) cmd_list "$2" "$3" ;;
all) cmd_all "$2" ;;
add) cmd_add "$2" "$3" "$4" ;;
complete) cmd_complete "$2" "$3" ;;
delete) cmd_delete "$2" "$3" ;;
search) cmd_search "$2" ;;
help|--help|-h) cmd_help ;;
*) json_error "Comando desconhecido: $1" ;;
esac
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment