palabre 0.8.0 → 0.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,7 @@
1
1
  import { createInterface } from "node:readline/promises";
2
2
  import { stdin as input, stdout as output } from "node:process";
3
+ import path from "node:path";
4
+ import { pathToFileURL } from "node:url";
3
5
  const supportsColor = Boolean(process.stdout.isTTY) && !process.env.NO_COLOR;
4
6
  const supportsInteractiveOutput = Boolean(process.stdout.isTTY);
5
7
  /** Cree le premier renderer TUI leger, sans dependance UI externe. */
@@ -56,34 +58,50 @@ export function renderTuiHome(config, _configPath, messages, state = {}) {
56
58
  }
57
59
  /** Affiche l'aide interne du composer TUI. */
58
60
  export function renderTuiHelp(messages) {
61
+ if (supportsInteractiveOutput) {
62
+ clearScreen();
63
+ }
59
64
  const viewport = viewportWidth();
60
65
  const width = surfaceWidth();
61
66
  process.stdout.write([
67
+ "",
68
+ ...centerLogo(viewport, messages),
62
69
  "",
63
70
  ...centerBlock(card([
64
71
  bold(messages.tui.helpTitle),
65
- `${accent("/ask")} ${messages.tui.helpAsk}`,
66
- `${accent("/debat")} ${messages.tui.helpDebate}`,
67
- `${accent("/agents")} ${messages.tui.helpAgents}`,
68
- `${accent("/roles")} ${messages.tui.helpRoles}`,
69
- `${accent("/config")} ${messages.tui.helpConfig}`,
70
- `${accent("/new")} ${messages.tui.helpNew}`,
71
- `${accent("/help")} ${messages.tui.helpHelp}`,
72
- `${accent("/quit")} ${messages.tui.helpQuit}`,
72
+ "",
73
+ row("/ask", messages.tui.helpAsk),
74
+ row("/debat", messages.tui.helpDebate),
75
+ "",
76
+ row("/agents", messages.tui.helpAgents),
77
+ row("/roles", messages.tui.helpRoles),
78
+ row("/config", messages.tui.helpConfig),
79
+ "",
80
+ row("/new", messages.tui.helpNew),
81
+ row("/retry", messages.tui.helpRetry),
82
+ row("/history", messages.tui.helpHistory),
83
+ row("/home", messages.tui.backCommand),
84
+ row("/help", messages.tui.helpHelp),
85
+ row("/quit", messages.tui.helpQuit),
73
86
  "",
74
87
  dim(messages.tui.helpFallback)
75
- ], Math.min(width, 78)), viewport),
88
+ ], width), viewport),
76
89
  ""
77
90
  ].join("\n"));
78
91
  }
79
92
  /** Affiche l'aide rapide des agents configures. */
80
93
  export function renderTuiAgentsHelp(config, mode, messages) {
94
+ if (supportsInteractiveOutput) {
95
+ clearScreen();
96
+ }
81
97
  const viewport = viewportWidth();
82
98
  const width = surfaceWidth();
83
99
  const activeAgents = activeAgentNamesForMode(config, mode);
84
100
  const separator = mode === "ask" ? ", " : " <-> ";
85
101
  const exampleAgents = exampleAgentsForMode(config, mode);
86
102
  process.stdout.write([
103
+ "",
104
+ ...centerLogo(viewport, messages),
87
105
  "",
88
106
  ...centerBlock(card([
89
107
  bold(messages.tui.agentsTitle),
@@ -96,12 +114,15 @@ export function renderTuiAgentsHelp(config, mode, messages) {
96
114
  ...agentInventoryRows(config, messages),
97
115
  "",
98
116
  dim(`${messages.tui.example}: ${messages.tui.modeLabel(mode)} > ${messages.tui.agentsPrompt} > ${exampleAgents.join(" ")}`)
99
- ], Math.min(width, 82)), viewport),
117
+ ], width), viewport),
100
118
  ""
101
119
  ].join("\n"));
102
120
  }
103
121
  /** Affiche l'aide rapide des roles disponibles. */
104
122
  export function renderTuiRolesHelp(mode, messages, config) {
123
+ if (supportsInteractiveOutput) {
124
+ clearScreen();
125
+ }
105
126
  const viewport = viewportWidth();
106
127
  const width = surfaceWidth();
107
128
  const currentRoles = config ? roleLineForMode(config, mode, messages) : undefined;
@@ -109,6 +130,8 @@ export function renderTuiRolesHelp(mode, messages, config) {
109
130
  const expectedCount = activeAgents.length || (mode === "ask" ? 3 : 2);
110
131
  const exampleRoles = exampleRolesForMode(mode, expectedCount);
111
132
  process.stdout.write([
133
+ "",
134
+ ...centerLogo(viewport, messages),
112
135
  "",
113
136
  ...centerBlock(card([
114
137
  bold(messages.tui.rolesTitle),
@@ -129,6 +152,42 @@ export function renderTuiRolesHelp(mode, messages, config) {
129
152
  ""
130
153
  ].join("\n"));
131
154
  }
155
+ /** Affiche les derniers exports Palabre disponibles. */
156
+ export function renderTuiHistory(entries, messages) {
157
+ if (supportsInteractiveOutput) {
158
+ clearScreen();
159
+ }
160
+ const viewport = viewportWidth();
161
+ const width = surfaceWidth();
162
+ const rows = entries.length === 0
163
+ ? [dim(messages.tui.historyEmpty)]
164
+ : entries.flatMap((entry) => {
165
+ const folderPath = path.dirname(entry.path);
166
+ const folderLabel = folderPath === "." ? dirnamePortable(entry.path) : folderPath;
167
+ return [
168
+ row(messages.tui.historyMode(entry.mode), entry.topic),
169
+ row(messages.tui.activeAgents, entry.agents || messages.tui.noValue),
170
+ ...(entry.count ? [row(messages.tui.historyCount(entry.mode), entry.count)] : []),
171
+ row(messages.tui.historyFile, terminalLink(entry.path, compactFileName(entry.fileName, width - 24))),
172
+ row(messages.tui.folder, terminalLink(folderPath, compactPath(folderLabel, width - 24))),
173
+ ...(entry.date ? [row("Date", entry.date)] : []),
174
+ ""
175
+ ];
176
+ }).slice(0, -1);
177
+ process.stdout.write([
178
+ "",
179
+ ...centerLogo(viewport, messages),
180
+ "",
181
+ ...centerBlock(panel([
182
+ bold(messages.tui.historyTitle),
183
+ "",
184
+ ...rows,
185
+ "",
186
+ dim(messages.tui.historyOpenHint)
187
+ ], width), viewport),
188
+ ""
189
+ ].join("\n"));
190
+ }
132
191
  /** Assistant minimal pour modifier les agents du mode courant. */
133
192
  export async function promptTuiAgentsWizard(config, mode, messages) {
134
193
  if (!input.isTTY) {
@@ -145,7 +204,7 @@ export async function promptTuiAgentsWizard(config, mode, messages) {
145
204
  return { kind: "back" };
146
205
  }
147
206
  const value = result.value.trim();
148
- if (!value || value === "/back") {
207
+ if (!value || value === "/home" || value === "/back") {
149
208
  return { kind: "back" };
150
209
  }
151
210
  if (value === "/quit" || value === "/q") {
@@ -174,7 +233,7 @@ export async function promptTuiRolesWizard(config, mode, messages) {
174
233
  }
175
234
  const answer = result.value;
176
235
  const value = answer.trim();
177
- if (!value || value === "/back") {
236
+ if (!value || value === "/home" || value === "/back") {
178
237
  return { kind: "back" };
179
238
  }
180
239
  if (value === "/quit" || value === "/q") {
@@ -216,30 +275,32 @@ export function renderTuiConfig(config, configPath, mode, messages, state = {})
216
275
  const summary = mode === "ask"
217
276
  ? defaults.askSummaryAgent ?? defaults.summaryAgent ?? messages.tui.lastAskAgent
218
277
  : defaults.summaryAgent ?? defaults.agentB ?? messages.tui.noValue;
278
+ const ollamaAgent = config.agents["ollama-local"];
279
+ const ollamaModel = ollamaAgent?.type === "ollama" ? ollamaAgent.model : undefined;
219
280
  const currentLines = mode === "ask"
220
281
  ? [
221
282
  row(messages.tui.activeAgents, askAgents),
222
- row(messages.tui.currentConfig, askRoles),
283
+ row(messages.tui.roles, askRoles),
223
284
  row(messages.tui.summary, summary),
224
285
  "",
225
286
  bold(messages.tui.availableCommands),
226
287
  "",
227
- row("/agents", "/agents codex claude opencode"),
228
- row("/roles", "/roles architect critic scout"),
229
- row("/summary", `/summary opencode ${dim(messages.tui.or)} /summary none`)
288
+ row("/agents", messages.tui.askAgentsUsage),
289
+ row("/roles", messages.tui.rolesUsage),
290
+ row("/summary", messages.tui.summaryUsage)
230
291
  ]
231
292
  : [
232
293
  row(messages.tui.activeAgents, debateAgents),
233
- row(messages.tui.currentConfig, debateRoles),
294
+ row(messages.tui.roles, debateRoles),
234
295
  row(messages.tui.summary, summary),
235
296
  row(messages.tui.responses, String(defaults.turns ?? "?")),
236
297
  "",
237
298
  bold(messages.tui.availableCommands),
238
299
  "",
239
- row("/agents", "/agents codex gemini"),
240
- row("/roles", "/roles implementer critic"),
241
- row("/turns", "/turns 4"),
242
- row("/summary", `/summary ollama-local ${dim(messages.tui.or)} /summary none`)
300
+ row("/agents", messages.tui.debateAgentsUsage),
301
+ row("/roles", messages.tui.rolesUsage),
302
+ row("/turns", messages.tui.turnsUsage),
303
+ row("/summary", messages.tui.summaryUsage)
243
304
  ];
244
305
  const lines = [
245
306
  "",
@@ -253,14 +314,22 @@ export function renderTuiConfig(config, configPath, mode, messages, state = {})
253
314
  row(messages.tui.interface, defaults.interface ?? "tui"),
254
315
  row(messages.tui.language, config.language ?? "fr"),
255
316
  row(messages.tui.availableAgentsShort, agentInventoryLine(config, messages)),
317
+ ...(ollamaModel ? [row(messages.tui.ollamaModel, ollamaModel)] : []),
256
318
  "",
257
319
  ...currentLines,
258
320
  "",
259
- row("/default", messages.tui.defaultModeCommand(mode)),
260
- row("/interface", `/interface tui ${dim(messages.tui.or)} /interface terminal`),
261
- row("/language", `/language fr ${dim(messages.tui.or)} /language en`),
262
321
  row("/mode", messages.tui.modeConfigCommand),
263
- row("/back", messages.tui.backCommand),
322
+ "",
323
+ ...(ollamaModel ? [
324
+ row("/ollama", messages.tui.ollamaInfoCommand),
325
+ row("/ollama-model", messages.tui.ollamaModelUsage),
326
+ row("/ollama-sync", messages.tui.ollamaSyncCommand),
327
+ ""
328
+ ] : []),
329
+ row("/interface", messages.tui.interfaceUsage),
330
+ row("/language", messages.tui.languageUsage),
331
+ "",
332
+ row("/home", messages.tui.backCommand),
264
333
  row("/quit", messages.tui.quitCommand)
265
334
  ], width), viewport),
266
335
  ...(state.message ? ["", ...centerBlock([state.message], viewport)] : [])
@@ -322,6 +391,15 @@ export async function promptTuiHomeTopic(mode = "debate", messages, options = {}
322
391
  if (command === "/new") {
323
392
  return { kind: "new" };
324
393
  }
394
+ if (command === "/retry") {
395
+ return { kind: "retry" };
396
+ }
397
+ if (command === "/historique" || command === "/history") {
398
+ return { kind: "history" };
399
+ }
400
+ if (command === "/home" || command === "/back" || command === "/b") {
401
+ return { kind: "home" };
402
+ }
325
403
  if (command === "/config") {
326
404
  return { kind: "config" };
327
405
  }
@@ -356,7 +434,6 @@ export async function promptTuiConfigCommand(mode, messages) {
356
434
  }
357
435
  const rl = createInterface({ input, output });
358
436
  try {
359
- renderTuiComposer(mode, messages, messages.tui.configPrompt);
360
437
  const result = await questionWithInterrupt(rl, tuiPrompt(mode, messages.tui.configPrompt, messages));
361
438
  if (result.kind === "quit") {
362
439
  return { kind: "quit" };
@@ -367,7 +444,7 @@ export async function promptTuiConfigCommand(mode, messages) {
367
444
  const answer = result.value;
368
445
  const parts = answer.trim().split(/\s+/).filter(Boolean);
369
446
  const command = parts[0]?.toLowerCase();
370
- if (!command || command === "/back" || command === "/b") {
447
+ if (!command || command === "/home" || command === "/back" || command === "/b") {
371
448
  return { kind: "back" };
372
449
  }
373
450
  if (command === "/quit" || command === "/q" || command === "/exit") {
@@ -414,6 +491,22 @@ export async function promptTuiConfigCommand(mode, messages) {
414
491
  }
415
492
  return { kind: "summary", agent: isNoneValue(value) ? undefined : value };
416
493
  }
494
+ if (command === "/ollama") {
495
+ const value = parts[1];
496
+ return value ? { kind: "ollama-model", model: value } : { kind: "ollama-info" };
497
+ }
498
+ if (command === "/ollama-model") {
499
+ const value = parts[1];
500
+ return value ? { kind: "ollama-model", model: value } : { kind: "unknown", message: messages.tui.ollamaModelUsage };
501
+ }
502
+ if (command === "/model") {
503
+ const [first, second] = parts.slice(1);
504
+ const value = first === "ollama-local" ? second : first;
505
+ return value ? { kind: "ollama-model", model: value } : { kind: "unknown", message: messages.tui.ollamaModelUsage };
506
+ }
507
+ if (command === "/ollama-sync") {
508
+ return { kind: "ollama-sync" };
509
+ }
417
510
  return { kind: "unknown", message: messages.tui.unknownCommand };
418
511
  }
419
512
  finally {
@@ -448,7 +541,11 @@ class TuiRenderer {
448
541
  process.stdout.write(this.renderSessionHeader(options, agents).join("\n") + "\n");
449
542
  }
450
543
  notice(message) {
451
- process.stdout.write(`${this.c("green", this.messages.renderers.infoPrefix)} ${message}\n`);
544
+ const viewport = viewportWidth();
545
+ const width = this.width();
546
+ process.stdout.write(`\n${centerBlock(card([
547
+ `${this.c("green", this.messages.renderers.infoPrefix)} ${message}`
548
+ ], width), viewport).join("\n")}\n`);
452
549
  }
453
550
  warning(message) {
454
551
  process.stderr.write(`${this.c("yellow", this.messages.renderers.warningPrefix)} ${message}\n`);
@@ -502,48 +599,46 @@ class TuiRenderer {
502
599
  }
503
600
  error(failure) {
504
601
  this.thinkingEnd();
505
- process.stderr.write(`\n${this.c("red", this.messages.common.errorPrefix)} ${formatFailureLocation(failure, this.messages)}: ${failure.message}\n`);
602
+ const viewport = viewportWidth();
603
+ const width = this.width();
604
+ process.stderr.write(`\n${centerBlock(card([
605
+ this.c("red", this.messages.common.errorPrefix),
606
+ `${formatFailureLocation(failure, this.messages)}: ${failure.message}`
607
+ ], width), viewport).join("\n")}\n`);
506
608
  }
507
609
  done(outputPath) {
508
610
  this.thinkingEnd();
509
611
  const viewport = viewportWidth();
510
612
  const width = this.width();
511
- process.stdout.write(`\n${centerBlock(card([
613
+ const folderPath = path.dirname(outputPath);
614
+ const fileName = path.basename(outputPath);
615
+ process.stdout.write(`\n${centerBlock(panel([
512
616
  bold(this.messages.tui.sessionDone),
513
- this.messages.renderers.exported(outputPath)
617
+ "",
618
+ row(this.messages.tui.historyFile, terminalLink(outputPath, compactFileName(fileName, width - 24))),
619
+ row(this.messages.tui.folder, terminalLink(folderPath, compactPath(folderPath, width - 24))),
620
+ "",
621
+ dim(this.messages.tui.sessionHistoryHint)
514
622
  ], width), viewport).join("\n")}\n\n`);
515
623
  }
516
624
  renderSessionHeader(options, agents) {
517
625
  const viewport = viewportWidth();
518
626
  const width = this.width();
519
627
  const mode = messagesModeLabel(this.messages, options.mode).toUpperCase();
520
- const main = [
521
- ...card([
522
- `${bold("PALABRE")} ${dim("-")} ${accent(mode)}`,
523
- this.messages.renderers.subject(options.topic),
524
- this.messages.renderers.agents(formatAgents(options, agents)),
525
- this.messages.renderers.responsesSummary(formatResponseCount(options), formatSummary(options, this.messages)),
526
- this.messages.renderers.context(formatContext(options, this.messages)),
527
- ...formatPtyNotice(agents, this.messages)
528
- ], width)
529
- ];
628
+ const main = panel([
629
+ accent(mode),
630
+ this.messages.renderers.subject(options.topic),
631
+ this.messages.renderers.agents(formatAgents(options, agents)),
632
+ formatSessionProgress(options, this.messages),
633
+ this.messages.renderers.context(formatContext(options, this.messages))
634
+ ], width);
530
635
  return [
531
- ...centerBlock(main, viewport),
636
+ ...centerLogo(viewport, this.messages),
532
637
  "",
533
- ...centerBlock(this.planPanel(options, width), viewport),
638
+ ...centerBlock(main, viewport),
534
639
  ""
535
640
  ];
536
641
  }
537
- planPanel(options, width) {
538
- return panel([
539
- bold(this.messages.tui.planTitle),
540
- dim(options.session.localDate),
541
- "",
542
- `${accent("1")} ${options.mode === "ask" ? this.messages.tui.planCollectAsk : this.messages.tui.planLaunchDebate}`,
543
- `${accent("2")} ${options.summaryEnabled ? this.messages.tui.planSummaryComparative : this.messages.tui.planSummaryDisabled}`,
544
- `${accent("3")} ${this.messages.tui.planExport}`
545
- ], width);
546
- }
547
642
  promptBlock(title, agent) {
548
643
  const viewport = viewportWidth();
549
644
  const width = this.width();
@@ -601,13 +696,7 @@ function formatAgents(options, agents) {
601
696
  return `${options.agentA} <-> ${options.agentB}`;
602
697
  }
603
698
  function formatAgent(agent) {
604
- return agent ? `${agentLabel(agent.name)} (${agent.role}, ${agent.type})` : "?";
605
- }
606
- function formatPtyNotice(agents, messages) {
607
- const ptyAgents = agents.filter((agent) => agent.type === "cli-pty").map((agent) => agent.name);
608
- return ptyAgents.length > 0
609
- ? ["", orange(messages.tui.ptyNotice(ptyAgents.join(", ")))]
610
- : [];
699
+ return agent ? `${agentLabel(agent.name)} (${agent.role})` : "?";
611
700
  }
612
701
  function formatSummary(options, messages) {
613
702
  if (!options.summaryEnabled) {
@@ -624,6 +713,9 @@ function formatSummary(options, messages) {
624
713
  function formatResponseCount(options) {
625
714
  return options.mode === "ask" ? options.askAgents?.length ?? 2 : options.turns;
626
715
  }
716
+ function formatSessionProgress(options, messages) {
717
+ return `${messages.tui.historyCount(options.mode)}: ${formatResponseCount(options)} | ${messages.tui.summary}: ${formatSummary(options, messages)}`;
718
+ }
627
719
  function formatContext(options, messages) {
628
720
  return options.files.length === 0
629
721
  ? messages.renderers.noInjectedFiles
@@ -637,7 +729,9 @@ function formatFailureLocation(failure, messages) {
637
729
  return `${failure.agent ?? "?"} (${failure.role ?? "?"}${turn})`;
638
730
  }
639
731
  function stripAnsi(value) {
640
- return value.replace(/\u001b\[[0-9;?]*[A-Za-z]/g, "");
732
+ return value
733
+ .replace(/\u001b\][^\u001b]*(?:\u0007|\u001b\\)/g, "")
734
+ .replace(/\u001b\[[0-9;?]*[A-Za-z]/g, "");
641
735
  }
642
736
  function clearScreen() {
643
737
  process.stdout.write("\u001bc\u001b[?25h");
@@ -649,18 +743,18 @@ function viewportWidth() {
649
743
  return Math.max(72, Math.min(process.stdout.columns || 100, 180));
650
744
  }
651
745
  function tuiPrompt(mode, labelPrefix, messages, notice) {
652
- const label = promptModeLabel(mode, messages);
746
+ const label = promptTrail(mode, labelPrefix, messages);
653
747
  const padding = surfacePadding();
654
- const promptLine = `${padding}${accent(label)} ${dim(">")} ${bold(labelPrefix)} ${dim(">")} `;
748
+ const promptLine = `${padding}${label} ${dim(">")} `;
655
749
  return [
656
750
  "",
657
751
  promptRuleLine(),
658
752
  ...(notice ? [
659
- `${padding}${accent(label)} ${dim(">")} ${bold(labelPrefix)} ${dim(">")}`,
753
+ `${padding}${label} ${dim(">")}`,
660
754
  ...promptNoticeLines(notice),
661
755
  ""
662
756
  ] : []),
663
- promptLine
757
+ promptLine,
664
758
  ].join("\n");
665
759
  }
666
760
  function promptRuleLine() {
@@ -680,6 +774,13 @@ function surfacePadding() {
680
774
  function promptModeLabel(mode, messages) {
681
775
  return `Mode ${messages.tui.modeValue(mode).toLowerCase()}`;
682
776
  }
777
+ function promptTrail(mode, labelPrefix, messages) {
778
+ const parts = [bold("Palabre"), accent(promptModeLabel(mode, messages))];
779
+ if (labelPrefix !== messages.tui.subject) {
780
+ parts.push(bold(labelPrefix));
781
+ }
782
+ return parts.join(` ${dim(">")} `);
783
+ }
683
784
  function messagesModeLabel(messages, mode) {
684
785
  return messages.tui.modeValue(mode);
685
786
  }
@@ -691,6 +792,25 @@ function compactPath(value, maxLength) {
691
792
  const tailLength = Math.max(12, maxLength - marker.length);
692
793
  return `${marker}${value.slice(-tailLength)}`;
693
794
  }
795
+ function dirnamePortable(value) {
796
+ const separatorIndex = Math.max(value.lastIndexOf("/"), value.lastIndexOf("\\"));
797
+ return separatorIndex > 0 ? value.slice(0, separatorIndex) : path.dirname(value);
798
+ }
799
+ function compactFileName(value, maxLength) {
800
+ if (value.length <= maxLength) {
801
+ return value;
802
+ }
803
+ const extension = value.match(/\.(debate|ask)\.md$/i)?.[0] ?? "";
804
+ const marker = "...";
805
+ const headLength = Math.max(12, maxLength - marker.length - extension.length);
806
+ return `${value.slice(0, headLength)}${marker}${extension}`;
807
+ }
808
+ function terminalLink(filePath, label) {
809
+ if (!supportsInteractiveOutput) {
810
+ return label;
811
+ }
812
+ return `\u001b]8;;${pathToFileURL(filePath).href}\u001b\\${label}\u001b]8;;\u001b\\`;
813
+ }
694
814
  function roleFor(config, agent, messages) {
695
815
  return config.agents[agent]?.role ?? messages.tui.noValue;
696
816
  }
@@ -714,16 +834,24 @@ function activeAgentNamesForMode(config, mode) {
714
834
  return [defaults.agentA, defaults.agentB].filter((agent) => Boolean(agent && config.agents[agent]));
715
835
  }
716
836
  function agentInventoryLine(config, messages) {
717
- const agents = Object.keys(config.agents).sort();
837
+ const agents = Object.entries(config.agents)
838
+ .filter(([name]) => !isRetiredAgentName(name))
839
+ .map(([name]) => name)
840
+ .sort();
718
841
  return agents.length > 0 ? agents.map(agentLabel).join(", ") : messages.tui.noValue;
719
842
  }
720
843
  function agentInventoryRows(config, messages) {
721
- const entries = Object.entries(config.agents).sort(([agentA], [agentB]) => agentA.localeCompare(agentB));
844
+ const entries = Object.entries(config.agents)
845
+ .filter(([name]) => !isRetiredAgentName(name))
846
+ .sort(([agentA], [agentB]) => agentA.localeCompare(agentB));
722
847
  if (entries.length === 0) {
723
848
  return [dim(messages.tui.noConfiguredAgents)];
724
849
  }
725
850
  return entries.map(([name, agent]) => row(name, `${agent.type} ${dim("·")} ${agent.role}`));
726
851
  }
852
+ function isRetiredAgentName(name) {
853
+ return name === "gemini";
854
+ }
727
855
  function exampleAgentsForMode(config, mode) {
728
856
  const activeAgents = activeAgentNamesForMode(config, mode);
729
857
  if (activeAgents.length > 0) {
@@ -786,9 +914,8 @@ function centerLine(line, width) {
786
914
  return `${" ".repeat(left)}${line}`;
787
915
  }
788
916
  function composerInputBox(mode, labelPrefix, width, messages) {
789
- const label = promptModeLabel(mode, messages);
790
917
  return composerCard([
791
- `${accent(label)} ${dim(">")} ${bold(labelPrefix)} ${dim(">")}`
918
+ `${promptTrail(mode, labelPrefix, messages)} ${dim(">")}`
792
919
  ], width, "center");
793
920
  }
794
921
  function panel(lines, width) {
@@ -863,9 +990,6 @@ function accent(value) {
863
990
  function violet(value) {
864
991
  return supportsColor ? `${codes.violet}${value}${codes.reset}` : value;
865
992
  }
866
- function orange(value) {
867
- return supportsColor ? `${codes.orange}${value}${codes.reset}` : value;
868
- }
869
993
  function muted(value) {
870
994
  return supportsColor ? `${codes.gray}${value}${codes.reset}` : value;
871
995
  }
@@ -909,7 +1033,6 @@ function hslToRgb(hue, saturation, lightness) {
909
1033
  const agentColors = {
910
1034
  antigravity: [76, 141, 255],
911
1035
  claude: [222, 115, 86],
912
- gemini: [71, 150, 227],
913
1036
  codex: [136, 82, 197],
914
1037
  opencode: [80, 168, 103],
915
1038
  vibe: [234, 92, 126],
@@ -0,0 +1,31 @@
1
+ const TUI_RUN_OVERRIDE_FLAGS = [
2
+ "preset",
3
+ "agent-a",
4
+ "agent-b",
5
+ "agents",
6
+ "model-a",
7
+ "model-b",
8
+ "summary-agent",
9
+ "summary-model",
10
+ "turns",
11
+ "files",
12
+ "context",
13
+ "no-summary",
14
+ "no-early-stop",
15
+ "pull-models",
16
+ "show-prompt",
17
+ "plain",
18
+ "terminal",
19
+ "json"
20
+ ];
21
+ export function clearTuiRunOverrides(flags) {
22
+ for (const flag of TUI_RUN_OVERRIDE_FLAGS) {
23
+ delete flags[flag];
24
+ }
25
+ }
26
+ export function askAgentSeedsForMode(mode, explicitAskAgents, defaultAskAgents) {
27
+ if (mode !== "ask") {
28
+ return [];
29
+ }
30
+ return explicitAskAgents.length > 0 ? explicitAskAgents : defaultAskAgents ?? [];
31
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "palabre",
3
- "version": "0.8.0",
3
+ "version": "0.8.1",
4
4
  "description": "Orchestrateur de debat entre agents IA locaux, CLIs et Ollama.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -39,23 +39,6 @@
39
39
  "role": "reviewer",
40
40
  "tier": "primary"
41
41
  },
42
- "gemini": {
43
- "type": "cli",
44
- "command": "gemini",
45
- "args": [
46
- "--output-format",
47
- "text",
48
- "--approval-mode",
49
- "plan",
50
- "--skip-trust",
51
- "--prompt",
52
- "-"
53
- ],
54
- "promptMode": "stdin",
55
- "shell": true,
56
- "role": "reviewer",
57
- "tier": "primary"
58
- },
59
42
  "opencode": {
60
43
  "type": "cli",
61
44
  "command": "opencode",