palabre 0.2.0 → 0.5.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 +33 -7
- package/dist/configWizard.js +45 -40
- package/dist/context.js +16 -14
- package/dist/doctor.js +139 -135
- package/dist/errors.js +4 -31
- package/dist/i18n.js +30 -0
- package/dist/index.js +290 -245
- package/dist/limits.js +11 -10
- package/dist/messages/adapter-errors.js +36 -0
- package/dist/messages/agents.js +38 -0
- package/dist/messages/common.js +28 -0
- package/dist/messages/config.js +88 -0
- package/dist/messages/context.js +24 -0
- package/dist/messages/doctor.js +126 -0
- package/dist/messages/help.js +280 -0
- package/dist/messages/index.js +38 -0
- package/dist/messages/init.js +30 -0
- package/dist/messages/limits.js +12 -0
- package/dist/messages/new.js +66 -0
- package/dist/messages/orchestrator.js +14 -0
- package/dist/messages/output.js +64 -0
- package/dist/messages/presets.js +26 -0
- package/dist/messages/preview.js +22 -0
- package/dist/messages/prompt.js +102 -0
- package/dist/messages/renderers.js +38 -0
- package/dist/messages/update.js +40 -0
- package/dist/new.js +42 -42
- package/dist/orchestrator.js +23 -18
- package/dist/output.js +34 -33
- package/dist/presets.js +78 -2
- package/dist/prompt.js +43 -58
- package/dist/renderers/console.js +32 -26
- package/dist/update.js +10 -21
- package/package.json +1 -1
- package/palabre.config.example.json +1 -0
package/dist/prompt.js
CHANGED
|
@@ -1,101 +1,86 @@
|
|
|
1
|
+
import { createTranslator } from "./i18n.js";
|
|
1
2
|
/**
|
|
2
3
|
* Formate le prompt complet transmis à l'adapter.
|
|
3
4
|
* Dispatche vers le format de synthèse si `input.mode === "summary"`, sinon construit le prompt de débat standard.
|
|
4
5
|
*/
|
|
5
6
|
export function formatAgentPrompt(input) {
|
|
7
|
+
const messages = createTranslator(input.language ?? "fr").prompt;
|
|
6
8
|
if (input.mode === "summary") {
|
|
7
|
-
return formatSummaryPrompt(input);
|
|
9
|
+
return formatSummaryPrompt(input, messages);
|
|
8
10
|
}
|
|
9
11
|
const transcript = formatTranscript(input.transcript);
|
|
10
12
|
return [
|
|
11
|
-
|
|
13
|
+
messages.subject(input.topic),
|
|
12
14
|
"",
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
roleInstruction(input.selfRole),
|
|
15
|
+
messages.debateIntro(input.selfName, input.turn),
|
|
16
|
+
messages.peer(input.peerName),
|
|
17
|
+
messages.role(input.selfName, input.selfRole),
|
|
18
|
+
messages.roleInstruction(input.selfRole),
|
|
17
19
|
"",
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
20
|
+
messages.sessionTitle,
|
|
21
|
+
messages.sessionSource,
|
|
22
|
+
messages.localDate(input.session.localDate),
|
|
23
|
+
messages.timeZone(input.session.timeZone),
|
|
24
|
+
messages.cwd(input.session.cwd),
|
|
25
|
+
messages.sessionStartedAt(input.session.startedAt),
|
|
26
|
+
messages.turnProgress(input.turn, input.totalTurns),
|
|
24
27
|
"",
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
"- Reagis aux arguments precedents au lieu de repartir de zero.",
|
|
28
|
-
"- Signale les incertitudes ou les points a trancher.",
|
|
29
|
-
"- Respecte ton role sans ignorer les faits du transcript.",
|
|
28
|
+
messages.objectiveTitle,
|
|
29
|
+
...messages.debateObjectives,
|
|
30
30
|
"",
|
|
31
|
-
input.files.length > 0 ?
|
|
31
|
+
input.files.length > 0 ? messages.fileContextTitle : "",
|
|
32
32
|
formatFileContext(input.files),
|
|
33
33
|
input.files.length > 0 ? "" : "",
|
|
34
|
-
transcript.length > 0 ?
|
|
34
|
+
transcript.length > 0 ? messages.historyTitle : messages.emptyHistory,
|
|
35
35
|
transcript,
|
|
36
36
|
"",
|
|
37
|
-
|
|
37
|
+
messages.answerTitle
|
|
38
38
|
]
|
|
39
39
|
.filter(Boolean)
|
|
40
40
|
.join("\n");
|
|
41
41
|
}
|
|
42
42
|
/** Formate le prompt de synthèse finale. Impose un format structuré : Consensus / Désaccords / Actions / Conclusion. */
|
|
43
|
-
function formatSummaryPrompt(input) {
|
|
43
|
+
function formatSummaryPrompt(input, messages) {
|
|
44
44
|
const transcript = formatTranscript(input.transcript);
|
|
45
45
|
return [
|
|
46
|
-
|
|
46
|
+
messages.subject(input.topic),
|
|
47
47
|
"",
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
roleInstruction("summarizer"),
|
|
48
|
+
messages.summaryIntro(input.selfName),
|
|
49
|
+
messages.role(input.selfName, input.selfRole),
|
|
50
|
+
messages.roleInstruction("summarizer"),
|
|
51
51
|
"",
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
52
|
+
messages.sessionTitle,
|
|
53
|
+
messages.sessionSource,
|
|
54
|
+
messages.localDate(input.session.localDate),
|
|
55
|
+
messages.timeZone(input.session.timeZone),
|
|
56
|
+
messages.cwd(input.session.cwd),
|
|
57
|
+
messages.sessionStartedAt(input.session.startedAt),
|
|
58
58
|
"",
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
"- Liste les desaccords ou incertitudes qui restent.",
|
|
62
|
-
"- Propose les prochaines actions techniques.",
|
|
63
|
-
"- Termine par une conclusion courte en prose, bien ecrite, qui explique rapidement ce qu'il faut retenir.",
|
|
64
|
-
"- Reste concis et exploitable.",
|
|
59
|
+
messages.objectiveTitle,
|
|
60
|
+
...messages.summaryObjectives,
|
|
65
61
|
"",
|
|
66
|
-
input.files.length > 0 ?
|
|
62
|
+
input.files.length > 0 ? messages.fileContextTitle : "",
|
|
67
63
|
formatFileContext(input.files),
|
|
68
64
|
input.files.length > 0 ? "" : "",
|
|
69
|
-
|
|
70
|
-
transcript ||
|
|
65
|
+
messages.transcriptTitle,
|
|
66
|
+
transcript || messages.noMessage,
|
|
71
67
|
"",
|
|
72
|
-
|
|
73
|
-
|
|
68
|
+
messages.expectedFormatTitle,
|
|
69
|
+
messages.consensusHeading,
|
|
74
70
|
"",
|
|
75
|
-
|
|
71
|
+
messages.disagreementsHeading,
|
|
76
72
|
"",
|
|
77
|
-
|
|
73
|
+
messages.actionsHeading,
|
|
78
74
|
"",
|
|
79
|
-
|
|
75
|
+
messages.conclusionHeading,
|
|
80
76
|
"",
|
|
81
|
-
|
|
77
|
+
messages.finalProseInstruction,
|
|
82
78
|
"",
|
|
83
|
-
|
|
79
|
+
messages.summaryAnswerTitle
|
|
84
80
|
]
|
|
85
81
|
.filter(Boolean)
|
|
86
82
|
.join("\n");
|
|
87
83
|
}
|
|
88
|
-
function roleInstruction(role) {
|
|
89
|
-
const instructions = {
|
|
90
|
-
implementer: "Consigne de role: propose une solution concrete, executable et sobrement justifiee.",
|
|
91
|
-
reviewer: "Consigne de role: cherche les risques, regressions, angles morts et tests manquants.",
|
|
92
|
-
architect: "Consigne de role: structure les options techniques, compromis et frontieres du systeme.",
|
|
93
|
-
scout: "Consigne de role: explore rapidement le terrain, releve les pistes utiles et les inconnues.",
|
|
94
|
-
critic: "Consigne de role: challenge les hypotheses, pointe les faiblesses et demande les preuves utiles.",
|
|
95
|
-
summarizer: "Consigne de role: synthetise fidelement le transcript sans ajouter de nouvelles hypotheses non signalees."
|
|
96
|
-
};
|
|
97
|
-
return instructions[role];
|
|
98
|
-
}
|
|
99
84
|
/** Formate les fichiers projet en blocs de code annotés pour l'injection dans le prompt. */
|
|
100
85
|
function formatFileContext(files) {
|
|
101
86
|
return files
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
const supportsColor = Boolean(process.stdout.isTTY) && !process.env.NO_COLOR;
|
|
2
2
|
const supportsInteractiveOutput = Boolean(process.stdout.isTTY);
|
|
3
3
|
/** Instancie le renderer adapté : pretty (spinner, couleurs ANSI, sections) ou plain (logs bruts). */
|
|
4
|
-
export function createConsoleRenderer(plain) {
|
|
5
|
-
return plain ? new PlainConsoleRenderer() : new PrettyConsoleRenderer(supportsColor, supportsInteractiveOutput);
|
|
4
|
+
export function createConsoleRenderer(plain, messages) {
|
|
5
|
+
return plain ? new PlainConsoleRenderer(messages) : new PrettyConsoleRenderer(supportsColor, supportsInteractiveOutput, messages);
|
|
6
6
|
}
|
|
7
7
|
/**
|
|
8
8
|
* Renderer interactif avec spinner, couleurs ANSI et encadrés de section.
|
|
@@ -11,6 +11,7 @@ export function createConsoleRenderer(plain) {
|
|
|
11
11
|
class PrettyConsoleRenderer {
|
|
12
12
|
color;
|
|
13
13
|
interactive;
|
|
14
|
+
messages;
|
|
14
15
|
spinner;
|
|
15
16
|
spinnerFrame = 0;
|
|
16
17
|
renderingSummary = false;
|
|
@@ -19,9 +20,10 @@ class PrettyConsoleRenderer {
|
|
|
19
20
|
* @param color - Active les codes couleur ANSI.
|
|
20
21
|
* @param interactive - Active le spinner en place (mode TTY interactif).
|
|
21
22
|
*/
|
|
22
|
-
constructor(color, interactive) {
|
|
23
|
+
constructor(color, interactive, messages) {
|
|
23
24
|
this.color = color;
|
|
24
25
|
this.interactive = interactive;
|
|
26
|
+
this.messages = messages;
|
|
25
27
|
}
|
|
26
28
|
/** Affiche l'en-tête du débat (sujet, agents, options). */
|
|
27
29
|
start(options, agents = []) {
|
|
@@ -29,29 +31,29 @@ class PrettyConsoleRenderer {
|
|
|
29
31
|
process.stdout.write([
|
|
30
32
|
"",
|
|
31
33
|
this.c("cyan", `┌─ ${title} ${"─".repeat(Math.max(1, 54 - title.length))}`),
|
|
32
|
-
this.c("cyan", `│`) + `
|
|
33
|
-
this.c("cyan", `│`) + `
|
|
34
|
-
this.c("cyan", `│`) + `
|
|
35
|
-
this.c("cyan", `│`) + `
|
|
36
|
-
this.c("cyan", `│`) + `
|
|
34
|
+
this.c("cyan", `│`) + ` ${this.messages.renderers.subject(options.topic)}`,
|
|
35
|
+
this.c("cyan", `│`) + ` ${this.messages.renderers.agents(formatAgentPair(options, agents))}`,
|
|
36
|
+
this.c("cyan", `│`) + ` ${this.messages.renderers.responsesSummary(options.turns, formatSummary(options, this.messages))}`,
|
|
37
|
+
this.c("cyan", `│`) + ` ${this.messages.renderers.context(formatContext(options, this.messages))}`,
|
|
38
|
+
this.c("cyan", `│`) + ` ${this.messages.renderers.options(options.earlyStopOnAgreement, options.pullModels)}`,
|
|
37
39
|
this.c("cyan", `└${"─".repeat(57)}`),
|
|
38
40
|
""
|
|
39
41
|
].join("\n"));
|
|
40
42
|
}
|
|
41
43
|
/** Écrit un avertissement sur `stderr` en jaune. */
|
|
42
44
|
warning(message) {
|
|
43
|
-
process.stderr.write(`${this.c("yellow",
|
|
45
|
+
process.stderr.write(`${this.c("yellow", this.messages.renderers.warningPrefix)} ${message}\n`);
|
|
44
46
|
}
|
|
45
47
|
/** Écrit une notice informative sur `stdout` en vert. */
|
|
46
48
|
notice(message) {
|
|
47
|
-
process.stdout.write(`${this.c("green",
|
|
49
|
+
process.stdout.write(`${this.c("green", this.messages.renderers.infoPrefix)} ${message}\n`);
|
|
48
50
|
}
|
|
49
51
|
/** Affiche l'en-tête d'un nouveau tour (agent, rôle, progression). */
|
|
50
52
|
turnStart(turn, totalTurns, agent, role) {
|
|
51
53
|
this.renderingSummary = false;
|
|
52
54
|
process.stdout.write([
|
|
53
55
|
"",
|
|
54
|
-
this.c("orange", `◆ ${agent}`) + this.dim(` · ${role} ·
|
|
56
|
+
this.c("orange", `◆ ${agent}`) + this.dim(` · ${role} · ${this.messages.renderers.turn(turn, totalTurns)}`),
|
|
55
57
|
this.dim("─".repeat(60)),
|
|
56
58
|
""
|
|
57
59
|
].join("\n"));
|
|
@@ -59,7 +61,7 @@ class PrettyConsoleRenderer {
|
|
|
59
61
|
/** Démarre le spinner de réflexion (ou affiche une ligne fixe si non interactif). */
|
|
60
62
|
thinkingStart(agent, role) {
|
|
61
63
|
this.thinkingEnd();
|
|
62
|
-
const text =
|
|
64
|
+
const text = this.messages.renderers.thinking(agent, role);
|
|
63
65
|
if (!this.interactive) {
|
|
64
66
|
process.stdout.write(`${this.dim(`${text}...`)}\n`);
|
|
65
67
|
return;
|
|
@@ -92,14 +94,14 @@ class PrettyConsoleRenderer {
|
|
|
92
94
|
this.renderingSummary = true;
|
|
93
95
|
process.stdout.write([
|
|
94
96
|
"",
|
|
95
|
-
this.c("pink", `◆
|
|
97
|
+
this.c("pink", `◆ ${this.messages.renderers.summaryTitle}`) + this.dim(` · ${agent} · ${role}`),
|
|
96
98
|
this.dim("─".repeat(60)),
|
|
97
99
|
""
|
|
98
100
|
].join("\n"));
|
|
99
101
|
}
|
|
100
102
|
/** Affiche le chemin du fichier de sortie en vert à la fin du débat. */
|
|
101
103
|
done(outputPath) {
|
|
102
|
-
process.stdout.write(`\n\n${this.c("green",
|
|
104
|
+
process.stdout.write(`\n\n${this.c("green", this.messages.renderers.exported(outputPath))}\n\n`);
|
|
103
105
|
}
|
|
104
106
|
/**
|
|
105
107
|
* Convertit les titres Markdown `### Heading` en titres colorés avec séparateur.
|
|
@@ -139,19 +141,23 @@ class PrettyConsoleRenderer {
|
|
|
139
141
|
* Utilisé avec `--plain` ou quand `stdout` n'est pas un TTY.
|
|
140
142
|
*/
|
|
141
143
|
class PlainConsoleRenderer {
|
|
144
|
+
messages;
|
|
145
|
+
constructor(messages) {
|
|
146
|
+
this.messages = messages;
|
|
147
|
+
}
|
|
142
148
|
/** Affiche les informations de démarrage du débat en texte brut. */
|
|
143
149
|
start(options, agents = []) {
|
|
144
|
-
process.stdout.write(
|
|
145
|
-
process.stdout.write(
|
|
146
|
-
process.stdout.write(
|
|
150
|
+
process.stdout.write(this.messages.renderers.subject(options.topic) + "\n");
|
|
151
|
+
process.stdout.write(this.messages.renderers.agents(formatAgentPair(options, agents)) + "\n");
|
|
152
|
+
process.stdout.write(this.messages.renderers.responsesSummaryContext(options.turns, formatSummary(options, this.messages), formatContext(options, this.messages)) + "\n");
|
|
147
153
|
}
|
|
148
154
|
/** Écrit un avertissement sur `stderr`. */
|
|
149
155
|
warning(message) {
|
|
150
|
-
process.stderr.write(
|
|
156
|
+
process.stderr.write(`${this.messages.renderers.warningPrefix} ${message}\n`);
|
|
151
157
|
}
|
|
152
158
|
/** Écrit une notice informative sur `stdout`. */
|
|
153
159
|
notice(message) {
|
|
154
|
-
process.stdout.write(
|
|
160
|
+
process.stdout.write(`${this.messages.renderers.infoPrefix} ${message}\n`);
|
|
155
161
|
}
|
|
156
162
|
/** Affiche la progression du tour en texte brut. */
|
|
157
163
|
turnStart(turn, totalTurns, agent, role) {
|
|
@@ -167,11 +173,11 @@ class PlainConsoleRenderer {
|
|
|
167
173
|
}
|
|
168
174
|
/** Affiche l'en-tête de la section synthèse en texte brut. */
|
|
169
175
|
summaryStart(agent, role) {
|
|
170
|
-
process.stdout.write(`\n[
|
|
176
|
+
process.stdout.write(`\n[${this.messages.renderers.summaryTitle}] ${agent} (${role})...\n`);
|
|
171
177
|
}
|
|
172
178
|
/** Affiche le chemin du fichier de sortie à la fin du débat. */
|
|
173
179
|
done(outputPath) {
|
|
174
|
-
process.stdout.write(`\
|
|
180
|
+
process.stdout.write(`\n${this.messages.renderers.exported(outputPath)}\n`);
|
|
175
181
|
}
|
|
176
182
|
}
|
|
177
183
|
/**
|
|
@@ -200,19 +206,19 @@ function formatAgentLabel(agent) {
|
|
|
200
206
|
* Renvoie le nom de l'agent de synthèse ou `"désactivée"` si la synthèse est désactivée.
|
|
201
207
|
* @param options - Options du débat.
|
|
202
208
|
*/
|
|
203
|
-
function formatSummary(options) {
|
|
204
|
-
return options.summaryEnabled ? options.summaryAgent ?? options.agentB :
|
|
209
|
+
function formatSummary(options, messages) {
|
|
210
|
+
return options.summaryEnabled ? options.summaryAgent ?? options.agentB : messages.renderers.disabled;
|
|
205
211
|
}
|
|
206
212
|
/**
|
|
207
213
|
* Renvoie un résumé du contexte injecté (nombre de fichiers ou mention d'absence).
|
|
208
214
|
* @param options - Options du débat.
|
|
209
215
|
*/
|
|
210
|
-
function formatContext(options) {
|
|
216
|
+
function formatContext(options, messages) {
|
|
211
217
|
const count = options.files.length;
|
|
212
218
|
if (count === 0) {
|
|
213
|
-
return
|
|
219
|
+
return messages.renderers.noInjectedFiles;
|
|
214
220
|
}
|
|
215
|
-
return
|
|
221
|
+
return messages.renderers.injectedFiles(count);
|
|
216
222
|
}
|
|
217
223
|
/** Codes d'échappement ANSI utilisés par `PrettyConsoleRenderer`. */
|
|
218
224
|
const codes = {
|
package/dist/update.js
CHANGED
|
@@ -12,32 +12,21 @@ export async function getUpdateInfo(version) {
|
|
|
12
12
|
};
|
|
13
13
|
}
|
|
14
14
|
/** Génère les instructions de mise à jour adaptées au mode d'installation détecté dans `info`. */
|
|
15
|
-
export function formatUpdateInstructions(info) {
|
|
16
|
-
|
|
17
|
-
`PALABRE ${info.version}`,
|
|
18
|
-
"",
|
|
19
|
-
"Mise a jour recommandee:"
|
|
20
|
-
];
|
|
21
|
-
if (info.sourceCheckout) {
|
|
22
|
-
lines.push("", "Installation depuis le repo source detectee.", "", ` cd "${info.projectRoot}"`, " git pull --ff-only", " pnpm install", " pnpm build", " pnpm link --global", "", "Pour executer ces etapes automatiquement:", "", " palabre update --apply");
|
|
23
|
-
}
|
|
24
|
-
else {
|
|
25
|
-
lines.push("", "Installation package detectee.", "", " pnpm add --global palabre@latest", "", "Si tu utilises npm:", "", " npm install --global palabre@latest");
|
|
26
|
-
}
|
|
27
|
-
return lines.join("\n");
|
|
15
|
+
export function formatUpdateInstructions(info, messages) {
|
|
16
|
+
return messages.update.instructions(info);
|
|
28
17
|
}
|
|
29
18
|
/**
|
|
30
19
|
* Exécute `git pull`, `pnpm install`, `pnpm build`, `pnpm link --global` dans le répertoire du projet.
|
|
31
20
|
* @throws {Error} si `info.sourceCheckout` est faux — la mise à jour automatique ne s'applique qu'aux checkouts git.
|
|
32
21
|
*/
|
|
33
|
-
export async function applySourceUpdate(info) {
|
|
22
|
+
export async function applySourceUpdate(info, messages) {
|
|
34
23
|
if (!info.sourceCheckout) {
|
|
35
|
-
throw new Error(
|
|
24
|
+
throw new Error(messages.update.automaticSourceOnly);
|
|
36
25
|
}
|
|
37
|
-
await runStep("git", ["pull", "--ff-only"], info.projectRoot);
|
|
38
|
-
await runStep("pnpm", ["install"], info.projectRoot);
|
|
39
|
-
await runStep("pnpm", ["build"], info.projectRoot);
|
|
40
|
-
await runStep("pnpm", ["link", "--global"], info.projectRoot);
|
|
26
|
+
await runStep("git", ["pull", "--ff-only"], info.projectRoot, messages);
|
|
27
|
+
await runStep("pnpm", ["install"], info.projectRoot, messages);
|
|
28
|
+
await runStep("pnpm", ["build"], info.projectRoot, messages);
|
|
29
|
+
await runStep("pnpm", ["link", "--global"], info.projectRoot, messages);
|
|
41
30
|
}
|
|
42
31
|
async function exists(targetPath) {
|
|
43
32
|
try {
|
|
@@ -48,7 +37,7 @@ async function exists(targetPath) {
|
|
|
48
37
|
return false;
|
|
49
38
|
}
|
|
50
39
|
}
|
|
51
|
-
function runStep(command, args, cwd) {
|
|
40
|
+
function runStep(command, args, cwd, messages) {
|
|
52
41
|
return new Promise((resolve, reject) => {
|
|
53
42
|
const child = spawn(command, args, {
|
|
54
43
|
cwd,
|
|
@@ -62,7 +51,7 @@ function runStep(command, args, cwd) {
|
|
|
62
51
|
resolve();
|
|
63
52
|
return;
|
|
64
53
|
}
|
|
65
|
-
reject(new Error(
|
|
54
|
+
reject(new Error(messages.update.stepFailed(command, args.join(" "), String(exitCode ?? "inconnu"))));
|
|
66
55
|
});
|
|
67
56
|
});
|
|
68
57
|
}
|
package/package.json
CHANGED