palabre 0.6.4 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/config.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { access, mkdir, readFile, writeFile } from "node:fs/promises";
2
2
  import os from "node:os";
3
3
  import path from "node:path";
4
- import { applyDetectedCommands } from "./agentRegistry.js";
4
+ import { applyDetectedCommands, detectedAgentNames } from "./agentRegistry.js";
5
5
  export const DEFAULT_CONFIG_PATH = "palabre.config.json";
6
6
  export const LEGACY_CONFIG_PATH = "chicane.config.json";
7
7
  export const CONFIG_DIR_NAME = ".palabre";
@@ -13,9 +13,13 @@ export const exampleConfig = {
13
13
  language: "fr",
14
14
  outputDir: DEFAULT_OUTPUT_DIR,
15
15
  defaults: {
16
+ interface: "tui",
17
+ mode: "debate",
16
18
  agentA: "codex",
17
19
  agentB: "claude",
20
+ askAgents: ["codex", "claude"],
18
21
  summaryAgent: "claude",
22
+ askSummaryAgent: "claude",
19
23
  turns: 4
20
24
  },
21
25
  agents: {
@@ -92,6 +96,23 @@ export const exampleConfig = {
92
96
  role: "reviewer",
93
97
  tier: "primary"
94
98
  },
99
+ vibe: {
100
+ type: "cli",
101
+ command: "vibe",
102
+ args: [
103
+ "--output",
104
+ "text",
105
+ "--agent",
106
+ "plan",
107
+ "--trust",
108
+ "--prompt"
109
+ ],
110
+ promptMode: "argument",
111
+ modelArg: "--model",
112
+ shell: process.platform === "win32",
113
+ role: "reviewer",
114
+ tier: "primary"
115
+ },
95
116
  "ollama-local": {
96
117
  type: "ollama",
97
118
  baseUrl: "http://localhost:11434",
@@ -189,13 +210,62 @@ export function createConfigFromDiscovery(discovery) {
189
210
  config.defaults = pair
190
211
  ? {
191
212
  ...config.defaults,
213
+ interface: config.defaults?.interface ?? "tui",
214
+ mode: config.defaults?.mode ?? "debate",
192
215
  agentA: pair[0],
193
216
  agentB: pair[1],
194
- summaryAgent: chooseDefaultSummaryAgent(pair)
217
+ askAgents: pair,
218
+ summaryAgent: chooseDefaultSummaryAgent(pair),
219
+ askSummaryAgent: chooseDefaultSummaryAgent(pair)
195
220
  }
196
- : { turns: config.defaults?.turns };
221
+ : {
222
+ interface: config.defaults?.interface ?? "tui",
223
+ mode: config.defaults?.mode ?? "debate",
224
+ turns: config.defaults?.turns,
225
+ askAgents: detectedAgentNames(discovery).slice(0, 2)
226
+ };
197
227
  return config;
198
228
  }
229
+ /**
230
+ * Ajoute dans `config.agents` les agents détectés localement mais absents de la config.
231
+ * Mute `config` directement ; l'appelant est responsable de persister la config.
232
+ */
233
+ export function syncDetectedAgents(config, discovery) {
234
+ const discoveredConfig = createConfigFromDiscovery(discovery);
235
+ const missingAgents = detectedAgentNames(discovery).filter((agentName) => !config.agents[agentName]);
236
+ applyDetectedCommands(config, discovery);
237
+ for (const agentName of missingAgents) {
238
+ config.agents[agentName] = discoveredConfig.agents[agentName];
239
+ }
240
+ return missingAgents;
241
+ }
242
+ export function syncOllamaModel(config, discovery) {
243
+ const agent = config.agents["ollama-local"];
244
+ if (agent?.type !== "ollama" || discovery.ollama.models.length === 0) {
245
+ return undefined;
246
+ }
247
+ if (discovery.ollama.models.includes(agent.model)) {
248
+ return undefined;
249
+ }
250
+ const previousModel = agent.model;
251
+ agent.model = chooseDefaultOllamaModel(discovery);
252
+ return {
253
+ previousModel,
254
+ nextModel: agent.model
255
+ };
256
+ }
257
+ export function setOllamaModel(config, model) {
258
+ const agent = config.agents["ollama-local"];
259
+ if (agent?.type !== "ollama") {
260
+ return undefined;
261
+ }
262
+ const previousModel = agent.model;
263
+ agent.model = model;
264
+ return {
265
+ previousModel,
266
+ nextModel: agent.model
267
+ };
268
+ }
199
269
  /** Écrit `config` sérialisé en JSON dans `configPath`. Crée le répertoire parent si nécessaire. */
200
270
  export async function writeExampleConfig(configPath = DEFAULT_CONFIG_PATH, config = exampleConfig) {
201
271
  const resolved = path.resolve(configPath);
@@ -209,7 +279,7 @@ function chooseDefaultOllamaModel(discovery) {
209
279
  return discovery.ollama.models[0] ?? DEFAULT_OLLAMA_MODEL;
210
280
  }
211
281
  function chooseDefaultSummaryAgent(pair) {
212
- for (const preferred of ["claude", "codex", "antigravity", "gemini"]) {
282
+ for (const preferred of ["claude", "codex", "antigravity", "vibe", "gemini"]) {
213
283
  if (pair.includes(preferred)) {
214
284
  return preferred;
215
285
  }
@@ -229,6 +299,9 @@ function chooseDefaultPair(discovery) {
229
299
  if (discovery.opencode.available && discovery.ollama.available) {
230
300
  return ["opencode", "ollama-local"];
231
301
  }
302
+ if (discovery.vibe.available && discovery.ollama.available) {
303
+ return ["vibe", "ollama-local"];
304
+ }
232
305
  if (discovery.antigravity.available && discovery.ollama.available) {
233
306
  return ["antigravity", "ollama-local"];
234
307
  }
@@ -240,6 +313,7 @@ function chooseDefaultPair(discovery) {
240
313
  discovery.claude.available ? "claude" : undefined,
241
314
  discovery.antigravity.available ? "antigravity" : undefined,
242
315
  discovery.opencode.available ? "opencode" : undefined,
316
+ discovery.vibe.available ? "vibe" : undefined,
243
317
  discovery.gemini.available ? "gemini" : undefined
244
318
  ].filter((agent) => Boolean(agent));
245
319
  if (cliAgents.length >= 2) {
@@ -1,6 +1,7 @@
1
1
  import { createInterface } from "node:readline/promises";
2
2
  import { stdin as input, stdout as output } from "node:process";
3
- import { writeExampleConfig } from "./config.js";
3
+ import { syncDetectedAgents, writeExampleConfig } from "./config.js";
4
+ import { discoverLocalTools } from "./discovery.js";
4
5
  import { DEFAULT_TURNS, MAX_TURNS, turnsOrDefault, validateTurns } from "./limits.js";
5
6
  /**
6
7
  * Lance le wizard interactif de configuration des defaults.
@@ -26,9 +27,10 @@ export async function runConfigWizard(configPath, config, messages) {
26
27
  console.log(messages.config.wizardActionQuestion);
27
28
  console.log(` 1) ${messages.config.wizardActionSetDefaults}`);
28
29
  console.log(` 2) ${messages.config.wizardActionClearDefaults}`);
29
- console.log(` 3) ${messages.config.wizardActionExit}`);
30
- const action = await askChoice(rl, messages.config.wizardChoicePrompt, "1", ["1", "2", "3"], messages);
31
- if (!action || action === "3") {
30
+ console.log(` 3) ${messages.config.wizardActionSyncAgents}`);
31
+ console.log(` 4) ${messages.config.wizardActionExit}`);
32
+ const action = await askChoice(rl, messages.config.wizardChoicePrompt, "1", ["1", "2", "3", "4"], messages);
33
+ if (!action || action === "4") {
32
34
  console.log(messages.config.wizardUnchanged);
33
35
  return;
34
36
  }
@@ -38,6 +40,17 @@ export async function runConfigWizard(configPath, config, messages) {
38
40
  console.log(messages.config.wizardCleared(configPath));
39
41
  return;
40
42
  }
43
+ if (action === "3") {
44
+ const discovery = await discoverLocalTools();
45
+ const addedAgents = syncDetectedAgents(config, discovery);
46
+ if (addedAgents.length === 0) {
47
+ console.log(messages.config.syncNoMissing(configPath));
48
+ return;
49
+ }
50
+ await writeExampleConfig(configPath, config);
51
+ console.log(messages.config.syncAdded(configPath, addedAgents.join(", ")));
52
+ return;
53
+ }
41
54
  const agentA = await askAgent(rl, choices, messages.config.wizardAgentADescription, config.defaults?.agentA, messages);
42
55
  if (!agentA)
43
56
  return;
@@ -51,11 +64,17 @@ export async function runConfigWizard(configPath, config, messages) {
51
64
  if (summaryAgent === undefined)
52
65
  return;
53
66
  config.defaults = {
67
+ ...(config.defaults ?? {}),
54
68
  agentA,
55
69
  agentB,
56
- ...(summaryAgent ? { summaryAgent } : {}),
57
70
  turns
58
71
  };
72
+ if (summaryAgent) {
73
+ config.defaults.summaryAgent = summaryAgent;
74
+ }
75
+ else {
76
+ delete config.defaults.summaryAgent;
77
+ }
59
78
  await writeExampleConfig(configPath, config);
60
79
  console.log(messages.config.wizardDefaultsSet(configPath, formatDefaults(config.defaults, messages)));
61
80
  }
@@ -192,8 +211,12 @@ function formatDefaults(defaults, messages) {
192
211
  return messages.config.wizardDefaults({
193
212
  agentA: defaults.agentA,
194
213
  agentB: defaults.agentB,
214
+ mode: defaults.mode,
215
+ interfaceName: defaults.interface,
216
+ askAgents: defaults.askAgents,
195
217
  turns: turnsOrDefault(defaults.turns ?? DEFAULT_TURNS),
196
- summaryAgent: defaults.summaryAgent
218
+ summaryAgent: defaults.summaryAgent,
219
+ askSummaryAgent: defaults.askSummaryAgent
197
220
  });
198
221
  }
199
222
  function isQuit(value) {
package/dist/discovery.js CHANGED
@@ -7,12 +7,13 @@ import { executableExtensions } from "./exec.js";
7
7
  * Antigravity est exposé selon les installations sous `agy` ou `antigravity`.
8
8
  */
9
9
  export async function discoverLocalTools() {
10
- const [codex, claude, gemini, antigravity, opencode, ollamaCommand] = await Promise.all([
10
+ const [codex, claude, gemini, antigravity, opencode, vibe, ollamaCommand] = await Promise.all([
11
11
  detectCommand("codex"),
12
12
  detectFirstCommand(process.platform === "win32" ? ["claude.exe", "claude"] : ["claude"]),
13
13
  detectCommand("gemini"),
14
14
  detectFirstCommand(["agy", "antigravity"]),
15
15
  detectCommand("opencode"),
16
+ detectCommand("vibe"),
16
17
  detectCommand("ollama")
17
18
  ]);
18
19
  const ollamaServer = await detectOllamaServer();
@@ -22,6 +23,7 @@ export async function discoverLocalTools() {
22
23
  gemini,
23
24
  antigravity,
24
25
  opencode,
26
+ vibe,
25
27
  ollama: {
26
28
  ...ollamaServer,
27
29
  commandAvailable: ollamaCommand.available
package/dist/doctor.js CHANGED
@@ -5,6 +5,7 @@ import { detectedAgentNames, detectionForCommand } from "./agentRegistry.js";
5
5
  import { discoverLocalTools } from "./discovery.js";
6
6
  import { createTranslator, resolveLanguage } from "./i18n.js";
7
7
  import { DEFAULT_TURNS, MAX_TURNS } from "./limits.js";
8
+ import { compareSemver, getLatestPackageVersion, getPackageVersion } from "./version.js";
8
9
  /**
9
10
  * Exécute le diagnostic complet : config, outils locaux et agents.
10
11
  * Retourne toujours un résultat (pas de throw) ; les erreurs de config sont reportées comme lignes `error`.
@@ -20,6 +21,7 @@ export async function runDoctor(explicitConfigPath, plain = false, explicitLangu
20
21
  });
21
22
  const t = createTranslator(language);
22
23
  lines.push(info(t.doctor.title, "title"));
24
+ await inspectCliVersion(lines, t);
23
25
  lines.push(info(t.doctor.currentDirectory(process.cwd()), "cwd"));
24
26
  lines.push(hasConfig
25
27
  ? ok(t.doctor.configFound(configPath))
@@ -44,6 +46,7 @@ export async function runDoctor(explicitConfigPath, plain = false, explicitLangu
44
46
  lines.push(formatCommand("Gemini CLI", discovery.gemini.available, discovery.gemini.command, discovery.gemini.path, t));
45
47
  lines.push(formatCommand("Antigravity CLI", discovery.antigravity.available, discovery.antigravity.command, discovery.antigravity.path, t));
46
48
  lines.push(formatCommand("OpenCode CLI", discovery.opencode.available, discovery.opencode.command, discovery.opencode.path, t));
49
+ lines.push(formatCommand("Mistral Vibe CLI", discovery.vibe.available, discovery.vibe.command, discovery.vibe.path, t));
47
50
  lines.push(discovery.ollama.available
48
51
  ? ok(t.doctor.ollamaReachable(discovery.ollama.baseUrl, discovery.ollama.models.length))
49
52
  : warn(discovery.ollama.commandAvailable
@@ -53,6 +56,18 @@ export async function runDoctor(explicitConfigPath, plain = false, explicitLangu
53
56
  inspectAgents(config, discovery, lines, t);
54
57
  return render(lines, plain, t);
55
58
  }
59
+ async function inspectCliVersion(lines, t) {
60
+ const currentVersion = await getPackageVersion();
61
+ lines.push(info(t.doctor.cliVersion(currentVersion)));
62
+ const latestVersion = await getLatestPackageVersion();
63
+ if (!latestVersion) {
64
+ lines.push(info(t.doctor.updateUnknown));
65
+ return;
66
+ }
67
+ lines.push(compareSemver(currentVersion, latestVersion) < 0
68
+ ? warn(t.doctor.updateAvailable(currentVersion, latestVersion))
69
+ : ok(t.doctor.updateCurrent(latestVersion)));
70
+ }
56
71
  async function loadConfigSafely(configPath) {
57
72
  try {
58
73
  return await loadConfig(configPath);
@@ -91,6 +106,9 @@ async function inspectConfig(config, lines, t) {
91
106
  else {
92
107
  lines.push(warn(t.doctor.summaryAgentMissing));
93
108
  }
109
+ if (config.defaults?.askSummaryAgent) {
110
+ inspectDefaultAgent("defaults.askSummaryAgent", config.defaults.askSummaryAgent, config, lines, t);
111
+ }
94
112
  await inspectOutputDir(config.outputDir, lines, t);
95
113
  }
96
114
  function inspectDefaultAgent(label, agentName, config, lines, t) {