agent-cloud-kit 1.0.0-rc.0 → 1.0.0-rc.1

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 CHANGED
@@ -35,12 +35,15 @@ platform does not tell you:
35
35
  ## The flow
36
36
 
37
37
  1. **Install your agent tooling** with agent-kitchen (config, hook and skill arrive in the repo).
38
- 2. **Run `npx agent-cloud-kit prepare`** in a local terminal. It asks a few questions (secret
39
- variable names, extra domains), creates a worktree on a dated branch, runs `init`, and opens
38
+ 2. **Run `npx agent-cloud-kit prepare`** in a local terminal. It asks nothing up front: it
39
+ creates a worktree on a dated branch, runs `init`, and opens
40
40
  Claude locally with the `cloud-ready` skill so it can write the cloud preparation with you. Then
41
41
  it writes the manual, commits, pushes and opens a draft PR.
42
42
  3. **Configure the environment in claude.ai** following `docs/agent-cloud.md`, which `prepare`
43
- generated from your `.claude/cloud.json`.
43
+ generated from your `.claude/cloud.json`. The document keeps growing: when the skill, locally
44
+ or in the cloud, finds that a domain or an environment variable is missing, it adds it to
45
+ `.claude/cloud.json`, regenerates the document and tells you in the session what to add in
46
+ claude.ai.
44
47
  4. **Verification in the cloud:** `prepare` launches `claude --cloud` on that branch, so a real
45
48
  cloud session runs `cloud-ready verify`, fixes what fails and reports in the PR.
46
49
 
@@ -141,7 +144,7 @@ A Node version that is not exact (`22`, `22.1`, `lts/iron`, `lts/*` or `node`) i
141
144
  | `agent-cloud-kit docker` | Starts `dockerd` detached and waits up to 60 seconds for it to answer. Exits 1 if it does not, at once when `dockerd` is not installed. |
142
145
  | `agent-cloud-kit doctor` | Checks that the proxy lets the needed hosts through, that the pinned tools are installed, that Docker answers, and the recorded state (fingerprint and each step). Exits 1 if any check fails. |
143
146
  | `agent-cloud-kit init` | Creates `.claude/cloud.json` if missing, adds the `SessionStart` hook to `.claude/settings.json` (keeping the hooks already there), copies the `cloud-ready` skill to `.agents/skills/cloud-ready` when its version differs, and links it from `.claude/skills/cloud-ready`. Safe to run again. |
144
- | `agent-cloud-kit manual` | Writes `docs/agent-cloud.md` from `.claude/cloud.json`, deterministically: the exact setup script, domains, variable names, how to verify the environment. |
147
+ | `agent-cloud-kit manual` | Writes `docs/agent-cloud.md` from `.claude/cloud.json`, deterministically: the exact setup script (`agent-cloud-kit@<major>`, or the exact version for a release candidate), domains, variable names, how to verify the environment. |
145
148
  | `agent-cloud-kit prepare [--resume]` | Local only, needs an interactive terminal: sets the repo up for the cloud on a new branch in a worktree, opens the PR and verifies it in a real cloud session (see "The flow"). `--resume` continues in the existing worktree. |
146
149
 
147
150
  Environment variables: `AGENT_CLOUD_KIT_DIR` overrides `/opt/agent-cloud-kit` and `AGENT_CLOUD_KIT_HOME`
@@ -223,7 +226,7 @@ is configured on a package that already exists. Publish the first version by han
223
226
  2. On npmjs.com, open the package settings and add a trusted publisher: this GitHub repository and
224
227
  the `publish.yml` workflow.
225
228
  3. Remove the `NPM_TOKEN` secret if you created one. From then on, bump `version` in
226
- `package.json`, update `CHANGELOG.md`, and publish a GitHub release tagged `v<version>`.
229
+ `package.json`, update `CHANGELOG.md`, and publish a GitHub release tagged `v<version>`. A version with a prerelease suffix (`1.0.0-rc.1`) is published under the `next` tag once a stable version is `latest`; before that it also becomes `latest`, so tools that read `latest` (agent-kitchen) see it. Mark its GitHub release as a pre-release.
227
230
 
228
231
  ## License
229
232
 
package/dist/cli.js CHANGED
@@ -282,7 +282,7 @@ function manualCommand(deps) {
282
282
  * @returns The raw answer.
283
283
  * @throws InterruptedError on Ctrl+C.
284
284
  * @example
285
- * await askTerminal("Extra domains", ""); // "api.example.com"
285
+ * await askTerminal("Include these changes in the commit? [y/N]", ""); // "y"
286
286
  */
287
287
  const askTerminal = async (question, suggestion) => {
288
288
  const rl = createInterface({ input: process.stdin, output: process.stdout });
package/dist/constants.js CHANGED
@@ -10,6 +10,21 @@ export const CONFIG_FILE = ".claude/cloud.json";
10
10
  export const RUNNING_PACKAGE_ROOT = fileURLToPath(new URL("..", import.meta.url));
11
11
  /** Name of this package on npm. */
12
12
  export const PACKAGE = "agent-cloud-kit";
13
+ /**
14
+ * The npm spec the setup script installs: the major (`agent-cloud-kit@1`) for a stable version,
15
+ * the exact version for a prerelease, which a major range does not match.
16
+ *
17
+ * @param packageVersion - Version of the running package.
18
+ * @returns The spec.
19
+ * @example
20
+ * packageSpec("1.2.0"); // "agent-cloud-kit@1"
21
+ * packageSpec("1.0.0-rc.1"); // "agent-cloud-kit@1.0.0-rc.1"
22
+ */
23
+ export function packageSpec(packageVersion) {
24
+ if (packageVersion.includes("-"))
25
+ return `${PACKAGE}@${packageVersion}`;
26
+ return `${PACKAGE}@${packageVersion.split(".")[0]}`;
27
+ }
13
28
  /** Default root directory that holds the installed tools and the state files. */
14
29
  export const TOOLS_DIR = "/opt/agent-cloud-kit";
15
30
  /** Environment variable that overrides `TOOLS_DIR` (used by tests). */
package/dist/manual.js CHANGED
@@ -5,7 +5,7 @@
5
5
  import { existsSync, mkdirSync, readFileSync, realpathSync, renameSync, rmSync, statSync, writeFileSync } from "node:fs";
6
6
  import { dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
7
7
  import { readConfig } from "./config.js";
8
- import { CONFIG_FILE, OUTPUT_PREFIX, PACKAGE } from "./constants.js";
8
+ import { CONFIG_FILE, OUTPUT_PREFIX, PACKAGE, packageSpec } from "./constants.js";
9
9
  /** Path of the manual, relative to the repo. */
10
10
  export const MANUAL_FILE = "docs/agent-cloud.md";
11
11
  /** Marker that opens the generated block. */
@@ -16,17 +16,28 @@ export const END = "<!-- agent-cloud-kit:end -->";
16
16
  const FINDINGS = "## Hallazgos\n\n_Lo que el agente descubra de la nube va aquí._\n";
17
17
  /** Prefix of an https URL. */
18
18
  const HTTPS_PREFIX = "https://";
19
- /** Setup script the environment must run, in a `bash` block. */
20
- const SETUP_SCRIPT = `#!/bin/bash\nnpx -y ${PACKAGE}@1 setup`;
19
+ /**
20
+ * Setup script the environment must run, for a `bash` block.
21
+ *
22
+ * @param packageVersion - Version of the running package.
23
+ * @returns The script.
24
+ * @example
25
+ * setupScript("1.2.0"); // "#!/bin/bash\nnpx -y agent-cloud-kit@1 setup"
26
+ */
27
+ function setupScript(packageVersion) {
28
+ return `#!/bin/bash\nnpx -y ${packageSpec(packageVersion)} setup`;
29
+ }
21
30
  /** The "how it works" section, five lines. */
22
31
  const HOW_IT_WORKS = [
23
32
  "## Cómo funciona",
24
33
  "",
25
34
  "1. agent-kitchen instala las herramientas y los ganchos en el repo.",
26
- `2. \`${PACKAGE} prepare\` configura el repo con la skill y deja lista la lista de dominios y variables.`,
35
+ `2. \`${PACKAGE} prepare\` configura el repo con la skill y genera este documento.`,
27
36
  "3. Tú configuras el entorno en claude.ai con lo que indica la siguiente sección.",
28
37
  "4. Una sesión en la nube verifica que el entorno quedó bien.",
29
38
  "5. El PR guarda el resultado.",
39
+ "",
40
+ "Este documento se va actualizando. Cuando la skill `cloud-ready`, en local o en la nube, detecta que hace falta un dominio o una variable de entorno nueva, la agrega a `.claude/cloud.json`, regenera este archivo y te lo dice en la sesión. Cuando cambie la sección \"Configurar el entorno en claude.ai\", aplica lo nuevo en claude.ai y abre una sesión nueva.",
30
41
  ].join("\n");
31
42
  /**
32
43
  * Extracts the host of an apt repo URL.
@@ -62,11 +73,12 @@ function allowedHosts(config) {
62
73
  * Renders the "Configurar el entorno en claude.ai" section.
63
74
  *
64
75
  * @param config - Repo config.
76
+ * @param packageVersion - Version of the running package, for the setup script.
65
77
  * @returns The section, without a trailing newline.
66
78
  * @example
67
- * renderEnvironmentSection(config).startsWith("## Configurar el entorno en claude.ai"); // true
79
+ * renderEnvironmentSection(config, "1.0.0").startsWith("## Configurar el entorno en claude.ai"); // true
68
80
  */
69
- export function renderEnvironmentSection(config) {
81
+ export function renderEnvironmentSection(config, packageVersion) {
70
82
  const hosts = allowedHosts(config);
71
83
  const lines = [
72
84
  "## Configurar el entorno en claude.ai",
@@ -82,7 +94,7 @@ export function renderEnvironmentSection(config) {
82
94
  "### Setup script",
83
95
  "",
84
96
  "```bash",
85
- SETUP_SCRIPT,
97
+ setupScript(packageVersion),
86
98
  "```",
87
99
  "",
88
100
  "### Variables de entorno",
@@ -154,7 +166,7 @@ export function renderManual(input) {
154
166
  `<!-- Generado por ${PACKAGE} ${input.packageVersion}. No edites entre las marcas. -->`,
155
167
  "# Nube de Claude Code",
156
168
  HOW_IT_WORKS,
157
- renderEnvironmentSection(input.config),
169
+ renderEnvironmentSection(input.config, input.packageVersion),
158
170
  VERIFY_SECTION,
159
171
  `## Qué corre en la nube\n\n${notes?.trim() ? notes.trim() : "Nada anotado."}`,
160
172
  END,
@@ -1,36 +1,8 @@
1
1
  /**
2
- * @file Pure parts of `prepare`: secret-name suggestions and preflight checks.
2
+ * @file Pure parts of `prepare`: preflight checks.
3
3
  */
4
- import { existsSync, readFileSync } from "node:fs";
5
- import { join } from "node:path";
6
- /** File, in the repo root, whose keys are suggested as secret names. */
7
- const ENV_EXAMPLE_FILE = ".env.example";
8
- /** Matches a `KEY=value` line (optionally prefixed by `export`) and captures the key. */
9
- const ENV_LINE = /^\s*(?:export\s+)?([A-Za-z_][A-Za-z0-9_]*)\s*=/;
10
4
  /** Flag `claude` must advertise in its help to launch cloud sessions. */
11
5
  const CLOUD_FLAG = "--cloud";
12
- /**
13
- * Suggests secret names from the keys of `.env.example` in the repo root.
14
- *
15
- * @param repo Repo root.
16
- * @returns Keys in file order, without duplicates; empty when the file does not exist.
17
- * @example
18
- * suggestSecrets("/repo"); // ["API_TOKEN", "DB_URL"]
19
- */
20
- export function suggestSecrets(repo) {
21
- const file = join(repo, ENV_EXAMPLE_FILE);
22
- if (!existsSync(file))
23
- return [];
24
- const keys = [];
25
- for (const line of readFileSync(file, "utf8").split(/\r?\n/)) {
26
- if (line.trimStart().startsWith("#"))
27
- continue;
28
- const key = ENV_LINE.exec(line)?.[1];
29
- if (key !== undefined && !keys.includes(key))
30
- keys.push(key);
31
- }
32
- return keys;
33
- }
34
6
  /**
35
7
  * Checks that `prepare` can run.
36
8
  *
@@ -10,9 +10,8 @@ import { CONFIG_FILE, OUTPUT_PREFIX, PACKAGE } from "../constants.js";
10
10
  import { defaultBranch } from "../detect.js";
11
11
  import { init } from "../init.js";
12
12
  import { renderEnvironmentSection, writeManual } from "../manual.js";
13
- import { preflight, suggestSecrets } from "./detect.js";
13
+ import { preflight } from "./detect.js";
14
14
  import { configurePrompt, verifyPrompt } from "./prompts.js";
15
- import { askAll } from "./questions.js";
16
15
  /** Prefix of the branch `prepare` creates; the day follows it. */
17
16
  const BRANCH_PREFIX = "chore/cloud-ready-";
18
17
  /** Suffix added to the repo folder name to name the worktree folder, next to the repo. */
@@ -235,7 +234,7 @@ async function findResume(repo, deps) {
235
234
  return undefined;
236
235
  }
237
236
  /**
238
- * Steps 2–5: asks the questions, creates the worktree, installs the kit and runs the local agent.
237
+ * Steps 2–5: creates the worktree, installs the kit and runs the local agent.
239
238
  *
240
239
  * @param repo - Git root of the repo.
241
240
  * @param branch - Branch to create.
@@ -243,7 +242,6 @@ async function findResume(repo, deps) {
243
242
  * @param deps - Dependencies.
244
243
  * @param progress - Gets the worktree once it exists.
245
244
  * @returns True when the worktree is ready to commit.
246
- * @throws InterruptedError when the user presses Ctrl+C during the questions.
247
245
  * @example
248
246
  * await createAndConfigure("/home/u/app", "chore/cloud-ready-20261102", "/home/u/app-cloud-ready", deps, {});
249
247
  */
@@ -256,7 +254,6 @@ async function createAndConfigure(repo, branch, worktree, deps, progress) {
256
254
  deps.print(`${OUTPUT_PREFIX}branch ${branch} already exists; delete it (git branch -D ${branch}) or run prepare another day`);
257
255
  return false;
258
256
  }
259
- const answers = await askAll(deps.ask, { secrets: suggestSecrets(repo) }, deps.print);
260
257
  const base = `origin/${defaultBranch(repo)}`;
261
258
  try {
262
259
  await deps.run("git", ["fetch", "-q", "origin"], { cwd: repo });
@@ -284,7 +281,7 @@ async function createAndConfigure(repo, branch, worktree, deps, progress) {
284
281
  }
285
282
  deps.print(EXIT_CLAUDE_HINT);
286
283
  try {
287
- await runInteractive(deps, progress, [configurePrompt(answers)], worktree);
284
+ await runInteractive(deps, progress, [configurePrompt()], worktree);
288
285
  }
289
286
  catch {
290
287
  deps.print(stopped);
@@ -478,7 +475,7 @@ async function prepareSteps(gitRoot, deps, options, progress) {
478
475
  return EXIT_FAIL;
479
476
  const config = readConfig(worktree).config;
480
477
  if (config)
481
- deps.print(renderEnvironmentSection(config));
478
+ deps.print(renderEnvironmentSection(config, deps.packageVersion));
482
479
  await deps.waitEnter(WAIT_TEXT);
483
480
  try {
484
481
  await runInteractive(deps, progress, ["--cloud", verifyPrompt({ branch, pr: pushed.pr })], worktree);
@@ -1,31 +1,16 @@
1
1
  /**
2
- * Formats a list for a prompt line.
3
- *
4
- * @param items Items.
5
- * @param none Text when there are no items.
6
- * @returns The items joined by commas, or `none`.
7
- * @example
8
- * list(["A", "B"], "ninguna"); // "A, B"
2
+ * @file Prompts `prepare` hands to Claude, in Spanish: they invoke the `cloud-ready` skill.
9
3
  */
10
- function list(items, none) {
11
- return items.length > 0 ? items.join(", ") : none;
12
- }
13
4
  /**
14
- * Prompt for the local session: `configure` mode with the user's answers.
5
+ * Prompt for the local session: `configure` mode. `prepare` asks nothing first; the skill detects
6
+ * secrets and domains itself.
15
7
  *
16
- * @param answers What the user answered.
17
8
  * @returns The prompt.
18
9
  * @example
19
- * configurePrompt({ secrets: ["A"], domains: [] }).startsWith("/cloud-ready configure"); // true
10
+ * configurePrompt(); // "/cloud-ready configure"
20
11
  */
21
- export function configurePrompt(answers) {
22
- return [
23
- "/cloud-ready configure",
24
- "",
25
- "Respuestas del usuario (no las vuelvas a preguntar):",
26
- `- Variables secretas: ${list(answers.secrets, "ninguna")}`,
27
- `- Dominios extra: ${list(answers.domains, "ninguno")}`,
28
- ].join("\n");
12
+ export function configurePrompt() {
13
+ return "/cloud-ready configure";
29
14
  }
30
15
  /**
31
16
  * Prompt for the cloud session: `verify` mode with the prepare branch and, when known, the PR.
@@ -1,70 +1,5 @@
1
1
  /**
2
- * @file The questions `prepare` asks: only secret names and extra domains (tests are handled by
3
- * the skill with the user).
2
+ * @file How `prepare` asks the user a question. It asks nothing up front: secrets and domains are
3
+ * detected by the `cloud-ready` skill, locally or in the cloud, when they are needed.
4
4
  */
5
- import { isHostName } from "../config.js";
6
- import { OUTPUT_PREFIX } from "../constants.js";
7
- /** Answer that leaves a list empty. */
8
- const EMPTY_LIST_ANSWER = "-";
9
- /**
10
- * Turns a raw answer into a list.
11
- *
12
- * @param answer Raw answer: comma-separated, empty to accept, `-` for none.
13
- * @param suggestion Suggested items, used when the answer is empty.
14
- * @returns The items.
15
- * @example
16
- * parseList("a, b", []); // ["a", "b"]
17
- */
18
- function parseList(answer, suggestion) {
19
- const text = answer.trim();
20
- if (text === "")
21
- return suggestion;
22
- if (text === EMPTY_LIST_ANSWER)
23
- return [];
24
- return text.split(",").map((item) => item.trim()).filter((item) => item !== "");
25
- }
26
- /** Example host shown when a typed domain is not a host name. */
27
- const HOST_EXAMPLE = "api.example.com";
28
- /**
29
- * Keeps the typed domains that are host names (the rule of `domains` in the config). Each invalid
30
- * entry is asked again once; if it is still not a host name it is dropped with a printed note.
31
- *
32
- * @param ask Function that asks one question.
33
- * @param typed Domains as typed.
34
- * @param print Prints one line.
35
- * @returns The valid domains.
36
- * @example
37
- * await validDomains(ask, ["api.example.com"], console.log); // ["api.example.com"]
38
- */
39
- async function validDomains(ask, typed, print) {
40
- const domains = [];
41
- for (const entry of typed) {
42
- if (isHostName(entry)) {
43
- domains.push(entry);
44
- continue;
45
- }
46
- const retry = (await ask(`${JSON.stringify(entry)} is not a host name (like ${HOST_EXAMPLE}); type it again, or ${EMPTY_LIST_ANSWER} to drop it`, "")).trim();
47
- if (isHostName(retry)) {
48
- domains.push(retry);
49
- continue;
50
- }
51
- const dropped = retry === "" || retry === EMPTY_LIST_ANSWER ? entry : retry;
52
- print(`${OUTPUT_PREFIX}dropped ${JSON.stringify(dropped)}: not a host name like ${HOST_EXAMPLE}`);
53
- }
54
- return domains;
55
- }
56
- /**
57
- * Asks every question.
58
- *
59
- * @param ask Function that asks one question.
60
- * @param suggestions Suggested items.
61
- * @param print Prints one line (notes about dropped domains).
62
- * @returns The answers.
63
- * @example
64
- * await askAll(ask, { secrets: ["API_TOKEN"] }, console.log); // { secrets: ["API_TOKEN"], domains: [] }
65
- */
66
- export async function askAll(ask, suggestions, print) {
67
- const secrets = parseList(await ask("Secret environment variables needed in the cloud (comma-separated, - for none)", suggestions.secrets.join(", ")), suggestions.secrets);
68
- const typed = parseList(await ask("Extra domains the setup or tests need (comma-separated, - for none)", ""), []);
69
- return { secrets, domains: await validDomains(ask, typed, print) };
70
- }
5
+ export {};
package/dist/session.js CHANGED
@@ -6,7 +6,7 @@ import { appendFileSync, existsSync } from "node:fs";
6
6
  import { basename, join } from "node:path";
7
7
  import { findProxyCa, shellQuote } from "./ca.js";
8
8
  import { readConfig } from "./config.js";
9
- import { CONFIG_FILE, GIT_FETCH_TIMEOUT_MS, OUTPUT_PREFIX, PACKAGE, SETUP_SLOW_MS } from "./constants.js";
9
+ import { CONFIG_FILE, GIT_FETCH_TIMEOUT_MS, OUTPUT_PREFIX, packageSpec, SETUP_SLOW_MS } from "./constants.js";
10
10
  import { configImages, defaultBranch, readToolVersions } from "./detect.js";
11
11
  import { realDocker } from "./docker.js";
12
12
  import { pathLine, toolBinDirs } from "./installers.js";
@@ -91,12 +91,13 @@ export function expectedFingerprint(repo, config, state) {
91
91
  * @param repo - Repo root.
92
92
  * @param config - Repo config.
93
93
  * @param state - Recorded state, if any.
94
+ * @param packageVersion - Version of the running package, for the setup command.
94
95
  * @returns Warning messages, without prefix.
95
96
  */
96
- function machineWarnings(repo, config, state) {
97
+ function machineWarnings(repo, config, state, packageVersion) {
97
98
  if (!state) {
98
99
  return [
99
- `the environment setup did not run for ${basename(repo)}. Set the setup script of the environment in claude.ai to: npx -y ${PACKAGE}@1 setup`,
100
+ `the environment setup did not run for ${basename(repo)}. Set the setup script of the environment in claude.ai to: npx -y ${packageSpec(packageVersion)} setup`,
100
101
  ];
101
102
  }
102
103
  const out = [];
@@ -209,7 +210,7 @@ async function sessionBody(repo, ctx, out) {
209
210
  if (envFileProblem)
210
211
  out.push(envFileProblem);
211
212
  if (config)
212
- out.push(...machineWarnings(repo, config, state));
213
+ out.push(...machineWarnings(repo, config, state, ctx.packageVersion));
213
214
  const missing = (config?.requiredEnv ?? []).filter((name) => !ctx.env[name]);
214
215
  if (missing.length)
215
216
  out.push(`missing environment variables: ${missing.join(", ")}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-cloud-kit",
3
- "version": "1.0.0-rc.0",
3
+ "version": "1.0.0-rc.1",
4
4
  "description": "Zero-dependency CLI that prepares Claude Code cloud sessions.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: cloud-ready
3
3
  description: Prepara o verifica un repo Node/TypeScript para las sesiones en la nube de Claude Code (claude.ai/code). Usa `configure` en local, con el usuario, para escribir `.claude/cloud.json` y decidir qué corre en la nube; usa `verify` dentro de una sesión en la nube para comprobar la preparación, arreglarla y reportar en el PR.
4
- argument-hint: "configure [respuestas] | verify"
4
+ argument-hint: "configure | verify"
5
5
  metadata:
6
6
  version: "1.0.0"
7
7
  ---
@@ -33,8 +33,9 @@ Son los únicos que `verify` puede cambiar:
33
33
  ## `configure` (local, con el usuario)
34
34
 
35
35
  Si `CLAUDE_CODE_REMOTE=true`, detente: este modo necesita al usuario en una terminal local.
36
- Las respuestas que traiga el argumento (variables secretas, dominios extra) son el punto de
37
- partida: no las vuelvas a preguntar.
36
+ No le pidas al usuario una lista de variables secretas ni de dominios: anota en `requiredEnv` y
37
+ `domains` solo lo que veas que el repo necesita en la nube; lo que falte lo detecta `verify` (ver
38
+ "Dominios y variables nuevos").
38
39
 
39
40
  1. **Lee qué usa el repo:** `package.json` (scripts, `packageManager`, `engines`), el lockfile,
40
41
  `.tool-versions`, `mise.toml`, `.nvmrc`, archivos de Docker compose, `Dockerfile`,
@@ -81,7 +82,9 @@ partida: no las vuelvas a preguntar.
81
82
  8. **Si existe `.agents/skills/test-audit/project.md`:** escribe o actualiza su sección "Nube"
82
83
  con el mismo resumen; no toques el resto del archivo.
83
84
  9. **Corre `agent-cloud-kit manual`** y muéstrale al usuario la sección "Configurar el entorno en
84
- claude.ai" de `docs/agent-cloud.md` (setup script, dominios, variables).
85
+ claude.ai" de `docs/agent-cloud.md` (setup script, dominios, variables). Dile que ese
86
+ documento se irá actualizando: si la skill, en local o en la nube, detecta que hace falta un
87
+ dominio o una variable nueva, lo agrega ahí y se lo dice.
85
88
  10. **No hagas commit:** `agent-cloud-kit prepare` lo hace al salir. Si te invocaron fuera de
86
89
  `prepare`, pregunta al usuario.
87
90
  11. **Termina diciéndole al usuario que salga:** dile al usuario, con estas palabras o parecidas,
@@ -112,9 +115,11 @@ Solo con `CLAUDE_CODE_REMOTE=true`; si no, detente y dilo. El prompt trae la ram
112
115
  - **Se arregla en la preparación:** cambia solo los archivos de la preparación y vuelve a
113
116
  comprobar. Un cambio de `setup` no se re-ejecuta en esta sesión (el setup ya corrió): corre
114
117
  el comando a mano para probarlo y anota que la máquina guardada se rehará en una sesión nueva.
115
- - **Solo se cambia en claude.ai** (dominios de la red, variables, entorno por defecto con
116
- `/remote-env`, rehacer la máquina editando el setup script, el Claude GitHub App): no lo
117
- intentes; deja la instrucción exacta para el reporte y deja de intentar arreglos.
118
+ - **Falta un dominio o una variable:** sigue "Dominios y variables nuevos" y deja de intentar
119
+ arreglos que dependan de eso.
120
+ - **Solo se cambia en claude.ai** (entorno por defecto con `/remote-env`, rehacer la máquina
121
+ editando el setup script, el Claude GitHub App): no lo intentes; deja la instrucción exacta
122
+ para el reporte y deja de intentar arreglos.
118
123
  - **Requiere cambiar código, tests o scripts:** no lo cambies; deja el cambio propuesto
119
124
  (archivo y diff) para el comentario del PR.
120
125
 
@@ -157,6 +162,24 @@ Solo con `CLAUDE_CODE_REMOTE=true`; si no, detente y dilo. El prompt trae la ram
157
162
  **Hallazgos:** los nuevos, o "ninguno".
158
163
  ```
159
164
 
165
+ ## Dominios y variables nuevos
166
+
167
+ En ambos modos, cuando algo falla porque falta un dominio en la red del entorno (el proxy
168
+ rechaza la conexión, `403` o `CONNECT` fallido hacia un host) o una variable de entorno (el
169
+ inicio de la sesión la marca como faltante, o el error nombra una variable vacía):
170
+
171
+ 1. Agrega el host a `domains` o el nombre a `requiredEnv` en `.claude/cloud.json` (solo el
172
+ nombre; nunca un valor).
173
+ 2. Corre `agent-cloud-kit manual`: `docs/agent-cloud.md` queda con lo nuevo.
174
+ 3. **Díselo al usuario en la sesión, en ese momento**, sin esperar al final: qué falta, por qué
175
+ (el comando y el error) y qué hacer, con estas palabras o parecidas: "Falta `<X>` en el entorno
176
+ de claude.ai. Agrégalo en <Network access / Variables de entorno> (está en
177
+ `docs/agent-cloud.md`), abre una sesión nueva y corre `/cloud-ready verify`".
178
+ 4. En `verify`, ponlo también en "Cambiar en claude.ai" del comentario del PR.
179
+
180
+ Un dominio que ya está en `domains`, o una variable que ya está en `requiredEnv`, no se agrega
181
+ de nuevo: si sigue faltando, el usuario aún no actualizó el entorno; recuérdaselo.
182
+
160
183
  ## Hallazgos
161
184
 
162
185
  En ambos modos: todo hecho nuevo sobre la nube (algo que no está en `reference/knowledge.md`,