palabre 0.6.4 → 0.8.0
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 +99 -63
- package/dist/adapters/cli-pty.js +14 -0
- package/dist/adapters/cli.js +32 -4
- package/dist/adapters/ollama.js +15 -0
- package/dist/agentRegistry.js +3 -2
- package/dist/args.js +22 -1
- package/dist/config.js +78 -4
- package/dist/configWizard.js +29 -6
- package/dist/discovery.js +3 -1
- package/dist/doctor.js +18 -0
- package/dist/index.js +593 -55
- package/dist/messages/agents.js +4 -2
- package/dist/messages/common.js +4 -0
- package/dist/messages/config.js +28 -8
- package/dist/messages/doctor.js +8 -0
- package/dist/messages/help.js +58 -2
- package/dist/messages/index.js +2 -0
- package/dist/messages/init.js +2 -2
- package/dist/messages/new.js +14 -0
- package/dist/messages/orchestrator.js +2 -0
- package/dist/messages/output.js +10 -0
- package/dist/messages/preview.js +4 -2
- package/dist/messages/prompt.js +46 -2
- package/dist/messages/renderers.js +2 -2
- package/dist/messages/tui.js +192 -0
- package/dist/messages/update.js +16 -2
- package/dist/new.js +158 -4
- package/dist/orchestrator.js +199 -6
- package/dist/output.js +31 -8
- package/dist/presets.js +48 -0
- package/dist/prompt.js +61 -10
- package/dist/renderers/console.js +39 -3
- package/dist/renderers/ndjson.js +30 -1
- package/dist/renderers/tui.js +932 -0
- package/dist/update.js +2 -0
- package/dist/version.js +54 -0
- package/package.json +2 -1
package/dist/index.js
CHANGED
|
@@ -1,8 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
import path from "node:path";
|
|
4
|
-
import { fileURLToPath } from "node:url";
|
|
5
|
-
import { assertRunnableConfig, configExists, createConfigFromDiscovery, DEFAULT_CONFIG_PATH, GLOBAL_CONFIG_PATH, loadConfig, resolveDefaultConfigPath, resolveOutputDir, writeExampleConfig } from "./config.js";
|
|
2
|
+
import { assertRunnableConfig, configExists, createConfigFromDiscovery, DEFAULT_CONFIG_PATH, GLOBAL_CONFIG_PATH, loadConfig, resolveDefaultConfigPath, resolveOutputDir, setOllamaModel, syncDetectedAgents, syncOllamaModel, writeExampleConfig } from "./config.js";
|
|
6
3
|
import { loadProjectInputs } from "./context.js";
|
|
7
4
|
import { buildContextScan } from "./contextScan.js";
|
|
8
5
|
import { discoverLocalTools } from "./discovery.js";
|
|
@@ -10,18 +7,20 @@ import { runDoctor } from "./doctor.js";
|
|
|
10
7
|
import { AdapterError, formatAdapterError } from "./errors.js";
|
|
11
8
|
import { runConfigWizard } from "./configWizard.js";
|
|
12
9
|
import { createTranslator, DEFAULT_LANGUAGE, parseLanguage, resolveLanguage } from "./i18n.js";
|
|
13
|
-
import { DEFAULT_TURNS, parseTurnsFlag, turnsOrDefault } from "./limits.js";
|
|
10
|
+
import { DEFAULT_TURNS, parseTurnsFlag, turnsOrDefault, validateTurns } from "./limits.js";
|
|
14
11
|
import { formatAgentPrompt } from "./prompt.js";
|
|
15
12
|
import { runNewWizard } from "./new.js";
|
|
16
13
|
import { listPresetNames, listPresetsWithAvailability, resolvePreset } from "./presets.js";
|
|
17
14
|
import { createConsoleRenderer } from "./renderers/console.js";
|
|
18
15
|
import { createNdjsonRenderer } from "./renderers/ndjson.js";
|
|
19
|
-
import {
|
|
16
|
+
import { createTuiRenderer, promptTuiAgentsWizard, promptTuiConfigCommand, promptTuiHomeTopic, promptTuiRolesWizard, renderTuiConfig, renderTuiHelp, renderTuiHome } from "./renderers/tui.js";
|
|
17
|
+
import { MAX_ASK_AGENTS, runAsk, runDebate } from "./orchestrator.js";
|
|
20
18
|
import { writeDebateMarkdown } from "./output.js";
|
|
21
19
|
import { applySourceUpdate, formatUpdateInstructions, getUpdateInfo } from "./update.js";
|
|
22
20
|
import { createSessionContext } from "./session.js";
|
|
23
21
|
import { getStringListFlag, parseArgs } from "./args.js";
|
|
24
22
|
import { detectedAgentNames, detectionForCommand } from "./agentRegistry.js";
|
|
23
|
+
import { getPackageVersion } from "./version.js";
|
|
25
24
|
/** Point d'entrée principal du CLI Palabre. Dispatche vers la commande appropriée selon les arguments. */
|
|
26
25
|
async function main() {
|
|
27
26
|
const rawArgs = process.argv.slice(2);
|
|
@@ -37,7 +36,7 @@ async function main() {
|
|
|
37
36
|
return;
|
|
38
37
|
}
|
|
39
38
|
if (parsed.command === "doctor") {
|
|
40
|
-
const result = await runDoctor(optionalString(parsed.flags.config), Boolean(parsed.flags.plain), optionalString(parsed.flags.language));
|
|
39
|
+
const result = await runDoctor(optionalString(parsed.flags.config), Boolean(parsed.flags.plain || parsed.flags.terminal), optionalString(parsed.flags.language));
|
|
41
40
|
console.log(result.output);
|
|
42
41
|
process.exitCode = result.ok ? 0 : 1;
|
|
43
42
|
return;
|
|
@@ -108,12 +107,106 @@ async function main() {
|
|
|
108
107
|
return;
|
|
109
108
|
}
|
|
110
109
|
const config = await loadConfig(configPath);
|
|
111
|
-
|
|
110
|
+
let language = resolveLanguage({
|
|
112
111
|
explicitLanguage: optionalString(parsed.flags.language),
|
|
113
112
|
configLanguage: config.language
|
|
114
113
|
});
|
|
115
|
-
|
|
114
|
+
let messages = createTranslator(language);
|
|
116
115
|
assertRunnableConfig(config, messages, configPath);
|
|
116
|
+
if (shouldOpenTuiHome(parsed)) {
|
|
117
|
+
let tuiMode = config.defaults?.mode ?? "debate";
|
|
118
|
+
const tuiVersion = await getPackageVersion();
|
|
119
|
+
let tuiNotice;
|
|
120
|
+
for (;;) {
|
|
121
|
+
renderTuiHome(config, configPath, messages, { mode: tuiMode, version: tuiVersion });
|
|
122
|
+
const tuiInput = await promptTuiHomeTopic(tuiMode, messages, { notice: tuiNotice });
|
|
123
|
+
tuiNotice = undefined;
|
|
124
|
+
if (!tuiInput) {
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
if (tuiInput.kind === "help") {
|
|
128
|
+
renderTuiHelp(messages);
|
|
129
|
+
const nextInput = await promptTuiHomeTopic(tuiMode, messages);
|
|
130
|
+
if (!nextInput) {
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
if (nextInput.kind === "help") {
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
136
|
+
if (nextInput.kind === "roles") {
|
|
137
|
+
const result = await runTuiRolesWizard(configPath, config, messages, tuiMode, nextInput.roles);
|
|
138
|
+
if (result.quit)
|
|
139
|
+
return;
|
|
140
|
+
tuiNotice = result.notice;
|
|
141
|
+
continue;
|
|
142
|
+
}
|
|
143
|
+
if (nextInput.kind === "agents") {
|
|
144
|
+
const result = await runTuiAgentsWizard(configPath, config, messages, tuiMode, nextInput.agents);
|
|
145
|
+
if (result.quit)
|
|
146
|
+
return;
|
|
147
|
+
tuiNotice = result.notice;
|
|
148
|
+
continue;
|
|
149
|
+
}
|
|
150
|
+
if (nextInput.kind === "mode") {
|
|
151
|
+
tuiMode = nextInput.mode;
|
|
152
|
+
continue;
|
|
153
|
+
}
|
|
154
|
+
if (nextInput.kind === "config") {
|
|
155
|
+
const result = await runTuiConfigLoop(configPath, config, messages, tuiMode);
|
|
156
|
+
if (result.quit)
|
|
157
|
+
return;
|
|
158
|
+
tuiMode = result.mode;
|
|
159
|
+
language = resolveLanguage({ explicitLanguage: optionalString(parsed.flags.language), configLanguage: config.language });
|
|
160
|
+
messages = createTranslator(language);
|
|
161
|
+
continue;
|
|
162
|
+
}
|
|
163
|
+
if (nextInput.kind === "new") {
|
|
164
|
+
parsed.command = "new";
|
|
165
|
+
parsed.commandExplicit = true;
|
|
166
|
+
}
|
|
167
|
+
else {
|
|
168
|
+
parsed.flags.topic = nextInput.topic;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
else if (tuiInput.kind === "mode") {
|
|
172
|
+
tuiMode = tuiInput.mode;
|
|
173
|
+
continue;
|
|
174
|
+
}
|
|
175
|
+
else if (tuiInput.kind === "roles") {
|
|
176
|
+
const result = await runTuiRolesWizard(configPath, config, messages, tuiMode, tuiInput.roles);
|
|
177
|
+
if (result.quit)
|
|
178
|
+
return;
|
|
179
|
+
tuiNotice = result.notice;
|
|
180
|
+
continue;
|
|
181
|
+
}
|
|
182
|
+
else if (tuiInput.kind === "agents") {
|
|
183
|
+
const result = await runTuiAgentsWizard(configPath, config, messages, tuiMode, tuiInput.agents);
|
|
184
|
+
if (result.quit)
|
|
185
|
+
return;
|
|
186
|
+
tuiNotice = result.notice;
|
|
187
|
+
continue;
|
|
188
|
+
}
|
|
189
|
+
else if (tuiInput.kind === "config") {
|
|
190
|
+
const result = await runTuiConfigLoop(configPath, config, messages, tuiMode);
|
|
191
|
+
if (result.quit)
|
|
192
|
+
return;
|
|
193
|
+
tuiMode = result.mode;
|
|
194
|
+
language = resolveLanguage({ explicitLanguage: optionalString(parsed.flags.language), configLanguage: config.language });
|
|
195
|
+
messages = createTranslator(language);
|
|
196
|
+
continue;
|
|
197
|
+
}
|
|
198
|
+
else if (tuiInput.kind === "new") {
|
|
199
|
+
parsed.command = "new";
|
|
200
|
+
parsed.commandExplicit = true;
|
|
201
|
+
}
|
|
202
|
+
else {
|
|
203
|
+
parsed.flags.topic = tuiInput.topic;
|
|
204
|
+
}
|
|
205
|
+
parsed.flags.mode = tuiMode;
|
|
206
|
+
parsed.flags.renderer = "tui";
|
|
207
|
+
break;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
117
210
|
if (parsed.command === "new") {
|
|
118
211
|
const selection = await runNewWizard(config, messages);
|
|
119
212
|
if (!selection) {
|
|
@@ -143,6 +236,10 @@ async function main() {
|
|
|
143
236
|
parsed.flags.files = selection.files;
|
|
144
237
|
if (selection.context.length > 0)
|
|
145
238
|
parsed.flags.context = selection.context;
|
|
239
|
+
if (selection.mode)
|
|
240
|
+
parsed.flags.mode = selection.mode;
|
|
241
|
+
if (selection.askAgents && selection.askAgents.length > 0)
|
|
242
|
+
parsed.flags.agents = selection.askAgents;
|
|
146
243
|
}
|
|
147
244
|
const topic = optionalString(parsed.flags.topic) ?? "";
|
|
148
245
|
const context = await loadProjectInputs(getStringListFlag(parsed.flags.files), getStringListFlag(parsed.flags.context), process.cwd(), messages);
|
|
@@ -151,37 +248,59 @@ async function main() {
|
|
|
151
248
|
if (!topic) {
|
|
152
249
|
throw new Error(messages.common.topicRequired);
|
|
153
250
|
}
|
|
251
|
+
const mode = parseModeFlag(optionalString(parsed.flags.mode) ?? config.defaults?.mode, messages);
|
|
252
|
+
const explicitAskAgents = getStringListFlag(parsed.flags.agents);
|
|
253
|
+
const askAgentSeeds = explicitAskAgents.length > 0 ? explicitAskAgents : config.defaults?.askAgents ?? [];
|
|
254
|
+
const agentA = resolveAgentName("agent A", parsed.flags["agent-a"], preset?.agentA, askAgentSeeds[0] ?? config.defaults?.agentA, messages);
|
|
255
|
+
const agentB = resolveAgentName("agent B", parsed.flags["agent-b"], preset?.agentB, askAgentSeeds[1] ?? askAgentSeeds[0] ?? config.defaults?.agentB, messages);
|
|
256
|
+
const askAgents = mode === "ask" ? resolveAskAgents(explicitAskAgents, config.defaults?.askAgents, [agentA, agentB], messages) : undefined;
|
|
154
257
|
const options = {
|
|
258
|
+
mode,
|
|
155
259
|
language,
|
|
156
260
|
topic,
|
|
157
|
-
agentA
|
|
158
|
-
agentB
|
|
261
|
+
agentA,
|
|
262
|
+
agentB,
|
|
263
|
+
askAgents,
|
|
159
264
|
turns: parseTurnsFlag(parsed.flags.turns, config.defaults?.turns ?? DEFAULT_TURNS, "--turns", messages),
|
|
160
265
|
session: createSessionContext(),
|
|
161
266
|
files: context.files,
|
|
162
267
|
modelA: optionalString(parsed.flags["model-a"]),
|
|
163
268
|
modelB: optionalString(parsed.flags["model-b"]),
|
|
164
269
|
pullModels: Boolean(parsed.flags["pull-models"]),
|
|
165
|
-
summaryAgent:
|
|
270
|
+
summaryAgent: resolveSummaryAgentOption(parsed.flags["summary-agent"], config.defaults, mode),
|
|
166
271
|
summaryModel: optionalString(parsed.flags["summary-model"]),
|
|
167
272
|
summaryEnabled: !parsed.flags["no-summary"],
|
|
168
273
|
earlyStopOnAgreement: !parsed.flags["no-early-stop"],
|
|
169
|
-
plainOutput: Boolean(parsed.flags.plain)
|
|
274
|
+
plainOutput: Boolean(parsed.flags.plain || parsed.flags.terminal),
|
|
275
|
+
signal: debateAbortSignal()
|
|
170
276
|
};
|
|
171
277
|
if (parsed.flags["show-prompt"]) {
|
|
172
278
|
printContextWarnings(context.warnings, messages);
|
|
173
279
|
printPromptPreview(config, options, language, messages);
|
|
174
280
|
return;
|
|
175
281
|
}
|
|
176
|
-
const renderer = createRendererFromFlags(parsed.flags, options.plainOutput, messages);
|
|
282
|
+
const renderer = createRendererFromFlags(parsed.flags, options.plainOutput, config.defaults?.interface, messages);
|
|
177
283
|
context.warnings.forEach((warning) => renderer.warning(warning));
|
|
178
|
-
const result =
|
|
284
|
+
const result = options.mode === "ask"
|
|
285
|
+
? await runAsk(config, options, renderer, messages)
|
|
286
|
+
: await runDebate(config, options, renderer, messages);
|
|
179
287
|
const outputPath = await writeDebateMarkdown(resolveOutputDir(config.outputDir), result.options, result.messages, result.summary, result.stopReason, messages, result.failure);
|
|
180
288
|
renderer.done(outputPath);
|
|
181
289
|
if (result.failure) {
|
|
182
|
-
process.exitCode = 1;
|
|
290
|
+
process.exitCode = result.failure.kind === "cancelled" ? 130 : 1;
|
|
183
291
|
}
|
|
184
292
|
}
|
|
293
|
+
function debateAbortSignal() {
|
|
294
|
+
const controller = new AbortController();
|
|
295
|
+
const abort = () => {
|
|
296
|
+
if (!controller.signal.aborted) {
|
|
297
|
+
controller.abort();
|
|
298
|
+
}
|
|
299
|
+
};
|
|
300
|
+
process.once("SIGINT", abort);
|
|
301
|
+
process.once("SIGTERM", abort);
|
|
302
|
+
return controller.signal;
|
|
303
|
+
}
|
|
185
304
|
/**
|
|
186
305
|
* Exécute la commande `agents` : charge la config et affiche les agents déclarés avec leur état de détection.
|
|
187
306
|
* @param flags - Flags parsés depuis la ligne de commande.
|
|
@@ -220,6 +339,19 @@ async function runConfigCommand(flags) {
|
|
|
220
339
|
configLanguage: config.language
|
|
221
340
|
});
|
|
222
341
|
const messages = createTranslator(language);
|
|
342
|
+
if (flags["ollama-models"]) {
|
|
343
|
+
await runOllamaModelsCommand(config, Boolean(flags.json));
|
|
344
|
+
return;
|
|
345
|
+
}
|
|
346
|
+
const setOllamaModelValue = optionalString(flags["set-ollama-model"]);
|
|
347
|
+
if (setOllamaModelValue !== undefined) {
|
|
348
|
+
await runSetOllamaModelCommand(configPath, config, setOllamaModelValue, messages);
|
|
349
|
+
return;
|
|
350
|
+
}
|
|
351
|
+
if (flags["sync-ollama-model"]) {
|
|
352
|
+
await runSyncOllamaModelCommand(configPath, config, messages);
|
|
353
|
+
return;
|
|
354
|
+
}
|
|
223
355
|
if (flags["sync-agents"]) {
|
|
224
356
|
const discovery = await discoverLocalTools();
|
|
225
357
|
const addedAgents = syncDetectedAgents(config, discovery);
|
|
@@ -234,8 +366,18 @@ async function runConfigCommand(flags) {
|
|
|
234
366
|
const defaultAgents = getStringListFlag(flags["set-defaults"]);
|
|
235
367
|
const hasTurnsFlag = flags.turns !== undefined;
|
|
236
368
|
const summaryAgentValue = optionalString(flags["summary-agent"]);
|
|
369
|
+
const askSummaryAgentValue = optionalString(flags["ask-summary-agent"]);
|
|
370
|
+
const interfaceValue = optionalString(flags.interface);
|
|
371
|
+
const modeValue = optionalString(flags.mode);
|
|
372
|
+
const askAgentsValue = getStringListFlag(flags["ask-agents"]);
|
|
237
373
|
const languageValue = explicitLanguage;
|
|
238
|
-
const changesDefaults = defaultAgents.length > 0
|
|
374
|
+
const changesDefaults = defaultAgents.length > 0
|
|
375
|
+
|| hasTurnsFlag
|
|
376
|
+
|| summaryAgentValue !== undefined
|
|
377
|
+
|| askSummaryAgentValue !== undefined
|
|
378
|
+
|| interfaceValue !== undefined
|
|
379
|
+
|| modeValue !== undefined
|
|
380
|
+
|| askAgentsValue.length > 0;
|
|
239
381
|
if (changesDefaults || languageValue !== undefined) {
|
|
240
382
|
const nextDefaults = { ...(config.defaults ?? {}) };
|
|
241
383
|
if (defaultAgents.length > 0) {
|
|
@@ -260,6 +402,24 @@ async function runConfigCommand(flags) {
|
|
|
260
402
|
nextDefaults.summaryAgent = summaryAgentValue;
|
|
261
403
|
}
|
|
262
404
|
}
|
|
405
|
+
if (askSummaryAgentValue !== undefined) {
|
|
406
|
+
if (isNoneValue(askSummaryAgentValue)) {
|
|
407
|
+
delete nextDefaults.askSummaryAgent;
|
|
408
|
+
}
|
|
409
|
+
else {
|
|
410
|
+
assertKnownAgent(config, askSummaryAgentValue, "defaults.askSummaryAgent", messages);
|
|
411
|
+
nextDefaults.askSummaryAgent = askSummaryAgentValue;
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
if (interfaceValue !== undefined) {
|
|
415
|
+
nextDefaults.interface = parseInterfaceFlag(interfaceValue, messages);
|
|
416
|
+
}
|
|
417
|
+
if (modeValue !== undefined) {
|
|
418
|
+
nextDefaults.mode = parseModeFlag(modeValue, messages);
|
|
419
|
+
}
|
|
420
|
+
if (askAgentsValue.length > 0) {
|
|
421
|
+
nextDefaults.askAgents = normalizeAskAgentsForConfig(config, askAgentsValue, messages);
|
|
422
|
+
}
|
|
263
423
|
if (languageValue !== undefined) {
|
|
264
424
|
config.language = parseLanguage(languageValue, "--language");
|
|
265
425
|
}
|
|
@@ -278,6 +438,315 @@ async function runConfigCommand(flags) {
|
|
|
278
438
|
}
|
|
279
439
|
await runConfigWizard(configPath, config, messages);
|
|
280
440
|
}
|
|
441
|
+
async function runTuiConfigLoop(configPath, config, messages, initialMode) {
|
|
442
|
+
let mode = initialMode;
|
|
443
|
+
let notice;
|
|
444
|
+
let currentMessages = messages;
|
|
445
|
+
for (;;) {
|
|
446
|
+
renderTuiConfig(config, configPath, mode, currentMessages, { message: notice });
|
|
447
|
+
notice = undefined;
|
|
448
|
+
const input = await promptTuiConfigCommand(mode, currentMessages);
|
|
449
|
+
if (input.kind === "quit") {
|
|
450
|
+
return { mode, quit: true };
|
|
451
|
+
}
|
|
452
|
+
if (input.kind === "back") {
|
|
453
|
+
return { mode, quit: false };
|
|
454
|
+
}
|
|
455
|
+
if (input.kind === "unknown") {
|
|
456
|
+
notice = input.message;
|
|
457
|
+
continue;
|
|
458
|
+
}
|
|
459
|
+
if (input.kind === "mode") {
|
|
460
|
+
mode = mode === "ask" ? "debate" : "ask";
|
|
461
|
+
notice = mode === "ask" ? currentMessages.tui.askConfigMode : currentMessages.tui.debateConfigMode;
|
|
462
|
+
continue;
|
|
463
|
+
}
|
|
464
|
+
if (input.kind === "default-mode") {
|
|
465
|
+
config.defaults = { ...(config.defaults ?? {}), mode };
|
|
466
|
+
await writeExampleConfig(configPath, config);
|
|
467
|
+
notice = mode === "ask" ? currentMessages.tui.askDefaultMode : currentMessages.tui.debateDefaultMode;
|
|
468
|
+
continue;
|
|
469
|
+
}
|
|
470
|
+
if (input.kind === "interface") {
|
|
471
|
+
config.defaults = { ...(config.defaults ?? {}), interface: input.interfaceName };
|
|
472
|
+
await writeExampleConfig(configPath, config);
|
|
473
|
+
notice = currentMessages.tui.interfaceDefault(input.interfaceName);
|
|
474
|
+
continue;
|
|
475
|
+
}
|
|
476
|
+
if (input.kind === "language") {
|
|
477
|
+
config.language = parseLanguage(input.language, "--language");
|
|
478
|
+
await writeExampleConfig(configPath, config);
|
|
479
|
+
currentMessages = createTranslator(config.language ?? DEFAULT_LANGUAGE);
|
|
480
|
+
notice = currentMessages.tui.languageUpdated(input.language);
|
|
481
|
+
continue;
|
|
482
|
+
}
|
|
483
|
+
if (input.kind === "agents") {
|
|
484
|
+
try {
|
|
485
|
+
const agentsInput = input.agents.length > 0
|
|
486
|
+
? { kind: "agents", agents: input.agents }
|
|
487
|
+
: await promptTuiAgentsWizard(config, mode, currentMessages);
|
|
488
|
+
if (agentsInput.kind === "quit") {
|
|
489
|
+
return { mode, quit: true };
|
|
490
|
+
}
|
|
491
|
+
if (agentsInput.kind === "back" || agentsInput.agents.length === 0) {
|
|
492
|
+
notice = currentMessages.tui.agentsUnchanged;
|
|
493
|
+
continue;
|
|
494
|
+
}
|
|
495
|
+
if (mode === "ask") {
|
|
496
|
+
const agents = normalizeTuiAskAgents(config, agentsInput.agents, currentMessages);
|
|
497
|
+
config.defaults = { ...(config.defaults ?? {}), askAgents: agents };
|
|
498
|
+
await writeExampleConfig(configPath, config);
|
|
499
|
+
notice = currentMessages.tui.askAgentsUpdated(agents.join(", "));
|
|
500
|
+
}
|
|
501
|
+
else {
|
|
502
|
+
const [agentA, agentB] = normalizeTuiDebateAgents(config, agentsInput.agents, currentMessages);
|
|
503
|
+
config.defaults = { ...(config.defaults ?? {}), agentA, agentB };
|
|
504
|
+
await writeExampleConfig(configPath, config);
|
|
505
|
+
notice = currentMessages.tui.debateAgentsUpdated(`${agentA} <-> ${agentB}`);
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
catch (error) {
|
|
509
|
+
notice = error instanceof Error ? error.message : String(error);
|
|
510
|
+
}
|
|
511
|
+
continue;
|
|
512
|
+
}
|
|
513
|
+
if (input.kind === "roles") {
|
|
514
|
+
try {
|
|
515
|
+
const rolesInput = input.roles.length > 0
|
|
516
|
+
? { kind: "roles", roles: input.roles }
|
|
517
|
+
: await promptTuiRolesWizard(config, mode, currentMessages);
|
|
518
|
+
if (rolesInput.kind === "quit") {
|
|
519
|
+
return { mode, quit: true };
|
|
520
|
+
}
|
|
521
|
+
if (rolesInput.kind === "back" || rolesInput.roles.length === 0) {
|
|
522
|
+
notice = currentMessages.tui.rolesUnchanged;
|
|
523
|
+
continue;
|
|
524
|
+
}
|
|
525
|
+
notice = applyTuiRoles(config, mode, rolesInput.roles, currentMessages);
|
|
526
|
+
await writeExampleConfig(configPath, config);
|
|
527
|
+
}
|
|
528
|
+
catch (error) {
|
|
529
|
+
notice = error instanceof Error ? error.message : String(error);
|
|
530
|
+
}
|
|
531
|
+
continue;
|
|
532
|
+
}
|
|
533
|
+
if (input.kind === "turns") {
|
|
534
|
+
if (mode === "ask") {
|
|
535
|
+
notice = currentMessages.tui.askTurnsNotice;
|
|
536
|
+
continue;
|
|
537
|
+
}
|
|
538
|
+
try {
|
|
539
|
+
validateTurns(input.turns, "--turns", currentMessages);
|
|
540
|
+
config.defaults = { ...(config.defaults ?? {}), turns: input.turns };
|
|
541
|
+
await writeExampleConfig(configPath, config);
|
|
542
|
+
notice = currentMessages.tui.turnsUpdated(input.turns);
|
|
543
|
+
}
|
|
544
|
+
catch (error) {
|
|
545
|
+
notice = error instanceof Error ? error.message : String(error);
|
|
546
|
+
}
|
|
547
|
+
continue;
|
|
548
|
+
}
|
|
549
|
+
if (input.kind === "summary") {
|
|
550
|
+
try {
|
|
551
|
+
const nextDefaults = { ...(config.defaults ?? {}) };
|
|
552
|
+
if (input.agent !== undefined) {
|
|
553
|
+
assertKnownAgent(config, input.agent, mode === "ask" ? "defaults.askSummaryAgent" : "defaults.summaryAgent", currentMessages);
|
|
554
|
+
}
|
|
555
|
+
if (mode === "ask") {
|
|
556
|
+
if (input.agent === undefined) {
|
|
557
|
+
delete nextDefaults.askSummaryAgent;
|
|
558
|
+
notice = currentMessages.tui.askSummaryFallback;
|
|
559
|
+
}
|
|
560
|
+
else {
|
|
561
|
+
nextDefaults.askSummaryAgent = input.agent;
|
|
562
|
+
notice = currentMessages.tui.askSummaryAgent(input.agent);
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
else if (input.agent === undefined) {
|
|
566
|
+
delete nextDefaults.summaryAgent;
|
|
567
|
+
notice = currentMessages.tui.debateSummaryFallback;
|
|
568
|
+
}
|
|
569
|
+
else {
|
|
570
|
+
nextDefaults.summaryAgent = input.agent;
|
|
571
|
+
notice = currentMessages.tui.debateSummaryAgent(input.agent);
|
|
572
|
+
}
|
|
573
|
+
config.defaults = nextDefaults;
|
|
574
|
+
await writeExampleConfig(configPath, config);
|
|
575
|
+
}
|
|
576
|
+
catch (error) {
|
|
577
|
+
notice = error instanceof Error ? error.message : String(error);
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
function normalizeTuiDebateAgents(config, agents, messages) {
|
|
583
|
+
const unique = agents.map((agent) => agent.trim()).filter((agent, index, list) => agent && list.indexOf(agent) === index);
|
|
584
|
+
if (unique.length !== 2) {
|
|
585
|
+
throw new Error(messages.tui.debateAgentsUsage);
|
|
586
|
+
}
|
|
587
|
+
assertKnownAgent(config, unique[0], "defaults.agentA", messages);
|
|
588
|
+
assertKnownAgent(config, unique[1], "defaults.agentB", messages);
|
|
589
|
+
return [unique[0], unique[1]];
|
|
590
|
+
}
|
|
591
|
+
function normalizeTuiAskAgents(config, agents, messages) {
|
|
592
|
+
const unique = agents.map((agent) => agent.trim()).filter((agent, index, list) => agent && list.indexOf(agent) === index);
|
|
593
|
+
if (unique.length === 0) {
|
|
594
|
+
throw new Error(messages.tui.askAgentsUsage);
|
|
595
|
+
}
|
|
596
|
+
if (unique.length > MAX_ASK_AGENTS) {
|
|
597
|
+
throw new Error(messages.common.tooManyAskAgents(MAX_ASK_AGENTS));
|
|
598
|
+
}
|
|
599
|
+
unique.forEach((agent) => assertKnownAgent(config, agent, "defaults.askAgents", messages));
|
|
600
|
+
return unique;
|
|
601
|
+
}
|
|
602
|
+
async function runTuiAgentsWizard(configPath, config, messages, mode, inlineAgents = []) {
|
|
603
|
+
try {
|
|
604
|
+
const agentsInput = inlineAgents.length > 0
|
|
605
|
+
? { kind: "agents", agents: inlineAgents }
|
|
606
|
+
: await promptTuiAgentsWizard(config, mode, messages);
|
|
607
|
+
if (agentsInput.kind === "quit") {
|
|
608
|
+
return { quit: true };
|
|
609
|
+
}
|
|
610
|
+
if (agentsInput.kind === "back" || agentsInput.agents.length === 0) {
|
|
611
|
+
return { quit: false };
|
|
612
|
+
}
|
|
613
|
+
const notice = applyTuiAgents(config, mode, agentsInput.agents, messages);
|
|
614
|
+
await writeExampleConfig(configPath, config);
|
|
615
|
+
return { notice, quit: false };
|
|
616
|
+
}
|
|
617
|
+
catch (error) {
|
|
618
|
+
return { notice: messages.tui.agentsError(error instanceof Error ? error.message : String(error)), quit: false };
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
async function runTuiRolesWizard(configPath, config, messages, mode, inlineRoles = []) {
|
|
622
|
+
try {
|
|
623
|
+
const rolesInput = inlineRoles.length > 0
|
|
624
|
+
? { kind: "roles", roles: inlineRoles }
|
|
625
|
+
: await promptTuiRolesWizard(config, mode, messages);
|
|
626
|
+
if (rolesInput.kind === "quit") {
|
|
627
|
+
return { quit: true };
|
|
628
|
+
}
|
|
629
|
+
if (rolesInput.kind === "back" || rolesInput.roles.length === 0) {
|
|
630
|
+
return { quit: false };
|
|
631
|
+
}
|
|
632
|
+
const notice = applyTuiRoles(config, mode, rolesInput.roles, messages);
|
|
633
|
+
await writeExampleConfig(configPath, config);
|
|
634
|
+
return { notice, quit: false };
|
|
635
|
+
}
|
|
636
|
+
catch (error) {
|
|
637
|
+
return { notice: messages.tui.rolesError(error instanceof Error ? error.message : String(error)), quit: false };
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
function applyTuiAgents(config, mode, agentNames, messages) {
|
|
641
|
+
if (mode === "ask") {
|
|
642
|
+
const agents = normalizeTuiAskAgents(config, agentNames, messages);
|
|
643
|
+
config.defaults = { ...(config.defaults ?? {}), askAgents: agents };
|
|
644
|
+
return messages.tui.askAgentsUpdated(agents.join(", "));
|
|
645
|
+
}
|
|
646
|
+
const [agentA, agentB] = normalizeTuiDebateAgents(config, agentNames, messages);
|
|
647
|
+
config.defaults = { ...(config.defaults ?? {}), agentA, agentB };
|
|
648
|
+
return messages.tui.debateAgentsUpdated(`${agentA} <-> ${agentB}`);
|
|
649
|
+
}
|
|
650
|
+
function applyTuiRoles(config, mode, roleNames, messages) {
|
|
651
|
+
const agents = activeAgentsForMode(config, mode);
|
|
652
|
+
if (agents.length === 0) {
|
|
653
|
+
throw new Error(mode === "ask" ? messages.tui.noAskAgentsConfigured : messages.tui.noDebateAgentsConfigured);
|
|
654
|
+
}
|
|
655
|
+
const roles = normalizeTuiRoles(roleNames, agents, mode, messages);
|
|
656
|
+
agents.forEach((agent, index) => {
|
|
657
|
+
config.agents[agent].role = roles[index];
|
|
658
|
+
});
|
|
659
|
+
return mode === "ask"
|
|
660
|
+
? messages.tui.askRolesUpdated(roles.join(", "))
|
|
661
|
+
: messages.tui.debateRolesUpdated(roles.join(" <-> "));
|
|
662
|
+
}
|
|
663
|
+
function activeAgentsForMode(config, mode) {
|
|
664
|
+
const defaults = config.defaults ?? {};
|
|
665
|
+
if (mode === "ask") {
|
|
666
|
+
if (defaults.askAgents && defaults.askAgents.length > 0) {
|
|
667
|
+
return defaults.askAgents.filter((agent) => Boolean(config.agents[agent]));
|
|
668
|
+
}
|
|
669
|
+
return [defaults.agentA, defaults.agentB].filter((agent) => Boolean(agent && config.agents[agent]));
|
|
670
|
+
}
|
|
671
|
+
return [defaults.agentA, defaults.agentB].filter((agent) => Boolean(agent && config.agents[agent]));
|
|
672
|
+
}
|
|
673
|
+
function normalizeTuiRoles(roleNames, agents, mode, messages) {
|
|
674
|
+
const roles = roleNames.map((role) => role.trim().toLowerCase()).filter(Boolean);
|
|
675
|
+
const expectedCount = agents.length;
|
|
676
|
+
if (roles.length < expectedCount) {
|
|
677
|
+
const agentLabel = mode === "ask"
|
|
678
|
+
? agents.join(", ")
|
|
679
|
+
: agents.join(" <-> ");
|
|
680
|
+
throw new Error(messages.tui.rolesCountError(roles.length, expectedCount, agentLabel));
|
|
681
|
+
}
|
|
682
|
+
return roles.slice(0, expectedCount).map((role) => {
|
|
683
|
+
if (isAgentRole(role)) {
|
|
684
|
+
return role;
|
|
685
|
+
}
|
|
686
|
+
throw new Error(messages.tui.unknownRole(role, VALID_AGENT_ROLES.join(", ")));
|
|
687
|
+
});
|
|
688
|
+
}
|
|
689
|
+
function isAgentRole(value) {
|
|
690
|
+
return VALID_AGENT_ROLES.includes(value);
|
|
691
|
+
}
|
|
692
|
+
const VALID_AGENT_ROLES = ["implementer", "reviewer", "architect", "scout", "critic", "summarizer"];
|
|
693
|
+
async function runOllamaModelsCommand(config, json) {
|
|
694
|
+
const discovery = await discoverLocalTools();
|
|
695
|
+
const agent = config.agents["ollama-local"];
|
|
696
|
+
const currentModel = agent?.type === "ollama" ? agent.model : null;
|
|
697
|
+
const payload = {
|
|
698
|
+
v: 1,
|
|
699
|
+
agent: "ollama-local",
|
|
700
|
+
available: discovery.ollama.available,
|
|
701
|
+
baseUrl: discovery.ollama.baseUrl,
|
|
702
|
+
currentModel,
|
|
703
|
+
currentModelInstalled: currentModel ? discovery.ollama.models.includes(currentModel) : false,
|
|
704
|
+
installedModels: discovery.ollama.models
|
|
705
|
+
};
|
|
706
|
+
if (json) {
|
|
707
|
+
console.log(JSON.stringify(payload, null, 2));
|
|
708
|
+
return;
|
|
709
|
+
}
|
|
710
|
+
console.log(`ollama-local: ${currentModel ?? "(non configuré)"}`);
|
|
711
|
+
console.log(`Ollama API: ${discovery.ollama.available ? "joignable" : "indisponible"} (${discovery.ollama.baseUrl})`);
|
|
712
|
+
console.log(`Modèles installés: ${discovery.ollama.models.length > 0 ? discovery.ollama.models.join(", ") : "(aucun)"}`);
|
|
713
|
+
}
|
|
714
|
+
async function runSetOllamaModelCommand(configPath, config, model, messages) {
|
|
715
|
+
const trimmed = model.trim();
|
|
716
|
+
if (!trimmed) {
|
|
717
|
+
throw new Error(messages.common.optionRequiresValue("--set-ollama-model"));
|
|
718
|
+
}
|
|
719
|
+
const discovery = await discoverLocalTools();
|
|
720
|
+
const agent = config.agents["ollama-local"];
|
|
721
|
+
if (agent?.type !== "ollama") {
|
|
722
|
+
throw new Error(messages.config.ollamaModelNoAgent);
|
|
723
|
+
}
|
|
724
|
+
if (!discovery.ollama.models.includes(trimmed)) {
|
|
725
|
+
throw new Error(messages.config.ollamaModelUnavailable(trimmed));
|
|
726
|
+
}
|
|
727
|
+
const result = setOllamaModel(config, trimmed);
|
|
728
|
+
await writeExampleConfig(configPath, config);
|
|
729
|
+
console.log(result
|
|
730
|
+
? messages.config.ollamaModelUpdated(configPath, result.previousModel, result.nextModel)
|
|
731
|
+
: messages.config.ollamaModelNoChange(configPath, agent.model));
|
|
732
|
+
}
|
|
733
|
+
async function runSyncOllamaModelCommand(configPath, config, messages) {
|
|
734
|
+
const discovery = await discoverLocalTools();
|
|
735
|
+
const agent = config.agents["ollama-local"];
|
|
736
|
+
if (agent?.type !== "ollama") {
|
|
737
|
+
throw new Error(messages.config.ollamaModelNoAgent);
|
|
738
|
+
}
|
|
739
|
+
if (discovery.ollama.models.length === 0) {
|
|
740
|
+
throw new Error(messages.config.ollamaModelNoInstalledModels);
|
|
741
|
+
}
|
|
742
|
+
const result = syncOllamaModel(config, discovery);
|
|
743
|
+
if (!result) {
|
|
744
|
+
console.log(messages.config.ollamaModelNoChange(configPath, agent.model));
|
|
745
|
+
return;
|
|
746
|
+
}
|
|
747
|
+
await writeExampleConfig(configPath, config);
|
|
748
|
+
console.log(messages.config.ollamaModelUpdated(configPath, result.previousModel, result.nextModel));
|
|
749
|
+
}
|
|
281
750
|
/**
|
|
282
751
|
* Renvoie `true` si la valeur représente une désactivation explicite (ex. "none", "0", "disabled").
|
|
283
752
|
* @param value - Chaîne saisie par l'utilisateur.
|
|
@@ -291,7 +760,19 @@ function isNoneValue(value) {
|
|
|
291
760
|
* @returns Chaîne résumant la paire d'agents, le nombre de réponses et l'agent de synthèse.
|
|
292
761
|
*/
|
|
293
762
|
function formatDefaultsForMessage(defaults, messages) {
|
|
294
|
-
return messages.config.defaultsSummary(defaults.agentA, defaults.agentB, turnsOrDefault(defaults.turns), defaults.summaryAgent);
|
|
763
|
+
return messages.config.defaultsSummary(defaults.agentA, defaults.agentB, turnsOrDefault(defaults.turns), defaults.summaryAgent, defaults.askSummaryAgent, defaults.mode, defaults.askAgents, defaults.interface);
|
|
764
|
+
}
|
|
765
|
+
function normalizeAskAgentsForConfig(config, agents, messages) {
|
|
766
|
+
const unique = agents
|
|
767
|
+
.map((agent) => agent.trim())
|
|
768
|
+
.filter((agent, index, list) => agent && list.indexOf(agent) === index);
|
|
769
|
+
if (unique.length > MAX_ASK_AGENTS) {
|
|
770
|
+
throw new Error(messages.common.tooManyAskAgents(MAX_ASK_AGENTS));
|
|
771
|
+
}
|
|
772
|
+
for (const agent of unique) {
|
|
773
|
+
assertKnownAgent(config, agent, "defaults.askAgents", messages);
|
|
774
|
+
}
|
|
775
|
+
return unique;
|
|
295
776
|
}
|
|
296
777
|
/**
|
|
297
778
|
* Lève une erreur si `agentName` n'est pas déclaré dans la config.
|
|
@@ -320,38 +801,88 @@ function resolveAgentName(label, explicitValue, presetValue, defaultValue, messa
|
|
|
320
801
|
}
|
|
321
802
|
return resolved;
|
|
322
803
|
}
|
|
804
|
+
function resolveSummaryAgentOption(explicitValue, defaults, mode) {
|
|
805
|
+
const explicit = optionalString(explicitValue);
|
|
806
|
+
if (explicit) {
|
|
807
|
+
return explicit;
|
|
808
|
+
}
|
|
809
|
+
if (mode === "ask") {
|
|
810
|
+
return defaults?.askSummaryAgent ?? defaults?.summaryAgent;
|
|
811
|
+
}
|
|
812
|
+
return defaults?.summaryAgent;
|
|
813
|
+
}
|
|
814
|
+
function parseModeFlag(value, messages) {
|
|
815
|
+
if (!value) {
|
|
816
|
+
return "debate";
|
|
817
|
+
}
|
|
818
|
+
if (value === "debate" || value === "ask") {
|
|
819
|
+
return value;
|
|
820
|
+
}
|
|
821
|
+
throw new Error(messages.common.unknownMode(value, "debate, ask"));
|
|
822
|
+
}
|
|
823
|
+
function parseInterfaceFlag(value, messages) {
|
|
824
|
+
if (!value) {
|
|
825
|
+
return "tui";
|
|
826
|
+
}
|
|
827
|
+
if (value === "tui" || value === "terminal") {
|
|
828
|
+
return value;
|
|
829
|
+
}
|
|
830
|
+
throw new Error(messages.common.unknownMode(value, "tui, terminal"));
|
|
831
|
+
}
|
|
832
|
+
function resolveAskAgents(explicitAgents, defaultAgents, fallbackAgents, messages) {
|
|
833
|
+
const selected = explicitAgents.length > 0
|
|
834
|
+
? explicitAgents
|
|
835
|
+
: defaultAgents && defaultAgents.length > 0 ? defaultAgents : fallbackAgents;
|
|
836
|
+
const unique = selected.filter((agent, index) => agent.trim() && selected.indexOf(agent) === index);
|
|
837
|
+
if (unique.length > MAX_ASK_AGENTS) {
|
|
838
|
+
throw new Error(messages.common.tooManyAskAgents(MAX_ASK_AGENTS));
|
|
839
|
+
}
|
|
840
|
+
return unique;
|
|
841
|
+
}
|
|
323
842
|
/**
|
|
324
843
|
* Affiche un aperçu du prompt du premier tour sans appeler aucun agent (flag `--show-prompt`).
|
|
325
844
|
* @param config - Config chargée.
|
|
326
845
|
* @param options - Options du débat résolues.
|
|
327
846
|
*/
|
|
328
847
|
function printPromptPreview(config, options, language, messages) {
|
|
329
|
-
const
|
|
848
|
+
const previewAgent = options.mode === "ask" ? options.askAgents?.[0] ?? options.agentA : options.agentA;
|
|
849
|
+
const peerName = options.mode === "ask" ? "independent-agents" : options.agentB;
|
|
850
|
+
const agentConfig = config.agents[previewAgent];
|
|
330
851
|
if (!agentConfig) {
|
|
331
|
-
throw new Error(messages.common.unknownAgent(
|
|
852
|
+
throw new Error(messages.common.unknownAgent(previewAgent));
|
|
332
853
|
}
|
|
333
854
|
const prompt = formatAgentPrompt({
|
|
334
855
|
topic: options.topic,
|
|
335
856
|
turn: 1,
|
|
336
|
-
totalTurns: options.turns,
|
|
337
|
-
selfName:
|
|
338
|
-
peerName
|
|
857
|
+
totalTurns: options.mode === "ask" ? options.askAgents?.length ?? 1 : options.turns,
|
|
858
|
+
selfName: previewAgent,
|
|
859
|
+
peerName,
|
|
339
860
|
selfRole: agentConfig.role,
|
|
861
|
+
mode: options.mode === "ask" ? "ask" : "debate",
|
|
340
862
|
language: options.language,
|
|
341
863
|
session: options.session,
|
|
342
864
|
files: options.files,
|
|
343
865
|
transcript: []
|
|
344
866
|
});
|
|
345
867
|
console.log(messages.preview.title);
|
|
346
|
-
console.log(messages.preview.agent(
|
|
347
|
-
console.log(messages.preview.peer(
|
|
868
|
+
console.log(messages.preview.agent(previewAgent, agentConfig.role));
|
|
869
|
+
console.log(messages.preview.peer(peerName));
|
|
348
870
|
console.log(messages.preview.pullModels(options.pullModels));
|
|
349
|
-
console.log(messages.preview.summary(options.summaryEnabled ? options
|
|
871
|
+
console.log(messages.preview.summary(options.summaryEnabled ? previewSummaryAgent(options) : messages.preview.disabled));
|
|
350
872
|
console.log(messages.preview.interfaceLanguage(language));
|
|
351
873
|
console.log("");
|
|
352
874
|
console.log(prompt);
|
|
353
875
|
console.log("");
|
|
354
|
-
console.log(messages.preview.note);
|
|
876
|
+
console.log(options.mode === "ask" ? messages.preview.askNote : messages.preview.note);
|
|
877
|
+
}
|
|
878
|
+
function previewSummaryAgent(options) {
|
|
879
|
+
if (options.summaryAgent) {
|
|
880
|
+
return options.summaryAgent;
|
|
881
|
+
}
|
|
882
|
+
if (options.mode === "ask" && options.askAgents && options.askAgents.length > 0) {
|
|
883
|
+
return options.askAgents[options.askAgents.length - 1] ?? options.agentB;
|
|
884
|
+
}
|
|
885
|
+
return options.agentB;
|
|
355
886
|
}
|
|
356
887
|
/**
|
|
357
888
|
* Extrait une chaîne non vide depuis une valeur de flag, ou renvoie `undefined`.
|
|
@@ -375,7 +906,7 @@ function findRawLanguageFlag(args) {
|
|
|
375
906
|
return undefined;
|
|
376
907
|
}
|
|
377
908
|
/** Liste des kinds de renderer acceptés par `--renderer`. */
|
|
378
|
-
const SUPPORTED_RENDERERS = ["auto", "pretty", "plain", "ndjson"];
|
|
909
|
+
const SUPPORTED_RENDERERS = ["auto", "pretty", "plain", "tui", "ndjson"];
|
|
379
910
|
/**
|
|
380
911
|
* Instancie le renderer en fonction des flags CLI.
|
|
381
912
|
*
|
|
@@ -387,7 +918,7 @@ const SUPPORTED_RENDERERS = ["auto", "pretty", "plain", "ndjson"];
|
|
|
387
918
|
*
|
|
388
919
|
* Lève si la valeur de `--renderer` n'est pas dans `SUPPORTED_RENDERERS`.
|
|
389
920
|
*/
|
|
390
|
-
function createRendererFromFlags(flags, plainOutputFallback, messages) {
|
|
921
|
+
function createRendererFromFlags(flags, plainOutputFallback, defaultInterface, messages) {
|
|
391
922
|
const explicit = optionalString(flags.renderer);
|
|
392
923
|
if (explicit) {
|
|
393
924
|
if (!SUPPORTED_RENDERERS.includes(explicit)) {
|
|
@@ -401,14 +932,41 @@ function createRendererFromFlags(flags, plainOutputFallback, messages) {
|
|
|
401
932
|
return createConsoleRenderer(true, messages);
|
|
402
933
|
case "pretty":
|
|
403
934
|
return createConsoleRenderer(false, messages);
|
|
935
|
+
case "tui":
|
|
936
|
+
return createTuiRenderer(messages);
|
|
404
937
|
case "auto":
|
|
405
|
-
return
|
|
938
|
+
return createAutoRenderer(flags, plainOutputFallback, defaultInterface, messages);
|
|
406
939
|
}
|
|
407
940
|
}
|
|
408
941
|
if (flags.json) {
|
|
409
942
|
return createNdjsonRenderer();
|
|
410
943
|
}
|
|
411
|
-
|
|
944
|
+
if (flags.tui) {
|
|
945
|
+
return createTuiRenderer(messages);
|
|
946
|
+
}
|
|
947
|
+
if (flags.terminal || flags.plain || plainOutputFallback || defaultInterface === "terminal") {
|
|
948
|
+
return createConsoleRenderer(true, messages);
|
|
949
|
+
}
|
|
950
|
+
return createAutoRenderer(flags, plainOutputFallback, defaultInterface, messages);
|
|
951
|
+
}
|
|
952
|
+
function createAutoRenderer(flags, plainOutputFallback, defaultInterface, messages) {
|
|
953
|
+
if (flags.tui) {
|
|
954
|
+
return createTuiRenderer(messages);
|
|
955
|
+
}
|
|
956
|
+
if (flags.terminal || flags.plain || plainOutputFallback || defaultInterface === "terminal") {
|
|
957
|
+
return createConsoleRenderer(true, messages);
|
|
958
|
+
}
|
|
959
|
+
return process.stdout.isTTY ? createTuiRenderer(messages) : createConsoleRenderer(true, messages);
|
|
960
|
+
}
|
|
961
|
+
function shouldOpenTuiHome(parsed) {
|
|
962
|
+
return parsed.command === "run"
|
|
963
|
+
&& !parsed.commandExplicit
|
|
964
|
+
&& parsed.positionals.length === 0
|
|
965
|
+
&& optionalString(parsed.flags.topic) === undefined
|
|
966
|
+
&& optionalString(parsed.flags.renderer) === undefined
|
|
967
|
+
&& parsed.flags.json !== true
|
|
968
|
+
&& parsed.flags.plain !== true
|
|
969
|
+
&& parsed.flags.terminal !== true;
|
|
412
970
|
}
|
|
413
971
|
/**
|
|
414
972
|
* Exécute la commande `palabre presets`.
|
|
@@ -472,13 +1030,6 @@ async function runContextCommand(flags, positionals) {
|
|
|
472
1030
|
console.error(`${messages.renderers.warningPrefix} ${warning}`);
|
|
473
1031
|
}
|
|
474
1032
|
}
|
|
475
|
-
/** Lit la version depuis `package.json` adjacent au bundle compilé. */
|
|
476
|
-
async function getPackageVersion() {
|
|
477
|
-
const packageJsonPath = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..", "package.json");
|
|
478
|
-
const raw = await readFile(packageJsonPath, "utf8");
|
|
479
|
-
const packageJson = JSON.parse(raw);
|
|
480
|
-
return packageJson.version ?? "0.0.0";
|
|
481
|
-
}
|
|
482
1033
|
/**
|
|
483
1034
|
* Écrit les avertissements de contexte sur `stderr`.
|
|
484
1035
|
* @param warnings - Messages d'avertissement issus du chargement des fichiers de contexte.
|
|
@@ -495,22 +1046,6 @@ function printContextWarnings(warnings, messages) {
|
|
|
495
1046
|
* @param discovery - Résultat de la découverte locale des outils.
|
|
496
1047
|
* @returns Noms des agents nouvellement ajoutés.
|
|
497
1048
|
*/
|
|
498
|
-
function syncDetectedAgents(config, discovery) {
|
|
499
|
-
const discoveredConfig = createConfigFromDiscovery(discovery);
|
|
500
|
-
const missingAgents = findDetectedMissingAgents(config, discovery);
|
|
501
|
-
for (const agentName of missingAgents) {
|
|
502
|
-
config.agents[agentName] = discoveredConfig.agents[agentName];
|
|
503
|
-
}
|
|
504
|
-
return missingAgents;
|
|
505
|
-
}
|
|
506
|
-
/**
|
|
507
|
-
* Renvoie les noms des agents détectés localement qui ne sont pas encore dans `config.agents`.
|
|
508
|
-
* @param config - Config Palabre existante.
|
|
509
|
-
* @param discovery - Résultat de la découverte locale des outils.
|
|
510
|
-
*/
|
|
511
|
-
function findDetectedMissingAgents(config, discovery) {
|
|
512
|
-
return detectedAgentNames(discovery).filter((agentName) => !config.agents[agentName]);
|
|
513
|
-
}
|
|
514
1049
|
/**
|
|
515
1050
|
* Affiche la liste des agents déclarés avec leur type, rôle, état de détection et défauts.
|
|
516
1051
|
* @param configPath - Chemin du fichier de config (affiché en en-tête).
|
|
@@ -533,7 +1068,7 @@ function printAgents(configPath, config, discovery, messages) {
|
|
|
533
1068
|
}
|
|
534
1069
|
}
|
|
535
1070
|
console.log("");
|
|
536
|
-
console.log(messages.agents.defaults(config.defaults?.agentA ?? messages.agents.none, config.defaults?.agentB ?? messages.agents.none, turnsOrDefault(config.defaults?.turns), config.defaults?.summaryAgent ?? messages.agents.summaryAgentB));
|
|
1071
|
+
console.log(messages.agents.defaults(config.defaults?.agentA ?? messages.agents.none, config.defaults?.agentB ?? messages.agents.none, turnsOrDefault(config.defaults?.turns), config.defaults?.summaryAgent ?? messages.agents.summaryAgentB, config.defaults?.askSummaryAgent));
|
|
537
1072
|
}
|
|
538
1073
|
/**
|
|
539
1074
|
* Renvoie un libellé indiquant si l'agent est agent A, agent B ou agent de synthèse par défaut.
|
|
@@ -548,6 +1083,8 @@ function formatAgentDefaults(name, config, messages) {
|
|
|
548
1083
|
labels.push(messages.agents.defaultAgentB);
|
|
549
1084
|
if (config.defaults?.summaryAgent === name)
|
|
550
1085
|
labels.push(messages.agents.defaultSummary);
|
|
1086
|
+
if (config.defaults?.askSummaryAgent === name)
|
|
1087
|
+
labels.push(messages.agents.defaultAskSummary);
|
|
551
1088
|
return labels.join(", ");
|
|
552
1089
|
}
|
|
553
1090
|
/**
|
|
@@ -603,6 +1140,7 @@ function printInitDiscovery(discovery, config, messages) {
|
|
|
603
1140
|
console.log(`- Gemini CLI: ${formatCommandDetection(discovery.gemini, messages)}`);
|
|
604
1141
|
console.log(`- Antigravity CLI: ${formatCommandDetection(discovery.antigravity, messages)}`);
|
|
605
1142
|
console.log(`- OpenCode CLI: ${formatCommandDetection(discovery.opencode, messages)}`);
|
|
1143
|
+
console.log(`- Mistral Vibe CLI: ${formatCommandDetection(discovery.vibe, messages)}`);
|
|
606
1144
|
console.log(`- Ollama API: ${formatOllamaDetection(discovery.ollama, messages)}`);
|
|
607
1145
|
console.log("");
|
|
608
1146
|
console.log(config.defaults?.agentA && config.defaults.agentB
|