palabre 0.7.0 → 0.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -7,26 +7,26 @@
7
7
  <a href="https://palab.re"><img src="https://img.shields.io/badge/docs-palab.re-18181B?logo=netlify&logoColor=7C3AED" alt="Documentation"></a>
8
8
  </p>
9
9
 
10
- ![PALABRE](docs/assets/palabre-logo-text-og.png)
10
+ ![Palabre CLI orchestrating a debate between AI agents](docs/assets/palabre-cli-orchestre-debates-between-AI-agents.png)
11
11
 
12
- [Français](#français) | [English](#english)
12
+ [English](#english) | [Français](#français)
13
13
 
14
- ## Français
14
+ ## English
15
15
 
16
- PALABRE est un orchestrateur CLI qui fait dialoguer plusieurs agents IA installés sur votre machine : Claude Code, Codex CLI, Gemini CLI, Antigravity CLI, OpenCode et Ollama.
16
+ PALABRE is a CLI/TUI orchestrator that lets multiple AI agents installed on your machine work together: Claude Code, Codex CLI, Antigravity CLI, OpenCode, Mistral Vibe, and Ollama.
17
17
 
18
- Il ne remplace pas vos outils : il les pilote. Vous gardez vos abonnements, vos modèles par défaut, vos habitudes de terminal et vos fichiers en local. PALABRE exporte ensuite le débat en Markdown.
18
+ It does not replace your tools: it drives them. You keep your subscriptions, default models, terminal habits, and local files. PALABRE can run a debate between two agents or an Ask request where several agents answer independently before a comparative summary. It then exports the session as Markdown.
19
19
 
20
20
  ### Documentation
21
21
 
22
22
  - https://palab.re
23
23
  - https://palabre.netlify.app
24
24
 
25
- Pages utiles : [Installation](https://palab.re/fr/get-started/installation), [Configuration](https://palab.re/fr/get-started/configuration), [Premier débat](https://palab.re/fr/get-started/first-debate), [Référence CLI](https://palab.re/fr/reference/cli), [Dépannage](https://palab.re/fr/troubleshooting), [Roadmap](https://palab.re/fr/roadmap).
25
+ Useful pages: [Installation](https://palab.re/en/get-started/installation), [Configuration](https://palab.re/en/get-started/configuration), [First session](https://palab.re/en/get-started/first-debate), [CLI reference](https://palab.re/en/reference/cli), [Troubleshooting](https://palab.re/en/troubleshooting), [Roadmap](https://palab.re/en/roadmap).
26
26
 
27
27
  ### Installation
28
28
 
29
- Prérequis : Node.js 20 ou plus, et au moins deux agents déjà installés/authentifiés si vous voulez les faire débattre.
29
+ Requirements: Node.js 20 or newer, and at least two already installed/authenticated agents if you want them to debate.
30
30
 
31
31
  ```bash
32
32
  npm install -g palabre
@@ -34,53 +34,69 @@ palabre --version
34
34
  palabre --help
35
35
  ```
36
36
 
37
- ### Démarrage rapide
37
+ ### Quick Start
38
38
 
39
39
  ```bash
40
- palabre init
41
40
  palabre doctor
42
- palabre new
41
+ palabre
43
42
  ```
44
43
 
45
- Exemples directs :
44
+ Direct examples:
46
45
 
47
46
  ```bash
48
- palabre codex-claude "Critique ce plan" -t 4
49
- palabre -s "Compare ces deux approches" -t 2
50
- palabre codex-claude "Relis cette architecture" --context src docs
51
- palabre claude-ollama "Critique ce fichier" --files README.md
47
+ palabre codex-claude "Review this plan" -t 4
48
+ palabre ask "Compare these two approaches" --agents codex claude opencode
49
+ palabre -s "Compare these two approaches" -t 2
50
+ palabre codex-claude "Review this architecture" --context src docs
51
+ palabre claude-ollama "Review this file" --files README.md
52
52
  palabre codex-claude "Preview" --context src --show-prompt
53
53
  palabre context scan src docs --json
54
54
  ```
55
55
 
56
- ### Agents supportés
56
+ In an interactive terminal, Palabre uses the TUI by default. `palabre` opens the home screen, creates the global config on first launch when needed, and refreshes detected known agents before showing the UI. `/ask` switches from debate to independent answers, `/agents` and `/roles` help you choose the active setup, `/history` shows recent exports, and `/home` returns to the home screen. `--terminal` forces the older raw rendering suitable for logs. `palabre init` remains available for explicit setup, especially with `--local`.
57
+
58
+ ### Supported Agents
57
59
 
58
60
  - Claude Code via `claude --print`
59
61
  - Codex CLI via `codex exec`
60
- - Gemini CLI via `gemini --prompt -`
61
- - Antigravity CLI via `agy --print` en pseudo-terminal
62
+ - Antigravity CLI via `agy --print` in a pseudo-terminal
62
63
  - OpenCode via `opencode run`
63
- - Ollama via l'API locale HTTP
64
+ - Mistral Vibe via `vibe --output text --trust --prompt`
65
+ - Ollama via the local HTTP API
64
66
 
65
- PALABRE ne liste pas les modèles : ils changent souvent et dépendent de chaque CLI ou compte utilisateur. `--model-a`, `--model-b` et `--summary-model` transmettent simplement la valeur brute à l'agent concerné.
67
+ PALABRE does not list models: they change often and depend on each CLI or user account. `--model-a`, `--model-b`, and `--summary-model` simply pass the raw value to the selected agent.
66
68
 
67
- ### Intégrations
69
+ ### Integrations
68
70
 
69
- PALABRE expose des sorties JSON versionnées pour les clients externes :
71
+ PALABRE exposes versioned JSON outputs for external clients:
70
72
 
71
- - `palabre presets --json` pour lire les paires d'agents disponibles ;
72
- - `palabre context scan --json` pour prévisualiser le contexte que `--context` retiendrait ;
73
- - `--renderer ndjson` ou `--json` pour suivre un débat événement par événement.
73
+ - `palabre presets --json` to read available agent pairs;
74
+ - `palabre context scan --json` to preview the context `--context` would retain;
75
+ - `--renderer ndjson` or `--json` to follow a debate event by event.
74
76
 
75
- Le flux NDJSON v1 est traité comme une API publique d'intégration. Les ajouts compatibles se font sans casser v1 ; les changements cassants doivent changer le champ `v`.
77
+ The NDJSON v1 stream is treated as a public integration API. Compatible additions do not break v1; breaking changes must change the `v` field.
76
78
 
77
- ### Confidentialité
79
+ ### Skill for AI agents
78
80
 
79
- PALABRE tourne localement et n'envoie aucune donnée à un serveur appartenant à PALABRE. Les données envoyées aux agents dépendent des outils que vous utilisez : vérifiez les politiques de confidentialité de Claude Code, Codex CLI, Gemini CLI, Antigravity CLI, OpenCode, Ollama ou de tout autre agent configuré.
81
+ PALABRE ships a ready-to-use skill that teaches an AI agent when and how to run Palabre sessions. It follows the open [agentskills.io](https://agentskills.io) standard, so it is portable across Hermes Agent, Claude, Codex, and any skills-compatible agent.
80
82
 
81
- Si un agent échoue pendant le débat ou la synthèse, PALABRE conserve l'export Markdown partiel avec une section d'interruption quand c'est possible.
83
+ Install it in **Hermes Agent**:
82
84
 
83
- ### Développement local
85
+ ```bash
86
+ hermes skills install JuReyms/Palabre/skills/palabre
87
+ ```
88
+
89
+ For other agents (Claude desktop, Claude Code…), see the docs: [Palabre skill](https://palab.re/en/get-started/skill).
90
+
91
+ The skill is versioned under [skills/palabre](./skills/palabre).
92
+
93
+ ### Privacy
94
+
95
+ PALABRE runs locally and does not send data to a PALABRE-owned server. Data sent to agents depends on the tools you use: check the privacy policies of Claude Code, Codex CLI, Antigravity CLI, OpenCode, Mistral Vibe, Ollama, or any custom agent you configure.
96
+
97
+ If an agent fails during the debate or final summary, PALABRE keeps the partial Markdown export with an interruption section whenever possible.
98
+
99
+ ### Local Development
84
100
 
85
101
  ```bash
86
102
  git clone https://github.com/JuReyms/Palabre.git
@@ -91,32 +107,34 @@ pnpm link --global
91
107
  palabre --version
92
108
  ```
93
109
 
94
- Commandes utiles : `pnpm check`, `pnpm test`, `pnpm build`.
110
+ Useful commands: `pnpm check`, `pnpm test`, `pnpm build`.
95
111
 
96
- Avant une publication, `pnpm smoke:real-presets -- --keep-going` lance des débats réels sur les presets prioritaires disponibles afin de vérifier le flux complet agent → NDJSON → export. Ce smoke test appelle de vraies CLIs IA et peut consommer des quotas ; il n'est donc pas lancé par `pnpm test`.
112
+ Before publishing, `pnpm smoke:real-presets -- --keep-going` runs real debates for the available priority presets to validate the full agent → NDJSON → export flow. This smoke test calls real AI CLIs and may consume quota, so it is not part of `pnpm test`.
97
113
 
98
- Roadmap publique : [docs/guide/fr/roadmap.md](./docs/guide/fr/roadmap.md). Changements : [CHANGELOG.md](./CHANGELOG.md). Guide agents/contributeurs : [AGENTS.md](./AGENTS.md).
114
+ Public roadmap: [docs/guide/fr/roadmap.md](./docs/guide/fr/roadmap.md). Changes: [CHANGELOG.md](./CHANGELOG.md). Agent/contributor guide: [AGENTS.md](./AGENTS.md).
99
115
 
100
- ### Licence
116
+ ### License
101
117
 
102
- MIT. Voir [LICENSE](./LICENSE).
118
+ MIT. See [LICENSE](./LICENSE).
103
119
 
104
- ## English
120
+ ![PALABRE](docs/assets/palabre-logo-text-og.png)
121
+
122
+ ## Français
105
123
 
106
- PALABRE is a CLI orchestrator that lets multiple AI agents installed on your machine talk to each other: Claude Code, Codex CLI, Gemini CLI, Antigravity CLI, OpenCode, and Ollama.
124
+ PALABRE est un orchestrateur CLI/TUI qui fait travailler plusieurs agents IA installés sur votre machine : Claude Code, Codex CLI, Antigravity CLI, OpenCode, Mistral Vibe et Ollama.
107
125
 
108
- It does not replace your tools: it drives them. You keep your subscriptions, default models, terminal habits, and local files. PALABRE then exports the debate as Markdown.
126
+ Il ne remplace pas vos outils : il les pilote. Vous gardez vos abonnements, vos modèles par défaut, vos habitudes de terminal et vos fichiers en local. PALABRE peut lancer un débat entre deux agents ou une demande Ask où plusieurs agents répondent indépendamment avant une synthèse comparative. Il exporte ensuite la session en Markdown.
109
127
 
110
128
  ### Documentation
111
129
 
112
130
  - https://palab.re
113
131
  - https://palabre.netlify.app
114
132
 
115
- Useful pages: [Installation](https://palab.re/en/get-started/installation), [Configuration](https://palab.re/en/get-started/configuration), [First debate](https://palab.re/en/get-started/first-debate), [CLI reference](https://palab.re/en/reference/cli), [Troubleshooting](https://palab.re/en/troubleshooting), [Roadmap](https://palab.re/en/roadmap).
133
+ Pages utiles : [Installation](https://palab.re/fr/get-started/installation), [Configuration](https://palab.re/fr/get-started/configuration), [Première session](https://palab.re/fr/get-started/first-debate), [Référence CLI](https://palab.re/fr/reference/cli), [Dépannage](https://palab.re/fr/troubleshooting), [Roadmap](https://palab.re/fr/roadmap).
116
134
 
117
135
  ### Installation
118
136
 
119
- Requirements: Node.js 20 or newer, and at least two already installed/authenticated agents if you want them to debate.
137
+ Prérequis : Node.js 20 ou plus, et au moins deux agents déjà installés/authentifiés si vous voulez les faire débattre.
120
138
 
121
139
  ```bash
122
140
  npm install -g palabre
@@ -124,53 +142,69 @@ palabre --version
124
142
  palabre --help
125
143
  ```
126
144
 
127
- ### Quick Start
145
+ ### Démarrage rapide
128
146
 
129
147
  ```bash
130
- palabre init
131
148
  palabre doctor
132
- palabre new
149
+ palabre
133
150
  ```
134
151
 
135
- Direct examples:
152
+ Exemples directs :
136
153
 
137
154
  ```bash
138
- palabre codex-claude "Review this plan" -t 4
139
- palabre -s "Compare these two approaches" -t 2
140
- palabre codex-claude "Review this architecture" --context src docs
141
- palabre claude-ollama "Review this file" --files README.md
155
+ palabre codex-claude "Critique ce plan" -t 4
156
+ palabre ask "Compare ces deux approches" --agents codex claude opencode
157
+ palabre -s "Compare ces deux approches" -t 2
158
+ palabre codex-claude "Relis cette architecture" --context src docs
159
+ palabre claude-ollama "Critique ce fichier" --files README.md
142
160
  palabre codex-claude "Preview" --context src --show-prompt
143
161
  palabre context scan src docs --json
144
162
  ```
145
163
 
146
- ### Supported Agents
164
+ Dans un terminal interactif, Palabre utilise l'interface TUI par défaut. `palabre` ouvre l'accueil, crée la config globale au premier lancement si nécessaire, et rafraîchit les agents connus détectés avant d'afficher l'interface. `/ask` passe du débat aux réponses indépendantes, `/agents` et `/roles` aident à choisir la configuration courante, `/history` affiche les derniers exports, et `/home` revient à l'accueil. `--terminal` force l'ancien rendu brut adapté aux logs. `palabre init` reste disponible pour un setup explicite, notamment avec `--local`.
165
+
166
+ ### Agents supportés
147
167
 
148
168
  - Claude Code via `claude --print`
149
169
  - Codex CLI via `codex exec`
150
- - Gemini CLI via `gemini --prompt -`
151
- - Antigravity CLI via `agy --print` in a pseudo-terminal
170
+ - Antigravity CLI via `agy --print` en pseudo-terminal
152
171
  - OpenCode via `opencode run`
153
- - Ollama via the local HTTP API
172
+ - Mistral Vibe via `vibe --output text --trust --prompt`
173
+ - Ollama via l'API locale HTTP
154
174
 
155
- PALABRE does not list models: they change often and depend on each CLI or user account. `--model-a`, `--model-b`, and `--summary-model` simply pass the raw value to the selected agent.
175
+ PALABRE ne liste pas les modèles : ils changent souvent et dépendent de chaque CLI ou compte utilisateur. `--model-a`, `--model-b` et `--summary-model` transmettent simplement la valeur brute à l'agent concerné.
156
176
 
157
- ### Integrations
177
+ ### Intégrations
158
178
 
159
- PALABRE exposes versioned JSON outputs for external clients:
179
+ PALABRE expose des sorties JSON versionnées pour les clients externes :
160
180
 
161
- - `palabre presets --json` to read available agent pairs;
162
- - `palabre context scan --json` to preview the context `--context` would retain;
163
- - `--renderer ndjson` or `--json` to follow a debate event by event.
181
+ - `palabre presets --json` pour lire les paires d'agents disponibles ;
182
+ - `palabre context scan --json` pour prévisualiser le contexte que `--context` retiendrait ;
183
+ - `--renderer ndjson` ou `--json` pour suivre un débat événement par événement.
164
184
 
165
- The NDJSON v1 stream is treated as a public integration API. Compatible additions do not break v1; breaking changes must change the `v` field.
185
+ Le flux NDJSON v1 est traité comme une API publique d'intégration. Les ajouts compatibles se font sans casser v1 ; les changements cassants doivent changer le champ `v`.
166
186
 
167
- ### Privacy
187
+ ### Skill pour agents IA
168
188
 
169
- PALABRE runs locally and does not send data to a PALABRE-owned server. Data sent to agents depends on the tools you use: check the privacy policies of Claude Code, Codex CLI, Gemini CLI, Antigravity CLI, OpenCode, Ollama, or any custom agent you configure.
189
+ PALABRE fournit un skill prêt à l'emploi qui apprend à un agent IA quand et comment lancer des sessions Palabre. Il suit le standard ouvert [agentskills.io](https://agentskills.io) : il est donc portable entre Hermes Agent, Claude, Codex et tout agent compatible skills.
170
190
 
171
- If an agent fails during the debate or final summary, PALABRE keeps the partial Markdown export with an interruption section whenever possible.
191
+ Installation dans **Hermes Agent** :
172
192
 
173
- ### Local Development
193
+ ```bash
194
+ hermes skills install JuReyms/Palabre/skills/palabre
195
+ ```
196
+
197
+ Pour les autres agents (Claude desktop, Claude Code…), voir la doc : [Skill Palabre](https://palab.re/fr/get-started/skill).
198
+
199
+ Le skill est versionné dans [skills/palabre](./skills/palabre).
200
+
201
+ ### Confidentialité
202
+
203
+ PALABRE tourne localement et n'envoie aucune donnée à un serveur appartenant à PALABRE. Les données envoyées aux agents dépendent des outils que vous utilisez : vérifiez les politiques de confidentialité de Claude Code, Codex CLI, Antigravity CLI, OpenCode, Mistral Vibe, Ollama ou de tout autre agent configuré.
204
+
205
+ Si un agent échoue pendant le débat ou la synthèse, PALABRE conserve l'export Markdown partiel avec une section d'interruption quand c'est possible.
206
+
207
+ ### Développement local
174
208
 
175
209
  ```bash
176
210
  git clone https://github.com/JuReyms/Palabre.git
@@ -181,12 +215,12 @@ pnpm link --global
181
215
  palabre --version
182
216
  ```
183
217
 
184
- Useful commands: `pnpm check`, `pnpm test`, `pnpm build`.
218
+ Commandes utiles : `pnpm check`, `pnpm test`, `pnpm build`.
185
219
 
186
- Before publishing, `pnpm smoke:real-presets -- --keep-going` runs real debates for the available priority presets to validate the full agent → NDJSON → export flow. This smoke test calls real AI CLIs and may consume quota, so it is not part of `pnpm test`.
220
+ Avant une publication, `pnpm smoke:real-presets -- --keep-going` lance des débats réels sur les presets prioritaires disponibles afin de vérifier le flux complet agent → NDJSON → export. Ce smoke test appelle de vraies CLIs IA et peut consommer des quotas ; il n'est donc pas lancé par `pnpm test`.
187
221
 
188
- Public roadmap: [docs/guide/fr/roadmap.md](./docs/guide/fr/roadmap.md). Changes: [CHANGELOG.md](./CHANGELOG.md). Agent/contributor guide: [AGENTS.md](./AGENTS.md).
222
+ Roadmap publique : [docs/guide/fr/roadmap.md](./docs/guide/fr/roadmap.md). Changements : [CHANGELOG.md](./CHANGELOG.md). Guide agents/contributeurs : [AGENTS.md](./AGENTS.md).
189
223
 
190
- ### License
224
+ ### Licence
191
225
 
192
- MIT. See [LICENSE](./LICENSE).
226
+ MIT. Voir [LICENSE](./LICENSE).
@@ -82,7 +82,7 @@ export class CliPtyAdapter {
82
82
  return;
83
83
  }
84
84
  const content = cleanTerminalOutput(output);
85
- if (exitCode && exitCode !== 0 && !content) {
85
+ if (exitCode && exitCode !== 0) {
86
86
  reject(createPtyExitError(this.name, exitCode, output));
87
87
  return;
88
88
  }
@@ -4,7 +4,7 @@ import { formatAgentPrompt } from "../prompt.js";
4
4
  import { DEFAULT_MAX_OUTPUT_BYTES, DEFAULT_TIMEOUT_MS, withModelArgs } from "./cli-shared.js";
5
5
  import { cleanTerminalOutput } from "./terminal.js";
6
6
  /**
7
- * Adapter pour les CLIs batch (Codex, Claude, Gemini…).
7
+ * Adapter pour les CLIs batch (Codex, Claude, OpenCode, Vibe...).
8
8
  * Lance un sous-processus, injecte le prompt via stdin ou argument, capture stdout.
9
9
  * Garantit : rejection des sorties vides (sauf `allowEmptyOutput`), des timeouts et des exit codes non nuls sans stdout.
10
10
  */
@@ -47,7 +47,8 @@ export class CliAdapter {
47
47
  ? [...baseArgs, renderedPrompt]
48
48
  : baseArgs;
49
49
  return new Promise((resolve, reject) => {
50
- const child = spawn(this.config.command, args, {
50
+ const spawnCommand = shellCommandForSpawn(this.config.command, args, this.config.shell ?? false);
51
+ const child = spawn(spawnCommand.command, spawnCommand.args, {
51
52
  stdio: ["pipe", "pipe", "pipe"],
52
53
  shell: this.config.shell ?? false
53
54
  });
@@ -147,7 +148,7 @@ export class CliAdapter {
147
148
  }));
148
149
  });
149
150
  const finishFromExitCode = (code) => {
150
- if (code && code !== 0 && !stdout.trim()) {
151
+ if (code && code !== 0) {
151
152
  finish(createCliExitError(this.name, code, stderr));
152
153
  return;
153
154
  }
@@ -307,6 +308,35 @@ function clipLine(value, maxLength) {
307
308
  ? value
308
309
  : `${value.slice(0, maxLength - 1)}…`;
309
310
  }
311
+ function shellCommandForSpawn(command, args, shell) {
312
+ if (!shell) {
313
+ return { command, args };
314
+ }
315
+ if (process.platform !== "win32") {
316
+ return {
317
+ command: [command, ...args].map(quotePosixShellArg).join(" "),
318
+ args: []
319
+ };
320
+ }
321
+ return {
322
+ command: [command, ...args].map(quoteWindowsShellArg).join(" "),
323
+ args: []
324
+ };
325
+ }
326
+ function quoteWindowsShellArg(value) {
327
+ if (value.length === 0) {
328
+ return "\"\"";
329
+ }
330
+ return `"${value
331
+ .replace(/(\\*)"/g, "$1$1\\\"")
332
+ .replace(/(\\+)$/g, "$1$1")}"`;
333
+ }
334
+ function quotePosixShellArg(value) {
335
+ if (value.length === 0) {
336
+ return "''";
337
+ }
338
+ return `'${value.replace(/'/g, "'\\''")}'`;
339
+ }
310
340
  function cancelledError(adapterName) {
311
341
  return new AdapterError("cancelled", adapterName, `${adapterName} cancelled by user.`);
312
342
  }
@@ -116,7 +116,7 @@ export class OllamaAdapter {
116
116
  throw new AdapterError("model-unavailable", this.name, `Modele Ollama indisponible: ${this.config.model}. Modeles detectes: ${models.join(", ") || "aucun"}. ` +
117
117
  "Utilise --pull-models ou autoPullModel: true pour autoriser le telechargement.", { model: this.config.model, availableModels: models });
118
118
  }
119
- process.stdout.write(`\n[ollama] Modele absent, telechargement: ${this.config.model}\n`);
119
+ process.stderr.write(`\n[ollama] Modele absent, telechargement: ${this.config.model}\n`);
120
120
  await this.pullModel(baseUrl);
121
121
  if (!(await this.isModelAvailable(baseUrl))) {
122
122
  throw new AdapterError("model-pull-failed", this.name, `Le modele Ollama ${this.config.model} reste indisponible apres telechargement.`);
@@ -6,9 +6,9 @@
6
6
  const KNOWN_CLI_AGENTS = [
7
7
  { configKey: "codex", commandAliases: ["codex"], discoveryKey: "codex" },
8
8
  { configKey: "claude", commandAliases: ["claude"], discoveryKey: "claude" },
9
- { configKey: "gemini", commandAliases: ["gemini"], discoveryKey: "gemini" },
10
9
  { configKey: "antigravity", commandAliases: ["agy", "antigravity"], discoveryKey: "antigravity" },
11
- { configKey: "opencode", commandAliases: ["opencode"], discoveryKey: "opencode" }
10
+ { configKey: "opencode", commandAliases: ["opencode"], discoveryKey: "opencode" },
11
+ { configKey: "vibe", commandAliases: ["vibe"], discoveryKey: "vibe" }
12
12
  ];
13
13
  /** Clé de config de l'agent Ollama local par défaut. */
14
14
  export const OLLAMA_AGENT_KEY = "ollama-local";
@@ -36,7 +36,7 @@ export function detectionForCommand(command, discovery) {
36
36
  }
37
37
  /**
38
38
  * Liste les clés d'agents connus effectivement détectés localement, dans
39
- * l'ordre canonique (`codex`, `claude`, `gemini`, `antigravity`, `opencode`,
39
+ * l'ordre canonique (`codex`, `claude`, `antigravity`, `opencode`, `vibe`,
40
40
  * puis `ollama-local`).
41
41
  */
42
42
  export function detectedAgentNames(discovery) {
package/dist/args.js CHANGED
@@ -13,6 +13,8 @@ const FLAG_SPECS = {
13
13
  // Booléens : présence = vrai, aucune valeur consommée.
14
14
  help: { arity: "boolean" },
15
15
  version: { arity: "boolean" },
16
+ tui: { arity: "boolean" },
17
+ terminal: { arity: "boolean" },
16
18
  plain: { arity: "boolean" },
17
19
  json: { arity: "boolean" },
18
20
  "no-summary": { arity: "boolean" },
@@ -29,17 +31,22 @@ const FLAG_SPECS = {
29
31
  "agent-a": { arity: "single" },
30
32
  "agent-b": { arity: "single" },
31
33
  config: { arity: "single" },
34
+ interface: { arity: "single" },
32
35
  language: { arity: "single" },
33
36
  "model-a": { arity: "single" },
34
37
  "model-b": { arity: "single" },
38
+ mode: { arity: "single" },
35
39
  "set-ollama-model": { arity: "single" },
36
40
  preset: { arity: "single" },
37
41
  "summary-agent": { arity: "single" },
42
+ "ask-summary-agent": { arity: "single" },
38
43
  "summary-model": { arity: "single" },
39
44
  topic: { arity: "single" },
40
45
  turns: { arity: "single" },
41
46
  renderer: { arity: "single" },
42
47
  // Valeurs multiples.
48
+ agents: { arity: "multi" },
49
+ "ask-agents": { arity: "multi" },
43
50
  "set-defaults": { arity: "multi", max: 2 },
44
51
  files: { arity: "multi" },
45
52
  context: { arity: "multi" }
@@ -47,6 +54,7 @@ const FLAG_SPECS = {
47
54
  /** Commandes acceptées comme premier argument positionnel. */
48
55
  const COMMANDS = new Set([
49
56
  "run",
57
+ "ask",
50
58
  "new",
51
59
  "init",
52
60
  "setup",
@@ -59,6 +67,8 @@ const COMMANDS = new Set([
59
67
  "agents",
60
68
  "preset",
61
69
  "presets",
70
+ "history",
71
+ "historique",
62
72
  "context"
63
73
  ]);
64
74
  /**
@@ -173,8 +183,17 @@ export function parseArgs(args, messages) {
173
183
  if (command === "run") {
174
184
  applyRunPositionals(positionals, flags, presets, commandExplicit, COMMANDS, messages);
175
185
  }
186
+ else if (command === "ask") {
187
+ flags.mode = "ask";
188
+ applyTopicPositionals(positionals, flags);
189
+ }
176
190
  return { command, commandExplicit, positionals, flags };
177
191
  }
192
+ function applyTopicPositionals(positionals, flags) {
193
+ if (positionals.length > 0) {
194
+ flags.topic ??= positionals.join(" ");
195
+ }
196
+ }
178
197
  /**
179
198
  * Détecte si une valeur ressemble à une faute de frappe d'une commande connue
180
199
  * (même première lettre et distance de Levenshtein ≤ 2).
@@ -248,7 +267,8 @@ export function normalizeFlagName(value) {
248
267
  lang: "language",
249
268
  s: "topic",
250
269
  subject: "topic",
251
- t: "turns"
270
+ t: "turns",
271
+ "no-tui": "terminal"
252
272
  };
253
273
  return aliases[value] ?? value;
254
274
  }
package/dist/config.js CHANGED
@@ -13,9 +13,13 @@ export const exampleConfig = {
13
13
  language: "fr",
14
14
  outputDir: DEFAULT_OUTPUT_DIR,
15
15
  defaults: {
16
+ interface: "tui",
17
+ mode: "debate",
16
18
  agentA: "codex",
17
19
  agentB: "claude",
20
+ askAgents: ["codex", "claude"],
18
21
  summaryAgent: "claude",
22
+ askSummaryAgent: "claude",
19
23
  turns: 4
20
24
  },
21
25
  agents: {
@@ -50,23 +54,6 @@ export const exampleConfig = {
50
54
  role: "reviewer",
51
55
  tier: "primary"
52
56
  },
53
- gemini: {
54
- type: "cli",
55
- command: "gemini",
56
- args: [
57
- "--output-format",
58
- "text",
59
- "--approval-mode",
60
- "plan",
61
- "--skip-trust",
62
- "--prompt",
63
- "-"
64
- ],
65
- promptMode: "stdin",
66
- shell: process.platform === "win32",
67
- role: "reviewer",
68
- tier: "primary"
69
- },
70
57
  antigravity: {
71
58
  type: "cli-pty",
72
59
  command: "agy",
@@ -92,6 +79,21 @@ export const exampleConfig = {
92
79
  role: "reviewer",
93
80
  tier: "primary"
94
81
  },
82
+ vibe: {
83
+ type: "cli",
84
+ command: "vibe",
85
+ args: [
86
+ "--output",
87
+ "text",
88
+ "--trust",
89
+ "--prompt"
90
+ ],
91
+ promptMode: "argument",
92
+ modelArg: "--model",
93
+ shell: process.platform === "win32",
94
+ role: "reviewer",
95
+ tier: "primary"
96
+ },
95
97
  "ollama-local": {
96
98
  type: "ollama",
97
99
  baseUrl: "http://localhost:11434",
@@ -189,11 +191,20 @@ export function createConfigFromDiscovery(discovery) {
189
191
  config.defaults = pair
190
192
  ? {
191
193
  ...config.defaults,
194
+ interface: config.defaults?.interface ?? "tui",
195
+ mode: config.defaults?.mode ?? "debate",
192
196
  agentA: pair[0],
193
197
  agentB: pair[1],
194
- summaryAgent: chooseDefaultSummaryAgent(pair)
198
+ askAgents: pair,
199
+ summaryAgent: chooseDefaultSummaryAgent(pair),
200
+ askSummaryAgent: chooseDefaultSummaryAgent(pair)
195
201
  }
196
- : { turns: config.defaults?.turns };
202
+ : {
203
+ interface: config.defaults?.interface ?? "tui",
204
+ mode: config.defaults?.mode ?? "debate",
205
+ turns: config.defaults?.turns,
206
+ askAgents: detectedAgentNames(discovery).slice(0, 2)
207
+ };
197
208
  return config;
198
209
  }
199
210
  /**
@@ -204,11 +215,34 @@ export function syncDetectedAgents(config, discovery) {
204
215
  const discoveredConfig = createConfigFromDiscovery(discovery);
205
216
  const missingAgents = detectedAgentNames(discovery).filter((agentName) => !config.agents[agentName]);
206
217
  applyDetectedCommands(config, discovery);
218
+ migrateKnownAgentDefaults(config);
207
219
  for (const agentName of missingAgents) {
208
220
  config.agents[agentName] = discoveredConfig.agents[agentName];
209
221
  }
210
222
  return missingAgents;
211
223
  }
224
+ function migrateKnownAgentDefaults(config) {
225
+ migrateVibePlanAgent(config);
226
+ }
227
+ function migrateVibePlanAgent(config) {
228
+ const agent = config.agents.vibe;
229
+ if (agent?.type !== "cli" || !isLegacyVibePlanArgs(agent.args)) {
230
+ return;
231
+ }
232
+ agent.args = ["--output", "text", "--trust", "--prompt"];
233
+ }
234
+ function isLegacyVibePlanArgs(args) {
235
+ return JSON.stringify(args) === JSON.stringify(["--output", "text", "--agent", "plan", "--trust", "--prompt"]);
236
+ }
237
+ export function syncDetectedAgentsDetailed(config, discovery) {
238
+ const before = JSON.stringify(config.agents);
239
+ const addedAgents = syncDetectedAgents(config, discovery);
240
+ const changed = JSON.stringify(config.agents) !== before;
241
+ return {
242
+ addedAgents,
243
+ changed
244
+ };
245
+ }
212
246
  export function syncOllamaModel(config, discovery) {
213
247
  const agent = config.agents["ollama-local"];
214
248
  if (agent?.type !== "ollama" || discovery.ollama.models.length === 0) {
@@ -249,7 +283,7 @@ function chooseDefaultOllamaModel(discovery) {
249
283
  return discovery.ollama.models[0] ?? DEFAULT_OLLAMA_MODEL;
250
284
  }
251
285
  function chooseDefaultSummaryAgent(pair) {
252
- for (const preferred of ["claude", "codex", "antigravity", "gemini"]) {
286
+ for (const preferred of ["claude", "codex", "antigravity", "vibe"]) {
253
287
  if (pair.includes(preferred)) {
254
288
  return preferred;
255
289
  }
@@ -269,18 +303,18 @@ function chooseDefaultPair(discovery) {
269
303
  if (discovery.opencode.available && discovery.ollama.available) {
270
304
  return ["opencode", "ollama-local"];
271
305
  }
306
+ if (discovery.vibe.available && discovery.ollama.available) {
307
+ return ["vibe", "ollama-local"];
308
+ }
272
309
  if (discovery.antigravity.available && discovery.ollama.available) {
273
310
  return ["antigravity", "ollama-local"];
274
311
  }
275
- if (discovery.gemini.available && discovery.ollama.available) {
276
- return ["gemini", "ollama-local"];
277
- }
278
312
  const cliAgents = [
279
313
  discovery.codex.available ? "codex" : undefined,
280
314
  discovery.claude.available ? "claude" : undefined,
281
315
  discovery.antigravity.available ? "antigravity" : undefined,
282
316
  discovery.opencode.available ? "opencode" : undefined,
283
- discovery.gemini.available ? "gemini" : undefined
317
+ discovery.vibe.available ? "vibe" : undefined
284
318
  ].filter((agent) => Boolean(agent));
285
319
  if (cliAgents.length >= 2) {
286
320
  return [cliAgents[0], cliAgents[1]];