Debugger
catnip debug suspend la VM sur des breakpoints, expose les variables et reprend l'exécution à la demande. La console,
l'API Python et le serveur MCP pilotent le même mécanisme.
Le debugger observe une VM suspendue et change son futur avec une commande. Heisenberg avait prévu le problème, pas l'alias
c.
CLI
# Script, plusieurs breakpoints ou code inline
catnip debug -b 5 script.cat
catnip debug -b 3 -b 7 script.cat
catnip debug -c "x = 10; y = x * 2; y + 1" -b 1
-b, --break LINEajoute un breakpoint et peut être répété ;-c, --command CODEdébogue du code inline à la place d'un fichier.
Au point d'arrêt, le prompt (catnip-dbg:L5) > accepte :
| Commande | Alias | Effet |
|---|---|---|
continue |
c |
reprendre jusqu'au prochain arrêt |
step |
s |
entrer dans l'appel suivant |
next |
n |
avancer sans entrer dans les appels |
out |
o |
sortir de la fonction courante |
break N |
b N |
ajouter un breakpoint |
rbreak N |
rb N |
retirer un breakpoint |
print EXPR |
p EXPR |
évaluer dans le scope courant |
vars |
v |
afficher les variables locales |
list |
l |
afficher le source voisin |
backtrace |
bt |
afficher la pile d'appels |
repl |
ouvrir le sous-mode REPL | |
quit |
q |
arrêter l'exécution |
help |
h |
afficher l'aide |
Une ligne vide répète le dernier step.
⇒ catnip debug -b 3 factorial.cat
Paused at line 3, col 5
(catnip-dbg:L3) > v
n = 5
(catnip-dbg:L3) > p n * 2
= 10
(catnip-dbg:L3) > c
Execution finished. Result: 120
Quand le programme échoue au lieu de terminer, la session rend l'erreur exactement comme l'exécution ordinaire — même pile d'appels, même type, même message, même extrait — précédée de l'étiquette de l'événement :
(catnip-dbg:L3) > c
Execution error: Traceback (most recent call last):
File "/chemin/vers/script.cat", line 7, in outer
NameError: Name 'nope' is not defined
Did you mean 'open'?
2 | x + nope
| ^
backtrace reste la commande pour lire la pile pendant une pause ; celle-ci est celle du point d'échec.
Les deux frontends — console et session programmatique, celle qu'utilisent l'API Python et les tools MCP — passent par le même rendu que le CLI. Un débogueur qui rapporte autrement que le programme qu'il débogue oblige à traduire entre les deux.
Sous-mode REPL
repl ouvre un interpréteur dans le frame suspendu. Les locales existantes sont visibles et les nouvelles définitions
restent disponibles jusqu'à la reprise :
(catnip-dbg:L3) > repl
(repl:L3) => n
5
(repl:L3) => y = n * 2
(repl:L3) => y + 1
11
Les commandes de mouvement reprennent directement la VM. /exit ou une ligne vide revient au prompt du debugger. Les
alias courts sont prioritaires sur les noms de variables ; p v évalue une variable nommée v.
Breakpoints dans le source
breakpoint() émet un opcode dédié :
x = 10
breakpoint()
y = x * 2
Un breakpoint -b N cible la première instruction associée à la ligne ; breakpoint() fixe directement l'emplacement
pendant la compilation. Les deux formes déclenchent le même événement de pause.
API Python
from catnip import Catnip
from catnip.debug import DebugSession
source = """
x = 10
y = x * 2
y + 1
"""
session = DebugSession(Catnip(), source)
session.add_breakpoint(3)
session.start(blocking=False)
event_type, pause = session.wait_for_event(timeout=10)
print(pause.locals)
session.send_command('continue')
event_type, result = session.wait_for_event(timeout=10)
API principale :
add_breakpoint(line)etremove_breakpoint(line);start(blocking=False);wait_for_event(timeout), qui retournepaused,finishedouerror; letimeoutest un nombre de secondes fini et non négatif, sans quoi l'appel lèveValueError— et la session reste utilisable, le refus tombant avant l'attente ;send_command(action)aveccontinue,step_into,step_overoustep_out;stateetlast_pause.
MCP
| Tool | Effet |
|---|---|
debug_start |
démarrer une session et attendre le premier arrêt |
debug_continue |
reprendre jusqu'au prochain événement |
debug_step |
avancer en mode into, over ou out |
debug_inspect |
lire les variables locales |
debug_eval |
évaluer une expression dans le scope |
debug_breakpoint |
ajouter ou retirer un breakpoint |
Chaque debug_start crée une session indépendante. Le client conserve le session_id pour les appels suivants.
Contrat d'exécution
La VM s'exécute dans un thread et échange événements et commandes avec le frontend. Les positions bytecode sont reliées aux offsets UTF-8 du source afin que CLI, API et MCP utilisent les mêmes numéros de ligne. Pendant une pause, la VM libère le GIL avant d'attendre la commande suivante, ce qui autorise l'évaluation depuis le frontend Python.
Limites
- pas de breakpoint conditionnel ; utiliser
if condition { breakpoint() }; - pas de watchpoint sur mutation de variable ;
- après cinq attentes de 60 secondes sans commande, la VM reprend pour ne pas conserver une session suspendue ;
- debugger disponible uniquement en mode VM, sélectionné automatiquement pour la session.
Après cinq minutes sans commande, la VM reprend. Le silence a un timeout.