palabre 0.8.0 → 0.9.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 +13 -15
- package/dist/adapters/cli-pty.js +1 -1
- package/dist/adapters/cli.js +33 -3
- package/dist/adapters/index.js +2 -2
- package/dist/adapters/ollama.js +9 -7
- package/dist/agentRegistry.js +7 -2
- package/dist/args.js +5 -2
- package/dist/config.js +33 -25
- package/dist/context.js +5 -1
- package/dist/discovery.js +30 -9
- package/dist/doctor.js +19 -5
- package/dist/history.js +85 -0
- package/dist/index.js +450 -205
- package/dist/messages/common.js +6 -0
- package/dist/messages/config.js +2 -0
- package/dist/messages/doctor.js +2 -2
- package/dist/messages/help.js +64 -8
- package/dist/messages/init.js +2 -2
- package/dist/messages/tui.js +78 -28
- package/dist/ollamaUrl.js +76 -0
- package/dist/orchestrator.js +34 -13
- package/dist/presets.js +25 -52
- package/dist/renderers/tui.js +242 -77
- package/dist/tuiState.js +32 -0
- package/package.json +1 -1
- package/palabre.config.example.json +0 -17
package/dist/renderers/tui.js
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
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";
|
|
5
|
+
import { isRetiredAgentName } from "../agentRegistry.js";
|
|
6
|
+
import { DEFAULT_OLLAMA_BASE_URL, resolveOllamaBaseUrl } from "../ollamaUrl.js";
|
|
3
7
|
const supportsColor = Boolean(process.stdout.isTTY) && !process.env.NO_COLOR;
|
|
4
8
|
const supportsInteractiveOutput = Boolean(process.stdout.isTTY);
|
|
5
9
|
/** Cree le premier renderer TUI leger, sans dependance UI externe. */
|
|
@@ -33,10 +37,14 @@ export function renderTuiHome(config, _configPath, messages, state = {}) {
|
|
|
33
37
|
const summary = mode === "ask"
|
|
34
38
|
? defaults.askSummaryAgent ?? defaults.summaryAgent ?? messages.tui.lastAskAgent
|
|
35
39
|
: defaults.summaryAgent ?? defaults.agentB ?? "agent B";
|
|
40
|
+
const version = state.version ?? "0.0.0";
|
|
41
|
+
const versionLines = state.latestVersion
|
|
42
|
+
? [dim(`v${version}`), accent(messages.tui.updateAvailable(version, state.latestVersion))]
|
|
43
|
+
: [dim(`v${version}`)];
|
|
36
44
|
const lines = [
|
|
37
45
|
"",
|
|
38
46
|
...centerLogo(viewport, messages),
|
|
39
|
-
...centerBlock(
|
|
47
|
+
...centerBlock(versionLines, viewport),
|
|
40
48
|
"",
|
|
41
49
|
...centerBlock(composerCard([
|
|
42
50
|
`${accent(messages.tui.modeValue(mode))} ${dim("·")} ${mode === "ask" ? askAgents : debateAgents}`,
|
|
@@ -54,36 +62,68 @@ export function renderTuiHome(config, _configPath, messages, state = {}) {
|
|
|
54
62
|
];
|
|
55
63
|
process.stdout.write(lines.join("\n") + "\n");
|
|
56
64
|
}
|
|
65
|
+
/** Affiche les instructions de mise a jour sans quitter le TUI. */
|
|
66
|
+
export function renderTuiUpdate(instructions, messages) {
|
|
67
|
+
if (supportsInteractiveOutput) {
|
|
68
|
+
clearScreen();
|
|
69
|
+
}
|
|
70
|
+
const viewport = viewportWidth();
|
|
71
|
+
const width = surfaceWidth();
|
|
72
|
+
process.stdout.write([
|
|
73
|
+
"",
|
|
74
|
+
...centerLogo(viewport, messages),
|
|
75
|
+
"",
|
|
76
|
+
...centerBlock(card(instructions.split(/\r?\n/), width), viewport),
|
|
77
|
+
""
|
|
78
|
+
].join("\n"));
|
|
79
|
+
}
|
|
57
80
|
/** Affiche l'aide interne du composer TUI. */
|
|
58
81
|
export function renderTuiHelp(messages) {
|
|
82
|
+
if (supportsInteractiveOutput) {
|
|
83
|
+
clearScreen();
|
|
84
|
+
}
|
|
59
85
|
const viewport = viewportWidth();
|
|
60
86
|
const width = surfaceWidth();
|
|
61
87
|
process.stdout.write([
|
|
88
|
+
"",
|
|
89
|
+
...centerLogo(viewport, messages),
|
|
62
90
|
"",
|
|
63
91
|
...centerBlock(card([
|
|
64
92
|
bold(messages.tui.helpTitle),
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
93
|
+
"",
|
|
94
|
+
row("/ask", messages.tui.helpAsk),
|
|
95
|
+
row("/debat", messages.tui.helpDebate),
|
|
96
|
+
"",
|
|
97
|
+
row("/agents", messages.tui.helpAgents),
|
|
98
|
+
row("/roles", messages.tui.helpRoles),
|
|
99
|
+
row("/config", messages.tui.helpConfig),
|
|
100
|
+
"",
|
|
101
|
+
row("/new", messages.tui.helpNew),
|
|
102
|
+
row("/retry", messages.tui.helpRetry),
|
|
103
|
+
row("/history", messages.tui.helpHistory),
|
|
104
|
+
row("/update", messages.tui.helpUpdate),
|
|
105
|
+
row("/home", messages.tui.backCommand),
|
|
106
|
+
row("/help", messages.tui.helpHelp),
|
|
107
|
+
row("/quit", messages.tui.helpQuit),
|
|
73
108
|
"",
|
|
74
109
|
dim(messages.tui.helpFallback)
|
|
75
|
-
],
|
|
110
|
+
], width), viewport),
|
|
76
111
|
""
|
|
77
112
|
].join("\n"));
|
|
78
113
|
}
|
|
79
114
|
/** Affiche l'aide rapide des agents configures. */
|
|
80
115
|
export function renderTuiAgentsHelp(config, mode, messages) {
|
|
116
|
+
if (supportsInteractiveOutput) {
|
|
117
|
+
clearScreen();
|
|
118
|
+
}
|
|
81
119
|
const viewport = viewportWidth();
|
|
82
120
|
const width = surfaceWidth();
|
|
83
121
|
const activeAgents = activeAgentNamesForMode(config, mode);
|
|
84
122
|
const separator = mode === "ask" ? ", " : " <-> ";
|
|
85
123
|
const exampleAgents = exampleAgentsForMode(config, mode);
|
|
86
124
|
process.stdout.write([
|
|
125
|
+
"",
|
|
126
|
+
...centerLogo(viewport, messages),
|
|
87
127
|
"",
|
|
88
128
|
...centerBlock(card([
|
|
89
129
|
bold(messages.tui.agentsTitle),
|
|
@@ -96,12 +136,15 @@ export function renderTuiAgentsHelp(config, mode, messages) {
|
|
|
96
136
|
...agentInventoryRows(config, messages),
|
|
97
137
|
"",
|
|
98
138
|
dim(`${messages.tui.example}: ${messages.tui.modeLabel(mode)} > ${messages.tui.agentsPrompt} > ${exampleAgents.join(" ")}`)
|
|
99
|
-
],
|
|
139
|
+
], width), viewport),
|
|
100
140
|
""
|
|
101
141
|
].join("\n"));
|
|
102
142
|
}
|
|
103
143
|
/** Affiche l'aide rapide des roles disponibles. */
|
|
104
144
|
export function renderTuiRolesHelp(mode, messages, config) {
|
|
145
|
+
if (supportsInteractiveOutput) {
|
|
146
|
+
clearScreen();
|
|
147
|
+
}
|
|
105
148
|
const viewport = viewportWidth();
|
|
106
149
|
const width = surfaceWidth();
|
|
107
150
|
const currentRoles = config ? roleLineForMode(config, mode, messages) : undefined;
|
|
@@ -109,6 +152,8 @@ export function renderTuiRolesHelp(mode, messages, config) {
|
|
|
109
152
|
const expectedCount = activeAgents.length || (mode === "ask" ? 3 : 2);
|
|
110
153
|
const exampleRoles = exampleRolesForMode(mode, expectedCount);
|
|
111
154
|
process.stdout.write([
|
|
155
|
+
"",
|
|
156
|
+
...centerLogo(viewport, messages),
|
|
112
157
|
"",
|
|
113
158
|
...centerBlock(card([
|
|
114
159
|
bold(messages.tui.rolesTitle),
|
|
@@ -129,6 +174,42 @@ export function renderTuiRolesHelp(mode, messages, config) {
|
|
|
129
174
|
""
|
|
130
175
|
].join("\n"));
|
|
131
176
|
}
|
|
177
|
+
/** Affiche les derniers exports Palabre disponibles. */
|
|
178
|
+
export function renderTuiHistory(entries, messages) {
|
|
179
|
+
if (supportsInteractiveOutput) {
|
|
180
|
+
clearScreen();
|
|
181
|
+
}
|
|
182
|
+
const viewport = viewportWidth();
|
|
183
|
+
const width = surfaceWidth();
|
|
184
|
+
const rows = entries.length === 0
|
|
185
|
+
? [dim(messages.tui.historyEmpty)]
|
|
186
|
+
: entries.flatMap((entry) => {
|
|
187
|
+
const folderPath = path.dirname(entry.path);
|
|
188
|
+
const folderLabel = folderPath === "." ? dirnamePortable(entry.path) : folderPath;
|
|
189
|
+
return [
|
|
190
|
+
row(messages.tui.historyMode(entry.mode), entry.topic),
|
|
191
|
+
row(messages.tui.activeAgents, entry.agents || messages.tui.noValue),
|
|
192
|
+
...(entry.count ? [row(messages.tui.historyCount(entry.mode), entry.count)] : []),
|
|
193
|
+
row(messages.tui.historyFile, terminalLink(entry.path, compactFileName(entry.fileName, width - 24))),
|
|
194
|
+
row(messages.tui.folder, terminalLink(folderPath, compactPath(folderLabel, width - 24))),
|
|
195
|
+
...(entry.date ? [row("Date", entry.date)] : []),
|
|
196
|
+
""
|
|
197
|
+
];
|
|
198
|
+
}).slice(0, -1);
|
|
199
|
+
process.stdout.write([
|
|
200
|
+
"",
|
|
201
|
+
...centerLogo(viewport, messages),
|
|
202
|
+
"",
|
|
203
|
+
...centerBlock(panel([
|
|
204
|
+
bold(messages.tui.historyTitle),
|
|
205
|
+
"",
|
|
206
|
+
...rows,
|
|
207
|
+
"",
|
|
208
|
+
dim(messages.tui.historyOpenHint)
|
|
209
|
+
], width), viewport),
|
|
210
|
+
""
|
|
211
|
+
].join("\n"));
|
|
212
|
+
}
|
|
132
213
|
/** Assistant minimal pour modifier les agents du mode courant. */
|
|
133
214
|
export async function promptTuiAgentsWizard(config, mode, messages) {
|
|
134
215
|
if (!input.isTTY) {
|
|
@@ -145,7 +226,7 @@ export async function promptTuiAgentsWizard(config, mode, messages) {
|
|
|
145
226
|
return { kind: "back" };
|
|
146
227
|
}
|
|
147
228
|
const value = result.value.trim();
|
|
148
|
-
if (!value || value === "/back") {
|
|
229
|
+
if (!value || value === "/home" || value === "/back") {
|
|
149
230
|
return { kind: "back" };
|
|
150
231
|
}
|
|
151
232
|
if (value === "/quit" || value === "/q") {
|
|
@@ -174,7 +255,7 @@ export async function promptTuiRolesWizard(config, mode, messages) {
|
|
|
174
255
|
}
|
|
175
256
|
const answer = result.value;
|
|
176
257
|
const value = answer.trim();
|
|
177
|
-
if (!value || value === "/back") {
|
|
258
|
+
if (!value || value === "/home" || value === "/back") {
|
|
178
259
|
return { kind: "back" };
|
|
179
260
|
}
|
|
180
261
|
if (value === "/quit" || value === "/q") {
|
|
@@ -216,30 +297,34 @@ export function renderTuiConfig(config, configPath, mode, messages, state = {})
|
|
|
216
297
|
const summary = mode === "ask"
|
|
217
298
|
? defaults.askSummaryAgent ?? defaults.summaryAgent ?? messages.tui.lastAskAgent
|
|
218
299
|
: defaults.summaryAgent ?? defaults.agentB ?? messages.tui.noValue;
|
|
300
|
+
const ollamaAgent = config.agents["ollama-local"];
|
|
301
|
+
const ollamaModel = ollamaAgent?.type === "ollama" ? ollamaAgent.model : undefined;
|
|
302
|
+
const ollamaUrl = ollamaAgent?.type === "ollama" ? ollamaAgent.baseUrl ?? DEFAULT_OLLAMA_BASE_URL : undefined;
|
|
303
|
+
const ollamaEffectiveUrl = ollamaUrl ? safeEffectiveOllamaUrl(ollamaUrl) : undefined;
|
|
219
304
|
const currentLines = mode === "ask"
|
|
220
305
|
? [
|
|
221
306
|
row(messages.tui.activeAgents, askAgents),
|
|
222
|
-
row(messages.tui.
|
|
307
|
+
row(messages.tui.roles, askRoles),
|
|
223
308
|
row(messages.tui.summary, summary),
|
|
224
309
|
"",
|
|
225
310
|
bold(messages.tui.availableCommands),
|
|
226
311
|
"",
|
|
227
|
-
row("/agents",
|
|
228
|
-
row("/roles",
|
|
229
|
-
row("/summary",
|
|
312
|
+
row("/agents", messages.tui.askAgentsUsage),
|
|
313
|
+
row("/roles", messages.tui.rolesUsage),
|
|
314
|
+
row("/summary", messages.tui.summaryUsage)
|
|
230
315
|
]
|
|
231
316
|
: [
|
|
232
317
|
row(messages.tui.activeAgents, debateAgents),
|
|
233
|
-
row(messages.tui.
|
|
318
|
+
row(messages.tui.roles, debateRoles),
|
|
234
319
|
row(messages.tui.summary, summary),
|
|
235
320
|
row(messages.tui.responses, String(defaults.turns ?? "?")),
|
|
236
321
|
"",
|
|
237
322
|
bold(messages.tui.availableCommands),
|
|
238
323
|
"",
|
|
239
|
-
row("/agents",
|
|
240
|
-
row("/roles",
|
|
241
|
-
row("/turns",
|
|
242
|
-
row("/summary",
|
|
324
|
+
row("/agents", messages.tui.debateAgentsUsage),
|
|
325
|
+
row("/roles", messages.tui.rolesUsage),
|
|
326
|
+
row("/turns", messages.tui.turnsUsage),
|
|
327
|
+
row("/summary", messages.tui.summaryUsage)
|
|
243
328
|
];
|
|
244
329
|
const lines = [
|
|
245
330
|
"",
|
|
@@ -249,24 +334,47 @@ export function renderTuiConfig(config, configPath, mode, messages, state = {})
|
|
|
249
334
|
bold(messages.tui.configTitle),
|
|
250
335
|
"",
|
|
251
336
|
row(messages.tui.activeMode, messages.tui.modeValue(mode)),
|
|
337
|
+
...(ollamaUrl ? [row(messages.tui.ollamaUrl, ollamaUrl)] : []),
|
|
338
|
+
...(ollamaEffectiveUrl && ollamaEffectiveUrl !== ollamaUrl ? [row(messages.tui.ollamaUrlEffective, ollamaEffectiveUrl)] : []),
|
|
252
339
|
row(messages.tui.configFile, configPath),
|
|
253
340
|
row(messages.tui.interface, defaults.interface ?? "tui"),
|
|
254
341
|
row(messages.tui.language, config.language ?? "fr"),
|
|
255
342
|
row(messages.tui.availableAgentsShort, agentInventoryLine(config, messages)),
|
|
343
|
+
...(ollamaModel ? [row(messages.tui.ollamaModel, ollamaModel)] : []),
|
|
256
344
|
"",
|
|
257
345
|
...currentLines,
|
|
258
346
|
"",
|
|
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
347
|
row("/mode", messages.tui.modeConfigCommand),
|
|
263
|
-
|
|
348
|
+
"",
|
|
349
|
+
...(ollamaModel ? [
|
|
350
|
+
row("/ollama", messages.tui.ollamaInfoCommand),
|
|
351
|
+
row("/ollama-model", messages.tui.ollamaModelUsage),
|
|
352
|
+
row("/ollama-url", messages.tui.ollamaUrlCommand),
|
|
353
|
+
row("/ollama-sync", messages.tui.ollamaSyncCommand),
|
|
354
|
+
""
|
|
355
|
+
] : []),
|
|
356
|
+
row("/interface", messages.tui.interfaceUsage),
|
|
357
|
+
row("/language", messages.tui.languageUsage),
|
|
358
|
+
"",
|
|
359
|
+
row("/home", messages.tui.backCommand),
|
|
264
360
|
row("/quit", messages.tui.quitCommand)
|
|
265
361
|
], width), viewport),
|
|
266
362
|
...(state.message ? ["", ...centerBlock([state.message], viewport)] : [])
|
|
267
363
|
];
|
|
268
364
|
process.stdout.write(lines.join("\n") + "\n");
|
|
269
365
|
}
|
|
366
|
+
export function parseTuiOllamaUrlCommand(parts, messages) {
|
|
367
|
+
const value = parts[1];
|
|
368
|
+
return value ? { kind: "ollama-url", url: value } : { kind: "unknown", message: messages.tui.ollamaUrlUsage };
|
|
369
|
+
}
|
|
370
|
+
function safeEffectiveOllamaUrl(configUrl) {
|
|
371
|
+
try {
|
|
372
|
+
return resolveOllamaBaseUrl({ configUrl });
|
|
373
|
+
}
|
|
374
|
+
catch {
|
|
375
|
+
return process.env.OLLAMA_HOST?.trim() || configUrl;
|
|
376
|
+
}
|
|
377
|
+
}
|
|
270
378
|
let lastTuiInterruptAt = 0;
|
|
271
379
|
const doubleInterruptMs = 1200;
|
|
272
380
|
function nextInterruptKind() {
|
|
@@ -322,6 +430,18 @@ export async function promptTuiHomeTopic(mode = "debate", messages, options = {}
|
|
|
322
430
|
if (command === "/new") {
|
|
323
431
|
return { kind: "new" };
|
|
324
432
|
}
|
|
433
|
+
if (command === "/retry") {
|
|
434
|
+
return { kind: "retry" };
|
|
435
|
+
}
|
|
436
|
+
if (command === "/update") {
|
|
437
|
+
return { kind: "update" };
|
|
438
|
+
}
|
|
439
|
+
if (command === "/historique" || command === "/history") {
|
|
440
|
+
return { kind: "history" };
|
|
441
|
+
}
|
|
442
|
+
if (command === "/home" || command === "/back" || command === "/b") {
|
|
443
|
+
return { kind: "home" };
|
|
444
|
+
}
|
|
325
445
|
if (command === "/config") {
|
|
326
446
|
return { kind: "config" };
|
|
327
447
|
}
|
|
@@ -356,7 +476,6 @@ export async function promptTuiConfigCommand(mode, messages) {
|
|
|
356
476
|
}
|
|
357
477
|
const rl = createInterface({ input, output });
|
|
358
478
|
try {
|
|
359
|
-
renderTuiComposer(mode, messages, messages.tui.configPrompt);
|
|
360
479
|
const result = await questionWithInterrupt(rl, tuiPrompt(mode, messages.tui.configPrompt, messages));
|
|
361
480
|
if (result.kind === "quit") {
|
|
362
481
|
return { kind: "quit" };
|
|
@@ -367,7 +486,7 @@ export async function promptTuiConfigCommand(mode, messages) {
|
|
|
367
486
|
const answer = result.value;
|
|
368
487
|
const parts = answer.trim().split(/\s+/).filter(Boolean);
|
|
369
488
|
const command = parts[0]?.toLowerCase();
|
|
370
|
-
if (!command || command === "/back" || command === "/b") {
|
|
489
|
+
if (!command || command === "/home" || command === "/back" || command === "/b") {
|
|
371
490
|
return { kind: "back" };
|
|
372
491
|
}
|
|
373
492
|
if (command === "/quit" || command === "/q" || command === "/exit") {
|
|
@@ -414,6 +533,25 @@ export async function promptTuiConfigCommand(mode, messages) {
|
|
|
414
533
|
}
|
|
415
534
|
return { kind: "summary", agent: isNoneValue(value) ? undefined : value };
|
|
416
535
|
}
|
|
536
|
+
if (command === "/ollama") {
|
|
537
|
+
const value = parts[1];
|
|
538
|
+
return value ? { kind: "ollama-model", model: value } : { kind: "ollama-info" };
|
|
539
|
+
}
|
|
540
|
+
if (command === "/ollama-url" || command === "/ollama-host") {
|
|
541
|
+
return parseTuiOllamaUrlCommand(parts, messages);
|
|
542
|
+
}
|
|
543
|
+
if (command === "/ollama-model") {
|
|
544
|
+
const value = parts[1];
|
|
545
|
+
return value ? { kind: "ollama-model", model: value } : { kind: "unknown", message: messages.tui.ollamaModelUsage };
|
|
546
|
+
}
|
|
547
|
+
if (command === "/model") {
|
|
548
|
+
const [first, second] = parts.slice(1);
|
|
549
|
+
const value = first === "ollama-local" ? second : first;
|
|
550
|
+
return value ? { kind: "ollama-model", model: value } : { kind: "unknown", message: messages.tui.ollamaModelUsage };
|
|
551
|
+
}
|
|
552
|
+
if (command === "/ollama-sync") {
|
|
553
|
+
return { kind: "ollama-sync" };
|
|
554
|
+
}
|
|
417
555
|
return { kind: "unknown", message: messages.tui.unknownCommand };
|
|
418
556
|
}
|
|
419
557
|
finally {
|
|
@@ -448,7 +586,11 @@ class TuiRenderer {
|
|
|
448
586
|
process.stdout.write(this.renderSessionHeader(options, agents).join("\n") + "\n");
|
|
449
587
|
}
|
|
450
588
|
notice(message) {
|
|
451
|
-
|
|
589
|
+
const viewport = viewportWidth();
|
|
590
|
+
const width = this.width();
|
|
591
|
+
process.stdout.write(`\n${centerBlock(card([
|
|
592
|
+
`${this.c("green", this.messages.renderers.infoPrefix)} ${message}`
|
|
593
|
+
], width), viewport).join("\n")}\n`);
|
|
452
594
|
}
|
|
453
595
|
warning(message) {
|
|
454
596
|
process.stderr.write(`${this.c("yellow", this.messages.renderers.warningPrefix)} ${message}\n`);
|
|
@@ -502,48 +644,46 @@ class TuiRenderer {
|
|
|
502
644
|
}
|
|
503
645
|
error(failure) {
|
|
504
646
|
this.thinkingEnd();
|
|
505
|
-
|
|
647
|
+
const viewport = viewportWidth();
|
|
648
|
+
const width = this.width();
|
|
649
|
+
process.stderr.write(`\n${centerBlock(card([
|
|
650
|
+
this.c("red", this.messages.common.errorPrefix),
|
|
651
|
+
`${formatFailureLocation(failure, this.messages)}: ${failure.message}`
|
|
652
|
+
], width), viewport).join("\n")}\n`);
|
|
506
653
|
}
|
|
507
654
|
done(outputPath) {
|
|
508
655
|
this.thinkingEnd();
|
|
509
656
|
const viewport = viewportWidth();
|
|
510
657
|
const width = this.width();
|
|
511
|
-
|
|
658
|
+
const folderPath = path.dirname(outputPath);
|
|
659
|
+
const fileName = path.basename(outputPath);
|
|
660
|
+
process.stdout.write(`\n${centerBlock(panel([
|
|
512
661
|
bold(this.messages.tui.sessionDone),
|
|
513
|
-
|
|
662
|
+
"",
|
|
663
|
+
row(this.messages.tui.historyFile, terminalLink(outputPath, compactFileName(fileName, width - 24))),
|
|
664
|
+
row(this.messages.tui.folder, terminalLink(folderPath, compactPath(folderPath, width - 24))),
|
|
665
|
+
"",
|
|
666
|
+
dim(this.messages.tui.sessionHistoryHint)
|
|
514
667
|
], width), viewport).join("\n")}\n\n`);
|
|
515
668
|
}
|
|
516
669
|
renderSessionHeader(options, agents) {
|
|
517
670
|
const viewport = viewportWidth();
|
|
518
671
|
const width = this.width();
|
|
519
672
|
const mode = messagesModeLabel(this.messages, options.mode).toUpperCase();
|
|
520
|
-
const main = [
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
...formatPtyNotice(agents, this.messages)
|
|
528
|
-
], width)
|
|
529
|
-
];
|
|
673
|
+
const main = panel([
|
|
674
|
+
accent(mode),
|
|
675
|
+
this.messages.renderers.subject(options.topic),
|
|
676
|
+
this.messages.renderers.agents(formatAgents(options, agents)),
|
|
677
|
+
formatSessionProgress(options, this.messages),
|
|
678
|
+
this.messages.renderers.context(formatContext(options, this.messages))
|
|
679
|
+
], width);
|
|
530
680
|
return [
|
|
531
|
-
...
|
|
681
|
+
...centerLogo(viewport, this.messages),
|
|
532
682
|
"",
|
|
533
|
-
...centerBlock(
|
|
683
|
+
...centerBlock(main, viewport),
|
|
534
684
|
""
|
|
535
685
|
];
|
|
536
686
|
}
|
|
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
687
|
promptBlock(title, agent) {
|
|
548
688
|
const viewport = viewportWidth();
|
|
549
689
|
const width = this.width();
|
|
@@ -601,13 +741,7 @@ function formatAgents(options, agents) {
|
|
|
601
741
|
return `${options.agentA} <-> ${options.agentB}`;
|
|
602
742
|
}
|
|
603
743
|
function formatAgent(agent) {
|
|
604
|
-
return agent ? `${agentLabel(agent.name)} (${agent.role}
|
|
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
|
-
: [];
|
|
744
|
+
return agent ? `${agentLabel(agent.name)} (${agent.role})` : "?";
|
|
611
745
|
}
|
|
612
746
|
function formatSummary(options, messages) {
|
|
613
747
|
if (!options.summaryEnabled) {
|
|
@@ -624,6 +758,9 @@ function formatSummary(options, messages) {
|
|
|
624
758
|
function formatResponseCount(options) {
|
|
625
759
|
return options.mode === "ask" ? options.askAgents?.length ?? 2 : options.turns;
|
|
626
760
|
}
|
|
761
|
+
function formatSessionProgress(options, messages) {
|
|
762
|
+
return `${messages.tui.historyCount(options.mode)}: ${formatResponseCount(options)} | ${messages.tui.summary}: ${formatSummary(options, messages)}`;
|
|
763
|
+
}
|
|
627
764
|
function formatContext(options, messages) {
|
|
628
765
|
return options.files.length === 0
|
|
629
766
|
? messages.renderers.noInjectedFiles
|
|
@@ -637,7 +774,9 @@ function formatFailureLocation(failure, messages) {
|
|
|
637
774
|
return `${failure.agent ?? "?"} (${failure.role ?? "?"}${turn})`;
|
|
638
775
|
}
|
|
639
776
|
function stripAnsi(value) {
|
|
640
|
-
return value
|
|
777
|
+
return value
|
|
778
|
+
.replace(/\u001b\][^\u001b]*(?:\u0007|\u001b\\)/g, "")
|
|
779
|
+
.replace(/\u001b\[[0-9;?]*[A-Za-z]/g, "");
|
|
641
780
|
}
|
|
642
781
|
function clearScreen() {
|
|
643
782
|
process.stdout.write("\u001bc\u001b[?25h");
|
|
@@ -649,18 +788,18 @@ function viewportWidth() {
|
|
|
649
788
|
return Math.max(72, Math.min(process.stdout.columns || 100, 180));
|
|
650
789
|
}
|
|
651
790
|
function tuiPrompt(mode, labelPrefix, messages, notice) {
|
|
652
|
-
const label =
|
|
791
|
+
const label = promptTrail(mode, labelPrefix, messages);
|
|
653
792
|
const padding = surfacePadding();
|
|
654
|
-
const promptLine = `${padding}${
|
|
793
|
+
const promptLine = `${padding}${label} ${dim(">")} `;
|
|
655
794
|
return [
|
|
656
795
|
"",
|
|
657
796
|
promptRuleLine(),
|
|
658
797
|
...(notice ? [
|
|
659
|
-
`${padding}${
|
|
798
|
+
`${padding}${label} ${dim(">")}`,
|
|
660
799
|
...promptNoticeLines(notice),
|
|
661
800
|
""
|
|
662
801
|
] : []),
|
|
663
|
-
promptLine
|
|
802
|
+
promptLine,
|
|
664
803
|
].join("\n");
|
|
665
804
|
}
|
|
666
805
|
function promptRuleLine() {
|
|
@@ -680,6 +819,13 @@ function surfacePadding() {
|
|
|
680
819
|
function promptModeLabel(mode, messages) {
|
|
681
820
|
return `Mode ${messages.tui.modeValue(mode).toLowerCase()}`;
|
|
682
821
|
}
|
|
822
|
+
function promptTrail(mode, labelPrefix, messages) {
|
|
823
|
+
const parts = [bold("Palabre"), accent(promptModeLabel(mode, messages))];
|
|
824
|
+
if (labelPrefix !== messages.tui.subject) {
|
|
825
|
+
parts.push(bold(labelPrefix));
|
|
826
|
+
}
|
|
827
|
+
return parts.join(` ${dim(">")} `);
|
|
828
|
+
}
|
|
683
829
|
function messagesModeLabel(messages, mode) {
|
|
684
830
|
return messages.tui.modeValue(mode);
|
|
685
831
|
}
|
|
@@ -691,6 +837,25 @@ function compactPath(value, maxLength) {
|
|
|
691
837
|
const tailLength = Math.max(12, maxLength - marker.length);
|
|
692
838
|
return `${marker}${value.slice(-tailLength)}`;
|
|
693
839
|
}
|
|
840
|
+
function dirnamePortable(value) {
|
|
841
|
+
const separatorIndex = Math.max(value.lastIndexOf("/"), value.lastIndexOf("\\"));
|
|
842
|
+
return separatorIndex > 0 ? value.slice(0, separatorIndex) : path.dirname(value);
|
|
843
|
+
}
|
|
844
|
+
function compactFileName(value, maxLength) {
|
|
845
|
+
if (value.length <= maxLength) {
|
|
846
|
+
return value;
|
|
847
|
+
}
|
|
848
|
+
const extension = value.match(/\.(debate|ask)\.md$/i)?.[0] ?? "";
|
|
849
|
+
const marker = "...";
|
|
850
|
+
const headLength = Math.max(12, maxLength - marker.length - extension.length);
|
|
851
|
+
return `${value.slice(0, headLength)}${marker}${extension}`;
|
|
852
|
+
}
|
|
853
|
+
function terminalLink(filePath, label) {
|
|
854
|
+
if (!supportsInteractiveOutput) {
|
|
855
|
+
return label;
|
|
856
|
+
}
|
|
857
|
+
return `\u001b]8;;${pathToFileURL(filePath).href}\u001b\\${label}\u001b]8;;\u001b\\`;
|
|
858
|
+
}
|
|
694
859
|
function roleFor(config, agent, messages) {
|
|
695
860
|
return config.agents[agent]?.role ?? messages.tui.noValue;
|
|
696
861
|
}
|
|
@@ -709,16 +874,21 @@ function activeAgentNamesForMode(config, mode) {
|
|
|
709
874
|
const agents = defaults.askAgents && defaults.askAgents.length > 0
|
|
710
875
|
? defaults.askAgents
|
|
711
876
|
: [defaults.agentA, defaults.agentB].filter((agent) => Boolean(agent));
|
|
712
|
-
return agents.filter((agent) => Boolean(config.agents[agent]));
|
|
877
|
+
return agents.filter((agent) => Boolean(config.agents[agent]) && !isRetiredAgentName(agent));
|
|
713
878
|
}
|
|
714
|
-
return [defaults.agentA, defaults.agentB].filter((agent) =>
|
|
879
|
+
return [defaults.agentA, defaults.agentB].filter((agent) => typeof agent === "string" && Boolean(config.agents[agent]) && !isRetiredAgentName(agent));
|
|
715
880
|
}
|
|
716
881
|
function agentInventoryLine(config, messages) {
|
|
717
|
-
const agents = Object.
|
|
882
|
+
const agents = Object.entries(config.agents)
|
|
883
|
+
.filter(([name]) => !isRetiredAgentName(name))
|
|
884
|
+
.map(([name]) => name)
|
|
885
|
+
.sort();
|
|
718
886
|
return agents.length > 0 ? agents.map(agentLabel).join(", ") : messages.tui.noValue;
|
|
719
887
|
}
|
|
720
888
|
function agentInventoryRows(config, messages) {
|
|
721
|
-
const entries = Object.entries(config.agents)
|
|
889
|
+
const entries = Object.entries(config.agents)
|
|
890
|
+
.filter(([name]) => !isRetiredAgentName(name))
|
|
891
|
+
.sort(([agentA], [agentB]) => agentA.localeCompare(agentB));
|
|
722
892
|
if (entries.length === 0) {
|
|
723
893
|
return [dim(messages.tui.noConfiguredAgents)];
|
|
724
894
|
}
|
|
@@ -729,7 +899,7 @@ function exampleAgentsForMode(config, mode) {
|
|
|
729
899
|
if (activeAgents.length > 0) {
|
|
730
900
|
return activeAgents;
|
|
731
901
|
}
|
|
732
|
-
const available = Object.keys(config.agents).sort();
|
|
902
|
+
const available = Object.keys(config.agents).filter((agent) => !isRetiredAgentName(agent)).sort();
|
|
733
903
|
return mode === "ask" ? available.slice(0, 3) : available.slice(0, 2);
|
|
734
904
|
}
|
|
735
905
|
function documentationUrl(config) {
|
|
@@ -786,9 +956,8 @@ function centerLine(line, width) {
|
|
|
786
956
|
return `${" ".repeat(left)}${line}`;
|
|
787
957
|
}
|
|
788
958
|
function composerInputBox(mode, labelPrefix, width, messages) {
|
|
789
|
-
const label = promptModeLabel(mode, messages);
|
|
790
959
|
return composerCard([
|
|
791
|
-
`${
|
|
960
|
+
`${promptTrail(mode, labelPrefix, messages)} ${dim(">")}`
|
|
792
961
|
], width, "center");
|
|
793
962
|
}
|
|
794
963
|
function panel(lines, width) {
|
|
@@ -863,9 +1032,6 @@ function accent(value) {
|
|
|
863
1032
|
function violet(value) {
|
|
864
1033
|
return supportsColor ? `${codes.violet}${value}${codes.reset}` : value;
|
|
865
1034
|
}
|
|
866
|
-
function orange(value) {
|
|
867
|
-
return supportsColor ? `${codes.orange}${value}${codes.reset}` : value;
|
|
868
|
-
}
|
|
869
1035
|
function muted(value) {
|
|
870
1036
|
return supportsColor ? `${codes.gray}${value}${codes.reset}` : value;
|
|
871
1037
|
}
|
|
@@ -909,7 +1075,6 @@ function hslToRgb(hue, saturation, lightness) {
|
|
|
909
1075
|
const agentColors = {
|
|
910
1076
|
antigravity: [76, 141, 255],
|
|
911
1077
|
claude: [222, 115, 86],
|
|
912
|
-
gemini: [71, 150, 227],
|
|
913
1078
|
codex: [136, 82, 197],
|
|
914
1079
|
opencode: [80, 168, 103],
|
|
915
1080
|
vibe: [234, 92, 126],
|
package/dist/tuiState.js
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
const TUI_RUN_OVERRIDE_FLAGS = [
|
|
2
|
+
"preset",
|
|
3
|
+
"agent-a",
|
|
4
|
+
"agent-b",
|
|
5
|
+
"agents",
|
|
6
|
+
"model-a",
|
|
7
|
+
"ollama-url",
|
|
8
|
+
"model-b",
|
|
9
|
+
"summary-agent",
|
|
10
|
+
"summary-model",
|
|
11
|
+
"turns",
|
|
12
|
+
"files",
|
|
13
|
+
"context",
|
|
14
|
+
"no-summary",
|
|
15
|
+
"no-early-stop",
|
|
16
|
+
"pull-models",
|
|
17
|
+
"show-prompt",
|
|
18
|
+
"plain",
|
|
19
|
+
"terminal",
|
|
20
|
+
"json"
|
|
21
|
+
];
|
|
22
|
+
export function clearTuiRunOverrides(flags) {
|
|
23
|
+
for (const flag of TUI_RUN_OVERRIDE_FLAGS) {
|
|
24
|
+
delete flags[flag];
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
export function askAgentSeedsForMode(mode, explicitAskAgents, defaultAskAgents) {
|
|
28
|
+
if (mode !== "ask") {
|
|
29
|
+
return [];
|
|
30
|
+
}
|
|
31
|
+
return explicitAskAgents.length > 0 ? explicitAskAgents : defaultAskAgents ?? [];
|
|
32
|
+
}
|
package/package.json
CHANGED
|
@@ -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",
|