palabre 0.9.0 → 0.10.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.
Files changed (53) hide show
  1. package/README.md +2 -0
  2. package/dist/adapters/cli-pty.js +30 -10
  3. package/dist/adapters/cli-shared.js +73 -0
  4. package/dist/adapters/cli.js +40 -77
  5. package/dist/adapters/index.js +1 -0
  6. package/dist/adapters/ollama.js +32 -32
  7. package/dist/adapters/terminal.js +1 -0
  8. package/dist/args.js +1 -0
  9. package/dist/commands/agents.js +91 -0
  10. package/dist/commands/context.js +31 -0
  11. package/dist/commands/history.js +33 -0
  12. package/dist/commands/init.js +64 -0
  13. package/dist/commands/presets.js +39 -0
  14. package/dist/commands/shared.js +8 -0
  15. package/dist/commands/update.js +26 -0
  16. package/dist/config.js +17 -1
  17. package/dist/configWizard.js +5 -4
  18. package/dist/context.js +1 -0
  19. package/dist/contextScan.js +4 -3
  20. package/dist/discovery.js +9 -1
  21. package/dist/doctor.js +1 -0
  22. package/dist/errors.js +4 -0
  23. package/dist/exec.js +1 -0
  24. package/dist/history.js +10 -0
  25. package/dist/i18n.js +2 -0
  26. package/dist/index.js +174 -879
  27. package/dist/limits.js +5 -0
  28. package/dist/messages/adapter-errors.js +26 -2
  29. package/dist/messages/config.js +6 -0
  30. package/dist/messages/index.js +1 -0
  31. package/dist/messages/renderers.js +10 -2
  32. package/dist/messages/tui.js +8 -2
  33. package/dist/new.js +1 -0
  34. package/dist/ollamaUrl.js +20 -0
  35. package/dist/orchestrator.js +106 -161
  36. package/dist/output.js +2 -10
  37. package/dist/presets.js +1 -0
  38. package/dist/prompt.js +1 -0
  39. package/dist/renderers/console.js +2 -8
  40. package/dist/renderers/ndjson.js +1 -10
  41. package/dist/renderers/tui-prompts.js +339 -0
  42. package/dist/renderers/tui-renderer.js +224 -0
  43. package/dist/renderers/tui-screens.js +352 -0
  44. package/dist/renderers/tui-theme.js +356 -0
  45. package/dist/renderers/tui.js +7 -1095
  46. package/dist/runOptions.js +97 -0
  47. package/dist/session.js +1 -0
  48. package/dist/tuiController.js +445 -0
  49. package/dist/tuiState.js +4 -0
  50. package/dist/types.js +1 -0
  51. package/dist/update.js +1 -0
  52. package/dist/version.js +1 -0
  53. package/package.json +3 -2
@@ -0,0 +1,91 @@
1
+ /** @file Commande palabre agents et contrat JSON v1 pour les integrations. */
2
+ import { configExists, loadConfig, resolveDefaultConfigPath } from "../config.js";
3
+ import { discoverLocalToolsForConfig } from "../discovery.js";
4
+ import { createTranslator, resolveLanguage } from "../i18n.js";
5
+ import { turnsOrDefault } from "../limits.js";
6
+ import { listAgentsWithAvailability } from "../presets.js";
7
+ import { detectionForCommand, isRetiredAgentName } from "../agentRegistry.js";
8
+ import { optionalString } from "./shared.js";
9
+ /**
10
+ * Liste les agents configurés avec leur disponibilité calculée par le CLI.
11
+ * @param flags - Flags de langue, config, URL Ollama et format JSON.
12
+ * @returns Une promesse résolue après écriture de la sortie.
13
+ * @throws {Error} Si aucune configuration n'est disponible.
14
+ */
15
+ export async function runAgentsCommand(flags) {
16
+ const configPath = optionalString(flags.config) ?? await resolveDefaultConfigPath();
17
+ if (!(await configExists(configPath))) {
18
+ const messages = createTranslator(resolveLanguage({ explicitLanguage: optionalString(flags.language) }));
19
+ throw new Error(messages.agents.noConfig);
20
+ }
21
+ const config = await loadConfig(configPath);
22
+ const messages = createTranslator(resolveLanguage({
23
+ explicitLanguage: optionalString(flags.language),
24
+ configLanguage: config.language
25
+ }));
26
+ const discovery = await discoverLocalToolsForConfig(config, optionalString(flags["ollama-url"]));
27
+ if (flags.json) {
28
+ const fallbackAskAgents = [config.defaults?.agentA, config.defaults?.agentB]
29
+ .filter((name) => typeof name === "string" && !isRetiredAgentName(name));
30
+ process.stdout.write(JSON.stringify({
31
+ v: 1,
32
+ agents: listAgentsWithAvailability(config, discovery, messages),
33
+ defaults: {
34
+ askAgents: config.defaults?.askAgents?.length
35
+ ? config.defaults.askAgents.filter((name) => !isRetiredAgentName(name))
36
+ : fallbackAskAgents
37
+ }
38
+ }) + "\n");
39
+ return;
40
+ }
41
+ printAgents(configPath, config, discovery, messages);
42
+ }
43
+ function printAgents(configPath, config, discovery, messages) {
44
+ const entries = Object.entries(config.agents)
45
+ .filter(([name]) => !isRetiredAgentName(name))
46
+ .sort(([left], [right]) => left.localeCompare(right));
47
+ console.log(messages.agents.config(configPath));
48
+ console.log("");
49
+ console.log(messages.agents.title);
50
+ for (const [name, agentConfig] of entries) {
51
+ const status = formatAgentDetection(name, agentConfig, discovery, messages);
52
+ const defaults = formatAgentDefaults(name, config, messages);
53
+ const details = formatAgentDetails(agentConfig, messages);
54
+ console.log(`- ${name.padEnd(13)} ${`${agentConfig.type}/${agentConfig.role}`.padEnd(18)} ${status}${defaults ? ` | ${defaults}` : ""}`);
55
+ if (details)
56
+ console.log(` ${details}`);
57
+ }
58
+ console.log("");
59
+ 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));
60
+ }
61
+ function formatAgentDefaults(name, config, messages) {
62
+ const labels = [];
63
+ if (config.defaults?.agentA === name)
64
+ labels.push(messages.agents.defaultAgentA);
65
+ if (config.defaults?.agentB === name)
66
+ labels.push(messages.agents.defaultAgentB);
67
+ if (config.defaults?.summaryAgent === name)
68
+ labels.push(messages.agents.defaultSummary);
69
+ if (config.defaults?.askSummaryAgent === name)
70
+ labels.push(messages.agents.defaultAskSummary);
71
+ return labels.join(", ");
72
+ }
73
+ function formatAgentDetails(agentConfig, messages) {
74
+ return agentConfig.type === "ollama"
75
+ ? messages.agents.model(agentConfig.model)
76
+ : messages.agents.command(agentConfig.command, agentConfig.model);
77
+ }
78
+ function formatAgentDetection(name, agentConfig, discovery, messages) {
79
+ if (agentConfig.type === "ollama") {
80
+ const ollama = discovery.ollama;
81
+ if (!ollama.available)
82
+ return ollama.commandAvailable ? messages.agents.ollamaUnreachable : messages.agents.ollamaNotDetected;
83
+ return ollama.models.includes(agentConfig.model) ? messages.agents.detected() : messages.agents.missingModel(agentConfig.model);
84
+ }
85
+ const detection = cliDetectionForAgent(name, agentConfig, discovery);
86
+ return detection.available ? messages.agents.detected(detection.command) : messages.agents.notDetected;
87
+ }
88
+ function cliDetectionForAgent(name, agentConfig, discovery) {
89
+ const command = agentConfig.type === "cli" || agentConfig.type === "cli-pty" ? agentConfig.command : name;
90
+ return detectionForCommand(command, discovery) ?? { available: true, command };
91
+ }
@@ -0,0 +1,31 @@
1
+ /** @file Commande palabre context scan et rendu de son contrat versionne. */
2
+ import { buildContextScan } from "../contextScan.js";
3
+ import { createTranslator, resolveLanguage } from "../i18n.js";
4
+ import { optionalString } from "./shared.js";
5
+ /**
6
+ * Scanne les chemins demandés avec les mêmes règles que `--context`.
7
+ * @param flags - Flags de langue et de format JSON.
8
+ * @param positionals - Sous-commande puis chemins à scanner.
9
+ * @returns Une promesse résolue après écriture du résultat et des warnings.
10
+ */
11
+ export async function runContextCommand(flags, positionals) {
12
+ const messages = createTranslator(resolveLanguage({ explicitLanguage: optionalString(flags.language) }));
13
+ const subcommand = positionals[0] ?? "scan";
14
+ if (subcommand !== "scan") {
15
+ throw new Error(messages.common.unknownCommand(`context ${subcommand}`, "context scan"));
16
+ }
17
+ const result = await buildContextScan(positionals.slice(1), process.cwd(), messages);
18
+ if (flags.json) {
19
+ console.log(JSON.stringify(result, null, 2));
20
+ return;
21
+ }
22
+ for (const folder of result.items.filter((item) => item.kind === "folder")) {
23
+ console.log(`[folder] ${folder.path}`);
24
+ }
25
+ for (const file of result.items.filter((item) => item.kind === "file")) {
26
+ console.log(`[file] ${file.path} (${file.sizeBytes} bytes)`);
27
+ }
28
+ for (const warning of result.warnings) {
29
+ console.error(`${messages.renderers.warningPrefix} ${warning}`);
30
+ }
31
+ }
@@ -0,0 +1,33 @@
1
+ /** @file Commande de consultation des exports Markdown recents. */
2
+ import { configExists, loadConfig, resolveDefaultConfigPath, resolveOutputDir } from "../config.js";
3
+ import { listHistoryEntries } from "../history.js";
4
+ import { createTranslator, resolveLanguage } from "../i18n.js";
5
+ import { optionalString } from "./shared.js";
6
+ /**
7
+ * Liste les exports du dossier de sortie configuré.
8
+ * @param flags - Flags de config, langue et format JSON.
9
+ * @returns Une promesse résolue après écriture de l'historique.
10
+ */
11
+ export async function runHistoryCommand(flags) {
12
+ const configPath = optionalString(flags.config) ?? await resolveDefaultConfigPath();
13
+ const config = await configExists(configPath) ? await loadConfig(configPath) : undefined;
14
+ const messages = createTranslator(resolveLanguage({
15
+ explicitLanguage: optionalString(flags.language),
16
+ configLanguage: config?.language
17
+ }));
18
+ const entries = await listHistoryEntries(resolveOutputDir(config?.outputDir));
19
+ if (flags.json) {
20
+ process.stdout.write(JSON.stringify({ v: 1, history: entries }) + "\n");
21
+ return;
22
+ }
23
+ console.log(messages.tui.historyTitle);
24
+ console.log("");
25
+ if (entries.length === 0) {
26
+ console.log(messages.tui.historyEmpty);
27
+ return;
28
+ }
29
+ for (const entry of entries) {
30
+ console.log(`- ${entry.date || entry.fileName} | ${entry.mode} | ${entry.topic}`);
31
+ console.log(` ${entry.path}`);
32
+ }
33
+ }
@@ -0,0 +1,64 @@
1
+ /** @file Initialisation explicite de configuration globale ou locale. */
2
+ import { configExists, createConfigFromDiscovery, DEFAULT_CONFIG_PATH, GLOBAL_CONFIG_PATH, writeConfig } from "../config.js";
3
+ import { discoverLocalTools } from "../discovery.js";
4
+ import { detectedAgentNames } from "../agentRegistry.js";
5
+ import { createTranslator, DEFAULT_LANGUAGE, resolveLanguage } from "../i18n.js";
6
+ import { optionalString } from "./shared.js";
7
+ /**
8
+ * Crée une configuration à partir des outils détectés localement.
9
+ * @param flags - Flags de chemin, portée locale, langue et URL Ollama.
10
+ * @returns Une promesse résolue après création et affichage du récapitulatif.
11
+ */
12
+ export async function runInitCommand(flags) {
13
+ const configPath = optionalString(flags.config) ?? (flags.local ? DEFAULT_CONFIG_PATH : GLOBAL_CONFIG_PATH);
14
+ const startupMessages = createTranslator(resolveLanguage({ explicitLanguage: optionalString(flags.language) }));
15
+ if (await configExists(configPath)) {
16
+ console.log(startupMessages.init.configExists(configPath));
17
+ return;
18
+ }
19
+ const discovery = await discoverLocalTools({ ollamaUrl: optionalString(flags["ollama-url"]) });
20
+ const config = createConfigFromDiscovery(discovery);
21
+ config.language = resolveLanguage({
22
+ explicitLanguage: optionalString(flags.language),
23
+ configLanguage: config.language
24
+ });
25
+ const messages = createTranslator(config.language);
26
+ await writeConfig(configPath, config);
27
+ console.log(messages.init.configCreated(configPath));
28
+ printInitDiscovery(discovery, config, messages);
29
+ }
30
+ function printInitDiscovery(discovery, config, messages) {
31
+ console.log("");
32
+ console.log(messages.init.localDetectionTitle);
33
+ console.log(`- Codex CLI: ${formatCommandDetection(discovery.codex, messages)}`);
34
+ console.log(`- Claude CLI: ${formatCommandDetection(discovery.claude, messages)}`);
35
+ console.log(`- Antigravity CLI: ${formatCommandDetection(discovery.antigravity, messages)}`);
36
+ console.log(`- OpenCode CLI: ${formatCommandDetection(discovery.opencode, messages)}`);
37
+ console.log(`- Mistral Vibe CLI: ${formatCommandDetection(discovery.vibe, messages)}`);
38
+ console.log(`- Ollama API: ${formatOllamaDetection(discovery.ollama, messages)}`);
39
+ console.log("");
40
+ console.log(config.defaults?.agentA && config.defaults.agentB
41
+ ? messages.init.defaults(config.defaults.agentA, config.defaults.agentB)
42
+ : messages.init.noDefaultPair(formatDetectedAgentSummary(discovery, config.language ?? DEFAULT_LANGUAGE)));
43
+ console.log(messages.init.languageHint(config.language ?? DEFAULT_LANGUAGE));
44
+ }
45
+ function formatDetectedAgentSummary(discovery, language) {
46
+ const names = detectedAgentNames(discovery);
47
+ if (names.length === 0)
48
+ return language === "en" ? "no agent detected" : "aucun agent détecté";
49
+ if (names.length === 1) {
50
+ return language === "en" ? `only one agent detected (${names[0]})` : `un seul agent détecté (${names[0]})`;
51
+ }
52
+ return language === "en"
53
+ ? `no usable pair detected among ${names.join(", ")}`
54
+ : `aucune paire utilisable détectée parmi ${names.join(", ")}`;
55
+ }
56
+ function formatCommandDetection(detection, messages) {
57
+ return detection.available ? messages.init.commandDetected(detection.command) : messages.init.commandMissing;
58
+ }
59
+ function formatOllamaDetection(detection, messages) {
60
+ if (!detection.available) {
61
+ return detection.commandAvailable ? messages.init.ollamaServerUnreachable(detection.baseUrl) : messages.init.ollamaMissing;
62
+ }
63
+ return messages.init.ollamaDetected(detection.models.length);
64
+ }
@@ -0,0 +1,39 @@
1
+ /** @file Commande de decouverte des presets et de leur disponibilite. */
2
+ import { configExists, createConfigFromDiscovery, loadConfig, resolveDefaultConfigPath } from "../config.js";
3
+ import { discoverLocalTools, discoverLocalToolsForConfig } from "../discovery.js";
4
+ import { createTranslator, resolveLanguage } from "../i18n.js";
5
+ import { listPresetsWithAvailability } from "../presets.js";
6
+ import { optionalString } from "./shared.js";
7
+ /**
8
+ * Liste les presets enrichis avec la disponibilité issue de la config et de la discovery.
9
+ * @param flags - Flags de config, langue, URL Ollama et format JSON.
10
+ * @returns Une promesse résolue après écriture de la liste.
11
+ */
12
+ export async function runPresetsCommand(flags) {
13
+ const configPath = optionalString(flags.config) ?? await resolveDefaultConfigPath();
14
+ const ollamaUrl = optionalString(flags["ollama-url"]);
15
+ const config = await configExists(configPath) ? await loadConfig(configPath) : undefined;
16
+ const discovery = config
17
+ ? await discoverLocalToolsForConfig(config, ollamaUrl)
18
+ : await discoverLocalTools({ ollamaUrl });
19
+ const resolvedConfig = config ?? createConfigFromDiscovery(discovery);
20
+ const messages = createTranslator(resolveLanguage({
21
+ explicitLanguage: optionalString(flags.language),
22
+ configLanguage: resolvedConfig.language
23
+ }));
24
+ const presets = listPresetsWithAvailability(resolvedConfig, discovery, messages);
25
+ if (flags.json) {
26
+ process.stdout.write(JSON.stringify({ v: 1, presets }) + "\n");
27
+ return;
28
+ }
29
+ console.log(messages.presets.title);
30
+ console.log("");
31
+ for (const preset of presets) {
32
+ const status = preset.available
33
+ ? messages.presets.available
34
+ : messages.presets.unavailable(preset.unavailableReasons.join("; "));
35
+ console.log(` ${preset.name.padEnd(20)} ${preset.agentA} <-> ${preset.agentB} ${status}`);
36
+ }
37
+ console.log("");
38
+ console.log(messages.presets.total(presets.length));
39
+ }
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Extrait une chaîne non vide depuis une valeur de flag.
3
+ * @param value - Valeur brute produite par le parseur CLI.
4
+ * @returns La chaîne non vide, sinon `undefined`.
5
+ */
6
+ export function optionalString(value) {
7
+ return typeof value === "string" && value.trim() ? value : undefined;
8
+ }
@@ -0,0 +1,26 @@
1
+ /** @file Commande de diagnostic et application des mises a jour Palabre. */
2
+ import { configExists, loadConfig, resolveDefaultConfigPath } from "../config.js";
3
+ import { createTranslator, resolveLanguage } from "../i18n.js";
4
+ import { applySourceUpdate, formatUpdateInstructions, getUpdateInfo } from "../update.js";
5
+ import { getPackageVersion } from "../version.js";
6
+ import { optionalString } from "./shared.js";
7
+ /**
8
+ * Affiche les instructions de mise à jour ou applique le workflow d'un checkout source.
9
+ * @param flags - Flags de config, langue et application explicite.
10
+ * @returns Une promesse résolue après affichage ou mise à jour.
11
+ */
12
+ export async function runUpdateCommand(flags) {
13
+ const info = await getUpdateInfo(await getPackageVersion());
14
+ const configPath = optionalString(flags.config) ?? await resolveDefaultConfigPath();
15
+ const config = await configExists(configPath) ? await loadConfig(configPath) : undefined;
16
+ const messages = createTranslator(resolveLanguage({
17
+ explicitLanguage: optionalString(flags.language),
18
+ configLanguage: config?.language
19
+ }));
20
+ if (flags.apply) {
21
+ await applySourceUpdate(info, messages);
22
+ console.log(messages.update.upToDate);
23
+ return;
24
+ }
25
+ console.log(formatUpdateInstructions(info, messages));
26
+ }
package/dist/config.js CHANGED
@@ -1,3 +1,4 @@
1
+ /** @file Chargement, génération et validation de la config Palabre, ainsi que la synchronisation des agents/modèles Ollama détectés. */
1
2
  import { access, mkdir, readFile, writeFile } from "node:fs/promises";
2
3
  import os from "node:os";
3
4
  import path from "node:path";
@@ -234,6 +235,10 @@ function migrateVibePlanAgent(config) {
234
235
  function isLegacyVibePlanArgs(args) {
235
236
  return JSON.stringify(args) === JSON.stringify(["--output", "text", "--agent", "plan", "--trust", "--prompt"]);
236
237
  }
238
+ /**
239
+ * Variante de `syncDetectedAgents` qui indique aussi si la config a changé,
240
+ * même quand aucun agent n'a été ajouté (ex. migration d'arguments legacy).
241
+ */
237
242
  export function syncDetectedAgentsDetailed(config, discovery) {
238
243
  const before = JSON.stringify(config.agents);
239
244
  const addedAgents = syncDetectedAgents(config, discovery);
@@ -243,6 +248,12 @@ export function syncDetectedAgentsDetailed(config, discovery) {
243
248
  changed
244
249
  };
245
250
  }
251
+ /**
252
+ * Bascule le modèle de l'agent `ollama-local` vers un modèle installé si celui configuré
253
+ * ne l'est pas. Mute `config` directement.
254
+ * @returns `undefined` si l'agent n'est pas de type `ollama`, si aucun modèle n'est installé,
255
+ * ou si le modèle configuré est déjà installé.
256
+ */
246
257
  export function syncOllamaModel(config, discovery) {
247
258
  const agent = config.agents["ollama-local"];
248
259
  if (agent?.type !== "ollama" || discovery.ollama.models.length === 0) {
@@ -258,6 +269,11 @@ export function syncOllamaModel(config, discovery) {
258
269
  nextModel: agent.model
259
270
  };
260
271
  }
272
+ /**
273
+ * Force le modèle de l'agent `ollama-local` à `model`, sans vérifier qu'il est installé.
274
+ * Mute `config` directement.
275
+ * @returns `undefined` si l'agent n'est pas de type `ollama`.
276
+ */
261
277
  export function setOllamaModel(config, model) {
262
278
  const agent = config.agents["ollama-local"];
263
279
  if (agent?.type !== "ollama") {
@@ -279,7 +295,7 @@ export function setOllamaBaseUrl(config, baseUrl) {
279
295
  return agents.length;
280
296
  }
281
297
  /** Écrit `config` sérialisé en JSON dans `configPath`. Crée le répertoire parent si nécessaire. */
282
- export async function writeExampleConfig(configPath = DEFAULT_CONFIG_PATH, config = exampleConfig) {
298
+ export async function writeConfig(configPath = DEFAULT_CONFIG_PATH, config = exampleConfig) {
283
299
  const resolved = path.resolve(configPath);
284
300
  await mkdir(path.dirname(resolved), { recursive: true });
285
301
  await writeFile(resolved, `${JSON.stringify(config, null, 2)}\n`, "utf8");
@@ -1,6 +1,7 @@
1
+ /** @file Wizard interactif `palabre config` (sans sous-commande) pour éditer les defaults au clavier. */
1
2
  import { createInterface } from "node:readline/promises";
2
3
  import { stdin as input, stdout as output } from "node:process";
3
- import { syncDetectedAgents, writeExampleConfig } from "./config.js";
4
+ import { syncDetectedAgents, writeConfig } from "./config.js";
4
5
  import { discoverLocalTools } from "./discovery.js";
5
6
  import { DEFAULT_TURNS, MAX_TURNS, turnsOrDefault, validateTurns } from "./limits.js";
6
7
  /**
@@ -36,7 +37,7 @@ export async function runConfigWizard(configPath, config, messages) {
36
37
  }
37
38
  if (action === "2") {
38
39
  delete config.defaults;
39
- await writeExampleConfig(configPath, config);
40
+ await writeConfig(configPath, config);
40
41
  console.log(messages.config.wizardCleared(configPath));
41
42
  return;
42
43
  }
@@ -47,7 +48,7 @@ export async function runConfigWizard(configPath, config, messages) {
47
48
  console.log(messages.config.syncNoMissing(configPath));
48
49
  return;
49
50
  }
50
- await writeExampleConfig(configPath, config);
51
+ await writeConfig(configPath, config);
51
52
  console.log(messages.config.syncAdded(configPath, addedAgents.join(", ")));
52
53
  return;
53
54
  }
@@ -75,7 +76,7 @@ export async function runConfigWizard(configPath, config, messages) {
75
76
  else {
76
77
  delete config.defaults.summaryAgent;
77
78
  }
78
- await writeExampleConfig(configPath, config);
79
+ await writeConfig(configPath, config);
79
80
  console.log(messages.config.wizardDefaultsSet(configPath, formatDefaults(config.defaults, messages)));
80
81
  }
81
82
  finally {
package/dist/context.js CHANGED
@@ -1,3 +1,4 @@
1
+ /** @file Chargement du contexte projet : `--files` strict et `--context` tolérant avec règles `.gitignore` simplifiées. */
1
2
  import { readdir, readFile, stat } from "node:fs/promises";
2
3
  import path from "node:path";
3
4
  import { createTranslator } from "./i18n.js";
@@ -1,11 +1,12 @@
1
+ /** @file Contrat JSON v1 de `palabre context scan --json`, consommé par les intégrations. */
1
2
  import path from "node:path";
2
3
  import { loadProjectInputs } from "./context.js";
3
4
  import { createTranslator } from "./i18n.js";
4
5
  /**
5
- * Builds the machine-readable context preview used by integrations.
6
+ * Construit l'aperçu de contexte lisible par une machine, utilisé par les intégrations.
6
7
  *
7
- * The scan intentionally reuses the same tolerant loader as `--context`, so
8
- * the returned files are the files Palabre would actually inject into a debate.
8
+ * Le scan réutilise volontairement le même chargeur tolérant que `--context`, afin que
9
+ * les fichiers renvoyés soient exactement ceux que Palabre injecterait dans un débat.
9
10
  */
10
11
  export async function buildContextScan(scanPaths, cwd = process.cwd(), messages = createTranslator("fr")) {
11
12
  const effectiveScanPaths = scanPaths.length > 0 ? scanPaths : ["."];
package/dist/discovery.js CHANGED
@@ -1,7 +1,8 @@
1
+ /** @file Détection locale des CLIs agents et d'Ollama, utilisée par `init`, `doctor`, `presets` et l'accueil TUI. */
1
2
  import { access } from "node:fs/promises";
2
3
  import path from "node:path";
3
4
  import { executableExtensions } from "./exec.js";
4
- import { resolveOllamaBaseUrl } from "./ollamaUrl.js";
5
+ import { configuredOllamaTargets, resolveOllamaBaseUrl } from "./ollamaUrl.js";
5
6
  /**
6
7
  * Détecte en parallèle toutes les CLIs supportées et le serveur Ollama local.
7
8
  * Sur Windows, tente `claude.exe` avant `claude`.
@@ -134,3 +135,10 @@ async function isAccessible(filePath) {
134
135
  return false;
135
136
  }
136
137
  }
138
+ /** Détecte les outils en tenant compte de tous les serveurs Ollama configurés. */
139
+ export function discoverLocalToolsForConfig(config, ollamaUrl) {
140
+ return discoverLocalTools({
141
+ ollamaUrl,
142
+ ollamaTargets: configuredOllamaTargets(config)
143
+ });
144
+ }
package/dist/doctor.js CHANGED
@@ -1,3 +1,4 @@
1
+ /** @file Diagnostic `palabre doctor` : vérifie config, agents détectés et connectivité Ollama. */
1
2
  import path from "node:path";
2
3
  import { stat } from "node:fs/promises";
3
4
  import { configExists, loadConfig, resolveDefaultConfigPath, resolveOutputDir } from "./config.js";
package/dist/errors.js CHANGED
@@ -20,3 +20,7 @@ export function formatAdapterError(error, messages = createTranslator("fr")) {
20
20
  const hint = messages.adapterErrors.hint(error.kind);
21
21
  return hint ? `${error.message}\n${messages.adapterErrors.suggestionPrefix}: ${hint}` : error.message;
22
22
  }
23
+ /** Construit l'`AdapterError` standard d'annulation utilisateur, partagée par tous les adapters. */
24
+ export function cancelledError(adapterName) {
25
+ return new AdapterError("cancelled", adapterName, `${adapterName} cancelled by user.`);
26
+ }
package/dist/exec.js CHANGED
@@ -1,3 +1,4 @@
1
+ /** @file Résolution d'extensions exécutables partagée entre discovery et l'adapter PTY. */
1
2
  import path from "node:path";
2
3
  /**
3
4
  * Extensions exécutables candidates pour résoudre une commande dans le PATH.
package/dist/history.js CHANGED
@@ -1,6 +1,12 @@
1
+ /** @file Liste les exports Markdown récents en reparsant leur table de métadonnées, pour `palabre history` et la TUI. */
1
2
  import { readdir, readFile, stat } from "node:fs/promises";
2
3
  import path from "node:path";
4
+ /** Limite de lecture par fichier : la table de métadonnées est toujours en tête de l'export. */
3
5
  const maxHeaderBytes = 12_000;
6
+ /**
7
+ * Liste les exports les plus récents d'un dossier de sortie, triés par date de modification.
8
+ * Silencieux si `outputDir` est absent ou inaccessible : retourne `[]` sans lever.
9
+ */
4
10
  export async function listHistoryEntries(outputDir, limit = 10) {
5
11
  const resolved = path.resolve(outputDir);
6
12
  let entries;
@@ -19,6 +25,7 @@ export async function listHistoryEntries(outputDir, limit = 10) {
19
25
  .sort((left, right) => right.mtimeMs - left.mtimeMs)
20
26
  .slice(0, limit);
21
27
  }
28
+ /** Lit et parse un fichier d'export. Retourne `undefined` sur toute erreur filesystem/parsing plutôt que de lever. */
22
29
  async function readHistoryFile(filePath) {
23
30
  try {
24
31
  const [metadata, raw] = await Promise.all([
@@ -44,6 +51,7 @@ async function readHistoryFile(filePath) {
44
51
  return undefined;
45
52
  }
46
53
  }
54
+ /** Formate le compteur `x/y` adapté au mode, en tolérant les clés FR/EN de la table de métadonnées. */
47
55
  function countFromTable(mode, table) {
48
56
  if (mode === "ask") {
49
57
  const received = table["Reponses recues"] ?? table["Received responses"];
@@ -54,6 +62,7 @@ function countFromTable(mode, table) {
54
62
  const requested = table["Tours demandes"] ?? table["Requested turns"];
55
63
  return played && requested ? `${played}/${requested}` : played ?? requested ?? "";
56
64
  }
65
+ /** Extrait les paires clé/valeur de la table Markdown `| Champ | Valeur |` générée par l'export. */
57
66
  function parseMetadataTable(markdown) {
58
67
  const fields = {};
59
68
  const lines = markdown.split(/\r?\n/);
@@ -75,6 +84,7 @@ function stripMarkdown(value) {
75
84
  .replace(/`/g, "")
76
85
  .trim();
77
86
  }
87
+ /** Reconstruit un sujet lisible depuis le nom de fichier quand la table de métadonnées ne l'indique pas. */
78
88
  function topicFromFileName(fileName) {
79
89
  return fileName
80
90
  .replace(/^palabre-/, "")
package/dist/i18n.js CHANGED
@@ -1,5 +1,7 @@
1
1
  import { createTranslator } from "./messages/index.js";
2
+ /** Langue utilisée quand aucune source explicite (flag, env, config) n'en fournit une valide. */
2
3
  export const DEFAULT_LANGUAGE = "fr";
4
+ /** Langues acceptées par `parseLanguage`/`resolveLanguage`. */
3
5
  export const SUPPORTED_LANGUAGES = ["fr", "en"];
4
6
  /**
5
7
  * Valide une langue Palabre.