palabre 0.5.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.
- package/README.md +6 -4
- package/dist/adapters/cli-pty.js +183 -0
- package/dist/adapters/cli.js +6 -6
- package/dist/adapters/index.js +3 -0
- package/dist/adapters/terminal.js +13 -0
- package/dist/config.js +22 -1
- package/dist/discovery.js +3 -1
- package/dist/doctor.js +8 -2
- package/dist/index.js +9 -2
- package/dist/messages/init.js +2 -2
- package/dist/new.js +4 -0
- package/dist/presets.js +44 -0
- package/dist/renderers/console.js +1 -1
- package/package.json +4 -1
package/README.md
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
|
|
14
14
|
## Français
|
|
15
15
|
|
|
16
|
-
PALABRE est un orchestrateur CLI qui fait dialoguer plusieurs agents IA installés sur votre machine : Claude Code, Codex CLI, Gemini CLI, OpenCode et Ollama.
|
|
16
|
+
PALABRE est un orchestrateur CLI qui fait dialoguer plusieurs agents IA installés sur votre machine : Claude Code, Codex CLI, Gemini CLI, Antigravity CLI, OpenCode et Ollama.
|
|
17
17
|
|
|
18
18
|
Il ne remplace pas vos outils : il les pilote. Vous gardez vos abonnements, vos modèles par défaut, vos habitudes de terminal et vos fichiers en local. PALABRE exporte ensuite le débat en Markdown.
|
|
19
19
|
|
|
@@ -57,6 +57,7 @@ palabre codex-claude "Preview" --context src --show-prompt
|
|
|
57
57
|
- Claude Code via `claude --print`
|
|
58
58
|
- Codex CLI via `codex exec`
|
|
59
59
|
- Gemini CLI via `gemini --prompt -`
|
|
60
|
+
- Antigravity CLI via `agy --print` en pseudo-terminal
|
|
60
61
|
- OpenCode via `opencode run`
|
|
61
62
|
- Ollama via l'API locale HTTP
|
|
62
63
|
|
|
@@ -64,7 +65,7 @@ PALABRE ne liste pas les modèles : ils changent souvent et dépendent de chaque
|
|
|
64
65
|
|
|
65
66
|
### Confidentialité
|
|
66
67
|
|
|
67
|
-
PALABRE tourne localement et n'envoie aucune donnée à un serveur appartenant à PALABRE. Les données envoyées aux agents dépendent des outils que vous utilisez : vérifiez les politiques de confidentialité de Claude Code, Codex CLI, Gemini CLI, OpenCode, Ollama ou de tout autre agent configuré.
|
|
68
|
+
PALABRE tourne localement et n'envoie aucune donnée à un serveur appartenant à PALABRE. Les données envoyées aux agents dépendent des outils que vous utilisez : vérifiez les politiques de confidentialité de Claude Code, Codex CLI, Gemini CLI, Antigravity CLI, OpenCode, Ollama ou de tout autre agent configuré.
|
|
68
69
|
|
|
69
70
|
### Développement local
|
|
70
71
|
|
|
@@ -87,7 +88,7 @@ MIT. Voir [LICENSE](./LICENSE).
|
|
|
87
88
|
|
|
88
89
|
## English
|
|
89
90
|
|
|
90
|
-
PALABRE is a CLI orchestrator that lets multiple AI agents installed on your machine talk to each other: Claude Code, Codex CLI, Gemini CLI, OpenCode, and Ollama.
|
|
91
|
+
PALABRE is a CLI orchestrator that lets multiple AI agents installed on your machine talk to each other: Claude Code, Codex CLI, Gemini CLI, Antigravity CLI, OpenCode, and Ollama.
|
|
91
92
|
|
|
92
93
|
It does not replace your tools: it drives them. You keep your subscriptions, default models, terminal habits, and local files. PALABRE then exports the debate as Markdown.
|
|
93
94
|
|
|
@@ -131,6 +132,7 @@ palabre codex-claude "Preview" --context src --show-prompt
|
|
|
131
132
|
- Claude Code via `claude --print`
|
|
132
133
|
- Codex CLI via `codex exec`
|
|
133
134
|
- Gemini CLI via `gemini --prompt -`
|
|
135
|
+
- Antigravity CLI via `agy --print` in a pseudo-terminal
|
|
134
136
|
- OpenCode via `opencode run`
|
|
135
137
|
- Ollama via the local HTTP API
|
|
136
138
|
|
|
@@ -138,7 +140,7 @@ PALABRE does not list models: they change often and depend on each CLI or user a
|
|
|
138
140
|
|
|
139
141
|
### Privacy
|
|
140
142
|
|
|
141
|
-
PALABRE runs locally and does not send data to a PALABRE-owned server. Data sent to agents depends on the tools you use: check the privacy policies of Claude Code, Codex CLI, Gemini CLI, OpenCode, Ollama, or any custom agent you configure.
|
|
143
|
+
PALABRE runs locally and does not send data to a PALABRE-owned server. Data sent to agents depends on the tools you use: check the privacy policies of Claude Code, Codex CLI, Gemini CLI, Antigravity CLI, OpenCode, Ollama, or any custom agent you configure.
|
|
142
144
|
|
|
143
145
|
### Local Development
|
|
144
146
|
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import { spawn as spawnPty } from "node-pty";
|
|
2
|
+
import { existsSync } from "node:fs";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { AdapterError } from "../errors.js";
|
|
5
|
+
import { formatAgentPrompt } from "../prompt.js";
|
|
6
|
+
import { cleanTerminalOutput } from "./terminal.js";
|
|
7
|
+
/**
|
|
8
|
+
* Adapter pour les CLIs qui exigent un vrai terminal.
|
|
9
|
+
* Contrairement à `CliAdapter`, stdout/stderr sont fusionnés dans le flux PTY.
|
|
10
|
+
*/
|
|
11
|
+
export class CliPtyAdapter {
|
|
12
|
+
name;
|
|
13
|
+
config;
|
|
14
|
+
role;
|
|
15
|
+
contract;
|
|
16
|
+
constructor(name, config) {
|
|
17
|
+
this.name = name;
|
|
18
|
+
this.config = config;
|
|
19
|
+
this.role = config.role;
|
|
20
|
+
this.contract = {
|
|
21
|
+
name,
|
|
22
|
+
kind: "cli-pty",
|
|
23
|
+
capabilities: {
|
|
24
|
+
mode: "pty",
|
|
25
|
+
supportsModelOverride: true,
|
|
26
|
+
supportsFilesystemAccess: true,
|
|
27
|
+
supportsStreaming: false,
|
|
28
|
+
supportsProcessExitCode: true,
|
|
29
|
+
supportsStderr: false
|
|
30
|
+
},
|
|
31
|
+
guarantees: {
|
|
32
|
+
rejectsEmptyOutput: !config.allowEmptyOutput,
|
|
33
|
+
rejectsNonZeroExit: true,
|
|
34
|
+
rejectsTimeout: true,
|
|
35
|
+
returnsRawOutput: true
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
async generate(prompt) {
|
|
40
|
+
const renderedPrompt = formatAgentPrompt(prompt);
|
|
41
|
+
const promptMode = this.config.promptMode ?? "stdin";
|
|
42
|
+
const baseArgs = withModelArgs(this.config.args ?? [], this.config.model, this.config.modelArg ?? "--model");
|
|
43
|
+
const args = promptMode === "argument"
|
|
44
|
+
? [...baseArgs, renderedPrompt]
|
|
45
|
+
: baseArgs;
|
|
46
|
+
return new Promise((resolve, reject) => {
|
|
47
|
+
let output = "";
|
|
48
|
+
let settled = false;
|
|
49
|
+
let hardTimer;
|
|
50
|
+
let term;
|
|
51
|
+
let dataSubscription;
|
|
52
|
+
let exitSubscription;
|
|
53
|
+
const finish = (error, exitCode, kill = true) => {
|
|
54
|
+
if (settled)
|
|
55
|
+
return;
|
|
56
|
+
settled = true;
|
|
57
|
+
clearTimeout(hardTimer);
|
|
58
|
+
dataSubscription?.dispose();
|
|
59
|
+
exitSubscription?.dispose();
|
|
60
|
+
if (kill) {
|
|
61
|
+
try {
|
|
62
|
+
term.kill();
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
// The PTY may already be closed.
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
cleanupPty(term);
|
|
69
|
+
if (error) {
|
|
70
|
+
reject(error);
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
const content = cleanTerminalOutput(output);
|
|
74
|
+
if (exitCode && exitCode !== 0 && !content) {
|
|
75
|
+
reject(createPtyExitError(this.name, exitCode, output));
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
if (!content && !this.config.allowEmptyOutput) {
|
|
79
|
+
reject(new AdapterError("empty-output", this.name, `${this.name} produced empty PTY output.`, {
|
|
80
|
+
raw: output
|
|
81
|
+
}));
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
resolve({
|
|
85
|
+
content,
|
|
86
|
+
raw: output
|
|
87
|
+
});
|
|
88
|
+
};
|
|
89
|
+
try {
|
|
90
|
+
term = spawnPty(resolveExecutable(this.config.command), args, {
|
|
91
|
+
name: "xterm-256color",
|
|
92
|
+
cols: this.config.cols ?? 120,
|
|
93
|
+
rows: this.config.rows ?? 40,
|
|
94
|
+
cwd: process.cwd(),
|
|
95
|
+
env: process.env,
|
|
96
|
+
...(process.platform !== "win32" ? { encoding: "utf8" } : {}),
|
|
97
|
+
...(process.platform === "win32" ? { useConpty: true } : {})
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
catch (error) {
|
|
101
|
+
reject(new AdapterError("spawn-failed", this.name, `${this.name} failed to start PTY command "${this.config.command}": ${error instanceof Error ? error.message : String(error)}`, {
|
|
102
|
+
command: this.config.command
|
|
103
|
+
}));
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
hardTimer = setTimeout(() => {
|
|
107
|
+
finish(new AdapterError("timeout", this.name, `${this.name} timed out after ${this.config.timeoutMs ?? 180_000}ms`, {
|
|
108
|
+
timeoutMs: this.config.timeoutMs ?? 180_000
|
|
109
|
+
}));
|
|
110
|
+
}, this.config.timeoutMs ?? 180_000);
|
|
111
|
+
dataSubscription = term.onData((chunk) => {
|
|
112
|
+
output += chunk;
|
|
113
|
+
});
|
|
114
|
+
exitSubscription = term.onExit(({ exitCode }) => {
|
|
115
|
+
finish(undefined, exitCode, false);
|
|
116
|
+
});
|
|
117
|
+
if (promptMode === "stdin") {
|
|
118
|
+
term.write(`${renderedPrompt}\r`);
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
function resolveExecutable(command) {
|
|
124
|
+
if (path.isAbsolute(command) || command.includes("\\") || command.includes("/")) {
|
|
125
|
+
return command;
|
|
126
|
+
}
|
|
127
|
+
for (const directory of (process.env.PATH ?? "").split(path.delimiter)) {
|
|
128
|
+
const trimmed = directory.trim();
|
|
129
|
+
if (!trimmed)
|
|
130
|
+
continue;
|
|
131
|
+
for (const extension of executableExtensions(command)) {
|
|
132
|
+
const candidate = path.join(trimmed, `${command}${extension}`);
|
|
133
|
+
if (existsSync(candidate)) {
|
|
134
|
+
return candidate;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
return command;
|
|
139
|
+
}
|
|
140
|
+
function cleanupPty(term) {
|
|
141
|
+
const maybeTerm = term;
|
|
142
|
+
try {
|
|
143
|
+
maybeTerm._agent?._cleanUpProcess?.();
|
|
144
|
+
maybeTerm._agent?._conoutSocketWorker?._worker?.terminate?.();
|
|
145
|
+
}
|
|
146
|
+
catch {
|
|
147
|
+
// Best-effort cleanup for Windows ConPTY internals.
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
function executableExtensions(command) {
|
|
151
|
+
if (path.extname(command) || process.platform !== "win32") {
|
|
152
|
+
return [""];
|
|
153
|
+
}
|
|
154
|
+
return (process.env.PATHEXT ?? ".COM;.EXE;.BAT;.CMD")
|
|
155
|
+
.split(";")
|
|
156
|
+
.map((extension) => extension.toLowerCase())
|
|
157
|
+
.concat(".ps1", "");
|
|
158
|
+
}
|
|
159
|
+
function withModelArgs(args, model, modelArg) {
|
|
160
|
+
if (!model) {
|
|
161
|
+
return [...args];
|
|
162
|
+
}
|
|
163
|
+
const promptStdinIndex = args.lastIndexOf("-");
|
|
164
|
+
if (promptStdinIndex === args.length - 1) {
|
|
165
|
+
return [
|
|
166
|
+
...args.slice(0, promptStdinIndex),
|
|
167
|
+
modelArg,
|
|
168
|
+
model,
|
|
169
|
+
...args.slice(promptStdinIndex)
|
|
170
|
+
];
|
|
171
|
+
}
|
|
172
|
+
return [...args, modelArg, model];
|
|
173
|
+
}
|
|
174
|
+
function createPtyExitError(adapterName, exitCode, raw) {
|
|
175
|
+
return new AdapterError("non-zero-exit", adapterName, `${adapterName} exited with code ${exitCode}: ${summarizePtyOutput(raw)}`, {
|
|
176
|
+
exitCode,
|
|
177
|
+
raw
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
function summarizePtyOutput(output) {
|
|
181
|
+
const cleaned = cleanTerminalOutput(output);
|
|
182
|
+
return cleaned ? cleaned.slice(-1_200) : "aucune sortie PTY capturee.";
|
|
183
|
+
}
|
package/dist/adapters/cli.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { spawn } from "node:child_process";
|
|
2
2
|
import { AdapterError } from "../errors.js";
|
|
3
3
|
import { formatAgentPrompt } from "../prompt.js";
|
|
4
|
+
import { cleanTerminalOutput } from "./terminal.js";
|
|
4
5
|
/**
|
|
5
6
|
* Adapter pour les CLIs batch (Codex, Claude, Gemini…).
|
|
6
7
|
* Lance un sous-processus, injecte le prompt via stdin ou argument, capture stdout.
|
|
@@ -107,17 +108,18 @@ export class CliAdapter {
|
|
|
107
108
|
command: this.config.command
|
|
108
109
|
}));
|
|
109
110
|
});
|
|
110
|
-
|
|
111
|
+
const finishFromExitCode = (code) => {
|
|
111
112
|
if (code && code !== 0 && !stdout.trim()) {
|
|
112
113
|
finish(createCliExitError(this.name, code, stderr));
|
|
113
114
|
return;
|
|
114
115
|
}
|
|
115
116
|
finish();
|
|
116
|
-
}
|
|
117
|
+
};
|
|
118
|
+
child.on("close", finishFromExitCode);
|
|
117
119
|
if (promptMode === "stdin") {
|
|
118
120
|
child.stdin.write(renderedPrompt);
|
|
119
|
-
child.stdin.end();
|
|
120
121
|
}
|
|
122
|
+
child.stdin.end();
|
|
121
123
|
});
|
|
122
124
|
}
|
|
123
125
|
}
|
|
@@ -142,9 +144,7 @@ function withModelArgs(args, model, modelArg) {
|
|
|
142
144
|
}
|
|
143
145
|
/** Retire les séquences ANSI et les espaces en tête/fin. */
|
|
144
146
|
function cleanCliOutput(output) {
|
|
145
|
-
return output
|
|
146
|
-
.replace(/\u001b\[[0-9;?]*[ -/]*[@-~]/g, "")
|
|
147
|
-
.trim();
|
|
147
|
+
return cleanTerminalOutput(output);
|
|
148
148
|
}
|
|
149
149
|
/**
|
|
150
150
|
* Construit une `AdapterError` typée depuis un exit code non nul.
|
package/dist/adapters/index.js
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import { CliAdapter } from "./cli.js";
|
|
2
|
+
import { CliPtyAdapter } from "./cli-pty.js";
|
|
2
3
|
import { OllamaAdapter } from "./ollama.js";
|
|
3
4
|
/** Factory qui instancie l'adapter approprié selon `config.type`. Exhaustive : tout `AgentConfig` valide produit un adapter. */
|
|
4
5
|
export function createAgent(name, config) {
|
|
5
6
|
switch (config.type) {
|
|
6
7
|
case "cli":
|
|
7
8
|
return new CliAdapter(name, config);
|
|
9
|
+
case "cli-pty":
|
|
10
|
+
return new CliPtyAdapter(name, config);
|
|
8
11
|
case "ollama":
|
|
9
12
|
return new OllamaAdapter(name, config);
|
|
10
13
|
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/** Retire les séquences de contrôle ANSI/OSC et normalise les retours ligne d'une sortie terminal. */
|
|
2
|
+
export function cleanTerminalOutput(output) {
|
|
3
|
+
return output
|
|
4
|
+
.replace(/\u001b\][^\u0007]*(?:\u0007|\u001b\\)/g, "")
|
|
5
|
+
.replace(/\u001b\[[0-9;?]*[ -/]*[@-~]/g, "")
|
|
6
|
+
.replace(/\u001b[()][A-Za-z0-9]/g, "")
|
|
7
|
+
.replace(/\u001b[=>]/g, "")
|
|
8
|
+
.replace(/\r\n/g, "\n")
|
|
9
|
+
.replace(/\r/g, "\n")
|
|
10
|
+
.replace(/\u0007/g, "")
|
|
11
|
+
.replace(/\u0000/g, "")
|
|
12
|
+
.trim();
|
|
13
|
+
}
|
package/dist/config.js
CHANGED
|
@@ -66,6 +66,19 @@ export const exampleConfig = {
|
|
|
66
66
|
role: "reviewer",
|
|
67
67
|
tier: "primary"
|
|
68
68
|
},
|
|
69
|
+
antigravity: {
|
|
70
|
+
type: "cli-pty",
|
|
71
|
+
command: "agy",
|
|
72
|
+
args: [
|
|
73
|
+
"--print-timeout",
|
|
74
|
+
"5m0s",
|
|
75
|
+
"--print"
|
|
76
|
+
],
|
|
77
|
+
promptMode: "argument",
|
|
78
|
+
role: "reviewer",
|
|
79
|
+
tier: "primary",
|
|
80
|
+
timeoutMs: 300_000
|
|
81
|
+
},
|
|
69
82
|
opencode: {
|
|
70
83
|
type: "cli",
|
|
71
84
|
command: "opencode",
|
|
@@ -155,6 +168,10 @@ export function createConfigFromDiscovery(discovery) {
|
|
|
155
168
|
...config.agents.gemini,
|
|
156
169
|
...(discovery.gemini.available ? { command: discovery.gemini.command } : {})
|
|
157
170
|
};
|
|
171
|
+
config.agents.antigravity = {
|
|
172
|
+
...config.agents.antigravity,
|
|
173
|
+
...(discovery.antigravity.available ? { command: discovery.antigravity.command } : {})
|
|
174
|
+
};
|
|
158
175
|
config.agents.opencode = {
|
|
159
176
|
...config.agents.opencode,
|
|
160
177
|
...(discovery.opencode.available ? { command: discovery.opencode.command } : {})
|
|
@@ -186,7 +203,7 @@ function chooseDefaultOllamaModel(discovery) {
|
|
|
186
203
|
return discovery.ollama.models[0] ?? DEFAULT_OLLAMA_MODEL;
|
|
187
204
|
}
|
|
188
205
|
function chooseDefaultSummaryAgent(pair) {
|
|
189
|
-
for (const preferred of ["claude", "codex", "gemini"]) {
|
|
206
|
+
for (const preferred of ["claude", "codex", "antigravity", "gemini"]) {
|
|
190
207
|
if (pair.includes(preferred)) {
|
|
191
208
|
return preferred;
|
|
192
209
|
}
|
|
@@ -206,12 +223,16 @@ function chooseDefaultPair(discovery) {
|
|
|
206
223
|
if (discovery.opencode.available && discovery.ollama.available) {
|
|
207
224
|
return ["opencode", "ollama-local"];
|
|
208
225
|
}
|
|
226
|
+
if (discovery.antigravity.available && discovery.ollama.available) {
|
|
227
|
+
return ["antigravity", "ollama-local"];
|
|
228
|
+
}
|
|
209
229
|
if (discovery.gemini.available && discovery.ollama.available) {
|
|
210
230
|
return ["gemini", "ollama-local"];
|
|
211
231
|
}
|
|
212
232
|
const cliAgents = [
|
|
213
233
|
discovery.codex.available ? "codex" : undefined,
|
|
214
234
|
discovery.claude.available ? "claude" : undefined,
|
|
235
|
+
discovery.antigravity.available ? "antigravity" : undefined,
|
|
215
236
|
discovery.opencode.available ? "opencode" : undefined,
|
|
216
237
|
discovery.gemini.available ? "gemini" : undefined
|
|
217
238
|
].filter((agent) => Boolean(agent));
|
package/dist/discovery.js
CHANGED
|
@@ -5,10 +5,11 @@ import path from "node:path";
|
|
|
5
5
|
* Sur Windows, tente `claude.exe` avant `claude`.
|
|
6
6
|
*/
|
|
7
7
|
export async function discoverLocalTools() {
|
|
8
|
-
const [codex, claude, gemini, opencode, ollamaCommand] = await Promise.all([
|
|
8
|
+
const [codex, claude, gemini, antigravity, opencode, ollamaCommand] = await Promise.all([
|
|
9
9
|
detectCommand("codex"),
|
|
10
10
|
detectFirstCommand(process.platform === "win32" ? ["claude.exe", "claude"] : ["claude"]),
|
|
11
11
|
detectCommand("gemini"),
|
|
12
|
+
detectCommand("agy"),
|
|
12
13
|
detectCommand("opencode"),
|
|
13
14
|
detectCommand("ollama")
|
|
14
15
|
]);
|
|
@@ -17,6 +18,7 @@ export async function discoverLocalTools() {
|
|
|
17
18
|
codex,
|
|
18
19
|
claude,
|
|
19
20
|
gemini,
|
|
21
|
+
antigravity,
|
|
20
22
|
opencode,
|
|
21
23
|
ollama: {
|
|
22
24
|
...ollamaServer,
|
package/dist/doctor.js
CHANGED
|
@@ -41,6 +41,7 @@ export async function runDoctor(explicitConfigPath, plain = false, explicitLangu
|
|
|
41
41
|
lines.push(formatCommand("Codex CLI", discovery.codex.available, discovery.codex.command, discovery.codex.path, t));
|
|
42
42
|
lines.push(formatCommand("Claude CLI", discovery.claude.available, discovery.claude.command, discovery.claude.path, t));
|
|
43
43
|
lines.push(formatCommand("Gemini CLI", discovery.gemini.available, discovery.gemini.command, discovery.gemini.path, t));
|
|
44
|
+
lines.push(formatCommand("Antigravity CLI", discovery.antigravity.available, discovery.antigravity.command, discovery.antigravity.path, t));
|
|
44
45
|
lines.push(formatCommand("OpenCode CLI", discovery.opencode.available, discovery.opencode.command, discovery.opencode.path, t));
|
|
45
46
|
lines.push(discovery.ollama.available
|
|
46
47
|
? ok(t.doctor.ollamaReachable(discovery.ollama.baseUrl, discovery.ollama.models.length))
|
|
@@ -156,7 +157,7 @@ function inspectAgents(config, discovery, lines, t) {
|
|
|
156
157
|
lines.push(info(t.doctor.configuredAgents, "agents"));
|
|
157
158
|
for (const [name, agent] of Object.entries(config.agents)) {
|
|
158
159
|
inspectAgentShape(name, agent, lines, t);
|
|
159
|
-
if (agent.type === "cli") {
|
|
160
|
+
if (agent.type === "cli" || agent.type === "cli-pty") {
|
|
160
161
|
inspectCliAgent(name, agent, discovery, lines, t);
|
|
161
162
|
continue;
|
|
162
163
|
}
|
|
@@ -167,7 +168,7 @@ function inspectAgentShape(name, agent, lines, t) {
|
|
|
167
168
|
if (!agent.role) {
|
|
168
169
|
lines.push(error(t.doctor.roleMissing(name)));
|
|
169
170
|
}
|
|
170
|
-
if (agent.type === "cli") {
|
|
171
|
+
if (agent.type === "cli" || agent.type === "cli-pty") {
|
|
171
172
|
if (!agent.command || !agent.command.trim()) {
|
|
172
173
|
lines.push(error(t.doctor.cliCommandMissing(name)));
|
|
173
174
|
}
|
|
@@ -223,6 +224,7 @@ function detectedAgentNames(discovery) {
|
|
|
223
224
|
discovery.codex.available ? "codex" : undefined,
|
|
224
225
|
discovery.claude.available ? "claude" : undefined,
|
|
225
226
|
discovery.gemini.available ? "gemini" : undefined,
|
|
227
|
+
discovery.antigravity.available ? "antigravity" : undefined,
|
|
226
228
|
discovery.opencode.available ? "opencode" : undefined,
|
|
227
229
|
discovery.ollama.available ? "ollama-local" : undefined
|
|
228
230
|
].filter((name) => Boolean(name));
|
|
@@ -240,6 +242,10 @@ function knownCliDetection(command, discovery) {
|
|
|
240
242
|
return discovery.claude;
|
|
241
243
|
if (normalized === "gemini")
|
|
242
244
|
return discovery.gemini;
|
|
245
|
+
if (normalized === "agy")
|
|
246
|
+
return discovery.antigravity;
|
|
247
|
+
if (normalized === "antigravity")
|
|
248
|
+
return discovery.antigravity;
|
|
243
249
|
if (normalized === "opencode")
|
|
244
250
|
return discovery.opencode;
|
|
245
251
|
return undefined;
|
package/dist/index.js
CHANGED
|
@@ -699,6 +699,7 @@ function findDetectedMissingAgents(config, discovery) {
|
|
|
699
699
|
discovery.codex.available ? "codex" : undefined,
|
|
700
700
|
discovery.claude.available ? "claude" : undefined,
|
|
701
701
|
discovery.gemini.available ? "gemini" : undefined,
|
|
702
|
+
discovery.antigravity.available ? "antigravity" : undefined,
|
|
702
703
|
discovery.opencode.available ? "opencode" : undefined,
|
|
703
704
|
discovery.ollama.available ? "ollama-local" : undefined
|
|
704
705
|
].filter((agent) => Boolean(agent));
|
|
@@ -780,16 +781,20 @@ function formatAgentDetection(name, agentConfig, discovery, messages) {
|
|
|
780
781
|
* @param discovery - Résultat de la découverte locale des outils.
|
|
781
782
|
*/
|
|
782
783
|
function cliDetectionForAgent(name, agentConfig, discovery) {
|
|
783
|
-
const command = normalizeCommandName(agentConfig.type === "cli" ? agentConfig.command : name);
|
|
784
|
+
const command = normalizeCommandName(agentConfig.type === "cli" || agentConfig.type === "cli-pty" ? agentConfig.command : name);
|
|
784
785
|
if (command === "codex")
|
|
785
786
|
return discovery.codex;
|
|
786
787
|
if (command === "claude")
|
|
787
788
|
return discovery.claude;
|
|
788
789
|
if (command === "gemini")
|
|
789
790
|
return discovery.gemini;
|
|
791
|
+
if (command === "agy")
|
|
792
|
+
return discovery.antigravity;
|
|
793
|
+
if (command === "antigravity")
|
|
794
|
+
return discovery.antigravity;
|
|
790
795
|
if (command === "opencode")
|
|
791
796
|
return discovery.opencode;
|
|
792
|
-
return { available: true, command: agentConfig.type === "cli" ? agentConfig.command : name };
|
|
797
|
+
return { available: true, command: agentConfig.type === "cli" || agentConfig.type === "cli-pty" ? agentConfig.command : name };
|
|
793
798
|
}
|
|
794
799
|
/**
|
|
795
800
|
* Extrait le nom de base d'une commande en supprimant le chemin et l'extension Windows éventuelle.
|
|
@@ -809,6 +814,7 @@ function printInitDiscovery(discovery, config, messages) {
|
|
|
809
814
|
console.log(`- Codex CLI: ${formatCommandDetection(discovery.codex, messages)}`);
|
|
810
815
|
console.log(`- Claude CLI: ${formatCommandDetection(discovery.claude, messages)}`);
|
|
811
816
|
console.log(`- Gemini CLI: ${formatCommandDetection(discovery.gemini, messages)}`);
|
|
817
|
+
console.log(`- Antigravity CLI: ${formatCommandDetection(discovery.antigravity, messages)}`);
|
|
812
818
|
console.log(`- OpenCode CLI: ${formatCommandDetection(discovery.opencode, messages)}`);
|
|
813
819
|
console.log(`- Ollama API: ${formatOllamaDetection(discovery.ollama, messages)}`);
|
|
814
820
|
console.log("");
|
|
@@ -822,6 +828,7 @@ function formatDetectedAgentSummary(discovery, language) {
|
|
|
822
828
|
discovery.codex.available ? "codex" : undefined,
|
|
823
829
|
discovery.claude.available ? "claude" : undefined,
|
|
824
830
|
discovery.gemini.available ? "gemini" : undefined,
|
|
831
|
+
discovery.antigravity.available ? "antigravity" : undefined,
|
|
825
832
|
discovery.opencode.available ? "opencode" : undefined,
|
|
826
833
|
discovery.ollama.available ? "ollama-local" : undefined
|
|
827
834
|
].filter((name) => Boolean(name));
|
package/dist/messages/init.js
CHANGED
|
@@ -10,7 +10,7 @@ export const initMessages = {
|
|
|
10
10
|
ollamaMissing: "non détecté",
|
|
11
11
|
ollamaDetected: (modelCount) => `détectée (${modelCount} modèle${modelCount > 1 ? "s" : ""})`,
|
|
12
12
|
defaults: (agentA, agentB) => `Défauts: ${agentA} <-> ${agentB}`,
|
|
13
|
-
noDefaultPair: (detectedAgents) => `Défauts: ${detectedAgents}. Palabre a besoin d'au moins deux agents.\nAgents compatibles: Codex CLI, Claude CLI, Gemini CLI, OpenCode CLI, Ollama local.\nGuide: https://palab.re/fr/agents/overview`,
|
|
13
|
+
noDefaultPair: (detectedAgents) => `Défauts: ${detectedAgents}. Palabre a besoin d'au moins deux agents.\nAgents compatibles: Codex CLI, Claude CLI, Gemini CLI, Antigravity CLI, OpenCode CLI, Ollama local.\nGuide: https://palab.re/fr/agents/overview`,
|
|
14
14
|
languageHint: (language) => `Langue: ${language}\nEnglish > palabre config --language en`
|
|
15
15
|
},
|
|
16
16
|
en: {
|
|
@@ -24,7 +24,7 @@ export const initMessages = {
|
|
|
24
24
|
ollamaMissing: "not detected",
|
|
25
25
|
ollamaDetected: (modelCount) => `detected (${modelCount} model${modelCount > 1 ? "s" : ""})`,
|
|
26
26
|
defaults: (agentA, agentB) => `Defaults: ${agentA} <-> ${agentB}`,
|
|
27
|
-
noDefaultPair: (detectedAgents) => `Defaults: ${detectedAgents}. Palabre needs at least two agents.\nCompatible agents: Codex CLI, Claude CLI, Gemini CLI, OpenCode CLI, local Ollama.\nGuide: https://palab.re/en/agents/overview`,
|
|
27
|
+
noDefaultPair: (detectedAgents) => `Defaults: ${detectedAgents}. Palabre needs at least two agents.\nCompatible agents: Codex CLI, Claude CLI, Gemini CLI, Antigravity CLI, OpenCode CLI, local Ollama.\nGuide: https://palab.re/en/agents/overview`,
|
|
28
28
|
languageHint: (language) => `Language: ${language}\nFrançais > palabre config --language fr`
|
|
29
29
|
}
|
|
30
30
|
};
|
package/dist/new.js
CHANGED
|
@@ -147,6 +147,10 @@ function isAgentDetected(name, config, discovery) {
|
|
|
147
147
|
return discovery.claude.available;
|
|
148
148
|
if (normalized === "gemini")
|
|
149
149
|
return discovery.gemini.available;
|
|
150
|
+
if (normalized === "agy")
|
|
151
|
+
return discovery.antigravity.available;
|
|
152
|
+
if (normalized === "antigravity")
|
|
153
|
+
return discovery.antigravity.available;
|
|
150
154
|
if (normalized === "opencode")
|
|
151
155
|
return discovery.opencode.available;
|
|
152
156
|
return true;
|
package/dist/presets.js
CHANGED
|
@@ -16,6 +16,14 @@ const presets = {
|
|
|
16
16
|
agentA: "opencode",
|
|
17
17
|
agentB: "codex"
|
|
18
18
|
},
|
|
19
|
+
"codex-antigravity": {
|
|
20
|
+
agentA: "codex",
|
|
21
|
+
agentB: "antigravity"
|
|
22
|
+
},
|
|
23
|
+
"antigravity-codex": {
|
|
24
|
+
agentA: "antigravity",
|
|
25
|
+
agentB: "codex"
|
|
26
|
+
},
|
|
19
27
|
"claude-opencode": {
|
|
20
28
|
agentA: "claude",
|
|
21
29
|
agentB: "opencode"
|
|
@@ -24,6 +32,14 @@ const presets = {
|
|
|
24
32
|
agentA: "opencode",
|
|
25
33
|
agentB: "claude"
|
|
26
34
|
},
|
|
35
|
+
"claude-antigravity": {
|
|
36
|
+
agentA: "claude",
|
|
37
|
+
agentB: "antigravity"
|
|
38
|
+
},
|
|
39
|
+
"antigravity-claude": {
|
|
40
|
+
agentA: "antigravity",
|
|
41
|
+
agentB: "claude"
|
|
42
|
+
},
|
|
27
43
|
"gemini-opencode": {
|
|
28
44
|
agentA: "gemini",
|
|
29
45
|
agentB: "opencode"
|
|
@@ -32,6 +48,22 @@ const presets = {
|
|
|
32
48
|
agentA: "opencode",
|
|
33
49
|
agentB: "gemini"
|
|
34
50
|
},
|
|
51
|
+
"gemini-antigravity": {
|
|
52
|
+
agentA: "gemini",
|
|
53
|
+
agentB: "antigravity"
|
|
54
|
+
},
|
|
55
|
+
"antigravity-gemini": {
|
|
56
|
+
agentA: "antigravity",
|
|
57
|
+
agentB: "gemini"
|
|
58
|
+
},
|
|
59
|
+
"opencode-antigravity": {
|
|
60
|
+
agentA: "opencode",
|
|
61
|
+
agentB: "antigravity"
|
|
62
|
+
},
|
|
63
|
+
"antigravity-opencode": {
|
|
64
|
+
agentA: "antigravity",
|
|
65
|
+
agentB: "opencode"
|
|
66
|
+
},
|
|
35
67
|
"opencode-ollama": {
|
|
36
68
|
agentA: "opencode",
|
|
37
69
|
agentB: "ollama-local"
|
|
@@ -64,6 +96,14 @@ const presets = {
|
|
|
64
96
|
agentA: "ollama-local",
|
|
65
97
|
agentB: "gemini"
|
|
66
98
|
},
|
|
99
|
+
"antigravity-ollama": {
|
|
100
|
+
agentA: "antigravity",
|
|
101
|
+
agentB: "ollama-local"
|
|
102
|
+
},
|
|
103
|
+
"ollama-antigravity": {
|
|
104
|
+
agentA: "ollama-local",
|
|
105
|
+
agentB: "antigravity"
|
|
106
|
+
},
|
|
67
107
|
"codex-gemini": {
|
|
68
108
|
agentA: "codex",
|
|
69
109
|
agentB: "gemini"
|
|
@@ -159,6 +199,10 @@ function knownCliDetection(agent, discovery) {
|
|
|
159
199
|
return discovery.claude;
|
|
160
200
|
if (command === "gemini")
|
|
161
201
|
return discovery.gemini;
|
|
202
|
+
if (command === "agy")
|
|
203
|
+
return discovery.antigravity;
|
|
204
|
+
if (command === "antigravity")
|
|
205
|
+
return discovery.antigravity;
|
|
162
206
|
if (command === "opencode")
|
|
163
207
|
return discovery.opencode;
|
|
164
208
|
return undefined;
|
|
@@ -27,7 +27,7 @@ class PrettyConsoleRenderer {
|
|
|
27
27
|
}
|
|
28
28
|
/** Affiche l'en-tête du débat (sujet, agents, options). */
|
|
29
29
|
start(options, agents = []) {
|
|
30
|
-
const title = "PALABRE";
|
|
30
|
+
const title = "PALABRE CLI";
|
|
31
31
|
process.stdout.write([
|
|
32
32
|
"",
|
|
33
33
|
this.c("cyan", `┌─ ${title} ${"─".repeat(Math.max(1, 54 - title.length))}`),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "palabre",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "Orchestrateur de debat entre agents IA locaux, CLIs et Ollama.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -43,6 +43,9 @@
|
|
|
43
43
|
"engines": {
|
|
44
44
|
"node": ">=20"
|
|
45
45
|
},
|
|
46
|
+
"dependencies": {
|
|
47
|
+
"node-pty": "^1.1.0"
|
|
48
|
+
},
|
|
46
49
|
"devDependencies": {
|
|
47
50
|
"@types/node": "^20.12.0",
|
|
48
51
|
"typescript": "^5.4.0"
|