Skip to content

title: "Riferimento della CLI" description: "Guidare Mercy SF da un altro programma: ogni comando, il suo output JSON, i codici di uscita ed esempi svolti."

Riferimento della CLI, guidare Mercy SF da un altro programma

mercy-cli ha una modalità non interattiva: argomenti in ingresso, un oggetto JSON in uscita. È pensata per dashboard, supervisori e script.

Questa pagina è la promessa. I comandi e i nomi dei campi qui sotto non cambieranno senza preavviso. Tutto il resto della CLI, il menu, il modo in cui è scritto, l'impaginazione del suo output, è libero di cambiare in qualsiasi momento, quindi per favore non costruiteci sopra.

Eseguita senza argomenti, parte il menu interattivo esattamente come prima.

Ogni risposta porta "api". Oggi è 1. Aggiungere un campo non lo cambia, un chiamante che legge solo i campi che conosce resta inalterato. Cambia quando un campo viene rimosso o il suo significato cambia, così potete rifiutarvi di girare contro una forma per cui non siete stati costruiti.


Accedere

Gli account creati tramite il single sign-on di S&F non hanno bisogno di altro. Un account che appartiene a un server e non ha mai fatto parte del single sign-on per esso non esiste, e ha bisogno di --server:

bash
mercy-cli --status --user <account> --server https://f1.sfgame.net/

--server funziona con ogni comando qui sotto.

Output

Ogni comando tranne --start stampa JSON e nient'altro, quindi --json è già il comportamento predefinito e passarlo non cambia nulla. Esiste per i chiamanti che preferiscono dirlo piuttosto che affidarsi a un valore di serie, e per --start, che altrimenti scrive un registro per persone.


Leggere

Elencare i personaggi di un account

bash
mercy-cli --characters --user <account>
json
{
  "ok": true,
  "characters": [
    { "character": "Hero", "server": "https://s1.sfgame.net/", "level": 345 },
    { "character": "Alt",  "server": "https://s42.sfgame.net/", "level": 88 }
  ]
}

Un solo accesso copre ogni personaggio dell'account, su tutti i server. level è null se lo stato di quel personaggio non è stato recuperato, la voce viene comunque elencata, perché sapere che esiste è il senso della chiamata.

Leggere lo stato di un personaggio

bash
mercy-cli --status --user <account> --character <name>

--character si può omettere quando l'account ne ha esattamente uno.

json
{
  "ok": true,
  "character": "Hero",
  "server": "https://s1.sfgame.net/",
  "level": 345,
  "class": "DemonHunter",
  "race": "DarkElf",
  "experience": { "current": 740300000, "next_level": 769800000 },
  "silver": 725000000,
  "mushrooms": 8,
  "honor": 12043,
  "rank": 1800,
  "action": "CityGuard",
  "attributes": {
    "strength":     { "base": 4077, "bonus": 1200 },
    "dexterity":    { "base": 1000, "bonus": 300 },
    "intelligence": { "base": 900,  "bonus": 250 },
    "constitution": { "base": 3000, "bonus": 800 },
    "luck":         { "base": 700,  "bonus": 150 }
  },
  "equipment": [
    {
      "slot": "Weapon",
      "model_id": 55,
      "color": 1,
      "class": "DemonHunter",
      "epic": true,
      "legendary": false,
      "armor": 0,
      "min_damage": 900,
      "max_damage": 1400,
      "upgrades": 3,
      "attributes": { "strength": 420, "constitution": 210 },
      "rune": { "type": "FireDamage", "value": 60 },
      "enchantment": "SwordOfVengeance",
      "gem": { "type": "Strength", "value": 300 }
    }
  ],
  "arena": {
    "fights_for_xp": 7,
    "next_free_fight": "2026-08-06T12:04:11+02:00",
    "opponents": [50099, 34316, 13668]
  },
  "tavern": {
    "thirst_for_adventure_sec": 3600,
    "beer_drunk": 2,
    "mushroom_skip_allowed": true,
    "quests": [
      { "length_sec": 600, "silver": 120000, "experience": 45000,
        "location": "Wolves", "item": true }
    ]
  },
  "guild": {
    "name": "Blvck Clover",
    "rank": 12,
    "honor": 90000,
    "members": [
      { "name": "Hero", "level": 345, "last_online": "2026-08-06T09:12:00+02:00" }
    ]
  },
  "scrapbook_items": 1102
}

Tutto viene da un solo recupero di stato, quindi non ci sono sezioni da chiedere e niente da risparmiare chiedendo di meno.

guild è null quando il personaggio non è in nessuna. scrapbook_items è null finché l'album non è stato letto almeno una volta. Uno slot di equipaggiamento vuoto viene omesso invece che elencato come null.

Sui nomi degli oggetti: il protocollo porta un id di modello e uno slot, non un nome visualizzato, quindi è quello che ottenete. È anche ciò con cui viene indirizzata la grafica, quindi una dashboard può disegnare esattamente l'immagine che disegna l'app desktop. Inventare qui un nome sarebbe un'ipotesi non verificabile.

Ripetere una lettura a intervalli

bash
mercy-cli --status --user <account> --character <name> --watch 60

Un accesso, poi un oggetto ogni 60 secondi finché il processo non viene fermato. Usate questo invece di rilanciare il comando in un ciclo: ogni esecuzione è un accesso nuovo, che è il modo più costoso di sorvegliare un numero e il più vistoso dal lato del server. Il minimo è 30 secondi. Un giro fallito viene stampato e il ciclo prosegue: un osservatore che si arrende al primo singhiozzo sembra esattamente uno in cui non succede nulla.

Chi affronterà dopo, e perché

bash
mercy-cli --plan --user <account> --character <name>
json
{
  "ok": true,
  "outcome": "planned",
  "reason": "Next: Someone — 3 scrapbook items, 72% odds",
  "candidates": [
    {
      "name": "Someone",
      "level": 340,
      "source": "pool",
      "missing_items": 3,
      "rank_gain": 12,
      "favourite": false,
      "win_chance": 0.72,
      "item_score": 300.0,
      "xp_score": 60.0,
      "rank_score": 25.0,
      "base": 385.0,
      "score": 277.2
    }
  ]
}

La stessa decisione che disegna l'app: candidati valutati su oggetti, XP quotidiana e posizione, poi moltiplicati per le probabilità. outcome è planned, waiting, blocked o empty, e reason dice quale in una frase.

Questo non spende alcun combattimento né alcun fungo. Fa però una scansione per trovare candidati, quindi non è gratis in richieste: non mettetelo in un ciclo stretto.

Provare un combattimento

bash
mercy-cli --simulate --user <account> --character <name> --against <player>
json
{ "ok": true, "against": "Someone", "against_level": 340, "win_chance": 0.63, "iterations": 1000 }

Aritmetica. Una consultazione va al server per scoprire chi è; il combattimento in sé non viene mai inviato. win_chance sono le vittorie sui combattimenti decisi, quindi una simulazione che non riesce a risolvere riferisce su meno di quanti ne ha eseguiti.

Cosa si porta addosso

bash
mercy-cli --inventory --user <account> --character <name>
json
{ "ok": true, "carried": 12, "backpack": [ { "slot_index": 0, "model_id": 55 } ] }

Un solo elenco, perché il gioco ne tiene uno. Gli oggetti hanno la stessa forma che in --status, più slot_index.

Album

bash
mercy-cli --scrapbook --user <account> --character <name>
json
{ "ok": true, "unlocked": true, "owned": 1102, "monsters": 214 }

unlocked è false sotto il livello che concede un album, e lì owned è null. Non è un errore.

Combattimenti registrati

bash
mercy-cli --history --user <account> --character <name> --limit 50
json
{ "ok": true, "total": 4210, "returned": 50, "battles": [] }

I più recenti per primi. Sono registrati dall'installazione che ha fatto girare il bot, non recuperati dal server: un processo appena avviato non ha nulla da mostrare, e non è un guasto. total è ciò che esiste, returned è ciò che --limit ha lasciato.


Agire

Far girare il bot

bash
mercy-cli --start --user <account> --character <name>

Gira finché il processo non viene fermato, registrando man mano. Qui --character è obbligatorio: elencare e leggere lo stato sono innocui, ma avviare il bot gioca la partita, e sbagliare personaggio non è una cosa che si possa annullare.

--all fa invece girare ogni personaggio dell'account in questo unico processo. È un accesso per l'account invece di uno per personaggio, il che costa meno e impedisce ai personaggi di invalidarsi la sessione a vicenda.

Su Ctrl-C (o SIGTERM) la mossa in corso può concludersi prima che il processo esca, invece di essere troncata a metà richiesta.

Eventi invece di prosa

bash
mercy-cli --start --user <account> --character <name> --events

Un oggetto JSON per riga, così un supervisore legge una riga alla volta:

json
{"at":"2026-08-06T17:22:04+02:00","api":1,"event":"arena_win","character":"Hero"}
{"at":"2026-08-06T17:22:31+02:00","api":1,"event":"quest_done","character":"Hero"}

event è uno tra started, stopping, stopped, arena_win, arena_loss, dungeon_win, dungeon_loss, quest_done, scrapbook_win, scrapbook_loss, scrapbook_items (che porta count).

Questo elenco crescerà. Trattate un evento che non riconoscete come uno da ignorare, non come un errore: è tutta la ragione per cui i nomi sono scritti per esteso invece di essere ciò che Rust ha stampato.

Usate questo invece di leggere il registro per persone. Quel registro è scritto per una persona ed è libero di essere riscritto in qualsiasi momento; analizzarlo significa che il vostro strumento si rompe quando qualcuno migliora una frase.

Raccogliere ciò che aspetta

bash
mercy-cli --claim --user <account> --character <name>

Calendario, incarichi quotidiani, sblocchi in attesa. --character è obbligatorio, per lo stesso motivo di --start.

Leggere o cambiare la configurazione

bash
mercy-cli --config --user <account> --character <name>
mercy-cli --config --user <account> --character <name> --set auto_arena=false
json
{ "ok": true, "settable": ["auto_arena"], "changed": [ { "key": "auto_arena", "from": true, "to": false } ] }

Leggere restituisce l'intera configurazione sotto config. I nomi dei campi dentro quel blocco non fanno parte di questa promessa, solo le chiavi elencate in settable ne fanno parte. La configurazione ha ben oltre cento campi e cresce a ogni versione; prometterli tutti significherebbe non poter mai più rimettere mano alle impostazioni.

--set accetta true/false, on/off, yes/no, 1/0, richiede sempre --character (un interruttore appartiene a un personaggio, e «l'unico» è un'ipotesi accettabile per leggere e sbagliata per scrivere), e si può ripetere. Il valore viene poi riletto da disco e la chiamata fallisce se non è atterrato, perché segnalare un cambiamento che non è avvenuto è l'unico esito da cui non ci si riprende.


Esercizio

Che build è questa

bash
mercy-cli --version
json
{ "ok": true, "version": "2.12.0", "api": 1 }

L'unico comando che non ha bisogno né di una password né della rete. Un supervisore deve poter chiedere con che cosa sta parlando prima di avere le credenziali per parlarci.

È raggiungibile

bash
mercy-cli --health --user <account> --character <name>
json
{ "ok": true, "character": "Hero", "level": 345, "round_trip_ms": 412 }

Accedere, recuperare, riferire, uscire. Volutamente minuscolo: un controllo di salute che restituisce una scheda personaggio completa invita ad analizzarla, e a quel punto il controllo diventa un'interfaccia a sé.


La password

Non c'è un'opzione --password, di proposito. Gli argomenti da riga di comando sono leggibili da ogni altro processo sulla macchina, ps, /proc, Gestione attività, quindi una dashboard che lo eseguisse per più persone consegnerebbe tutte le loro password di gioco a chiunque abbia una shell su quella macchina.

Due strade invece:

bash
MERCY_SF_PASSWORD='…' mercy-cli --status --user someone
bash
printf '%s' "$password" | mercy-cli --status --user someone --password-stdin

--password-stdin legge la prima riga dello standard input, il che tiene il segreto anche fuori dall'ambiente.


Codici di uscita

CodiceSignificato
0Successo, e per --help
1Ha girato ed è fallito, il motivo è in error, e ok è false
2La chiamata era sbagliata: opzione sconosciuta, valore mancante, nessuna azione. Su stderr

La differenza tra 1 e 2 conta per un supervisore: 2 fallirà allo stesso modo ogni volta e ha bisogno di una persona, 1 può benissimo funzionare al tentativo successivo.


Errori

Anche i fallimenti sono JSON, quindi un solo parser gestisce entrambi:

json
{ "ok": false, "error": "no character called 'Typo' on this account" }

ok è presente in ogni risposta. Controllatelo prima di ogni altra cosa.

Cause comuni:

MessaggioCosa fare
--user is requiredManca --user (ogni azione tranne --version)
--start needs --character (or --all)Nominate il bersaglio; non verrà indovinato
this account has N characters — name one with --characterCe ne sono diversi, sceglietene uno
no character called '…' on this accountRefuso; --characters elenca i nomi validi
no password: set MERCY_SF_PASSWORD or pass --password-stdinScegliete una delle due strade per la password
login failed: …Controllate le credenziali o il server; gli account senza single sign-on richiedono --server
'…' is not settable from hereNon è nell'elenco consentito; --config senza --set stampa settable
'…' did not save — it still reads back unchangedLa modifica non è atterrata; controllate i permessi di scrittura

Ricette

Raccogliere su ogni account una volta al giorno

bash
for account in alpha beta gamma; do
  MERCY_SF_PASSWORD="$(pass mercy/$account)" \
    mercy-cli --claim --user "$account" --character Hero || echo "failed: $account"
done

Tenere aggiornato un riquadro della dashboard

bash
MERCY_SF_PASSWORD='…' mercy-cli --status --user someone --character Hero --watch 60

Un accesso, un oggetto al minuto. Non rilanciatelo invece da cron ogni minuto: quello è un accesso nuovo ogni volta.

Registrare gli eventi su file

bash
MERCY_SF_PASSWORD='…' mercy-cli --start --user someone --character Hero --events \
  >> events.ndjson

Controllare con cosa state parlando prima di accedere

bash
api=$(mercy-cli --version | jq -r .api)
[ "$api" = "1" ] || { echo "unknown contract version: $api"; exit 1; }

Come servizio systemd

ini
[Service]
Environment=MERCY_SF_PASSWORD=…
ExecStart=/usr/local/bin/mercy-cli --start --user someone --all --events
Restart=on-failure
KillSignal=SIGTERM

SIGTERM lascia concludere la mossa in corso. Per favore non usate SIGKILL.


Cosa non fa ancora

Avviare più personaggi e fermarli singolarmente (--all li avvia tutti e li ferma tutti insieme), un canale di controllo verso un processo in esecuzione, e cambiare qualsiasi cosa oltre agli interruttori dei moduli.

Se vi serve una di queste, dite quale: è più facile costruire la cosa giusta che tirare a indovinare e vederla inutilizzata.

Mercy SF non è affiliato a Shakes & Fidget né a Playa Games. Lo usi a tuo rischio.