@sinoia/pulse-cli
v0.3.0
Published
CLI Pulse — orienté agent/LLM (--json) : piloter le support (tickets) et le CRM/commerce (prospects, leads, pipeline, tâches, relances) via l'API REST Pulse.
Maintainers
Readme
pulse-cli
CLI pour l'API REST Pulse, pensé pour le pilotage par agent/LLM : sortie
--json structurée, auth par clé API (pk_…) ou login JWT. Deux cas
d'usage : un agent support qui prend des tickets et y répond, et un agent
commercial qui qualifie les prospects entrants, travaille ses leads, fait
avancer le pipeline et tient ses relances/tâches à jour.
Vit dans le repo Pulse, sous tools/cli/.
Installation
npm (global — nécessite Node ≥ 20)
npm install -g @sinoia/pulse-cli
pulse --versionBinaire autonome (sans Node)
Des exécutables autonomes (runtime Node embarqué) sont produits par pkg :
cd tools/cli
npm install
npm run package # → binaries/pulse-cli-{macos-arm64,macos-x64,linux-x64,linux-arm64}
# ciblé : npm run package:macos | npm run package:linux
# installer (ex. macOS arm64)
sudo install binaries/pulse-cli-macos-arm64 /usr/local/bin/pulse
pulse --versionAucune dépendance Node requise pour exécuter le binaire (~46 Mo, runtime inclus).
Pour un agent : déposer le binaire de la plateforme et définir PULSE_TOKEN.
Depuis les sources (Node ≥ 20)
cd tools/cli
npm install
npm run build # → dist/cli.js (bin: pulse)En dev : npm run dev -- <commande> (ts-node).
Authentification
Deux modes :
# Humain : login email / mot de passe → JWT (stocké dans ~/.pulse-config.json, 0600)
pulse login -e [email protected] -p '••••••'
# Agent autonome : clé API non-expirante (recommandé)
export PULSE_TOKEN=pk_xxxxxxxx # générée via /profile + l'API api_keys
# ou : pulse config set-token pk_xxxxxxxxSurcharges d'environnement : PULSE_API_URL (défaut https://pulse.sinoia.fr),
PULSE_TOKEN. La clé/JWT voyage en Authorization: Bearer ….
L'auteur des réponses = l'utilisateur de la clé API (doit avoir un rôle
support/agent). --as-support masque son nom côté client (« L'équipe support SINOIA »).
Commandes (toutes acceptent --json)
pulse whoami
pulse tickets ls [--status open] [--severity S1] [--queue <id>] [--mine] [--search "connexion"] [--page N]
pulse tickets show <id>
pulse tickets take <id>
pulse tickets assign <id> --agent <agentId> # dispatch vers un agent (cf. pulse agents)
pulse tickets transfer <id> --queue <queueId> # transfert vers une file (cf. pulse queues)
pulse tickets severity <id> S1 # sévérité S1 (critique) → S4 (gênant) ; liste triée S1 d'abord
pulse tickets attachments <ticketId> # liste les pièces jointes (id, nom, type, taille)
pulse tickets attachment <ticketId> <attId> [-o f] # télécharge le contenu d'une pièce jointe
pulse tickets reply <id> -m "Bonjour, …" [--internal] [--as-support] [--attach capture.png …]
pulse tickets suggest <id> # brouillon de réponse ancré sur la KB (relecture humaine)
pulse tickets close <id> [--reason "résolu"]
pulse tickets stats [--queue <id>] # compteurs par statut
pulse agents # agents (cibles d'assignation)
pulse queues # files (cibles de transfert)
# Base de connaissances (enrichissement + lecture)
pulse kb ls [--search "bannette"] [--status published]
pulse kb show <id>
pulse kb add-from-ticket <ticketId> --title "…" --content "…" [--publish] [--tags a,b]
# Licences & vouchers (Phase 2 — nécessite un token ADMIN : pulse login d'un
# admin, ou une clé API pk_ d'un utilisateur admin)
pulse licenses ls [--status active] [--type pro] [--org <id>] [--expiration expiring_soon] [--limit N]
pulse licenses show <id>
pulse licenses suspend <id> [--reason "…"] | activate <id>
pulse licenses generate-voucher <id> [--max-uses N] [--instance <id>]
pulse licenses stats
pulse vouchers ls [--status …] [--license <id>] [--instance <id>]
pulse vouchers show <id>
pulse vouchers revoke <id> [--reason "…"]
pulse vouchers extend <id> --hours N
# Commandes du store (Phase 2 — token ADMIN)
pulse orders ls [--status failed] [--limit N]
pulse orders show <id>
pulse orders retry <id> # rejoue le provisioning en échec (idempotent)
pulse orders cancel <id> [--reason "…"]
# Parc d'instances (Phase 2 — token ADMIN)
pulse instances ls [--status running] [--org <id>] [--limit N]
pulse instances show <id>
pulse instances credentials <id> # identifiants admin (via la commande liée)
CRM / commerce (rôle admin ou commerce — scopes crm:read / crm:write)
# Référentiel & annuaire (rien n'est codé en dur dans le CLI : les valeurs
# admises — statuts, étapes, types, canaux, résultats — viennent de l'API)
pulse crm meta [lead|contact|opportunity|task|follow_up|deal|prospect]
pulse crm sales-reps # commerciaux (cibles d'assignation)
pulse crm products [--all] # produits (conversion, opportunités)
pulse crm orgs [--search "acme"] # organisations (création contacts/opportunités)
pulse crm today # briefing : relances/tâches du jour et en retard,
# prospects qualifiés non assignés, pipeline en retard
# Prospects entrants (demandes de démo = tickets « commercial ») → qualifier → convertir en lead
pulse prospects ls [--temperature hot] [--mine] [--unassigned] [--unconverted] [--min-score 50] [--search q]
pulse prospects show <id>
pulse prospects take <id> | assign <id> --user <userId>
pulse prospects qualify <id> [--company …] [--size …] [--budget …] [--timeline …] \
[--decision-maker …] [--decision-maker-title …] [--source …] [--auto-convert]
pulse prospects convert <id> [--company …] [--description …] [--notes …] # score ≥ 50 requis
# Leads
pulse leads ls [--status qualified] [--temperature hot] [--mine] [--unassigned] [--active] \
[--follow-up overdue|today|week] [--min-score N] [--sort score] [--search "Acme"] [--org <id>]
pulse leads show <id> # + contacts, notes, tâches
pulse leads create --company "Acme" [--industry …] [--temperature warm] [--contact-first-name … --contact-last-name … --contact-email …]
pulse leads update <id> [--status qualified] [--temperature hot] [--notes "…"] [--tags a,b]
pulse leads take <id> | assign <id> --user <userId> [--reason …]
pulse leads note <id> -m "…" [--type meeting_notes] [--private]
pulse leads follow-up <id> --at +3d [--notes "…"] # dates : ISO 8601, +2h, +3d, +1w, today (18 h), tomorrow (9 h)
pulse leads score <id> 85 [--reason "…"]
pulse leads convert <id> [--title …] [--value 12000] [--probability 40] [--close-date 2026-12-31] [--products id1,id2]
pulse leads stats
# Contacts
pulse contacts ls [--search "curie"] [--org <id>] [--mine] [--decision-makers] [--stage customer]
pulse contacts show <id> # + leads, opportunités, activités, tâches
pulse contacts create --first-name … --last-name … --email … --org <id> [--job-title …] [--role decision_maker] [--decision-maker]
pulse contacts update <id> [--phone …] [--champion] [--tags vip]
pulse contacts note <id> -m "…"
pulse contacts log-call <id> --direction outbound [--result answered] [--duration 12] [--notes "…"] [--schedule-follow-up]
pulse contacts log-email <id> -m "…" [--subject "…"] [--at …]
pulse contacts log-meeting <id> -m "…" [--at …]
# Opportunités (pipeline) — alias : pulse opps
pulse opportunities ls [--stage demo] [--mine] [--open] [--overdue] [--search q] [--org <id>] [--sort close_date|value]
pulse opportunities show <id> # + contacts, produits, timeline, tâches, deal
pulse opportunities create --title "…" --org <id> [--value 5000] [--probability 25] [--close-date …] [--products …] [--contacts …]
pulse opportunities update <id> [--value …] [--close-date …] [--notes "…"]
pulse opportunities advance <id> # étape suivante (probabilité de l'étape appliquée)
pulse opportunities probability <id> 60
pulse opportunities take <id> | assign <id> --user <userId>
pulse opportunities note <id> -m "…"
pulse opportunities close-won <id> [--value 11000] | close-lost <id> [--reason "…"]
pulse opportunities deal <id> [--value …] [--start …] [--end …] [--type annual] [--payment annual] [--billing annual] [--renewal auto]
pulse opportunities stats # pipeline par étape (nombre, valeur, pondérée)
# Tâches
pulse tasks ls [--mine] [--overdue] [--due today|week] [--priority high] [--status …] [--lead|--contact|--opportunity <id>]
pulse tasks show <id>
pulse tasks create --title "…" --due +2d (--lead <id> | --contact <id> | --opportunity <id> | --follow-up <id>) [--type phone_call] [--priority urgent]
pulse tasks update <id> [--title …] [--priority …] [--due …]
pulse tasks start <id> | complete <id> [--notes "…"] [--duration 15] | cancel <id> [--reason "…"]
# Relances planifiées — alias : pulse followups
pulse follow-ups ls [--mine] [--overdue] [--due today|week] [--lead|--contact|--opportunity <id>]
pulse follow-ups show <id>
pulse follow-ups create --title "…" --at +5d (--lead <id> | --contact <id> | --opportunity <id>) [--type demo_follow_up] [--method phone] [--priority high]
pulse follow-ups complete <id> [--outcome meeting_booked] [--notes "…"]
pulse follow-ups reschedule <id> --at +1w [--reason "…"]
# Deals (contrats issus d'opportunités gagnées) — lecture ; création via `opportunities deal`
pulse deals ls [--status signed] [--org <id>] [--expiring] [--search q]
pulse deals show <id>Les mutations refusent en 422 (error_code: invalid_enum_value, avec la liste
allowed) toute valeur hors énumération : un agent peut se corriger sans
consulter la doc. Une clé crm:read seule ne peut pas écrire (403).
Usage agent (non interactif)
export PULSE_TOKEN=pk_…
pulse --json tickets ls --status open # triage
pulse --json tickets take <id> # prendre le ticket
pulse --json tickets suggest <id> # brouillon sourcé KB (relecture humaine, aucun envoi)
pulse --json tickets reply <id> -m "…" --attach shot.png --as-supportBoucle type d'un agent commercial (clé pk_ d'un utilisateur au rôle commerce,
scopes crm:read + crm:write) :
export PULSE_TOKEN=pk_…
pulse --json crm today # plan de travail du jour
pulse --json prospects ls --unassigned --unconverted # nouvelles demandes de démo
pulse --json prospects take <id>
pulse --json prospects qualify <id> --decision-maker "…" --decision-maker-title DAF --auto-convert
pulse --json leads note <leadId> -m "Appel de découverte : …" --type call_log
pulse --json leads follow-up <leadId> --at +3d
pulse --json leads convert <leadId> --value 12000 --products <productId>
pulse --json opps advance <oppId>
pulse --json tasks create --opportunity <oppId> --title "Envoyer la proposition" --due tomorrow --type send_proposal
pulse --json follow-ups complete <id> --outcome meeting_booked --notes "RDV le 12"En mode --json, objets/listes sortent sur stdout ; les erreurs en JSON sur
stderr ({ "ok": false, "error": … }), code de sortie 1.
Contrat d'API
OpenAPI servi par Pulse sur GET /api/v1/docs/openapi.json. Vendoré localement
via npm run update:spec (→ openapi/pulse-api.json).
Architecture
src/
├── cli.ts # entrée Commander, --json global, wiring des commandes
├── config.ts # ~/.pulse-config.json (+ surcharges env)
├── api.ts # client axios (Bearer clé API / JWT)
├── auth.ts # login email/mot de passe → JWT
├── output.ts # bascule JSON / tables humaines
├── query.ts # mapping options → params API, dates relatives (+3d, tomorrow)
└── crm.ts # commandes CRM / commerce (prospects, leads, contacts, opportunités, tâches, relances, deals, crm)