agent-cloud-kit 1.0.0-rc.7 → 1.0.0-rc.8

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.
@@ -0,0 +1,234 @@
1
+ /**
2
+ * @file The Spanish messages. Its shape is the shape of every catalog: `en.ts` must match it.
3
+ * Each message is a string or a function that builds one. Only what the terminal shows lives
4
+ * here: what is written in the repo (commit message, hook command, `docs/agent-cloud.md` outside
5
+ * the environment section) and the prompts for Claude stay where they are.
6
+ */
7
+ /** Command that continues a prepare run. */
8
+ const RESUME = "npx agent-cloud-kit prepare --resume";
9
+ /** Command that launches the cloud verification. */
10
+ const VERIFY = "npx agent-cloud-kit verify";
11
+ export const es = {
12
+ help: `agent-cloud-kit: prepara repos para las sesiones cloud de Claude Code.
13
+
14
+ Uso: agent-cloud-kit <comando> [--lang es|en]
15
+
16
+ Comandos:
17
+ setup [--repo <path>] prepara la máquina para cada repo del directorio home (o solo <path>)
18
+ session informa el estado de la máquina y conecta las herramientas a la sesión
19
+ docker inicia el demonio de Docker y espera a que responda
20
+ doctor revisa los dominios permitidos, las herramientas, Docker y el estado de la máquina
21
+ init crea .claude/cloud.json y registra el hook SessionStart
22
+ manual escribe docs/agent-cloud.md a partir de .claude/cloud.json
23
+ prepare [--pr|--here|--resume]
24
+ corre en local: deja el repo listo para la nube, en un PR nuevo (--pr) o en la
25
+ rama actual sin commit (--here); sin opción, pregunta dónde
26
+ verify corre en local: lanza una sesión cloud que verifica la rama actual (ya subida)
27
+
28
+ Opciones:
29
+ --lang es|en idioma de los mensajes (español por defecto; AGENT_CLOUD_KIT_LANG=es|en lo fija)
30
+ --help muestra esta ayuda
31
+ --version muestra la versión del paquete
32
+ `,
33
+ lang: {
34
+ invalid: (source, value) => `${source} espera es o en: ${value}`,
35
+ },
36
+ cli: {
37
+ versionMismatch: (running, file, pinned) => `corriendo la versión ${running}, aunque ${file} pide la ${pinned}`,
38
+ setupSummary: (repo, steps, failed, names) => `setup ${repo}: ${steps} pasos, ${failed} fallaron${names.length ? ` (${names.join(", ")})` : ""}`,
39
+ skip: (repo, reason) => `se omite ${repo}: ${reason}`,
40
+ relaunching: (version, repo) => `relanzando con la versión ${version} para ${repo}`,
41
+ relaunchFailed: (version, repo, error) => `falló el relanzamiento con la versión ${version} para ${repo}: ${error}`,
42
+ repoNeedsPath: (option) => `${option} necesita una ruta`,
43
+ noRepos: (home) => `no se encontraron repos en ${home}`,
44
+ setupErrorFor: (repo, error) => `error en setup de ${repo}: ${error}`,
45
+ setupError: (error) => `error en setup: ${error}`,
46
+ sessionDelegateFailed: (version, error) => `falló session con la versión ${version}: ${error}`,
47
+ manualWritten: (file) => `se escribió ${file}`,
48
+ unknownOption: (command, options) => `opción desconocida para ${command}: ${options}`,
49
+ onlyOne: (options) => `usa solo una de ${options}`,
50
+ },
51
+ config: {
52
+ dockerNotObject: '"docker" debe ser un objeto',
53
+ unknownField: (key) => `campo desconocido "${key}"`,
54
+ badPull: '"docker.pull" debe ser "auto", false o un arreglo de strings',
55
+ notStringList: (key) => `"${key}" debe ser un arreglo de strings`,
56
+ badHost: (host) => `"domains" tiene un host inválido: ${host}`,
57
+ badVersion: '"version" debe ser un semver exacto, como "1.0.0"',
58
+ notesNotString: '"notes" debe ser un string',
59
+ unreadable: (reason) => `no se pudo leer el archivo: ${reason}`,
60
+ notObject: "debe contener un objeto JSON",
61
+ missing: (file) => `no hay ${file}`,
62
+ },
63
+ run: {
64
+ timedOut: (cmd, ms) => `${cmd} superó el límite de ${ms}ms`,
65
+ exitCode: (cmd, code) => `${cmd} terminó con el código ${code}`,
66
+ exitSignal: (cmd, signal) => `${cmd} terminó con la señal ${signal}`,
67
+ },
68
+ docker: {
69
+ missing: "dockerd no está instalado",
70
+ didNotStart: (log) => `dockerd no arrancó; revisa ${log}`,
71
+ },
72
+ doctor: {
73
+ domain: (host, ok) => `red ${host}: ${ok ? "ok" : "bloqueado"}`,
74
+ toolInvalid: (tool, version) => `herramienta ${tool} ${version}: versión inválida`,
75
+ toolUnresolved: (tool, version) => `herramienta ${tool} ${version}: sin resolver (setup no la instaló)`,
76
+ tool: (tool, version, present) => `herramienta ${tool} ${version}: ${present ? "ok" : "falta"}`,
77
+ fileMissing: (file) => `${file}: falta`,
78
+ stateMissing: "estado: falta (setup no corrió)",
79
+ fingerprint: (same) => `huella: ${same ? "ok" : "distinta"}`,
80
+ step: (name, ok, seconds) => `paso ${name}: ${ok ? "ok" : "falló"} (${seconds}s)`,
81
+ docker: (ok) => `docker: ${ok ? "ok" : "falta"}`,
82
+ plugin: (name) => `aviso: el plugin ${name} está activado pero no está en el repo; no llegará a la nube (copia sus skills con skills-manager)`,
83
+ skill: (dir, installed, version) => `aviso: ${dir} está en ${installed} y el paquete en ${version}; corre npx agent-cloud-kit@${version} init`,
84
+ groupError: (group, error) => `${group}: error: ${error}`,
85
+ groups: { network: "red", tools: "herramientas", docker: "docker", state: "estado", plugins: "plugins", skill: "skill" },
86
+ allOk: "Todo en orden",
87
+ someFailed: (failed, total) => (failed === 1 ? `Falló 1 de ${total} revisiones` : `Fallaron ${failed} de ${total} revisiones`),
88
+ warnings: (count) => (count === 1 ? "1 aviso" : `${count} avisos`),
89
+ failedHint: "revisa las líneas con falta, bloqueado o falló",
90
+ },
91
+ session: {
92
+ genericNote: "estás en una sesión cloud de Claude Code. No hay puertos abiertos ni previews: prueba contra localhost. gh pr y gh issue fallan (el proxy de GitHub bloquea GraphQL): usa gh api (REST).",
93
+ setupNotRun: (repo, spec) => `el setup del entorno no corrió para ${repo}. Pon como script de setup del entorno en claude.ai: npx -y ${spec} setup`,
94
+ setupFailed: (names) => `falló el setup: ${names.join(", ")}. Corre agent-cloud-kit doctor.`,
95
+ otherConfig: "la máquina se preparó con otra configuración. Edita el campo del script de setup en claude.ai (cualquier cambio) para que se reconstruya.",
96
+ slow: (time) => `el setup tardó ${time}, cerca del límite de ~5 minutos.`,
97
+ envFileFailed: (variable, file, error) => `no se pudo escribir ${variable} (${file}): ${error}`,
98
+ stepTimedOut: (command) => `el paso de sesión superó el tiempo límite: ${command}`,
99
+ stepFailed: (command) => `falló el paso de sesión: ${command}`,
100
+ missingEnv: (names) => `faltan variables de entorno: ${names.join(", ")}`,
101
+ dockerFailed: (problem) => `no se pudo iniciar dockerd: ${problem}`,
102
+ error: (error) => `error en session: ${error}`,
103
+ },
104
+ setup: {
105
+ aptRepoHttps: (prefix) => `el repo de apt debe ser una URL ${prefix}`,
106
+ badDebianName: "nombre de paquete Debian inválido",
107
+ badImage: "referencia de imagen inválida",
108
+ packageMismatch: (source, found, version) => `el paquete en ${source} es ${found ?? "desconocido"}, no ${version}`,
109
+ noConfig: "sin configuración",
110
+ },
111
+ /** Names of the setup steps, built from the name stored in the state (which never changes). */
112
+ steps: {
113
+ aptRepo: (url) => `repo de apt ${url}`,
114
+ aptPackage: (name) => `paquete de apt ${name}`,
115
+ selfInstall: (version) => `autoinstalación ${version}`,
116
+ writeState: "guardar el estado",
117
+ lane: (index) => `grupo ${index}`,
118
+ config: "configuración",
119
+ },
120
+ installers: {
121
+ notInShasums: (file, shasums) => `${file} no aparece en ${shasums}`,
122
+ unsupportedArch: (arch) => `arquitectura no soportada para node: ${arch}`,
123
+ invalidVersion: (tool, version) => `versión inválida para ${tool}: ${version}`,
124
+ indexNotList: "el índice de versiones de node no es una lista",
125
+ noNodeMatch: (requested) => `ninguna versión de node coincide con ${requested}`,
126
+ nodeMustResolve: (version) => `node ${version} debe resolverse primero a una versión exacta`,
127
+ },
128
+ init: {
129
+ byHand: (file, reason, entry) => `${file} ${reason}; no se tocó. Agrega esta entrada a hooks.SessionStart a mano: ${entry}`,
130
+ notJson: "no es JSON válido",
131
+ notObject: "no es un objeto JSON",
132
+ hooksNotObject: 'tiene un "hooks" que no es un objeto',
133
+ sessionStartNotArray: 'tiene un "hooks.SessionStart" que no es un arreglo',
134
+ configExists: (file) => `${file} ya existe; se dejó como estaba`,
135
+ configCreated: (file) => `se creó ${file}`,
136
+ hookExists: (file) => `${file} ya tiene el hook SessionStart`,
137
+ hookAdded: (file) => `se agregó el hook SessionStart a ${file}`,
138
+ },
139
+ skill: {
140
+ current: (dir, version) => `${dir} ya está en ${version}`,
141
+ missing: (path, root) => `no se encontró ${path}/SKILL.md en ${root}`,
142
+ installed: (dir, version) => `se instaló ${dir} ${version}`,
143
+ updated: (dir, from, to) => `se actualizó ${dir} de ${from} a ${to}`,
144
+ linked: (link, dir) => `se enlazó ${link} a ${dir}`,
145
+ },
146
+ manual: {
147
+ noConfig: (file) => `no existe ${file}; corre init primero`,
148
+ },
149
+ /** The "configure the environment" section, shown by `prepare` (the manual keeps it in Spanish). */
150
+ environment: {
151
+ title: "## Configurar el entorno en claude.ai",
152
+ intro: "Elige el entorno con `/remote-env` y edítalo en claude.ai/code:",
153
+ network: (hosts) => `- **Acceso a la red:** Limitado (Custom) con "Permitir administradores de paquetes" encendido ("Also include default list of common package managers"). Dominios extra: ${hosts}.`,
154
+ variables: (names) => `- **Variables:** ${names}.`,
155
+ namesOnly: (names) => `${names} (solo los nombres; los valores los pones tú)`,
156
+ none: "ninguno",
157
+ noneVariables: "ninguna",
158
+ githubApp: "- **Claude GitHub App:** instalado en el repo, o la sesión no puede pushear.",
159
+ setupScript: "- **Setup script:**",
160
+ variablesWarning: "> ⚠️ Quien use el entorno puede leer las variables, y no llegan al setup script (solo a la sesión).",
161
+ },
162
+ menu: {
163
+ cancelled: "Cancelado",
164
+ },
165
+ preflight: {
166
+ noTty: (command) => `${command} necesita una terminal interactiva (corre el comando directamente en tu terminal)`,
167
+ noGit: (command) => `esto no es un repositorio git; corre ${command} dentro del repo`,
168
+ noOrigin: (command) => `el repositorio no tiene el remoto 'origin'; ${command} necesita subir una rama a GitHub`,
169
+ noClaude: (command) => `claude no está instalado o no está en el PATH; instala Claude Code y vuelve a correr ${command}`,
170
+ noCloud: (command) => `tu versión de claude no soporta --cloud; actualiza Claude Code y vuelve a correr ${command}`,
171
+ },
172
+ banner: {
173
+ title: "Ahora se abre Claude Code",
174
+ subtitle: "con la skill cloud-ready",
175
+ step1: "Claude revisa el repo y te propone cómo prepararlo para la nube",
176
+ step2: "Responde sus preguntas",
177
+ step3: (done, exit, after) => `Cuando diga ${done}, sal con ${exit} ${after}`,
178
+ configureDone: "configure terminó",
179
+ afterPr: "→ prepare hace commit, push y PR",
180
+ afterHere: "→ quedan los cambios sin commit",
181
+ free: (script) => `Se abre con ${script} (sin sandbox ni preguntas de permisos): el repo usa claude-repo-guard`,
182
+ enter: "abre Claude Code",
183
+ cancel: "· Ctrl+C cancela",
184
+ continue: "cuando hayas configurado el entorno en claude.ai",
185
+ continueHint: "· abre la sesión cloud que lo verifica",
186
+ },
187
+ prepare: {
188
+ interrupted: "interrumpido",
189
+ resume: (reason, worktree) => `${reason}; el worktree está en ${worktree}; corre ${RESUME} ahí para continuar`,
190
+ noConfig: (file) => `no existe ${file}`,
191
+ noNotes: (file) => `no existe el archivo de notas ${file}`,
192
+ worktreeExists: (worktree) => `${worktree} ya existe; bórralo (git worktree remove ${worktree}) o continúa ahí con ${RESUME}`,
193
+ branchExists: (branch) => `la rama ${branch} ya existe; bórrala (git branch -D ${branch}) o corre prepare otro día`,
194
+ worktreeCreated: (worktree, branch) => `se creó el worktree ${worktree} en la rama ${branch}`,
195
+ worktreeFailed: (error) => `no se pudo crear el worktree: ${error}`,
196
+ agentStopped: "el agente local se detuvo",
197
+ prepareStopped: "prepare se detuvo",
198
+ configureUnfinished: (problem) => `configure no terminó: ${problem}`,
199
+ otherChanges: "el agente local también cambió:",
200
+ includeQuestion: "¿Incluir estos cambios en el commit? [s/N]",
201
+ leftUncommitted: (worktree) => `quedó sin commitear en ${worktree}`,
202
+ nothingToCommit: "no hay nada nuevo que commitear",
203
+ pushed: (branch) => `se subió la rama ${branch}`,
204
+ pushFailed: (error, worktree) => `no se pudo hacer commit y push: ${error}; corrígelo en ${worktree} y corre ${RESUME} ahí`,
205
+ prReused: (pr) => `se reutiliza el PR abierto #${pr}`,
206
+ prDraft: (url) => `PR en borrador: ${url}`,
207
+ prByHand: (link, branch) => `no se pudo abrir el PR con gh; ábrelo a mano${link ? `: ${link}` : ` desde la rama ${branch}`}`,
208
+ interruptedHere: "interrumpido; lo que alcanzó a cambiar quedó sin commit en tu rama",
209
+ interruptedNothing: "interrumpido; no se creó nada",
210
+ nothingToResume: (suffix, prefix) => `no hay nada que reanudar: corre prepare --resume en el worktree *${suffix}, sobre una rama ${prefix}*`,
211
+ resumeUnfinished: (worktree, problem) => `configure no terminó en ${worktree}: ${problem}; corre claude "/cloud-ready configure" ahí primero y luego ${RESUME}`,
212
+ nothingChanged: "no se cambió nada",
213
+ cloudFailedResume: (error, worktree) => `falló claude --cloud: ${error}; corre ${RESUME} en ${worktree} para reintentar`,
214
+ placeQuestion: "¿Dónde preparo el repo?",
215
+ placePr: "En un PR nuevo",
216
+ placePrHint: (base) => `recomendado · parte de origin/${base}, no toca tu rama ni tus archivos`,
217
+ placeHere: "En la rama actual, sin commit",
218
+ placeHereHint: `los revisas con git diff, haces commit y push, y luego corres ${VERIFY}`,
219
+ stoppedHere: "prepare se detuvo; lo que alcanzó a cambiar quedó sin commit en tu rama",
220
+ hereUnfinished: (problem) => `configure no terminó: ${problem}; corre claude "/cloud-ready configure" y luego prepare otra vez`,
221
+ manualFailed: (file, error) => `no se pudo escribir ${file}: ${error}`,
222
+ hereTitle: "Listo, sin commit",
223
+ hereSteps: (manual) => ["Revisa los cambios con git diff", "Haz commit y push", `Configura el entorno en claude.ai (${manual})`, `Corre ${VERIFY}`],
224
+ noBranch: "no estás en una rama; cámbiate a la rama que quieres verificar",
225
+ notPrepared: (problem) => `el repo no está preparado (${problem}); corre npx agent-cloud-kit prepare primero`,
226
+ dirty: "hay cambios sin commit en la preparación; haz commit y push: la nube solo ve lo que está en origin",
227
+ notPushed: (branch) => `la rama ${branch} no está subida o tiene commits sin subir; haz git push y vuelve a correr verify`,
228
+ cloudFailed: (error) => `falló claude --cloud: ${error}`,
229
+ cloudStarted: "La sesión cloud está en marcha",
230
+ cloudWillReport: (branch, pr) => `la sesión cloud avisará con un push a ${branch}${pr ? " y un comentario en el PR" : ""}`,
231
+ rowBranch: "Rama",
232
+ rowPr: "PR",
233
+ },
234
+ };
@@ -0,0 +1,75 @@
1
+ import { en } from "./en.js";
2
+ import { es } from "./es.js";
3
+ export { es };
4
+ /** Catalog of the current run; Spanish until `useLang` says otherwise. */
5
+ let current = es;
6
+ /**
7
+ * The catalog of a language.
8
+ *
9
+ * @param lang - The language.
10
+ * @returns Its messages.
11
+ * @example
12
+ * messages("en").docker.missing; // "dockerd is not installed"
13
+ */
14
+ export function messages(lang) {
15
+ return lang === "en" ? en : es;
16
+ }
17
+ /**
18
+ * Sets the language of this run.
19
+ *
20
+ * @param lang - The language.
21
+ * @example
22
+ * useLang("en");
23
+ */
24
+ export function useLang(lang) {
25
+ current = messages(lang);
26
+ }
27
+ /**
28
+ * The messages of the current language.
29
+ *
30
+ * @returns The catalog.
31
+ * @example
32
+ * t().menu.cancelled; // "Cancelado"
33
+ */
34
+ export function t() {
35
+ return current;
36
+ }
37
+ /**
38
+ * Turns the name of a setup step, as the state stores it, into the current language. The stored
39
+ * name never changes, so a state written in one language reads well in the other.
40
+ *
41
+ * @param name - Stored step name, like `self install 1.0.0` or `docker pull redis:7`.
42
+ * @returns The name to show.
43
+ * @example
44
+ * stepLabel("write state"); // "guardar el estado" in Spanish
45
+ */
46
+ export function stepLabel(name) {
47
+ const m = current.steps;
48
+ const rest = (prefix) => (name.startsWith(prefix) ? name.slice(prefix.length) : undefined);
49
+ const aptRepo = rest(STEP.aptRepo);
50
+ if (aptRepo !== undefined)
51
+ return m.aptRepo(aptRepo);
52
+ const aptPackage = rest(STEP.aptPackage);
53
+ if (aptPackage !== undefined)
54
+ return m.aptPackage(aptPackage);
55
+ const selfInstall = rest(STEP.selfInstall);
56
+ if (selfInstall !== undefined)
57
+ return m.selfInstall(selfInstall);
58
+ const lane = rest(STEP.lane);
59
+ if (lane !== undefined && /^\d+$/.test(lane))
60
+ return m.lane(lane);
61
+ if (name === STEP.writeState)
62
+ return m.writeState;
63
+ if (name === STEP.config)
64
+ return m.config;
65
+ return name;
66
+ }
67
+ /** Stored names (or name prefixes) of the setup steps that have words in them. */
68
+ export const STEP = {
69
+ aptRepo: "apt repo ",
70
+ aptPackage: "apt package ",
71
+ selfInstall: "self install ",
72
+ lane: "lane ",
73
+ writeState: "write state",
74
+ config: "config",
75
+ };
@@ -1,9 +1,11 @@
1
1
  /**
2
- * @file The screen `prepare` shows before opening Claude Code: a small cloud, what will happen and
3
- * what the user has to do, in a few colored lines.
2
+ * @file The screen `prepare` shows before opening Claude Code: Kuro, what will happen and what the
3
+ * user has to do, in a few colored lines. `prepare` only runs in a terminal, so Kuro is always there.
4
4
  */
5
5
  import { existsSync, readFileSync } from "node:fs";
6
6
  import { join } from "node:path";
7
+ import { renderBlock } from "../block.js";
8
+ import { t } from "../messages/index.js";
7
9
  /** Script of claude-repo-guard that opens Claude without sandbox nor permission prompts. */
8
10
  export const FREE_SCRIPT = "claude:free";
9
11
  /**
@@ -26,27 +28,23 @@ function paint(on, code, text) {
26
28
  * @param input - Place, mode and color.
27
29
  * @returns The lines.
28
30
  * @example
29
- * renderBanner({ place: "pr", free: false, color: false })[2]; // " .-( ). Ahora se abre Claude Code"
31
+ * renderBanner({ place: "pr", free: false, color: false })[2]; // " ≋≋██▀▀▀▀▀██ [>] Ahora se abre Claude Code"
30
32
  */
31
33
  export function renderBanner(input) {
34
+ const m = t().banner;
32
35
  const c = (code, text) => paint(input.color, code, text);
33
- const cloud = (text) => c("36", text);
34
- const step = (n, text) => ` ${c("1;35", String(n))} ${text}`;
35
- const after = input.place === "pr" ? "prepare hace commit, push y PR" : "quedan los cambios sin commit";
36
+ const step = (n, text) => `${c("1;35", String(n))} ${text}`;
37
+ const after = input.place === "pr" ? m.afterPr : m.afterHere;
36
38
  const lines = [
39
+ c("2", m.subtitle),
37
40
  "",
38
- cloud(" .--."),
39
- `${cloud(" .-( ).")} ${c("1", "Ahora se abre Claude Code")}`,
40
- `${cloud(" (___.__)__)")} ${c("2", "con la skill cloud-ready")}`,
41
- "",
42
- step(1, "Claude revisa el repo y te propone cómo prepararlo para la nube"),
43
- step(2, "Responde sus preguntas"),
44
- step(3, `Cuando diga ${c("1", "configure terminó")}, sal con ${c("1;33", "/exit")} ${c("2", `→ ${after}`)}`),
41
+ step(1, m.step1),
42
+ step(2, m.step2),
43
+ step(3, m.step3(c("1", m.configureDone), c("1;33", "/exit"), c("2", after))),
45
44
  ];
46
45
  if (input.free)
47
- lines.push("", c("2", ` Se abre con ${FREE_SCRIPT} (sin sandbox ni preguntas de permisos): el repo usa claude-repo-guard`));
48
- lines.push("");
49
- return lines;
46
+ lines.push("", c("2", m.free(FREE_SCRIPT)));
47
+ return renderBlock({ mood: "next", title: m.title, lines }, { art: true, color: input.color });
50
48
  }
51
49
  /**
52
50
  * The line asked after the banner.
@@ -57,7 +55,8 @@ export function renderBanner(input) {
57
55
  * enterLine(false); // " ⏎ Enter abre Claude Code · Ctrl+C cancela "
58
56
  */
59
57
  export function enterLine(color) {
60
- return ` ${paint(color, "1;32", "⏎ Enter")} abre Claude Code ${paint(color, "2", "· Ctrl+C cancela")} `;
58
+ const m = t().banner;
59
+ return ` ${paint(color, "1;32", "⏎ Enter")} ${m.enter} ${paint(color, "2", m.cancel)} `;
61
60
  }
62
61
  /**
63
62
  * The line asked while the user configures the environment in claude.ai.
@@ -68,7 +67,8 @@ export function enterLine(color) {
68
67
  * continueLine(false); // "\n ⏎ Enter cuando hayas configurado el entorno en claude.ai · abre la sesión cloud que lo verifica "
69
68
  */
70
69
  export function continueLine(color) {
71
- return `\n ${paint(color, "1;32", "⏎ Enter")} cuando hayas configurado el entorno en claude.ai ${paint(color, "2", "· abre la sesión cloud que lo verifica")} `;
70
+ const m = t().banner;
71
+ return `\n ${paint(color, "1;32", "⏎ Enter")} ${m.continue} ${paint(color, "2", m.continueHint)} `;
72
72
  }
73
73
  /** Config file claude-repo-guard installs; the free mode is used only when it is there. */
74
74
  const GUARD_CONFIG = ".claude/repo-guard.config.json";
@@ -1,6 +1,7 @@
1
1
  /**
2
2
  * @file Pure parts of `prepare`: preflight checks.
3
3
  */
4
+ import { t } from "../messages/index.js";
4
5
  /** Flag `claude` must advertise in its help to launch cloud sessions. */
5
6
  const CLOUD_FLAG = "--cloud";
6
7
  /**
@@ -8,21 +9,22 @@ const CLOUD_FLAG = "--cloud";
8
9
  *
9
10
  * @param probe What was observed about the environment.
10
11
  * @param command Command named in the messages.
11
- * @returns Problems in Spanish, in a fixed order; empty when everything is fine.
12
+ * @returns Problems in the language of the terminal, in a fixed order; empty when everything is fine.
12
13
  * @example
13
14
  * preflight({ isTty: false, hasOrigin: true }); // ["prepare necesita una terminal interactiva", ...]
14
15
  */
15
16
  export function preflight(probe, command = "prepare") {
17
+ const m = t().preflight;
16
18
  const problems = [];
17
19
  if (!probe.isTty)
18
- problems.push(`${command} necesita una terminal interactiva (corre el comando directamente en tu terminal)`);
20
+ problems.push(m.noTty(command));
19
21
  if (probe.gitRoot === undefined)
20
- problems.push(`esto no es un repositorio git; corre ${command} dentro del repo`);
22
+ problems.push(m.noGit(command));
21
23
  if (!probe.hasOrigin)
22
- problems.push(`el repositorio no tiene el remoto 'origin'; ${command} necesita subir una rama a GitHub`);
24
+ problems.push(m.noOrigin(command));
23
25
  if (probe.claudeHelp === undefined)
24
- problems.push(`claude no está instalado o no está en el PATH; instala Claude Code y vuelve a correr ${command}`);
26
+ problems.push(m.noClaude(command));
25
27
  else if (!probe.claudeHelp.includes(CLOUD_FLAG))
26
- problems.push(`tu versión de claude no soporta --cloud; actualiza Claude Code y vuelve a correr ${command}`);
28
+ problems.push(m.noCloud(command));
27
29
  return problems;
28
30
  }