palabre 0.7.0 → 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/agentRegistry.js +3 -2
- package/dist/args.js +19 -1
- package/dist/config.js +37 -3
- package/dist/configWizard.js +12 -2
- package/dist/discovery.js +3 -1
- package/dist/doctor.js +4 -0
- package/dist/index.js +508 -27
- package/dist/messages/agents.js +4 -2
- package/dist/messages/common.js +4 -0
- package/dist/messages/config.js +16 -8
- 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/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 +156 -5
- 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/package.json +2 -1
package/dist/index.js
CHANGED
|
@@ -7,13 +7,14 @@ import { runDoctor } from "./doctor.js";
|
|
|
7
7
|
import { AdapterError, formatAdapterError } from "./errors.js";
|
|
8
8
|
import { runConfigWizard } from "./configWizard.js";
|
|
9
9
|
import { createTranslator, DEFAULT_LANGUAGE, parseLanguage, resolveLanguage } from "./i18n.js";
|
|
10
|
-
import { DEFAULT_TURNS, parseTurnsFlag, turnsOrDefault } from "./limits.js";
|
|
10
|
+
import { DEFAULT_TURNS, parseTurnsFlag, turnsOrDefault, validateTurns } from "./limits.js";
|
|
11
11
|
import { formatAgentPrompt } from "./prompt.js";
|
|
12
12
|
import { runNewWizard } from "./new.js";
|
|
13
13
|
import { listPresetNames, listPresetsWithAvailability, resolvePreset } from "./presets.js";
|
|
14
14
|
import { createConsoleRenderer } from "./renderers/console.js";
|
|
15
15
|
import { createNdjsonRenderer } from "./renderers/ndjson.js";
|
|
16
|
-
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";
|
|
17
18
|
import { writeDebateMarkdown } from "./output.js";
|
|
18
19
|
import { applySourceUpdate, formatUpdateInstructions, getUpdateInfo } from "./update.js";
|
|
19
20
|
import { createSessionContext } from "./session.js";
|
|
@@ -35,7 +36,7 @@ async function main() {
|
|
|
35
36
|
return;
|
|
36
37
|
}
|
|
37
38
|
if (parsed.command === "doctor") {
|
|
38
|
-
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));
|
|
39
40
|
console.log(result.output);
|
|
40
41
|
process.exitCode = result.ok ? 0 : 1;
|
|
41
42
|
return;
|
|
@@ -106,12 +107,106 @@ async function main() {
|
|
|
106
107
|
return;
|
|
107
108
|
}
|
|
108
109
|
const config = await loadConfig(configPath);
|
|
109
|
-
|
|
110
|
+
let language = resolveLanguage({
|
|
110
111
|
explicitLanguage: optionalString(parsed.flags.language),
|
|
111
112
|
configLanguage: config.language
|
|
112
113
|
});
|
|
113
|
-
|
|
114
|
+
let messages = createTranslator(language);
|
|
114
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
|
+
}
|
|
115
210
|
if (parsed.command === "new") {
|
|
116
211
|
const selection = await runNewWizard(config, messages);
|
|
117
212
|
if (!selection) {
|
|
@@ -141,6 +236,10 @@ async function main() {
|
|
|
141
236
|
parsed.flags.files = selection.files;
|
|
142
237
|
if (selection.context.length > 0)
|
|
143
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;
|
|
144
243
|
}
|
|
145
244
|
const topic = optionalString(parsed.flags.topic) ?? "";
|
|
146
245
|
const context = await loadProjectInputs(getStringListFlag(parsed.flags.files), getStringListFlag(parsed.flags.context), process.cwd(), messages);
|
|
@@ -149,22 +248,30 @@ async function main() {
|
|
|
149
248
|
if (!topic) {
|
|
150
249
|
throw new Error(messages.common.topicRequired);
|
|
151
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;
|
|
152
257
|
const options = {
|
|
258
|
+
mode,
|
|
153
259
|
language,
|
|
154
260
|
topic,
|
|
155
|
-
agentA
|
|
156
|
-
agentB
|
|
261
|
+
agentA,
|
|
262
|
+
agentB,
|
|
263
|
+
askAgents,
|
|
157
264
|
turns: parseTurnsFlag(parsed.flags.turns, config.defaults?.turns ?? DEFAULT_TURNS, "--turns", messages),
|
|
158
265
|
session: createSessionContext(),
|
|
159
266
|
files: context.files,
|
|
160
267
|
modelA: optionalString(parsed.flags["model-a"]),
|
|
161
268
|
modelB: optionalString(parsed.flags["model-b"]),
|
|
162
269
|
pullModels: Boolean(parsed.flags["pull-models"]),
|
|
163
|
-
summaryAgent:
|
|
270
|
+
summaryAgent: resolveSummaryAgentOption(parsed.flags["summary-agent"], config.defaults, mode),
|
|
164
271
|
summaryModel: optionalString(parsed.flags["summary-model"]),
|
|
165
272
|
summaryEnabled: !parsed.flags["no-summary"],
|
|
166
273
|
earlyStopOnAgreement: !parsed.flags["no-early-stop"],
|
|
167
|
-
plainOutput: Boolean(parsed.flags.plain),
|
|
274
|
+
plainOutput: Boolean(parsed.flags.plain || parsed.flags.terminal),
|
|
168
275
|
signal: debateAbortSignal()
|
|
169
276
|
};
|
|
170
277
|
if (parsed.flags["show-prompt"]) {
|
|
@@ -172,9 +279,11 @@ async function main() {
|
|
|
172
279
|
printPromptPreview(config, options, language, messages);
|
|
173
280
|
return;
|
|
174
281
|
}
|
|
175
|
-
const renderer = createRendererFromFlags(parsed.flags, options.plainOutput, messages);
|
|
282
|
+
const renderer = createRendererFromFlags(parsed.flags, options.plainOutput, config.defaults?.interface, messages);
|
|
176
283
|
context.warnings.forEach((warning) => renderer.warning(warning));
|
|
177
|
-
const result =
|
|
284
|
+
const result = options.mode === "ask"
|
|
285
|
+
? await runAsk(config, options, renderer, messages)
|
|
286
|
+
: await runDebate(config, options, renderer, messages);
|
|
178
287
|
const outputPath = await writeDebateMarkdown(resolveOutputDir(config.outputDir), result.options, result.messages, result.summary, result.stopReason, messages, result.failure);
|
|
179
288
|
renderer.done(outputPath);
|
|
180
289
|
if (result.failure) {
|
|
@@ -257,8 +366,18 @@ async function runConfigCommand(flags) {
|
|
|
257
366
|
const defaultAgents = getStringListFlag(flags["set-defaults"]);
|
|
258
367
|
const hasTurnsFlag = flags.turns !== undefined;
|
|
259
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"]);
|
|
260
373
|
const languageValue = explicitLanguage;
|
|
261
|
-
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;
|
|
262
381
|
if (changesDefaults || languageValue !== undefined) {
|
|
263
382
|
const nextDefaults = { ...(config.defaults ?? {}) };
|
|
264
383
|
if (defaultAgents.length > 0) {
|
|
@@ -283,6 +402,24 @@ async function runConfigCommand(flags) {
|
|
|
283
402
|
nextDefaults.summaryAgent = summaryAgentValue;
|
|
284
403
|
}
|
|
285
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
|
+
}
|
|
286
423
|
if (languageValue !== undefined) {
|
|
287
424
|
config.language = parseLanguage(languageValue, "--language");
|
|
288
425
|
}
|
|
@@ -301,6 +438,258 @@ async function runConfigCommand(flags) {
|
|
|
301
438
|
}
|
|
302
439
|
await runConfigWizard(configPath, config, messages);
|
|
303
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"];
|
|
304
693
|
async function runOllamaModelsCommand(config, json) {
|
|
305
694
|
const discovery = await discoverLocalTools();
|
|
306
695
|
const agent = config.agents["ollama-local"];
|
|
@@ -371,7 +760,19 @@ function isNoneValue(value) {
|
|
|
371
760
|
* @returns Chaîne résumant la paire d'agents, le nombre de réponses et l'agent de synthèse.
|
|
372
761
|
*/
|
|
373
762
|
function formatDefaultsForMessage(defaults, messages) {
|
|
374
|
-
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;
|
|
375
776
|
}
|
|
376
777
|
/**
|
|
377
778
|
* Lève une erreur si `agentName` n'est pas déclaré dans la config.
|
|
@@ -400,38 +801,88 @@ function resolveAgentName(label, explicitValue, presetValue, defaultValue, messa
|
|
|
400
801
|
}
|
|
401
802
|
return resolved;
|
|
402
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
|
+
}
|
|
403
842
|
/**
|
|
404
843
|
* Affiche un aperçu du prompt du premier tour sans appeler aucun agent (flag `--show-prompt`).
|
|
405
844
|
* @param config - Config chargée.
|
|
406
845
|
* @param options - Options du débat résolues.
|
|
407
846
|
*/
|
|
408
847
|
function printPromptPreview(config, options, language, messages) {
|
|
409
|
-
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];
|
|
410
851
|
if (!agentConfig) {
|
|
411
|
-
throw new Error(messages.common.unknownAgent(
|
|
852
|
+
throw new Error(messages.common.unknownAgent(previewAgent));
|
|
412
853
|
}
|
|
413
854
|
const prompt = formatAgentPrompt({
|
|
414
855
|
topic: options.topic,
|
|
415
856
|
turn: 1,
|
|
416
|
-
totalTurns: options.turns,
|
|
417
|
-
selfName:
|
|
418
|
-
peerName
|
|
857
|
+
totalTurns: options.mode === "ask" ? options.askAgents?.length ?? 1 : options.turns,
|
|
858
|
+
selfName: previewAgent,
|
|
859
|
+
peerName,
|
|
419
860
|
selfRole: agentConfig.role,
|
|
861
|
+
mode: options.mode === "ask" ? "ask" : "debate",
|
|
420
862
|
language: options.language,
|
|
421
863
|
session: options.session,
|
|
422
864
|
files: options.files,
|
|
423
865
|
transcript: []
|
|
424
866
|
});
|
|
425
867
|
console.log(messages.preview.title);
|
|
426
|
-
console.log(messages.preview.agent(
|
|
427
|
-
console.log(messages.preview.peer(
|
|
868
|
+
console.log(messages.preview.agent(previewAgent, agentConfig.role));
|
|
869
|
+
console.log(messages.preview.peer(peerName));
|
|
428
870
|
console.log(messages.preview.pullModels(options.pullModels));
|
|
429
|
-
console.log(messages.preview.summary(options.summaryEnabled ? options
|
|
871
|
+
console.log(messages.preview.summary(options.summaryEnabled ? previewSummaryAgent(options) : messages.preview.disabled));
|
|
430
872
|
console.log(messages.preview.interfaceLanguage(language));
|
|
431
873
|
console.log("");
|
|
432
874
|
console.log(prompt);
|
|
433
875
|
console.log("");
|
|
434
|
-
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;
|
|
435
886
|
}
|
|
436
887
|
/**
|
|
437
888
|
* Extrait une chaîne non vide depuis une valeur de flag, ou renvoie `undefined`.
|
|
@@ -455,7 +906,7 @@ function findRawLanguageFlag(args) {
|
|
|
455
906
|
return undefined;
|
|
456
907
|
}
|
|
457
908
|
/** Liste des kinds de renderer acceptés par `--renderer`. */
|
|
458
|
-
const SUPPORTED_RENDERERS = ["auto", "pretty", "plain", "ndjson"];
|
|
909
|
+
const SUPPORTED_RENDERERS = ["auto", "pretty", "plain", "tui", "ndjson"];
|
|
459
910
|
/**
|
|
460
911
|
* Instancie le renderer en fonction des flags CLI.
|
|
461
912
|
*
|
|
@@ -467,7 +918,7 @@ const SUPPORTED_RENDERERS = ["auto", "pretty", "plain", "ndjson"];
|
|
|
467
918
|
*
|
|
468
919
|
* Lève si la valeur de `--renderer` n'est pas dans `SUPPORTED_RENDERERS`.
|
|
469
920
|
*/
|
|
470
|
-
function createRendererFromFlags(flags, plainOutputFallback, messages) {
|
|
921
|
+
function createRendererFromFlags(flags, plainOutputFallback, defaultInterface, messages) {
|
|
471
922
|
const explicit = optionalString(flags.renderer);
|
|
472
923
|
if (explicit) {
|
|
473
924
|
if (!SUPPORTED_RENDERERS.includes(explicit)) {
|
|
@@ -481,14 +932,41 @@ function createRendererFromFlags(flags, plainOutputFallback, messages) {
|
|
|
481
932
|
return createConsoleRenderer(true, messages);
|
|
482
933
|
case "pretty":
|
|
483
934
|
return createConsoleRenderer(false, messages);
|
|
935
|
+
case "tui":
|
|
936
|
+
return createTuiRenderer(messages);
|
|
484
937
|
case "auto":
|
|
485
|
-
return
|
|
938
|
+
return createAutoRenderer(flags, plainOutputFallback, defaultInterface, messages);
|
|
486
939
|
}
|
|
487
940
|
}
|
|
488
941
|
if (flags.json) {
|
|
489
942
|
return createNdjsonRenderer();
|
|
490
943
|
}
|
|
491
|
-
|
|
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;
|
|
492
970
|
}
|
|
493
971
|
/**
|
|
494
972
|
* Exécute la commande `palabre presets`.
|
|
@@ -590,7 +1068,7 @@ function printAgents(configPath, config, discovery, messages) {
|
|
|
590
1068
|
}
|
|
591
1069
|
}
|
|
592
1070
|
console.log("");
|
|
593
|
-
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));
|
|
594
1072
|
}
|
|
595
1073
|
/**
|
|
596
1074
|
* Renvoie un libellé indiquant si l'agent est agent A, agent B ou agent de synthèse par défaut.
|
|
@@ -605,6 +1083,8 @@ function formatAgentDefaults(name, config, messages) {
|
|
|
605
1083
|
labels.push(messages.agents.defaultAgentB);
|
|
606
1084
|
if (config.defaults?.summaryAgent === name)
|
|
607
1085
|
labels.push(messages.agents.defaultSummary);
|
|
1086
|
+
if (config.defaults?.askSummaryAgent === name)
|
|
1087
|
+
labels.push(messages.agents.defaultAskSummary);
|
|
608
1088
|
return labels.join(", ");
|
|
609
1089
|
}
|
|
610
1090
|
/**
|
|
@@ -660,6 +1140,7 @@ function printInitDiscovery(discovery, config, messages) {
|
|
|
660
1140
|
console.log(`- Gemini CLI: ${formatCommandDetection(discovery.gemini, messages)}`);
|
|
661
1141
|
console.log(`- Antigravity CLI: ${formatCommandDetection(discovery.antigravity, messages)}`);
|
|
662
1142
|
console.log(`- OpenCode CLI: ${formatCommandDetection(discovery.opencode, messages)}`);
|
|
1143
|
+
console.log(`- Mistral Vibe CLI: ${formatCommandDetection(discovery.vibe, messages)}`);
|
|
663
1144
|
console.log(`- Ollama API: ${formatOllamaDetection(discovery.ollama, messages)}`);
|
|
664
1145
|
console.log("");
|
|
665
1146
|
console.log(config.defaults?.agentA && config.defaults.agentB
|