palabre 0.9.1 → 0.10.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 +6 -0
- package/dist/adapters/cli-pty.js +30 -10
- package/dist/adapters/cli-shared.js +73 -0
- package/dist/adapters/cli.js +40 -77
- package/dist/adapters/index.js +1 -0
- package/dist/adapters/ollama.js +32 -32
- package/dist/adapters/terminal.js +1 -0
- package/dist/args.js +1 -0
- package/dist/commands/agents.js +7 -1
- package/dist/commands/context.js +7 -1
- package/dist/commands/history.js +6 -1
- package/dist/commands/init.js +8 -3
- package/dist/commands/presets.js +6 -1
- package/dist/commands/shared.js +5 -1
- package/dist/commands/update.js +6 -1
- package/dist/config.js +17 -1
- package/dist/configWizard.js +5 -4
- package/dist/context.js +1 -0
- package/dist/contextScan.js +4 -3
- package/dist/discovery.js +1 -0
- package/dist/doctor.js +1 -0
- package/dist/errors.js +4 -0
- package/dist/exec.js +1 -0
- package/dist/history.js +10 -0
- package/dist/i18n.js +2 -0
- package/dist/index.js +170 -112
- package/dist/limits.js +4 -0
- package/dist/messages/adapter-errors.js +26 -2
- package/dist/messages/config.js +6 -0
- package/dist/messages/index.js +1 -0
- package/dist/messages/renderers.js +10 -2
- package/dist/messages/tui.js +8 -2
- package/dist/new.js +65 -11
- package/dist/ollamaUrl.js +20 -0
- package/dist/orchestrator.js +103 -150
- package/dist/output.js +1 -0
- package/dist/presets.js +1 -0
- package/dist/prompt.js +1 -0
- package/dist/renderers/console.js +1 -1
- package/dist/renderers/tui-prompts.js +343 -0
- package/dist/renderers/tui-renderer.js +228 -0
- package/dist/renderers/tui-screens.js +352 -0
- package/dist/renderers/tui-theme.js +356 -0
- package/dist/renderers/tui.js +7 -1086
- package/dist/runOptions.js +33 -2
- package/dist/session.js +1 -0
- package/dist/tuiController.js +61 -16
- package/dist/tuiState.js +4 -0
- package/dist/types.js +1 -0
- package/dist/update.js +1 -0
- package/dist/version.js +1 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
2
|
+
/**
|
|
3
|
+
* @file Point d'entrée CLI de Palabre : parsing des arguments, dispatch vers les
|
|
4
|
+
* commandes leaf (`agents`, `presets`, `history`, `context`, `update`, `init`, `config`),
|
|
5
|
+
* résolution de la config/langue, boucle TUI d'accueil et lancement d'un débat ou d'une
|
|
6
|
+
* requête `ask` via l'orchestrateur.
|
|
7
|
+
*/
|
|
8
|
+
import { assertRunnableConfig, configExists, createConfigFromDiscovery, loadConfig, resolveDefaultConfigPath, resolveOutputDir, setOllamaModel, syncDetectedAgentsDetailed, syncOllamaModel, writeConfig } from "./config.js";
|
|
3
9
|
import { loadProjectInputs } from "./context.js";
|
|
4
10
|
import { discoverLocalTools, discoverLocalToolsForConfig } from "./discovery.js";
|
|
5
11
|
import { runDoctor } from "./doctor.js";
|
|
@@ -19,7 +25,7 @@ import { writeDebateMarkdown } from "./output.js";
|
|
|
19
25
|
import { formatUpdateInstructions, getUpdateInfo } from "./update.js";
|
|
20
26
|
import { getStringListFlag, parseArgs } from "./args.js";
|
|
21
27
|
import { clearTuiRunOverrides } from "./tuiState.js";
|
|
22
|
-
import { OllamaUrlError } from "./ollamaUrl.js";
|
|
28
|
+
import { formatOllamaUrlError, OllamaUrlError } from "./ollamaUrl.js";
|
|
23
29
|
import { compareSemver, getLatestPackageVersion, getPackageVersion } from "./version.js";
|
|
24
30
|
import { runAgentsCommand } from "./commands/agents.js";
|
|
25
31
|
import { runContextCommand } from "./commands/context.js";
|
|
@@ -29,7 +35,7 @@ import { runPresetsCommand } from "./commands/presets.js";
|
|
|
29
35
|
import { runUpdateCommand } from "./commands/update.js";
|
|
30
36
|
import { optionalString } from "./commands/shared.js";
|
|
31
37
|
import { runTuiAgentsWizard, runTuiConfigLoop, runTuiRolesWizard, syncInteractiveDetectedAgents } from "./tuiController.js";
|
|
32
|
-
import { resolveRunOptions } from "./runOptions.js";
|
|
38
|
+
import { parseInterfaceFlag, parseModeFlag, resolveRunOptions } from "./runOptions.js";
|
|
33
39
|
/** Point d'entrée principal du CLI Palabre. Dispatche vers la commande appropriée selon les arguments. */
|
|
34
40
|
async function main() {
|
|
35
41
|
const rawArgs = process.argv.slice(2);
|
|
@@ -90,7 +96,7 @@ async function main() {
|
|
|
90
96
|
configLanguage: config.language
|
|
91
97
|
});
|
|
92
98
|
const messages = createTranslator(config.language);
|
|
93
|
-
await
|
|
99
|
+
await writeConfig(configPath, config);
|
|
94
100
|
if (!shouldOpenTuiHome(parsed)) {
|
|
95
101
|
console.log(messages.init.editConfigThenRerun(configPath));
|
|
96
102
|
return;
|
|
@@ -113,78 +119,94 @@ async function main() {
|
|
|
113
119
|
let tuiVersion = "";
|
|
114
120
|
let tuiLatestVersion;
|
|
115
121
|
const handleTuiHomeInput = async (tuiInput) => {
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
const nextInput = await promptTuiHomeTopic(tuiMode, messages);
|
|
122
|
-
return handleTuiHomeInput(nextInput);
|
|
123
|
-
}
|
|
124
|
-
if (tuiInput.kind === "history") {
|
|
125
|
-
renderTuiHistory(await listHistoryEntries(resolveOutputDir(config.outputDir)), messages);
|
|
126
|
-
const nextInput = await promptTuiHomeTopic(tuiMode, messages);
|
|
127
|
-
return handleTuiHomeInput(nextInput);
|
|
128
|
-
}
|
|
129
|
-
if (tuiInput.kind === "update") {
|
|
130
|
-
const info = await getUpdateInfo(tuiVersion);
|
|
131
|
-
renderTuiUpdate(formatUpdateInstructions(info, messages), messages);
|
|
132
|
-
const nextInput = await promptTuiHomeTopic(tuiMode, messages);
|
|
133
|
-
return handleTuiHomeInput(nextInput);
|
|
134
|
-
}
|
|
135
|
-
if (tuiInput.kind === "home") {
|
|
136
|
-
return "continue";
|
|
137
|
-
}
|
|
138
|
-
if (tuiInput.kind === "roles") {
|
|
139
|
-
const result = await runTuiRolesWizard(configPath, config, messages, tuiMode, tuiInput.roles);
|
|
140
|
-
if (result.quit)
|
|
141
|
-
return "quit";
|
|
142
|
-
tuiNotice = result.notice;
|
|
143
|
-
return "continue";
|
|
144
|
-
}
|
|
145
|
-
if (tuiInput.kind === "agents") {
|
|
146
|
-
const result = await runTuiAgentsWizard(configPath, config, messages, tuiMode, tuiInput.agents);
|
|
147
|
-
if (result.quit)
|
|
148
|
-
return "quit";
|
|
149
|
-
tuiNotice = result.notice;
|
|
150
|
-
resetTuiRunOverridesOnNextTopic ||= Boolean(result.changedRunDefaults);
|
|
151
|
-
return "continue";
|
|
152
|
-
}
|
|
153
|
-
if (tuiInput.kind === "mode") {
|
|
154
|
-
tuiMode = tuiInput.mode;
|
|
155
|
-
return "continue";
|
|
156
|
-
}
|
|
157
|
-
if (tuiInput.kind === "config") {
|
|
158
|
-
const result = await runTuiConfigLoop(configPath, config, messages, tuiMode);
|
|
159
|
-
if (result.quit)
|
|
122
|
+
let input = tuiInput;
|
|
123
|
+
// Les vues informatives (/help, /history, /update) réaffichent le prompt d'accueil
|
|
124
|
+
// puis reprennent le traitement avec la nouvelle saisie, d'où la boucle.
|
|
125
|
+
for (;;) {
|
|
126
|
+
if (!input) {
|
|
160
127
|
return "quit";
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
128
|
+
}
|
|
129
|
+
if (input.kind === "help") {
|
|
130
|
+
renderTuiHelp(messages);
|
|
131
|
+
input = await promptTuiHomeTopic(tuiMode, messages);
|
|
132
|
+
continue;
|
|
133
|
+
}
|
|
134
|
+
if (input.kind === "history") {
|
|
135
|
+
renderTuiHistory(await listHistoryEntries(resolveOutputDir(config.outputDir)), messages);
|
|
136
|
+
input = await promptTuiHomeTopic(tuiMode, messages);
|
|
137
|
+
continue;
|
|
138
|
+
}
|
|
139
|
+
if (input.kind === "update") {
|
|
140
|
+
const info = await getUpdateInfo(tuiVersion);
|
|
141
|
+
renderTuiUpdate(formatUpdateInstructions(info, messages), messages);
|
|
142
|
+
input = await promptTuiHomeTopic(tuiMode, messages);
|
|
143
|
+
continue;
|
|
144
|
+
}
|
|
145
|
+
if (input.kind === "home") {
|
|
176
146
|
return "continue";
|
|
177
147
|
}
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
148
|
+
if (input.kind === "roles") {
|
|
149
|
+
const result = await runTuiRolesWizard(configPath, config, messages, tuiMode, input.roles);
|
|
150
|
+
if (result.quit)
|
|
151
|
+
return "quit";
|
|
152
|
+
tuiNotice = result.notice;
|
|
153
|
+
return "continue";
|
|
154
|
+
}
|
|
155
|
+
if (input.kind === "agents") {
|
|
156
|
+
const result = await runTuiAgentsWizard(configPath, config, messages, tuiMode, input.agents);
|
|
157
|
+
if (result.quit)
|
|
158
|
+
return "quit";
|
|
159
|
+
tuiNotice = result.notice;
|
|
160
|
+
resetTuiRunOverridesOnNextTopic ||= Boolean(result.changedRunDefaults);
|
|
161
|
+
return "continue";
|
|
162
|
+
}
|
|
163
|
+
if (input.kind === "mode") {
|
|
164
|
+
tuiMode = input.mode;
|
|
165
|
+
return "continue";
|
|
166
|
+
}
|
|
167
|
+
if (input.kind === "config") {
|
|
168
|
+
const result = await runTuiConfigLoop(configPath, config, messages, tuiMode);
|
|
169
|
+
if (result.quit)
|
|
170
|
+
return "quit";
|
|
171
|
+
tuiMode = result.mode;
|
|
172
|
+
resetTuiRunOverridesOnNextTopic ||= result.changedRunDefaults;
|
|
173
|
+
language = resolveLanguage({ explicitLanguage: optionalString(parsed.flags.language), configLanguage: config.language });
|
|
174
|
+
messages = createTranslator(language);
|
|
175
|
+
return "continue";
|
|
176
|
+
}
|
|
177
|
+
if (input.kind === "new") {
|
|
178
|
+
parsed.command = "new";
|
|
179
|
+
parsed.commandExplicit = true;
|
|
180
|
+
delete parsed.flags.topic;
|
|
181
|
+
return "run";
|
|
182
|
+
}
|
|
183
|
+
if (input.kind === "retry") {
|
|
184
|
+
if (!optionalString(parsed.flags.topic)) {
|
|
185
|
+
tuiNotice = messages.tui.retryUnavailable;
|
|
186
|
+
return "continue";
|
|
187
|
+
}
|
|
188
|
+
return "retry";
|
|
189
|
+
}
|
|
190
|
+
if (!input.topic) {
|
|
191
|
+
// Saisie réduite à des flags inline (ex. "--context src") : re-prompter au lieu de sortir en erreur.
|
|
192
|
+
tuiNotice = messages.common.topicRequired;
|
|
193
|
+
return "continue";
|
|
194
|
+
}
|
|
195
|
+
parsed.command = "";
|
|
196
|
+
parsed.commandExplicit = false;
|
|
197
|
+
if (hasCompletedTuiSession || resetTuiRunOverridesOnNextTopic) {
|
|
198
|
+
clearTuiRunOverrides(parsed.flags);
|
|
199
|
+
resetTuiRunOverridesOnNextTopic = false;
|
|
200
|
+
}
|
|
201
|
+
parsed.flags.topic = input.topic;
|
|
202
|
+
if (input.files && input.files.length > 0) {
|
|
203
|
+
parsed.flags.files = input.files;
|
|
204
|
+
}
|
|
205
|
+
if (input.context && input.context.length > 0) {
|
|
206
|
+
parsed.flags.context = input.context;
|
|
207
|
+
}
|
|
208
|
+
return "run";
|
|
185
209
|
}
|
|
186
|
-
parsed.flags.topic = tuiInput.topic;
|
|
187
|
-
return "run";
|
|
188
210
|
};
|
|
189
211
|
if (shouldOpenTuiHome(parsed)) {
|
|
190
212
|
const [syncResult, currentVersion, latestVersion] = await Promise.all([
|
|
@@ -218,6 +240,25 @@ async function main() {
|
|
|
218
240
|
if (parsed.command === "new") {
|
|
219
241
|
const selection = await runNewWizard(config, messages);
|
|
220
242
|
if (!selection) {
|
|
243
|
+
if (stayInTuiAfterSession) {
|
|
244
|
+
tuiNotice = messages.new.cancelled;
|
|
245
|
+
parsed.command = "";
|
|
246
|
+
parsed.commandExplicit = false;
|
|
247
|
+
for (;;) {
|
|
248
|
+
renderTuiHome(config, configPath, messages, { mode: tuiMode, version: tuiVersion, latestVersion: tuiLatestVersion });
|
|
249
|
+
const nextInput = await promptTuiHomeTopic(tuiMode, messages, { notice: tuiNotice });
|
|
250
|
+
tuiNotice = undefined;
|
|
251
|
+
const action = await handleTuiHomeInput(nextInput);
|
|
252
|
+
if (action === "quit")
|
|
253
|
+
return;
|
|
254
|
+
if (action === "continue" || action === "retry")
|
|
255
|
+
continue;
|
|
256
|
+
parsed.flags.mode = tuiMode;
|
|
257
|
+
parsed.flags.renderer = "tui";
|
|
258
|
+
break;
|
|
259
|
+
}
|
|
260
|
+
continue;
|
|
261
|
+
}
|
|
221
262
|
console.log(messages.new.cancelled);
|
|
222
263
|
return;
|
|
223
264
|
}
|
|
@@ -308,6 +349,7 @@ async function main() {
|
|
|
308
349
|
}
|
|
309
350
|
}
|
|
310
351
|
}
|
|
352
|
+
/** Construit un signal d'annulation déclenché sur `SIGINT`/`SIGTERM` pour interrompre un débat en cours. */
|
|
311
353
|
function debateAbortSignal() {
|
|
312
354
|
const controller = new AbortController();
|
|
313
355
|
const abort = () => {
|
|
@@ -328,7 +370,7 @@ async function runConfigCommand(flags) {
|
|
|
328
370
|
const explicitLanguage = optionalString(flags.language);
|
|
329
371
|
if (!(await configExists(configPath))) {
|
|
330
372
|
const messages = createTranslator(resolveLanguage({ explicitLanguage }));
|
|
331
|
-
await
|
|
373
|
+
await writeConfig(configPath);
|
|
332
374
|
console.log(messages.config.createdForConfig(configPath));
|
|
333
375
|
return;
|
|
334
376
|
}
|
|
@@ -339,7 +381,7 @@ async function runConfigCommand(flags) {
|
|
|
339
381
|
});
|
|
340
382
|
const messages = createTranslator(language);
|
|
341
383
|
if (flags["ollama-models"]) {
|
|
342
|
-
await runOllamaModelsCommand(config, Boolean(flags.json));
|
|
384
|
+
await runOllamaModelsCommand(config, Boolean(flags.json), messages);
|
|
343
385
|
return;
|
|
344
386
|
}
|
|
345
387
|
const setOllamaModelValue = optionalString(flags["set-ollama-model"]);
|
|
@@ -358,7 +400,7 @@ async function runConfigCommand(flags) {
|
|
|
358
400
|
console.log(messages.config.syncNoMissing(configPath));
|
|
359
401
|
return;
|
|
360
402
|
}
|
|
361
|
-
await
|
|
403
|
+
await writeConfig(configPath, config);
|
|
362
404
|
console.log(result.addedAgents.length > 0
|
|
363
405
|
? messages.config.syncAdded(configPath, result.addedAgents.join(", "))
|
|
364
406
|
: messages.config.syncRefreshed(configPath));
|
|
@@ -427,19 +469,25 @@ async function runConfigCommand(flags) {
|
|
|
427
469
|
if (changesDefaults) {
|
|
428
470
|
config.defaults = nextDefaults;
|
|
429
471
|
}
|
|
430
|
-
await
|
|
472
|
+
await writeConfig(configPath, config);
|
|
431
473
|
console.log(messages.config.updated(configPath, formatDefaultsForMessage(config.defaults ?? {}, messages), config.language ?? DEFAULT_LANGUAGE));
|
|
432
474
|
return;
|
|
433
475
|
}
|
|
434
476
|
if (flags["clear-defaults"]) {
|
|
435
477
|
delete config.defaults;
|
|
436
|
-
await
|
|
478
|
+
await writeConfig(configPath, config);
|
|
437
479
|
console.log(messages.config.cleared(configPath));
|
|
438
480
|
return;
|
|
439
481
|
}
|
|
440
482
|
await runConfigWizard(configPath, config, messages);
|
|
441
483
|
}
|
|
442
|
-
|
|
484
|
+
/**
|
|
485
|
+
* Affiche l'état de l'agent Ollama local (modèle courant, disponibilité de l'API, modèles installés).
|
|
486
|
+
* @param config - Config chargée.
|
|
487
|
+
* @param json - Si `true`, affiche le résultat en JSON plutôt qu'en texte lisible.
|
|
488
|
+
* @param messages - Dictionnaire localisé pour la sortie texte.
|
|
489
|
+
*/
|
|
490
|
+
async function runOllamaModelsCommand(config, json, messages) {
|
|
443
491
|
const discovery = await discoverLocalToolsForConfig(config);
|
|
444
492
|
const agent = config.agents["ollama-local"];
|
|
445
493
|
const currentModel = agent?.type === "ollama" ? agent.model : null;
|
|
@@ -456,10 +504,16 @@ async function runOllamaModelsCommand(config, json) {
|
|
|
456
504
|
console.log(JSON.stringify(payload, null, 2));
|
|
457
505
|
return;
|
|
458
506
|
}
|
|
459
|
-
console.log(
|
|
460
|
-
console.log(
|
|
461
|
-
console.log(
|
|
507
|
+
console.log(messages.config.ollamaModelsCurrent(currentModel));
|
|
508
|
+
console.log(messages.config.ollamaModelsApi(discovery.ollama.available, discovery.ollama.baseUrl));
|
|
509
|
+
console.log(messages.config.ollamaModelsInstalled(discovery.ollama.models));
|
|
462
510
|
}
|
|
511
|
+
/**
|
|
512
|
+
* Change le modèle configuré pour l'agent `ollama-local` après vérification qu'il est bien installé.
|
|
513
|
+
* @param configPath - Chemin du fichier de config à mettre à jour.
|
|
514
|
+
* @param config - Config chargée.
|
|
515
|
+
* @param model - Nom du modèle Ollama à définir.
|
|
516
|
+
*/
|
|
463
517
|
async function runSetOllamaModelCommand(configPath, config, model, messages) {
|
|
464
518
|
const trimmed = model.trim();
|
|
465
519
|
if (!trimmed) {
|
|
@@ -474,11 +528,16 @@ async function runSetOllamaModelCommand(configPath, config, model, messages) {
|
|
|
474
528
|
throw new Error(messages.config.ollamaModelUnavailable(trimmed));
|
|
475
529
|
}
|
|
476
530
|
const result = setOllamaModel(config, trimmed);
|
|
477
|
-
await
|
|
531
|
+
await writeConfig(configPath, config);
|
|
478
532
|
console.log(result
|
|
479
533
|
? messages.config.ollamaModelUpdated(configPath, result.previousModel, result.nextModel)
|
|
480
534
|
: messages.config.ollamaModelNoChange(configPath, agent.model));
|
|
481
535
|
}
|
|
536
|
+
/**
|
|
537
|
+
* Aligne automatiquement le modèle de l'agent `ollama-local` sur un modèle réellement installé.
|
|
538
|
+
* @param configPath - Chemin du fichier de config à mettre à jour.
|
|
539
|
+
* @param config - Config chargée.
|
|
540
|
+
*/
|
|
482
541
|
async function runSyncOllamaModelCommand(configPath, config, messages) {
|
|
483
542
|
const discovery = await discoverLocalToolsForConfig(config);
|
|
484
543
|
const agent = config.agents["ollama-local"];
|
|
@@ -493,7 +552,7 @@ async function runSyncOllamaModelCommand(configPath, config, messages) {
|
|
|
493
552
|
console.log(messages.config.ollamaModelNoChange(configPath, agent.model));
|
|
494
553
|
return;
|
|
495
554
|
}
|
|
496
|
-
await
|
|
555
|
+
await writeConfig(configPath, config);
|
|
497
556
|
console.log(messages.config.ollamaModelUpdated(configPath, result.previousModel, result.nextModel));
|
|
498
557
|
}
|
|
499
558
|
/**
|
|
@@ -511,6 +570,11 @@ function isNoneValue(value) {
|
|
|
511
570
|
function formatDefaultsForMessage(defaults, messages) {
|
|
512
571
|
return messages.config.defaultsSummary(defaults.agentA, defaults.agentB, turnsOrDefault(defaults.turns), defaults.summaryAgent, defaults.askSummaryAgent, defaults.mode, defaults.askAgents, defaults.interface);
|
|
513
572
|
}
|
|
573
|
+
/**
|
|
574
|
+
* Déduplique et valide une liste d'agents `ask` fournie via `--ask-agents`.
|
|
575
|
+
* @param agents - Noms d'agents bruts, éventuellement en doublon.
|
|
576
|
+
* @throws Si la liste dépasse `MAX_ASK_AGENTS` ou référence un agent inconnu de la config.
|
|
577
|
+
*/
|
|
514
578
|
function normalizeAskAgentsForConfig(config, agents, messages) {
|
|
515
579
|
const unique = agents
|
|
516
580
|
.map((agent) => agent.trim())
|
|
@@ -534,24 +598,6 @@ function assertKnownAgent(config, agentName, fieldName, messages) {
|
|
|
534
598
|
throw new Error(messages.common.unknownAgentForField(fieldName, agentName, Object.keys(config.agents).join(", ")));
|
|
535
599
|
}
|
|
536
600
|
}
|
|
537
|
-
function parseModeFlag(value, messages) {
|
|
538
|
-
if (!value) {
|
|
539
|
-
return "debate";
|
|
540
|
-
}
|
|
541
|
-
if (value === "debate" || value === "ask") {
|
|
542
|
-
return value;
|
|
543
|
-
}
|
|
544
|
-
throw new Error(messages.common.unknownMode(value, "debate, ask"));
|
|
545
|
-
}
|
|
546
|
-
function parseInterfaceFlag(value, messages) {
|
|
547
|
-
if (!value) {
|
|
548
|
-
return "tui";
|
|
549
|
-
}
|
|
550
|
-
if (value === "tui" || value === "terminal") {
|
|
551
|
-
return value;
|
|
552
|
-
}
|
|
553
|
-
throw new Error(messages.common.unknownMode(value, "tui, terminal"));
|
|
554
|
-
}
|
|
555
601
|
/**
|
|
556
602
|
* Affiche un aperçu du prompt du premier tour sans appeler aucun agent (flag `--show-prompt`).
|
|
557
603
|
* @param config - Config chargée.
|
|
@@ -638,14 +684,12 @@ function createRendererFromFlags(flags, plainOutputFallback, defaultInterface, m
|
|
|
638
684
|
if (flags.json) {
|
|
639
685
|
return createNdjsonRenderer();
|
|
640
686
|
}
|
|
641
|
-
if (flags.tui) {
|
|
642
|
-
return createTuiRenderer(messages);
|
|
643
|
-
}
|
|
644
|
-
if (flags.terminal || flags.plain || plainOutputFallback || defaultInterface === "terminal") {
|
|
645
|
-
return createConsoleRenderer(true, messages);
|
|
646
|
-
}
|
|
647
687
|
return createAutoRenderer(flags, plainOutputFallback, defaultInterface, messages);
|
|
648
688
|
}
|
|
689
|
+
/**
|
|
690
|
+
* Choix du renderer par défaut (`--renderer auto`) : TUI si les flags/config le demandent
|
|
691
|
+
* ou si stdout est un TTY, rendu console plain sinon.
|
|
692
|
+
*/
|
|
649
693
|
function createAutoRenderer(flags, plainOutputFallback, defaultInterface, messages) {
|
|
650
694
|
if (flags.tui) {
|
|
651
695
|
return createTuiRenderer(messages);
|
|
@@ -655,6 +699,11 @@ function createAutoRenderer(flags, plainOutputFallback, defaultInterface, messag
|
|
|
655
699
|
}
|
|
656
700
|
return process.stdout.isTTY ? createTuiRenderer(messages) : createConsoleRenderer(true, messages);
|
|
657
701
|
}
|
|
702
|
+
/**
|
|
703
|
+
* Détermine si l'accueil TUI doit s'ouvrir : commande `run` implicite, sans sujet, preset
|
|
704
|
+
* ni flag de rendu déjà fourni. Toute intention explicite de lancer directement un débat
|
|
705
|
+
* (topic, `--renderer`, `--json`, `--plain`, `--terminal`) désactive l'accueil.
|
|
706
|
+
*/
|
|
658
707
|
function shouldOpenTuiHome(parsed) {
|
|
659
708
|
return parsed.command === "run"
|
|
660
709
|
&& !parsed.commandExplicit
|
|
@@ -679,6 +728,11 @@ function printHelp(messages, command) {
|
|
|
679
728
|
const commandHelp = command ? messages.help.renderCommand(command) : undefined;
|
|
680
729
|
console.log(commandHelp ?? messages.help.render(listPresetNames().join(", ")));
|
|
681
730
|
}
|
|
731
|
+
/**
|
|
732
|
+
* Résout la commande cible pour l'aide contextuelle (`palabre <cmd> --help`), en normalisant
|
|
733
|
+
* les alias (`agent` -> `agents`, `preset` -> `presets`, `setup` -> `init`).
|
|
734
|
+
* @returns `undefined` pour `help`/`run`, qui utilisent l'aide générale.
|
|
735
|
+
*/
|
|
682
736
|
function commandHelpTarget(parsed) {
|
|
683
737
|
if (parsed.command === "help" || parsed.command === "run") {
|
|
684
738
|
return undefined;
|
|
@@ -706,16 +760,16 @@ async function resolveCommandMessages(flags) {
|
|
|
706
760
|
}
|
|
707
761
|
return createTranslator(resolveLanguage({ explicitLanguage, configLanguage }));
|
|
708
762
|
}
|
|
763
|
+
/**
|
|
764
|
+
* Formate une erreur non gérée remontée jusqu'au point d'entrée en message lisible,
|
|
765
|
+
* en spécialisant `AdapterError` et `OllamaUrlError` pour rester actionnable.
|
|
766
|
+
*/
|
|
709
767
|
function formatRuntimeError(error, messages) {
|
|
710
768
|
if (error instanceof AdapterError) {
|
|
711
769
|
return formatAdapterError(error, messages);
|
|
712
770
|
}
|
|
713
771
|
if (error instanceof OllamaUrlError) {
|
|
714
|
-
|
|
715
|
-
return messages.common.ollamaUrlEmpty;
|
|
716
|
-
if (error.kind === "protocol")
|
|
717
|
-
return messages.common.ollamaUrlProtocol(error.protocol ?? "");
|
|
718
|
-
return messages.common.ollamaUrlInvalid(error.value);
|
|
772
|
+
return formatOllamaUrlError(error, messages);
|
|
719
773
|
}
|
|
720
774
|
return error instanceof Error ? error.message : String(error);
|
|
721
775
|
}
|
|
@@ -726,6 +780,10 @@ main().catch((error) => {
|
|
|
726
780
|
console.error(`${messages.common.errorPrefix}: ${message}`);
|
|
727
781
|
process.exitCode = 1;
|
|
728
782
|
});
|
|
783
|
+
/**
|
|
784
|
+
* Variante de `findRawLanguageFlag` + `resolveLanguage` qui ne peut pas lever, utilisée dans
|
|
785
|
+
* le gestionnaire d'erreur global où la config n'est pas forcément chargée.
|
|
786
|
+
*/
|
|
729
787
|
function safeStartupLanguage(args) {
|
|
730
788
|
try {
|
|
731
789
|
return resolveLanguage({ explicitLanguage: findRawLanguageFlag(args) });
|
package/dist/limits.js
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
|
+
/** @file Limites produit sur le nombre de tours et d'agents `ask`, et parsing/validation de `--turns`. */
|
|
1
2
|
import { createTranslator } from "./i18n.js";
|
|
3
|
+
/** Nombre de tours par défaut quand `--turns` n'est pas fourni. */
|
|
2
4
|
export const DEFAULT_TURNS = 4;
|
|
5
|
+
/** Nombre maximal d'agents acceptés par `--agents` en mode `ask`. */
|
|
3
6
|
export const MAX_ASK_AGENTS = 4;
|
|
7
|
+
/** Borne haute produit pour `--turns`, au-delà considérée comme une erreur d'utilisation. */
|
|
4
8
|
export const MAX_TURNS = 20;
|
|
5
9
|
/** Convertit `value` en nombre et valide la plage [1, `MAX_TURNS`]. Lève une erreur si invalide. */
|
|
6
10
|
export function parseTurns(value, label = "--turns", messages = createTranslator("fr")) {
|
|
@@ -29,10 +29,34 @@ const enHints = {
|
|
|
29
29
|
export const adapterErrorMessages = {
|
|
30
30
|
fr: {
|
|
31
31
|
suggestionPrefix: "Suggestion",
|
|
32
|
-
hint: (kind) => frHints[kind]
|
|
32
|
+
hint: (kind) => frHints[kind],
|
|
33
|
+
usageLimit: (adapterName, detail) => `${adapterName} a atteint une limite d'utilisation: ${detail}`,
|
|
34
|
+
unsupportedModel: (adapterName, detail) => `${adapterName} ne peut pas utiliser ce modèle: ${detail}`,
|
|
35
|
+
noStderrCaptured: "aucun stderr capturé.",
|
|
36
|
+
noPtyOutputCaptured: "aucune sortie PTY capturée.",
|
|
37
|
+
ollamaModelUnavailable: (model, installedModels) => `Modèle Ollama indisponible: ${model}. Modèles détectés: ${installedModels.join(", ") || "aucun"}. ` +
|
|
38
|
+
"Utilise --pull-models ou autoPullModel: true pour autoriser le téléchargement.",
|
|
39
|
+
ollamaModelStillUnavailable: (model) => `Le modèle Ollama ${model} reste indisponible après téléchargement.`,
|
|
40
|
+
ollamaPullProgress: (model) => `[ollama] Modèle absent, téléchargement: ${model}`,
|
|
41
|
+
ollamaPullFailed: (model, detail) => `Échec du téléchargement Ollama ${model}: ${detail}`,
|
|
42
|
+
ollamaTagsHttpError: (status) => `Ollama HTTP ${status} pendant la détection des modèles`,
|
|
43
|
+
ollamaPsHttpError: (status) => `Ollama HTTP ${status} pendant la détection des modèles chargés`,
|
|
44
|
+
ollamaUnloadFailed: (model, status) => `Impossible de décharger le modèle Ollama ${model}: HTTP ${status}`
|
|
33
45
|
},
|
|
34
46
|
en: {
|
|
35
47
|
suggestionPrefix: "Suggestion",
|
|
36
|
-
hint: (kind) => enHints[kind]
|
|
48
|
+
hint: (kind) => enHints[kind],
|
|
49
|
+
usageLimit: (adapterName, detail) => `${adapterName} hit a usage limit: ${detail}`,
|
|
50
|
+
unsupportedModel: (adapterName, detail) => `${adapterName} cannot use this model: ${detail}`,
|
|
51
|
+
noStderrCaptured: "no stderr captured.",
|
|
52
|
+
noPtyOutputCaptured: "no PTY output captured.",
|
|
53
|
+
ollamaModelUnavailable: (model, installedModels) => `Ollama model unavailable: ${model}. Detected models: ${installedModels.join(", ") || "none"}. ` +
|
|
54
|
+
"Use --pull-models or autoPullModel: true to allow downloading.",
|
|
55
|
+
ollamaModelStillUnavailable: (model) => `Ollama model ${model} is still unavailable after downloading.`,
|
|
56
|
+
ollamaPullProgress: (model) => `[ollama] Model missing, downloading: ${model}`,
|
|
57
|
+
ollamaPullFailed: (model, detail) => `Ollama download failed for ${model}: ${detail}`,
|
|
58
|
+
ollamaTagsHttpError: (status) => `Ollama HTTP ${status} while detecting models`,
|
|
59
|
+
ollamaPsHttpError: (status) => `Ollama HTTP ${status} while detecting loaded models`,
|
|
60
|
+
ollamaUnloadFailed: (model, status) => `Failed to unload Ollama model ${model}: HTTP ${status}`
|
|
37
61
|
}
|
|
38
62
|
};
|
package/dist/messages/config.js
CHANGED
|
@@ -9,6 +9,9 @@ export const configMessages = {
|
|
|
9
9
|
ollamaModelUnavailable: (model) => `Modèle Ollama non installé: ${model}. Action: choisis un modèle installé ou lance \`ollama pull ${model}\`.`,
|
|
10
10
|
ollamaModelNoAgent: "Agent ollama-local absent ou invalide dans la config.",
|
|
11
11
|
ollamaModelNoInstalledModels: "Aucun modèle Ollama installé détecté. Action: lance `ollama pull <modèle>`.",
|
|
12
|
+
ollamaModelsCurrent: (model) => `ollama-local: ${model ?? "(non configuré)"}`,
|
|
13
|
+
ollamaModelsApi: (available, baseUrl) => `Ollama API: ${available ? "joignable" : "indisponible"} (${baseUrl})`,
|
|
14
|
+
ollamaModelsInstalled: (models) => `Modèles installés: ${models.length > 0 ? models.join(", ") : "(aucun)"}`,
|
|
12
15
|
updated: (path, defaults, language) => `Configuration mise à jour dans ${path}: ${defaults}, langue: ${language}.`,
|
|
13
16
|
cleared: (path) => `Paramètres par défaut supprimés dans ${path}. Utilise maintenant un preset ou --agent-a/--agent-b pour lancer un débat.`,
|
|
14
17
|
defaultsSummary: (agentA, agentB, turns, summaryAgent, askSummaryAgent, mode, askAgents, interfaceName) => {
|
|
@@ -63,6 +66,9 @@ export const configMessages = {
|
|
|
63
66
|
ollamaModelUnavailable: (model) => `Ollama model is not installed: ${model}. Action: choose an installed model or run \`ollama pull ${model}\`.`,
|
|
64
67
|
ollamaModelNoAgent: "ollama-local agent is missing or invalid in the config.",
|
|
65
68
|
ollamaModelNoInstalledModels: "No installed Ollama model detected. Action: run `ollama pull <model>`.",
|
|
69
|
+
ollamaModelsCurrent: (model) => `ollama-local: ${model ?? "(not configured)"}`,
|
|
70
|
+
ollamaModelsApi: (available, baseUrl) => `Ollama API: ${available ? "reachable" : "unavailable"} (${baseUrl})`,
|
|
71
|
+
ollamaModelsInstalled: (models) => `Installed models: ${models.length > 0 ? models.join(", ") : "(none)"}`,
|
|
66
72
|
updated: (path, defaults, language) => `Configuration updated in ${path}: ${defaults}, language: ${language}.`,
|
|
67
73
|
cleared: (path) => `Default settings cleared in ${path}. Use a preset or --agent-a/--agent-b to start a debate now.`,
|
|
68
74
|
defaultsSummary: (agentA, agentB, turns, summaryAgent, askSummaryAgent, mode, askAgents, interfaceName) => {
|
package/dist/messages/index.js
CHANGED
|
@@ -16,6 +16,7 @@ import { previewMessages } from "./preview.js";
|
|
|
16
16
|
import { rendererMessages } from "./renderers.js";
|
|
17
17
|
import { tuiMessages } from "./tui.js";
|
|
18
18
|
import { updateMessages } from "./update.js";
|
|
19
|
+
/** Construit le dictionnaire `Messages` pour `language`, en assemblant chaque domaine indépendamment. */
|
|
19
20
|
export function createTranslator(language) {
|
|
20
21
|
return {
|
|
21
22
|
adapterErrors: adapterErrorMessages[language],
|
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
/** Tronque une liste de chemins pour l'affichage : 3 premiers + compteur du reste. */
|
|
2
|
+
function summarizePaths(paths) {
|
|
3
|
+
const shown = paths.slice(0, 3);
|
|
4
|
+
const extra = paths.length - shown.length;
|
|
5
|
+
return `${shown.join(", ")}${extra > 0 ? ` (+${extra})` : ""}`;
|
|
6
|
+
}
|
|
1
7
|
export const rendererMessages = {
|
|
2
8
|
fr: {
|
|
3
9
|
subject: (topic) => `Sujet: ${topic}`,
|
|
@@ -5,6 +11,7 @@ export const rendererMessages = {
|
|
|
5
11
|
responsesSummaryContext: (turns, summary, context) => `Réponses: ${turns} | Synthèse: ${summary} | Contexte: ${context}`,
|
|
6
12
|
responsesSummary: (turns, summary) => `Réponses: ${turns} | Synthèse: ${summary}`,
|
|
7
13
|
context: (context) => `Contexte: ${context}`,
|
|
14
|
+
workingFolder: (path) => `Dossier: ${path}`,
|
|
8
15
|
options: (earlyStop, pullModels) => `Options: arrêt anticipé ${earlyStop ? "activé" : "désactivé"}, auto-pull Ollama ${pullModels ? "activé" : "désactivé"}`,
|
|
9
16
|
enabled: "activé",
|
|
10
17
|
disabled: "désactivée",
|
|
@@ -15,7 +22,7 @@ export const rendererMessages = {
|
|
|
15
22
|
summaryTitle: "Synthese",
|
|
16
23
|
exported: (path) => `Palabre exporte: ${path}`,
|
|
17
24
|
noInjectedFiles: "aucun fichier injecté",
|
|
18
|
-
injectedFiles: (count) => `${count} fichier${count > 1 ? "s" : ""} injecté${count > 1 ? "s" : ""}`
|
|
25
|
+
injectedFiles: (count, paths) => `${count} fichier${count > 1 ? "s" : ""} injecté${count > 1 ? "s" : ""} : ${summarizePaths(paths)}`
|
|
19
26
|
},
|
|
20
27
|
en: {
|
|
21
28
|
subject: (topic) => `Subject: ${topic}`,
|
|
@@ -23,6 +30,7 @@ export const rendererMessages = {
|
|
|
23
30
|
responsesSummaryContext: (turns, summary, context) => `Responses: ${turns} | Summary: ${summary} | Context: ${context}`,
|
|
24
31
|
responsesSummary: (turns, summary) => `Responses: ${turns} | Summary: ${summary}`,
|
|
25
32
|
context: (context) => `Context: ${context}`,
|
|
33
|
+
workingFolder: (path) => `Folder: ${path}`,
|
|
26
34
|
options: (earlyStop, pullModels) => `Options: early stop ${earlyStop ? "enabled" : "disabled"}, Ollama auto-pull ${pullModels ? "enabled" : "disabled"}`,
|
|
27
35
|
enabled: "enabled",
|
|
28
36
|
disabled: "disabled",
|
|
@@ -33,6 +41,6 @@ export const rendererMessages = {
|
|
|
33
41
|
summaryTitle: "Summary",
|
|
34
42
|
exported: (path) => `Palabre exported: ${path}`,
|
|
35
43
|
noInjectedFiles: "no injected files",
|
|
36
|
-
injectedFiles: (count) => `${count} injected file${count > 1 ? "s" : ""}`
|
|
44
|
+
injectedFiles: (count, paths) => `${count} injected file${count > 1 ? "s" : ""}: ${summarizePaths(paths)}`
|
|
37
45
|
}
|
|
38
46
|
};
|
package/dist/messages/tui.js
CHANGED
|
@@ -9,7 +9,7 @@ export const tuiMessages = {
|
|
|
9
9
|
roles: "Roles",
|
|
10
10
|
summary: "Synthese",
|
|
11
11
|
ollamaModel: "Modele Ollama",
|
|
12
|
-
ollamaUrl: "Adresse Ollama
|
|
12
|
+
ollamaUrl: "Adresse Ollama",
|
|
13
13
|
ollamaUrlEffective: "Adresse Ollama effective",
|
|
14
14
|
responses: "Tours",
|
|
15
15
|
folder: "Dossier",
|
|
@@ -53,6 +53,9 @@ export const tuiMessages = {
|
|
|
53
53
|
roleReviewer: "cherche risques et tests manquants",
|
|
54
54
|
roleSummarizer: "synthetise fidelement",
|
|
55
55
|
configTitle: "Configuration Palabre",
|
|
56
|
+
configSectionGeneral: "Général",
|
|
57
|
+
exportedFile: "Fichier exporté",
|
|
58
|
+
exportedFolder: "Dossier d'export",
|
|
56
59
|
configFile: "Config",
|
|
57
60
|
interface: "Interface",
|
|
58
61
|
language: "Langue",
|
|
@@ -129,7 +132,7 @@ export const tuiMessages = {
|
|
|
129
132
|
roles: "Roles",
|
|
130
133
|
summary: "Summary",
|
|
131
134
|
ollamaModel: "Ollama model",
|
|
132
|
-
ollamaUrl: "
|
|
135
|
+
ollamaUrl: "Ollama address",
|
|
133
136
|
ollamaUrlEffective: "Effective Ollama address",
|
|
134
137
|
responses: "Turns",
|
|
135
138
|
folder: "Folder",
|
|
@@ -173,6 +176,9 @@ export const tuiMessages = {
|
|
|
173
176
|
roleReviewer: "looks for risks and missing tests",
|
|
174
177
|
roleSummarizer: "summarizes faithfully",
|
|
175
178
|
configTitle: "Palabre Configuration",
|
|
179
|
+
configSectionGeneral: "General",
|
|
180
|
+
exportedFile: "Exported file",
|
|
181
|
+
exportedFolder: "Export folder",
|
|
176
182
|
configFile: "Config",
|
|
177
183
|
interface: "Interface",
|
|
178
184
|
language: "Language",
|