palabre 0.9.0 → 0.9.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 +2 -0
- package/dist/commands/agents.js +85 -0
- package/dist/commands/context.js +25 -0
- package/dist/commands/history.js +28 -0
- package/dist/commands/init.js +59 -0
- package/dist/commands/presets.js +34 -0
- package/dist/commands/shared.js +4 -0
- package/dist/commands/update.js +21 -0
- package/dist/discovery.js +8 -1
- package/dist/index.js +26 -770
- package/dist/limits.js +1 -0
- package/dist/orchestrator.js +7 -15
- package/dist/output.js +1 -10
- package/dist/renderers/console.js +1 -7
- package/dist/renderers/ndjson.js +1 -10
- package/dist/renderers/tui.js +1 -10
- package/dist/runOptions.js +66 -0
- package/dist/tuiController.js +400 -0
- package/package.json +3 -2
package/dist/index.js
CHANGED
|
@@ -1,29 +1,35 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { assertRunnableConfig, configExists, createConfigFromDiscovery,
|
|
2
|
+
import { assertRunnableConfig, configExists, createConfigFromDiscovery, loadConfig, resolveDefaultConfigPath, resolveOutputDir, setOllamaModel, syncDetectedAgentsDetailed, syncOllamaModel, writeExampleConfig } from "./config.js";
|
|
3
3
|
import { loadProjectInputs } from "./context.js";
|
|
4
|
-
import {
|
|
5
|
-
import { discoverLocalTools } from "./discovery.js";
|
|
4
|
+
import { discoverLocalTools, discoverLocalToolsForConfig } from "./discovery.js";
|
|
6
5
|
import { runDoctor } from "./doctor.js";
|
|
7
6
|
import { AdapterError, formatAdapterError } from "./errors.js";
|
|
8
7
|
import { runConfigWizard } from "./configWizard.js";
|
|
9
8
|
import { createTranslator, DEFAULT_LANGUAGE, parseLanguage, resolveLanguage } from "./i18n.js";
|
|
10
|
-
import { DEFAULT_TURNS, parseTurnsFlag, turnsOrDefault
|
|
9
|
+
import { DEFAULT_TURNS, parseTurnsFlag, turnsOrDefault } from "./limits.js";
|
|
11
10
|
import { formatAgentPrompt } from "./prompt.js";
|
|
12
11
|
import { runNewWizard } from "./new.js";
|
|
13
|
-
import {
|
|
12
|
+
import { listPresetNames, resolvePreset } from "./presets.js";
|
|
14
13
|
import { listHistoryEntries } from "./history.js";
|
|
15
14
|
import { createConsoleRenderer } from "./renderers/console.js";
|
|
16
15
|
import { createNdjsonRenderer } from "./renderers/ndjson.js";
|
|
17
|
-
import { createTuiRenderer,
|
|
16
|
+
import { createTuiRenderer, promptTuiHomeTopic, renderTuiHelp, renderTuiHistory, renderTuiHome, renderTuiUpdate } from "./renderers/tui.js";
|
|
18
17
|
import { MAX_ASK_AGENTS, runAsk, runDebate } from "./orchestrator.js";
|
|
19
18
|
import { writeDebateMarkdown } from "./output.js";
|
|
20
|
-
import {
|
|
21
|
-
import { createSessionContext } from "./session.js";
|
|
19
|
+
import { formatUpdateInstructions, getUpdateInfo } from "./update.js";
|
|
22
20
|
import { getStringListFlag, parseArgs } from "./args.js";
|
|
23
|
-
import {
|
|
24
|
-
import {
|
|
25
|
-
import { configuredOllamaTargets, DEFAULT_OLLAMA_BASE_URL, normalizeOllamaBaseUrl, OllamaUrlError, resolveOllamaBaseUrl } from "./ollamaUrl.js";
|
|
21
|
+
import { clearTuiRunOverrides } from "./tuiState.js";
|
|
22
|
+
import { OllamaUrlError } from "./ollamaUrl.js";
|
|
26
23
|
import { compareSemver, getLatestPackageVersion, getPackageVersion } from "./version.js";
|
|
24
|
+
import { runAgentsCommand } from "./commands/agents.js";
|
|
25
|
+
import { runContextCommand } from "./commands/context.js";
|
|
26
|
+
import { runHistoryCommand } from "./commands/history.js";
|
|
27
|
+
import { runInitCommand } from "./commands/init.js";
|
|
28
|
+
import { runPresetsCommand } from "./commands/presets.js";
|
|
29
|
+
import { runUpdateCommand } from "./commands/update.js";
|
|
30
|
+
import { optionalString } from "./commands/shared.js";
|
|
31
|
+
import { runTuiAgentsWizard, runTuiConfigLoop, runTuiRolesWizard, syncInteractiveDetectedAgents } from "./tuiController.js";
|
|
32
|
+
import { resolveRunOptions } from "./runOptions.js";
|
|
27
33
|
/** Point d'entrée principal du CLI Palabre. Dispatche vers la commande appropriée selon les arguments. */
|
|
28
34
|
async function main() {
|
|
29
35
|
const rawArgs = process.argv.slice(2);
|
|
@@ -65,42 +71,11 @@ async function main() {
|
|
|
65
71
|
return;
|
|
66
72
|
}
|
|
67
73
|
if (parsed.command === "update") {
|
|
68
|
-
|
|
69
|
-
const updateConfigPath = optionalString(parsed.flags.config) ?? await resolveDefaultConfigPath();
|
|
70
|
-
const updateConfig = await configExists(updateConfigPath)
|
|
71
|
-
? await loadConfig(updateConfigPath)
|
|
72
|
-
: undefined;
|
|
73
|
-
const updateLanguage = resolveLanguage({
|
|
74
|
-
explicitLanguage: optionalString(parsed.flags.language),
|
|
75
|
-
configLanguage: updateConfig?.language
|
|
76
|
-
});
|
|
77
|
-
const updateMessages = createTranslator(updateLanguage);
|
|
78
|
-
if (parsed.flags.apply) {
|
|
79
|
-
await applySourceUpdate(info, updateMessages);
|
|
80
|
-
console.log(updateMessages.update.upToDate);
|
|
81
|
-
return;
|
|
82
|
-
}
|
|
83
|
-
console.log(formatUpdateInstructions(info, updateMessages));
|
|
74
|
+
await runUpdateCommand(parsed.flags);
|
|
84
75
|
return;
|
|
85
76
|
}
|
|
86
77
|
if (parsed.command === "init" || parsed.command === "setup") {
|
|
87
|
-
|
|
88
|
-
if (await configExists(initConfigPath)) {
|
|
89
|
-
console.log(startupMessages.init.configExists(initConfigPath));
|
|
90
|
-
return;
|
|
91
|
-
}
|
|
92
|
-
const discovery = await discoverLocalTools({
|
|
93
|
-
ollamaUrl: optionalString(parsed.flags["ollama-url"])
|
|
94
|
-
});
|
|
95
|
-
const config = createConfigFromDiscovery(discovery);
|
|
96
|
-
config.language = resolveLanguage({
|
|
97
|
-
explicitLanguage: optionalString(parsed.flags.language),
|
|
98
|
-
configLanguage: config.language
|
|
99
|
-
});
|
|
100
|
-
const initMessages = createTranslator(config.language);
|
|
101
|
-
await writeExampleConfig(initConfigPath, config);
|
|
102
|
-
console.log(initMessages.init.configCreated(initConfigPath));
|
|
103
|
-
printInitDiscovery(discovery, config, initMessages);
|
|
78
|
+
await runInitCommand(parsed.flags);
|
|
104
79
|
return;
|
|
105
80
|
}
|
|
106
81
|
const configPath = optionalString(parsed.flags.config) ?? await resolveDefaultConfigPath();
|
|
@@ -283,35 +258,15 @@ async function main() {
|
|
|
283
258
|
if (!topic) {
|
|
284
259
|
throw new Error(messages.common.topicRequired);
|
|
285
260
|
}
|
|
286
|
-
const
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
const agentA = resolveAgentName("agent A", parsed.flags["agent-a"], preset?.agentA, askAgentSeeds[0] ?? config.defaults?.agentA, messages);
|
|
290
|
-
const agentB = resolveAgentName("agent B", parsed.flags["agent-b"], preset?.agentB, askAgentSeeds[1] ?? askAgentSeeds[0] ?? config.defaults?.agentB, messages);
|
|
291
|
-
const askAgents = mode === "ask" ? resolveAskAgents(explicitAskAgents, config.defaults?.askAgents, [agentA, agentB], messages) : undefined;
|
|
292
|
-
const options = {
|
|
293
|
-
mode,
|
|
261
|
+
const options = resolveRunOptions({
|
|
262
|
+
flags: parsed.flags,
|
|
263
|
+
config,
|
|
294
264
|
language,
|
|
295
265
|
topic,
|
|
296
|
-
agentA,
|
|
297
|
-
agentB,
|
|
298
|
-
askAgents,
|
|
299
|
-
turns: parseTurnsFlag(parsed.flags.turns, config.defaults?.turns ?? DEFAULT_TURNS, "--turns", messages),
|
|
300
|
-
session: createSessionContext(),
|
|
301
266
|
files: context.files,
|
|
302
|
-
|
|
303
|
-
modelB: optionalString(parsed.flags["model-b"]),
|
|
304
|
-
ollamaUrl: optionalString(parsed.flags["ollama-url"])
|
|
305
|
-
? normalizeOllamaBaseUrl(optionalString(parsed.flags["ollama-url"]))
|
|
306
|
-
: undefined,
|
|
307
|
-
pullModels: Boolean(parsed.flags["pull-models"]),
|
|
308
|
-
summaryAgent: resolveSummaryAgentOption(parsed.flags["summary-agent"], config.defaults, mode),
|
|
309
|
-
summaryModel: optionalString(parsed.flags["summary-model"]),
|
|
310
|
-
summaryEnabled: !parsed.flags["no-summary"],
|
|
311
|
-
earlyStopOnAgreement: !parsed.flags["no-early-stop"],
|
|
312
|
-
plainOutput: Boolean(parsed.flags.plain || parsed.flags.terminal),
|
|
267
|
+
preset,
|
|
313
268
|
signal: debateAbortSignal()
|
|
314
|
-
};
|
|
269
|
+
}, messages);
|
|
315
270
|
if (parsed.flags["show-prompt"]) {
|
|
316
271
|
printContextWarnings(context.warnings, messages);
|
|
317
272
|
printPromptPreview(config, options, language, messages);
|
|
@@ -332,7 +287,7 @@ async function main() {
|
|
|
332
287
|
if (!stayInTuiAfterSession) {
|
|
333
288
|
return;
|
|
334
289
|
}
|
|
335
|
-
tuiMode = mode;
|
|
290
|
+
tuiMode = options.mode;
|
|
336
291
|
for (;;) {
|
|
337
292
|
const nextInput = await promptTuiHomeTopic(tuiMode, messages, { notice: tuiNotice });
|
|
338
293
|
tuiNotice = undefined;
|
|
@@ -364,39 +319,6 @@ function debateAbortSignal() {
|
|
|
364
319
|
process.once("SIGTERM", abort);
|
|
365
320
|
return controller.signal;
|
|
366
321
|
}
|
|
367
|
-
/**
|
|
368
|
-
* Exécute la commande `agents` : charge la config et affiche les agents déclarés avec leur état de détection.
|
|
369
|
-
* @param flags - Flags parsés depuis la ligne de commande.
|
|
370
|
-
*/
|
|
371
|
-
async function runAgentsCommand(flags) {
|
|
372
|
-
const configPath = optionalString(flags.config) ?? await resolveDefaultConfigPath();
|
|
373
|
-
if (!(await configExists(configPath))) {
|
|
374
|
-
const messages = createTranslator(resolveLanguage({ explicitLanguage: optionalString(flags.language) }));
|
|
375
|
-
throw new Error(messages.agents.noConfig);
|
|
376
|
-
}
|
|
377
|
-
const config = await loadConfig(configPath);
|
|
378
|
-
const language = resolveLanguage({
|
|
379
|
-
explicitLanguage: optionalString(flags.language),
|
|
380
|
-
configLanguage: config.language
|
|
381
|
-
});
|
|
382
|
-
const messages = createTranslator(language);
|
|
383
|
-
const discovery = await discoverLocalToolsForConfig(config, optionalString(flags["ollama-url"]));
|
|
384
|
-
if (flags.json) {
|
|
385
|
-
const fallbackAskAgents = [config.defaults?.agentA, config.defaults?.agentB]
|
|
386
|
-
.filter((name) => typeof name === "string" && !isRetiredAgentName(name));
|
|
387
|
-
process.stdout.write(JSON.stringify({
|
|
388
|
-
v: 1,
|
|
389
|
-
agents: listAgentsWithAvailability(config, discovery, messages),
|
|
390
|
-
defaults: {
|
|
391
|
-
askAgents: config.defaults?.askAgents?.length
|
|
392
|
-
? config.defaults.askAgents.filter((name) => !isRetiredAgentName(name))
|
|
393
|
-
: fallbackAskAgents
|
|
394
|
-
}
|
|
395
|
-
}) + "\n");
|
|
396
|
-
return;
|
|
397
|
-
}
|
|
398
|
-
printAgents(configPath, config, discovery, messages);
|
|
399
|
-
}
|
|
400
322
|
/**
|
|
401
323
|
* Exécute la commande `config` : wizard interactif ou mise à jour directe des paramètres par défaut.
|
|
402
324
|
* @param flags - Flags parsés depuis la ligne de commande.
|
|
@@ -517,382 +439,6 @@ async function runConfigCommand(flags) {
|
|
|
517
439
|
}
|
|
518
440
|
await runConfigWizard(configPath, config, messages);
|
|
519
441
|
}
|
|
520
|
-
async function runTuiConfigLoop(configPath, config, messages, initialMode) {
|
|
521
|
-
let mode = initialMode;
|
|
522
|
-
let notice;
|
|
523
|
-
let currentMessages = messages;
|
|
524
|
-
let changedRunDefaults = false;
|
|
525
|
-
for (;;) {
|
|
526
|
-
renderTuiConfig(config, configPath, mode, currentMessages, { message: notice });
|
|
527
|
-
notice = undefined;
|
|
528
|
-
const input = await promptTuiConfigCommand(mode, currentMessages);
|
|
529
|
-
if (input.kind === "quit") {
|
|
530
|
-
return { mode, quit: true, changedRunDefaults };
|
|
531
|
-
}
|
|
532
|
-
if (input.kind === "back") {
|
|
533
|
-
return { mode, quit: false, changedRunDefaults };
|
|
534
|
-
}
|
|
535
|
-
if (input.kind === "unknown") {
|
|
536
|
-
notice = input.message;
|
|
537
|
-
continue;
|
|
538
|
-
}
|
|
539
|
-
if (input.kind === "mode") {
|
|
540
|
-
mode = mode === "ask" ? "debate" : "ask";
|
|
541
|
-
config.defaults = { ...(config.defaults ?? {}), mode };
|
|
542
|
-
await writeExampleConfig(configPath, config);
|
|
543
|
-
changedRunDefaults = true;
|
|
544
|
-
notice = mode === "ask" ? currentMessages.tui.askDefaultMode : currentMessages.tui.debateDefaultMode;
|
|
545
|
-
continue;
|
|
546
|
-
}
|
|
547
|
-
if (input.kind === "default-mode") {
|
|
548
|
-
config.defaults = { ...(config.defaults ?? {}), mode };
|
|
549
|
-
await writeExampleConfig(configPath, config);
|
|
550
|
-
changedRunDefaults = true;
|
|
551
|
-
notice = mode === "ask" ? currentMessages.tui.askDefaultMode : currentMessages.tui.debateDefaultMode;
|
|
552
|
-
continue;
|
|
553
|
-
}
|
|
554
|
-
if (input.kind === "interface") {
|
|
555
|
-
config.defaults = { ...(config.defaults ?? {}), interface: input.interfaceName };
|
|
556
|
-
await writeExampleConfig(configPath, config);
|
|
557
|
-
notice = currentMessages.tui.interfaceDefault(input.interfaceName);
|
|
558
|
-
continue;
|
|
559
|
-
}
|
|
560
|
-
if (input.kind === "language") {
|
|
561
|
-
config.language = parseLanguage(input.language, "--language");
|
|
562
|
-
await writeExampleConfig(configPath, config);
|
|
563
|
-
currentMessages = createTranslator(config.language ?? DEFAULT_LANGUAGE);
|
|
564
|
-
notice = currentMessages.tui.languageUpdated(input.language);
|
|
565
|
-
continue;
|
|
566
|
-
}
|
|
567
|
-
if (input.kind === "agents") {
|
|
568
|
-
try {
|
|
569
|
-
const agentsInput = input.agents.length > 0
|
|
570
|
-
? { kind: "agents", agents: input.agents }
|
|
571
|
-
: await promptTuiAgentsWizard(config, mode, currentMessages);
|
|
572
|
-
if (agentsInput.kind === "quit") {
|
|
573
|
-
return { mode, quit: true, changedRunDefaults };
|
|
574
|
-
}
|
|
575
|
-
if (agentsInput.kind === "back" || agentsInput.agents.length === 0) {
|
|
576
|
-
notice = currentMessages.tui.agentsUnchanged;
|
|
577
|
-
continue;
|
|
578
|
-
}
|
|
579
|
-
if (mode === "ask") {
|
|
580
|
-
const agents = normalizeTuiAskAgents(config, agentsInput.agents, currentMessages);
|
|
581
|
-
config.defaults = { ...(config.defaults ?? {}), askAgents: agents };
|
|
582
|
-
await writeExampleConfig(configPath, config);
|
|
583
|
-
changedRunDefaults = true;
|
|
584
|
-
notice = currentMessages.tui.askAgentsUpdated(agents.join(", "));
|
|
585
|
-
}
|
|
586
|
-
else {
|
|
587
|
-
const [agentA, agentB] = normalizeTuiDebateAgents(config, agentsInput.agents, currentMessages);
|
|
588
|
-
config.defaults = { ...(config.defaults ?? {}), agentA, agentB };
|
|
589
|
-
await writeExampleConfig(configPath, config);
|
|
590
|
-
changedRunDefaults = true;
|
|
591
|
-
notice = currentMessages.tui.debateAgentsUpdated(`${agentA} <-> ${agentB}`);
|
|
592
|
-
}
|
|
593
|
-
}
|
|
594
|
-
catch (error) {
|
|
595
|
-
notice = error instanceof Error ? error.message : String(error);
|
|
596
|
-
}
|
|
597
|
-
continue;
|
|
598
|
-
}
|
|
599
|
-
if (input.kind === "roles") {
|
|
600
|
-
try {
|
|
601
|
-
const rolesInput = input.roles.length > 0
|
|
602
|
-
? { kind: "roles", roles: input.roles }
|
|
603
|
-
: await promptTuiRolesWizard(config, mode, currentMessages);
|
|
604
|
-
if (rolesInput.kind === "quit") {
|
|
605
|
-
return { mode, quit: true, changedRunDefaults };
|
|
606
|
-
}
|
|
607
|
-
if (rolesInput.kind === "back" || rolesInput.roles.length === 0) {
|
|
608
|
-
notice = currentMessages.tui.rolesUnchanged;
|
|
609
|
-
continue;
|
|
610
|
-
}
|
|
611
|
-
notice = applyTuiRoles(config, mode, rolesInput.roles, currentMessages);
|
|
612
|
-
await writeExampleConfig(configPath, config);
|
|
613
|
-
}
|
|
614
|
-
catch (error) {
|
|
615
|
-
notice = error instanceof Error ? error.message : String(error);
|
|
616
|
-
}
|
|
617
|
-
continue;
|
|
618
|
-
}
|
|
619
|
-
if (input.kind === "turns") {
|
|
620
|
-
if (mode === "ask") {
|
|
621
|
-
notice = currentMessages.tui.askTurnsNotice;
|
|
622
|
-
continue;
|
|
623
|
-
}
|
|
624
|
-
try {
|
|
625
|
-
validateTurns(input.turns, "--turns", currentMessages);
|
|
626
|
-
config.defaults = { ...(config.defaults ?? {}), turns: input.turns };
|
|
627
|
-
await writeExampleConfig(configPath, config);
|
|
628
|
-
changedRunDefaults = true;
|
|
629
|
-
notice = currentMessages.tui.turnsUpdated(input.turns);
|
|
630
|
-
}
|
|
631
|
-
catch (error) {
|
|
632
|
-
notice = error instanceof Error ? error.message : String(error);
|
|
633
|
-
}
|
|
634
|
-
continue;
|
|
635
|
-
}
|
|
636
|
-
if (input.kind === "summary") {
|
|
637
|
-
try {
|
|
638
|
-
const nextDefaults = { ...(config.defaults ?? {}) };
|
|
639
|
-
if (input.agent !== undefined) {
|
|
640
|
-
assertKnownAgent(config, input.agent, mode === "ask" ? "defaults.askSummaryAgent" : "defaults.summaryAgent", currentMessages);
|
|
641
|
-
}
|
|
642
|
-
if (mode === "ask") {
|
|
643
|
-
if (input.agent === undefined) {
|
|
644
|
-
delete nextDefaults.askSummaryAgent;
|
|
645
|
-
notice = currentMessages.tui.askSummaryFallback;
|
|
646
|
-
}
|
|
647
|
-
else {
|
|
648
|
-
nextDefaults.askSummaryAgent = input.agent;
|
|
649
|
-
notice = currentMessages.tui.askSummaryAgent(input.agent);
|
|
650
|
-
}
|
|
651
|
-
}
|
|
652
|
-
else if (input.agent === undefined) {
|
|
653
|
-
delete nextDefaults.summaryAgent;
|
|
654
|
-
notice = currentMessages.tui.debateSummaryFallback;
|
|
655
|
-
}
|
|
656
|
-
else {
|
|
657
|
-
nextDefaults.summaryAgent = input.agent;
|
|
658
|
-
notice = currentMessages.tui.debateSummaryAgent(input.agent);
|
|
659
|
-
}
|
|
660
|
-
config.defaults = nextDefaults;
|
|
661
|
-
await writeExampleConfig(configPath, config);
|
|
662
|
-
changedRunDefaults = true;
|
|
663
|
-
}
|
|
664
|
-
catch (error) {
|
|
665
|
-
notice = error instanceof Error ? error.message : String(error);
|
|
666
|
-
}
|
|
667
|
-
continue;
|
|
668
|
-
}
|
|
669
|
-
if (input.kind === "ollama-info") {
|
|
670
|
-
try {
|
|
671
|
-
notice = await formatTuiOllamaInfo(config, currentMessages);
|
|
672
|
-
}
|
|
673
|
-
catch (error) {
|
|
674
|
-
notice = error instanceof Error ? error.message : String(error);
|
|
675
|
-
}
|
|
676
|
-
continue;
|
|
677
|
-
}
|
|
678
|
-
if (input.kind === "ollama-url") {
|
|
679
|
-
try {
|
|
680
|
-
notice = await setTuiOllamaUrl(configPath, config, input.url, currentMessages);
|
|
681
|
-
changedRunDefaults = true;
|
|
682
|
-
}
|
|
683
|
-
catch (error) {
|
|
684
|
-
notice = formatRuntimeError(error, currentMessages);
|
|
685
|
-
}
|
|
686
|
-
continue;
|
|
687
|
-
}
|
|
688
|
-
if (input.kind === "ollama-model") {
|
|
689
|
-
try {
|
|
690
|
-
notice = await setTuiOllamaModel(configPath, config, input.model, currentMessages);
|
|
691
|
-
changedRunDefaults = true;
|
|
692
|
-
}
|
|
693
|
-
catch (error) {
|
|
694
|
-
notice = error instanceof Error ? error.message : String(error);
|
|
695
|
-
}
|
|
696
|
-
continue;
|
|
697
|
-
}
|
|
698
|
-
if (input.kind === "ollama-sync") {
|
|
699
|
-
try {
|
|
700
|
-
notice = await syncTuiOllamaModel(configPath, config, currentMessages);
|
|
701
|
-
changedRunDefaults = true;
|
|
702
|
-
}
|
|
703
|
-
catch (error) {
|
|
704
|
-
notice = error instanceof Error ? error.message : String(error);
|
|
705
|
-
}
|
|
706
|
-
continue;
|
|
707
|
-
}
|
|
708
|
-
}
|
|
709
|
-
}
|
|
710
|
-
async function setTuiOllamaUrl(configPath, config, value, messages) {
|
|
711
|
-
if (!Object.values(config.agents).some((agent) => agent.type === "ollama")) {
|
|
712
|
-
throw new Error(messages.config.ollamaModelNoAgent);
|
|
713
|
-
}
|
|
714
|
-
const normalized = isDefaultOllamaUrl(value)
|
|
715
|
-
? DEFAULT_OLLAMA_BASE_URL
|
|
716
|
-
: normalizeOllamaBaseUrl(value);
|
|
717
|
-
const effective = resolveOllamaBaseUrl({ configUrl: normalized });
|
|
718
|
-
setOllamaBaseUrl(config, normalized);
|
|
719
|
-
await writeExampleConfig(configPath, config);
|
|
720
|
-
return messages.tui.ollamaUrlUpdated(normalized, effective);
|
|
721
|
-
}
|
|
722
|
-
function isDefaultOllamaUrl(value) {
|
|
723
|
-
return ["default", "defaut", "défaut", "local", "localhost"].includes(value.trim().toLowerCase());
|
|
724
|
-
}
|
|
725
|
-
async function formatTuiOllamaInfo(config, messages) {
|
|
726
|
-
const discovery = await discoverLocalToolsForConfig(config);
|
|
727
|
-
const agent = config.agents["ollama-local"];
|
|
728
|
-
if (agent?.type !== "ollama") {
|
|
729
|
-
throw new Error(messages.config.ollamaModelNoAgent);
|
|
730
|
-
}
|
|
731
|
-
if (!discovery.ollama.available) {
|
|
732
|
-
return messages.tui.ollamaUnavailable(discovery.ollama.baseUrl);
|
|
733
|
-
}
|
|
734
|
-
const installed = discovery.ollama.models.length > 0
|
|
735
|
-
? discovery.ollama.models.join(", ")
|
|
736
|
-
: messages.config.ollamaModelNoInstalledModels;
|
|
737
|
-
const api = `${discovery.ollama.baseUrl}`;
|
|
738
|
-
return messages.tui.ollamaInfo(agent.model, installed, api);
|
|
739
|
-
}
|
|
740
|
-
async function setTuiOllamaModel(configPath, config, model, messages) {
|
|
741
|
-
const trimmed = model.trim();
|
|
742
|
-
if (!trimmed) {
|
|
743
|
-
throw new Error(messages.tui.ollamaModelUsage);
|
|
744
|
-
}
|
|
745
|
-
const discovery = await discoverLocalToolsForConfig(config);
|
|
746
|
-
const agent = config.agents["ollama-local"];
|
|
747
|
-
if (agent?.type !== "ollama") {
|
|
748
|
-
throw new Error(messages.config.ollamaModelNoAgent);
|
|
749
|
-
}
|
|
750
|
-
if (!discovery.ollama.models.includes(trimmed)) {
|
|
751
|
-
throw new Error(messages.config.ollamaModelUnavailable(trimmed));
|
|
752
|
-
}
|
|
753
|
-
const result = setOllamaModel(config, trimmed);
|
|
754
|
-
await writeExampleConfig(configPath, config);
|
|
755
|
-
return result
|
|
756
|
-
? messages.config.ollamaModelUpdated(configPath, result.previousModel, result.nextModel)
|
|
757
|
-
: messages.config.ollamaModelNoChange(configPath, agent.model);
|
|
758
|
-
}
|
|
759
|
-
async function syncTuiOllamaModel(configPath, config, messages) {
|
|
760
|
-
const discovery = await discoverLocalToolsForConfig(config);
|
|
761
|
-
const agent = config.agents["ollama-local"];
|
|
762
|
-
if (agent?.type !== "ollama") {
|
|
763
|
-
throw new Error(messages.config.ollamaModelNoAgent);
|
|
764
|
-
}
|
|
765
|
-
if (discovery.ollama.models.length === 0) {
|
|
766
|
-
throw new Error(messages.config.ollamaModelNoInstalledModels);
|
|
767
|
-
}
|
|
768
|
-
const result = syncOllamaModel(config, discovery);
|
|
769
|
-
if (!result) {
|
|
770
|
-
return messages.config.ollamaModelNoChange(configPath, agent.model);
|
|
771
|
-
}
|
|
772
|
-
await writeExampleConfig(configPath, config);
|
|
773
|
-
return messages.config.ollamaModelUpdated(configPath, result.previousModel, result.nextModel);
|
|
774
|
-
}
|
|
775
|
-
async function syncInteractiveDetectedAgents(configPath, config) {
|
|
776
|
-
const discovery = await discoverLocalToolsForConfig(config);
|
|
777
|
-
const result = syncDetectedAgentsDetailed(config, discovery);
|
|
778
|
-
if (result.changed) {
|
|
779
|
-
await writeExampleConfig(configPath, config);
|
|
780
|
-
}
|
|
781
|
-
return {
|
|
782
|
-
addedAgents: result.addedAgents
|
|
783
|
-
};
|
|
784
|
-
}
|
|
785
|
-
function normalizeTuiDebateAgents(config, agents, messages) {
|
|
786
|
-
const unique = agents.map((agent) => agent.trim()).filter((agent, index, list) => agent && list.indexOf(agent) === index);
|
|
787
|
-
if (unique.length !== 2) {
|
|
788
|
-
throw new Error(messages.tui.debateAgentsUsage);
|
|
789
|
-
}
|
|
790
|
-
assertKnownAgent(config, unique[0], "defaults.agentA", messages);
|
|
791
|
-
assertKnownAgent(config, unique[1], "defaults.agentB", messages);
|
|
792
|
-
return [unique[0], unique[1]];
|
|
793
|
-
}
|
|
794
|
-
function normalizeTuiAskAgents(config, agents, messages) {
|
|
795
|
-
const unique = agents.map((agent) => agent.trim()).filter((agent, index, list) => agent && list.indexOf(agent) === index);
|
|
796
|
-
if (unique.length === 0) {
|
|
797
|
-
throw new Error(messages.tui.askAgentsUsage);
|
|
798
|
-
}
|
|
799
|
-
if (unique.length > MAX_ASK_AGENTS) {
|
|
800
|
-
throw new Error(messages.common.tooManyAskAgents(MAX_ASK_AGENTS));
|
|
801
|
-
}
|
|
802
|
-
unique.forEach((agent) => assertKnownAgent(config, agent, "defaults.askAgents", messages));
|
|
803
|
-
return unique;
|
|
804
|
-
}
|
|
805
|
-
async function runTuiAgentsWizard(configPath, config, messages, mode, inlineAgents = []) {
|
|
806
|
-
try {
|
|
807
|
-
const agentsInput = inlineAgents.length > 0
|
|
808
|
-
? { kind: "agents", agents: inlineAgents }
|
|
809
|
-
: await promptTuiAgentsWizard(config, mode, messages);
|
|
810
|
-
if (agentsInput.kind === "quit") {
|
|
811
|
-
return { quit: true, changedRunDefaults: false };
|
|
812
|
-
}
|
|
813
|
-
if (agentsInput.kind === "back" || agentsInput.agents.length === 0) {
|
|
814
|
-
return { quit: false, changedRunDefaults: false };
|
|
815
|
-
}
|
|
816
|
-
const notice = applyTuiAgents(config, mode, agentsInput.agents, messages);
|
|
817
|
-
await writeExampleConfig(configPath, config);
|
|
818
|
-
return { notice, quit: false, changedRunDefaults: true };
|
|
819
|
-
}
|
|
820
|
-
catch (error) {
|
|
821
|
-
return { notice: messages.tui.agentsError(error instanceof Error ? error.message : String(error)), quit: false, changedRunDefaults: false };
|
|
822
|
-
}
|
|
823
|
-
}
|
|
824
|
-
async function runTuiRolesWizard(configPath, config, messages, mode, inlineRoles = []) {
|
|
825
|
-
try {
|
|
826
|
-
const rolesInput = inlineRoles.length > 0
|
|
827
|
-
? { kind: "roles", roles: inlineRoles }
|
|
828
|
-
: await promptTuiRolesWizard(config, mode, messages);
|
|
829
|
-
if (rolesInput.kind === "quit") {
|
|
830
|
-
return { quit: true };
|
|
831
|
-
}
|
|
832
|
-
if (rolesInput.kind === "back" || rolesInput.roles.length === 0) {
|
|
833
|
-
return { quit: false };
|
|
834
|
-
}
|
|
835
|
-
const notice = applyTuiRoles(config, mode, rolesInput.roles, messages);
|
|
836
|
-
await writeExampleConfig(configPath, config);
|
|
837
|
-
return { notice, quit: false };
|
|
838
|
-
}
|
|
839
|
-
catch (error) {
|
|
840
|
-
return { notice: messages.tui.rolesError(error instanceof Error ? error.message : String(error)), quit: false };
|
|
841
|
-
}
|
|
842
|
-
}
|
|
843
|
-
function applyTuiAgents(config, mode, agentNames, messages) {
|
|
844
|
-
if (mode === "ask") {
|
|
845
|
-
const agents = normalizeTuiAskAgents(config, agentNames, messages);
|
|
846
|
-
config.defaults = { ...(config.defaults ?? {}), askAgents: agents };
|
|
847
|
-
return messages.tui.askAgentsUpdated(agents.join(", "));
|
|
848
|
-
}
|
|
849
|
-
const [agentA, agentB] = normalizeTuiDebateAgents(config, agentNames, messages);
|
|
850
|
-
config.defaults = { ...(config.defaults ?? {}), agentA, agentB };
|
|
851
|
-
return messages.tui.debateAgentsUpdated(`${agentA} <-> ${agentB}`);
|
|
852
|
-
}
|
|
853
|
-
function applyTuiRoles(config, mode, roleNames, messages) {
|
|
854
|
-
const agents = activeAgentsForMode(config, mode);
|
|
855
|
-
if (agents.length === 0) {
|
|
856
|
-
throw new Error(mode === "ask" ? messages.tui.noAskAgentsConfigured : messages.tui.noDebateAgentsConfigured);
|
|
857
|
-
}
|
|
858
|
-
const roles = normalizeTuiRoles(roleNames, agents, mode, messages);
|
|
859
|
-
agents.forEach((agent, index) => {
|
|
860
|
-
config.agents[agent].role = roles[index];
|
|
861
|
-
});
|
|
862
|
-
return mode === "ask"
|
|
863
|
-
? messages.tui.askRolesUpdated(roles.join(", "))
|
|
864
|
-
: messages.tui.debateRolesUpdated(roles.join(" <-> "));
|
|
865
|
-
}
|
|
866
|
-
function activeAgentsForMode(config, mode) {
|
|
867
|
-
const defaults = config.defaults ?? {};
|
|
868
|
-
if (mode === "ask") {
|
|
869
|
-
if (defaults.askAgents && defaults.askAgents.length > 0) {
|
|
870
|
-
return defaults.askAgents.filter((agent) => Boolean(config.agents[agent]));
|
|
871
|
-
}
|
|
872
|
-
return [defaults.agentA, defaults.agentB].filter((agent) => Boolean(agent && config.agents[agent]));
|
|
873
|
-
}
|
|
874
|
-
return [defaults.agentA, defaults.agentB].filter((agent) => Boolean(agent && config.agents[agent]));
|
|
875
|
-
}
|
|
876
|
-
function normalizeTuiRoles(roleNames, agents, mode, messages) {
|
|
877
|
-
const roles = roleNames.map((role) => role.trim().toLowerCase()).filter(Boolean);
|
|
878
|
-
const expectedCount = agents.length;
|
|
879
|
-
if (roles.length < expectedCount) {
|
|
880
|
-
const agentLabel = mode === "ask"
|
|
881
|
-
? agents.join(", ")
|
|
882
|
-
: agents.join(" <-> ");
|
|
883
|
-
throw new Error(messages.tui.rolesCountError(roles.length, expectedCount, agentLabel));
|
|
884
|
-
}
|
|
885
|
-
return roles.slice(0, expectedCount).map((role) => {
|
|
886
|
-
if (isAgentRole(role)) {
|
|
887
|
-
return role;
|
|
888
|
-
}
|
|
889
|
-
throw new Error(messages.tui.unknownRole(role, VALID_AGENT_ROLES.join(", ")));
|
|
890
|
-
});
|
|
891
|
-
}
|
|
892
|
-
function isAgentRole(value) {
|
|
893
|
-
return VALID_AGENT_ROLES.includes(value);
|
|
894
|
-
}
|
|
895
|
-
const VALID_AGENT_ROLES = ["implementer", "reviewer", "architect", "scout", "critic", "summarizer"];
|
|
896
442
|
async function runOllamaModelsCommand(config, json) {
|
|
897
443
|
const discovery = await discoverLocalToolsForConfig(config);
|
|
898
444
|
const agent = config.agents["ollama-local"];
|
|
@@ -988,32 +534,6 @@ function assertKnownAgent(config, agentName, fieldName, messages) {
|
|
|
988
534
|
throw new Error(messages.common.unknownAgentForField(fieldName, agentName, Object.keys(config.agents).join(", ")));
|
|
989
535
|
}
|
|
990
536
|
}
|
|
991
|
-
/**
|
|
992
|
-
* Résout le nom d'un agent selon la priorité : flag CLI > preset > défaut config.
|
|
993
|
-
* Lève une erreur si aucune source ne fournit de valeur.
|
|
994
|
-
* @param label - Libellé humain utilisé dans le message d'erreur (ex. "agent A").
|
|
995
|
-
* @param explicitValue - Valeur passée via flag CLI.
|
|
996
|
-
* @param presetValue - Valeur issue du preset sélectionné.
|
|
997
|
-
* @param defaultValue - Valeur issue des défauts de la config.
|
|
998
|
-
* @returns Nom de l'agent résolu.
|
|
999
|
-
*/
|
|
1000
|
-
function resolveAgentName(label, explicitValue, presetValue, defaultValue, messages) {
|
|
1001
|
-
const resolved = optionalString(explicitValue) ?? presetValue ?? defaultValue;
|
|
1002
|
-
if (!resolved) {
|
|
1003
|
-
throw new Error(messages.common.noAgentDefined(label));
|
|
1004
|
-
}
|
|
1005
|
-
return resolved;
|
|
1006
|
-
}
|
|
1007
|
-
function resolveSummaryAgentOption(explicitValue, defaults, mode) {
|
|
1008
|
-
const explicit = optionalString(explicitValue);
|
|
1009
|
-
if (explicit) {
|
|
1010
|
-
return explicit;
|
|
1011
|
-
}
|
|
1012
|
-
if (mode === "ask") {
|
|
1013
|
-
return defaults?.askSummaryAgent ?? defaults?.summaryAgent;
|
|
1014
|
-
}
|
|
1015
|
-
return defaults?.summaryAgent;
|
|
1016
|
-
}
|
|
1017
537
|
function parseModeFlag(value, messages) {
|
|
1018
538
|
if (!value) {
|
|
1019
539
|
return "debate";
|
|
@@ -1032,16 +552,6 @@ function parseInterfaceFlag(value, messages) {
|
|
|
1032
552
|
}
|
|
1033
553
|
throw new Error(messages.common.unknownMode(value, "tui, terminal"));
|
|
1034
554
|
}
|
|
1035
|
-
function resolveAskAgents(explicitAgents, defaultAgents, fallbackAgents, messages) {
|
|
1036
|
-
const selected = explicitAgents.length > 0
|
|
1037
|
-
? explicitAgents
|
|
1038
|
-
: defaultAgents && defaultAgents.length > 0 ? defaultAgents : fallbackAgents;
|
|
1039
|
-
const unique = selected.filter((agent, index) => agent.trim() && selected.indexOf(agent) === index);
|
|
1040
|
-
if (unique.length > MAX_ASK_AGENTS) {
|
|
1041
|
-
throw new Error(messages.common.tooManyAskAgents(MAX_ASK_AGENTS));
|
|
1042
|
-
}
|
|
1043
|
-
return unique;
|
|
1044
|
-
}
|
|
1045
555
|
/**
|
|
1046
556
|
* Affiche un aperçu du prompt du premier tour sans appeler aucun agent (flag `--show-prompt`).
|
|
1047
557
|
* @param config - Config chargée.
|
|
@@ -1071,29 +581,13 @@ function printPromptPreview(config, options, language, messages) {
|
|
|
1071
581
|
console.log(messages.preview.agent(previewAgent, agentConfig.role));
|
|
1072
582
|
console.log(messages.preview.peer(peerName));
|
|
1073
583
|
console.log(messages.preview.pullModels(options.pullModels));
|
|
1074
|
-
console.log(messages.preview.summary(options.summaryEnabled ?
|
|
584
|
+
console.log(messages.preview.summary(options.summaryEnabled ? options.summaryAgent : messages.preview.disabled));
|
|
1075
585
|
console.log(messages.preview.interfaceLanguage(language));
|
|
1076
586
|
console.log("");
|
|
1077
587
|
console.log(prompt);
|
|
1078
588
|
console.log("");
|
|
1079
589
|
console.log(options.mode === "ask" ? messages.preview.askNote : messages.preview.note);
|
|
1080
590
|
}
|
|
1081
|
-
function previewSummaryAgent(options) {
|
|
1082
|
-
if (options.summaryAgent) {
|
|
1083
|
-
return options.summaryAgent;
|
|
1084
|
-
}
|
|
1085
|
-
if (options.mode === "ask" && options.askAgents && options.askAgents.length > 0) {
|
|
1086
|
-
return options.askAgents[options.askAgents.length - 1] ?? options.agentB;
|
|
1087
|
-
}
|
|
1088
|
-
return options.agentB;
|
|
1089
|
-
}
|
|
1090
|
-
/**
|
|
1091
|
-
* Extrait une chaîne non vide depuis une valeur de flag, ou renvoie `undefined`.
|
|
1092
|
-
* @param value - Valeur brute issue du parseur de flags.
|
|
1093
|
-
*/
|
|
1094
|
-
function optionalString(value) {
|
|
1095
|
-
return typeof value === "string" && value.trim() ? value : undefined;
|
|
1096
|
-
}
|
|
1097
591
|
/**
|
|
1098
592
|
* Pré-lit seulement `--language`/`--lang` dans les arguments bruts pour localiser
|
|
1099
593
|
* les erreurs qui peuvent survenir avant le parsing complet ou le chargement de config.
|
|
@@ -1171,98 +665,6 @@ function shouldOpenTuiHome(parsed) {
|
|
|
1171
665
|
&& parsed.flags.plain !== true
|
|
1172
666
|
&& parsed.flags.terminal !== true;
|
|
1173
667
|
}
|
|
1174
|
-
/** Lance la discovery avec la même adresse Ollama effective que la config et les overrides globaux. */
|
|
1175
|
-
async function discoverLocalToolsForConfig(config, ollamaUrl) {
|
|
1176
|
-
return discoverLocalTools({
|
|
1177
|
-
ollamaUrl,
|
|
1178
|
-
ollamaTargets: configuredOllamaTargets(config)
|
|
1179
|
-
});
|
|
1180
|
-
}
|
|
1181
|
-
/**
|
|
1182
|
-
* Exécute la commande `palabre presets` en sortie humaine ou JSON versionné.
|
|
1183
|
-
*/
|
|
1184
|
-
async function runPresetsCommand(flags) {
|
|
1185
|
-
const configPath = optionalString(flags.config) ?? await resolveDefaultConfigPath();
|
|
1186
|
-
const ollamaUrl = optionalString(flags["ollama-url"]);
|
|
1187
|
-
const config = await configExists(configPath)
|
|
1188
|
-
? await loadConfig(configPath)
|
|
1189
|
-
: undefined;
|
|
1190
|
-
const discovery = config
|
|
1191
|
-
? await discoverLocalToolsForConfig(config, ollamaUrl)
|
|
1192
|
-
: await discoverLocalTools({ ollamaUrl });
|
|
1193
|
-
const resolvedConfig = config ?? createConfigFromDiscovery(discovery);
|
|
1194
|
-
const language = resolveLanguage({
|
|
1195
|
-
explicitLanguage: optionalString(flags.language),
|
|
1196
|
-
configLanguage: resolvedConfig.language
|
|
1197
|
-
});
|
|
1198
|
-
const messages = createTranslator(language);
|
|
1199
|
-
const presets = listPresetsWithAvailability(resolvedConfig, discovery, messages);
|
|
1200
|
-
if (flags.json) {
|
|
1201
|
-
process.stdout.write(JSON.stringify({ v: 1, presets }) + "\n");
|
|
1202
|
-
return;
|
|
1203
|
-
}
|
|
1204
|
-
console.log(messages.presets.title);
|
|
1205
|
-
console.log("");
|
|
1206
|
-
for (const preset of presets) {
|
|
1207
|
-
const status = preset.available
|
|
1208
|
-
? messages.presets.available
|
|
1209
|
-
: messages.presets.unavailable(preset.unavailableReasons.join("; "));
|
|
1210
|
-
console.log(` ${preset.name.padEnd(20)} ${preset.agentA} <-> ${preset.agentB} ${status}`);
|
|
1211
|
-
}
|
|
1212
|
-
console.log("");
|
|
1213
|
-
console.log(messages.presets.total(presets.length));
|
|
1214
|
-
}
|
|
1215
|
-
async function runHistoryCommand(flags) {
|
|
1216
|
-
const configPath = optionalString(flags.config) ?? await resolveDefaultConfigPath();
|
|
1217
|
-
const config = await configExists(configPath)
|
|
1218
|
-
? await loadConfig(configPath)
|
|
1219
|
-
: undefined;
|
|
1220
|
-
const language = resolveLanguage({
|
|
1221
|
-
explicitLanguage: optionalString(flags.language),
|
|
1222
|
-
configLanguage: config?.language
|
|
1223
|
-
});
|
|
1224
|
-
const messages = createTranslator(language);
|
|
1225
|
-
const entries = await listHistoryEntries(resolveOutputDir(config?.outputDir));
|
|
1226
|
-
if (flags.json) {
|
|
1227
|
-
process.stdout.write(JSON.stringify({ v: 1, history: entries }) + "\n");
|
|
1228
|
-
return;
|
|
1229
|
-
}
|
|
1230
|
-
console.log(messages.tui.historyTitle);
|
|
1231
|
-
console.log("");
|
|
1232
|
-
if (entries.length === 0) {
|
|
1233
|
-
console.log(messages.tui.historyEmpty);
|
|
1234
|
-
return;
|
|
1235
|
-
}
|
|
1236
|
-
for (const entry of entries) {
|
|
1237
|
-
console.log(`- ${entry.date || entry.fileName} | ${entry.mode} | ${entry.topic}`);
|
|
1238
|
-
console.log(` ${entry.path}`);
|
|
1239
|
-
}
|
|
1240
|
-
}
|
|
1241
|
-
async function runContextCommand(flags, positionals) {
|
|
1242
|
-
const language = resolveLanguage({ explicitLanguage: optionalString(flags.language) });
|
|
1243
|
-
const messages = createTranslator(language);
|
|
1244
|
-
const subcommand = positionals[0] ?? "scan";
|
|
1245
|
-
if (subcommand !== "scan") {
|
|
1246
|
-
throw new Error(messages.common.unknownCommand(`context ${subcommand}`, "context scan"));
|
|
1247
|
-
}
|
|
1248
|
-
const paths = positionals.slice(1);
|
|
1249
|
-
const result = await buildContextScan(paths, process.cwd(), messages);
|
|
1250
|
-
const folders = result.items.filter((item) => item.kind === "folder");
|
|
1251
|
-
const files = result.items.filter((item) => item.kind === "file");
|
|
1252
|
-
if (flags.json) {
|
|
1253
|
-
console.log(JSON.stringify(result, null, 2));
|
|
1254
|
-
return;
|
|
1255
|
-
}
|
|
1256
|
-
for (const folder of folders) {
|
|
1257
|
-
console.log(`[folder] ${folder.path}`);
|
|
1258
|
-
}
|
|
1259
|
-
for (const file of files) {
|
|
1260
|
-
console.log(`[file] ${file.path} (${file.sizeBytes} bytes)`);
|
|
1261
|
-
}
|
|
1262
|
-
for (const warning of result.warnings) {
|
|
1263
|
-
console.error(`${messages.renderers.warningPrefix} ${warning}`);
|
|
1264
|
-
}
|
|
1265
|
-
}
|
|
1266
668
|
/**
|
|
1267
669
|
* Écrit les avertissements de contexte sur `stderr`.
|
|
1268
670
|
* @param warnings - Messages d'avertissement issus du chargement des fichiers de contexte.
|
|
@@ -1272,152 +674,6 @@ function printContextWarnings(warnings, messages) {
|
|
|
1272
674
|
process.stderr.write(`${messages.renderers.warningPrefix} ${warning}\n`);
|
|
1273
675
|
}
|
|
1274
676
|
}
|
|
1275
|
-
/**
|
|
1276
|
-
* Ajoute dans `config.agents` les agents détectés localement mais absents de la config.
|
|
1277
|
-
* Mute `config` directement ; l'appelant est responsable de persister la config.
|
|
1278
|
-
* @param config - Config Palabre à compléter.
|
|
1279
|
-
* @param discovery - Résultat de la découverte locale des outils.
|
|
1280
|
-
* @returns Noms des agents nouvellement ajoutés.
|
|
1281
|
-
*/
|
|
1282
|
-
/**
|
|
1283
|
-
* Affiche la liste des agents déclarés avec leur type, rôle, état de détection et défauts.
|
|
1284
|
-
* @param configPath - Chemin du fichier de config (affiché en en-tête).
|
|
1285
|
-
* @param config - Config Palabre chargée.
|
|
1286
|
-
* @param discovery - Résultat de la découverte locale des outils.
|
|
1287
|
-
*/
|
|
1288
|
-
function printAgents(configPath, config, discovery, messages) {
|
|
1289
|
-
const entries = Object.entries(config.agents)
|
|
1290
|
-
.filter(([name]) => !isRetiredAgentName(name))
|
|
1291
|
-
.sort(([left], [right]) => left.localeCompare(right));
|
|
1292
|
-
console.log(messages.agents.config(configPath));
|
|
1293
|
-
console.log("");
|
|
1294
|
-
console.log(messages.agents.title);
|
|
1295
|
-
for (const [name, agentConfig] of entries) {
|
|
1296
|
-
const status = formatAgentDetection(name, agentConfig, discovery, messages);
|
|
1297
|
-
const defaults = formatAgentDefaults(name, config, messages);
|
|
1298
|
-
const details = formatAgentDetails(agentConfig, messages);
|
|
1299
|
-
const suffix = defaults ? ` | ${defaults}` : "";
|
|
1300
|
-
console.log(`- ${name.padEnd(13)} ${`${agentConfig.type}/${agentConfig.role}`.padEnd(18)} ${status}${suffix}`);
|
|
1301
|
-
if (details) {
|
|
1302
|
-
console.log(` ${details}`);
|
|
1303
|
-
}
|
|
1304
|
-
}
|
|
1305
|
-
console.log("");
|
|
1306
|
-
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));
|
|
1307
|
-
}
|
|
1308
|
-
/**
|
|
1309
|
-
* Renvoie un libellé indiquant si l'agent est agent A, agent B ou agent de synthèse par défaut.
|
|
1310
|
-
* @param name - Nom de l'agent.
|
|
1311
|
-
* @param config - Config Palabre contenant les défauts.
|
|
1312
|
-
*/
|
|
1313
|
-
function formatAgentDefaults(name, config, messages) {
|
|
1314
|
-
const labels = [];
|
|
1315
|
-
if (config.defaults?.agentA === name)
|
|
1316
|
-
labels.push(messages.agents.defaultAgentA);
|
|
1317
|
-
if (config.defaults?.agentB === name)
|
|
1318
|
-
labels.push(messages.agents.defaultAgentB);
|
|
1319
|
-
if (config.defaults?.summaryAgent === name)
|
|
1320
|
-
labels.push(messages.agents.defaultSummary);
|
|
1321
|
-
if (config.defaults?.askSummaryAgent === name)
|
|
1322
|
-
labels.push(messages.agents.defaultAskSummary);
|
|
1323
|
-
return labels.join(", ");
|
|
1324
|
-
}
|
|
1325
|
-
/**
|
|
1326
|
-
* Renvoie une ligne de détails pour un agent : commande CLI ou modèle Ollama.
|
|
1327
|
-
* @param agentConfig - Configuration de l'agent.
|
|
1328
|
-
*/
|
|
1329
|
-
function formatAgentDetails(agentConfig, messages) {
|
|
1330
|
-
if (agentConfig.type === "ollama") {
|
|
1331
|
-
return messages.agents.model(agentConfig.model);
|
|
1332
|
-
}
|
|
1333
|
-
return messages.agents.command(agentConfig.command, agentConfig.model);
|
|
1334
|
-
}
|
|
1335
|
-
/**
|
|
1336
|
-
* Renvoie le statut de détection d'un agent sous forme de chaîne lisible.
|
|
1337
|
-
* Pour Ollama, vérifie la disponibilité du serveur et la présence du modèle.
|
|
1338
|
-
* @param name - Nom de l'agent dans la config.
|
|
1339
|
-
* @param agentConfig - Configuration de l'agent.
|
|
1340
|
-
* @param discovery - Résultat de la découverte locale des outils.
|
|
1341
|
-
*/
|
|
1342
|
-
function formatAgentDetection(name, agentConfig, discovery, messages) {
|
|
1343
|
-
if (agentConfig.type === "ollama") {
|
|
1344
|
-
if (!discovery.ollama.available) {
|
|
1345
|
-
return discovery.ollama.commandAvailable ? messages.agents.ollamaUnreachable : messages.agents.ollamaNotDetected;
|
|
1346
|
-
}
|
|
1347
|
-
return discovery.ollama.models.includes(agentConfig.model)
|
|
1348
|
-
? messages.agents.detected()
|
|
1349
|
-
: messages.agents.missingModel(agentConfig.model);
|
|
1350
|
-
}
|
|
1351
|
-
const detection = cliDetectionForAgent(name, agentConfig, discovery);
|
|
1352
|
-
return detection.available ? messages.agents.detected(detection.command) : messages.agents.notDetected;
|
|
1353
|
-
}
|
|
1354
|
-
/**
|
|
1355
|
-
* Résout l'entrée de détection correspondant à un agent CLI.
|
|
1356
|
-
* Renvoie un objet `{ available: true }` pour les agents CLI non reconnus (considérés disponibles).
|
|
1357
|
-
* @param name - Nom de l'agent dans la config.
|
|
1358
|
-
* @param agentConfig - Configuration de l'agent.
|
|
1359
|
-
* @param discovery - Résultat de la découverte locale des outils.
|
|
1360
|
-
*/
|
|
1361
|
-
function cliDetectionForAgent(name, agentConfig, discovery) {
|
|
1362
|
-
const command = agentConfig.type === "cli" || agentConfig.type === "cli-pty" ? agentConfig.command : name;
|
|
1363
|
-
return detectionForCommand(command, discovery) ?? { available: true, command };
|
|
1364
|
-
}
|
|
1365
|
-
/**
|
|
1366
|
-
* Affiche le récapitulatif de détection locale après `palabre init`.
|
|
1367
|
-
* @param discovery - Résultat de la découverte locale des outils.
|
|
1368
|
-
* @param config - Config générée à partir de la découverte.
|
|
1369
|
-
*/
|
|
1370
|
-
function printInitDiscovery(discovery, config, messages) {
|
|
1371
|
-
console.log("");
|
|
1372
|
-
console.log(messages.init.localDetectionTitle);
|
|
1373
|
-
console.log(`- Codex CLI: ${formatCommandDetection(discovery.codex, messages)}`);
|
|
1374
|
-
console.log(`- Claude CLI: ${formatCommandDetection(discovery.claude, messages)}`);
|
|
1375
|
-
console.log(`- Antigravity CLI: ${formatCommandDetection(discovery.antigravity, messages)}`);
|
|
1376
|
-
console.log(`- OpenCode CLI: ${formatCommandDetection(discovery.opencode, messages)}`);
|
|
1377
|
-
console.log(`- Mistral Vibe CLI: ${formatCommandDetection(discovery.vibe, messages)}`);
|
|
1378
|
-
console.log(`- Ollama API: ${formatOllamaDetection(discovery.ollama, messages)}`);
|
|
1379
|
-
console.log("");
|
|
1380
|
-
console.log(config.defaults?.agentA && config.defaults.agentB
|
|
1381
|
-
? messages.init.defaults(config.defaults.agentA, config.defaults.agentB)
|
|
1382
|
-
: messages.init.noDefaultPair(formatDetectedAgentSummary(discovery, config.language ?? DEFAULT_LANGUAGE)));
|
|
1383
|
-
console.log(messages.init.languageHint(config.language ?? DEFAULT_LANGUAGE));
|
|
1384
|
-
}
|
|
1385
|
-
function formatDetectedAgentSummary(discovery, language) {
|
|
1386
|
-
const names = detectedAgentNames(discovery);
|
|
1387
|
-
if (names.length === 0) {
|
|
1388
|
-
return language === "en" ? "no agent detected" : "aucun agent détecté";
|
|
1389
|
-
}
|
|
1390
|
-
if (names.length === 1) {
|
|
1391
|
-
return language === "en"
|
|
1392
|
-
? `only one agent detected (${names[0]})`
|
|
1393
|
-
: `un seul agent détecté (${names[0]})`;
|
|
1394
|
-
}
|
|
1395
|
-
return language === "en"
|
|
1396
|
-
? `no usable pair detected among ${names.join(", ")}`
|
|
1397
|
-
: `aucune paire utilisable détectée parmi ${names.join(", ")}`;
|
|
1398
|
-
}
|
|
1399
|
-
/**
|
|
1400
|
-
* Formate le statut de détection d'un outil CLI (disponible ou non).
|
|
1401
|
-
* @param detection - Résultat de détection d'un outil CLI.
|
|
1402
|
-
*/
|
|
1403
|
-
function formatCommandDetection(detection, messages) {
|
|
1404
|
-
return detection.available
|
|
1405
|
-
? messages.init.commandDetected(detection.command)
|
|
1406
|
-
: messages.init.commandMissing;
|
|
1407
|
-
}
|
|
1408
|
-
/**
|
|
1409
|
-
* Formate le statut de détection d'Ollama : commande absente, serveur injoignable ou modèles disponibles.
|
|
1410
|
-
* @param detection - Résultat de détection d'Ollama.
|
|
1411
|
-
*/
|
|
1412
|
-
function formatOllamaDetection(detection, messages) {
|
|
1413
|
-
if (!detection.available) {
|
|
1414
|
-
return detection.commandAvailable
|
|
1415
|
-
? messages.init.ollamaServerUnreachable(detection.baseUrl)
|
|
1416
|
-
: messages.init.ollamaMissing;
|
|
1417
|
-
}
|
|
1418
|
-
const modelCount = detection.models.length;
|
|
1419
|
-
return messages.init.ollamaDetected(modelCount);
|
|
1420
|
-
}
|
|
1421
677
|
/** Affiche le texte d'aide complet sur `stdout`. */
|
|
1422
678
|
function printHelp(messages, command) {
|
|
1423
679
|
const commandHelp = command ? messages.help.renderCommand(command) : undefined;
|