palabre 0.3.0 → 0.6.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 (41) hide show
  1. package/README.md +6 -4
  2. package/dist/adapters/cli-pty.js +183 -0
  3. package/dist/adapters/cli.js +6 -6
  4. package/dist/adapters/index.js +3 -0
  5. package/dist/adapters/terminal.js +13 -0
  6. package/dist/config.js +55 -8
  7. package/dist/configWizard.js +45 -40
  8. package/dist/context.js +16 -14
  9. package/dist/discovery.js +3 -1
  10. package/dist/doctor.js +147 -137
  11. package/dist/errors.js +4 -31
  12. package/dist/i18n.js +30 -0
  13. package/dist/index.js +275 -258
  14. package/dist/limits.js +11 -10
  15. package/dist/messages/adapter-errors.js +36 -0
  16. package/dist/messages/agents.js +38 -0
  17. package/dist/messages/common.js +28 -0
  18. package/dist/messages/config.js +88 -0
  19. package/dist/messages/context.js +24 -0
  20. package/dist/messages/doctor.js +126 -0
  21. package/dist/messages/help.js +280 -0
  22. package/dist/messages/index.js +38 -0
  23. package/dist/messages/init.js +30 -0
  24. package/dist/messages/limits.js +12 -0
  25. package/dist/messages/new.js +66 -0
  26. package/dist/messages/orchestrator.js +14 -0
  27. package/dist/messages/output.js +64 -0
  28. package/dist/messages/presets.js +26 -0
  29. package/dist/messages/preview.js +22 -0
  30. package/dist/messages/prompt.js +102 -0
  31. package/dist/messages/renderers.js +38 -0
  32. package/dist/messages/update.js +40 -0
  33. package/dist/new.js +46 -42
  34. package/dist/orchestrator.js +23 -18
  35. package/dist/output.js +34 -33
  36. package/dist/presets.js +122 -2
  37. package/dist/prompt.js +43 -58
  38. package/dist/renderers/console.js +33 -27
  39. package/dist/update.js +10 -21
  40. package/package.json +4 -1
  41. package/palabre.config.example.json +1 -0
package/dist/limits.js CHANGED
@@ -1,9 +1,10 @@
1
+ import { createTranslator } from "./i18n.js";
1
2
  export const DEFAULT_TURNS = 4;
2
3
  export const MAX_TURNS = 20;
3
4
  /** Convertit `value` en nombre et valide la plage [1, `MAX_TURNS`]. Lève une erreur si invalide. */
4
- export function parseTurns(value, label = "--turns") {
5
+ export function parseTurns(value, label = "--turns", messages = createTranslator("fr")) {
5
6
  const parsed = typeof value === "number" ? value : Number(value ?? DEFAULT_TURNS);
6
- validateTurns(parsed, label);
7
+ validateTurns(parsed, label, messages);
7
8
  return parsed;
8
9
  }
9
10
  /**
@@ -11,25 +12,25 @@ export function parseTurns(value, label = "--turns") {
11
12
  * (`boolean` pour un flag sans valeur, `string[]` si fourni plusieurs fois).
12
13
  * Lève une erreur si `value` est un booléen ou un tableau de longueur ≠ 1.
13
14
  */
14
- export function parseTurnsFlag(value, fallback = DEFAULT_TURNS, label = "--turns") {
15
+ export function parseTurnsFlag(value, fallback = DEFAULT_TURNS, label = "--turns", messages = createTranslator("fr")) {
15
16
  if (value === undefined) {
16
- return parseTurns(fallback, label);
17
+ return parseTurns(fallback, label, messages);
17
18
  }
18
19
  if (typeof value === "boolean") {
19
- throw new Error(`${label} attend un nombre entier entre 1 et ${MAX_TURNS}.`);
20
+ throw new Error(messages.limits.expectsInteger(label, MAX_TURNS));
20
21
  }
21
22
  if (Array.isArray(value)) {
22
23
  if (value.length !== 1) {
23
- throw new Error(`${label} doit être fourni une seule fois.`);
24
+ throw new Error(messages.limits.mustBeProvidedOnce(label));
24
25
  }
25
- return parseTurns(value[0], label);
26
+ return parseTurns(value[0], label, messages);
26
27
  }
27
- return parseTurns(value, label);
28
+ return parseTurns(value, label, messages);
28
29
  }
29
30
  /** Valide que `value` est un entier dans [1, `MAX_TURNS`]. Lève une erreur descriptive sinon. */
30
- export function validateTurns(value, label = "--turns") {
31
+ export function validateTurns(value, label = "--turns", messages = createTranslator("fr")) {
31
32
  if (!Number.isInteger(value) || value < 1 || value > MAX_TURNS) {
32
- throw new Error(`${label} doit être un nombre entier entre 1 et ${MAX_TURNS}.`);
33
+ throw new Error(messages.limits.mustBeInteger(label, MAX_TURNS));
33
34
  }
34
35
  }
35
36
  /** Retourne `value` s'il est valide, sinon `DEFAULT_TURNS`. Silencieux : ne lève pas d'erreur. */
@@ -0,0 +1,36 @@
1
+ const frHints = {
2
+ "command-not-found": "Verifie que la CLI est installee, authentifiee et disponible dans le PATH.",
3
+ "spawn-failed": "Sur Windows, essaye le wrapper .cmd ou active \"shell\": true dans la config agent.",
4
+ timeout: "Augmente timeoutMs ou teste la commande directement dans le terminal.",
5
+ "idle-timeout": "Desactive idleTimeoutMs pour les CLIs IA qui restent silencieuses pendant la generation.",
6
+ "empty-output": "Teste la commande en dehors de Palabre et verifie que le prompt est bien lu via stdin ou argument.",
7
+ "usage-limit": "Attends la fenetre indiquee par la CLI, change de modele ou relance avec un autre agent/preset disponible.",
8
+ "non-zero-exit": "Teste la commande directement, puis ajuste args, permissions, modele ou authentification de la CLI.",
9
+ "model-unavailable": "Installe le modele Ollama ou relance avec --pull-models pour autoriser le telechargement.",
10
+ "unsupported-model": "Verifie le nom du modele, ton abonnement, ou retire --model-a/--model-b/--summary-model pour laisser la CLI utiliser son modele par defaut.",
11
+ "model-pull-failed": "Verifie le nom du modele, ta connexion et l'espace disque disponible.",
12
+ "http-error": "Verifie que le service local est lance et que baseUrl est correct."
13
+ };
14
+ const enHints = {
15
+ "command-not-found": "Check that the CLI is installed, authenticated, and available in PATH.",
16
+ "spawn-failed": "On Windows, try the .cmd wrapper or enable \"shell\": true in the agent config.",
17
+ timeout: "Increase timeoutMs or test the command directly in the terminal.",
18
+ "idle-timeout": "Disable idleTimeoutMs for AI CLIs that stay silent while generating.",
19
+ "empty-output": "Test the command outside Palabre and check that the prompt is read through stdin or an argument.",
20
+ "usage-limit": "Wait for the window indicated by the CLI, change model, or run again with another available agent/preset.",
21
+ "non-zero-exit": "Test the command directly, then adjust args, permissions, model, or CLI authentication.",
22
+ "model-unavailable": "Install the Ollama model or run again with --pull-models to allow downloading.",
23
+ "unsupported-model": "Check the model name, your subscription, or remove --model-a/--model-b/--summary-model so the CLI can use its default model.",
24
+ "model-pull-failed": "Check the model name, your connection, and available disk space.",
25
+ "http-error": "Check that the local service is running and baseUrl is correct."
26
+ };
27
+ export const adapterErrorMessages = {
28
+ fr: {
29
+ suggestionPrefix: "Suggestion",
30
+ hint: (kind) => frHints[kind]
31
+ },
32
+ en: {
33
+ suggestionPrefix: "Suggestion",
34
+ hint: (kind) => enHints[kind]
35
+ }
36
+ };
@@ -0,0 +1,38 @@
1
+ export const agentsMessages = {
2
+ fr: {
3
+ noConfig: "Aucune config trouvée. Lance `palabre init`, puis `palabre agents`.",
4
+ config: (path) => `Config: ${path}`,
5
+ title: "Agents déclarés:",
6
+ defaultAgentA: "agent A par défaut",
7
+ defaultAgentB: "agent B par défaut",
8
+ defaultSummary: "synthèse par défaut",
9
+ defaults: (agentA, agentB, turns, summaryAgent) => `Défauts: ${agentA} <-> ${agentB}, réponses: ${turns}, synthèse: ${summaryAgent}`,
10
+ none: "aucun",
11
+ summaryAgentB: "agent B",
12
+ model: (model) => `modèle: ${model}`,
13
+ command: (command, model) => `commande: ${command}${model ? ` | modèle: ${model}` : ""}`,
14
+ detected: (command) => command ? `détecté (${command})` : "détecté",
15
+ notDetected: "non détecté",
16
+ ollamaUnreachable: "Ollama non joignable",
17
+ ollamaNotDetected: "Ollama non détecté",
18
+ missingModel: (model) => `modèle absent (${model})`
19
+ },
20
+ en: {
21
+ noConfig: "No config found. Run `palabre init`, then `palabre agents`.",
22
+ config: (path) => `Config: ${path}`,
23
+ title: "Declared agents:",
24
+ defaultAgentA: "default agent A",
25
+ defaultAgentB: "default agent B",
26
+ defaultSummary: "default summary",
27
+ defaults: (agentA, agentB, turns, summaryAgent) => `Defaults: ${agentA} <-> ${agentB}, responses: ${turns}, summary: ${summaryAgent}`,
28
+ none: "none",
29
+ summaryAgentB: "agent B",
30
+ model: (model) => `model: ${model}`,
31
+ command: (command, model) => `command: ${command}${model ? ` | model: ${model}` : ""}`,
32
+ detected: (command) => command ? `detected (${command})` : "detected",
33
+ notDetected: "not detected",
34
+ ollamaUnreachable: "Ollama unreachable",
35
+ ollamaNotDetected: "Ollama not detected",
36
+ missingModel: (model) => `missing model (${model})`
37
+ }
38
+ };
@@ -0,0 +1,28 @@
1
+ export const commonMessages = {
2
+ fr: {
3
+ invalidLanguage: (source, value, supported) => `${source} invalide: ${value}. Valeurs supportées: ${supported.join(", ")}.`,
4
+ unknownCommand: (value, commands) => `Commande inconnue: ${value}. Commandes disponibles: ${commands}.`,
5
+ ambiguousSubject: (value) => `Commande inconnue ou sujet ambigu: ${value}. Utilise -s "${value}" pour un sujet en un mot, ou palabre help pour voir les commandes.`,
6
+ optionRequiresValue: (option) => `L'option ${option} attend une valeur.`,
7
+ setDefaultsRequiresTwo: "L'option --set-defaults attend deux agents: --set-defaults <agentA> <agentB>.",
8
+ topicRequired: "Le paramètre --subject est requis.",
9
+ noAgentDefined: (label) => `Aucun ${label} défini. Utilise --agent-a/--agent-b, un preset, ou définis une paire avec palabre config --set-defaults <agentA> <agentB>. Guide: https://palab.re/fr/agents/overview`,
10
+ unknownAgentForField: (field, agent, available) => `Agent inconnu pour ${field}: ${agent}. Agents disponibles: ${available}.`,
11
+ unknownAgent: (agent) => `Agent inconnu: ${agent}`,
12
+ unknownRenderer: (value, supported) => `Renderer inconnu: ${value}. Valeurs supportées: ${supported}.`,
13
+ errorPrefix: "Erreur"
14
+ },
15
+ en: {
16
+ invalidLanguage: (source, value, supported) => `Invalid ${source}: ${value}. Supported values: ${supported.join(", ")}.`,
17
+ unknownCommand: (value, commands) => `Unknown command: ${value}. Available commands: ${commands}.`,
18
+ ambiguousSubject: (value) => `Unknown command or ambiguous subject: ${value}. Use -s "${value}" for a one-word subject, or palabre help to see commands.`,
19
+ optionRequiresValue: (option) => `Option ${option} expects a value.`,
20
+ setDefaultsRequiresTwo: "Option --set-defaults expects two agents: --set-defaults <agentA> <agentB>.",
21
+ topicRequired: "The --subject parameter is required.",
22
+ noAgentDefined: (label) => `No ${label} defined. Use --agent-a/--agent-b, a preset, or define a pair with palabre config --set-defaults <agentA> <agentB>. Guide: https://palab.re/en/agents/overview`,
23
+ unknownAgentForField: (field, agent, available) => `Unknown agent for ${field}: ${agent}. Available agents: ${available}.`,
24
+ unknownAgent: (agent) => `Unknown agent: ${agent}`,
25
+ unknownRenderer: (value, supported) => `Unknown renderer: ${value}. Supported values: ${supported}.`,
26
+ errorPrefix: "Error"
27
+ }
28
+ };
@@ -0,0 +1,88 @@
1
+ export const configMessages = {
2
+ fr: {
3
+ createdForConfig: (path) => `${path} créé. Édite la config puis relance palabre config.`,
4
+ syncNoMissing: (path) => `Aucun agent détecté manquant dans ${path}.`,
5
+ syncAdded: (path, agents) => `Agents ajoutés dans ${path}: ${agents}.`,
6
+ updated: (path, defaults, language) => `Configuration mise à jour dans ${path}: ${defaults}, langue: ${language}.`,
7
+ cleared: (path) => `Paramètres par défaut supprimés dans ${path}. Utilise maintenant un preset ou --agent-a/--agent-b pour lancer un débat.`,
8
+ defaultsSummary: (agentA, agentB, turns, summaryAgent) => {
9
+ const pair = agentA && agentB ? `agents: ${agentA} <-> ${agentB}` : "agents: non définis";
10
+ const summary = summaryAgent ? `synthèse: ${summaryAgent}` : "synthèse: agent B";
11
+ return `${pair}, réponses: ${turns}, ${summary}`;
12
+ },
13
+ wizardNeedsTwoAgents: "La config doit contenir au moins deux agents pour définir des paramètres par défaut.",
14
+ wizardTitle: "PALABRE - Configuration",
15
+ wizardQuitHint: "À tout moment: Ctrl+C pour interrompre, ou tape q, quit ou exit dans un prompt pour quitter.",
16
+ wizardConfigFile: "Fichier de configuration :",
17
+ wizardCurrentDefaults: "Paramètres par défaut actuels :",
18
+ wizardNoDefaults: "Aucun",
19
+ wizardActionQuestion: "Que veux-tu faire ?",
20
+ wizardActionSetDefaults: "Définir des paramètres par défaut",
21
+ wizardActionClearDefaults: "Supprimer les paramètres par défaut",
22
+ wizardActionExit: "Quitter sans modifier",
23
+ wizardChoicePrompt: "Tape le numéro de ton choix",
24
+ wizardChoiceQuestion: (label, defaultValue) => `${label} (Entrée = ${defaultValue}) : `,
25
+ wizardUnchanged: "Config inchangée.",
26
+ wizardCleared: (path) => `Paramètres par défaut supprimés dans ${path}.`,
27
+ wizardDefaultsSet: (path, defaults) => `Paramètres par défaut définis dans ${path}: ${defaults}.`,
28
+ wizardAgentADescription: "Choisis l'agent A, celui qui répondra en premier.",
29
+ wizardAgentBDescription: "Choisis l'agent B, celui qui répondra en second.",
30
+ wizardSummaryTitle: "Agent de synthèse par défaut",
31
+ wizardNoSummary: "Aucun agent de synthèse par défaut",
32
+ wizardCurrent: "Actuel",
33
+ wizardSuggestion: "Suggestion",
34
+ wizardAgentBHint: "agent B",
35
+ wizardAgentPrompt: (fallback) => `Tape un numéro ou un nom d'agent (Entrée = ${fallback}) : `,
36
+ wizardSummaryPrompt: (fallback) => `Tape un numéro, un nom d'agent, ou 0 pour aucun (Entrée = ${fallback}) : `,
37
+ wizardInvalidAgentChoice: "Choix invalide. Tape un numéro, un nom d'agent, Entrée ou q.",
38
+ wizardInvalidSummaryChoice: "Choix invalide. Tape un numéro, un nom d'agent, 0, Entrée ou q.",
39
+ wizardInvalidChoice: (allowed) => `Choix invalide. Valeurs: ${allowed}, Entrée ou q.`,
40
+ wizardTurnsLabel: "Nombre de réponses par défaut",
41
+ wizardTurnsPrompt: (defaultValue) => `Tape le nombre total de réponses du débat (Entrée = ${defaultValue}) : `,
42
+ wizardTurnsInvalid: (maxTurns) => `Entre un nombre entier entre 1 et ${maxTurns}, Entrée ou q.`,
43
+ wizardDefaults: (defaults) => `${defaults.agentA ?? "?"} <-> ${defaults.agentB ?? "?"}, réponses: ${defaults.turns}${defaults.summaryAgent ? `, synthèse: ${defaults.summaryAgent}` : ""}`
44
+ },
45
+ en: {
46
+ createdForConfig: (path) => `${path} created. Edit the config, then run palabre config again.`,
47
+ syncNoMissing: (path) => `No missing detected agent in ${path}.`,
48
+ syncAdded: (path, agents) => `Agents added to ${path}: ${agents}.`,
49
+ updated: (path, defaults, language) => `Configuration updated in ${path}: ${defaults}, language: ${language}.`,
50
+ cleared: (path) => `Default settings cleared in ${path}. Use a preset or --agent-a/--agent-b to start a debate now.`,
51
+ defaultsSummary: (agentA, agentB, turns, summaryAgent) => {
52
+ const pair = agentA && agentB ? `agents: ${agentA} <-> ${agentB}` : "agents: not set";
53
+ const summary = summaryAgent ? `summary: ${summaryAgent}` : "summary: agent B";
54
+ return `${pair}, responses: ${turns}, ${summary}`;
55
+ },
56
+ wizardNeedsTwoAgents: "The config must contain at least two agents to set default settings.",
57
+ wizardTitle: "PALABRE - Configuration",
58
+ wizardQuitHint: "At any time: Ctrl+C to interrupt, or type q, quit, or exit in a prompt to leave.",
59
+ wizardConfigFile: "Configuration file:",
60
+ wizardCurrentDefaults: "Current default settings:",
61
+ wizardNoDefaults: "None",
62
+ wizardActionQuestion: "What do you want to do?",
63
+ wizardActionSetDefaults: "Set default settings",
64
+ wizardActionClearDefaults: "Clear default settings",
65
+ wizardActionExit: "Exit without changes",
66
+ wizardChoicePrompt: "Type the number of your choice",
67
+ wizardChoiceQuestion: (label, defaultValue) => `${label} (Enter = ${defaultValue}): `,
68
+ wizardUnchanged: "Config unchanged.",
69
+ wizardCleared: (path) => `Default settings cleared in ${path}.`,
70
+ wizardDefaultsSet: (path, defaults) => `Default settings set in ${path}: ${defaults}.`,
71
+ wizardAgentADescription: "Choose agent A, the one that will answer first.",
72
+ wizardAgentBDescription: "Choose agent B, the one that will answer second.",
73
+ wizardSummaryTitle: "Default summary agent",
74
+ wizardNoSummary: "No default summary agent",
75
+ wizardCurrent: "Current",
76
+ wizardSuggestion: "Suggestion",
77
+ wizardAgentBHint: "agent B",
78
+ wizardAgentPrompt: (fallback) => `Type a number or agent name (Enter = ${fallback}): `,
79
+ wizardSummaryPrompt: (fallback) => `Type a number, agent name, or 0 for none (Enter = ${fallback}): `,
80
+ wizardInvalidAgentChoice: "Invalid choice. Type a number, an agent name, Enter, or q.",
81
+ wizardInvalidSummaryChoice: "Invalid choice. Type a number, an agent name, 0, Enter, or q.",
82
+ wizardInvalidChoice: (allowed) => `Invalid choice. Values: ${allowed}, Enter, or q.`,
83
+ wizardTurnsLabel: "Default number of responses",
84
+ wizardTurnsPrompt: (defaultValue) => `Type the total number of debate responses (Enter = ${defaultValue}): `,
85
+ wizardTurnsInvalid: (maxTurns) => `Enter an integer between 1 and ${maxTurns}, Enter, or q.`,
86
+ wizardDefaults: (defaults) => `${defaults.agentA ?? "?"} <-> ${defaults.agentB ?? "?"}, responses: ${defaults.turns}${defaults.summaryAgent ? `, summary: ${defaults.summaryAgent}` : ""}`
87
+ }
88
+ };
@@ -0,0 +1,24 @@
1
+ export const contextMessages = {
2
+ fr: {
3
+ explicitMustBeFile: (path) => `Le contexte fichier doit pointer vers un fichier: ${path}`,
4
+ explicitTooLarge: (path, sizeBytes, maxBytes) => `Fichier trop gros pour le contexte: ${path} (${sizeBytes} bytes, max ${maxBytes})`,
5
+ explicitBinary: (path) => `Fichier binaire ou non texte refuse: ${path}`,
6
+ explicitTotalTooLarge: (sizeBytes, maxBytes) => `Contexte fichiers trop gros (${sizeBytes} bytes, max ${maxBytes})`,
7
+ ignoredNotFileOrDirectory: (path) => `Contexte ignore (ni fichier ni dossier): ${path}`,
8
+ ignoredNonTextExtension: (path) => `Contexte ignore (extension non texte): ${path}`,
9
+ ignoredTooLarge: (path, sizeBytes) => `Contexte ignore (fichier trop gros): ${path} (${sizeBytes} bytes)`,
10
+ ignoredTotalLimit: (path) => `Contexte ignore (limite totale atteinte): ${path}`,
11
+ ignoredBinary: (path) => `Contexte ignore (binaire detecte): ${path}`
12
+ },
13
+ en: {
14
+ explicitMustBeFile: (path) => `File context must point to a file: ${path}`,
15
+ explicitTooLarge: (path, sizeBytes, maxBytes) => `File too large for context: ${path} (${sizeBytes} bytes, max ${maxBytes})`,
16
+ explicitBinary: (path) => `Binary or non-text file rejected: ${path}`,
17
+ explicitTotalTooLarge: (sizeBytes, maxBytes) => `Context files too large (${sizeBytes} bytes, max ${maxBytes})`,
18
+ ignoredNotFileOrDirectory: (path) => `Context ignored (neither file nor directory): ${path}`,
19
+ ignoredNonTextExtension: (path) => `Context ignored (non-text extension): ${path}`,
20
+ ignoredTooLarge: (path, sizeBytes) => `Context ignored (file too large): ${path} (${sizeBytes} bytes)`,
21
+ ignoredTotalLimit: (path) => `Context ignored (total limit reached): ${path}`,
22
+ ignoredBinary: (path) => `Context ignored (binary detected): ${path}`
23
+ }
24
+ };
@@ -0,0 +1,126 @@
1
+ export const doctorMessages = {
2
+ fr: {
3
+ title: "PALABRE doctor",
4
+ currentDirectory: (cwd) => `Dossier courant: ${cwd}`,
5
+ configFound: (path) => `Config trouvée: ${path}`,
6
+ configMissing: (path) => `Config absente: ${path}`,
7
+ noConfigAction: "Action: lance `palabre init` pour créer la config globale, ou `palabre init --local` pour une config projet.",
8
+ configReadable: "Config JSON lisible.",
9
+ configUnreadable: (message) => `Config illisible: ${message}`,
10
+ configUnreadableAction: "Action: corrige le JSON ou relance `palabre init --config <path>` vers un nouveau fichier.",
11
+ interfaceLanguage: (language) => `Langue: ${language}`,
12
+ noAgents: "Aucun agent configuré.",
13
+ oneAgent: (name) => `1 agent configuré: ${name}. Palabre fonctionne mieux avec au moins deux agents.`,
14
+ agentCount: (count, names) => `${count} agent(s) configuré(s): ${names}`,
15
+ defaultAgentMissing: (label) => `${label} absent.`,
16
+ defaultAgentUnknown: (label, name) => `${label} pointe vers un agent inconnu: ${name}`,
17
+ defaultAgentOk: (label, name) => `${label}: ${name}`,
18
+ defaultPairIncomplete: "Paire par défaut incomplète. Action: `palabre config --set-defaults <agentA> <agentB>`.",
19
+ sameDefaultAgent: (name) => `defaults.agentA et defaults.agentB pointent vers le même agent (${name}). C'est possible, mais souvent moins utile qu'une vraie paire.`,
20
+ defaultTurnsMissing: (turns) => `defaults.turns absent: Palabre utilisera ${turns} réponses.`,
21
+ defaultTurnsInvalid: (value, max) => `defaults.turns invalide: ${value}. Action: choisis un entier entre 1 et ${max}.`,
22
+ defaultTurnsOk: (value) => `defaults.turns: ${value}`,
23
+ summaryAgentMissing: "defaults.summaryAgent absent: la synthèse utilisera agentB.",
24
+ outputDirMissing: (path) => `outputDir absent: les exports seront écrits dans le dossier par défaut (${path}).`,
25
+ outputDirLegacy: (path) => `outputDir legacy '.': les exports seront regroupés dans ${path}.`,
26
+ outputDirIsFile: (path) => `outputDir pointe vers un fichier, pas un dossier: ${path}`,
27
+ outputDirConfigured: (path) => `outputDir configuré: ${path}`,
28
+ outputDirWillCreate: (path) => `outputDir n'existe pas encore: ${path}. Palabre tentera de le créer au moment de l'export.`,
29
+ localTools: "Outils locaux:",
30
+ ollamaReachable: (baseUrl, count) => `Ollama API joignable: ${baseUrl} (${count} modèle(s))`,
31
+ ollamaInstalledNoApi: (baseUrl, suffix) => `Ollama installé mais API non joignable: ${baseUrl}${suffix}`,
32
+ ollamaMissingNoApi: (baseUrl, suffix) => `Ollama non détecté et API non joignable: ${baseUrl}${suffix}`,
33
+ configuredAgents: "Agents configurés:",
34
+ detectedMissing: (names) => `Agent(s) détecté(s) mais absent(s) de la config: ${names}. Action: lance ` + "`palabre config --sync-agents`.",
35
+ roleMissing: (name) => `${name}: role absent.`,
36
+ cliCommandMissing: (name) => `${name}: command CLI absent.`,
37
+ promptModeInvalid: (name, value) => `${name}: promptMode invalide (${value}). Valeurs attendues: stdin ou argument.`,
38
+ positiveTimeout: (name, field) => `${name}: ${field} doit être un nombre positif.`,
39
+ ollamaModelMissing: (name) => `${name}: modèle Ollama absent.`,
40
+ ollamaBaseUrlInvalid: (name, value) => `${name}: baseUrl Ollama invalide (${value}). Attendu: http://... ou https://...`,
41
+ customCommand: (prefix) => `${prefix} (commande custom non vérifiée par doctor)`,
42
+ cliDetected: (prefix, path) => `${prefix} détectée (${path})`,
43
+ cliMissing: (prefix) => `${prefix} non détectée dans PATH. Action: installe/authentifie la CLI ou corrige command dans la config.`,
44
+ ollamaNotVerifiable: (prefix) => `${prefix} non vérifiable: API Ollama non joignable. Action: démarre Ollama ou corrige baseUrl.`,
45
+ ollamaValidateFalse: (prefix) => `${prefix} non validé car validateModel=false.`,
46
+ ollamaInstalled: (prefix) => `${prefix} installé.`,
47
+ ollamaMissing: (prefix, model) => `${prefix} absent. Action: lance ` + "`ollama pull " + model + "`" + " ou utilise `--pull-models`.",
48
+ commandDetected: (label, path) => `${label}: détecté (${path})`,
49
+ commandMissing: (label) => `${label}: non détecté dans PATH.`,
50
+ status: (errorCount, warnCount) => errorCount > 0
51
+ ? `${errorCount} erreur(s), ${warnCount} avertissement(s)`
52
+ : warnCount > 0 ? `${warnCount} avertissement(s)` : "OK",
53
+ sections: {
54
+ configuration: "Configuration",
55
+ tools: "Outils locaux",
56
+ agents: "Agents",
57
+ check: "À vérifier"
58
+ },
59
+ nothingToDisplay: "Rien à afficher.",
60
+ statusLabel: "Statut",
61
+ levelLabels: { ok: "OK", warn: "WARN", error: "ERREUR", info: "INFO" },
62
+ prettyLevelLabels: { ok: "OK ", warn: "WARN ", error: "ERREUR", info: "INFO " }
63
+ },
64
+ en: {
65
+ title: "PALABRE doctor",
66
+ currentDirectory: (cwd) => `Current directory: ${cwd}`,
67
+ configFound: (path) => `Config found: ${path}`,
68
+ configMissing: (path) => `Config missing: ${path}`,
69
+ noConfigAction: "Action: run `palabre init` to create the global config, or `palabre init --local` for a project config.",
70
+ configReadable: "Config JSON is readable.",
71
+ configUnreadable: (message) => `Config unreadable: ${message}`,
72
+ configUnreadableAction: "Action: fix the JSON or run `palabre init --config <path>` for a new file.",
73
+ interfaceLanguage: (language) => `Language: ${language}`,
74
+ noAgents: "No agent configured.",
75
+ oneAgent: (name) => `1 agent configured: ${name}. Palabre works best with at least two agents.`,
76
+ agentCount: (count, names) => `${count} agent(s) configured: ${names}`,
77
+ defaultAgentMissing: (label) => `${label} is missing.`,
78
+ defaultAgentUnknown: (label, name) => `${label} points to an unknown agent: ${name}`,
79
+ defaultAgentOk: (label, name) => `${label}: ${name}`,
80
+ defaultPairIncomplete: "Default pair is incomplete. Action: `palabre config --set-defaults <agentA> <agentB>`.",
81
+ sameDefaultAgent: (name) => `defaults.agentA and defaults.agentB point to the same agent (${name}). This is allowed, but usually less useful than a real pair.`,
82
+ defaultTurnsMissing: (turns) => `defaults.turns is missing: Palabre will use ${turns} responses.`,
83
+ defaultTurnsInvalid: (value, max) => `Invalid defaults.turns: ${value}. Action: choose an integer between 1 and ${max}.`,
84
+ defaultTurnsOk: (value) => `defaults.turns: ${value}`,
85
+ summaryAgentMissing: "defaults.summaryAgent is missing: the summary will use agentB.",
86
+ outputDirMissing: (path) => `outputDir is missing: exports will be written to the default folder (${path}).`,
87
+ outputDirLegacy: (path) => `legacy outputDir '.': exports will be grouped in ${path}.`,
88
+ outputDirIsFile: (path) => `outputDir points to a file, not a folder: ${path}`,
89
+ outputDirConfigured: (path) => `outputDir configured: ${path}`,
90
+ outputDirWillCreate: (path) => `outputDir does not exist yet: ${path}. Palabre will try to create it during export.`,
91
+ localTools: "Local tools:",
92
+ ollamaReachable: (baseUrl, count) => `Ollama API reachable: ${baseUrl} (${count} model(s))`,
93
+ ollamaInstalledNoApi: (baseUrl, suffix) => `Ollama is installed but the API is unreachable: ${baseUrl}${suffix}`,
94
+ ollamaMissingNoApi: (baseUrl, suffix) => `Ollama not detected and API unreachable: ${baseUrl}${suffix}`,
95
+ configuredAgents: "Configured agents:",
96
+ detectedMissing: (names) => `Detected agent(s) missing from config: ${names}. Action: run ` + "`palabre config --sync-agents`.",
97
+ roleMissing: (name) => `${name}: missing role.`,
98
+ cliCommandMissing: (name) => `${name}: missing CLI command.`,
99
+ promptModeInvalid: (name, value) => `${name}: invalid promptMode (${value}). Expected values: stdin or argument.`,
100
+ positiveTimeout: (name, field) => `${name}: ${field} must be a positive number.`,
101
+ ollamaModelMissing: (name) => `${name}: missing Ollama model.`,
102
+ ollamaBaseUrlInvalid: (name, value) => `${name}: invalid Ollama baseUrl (${value}). Expected: http://... or https://...`,
103
+ customCommand: (prefix) => `${prefix} (custom command not checked by doctor)`,
104
+ cliDetected: (prefix, path) => `${prefix} detected (${path})`,
105
+ cliMissing: (prefix) => `${prefix} not detected in PATH. Action: install/authenticate the CLI or fix command in the config.`,
106
+ ollamaNotVerifiable: (prefix) => `${prefix} cannot be verified: Ollama API is unreachable. Action: start Ollama or fix baseUrl.`,
107
+ ollamaValidateFalse: (prefix) => `${prefix} not validated because validateModel=false.`,
108
+ ollamaInstalled: (prefix) => `${prefix} installed.`,
109
+ ollamaMissing: (prefix, model) => `${prefix} missing. Action: run ` + "`ollama pull " + model + "`" + " or use `--pull-models`.",
110
+ commandDetected: (label, path) => `${label}: detected (${path})`,
111
+ commandMissing: (label) => `${label}: not detected in PATH.`,
112
+ status: (errorCount, warnCount) => errorCount > 0
113
+ ? `${errorCount} error(s), ${warnCount} warning(s)`
114
+ : warnCount > 0 ? `${warnCount} warning(s)` : "OK",
115
+ sections: {
116
+ configuration: "Configuration",
117
+ tools: "Local tools",
118
+ agents: "Agents",
119
+ check: "To check"
120
+ },
121
+ nothingToDisplay: "Nothing to display.",
122
+ statusLabel: "Status",
123
+ levelLabels: { ok: "OK", warn: "WARN", error: "ERROR", info: "INFO" },
124
+ prettyLevelLabels: { ok: "OK ", warn: "WARN ", error: "ERROR ", info: "INFO " }
125
+ }
126
+ };