palabre 0.3.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 +266 -256
- 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/config.js
CHANGED
|
@@ -6,8 +6,11 @@ export const LEGACY_CONFIG_PATH = "chicane.config.json";
|
|
|
6
6
|
export const CONFIG_DIR_NAME = ".palabre";
|
|
7
7
|
export const GLOBAL_CONFIG_PATH = path.join(os.homedir(), CONFIG_DIR_NAME, DEFAULT_CONFIG_PATH);
|
|
8
8
|
export const GLOBAL_LEGACY_CONFIG_PATH = path.join(os.homedir(), CONFIG_DIR_NAME, LEGACY_CONFIG_PATH);
|
|
9
|
+
export const DEFAULT_OLLAMA_MODEL = "nemotron-3-nano:4b";
|
|
10
|
+
export const DEFAULT_OUTPUT_DIR = ".palabre";
|
|
9
11
|
export const exampleConfig = {
|
|
10
|
-
|
|
12
|
+
language: "fr",
|
|
13
|
+
outputDir: DEFAULT_OUTPUT_DIR,
|
|
11
14
|
defaults: {
|
|
12
15
|
agentA: "codex",
|
|
13
16
|
agentB: "claude",
|
|
@@ -78,7 +81,7 @@ export const exampleConfig = {
|
|
|
78
81
|
"ollama-local": {
|
|
79
82
|
type: "ollama",
|
|
80
83
|
baseUrl: "http://localhost:11434",
|
|
81
|
-
model:
|
|
84
|
+
model: DEFAULT_OLLAMA_MODEL,
|
|
82
85
|
role: "critic",
|
|
83
86
|
tier: "local",
|
|
84
87
|
temperature: 0.2,
|
|
@@ -87,6 +90,15 @@ export const exampleConfig = {
|
|
|
87
90
|
}
|
|
88
91
|
}
|
|
89
92
|
};
|
|
93
|
+
/**
|
|
94
|
+
* Résout le dossier d'export effectif.
|
|
95
|
+
* `.` est traité comme l'ancien défaut historique afin de regrouper les exports
|
|
96
|
+
* dans un dossier dédié sans demander de migration manuelle aux utilisateurs.
|
|
97
|
+
*/
|
|
98
|
+
export function resolveOutputDir(outputDir) {
|
|
99
|
+
const normalized = outputDir?.trim();
|
|
100
|
+
return !normalized || normalized === "." ? DEFAULT_OUTPUT_DIR : normalized;
|
|
101
|
+
}
|
|
90
102
|
/** Charge et parse la config depuis `configPath`. Lance une erreur si le fichier est absent ou invalide. */
|
|
91
103
|
export async function loadConfig(configPath = DEFAULT_CONFIG_PATH) {
|
|
92
104
|
const resolved = path.resolve(configPath);
|
|
@@ -126,7 +138,7 @@ export async function resolveDefaultConfigPath() {
|
|
|
126
138
|
/**
|
|
127
139
|
* Construit une `PalabreConfig` complète à partir des outils détectés localement.
|
|
128
140
|
* Ajuste `defaults.agentA/agentB/summaryAgent` en fonction de la paire disponible.
|
|
129
|
-
* Si aucune paire n'est détectée,
|
|
141
|
+
* Si aucune paire n'est détectée, seuls les defaults sans agent sont conservés.
|
|
130
142
|
*/
|
|
131
143
|
export function createConfigFromDiscovery(discovery) {
|
|
132
144
|
const config = cloneConfig(exampleConfig);
|
|
@@ -147,10 +159,18 @@ export function createConfigFromDiscovery(discovery) {
|
|
|
147
159
|
...config.agents.opencode,
|
|
148
160
|
...(discovery.opencode.available ? { command: discovery.opencode.command } : {})
|
|
149
161
|
};
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
}
|
|
162
|
+
const ollamaAgent = config.agents["ollama-local"];
|
|
163
|
+
if (ollamaAgent?.type === "ollama") {
|
|
164
|
+
ollamaAgent.model = chooseDefaultOllamaModel(discovery);
|
|
165
|
+
}
|
|
166
|
+
config.defaults = pair
|
|
167
|
+
? {
|
|
168
|
+
...config.defaults,
|
|
169
|
+
agentA: pair[0],
|
|
170
|
+
agentB: pair[1],
|
|
171
|
+
summaryAgent: chooseDefaultSummaryAgent(pair)
|
|
172
|
+
}
|
|
173
|
+
: { turns: config.defaults?.turns };
|
|
154
174
|
return config;
|
|
155
175
|
}
|
|
156
176
|
/** Écrit `config` sérialisé en JSON dans `configPath`. Crée le répertoire parent si nécessaire. */
|
|
@@ -159,6 +179,12 @@ export async function writeExampleConfig(configPath = DEFAULT_CONFIG_PATH, confi
|
|
|
159
179
|
await mkdir(path.dirname(resolved), { recursive: true });
|
|
160
180
|
await writeFile(resolved, `${JSON.stringify(config, null, 2)}\n`, "utf8");
|
|
161
181
|
}
|
|
182
|
+
function chooseDefaultOllamaModel(discovery) {
|
|
183
|
+
if (discovery.ollama.models.includes(DEFAULT_OLLAMA_MODEL)) {
|
|
184
|
+
return DEFAULT_OLLAMA_MODEL;
|
|
185
|
+
}
|
|
186
|
+
return discovery.ollama.models[0] ?? DEFAULT_OLLAMA_MODEL;
|
|
187
|
+
}
|
|
162
188
|
function chooseDefaultSummaryAgent(pair) {
|
|
163
189
|
for (const preferred of ["claude", "codex", "gemini"]) {
|
|
164
190
|
if (pair.includes(preferred)) {
|
package/dist/configWizard.js
CHANGED
|
@@ -7,47 +7,47 @@ import { DEFAULT_TURNS, MAX_TURNS, turnsOrDefault, validateTurns } from "./limit
|
|
|
7
7
|
* Fonctionne en mode TTY (readline) et en mode piped (stdin lu en avance).
|
|
8
8
|
* Écrit la config sur disque si l'utilisateur confirme ; sort sans modifier si l'utilisateur quitte.
|
|
9
9
|
*/
|
|
10
|
-
export async function runConfigWizard(configPath, config) {
|
|
10
|
+
export async function runConfigWizard(configPath, config, messages) {
|
|
11
11
|
const choices = Object.entries(config.agents).map(([name, agentConfig]) => ({ name, config: agentConfig }));
|
|
12
12
|
if (choices.length < 2) {
|
|
13
|
-
throw new Error(
|
|
13
|
+
throw new Error(messages.config.wizardNeedsTwoAgents);
|
|
14
14
|
}
|
|
15
15
|
const rl = await createQuestioner();
|
|
16
16
|
try {
|
|
17
|
-
console.log(
|
|
18
|
-
console.log(
|
|
17
|
+
console.log(messages.config.wizardTitle);
|
|
18
|
+
console.log(messages.config.wizardQuitHint);
|
|
19
19
|
console.log("");
|
|
20
|
-
console.log(
|
|
20
|
+
console.log(messages.config.wizardConfigFile);
|
|
21
21
|
console.log(` ${configPath}`);
|
|
22
22
|
console.log("");
|
|
23
|
-
console.log(
|
|
24
|
-
console.log(` ${config.defaults ? formatDefaults(config.defaults) :
|
|
23
|
+
console.log(messages.config.wizardCurrentDefaults);
|
|
24
|
+
console.log(` ${config.defaults ? formatDefaults(config.defaults, messages) : messages.config.wizardNoDefaults}`);
|
|
25
25
|
console.log("");
|
|
26
|
-
console.log(
|
|
27
|
-
console.log(
|
|
28
|
-
console.log(
|
|
29
|
-
console.log(
|
|
30
|
-
const action = await askChoice(rl,
|
|
26
|
+
console.log(messages.config.wizardActionQuestion);
|
|
27
|
+
console.log(` 1) ${messages.config.wizardActionSetDefaults}`);
|
|
28
|
+
console.log(` 2) ${messages.config.wizardActionClearDefaults}`);
|
|
29
|
+
console.log(` 3) ${messages.config.wizardActionExit}`);
|
|
30
|
+
const action = await askChoice(rl, messages.config.wizardChoicePrompt, "1", ["1", "2", "3"], messages);
|
|
31
31
|
if (!action || action === "3") {
|
|
32
|
-
console.log(
|
|
32
|
+
console.log(messages.config.wizardUnchanged);
|
|
33
33
|
return;
|
|
34
34
|
}
|
|
35
35
|
if (action === "2") {
|
|
36
36
|
delete config.defaults;
|
|
37
37
|
await writeExampleConfig(configPath, config);
|
|
38
|
-
console.log(
|
|
38
|
+
console.log(messages.config.wizardCleared(configPath));
|
|
39
39
|
return;
|
|
40
40
|
}
|
|
41
|
-
const agentA = await askAgent(rl, choices,
|
|
41
|
+
const agentA = await askAgent(rl, choices, messages.config.wizardAgentADescription, config.defaults?.agentA, messages);
|
|
42
42
|
if (!agentA)
|
|
43
43
|
return;
|
|
44
|
-
const agentB = await askAgent(rl, choices.filter((choice) => choice.name !== agentA),
|
|
44
|
+
const agentB = await askAgent(rl, choices.filter((choice) => choice.name !== agentA), messages.config.wizardAgentBDescription, config.defaults?.agentB === agentA ? undefined : config.defaults?.agentB, messages);
|
|
45
45
|
if (!agentB)
|
|
46
46
|
return;
|
|
47
|
-
const turns = await askNumber(rl,
|
|
47
|
+
const turns = await askNumber(rl, messages.config.wizardTurnsLabel, turnsOrDefault(config.defaults?.turns), Boolean(config.defaults?.turns), messages);
|
|
48
48
|
if (turns === undefined)
|
|
49
49
|
return;
|
|
50
|
-
const summaryAgent = await askSummaryAgent(rl, choices, config.defaults?.summaryAgent ?? agentB, Boolean(config.defaults?.summaryAgent), agentB);
|
|
50
|
+
const summaryAgent = await askSummaryAgent(rl, choices, config.defaults?.summaryAgent ?? agentB, Boolean(config.defaults?.summaryAgent), agentB, messages);
|
|
51
51
|
if (summaryAgent === undefined)
|
|
52
52
|
return;
|
|
53
53
|
config.defaults = {
|
|
@@ -57,7 +57,7 @@ export async function runConfigWizard(configPath, config) {
|
|
|
57
57
|
turns
|
|
58
58
|
};
|
|
59
59
|
await writeExampleConfig(configPath, config);
|
|
60
|
-
console.log(
|
|
60
|
+
console.log(messages.config.wizardDefaultsSet(configPath, formatDefaults(config.defaults, messages)));
|
|
61
61
|
}
|
|
62
62
|
finally {
|
|
63
63
|
rl.close();
|
|
@@ -89,9 +89,9 @@ async function readPipedLines() {
|
|
|
89
89
|
}
|
|
90
90
|
return raw ? raw.replace(/\r\n/g, "\n").replace(/\r/g, "\n").split("\n") : [];
|
|
91
91
|
}
|
|
92
|
-
async function askAgent(rl, choices,
|
|
92
|
+
async function askAgent(rl, choices, description, defaultName, messages) {
|
|
93
93
|
const fallback = choices.find((choice) => choice.name === defaultName)?.name ?? choices[0]?.name;
|
|
94
|
-
const fallbackLabel = defaultName ?
|
|
94
|
+
const fallbackLabel = defaultName ? messages.config.wizardCurrent : messages.config.wizardSuggestion;
|
|
95
95
|
console.log("");
|
|
96
96
|
console.log(description);
|
|
97
97
|
console.log(`${fallbackLabel} : ${fallback}`);
|
|
@@ -100,7 +100,7 @@ async function askAgent(rl, choices, _label, description, defaultName) {
|
|
|
100
100
|
console.log(` ${index + 1}) ${formatAgentLine(choice)}`);
|
|
101
101
|
});
|
|
102
102
|
while (true) {
|
|
103
|
-
const answer = await rl.question(
|
|
103
|
+
const answer = await rl.question(messages.config.wizardAgentPrompt(fallback));
|
|
104
104
|
const value = answer.trim();
|
|
105
105
|
if (isQuit(value))
|
|
106
106
|
return undefined;
|
|
@@ -113,22 +113,22 @@ async function askAgent(rl, choices, _label, description, defaultName) {
|
|
|
113
113
|
if (choices.some((choice) => choice.name === value)) {
|
|
114
114
|
return value;
|
|
115
115
|
}
|
|
116
|
-
console.log(
|
|
116
|
+
console.log(messages.config.wizardInvalidAgentChoice);
|
|
117
117
|
}
|
|
118
118
|
}
|
|
119
|
-
async function askSummaryAgent(rl, choices, defaultName, hasCurrentDefault, agentB) {
|
|
119
|
+
async function askSummaryAgent(rl, choices, defaultName, hasCurrentDefault, agentB, messages) {
|
|
120
120
|
const fallback = choices.some((choice) => choice.name === defaultName) ? defaultName : choices[0]?.name;
|
|
121
|
-
const fallbackLabel = hasCurrentDefault ?
|
|
121
|
+
const fallbackLabel = hasCurrentDefault ? messages.config.wizardCurrent : messages.config.wizardSuggestion;
|
|
122
122
|
console.log("");
|
|
123
|
-
console.log(
|
|
124
|
-
console.log(`${fallbackLabel} : ${fallback}${!hasCurrentDefault && fallback === agentB ?
|
|
123
|
+
console.log(messages.config.wizardSummaryTitle);
|
|
124
|
+
console.log(`${fallbackLabel} : ${fallback}${!hasCurrentDefault && fallback === agentB ? ` (${messages.config.wizardAgentBHint})` : ""}`);
|
|
125
125
|
console.log("");
|
|
126
|
-
console.log(
|
|
126
|
+
console.log(` 0) ${messages.config.wizardNoSummary}`);
|
|
127
127
|
choices.forEach((choice, index) => {
|
|
128
128
|
console.log(` ${index + 1}) ${formatAgentLine(choice)}`);
|
|
129
129
|
});
|
|
130
130
|
while (true) {
|
|
131
|
-
const answer = await rl.question(
|
|
131
|
+
const answer = await rl.question(messages.config.wizardSummaryPrompt(fallback));
|
|
132
132
|
const value = answer.trim();
|
|
133
133
|
if (isQuit(value))
|
|
134
134
|
return undefined;
|
|
@@ -143,12 +143,12 @@ async function askSummaryAgent(rl, choices, defaultName, hasCurrentDefault, agen
|
|
|
143
143
|
if (choices.some((choice) => choice.name === value)) {
|
|
144
144
|
return value;
|
|
145
145
|
}
|
|
146
|
-
console.log(
|
|
146
|
+
console.log(messages.config.wizardInvalidSummaryChoice);
|
|
147
147
|
}
|
|
148
148
|
}
|
|
149
|
-
async function askChoice(rl, label, defaultValue, allowed) {
|
|
149
|
+
async function askChoice(rl, label, defaultValue, allowed, messages) {
|
|
150
150
|
while (true) {
|
|
151
|
-
const answer = await rl.question(
|
|
151
|
+
const answer = await rl.question(messages.config.wizardChoiceQuestion(label, defaultValue));
|
|
152
152
|
const value = answer.trim();
|
|
153
153
|
if (isQuit(value))
|
|
154
154
|
return undefined;
|
|
@@ -156,17 +156,17 @@ async function askChoice(rl, label, defaultValue, allowed) {
|
|
|
156
156
|
return defaultValue;
|
|
157
157
|
if (allowed.includes(value))
|
|
158
158
|
return value;
|
|
159
|
-
console.log(
|
|
159
|
+
console.log(messages.config.wizardInvalidChoice(allowed.join(", ")));
|
|
160
160
|
}
|
|
161
161
|
}
|
|
162
|
-
async function askNumber(rl, label, defaultValue, hasCurrentDefault) {
|
|
163
|
-
const fallbackLabel = hasCurrentDefault ?
|
|
162
|
+
async function askNumber(rl, label, defaultValue, hasCurrentDefault, messages) {
|
|
163
|
+
const fallbackLabel = hasCurrentDefault ? messages.config.wizardCurrent : messages.config.wizardSuggestion;
|
|
164
164
|
console.log("");
|
|
165
165
|
console.log(label);
|
|
166
166
|
console.log(`${fallbackLabel} : ${defaultValue}`);
|
|
167
167
|
console.log("");
|
|
168
168
|
while (true) {
|
|
169
|
-
const answer = await rl.question(
|
|
169
|
+
const answer = await rl.question(messages.config.wizardTurnsPrompt(defaultValue));
|
|
170
170
|
const value = answer.trim();
|
|
171
171
|
if (isQuit(value))
|
|
172
172
|
return undefined;
|
|
@@ -175,21 +175,26 @@ async function askNumber(rl, label, defaultValue, hasCurrentDefault) {
|
|
|
175
175
|
const parsed = Number(value);
|
|
176
176
|
if (Number.isInteger(parsed)) {
|
|
177
177
|
try {
|
|
178
|
-
validateTurns(parsed,
|
|
178
|
+
validateTurns(parsed, messages.config.wizardTurnsLabel, messages);
|
|
179
179
|
return parsed;
|
|
180
180
|
}
|
|
181
181
|
catch {
|
|
182
182
|
// Show the user-facing wizard hint below.
|
|
183
183
|
}
|
|
184
184
|
}
|
|
185
|
-
console.log(
|
|
185
|
+
console.log(messages.config.wizardTurnsInvalid(MAX_TURNS));
|
|
186
186
|
}
|
|
187
187
|
}
|
|
188
188
|
function formatAgentLine(choice) {
|
|
189
189
|
return `${choice.name.padEnd(12)} ${choice.config.type} / ${choice.config.role}`;
|
|
190
190
|
}
|
|
191
|
-
function formatDefaults(defaults) {
|
|
192
|
-
return
|
|
191
|
+
function formatDefaults(defaults, messages) {
|
|
192
|
+
return messages.config.wizardDefaults({
|
|
193
|
+
agentA: defaults.agentA,
|
|
194
|
+
agentB: defaults.agentB,
|
|
195
|
+
turns: turnsOrDefault(defaults.turns ?? DEFAULT_TURNS),
|
|
196
|
+
summaryAgent: defaults.summaryAgent
|
|
197
|
+
});
|
|
193
198
|
}
|
|
194
199
|
function isQuit(value) {
|
|
195
200
|
return ["q", "quit", "exit"].includes(value.toLowerCase());
|
package/dist/context.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { readdir, readFile, stat } from "node:fs/promises";
|
|
2
2
|
import path from "node:path";
|
|
3
|
+
import { createTranslator } from "./i18n.js";
|
|
3
4
|
const MAX_FILE_BYTES = 64 * 1024;
|
|
4
5
|
const MAX_TOTAL_BYTES = 192 * 1024;
|
|
5
6
|
const DEFAULT_EXCLUDED_NAMES = new Set([
|
|
@@ -32,8 +33,8 @@ const TEXT_EXTENSIONS = new Set([
|
|
|
32
33
|
* Mode strict (`--files`) : charge uniquement les fichiers explicitement listés.
|
|
33
34
|
* Lève une erreur si un chemin est un dossier, un binaire, ou dépasse 64 KiB / 192 KiB au total.
|
|
34
35
|
*/
|
|
35
|
-
export async function loadProjectFiles(paths, cwd = process.cwd()) {
|
|
36
|
-
const result = await loadProjectInputs(paths, [], cwd);
|
|
36
|
+
export async function loadProjectFiles(paths, cwd = process.cwd(), messages = createTranslator("fr")) {
|
|
37
|
+
const result = await loadProjectInputs(paths, [], cwd, messages);
|
|
37
38
|
return result.files;
|
|
38
39
|
}
|
|
39
40
|
/**
|
|
@@ -41,13 +42,14 @@ export async function loadProjectFiles(paths, cwd = process.cwd()) {
|
|
|
41
42
|
* Les fichiers explicites sont chargés en premier et comptent dans le budget total.
|
|
42
43
|
* Les chemins de contexte acceptent fichiers et dossiers ; les fichiers ignorés génèrent des warnings, pas des erreurs.
|
|
43
44
|
*/
|
|
44
|
-
export async function loadProjectInputs(filePaths, contextPaths, cwd = process.cwd()) {
|
|
45
|
+
export async function loadProjectInputs(filePaths, contextPaths, cwd = process.cwd(), messages = createTranslator("fr")) {
|
|
45
46
|
const state = {
|
|
46
47
|
files: [],
|
|
47
48
|
warnings: [],
|
|
48
49
|
seen: new Set(),
|
|
49
50
|
totalBytes: 0,
|
|
50
|
-
gitignoreRules: await loadGitignoreRules(cwd)
|
|
51
|
+
gitignoreRules: await loadGitignoreRules(cwd),
|
|
52
|
+
messages
|
|
51
53
|
};
|
|
52
54
|
await addExplicitFiles(filePaths, cwd, state);
|
|
53
55
|
await addContextPaths(contextPaths, cwd, state);
|
|
@@ -62,14 +64,14 @@ async function addExplicitFiles(paths, cwd, state) {
|
|
|
62
64
|
const absolutePath = path.resolve(cwd, inputPath);
|
|
63
65
|
const fileStat = await stat(absolutePath);
|
|
64
66
|
if (!fileStat.isFile()) {
|
|
65
|
-
throw new Error(
|
|
67
|
+
throw new Error(state.messages.context.explicitMustBeFile(inputPath));
|
|
66
68
|
}
|
|
67
69
|
if (fileStat.size > MAX_FILE_BYTES) {
|
|
68
|
-
throw new Error(
|
|
70
|
+
throw new Error(state.messages.context.explicitTooLarge(inputPath, fileStat.size, MAX_FILE_BYTES));
|
|
69
71
|
}
|
|
70
72
|
const content = await readFile(absolutePath, "utf8");
|
|
71
73
|
if (content.includes("\u0000")) {
|
|
72
|
-
throw new Error(
|
|
74
|
+
throw new Error(state.messages.context.explicitBinary(inputPath));
|
|
73
75
|
}
|
|
74
76
|
addFileToState(cwd, state, absolutePath, content, fileStat.size, "explicit");
|
|
75
77
|
}
|
|
@@ -84,7 +86,7 @@ async function addContextPaths(paths, cwd, state) {
|
|
|
84
86
|
continue;
|
|
85
87
|
}
|
|
86
88
|
if (!fileStat.isDirectory()) {
|
|
87
|
-
state.warnings.push(
|
|
89
|
+
state.warnings.push(state.messages.context.ignoredNotFileOrDirectory(inputPath));
|
|
88
90
|
continue;
|
|
89
91
|
}
|
|
90
92
|
await walkContextDirectory(absolutePath, cwd, state);
|
|
@@ -113,21 +115,21 @@ async function addContextFile(absolutePath, cwd, state) {
|
|
|
113
115
|
return;
|
|
114
116
|
}
|
|
115
117
|
if (!isLikelyTextFile(absolutePath)) {
|
|
116
|
-
state.warnings.push(
|
|
118
|
+
state.warnings.push(state.messages.context.ignoredNonTextExtension(relativePath));
|
|
117
119
|
return;
|
|
118
120
|
}
|
|
119
121
|
const fileStat = await stat(absolutePath);
|
|
120
122
|
if (fileStat.size > MAX_FILE_BYTES) {
|
|
121
|
-
state.warnings.push(
|
|
123
|
+
state.warnings.push(state.messages.context.ignoredTooLarge(relativePath, fileStat.size));
|
|
122
124
|
return;
|
|
123
125
|
}
|
|
124
126
|
if (state.totalBytes + fileStat.size > MAX_TOTAL_BYTES) {
|
|
125
|
-
state.warnings.push(
|
|
127
|
+
state.warnings.push(state.messages.context.ignoredTotalLimit(relativePath));
|
|
126
128
|
return;
|
|
127
129
|
}
|
|
128
130
|
const content = await readFile(absolutePath, "utf8");
|
|
129
131
|
if (content.includes("\u0000")) {
|
|
130
|
-
state.warnings.push(
|
|
132
|
+
state.warnings.push(state.messages.context.ignoredBinary(relativePath));
|
|
131
133
|
return;
|
|
132
134
|
}
|
|
133
135
|
addFileToState(cwd, state, absolutePath, content, fileStat.size, "context");
|
|
@@ -138,9 +140,9 @@ function addFileToState(cwd, state, absolutePath, content, sizeBytes, source) {
|
|
|
138
140
|
}
|
|
139
141
|
if (state.totalBytes + sizeBytes > MAX_TOTAL_BYTES) {
|
|
140
142
|
if (source === "explicit") {
|
|
141
|
-
throw new Error(
|
|
143
|
+
throw new Error(state.messages.context.explicitTotalTooLarge(state.totalBytes + sizeBytes, MAX_TOTAL_BYTES));
|
|
142
144
|
}
|
|
143
|
-
state.warnings.push(
|
|
145
|
+
state.warnings.push(state.messages.context.ignoredTotalLimit(normalizePath(path.relative(cwd, absolutePath))));
|
|
144
146
|
return;
|
|
145
147
|
}
|
|
146
148
|
state.seen.add(absolutePath);
|