chore(typo): retire tous les tirets cadratins/demi-cadratins + garde CI
Some checks failed
CI / Build & test (Node 24) (push) Has been cancelled
CI / Pack & boot smoke (Node 22) (push) Has been cancelled
CI / No em/en dashes (push) Has been cancelled
CI / Build & test (Node 22) (push) Has been cancelled
Deploy site (production) / build-and-deploy (push) Successful in 20s

Remplace les 547 tirets cadratins (U+2014) et demi-cadratins (U+2013) des fichiers versionnés par la ponctuation contextuelle adaptée (point médian, deux-points, virgule, parenthèses ; tiret simple pour les plages), sur 122 fichiers (appli, vitrine, doc, tests, workflows, scripts).

Ajoute le job CI « lint-dashes » (git grep -P) qui échoue si un tiret cadratin/demi-cadratin réapparaît, hors logo binaire et captures brutes du terminal (fidélité des fixtures de détection de dialogue).
This commit is contained in:
2026-07-17 16:44:00 +02:00
parent 985531a986
commit 65ef616867
122 changed files with 538 additions and 521 deletions

View File

@@ -14,7 +14,7 @@ export interface LoginResponse {
}
export interface MeResponse {
ok: true;
/** id du token de la session courante sert à marquer « courant » dans la liste des tokens. */
/** id du token de la session courante : sert à marquer « courant » dans la liste des tokens. */
tokenId: string;
tokenLabel: string;
serverVersion: string;
@@ -38,18 +38,18 @@ export interface CreateTokenRequest {
export interface CreateTokenResponse {
id: string;
label: string;
/** valeur en clair affichée une seule fois, jamais re-récupérable. */
/** valeur en clair : affichée une seule fois, jamais re-récupérable. */
token: string;
}
export interface CreateSessionRequest {
cwd: string;
/** binaire à lancer défaut "claude" ; "bash" sert aux tests d'acceptation sans quota */
/** binaire à lancer : défaut "claude" ; "bash" sert aux tests d'acceptation sans quota */
command?: 'claude' | 'bash';
}
/**
* POST /api/v1/projects crée un NOUVEAU dossier de projet `<root>/<name>` (le serveur ne crée
* POST /api/v1/projects : crée un NOUVEAU dossier de projet `<root>/<name>` (le serveur ne crée
* jamais de dossier ailleurs) puis y lance une session. Le `git init` est optionnel (case à cocher).
* Réponse : `CreateProjectResponse`.
*/
@@ -60,7 +60,7 @@ export interface CreateProjectRequest {
name: string;
/** true → `git init` dans le nouveau dossier avant la session (défaut false). */
gitInit?: boolean;
/** binaire à lancer défaut "claude" ; "bash" sert aux tests sans quota. */
/** binaire à lancer : défaut "claude" ; "bash" sert aux tests sans quota. */
command?: 'claude' | 'bash';
}
export interface CreateProjectResponse {
@@ -76,13 +76,13 @@ export interface SessionsListResponse {
export interface SessionResponse {
session: SessionSummary;
}
/** POST /sessions/hide-discovered masque tout l'historique de sessions externes visible. */
/** POST /sessions/hide-discovered : masque tout l'historique de sessions externes visible. */
export interface HideDiscoveredResponse {
/** nombre de sessions effectivement masquées. */
hidden: number;
}
// POST /sessions/:id/resume et /sessions/:id/fork (P2) : aucun corps cwd et command
// POST /sessions/:id/resume et /sessions/:id/fork (P2) : aucun corps, cwd et command
// sont TOUJOURS dérivés du :id (lu sur disque), jamais fournis par le client (cf. spike S1).
export type ResumeSessionRequest = Record<string, never>;
export type ForkSessionRequest = Record<string, never>;
@@ -134,7 +134,7 @@ export interface HookRunResult {
}
/**
* Stratégie de résolution de la branche d'un nouveau worktree :
* - `auto` (défaut) : détecte l'existence de la branche checkout si elle existe en local, suivi de
* - `auto` (défaut) : détecte l'existence de la branche, checkout si elle existe en local, suivi de
* `origin/<branch>` si elle n'existe que sur le remote, sinon création (`-b`). Robuste pour les
* groupes hétérogènes où la branche peut déjà exister dans certains dépôts mais pas d'autres.
* - `create` : force la création (`-b`), échoue si la branche existe déjà.
@@ -167,7 +167,7 @@ export interface CreateWorktreeResponse {
action: WorktreeBranchAction;
}
/** GET /api/v1/repos/:id/branches branches locales/remote pour alimenter un sélecteur de base. */
/** GET /api/v1/repos/:id/branches : branches locales/remote pour alimenter un sélecteur de base. */
export interface RepoBranchesResponse {
local: string[];
remote: string[];
@@ -175,12 +175,12 @@ export interface RepoBranchesResponse {
default: string | null;
}
/** POST /api/v1/repos/:id/worktrees/commit `git add -A` puis commit dans le worktree visé. */
/** POST /api/v1/repos/:id/worktrees/commit : `git add -A` puis commit dans le worktree visé. */
export interface CommitWorktreeRequest {
path: string;
message: string;
/**
* P7 `all` (défaut, rétrocompat) : `git add -A` + commit (tout l'arbre) ; `staged` : commit
* P7 : `all` (défaut, rétrocompat) : `git add -A` + commit (tout l'arbre) ; `staged` : commit
* de l'index uniquement (staging sélectif préalable via /stage). `amend` réécrit le dernier
* commit (refusé s'il est déjà poussé).
*/
@@ -214,7 +214,7 @@ export interface FileChange {
/** ancien chemin pour un renommage/copie, sinon absent. */
renamedFrom?: string;
}
/** GET /api/v1/repos/:id/worktrees/changes?path= liste des fichiers modifiés d'un worktree. */
/** GET /api/v1/repos/:id/worktrees/changes?path= : liste des fichiers modifiés d'un worktree. */
export interface WorktreeChangesResponse {
repoId: string;
path: string;
@@ -222,7 +222,7 @@ export interface WorktreeChangesResponse {
/** true si la liste a été bornée (trop de changements). */
truncated: boolean;
}
/** GET /api/v1/repos/:id/worktrees/diff?path=&file=&staged= diff unifié d'un fichier. */
/** GET /api/v1/repos/:id/worktrees/diff?path=&file=&staged= : diff unifié d'un fichier. */
export interface FileDiffResponse {
path: string;
file: string;
@@ -233,19 +233,19 @@ export interface FileDiffResponse {
/** texte du diff unifié git (vide si binaire ou tooLarge). */
diff: string;
}
/** GET /api/v1/repos/:id/files/content?wt=&path= contenu d'un fichier (pour l'éditeur Monaco). */
/** GET /api/v1/repos/:id/files/content?wt=&path= : contenu d'un fichier (pour l'éditeur Monaco). */
export interface FileContentResponse {
/** chemin relatif au worktree (POSIX). */
path: string;
content: string;
encoding: 'utf-8';
size: number;
/** mtime du fichier en ms (st.mtimeMs) base du garde-fou de conflit d'édition (P8). */
/** mtime du fichier en ms (st.mtimeMs) : base du garde-fou de conflit d'édition (P8). */
mtime: number;
/** langage déduit de l'extension (pour Monaco), si reconnu. */
language?: string;
}
/** PUT /api/v1/repos/:id/files/content écriture d'un fichier (borné au worktree). */
/** PUT /api/v1/repos/:id/files/content : écriture d'un fichier (borné au worktree). */
export interface WriteFileRequest {
/** chemin absolu du worktree. */
wt: string;
@@ -258,10 +258,10 @@ export interface WriteFileRequest {
export interface WriteFileResponse {
ok: true;
size: number;
/** mtime (ms) du fichier après écriture le client le réutilise comme nouvelle base. */
/** mtime (ms) du fichier après écriture : le client le réutilise comme nouvelle base. */
mtime: number;
}
/** P7 corps commun des mutations de staging/discard. */
/** P7 : corps commun des mutations de staging/discard. */
export interface WorktreeFilesRequest {
path: string;
/** chemins relatifs au worktree. */
@@ -271,21 +271,21 @@ export interface WorktreeFilesRequest {
export interface DiscardFilesRequest extends WorktreeFilesRequest {
includeUntracked?: boolean;
}
/** POST /api/v1/repos/:id/worktrees/fetch `git fetch --all --prune`. */
/** POST /api/v1/repos/:id/worktrees/fetch : `git fetch --all --prune`. */
export interface FetchWorktreeRequest {
path: string;
}
/** POST /api/v1/repos/:id/worktrees/pull `git pull` (ff-only par défaut). */
/** POST /api/v1/repos/:id/worktrees/pull : `git pull` (ff-only par défaut). */
export interface PullWorktreeRequest {
path: string;
mode?: 'ff-only' | 'rebase';
}
/** POST /api/v1/repos/:id/worktrees/push pousse la branche du worktree (upstream auto si absent). */
/** POST /api/v1/repos/:id/worktrees/push : pousse la branche du worktree (upstream auto si absent). */
export interface PushWorktreeRequest {
path: string;
}
/**
* POST /api/v1/repos/:id/worktrees/promote « passer en principal » : la branche du worktree devient
* POST /api/v1/repos/:id/worktrees/promote : « passer en principal » : la branche du worktree devient
* le checkout principal du dépôt (le worktree est supprimé, l'ancienne branche principale est conservée).
*/
export interface PromoteWorktreeRequest {
@@ -300,12 +300,12 @@ export interface AdoptWorktreeRequest {
}
/**
* POST /api/v1/repos/:id/session lance UNE session dans le checkout principal du repo
* POST /api/v1/repos/:id/session : lance UNE session dans le checkout principal du repo
* (`repo.path`) pour « bosser sur la branche principale » sans créer de worktree.
* Réponse : `SessionResponse`.
*/
export interface StartRepoSessionRequest {
/** binaire à lancer défaut "claude" ; "bash" sert aux tests sans quota. */
/** binaire à lancer : défaut "claude" ; "bash" sert aux tests sans quota. */
command?: 'claude' | 'bash';
/** si fourni : crée/bascule cette branche dans le checkout principal avant la session. */
branch?: string;
@@ -360,15 +360,15 @@ export interface FsEntry {
path: string;
/** présent (true) uniquement en mode markRepos quand le dossier est un dépôt git */
isRepo?: boolean;
/** P7 présent (true) en mode includeFiles quand l'entrée est un fichier (pas un dossier) */
/** P7 : présent (true) en mode includeFiles quand l'entrée est un fichier (pas un dossier) */
isFile?: boolean;
}
export interface FsListResponse {
/** chemin absolu listé (normalisé) */
path: string;
/** parent (null à la racine `/`) pour le bouton « remonter » */
/** parent (null à la racine `/`) : pour le bouton « remonter » */
parent: string | null;
/** home de l'utilisateur côté serveur point de départ par défaut */
/** home de l'utilisateur côté serveur : point de départ par défaut */
home: string;
/** sous-dossiers uniquement, triés sans tenir compte de la casse */
entries: FsEntry[];
@@ -388,7 +388,7 @@ export interface PushUnsubscribeRequest {
}
// ---- Réglages & info serveur (onglet Réglages) ----
/** Config runtime non sensible du daemon lecture seule (changée via flags CLI + redémarrage). */
/** Config runtime non sensible du daemon : lecture seule (changée via flags CLI + redémarrage). */
export interface ServerInfo {
version: string;
port: number;
@@ -413,22 +413,22 @@ export interface ClaudeBinDiagnostic {
ok: boolean;
}
export interface SettingsResponse {
/** réglages modifiables à chaud (allow-list serveur jamais les secrets). Cf. SettingsBroadcast. */
/** réglages modifiables à chaud (allow-list serveur, jamais les secrets). Cf. SettingsBroadcast. */
settings: SettingsBroadcast;
server: ServerInfo;
}
export interface UpdateSettingsRequest {
/** racines absolues à scanner (chemins normalisés, ≤ 16) ; remplace la liste. */
scanRoots?: string[];
/** intervalle du re-scan périodique en minutes (01440 ; 0 désactive). */
/** intervalle du re-scan périodique en minutes (0-1440 ; 0 désactive). */
scanIntervalMin?: number;
/** chemin absolu du binaire `claude` (fichier exécutable) ; '' pour réinitialiser à l'auto-détection. */
claudeBinPath?: string;
/** override de la racine ~/.claude (répertoire existant) ; '' pour réinitialiser au défaut. */
claudeHome?: string;
/** auto-archivage des sessions terminées après N jours (0 = jamais ; sinon 13650). */
/** auto-archivage des sessions terminées après N jours (0 = jamais ; sinon 1-3650). */
retentionDays?: number;
/** purge définitive après N jours (0 = désactivée ; sinon 13650). */
/** purge définitive après N jours (0 = désactivée ; sinon 1-3650). */
purgeDays?: number;
}
@@ -505,7 +505,7 @@ export interface CreateGitCredentialRequest {
/** instance self-hosted (Gitea/GitLab) ; absent = service public (github.com / gitlab.com). */
baseUrl?: string;
username?: string;
/** PAT ou app password chiffré côté serveur (SecretBox), jamais relu. */
/** PAT ou app password : chiffré côté serveur (SecretBox), jamais relu. */
secret?: string;
}
export interface UpdateGitCredentialRequest {
@@ -546,13 +546,13 @@ export interface CloneRequest {
credentialId: string;
/** URL HTTPS du dépôt à cloner. */
remoteUrl: string;
/** dossier de destination (sous une racine de scan) créé par le clone, refus si existant. */
/** dossier de destination (sous une racine de scan) : créé par le clone, refus si existant. */
dest: string;
}
export interface CloneStartResponse {
operationId: string;
}
/** État d'un clone (GET /repos/clone/:id) même forme que le push WS clone_update. */
/** État d'un clone (GET /repos/clone/:id) : même forme que le push WS clone_update. */
export interface CloneStatusResponse {
operation: CloneOperation;
}

View File

@@ -1,4 +1,4 @@
// Protocole WebSocket Arboretum une connexion multiplexée par client.
// Protocole WebSocket Arboretum : une connexion multiplexée par client.
// Messages de contrôle : frames TEXTE JSON. Sortie terminal : frames BINAIRES
// (un chunk PTY peut couper un caractère UTF-8 en frontière de frame ; le
// décodage incombe à xterm.write(Uint8Array) côté client, jamais au transport).
@@ -11,7 +11,7 @@ export const BINARY_FRAME = {
HEADER_BYTES: 5,
/** serveur → client : sortie terminal */
OUTPUT: 0x01,
/** serveur → client : resync le client doit reset son terminal avant d'écrire le payload */
/** serveur → client : resync, le client doit reset son terminal avant d'écrire le payload */
RESYNC: 0x02,
} as const;
@@ -53,7 +53,7 @@ export const FLOW = {
/**
* Replay à l'attach : reset terminal + queue du ring (l'écran TUI se repeint en continu).
* 1 Mo (≈ 1015k lignes) pour permettre de remonter une vraie conversation Claude dans le terminal ;
* 1 Mo (≈ 10-15k lignes) pour permettre de remonter une vraie conversation Claude dans le terminal ;
* reste < LAGGING_BYTES (pas de faux lagging) et bien dans RING_CAPACITY.
*/
export const REPLAY_TAIL_BYTES = 1024 * 1024;
@@ -160,7 +160,7 @@ export interface WorktreeGitStatus {
behind: number;
dirtyCount: number;
upstream: string | null;
// ---- Champs additifs P7 (optionnels, rétrocompat) compteurs bon marché calculés dans le
// ---- Champs additifs P7 (optionnels, rétrocompat) : compteurs bon marché calculés dans le
// même passage `status --porcelain=v2` que dirtyCount. La liste détaillée des changements
// (FileChange[]) n'est JAMAIS diffusée ici : elle est servie à la demande (REST) et poussée
// uniquement aux clients qui « regardent » le worktree (voir `worktree_changes`).
@@ -231,7 +231,7 @@ export type CloneState = 'pending' | 'running' | 'done' | 'error';
export interface CloneOperation {
id: string;
state: CloneState;
/** progression 0100 si git la communique, sinon null. */
/** progression 0-100 si git la communique, sinon null. */
progress: number | null;
/** phase courante rapportée par git (« Receiving objects », « Resolving deltas »…). */
phase: string | null;
@@ -255,7 +255,7 @@ export type ClientMessage =
| { type: 'resize'; channel: number; cols: number; rows: number }
| { type: 'ack'; channel: number; bytes: number }
| { type: 'sub'; topics: Array<'sessions' | 'worktrees' | 'groups' | 'settings' | 'clones'> }
// P7 abonnement ciblé au détail d'un worktree (diff/statut fin) : on ne pousse le détail
// P7 : abonnement ciblé au détail d'un worktree (diff/statut fin) : on ne pousse le détail
// qu'aux connexions qui « regardent » ce worktree (clé = repoId + path), indépendamment du
// topic global 'worktrees' (qui ne transporte que les compteurs légers).
| { type: 'watch'; repoId: string; path: string }
@@ -270,20 +270,20 @@ export type ServerMessage =
| { type: 'control_changed'; channel: number; controlling: boolean }
| { type: 'session_update'; session: SessionSummary }
| { type: 'session_exit'; sessionId: string; exitCode: number | null; signal: number | null }
// P10 une session managée vient d'être archivée (auto par ancienneté ou manuellement). Signal
// P10 : une session managée vient d'être archivée (auto par ancienneté ou manuellement). Signal
// léger : le client met à jour son row (badge archived) et le retire si « Show archived » est off.
| { type: 'session_archived'; sessionId: string }
// P11 un réglage a changé (PATCH /settings) : on diffuse le snapshot non sensible aux abonnés
// P11 : un réglage a changé (PATCH /settings) : on diffuse le snapshot non sensible aux abonnés
// du topic 'settings' pour que tous les clients (et onglets) se synchronisent sans polling.
| { type: 'settings_update'; settings: SettingsBroadcast }
// P12 progression/fin/erreur d'un clone, poussé aux abonnés du topic 'clones'. L'état complet
// P12 : progression/fin/erreur d'un clone, poussé aux abonnés du topic 'clones'. L'état complet
// (state) discrimine progress/done/error en un seul message.
| { type: 'clone_update'; operation: CloneOperation }
| { type: 'repo_update'; repo: RepoSummary }
| { type: 'repo_removed'; repoId: string }
| { type: 'worktree_update'; repoId: string; worktree: WorktreeSummary }
| { type: 'worktree_removed'; repoId: string; path: string }
// P7 signal léger « le détail (diff/fichiers modifiés) de ce worktree a changé, refais un
// P7 : signal léger « le détail (diff/fichiers modifiés) de ce worktree a changé, refais un
// GET /changes ou /diff ». Envoyé UNIQUEMENT aux connexions ayant `watch`é cette clé. On ne
// pousse pas le diff complet dans la frame (taille/flow control) : le client re-fetch en REST.
| { type: 'worktree_changes'; repoId: string; path: string }