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.
- package/README.md +2 -0
- package/dist/adapters/cli-pty.js +30 -10
- package/dist/adapters/cli-shared.js +73 -0
- package/dist/adapters/cli.js +40 -77
- package/dist/adapters/index.js +1 -0
- package/dist/adapters/ollama.js +32 -32
- package/dist/adapters/terminal.js +1 -0
- package/dist/args.js +1 -0
- package/dist/commands/agents.js +91 -0
- package/dist/commands/context.js +31 -0
- package/dist/commands/history.js +33 -0
- package/dist/commands/init.js +64 -0
- package/dist/commands/presets.js +39 -0
- package/dist/commands/shared.js +8 -0
- package/dist/commands/update.js +26 -0
- package/dist/config.js +17 -1
- package/dist/configWizard.js +5 -4
- package/dist/context.js +1 -0
- package/dist/contextScan.js +4 -3
- package/dist/discovery.js +9 -1
- package/dist/doctor.js +1 -0
- package/dist/errors.js +4 -0
- package/dist/exec.js +1 -0
- package/dist/history.js +10 -0
- package/dist/i18n.js +2 -0
- package/dist/index.js +174 -879
- package/dist/limits.js +5 -0
- package/dist/messages/adapter-errors.js +26 -2
- package/dist/messages/config.js +6 -0
- package/dist/messages/index.js +1 -0
- package/dist/messages/renderers.js +10 -2
- package/dist/messages/tui.js +8 -2
- package/dist/new.js +1 -0
- package/dist/ollamaUrl.js +20 -0
- package/dist/orchestrator.js +106 -161
- package/dist/output.js +2 -10
- package/dist/presets.js +1 -0
- package/dist/prompt.js +1 -0
- package/dist/renderers/console.js +2 -8
- package/dist/renderers/ndjson.js +1 -10
- package/dist/renderers/tui-prompts.js +339 -0
- package/dist/renderers/tui-renderer.js +224 -0
- package/dist/renderers/tui-screens.js +352 -0
- package/dist/renderers/tui-theme.js +356 -0
- package/dist/renderers/tui.js +7 -1095
- package/dist/runOptions.js +97 -0
- package/dist/session.js +1 -0
- package/dist/tuiController.js +445 -0
- package/dist/tuiState.js +4 -0
- package/dist/types.js +1 -0
- package/dist/update.js +1 -0
- package/dist/version.js +1 -0
- 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
|
|
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");
|
package/dist/configWizard.js
CHANGED
|
@@ -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,
|
|
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
|
|
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
|
|
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
|
|
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
package/dist/contextScan.js
CHANGED
|
@@ -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
|
-
*
|
|
6
|
+
* Construit l'aperçu de contexte lisible par une machine, utilisé par les intégrations.
|
|
6
7
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
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
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.
|