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 +8 -5
- package/dist/cli.js +1 -1
- package/dist/constants.js +15 -0
- package/dist/manual.js +20 -8
- package/dist/prepare/detect.js +1 -29
- package/dist/prepare/index.js +4 -7
- package/dist/prepare/prompts.js +6 -21
- package/dist/prepare/questions.js +3 -68
- package/dist/session.js +5 -4
- package/package.json +1 -1
- package/skills/cloud-ready/SKILL.md +30 -7
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
|
|
39
|
-
|
|
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("
|
|
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
|
-
/**
|
|
20
|
-
|
|
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
|
|
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
|
-
|
|
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,
|
package/dist/prepare/detect.js
CHANGED
|
@@ -1,36 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @file Pure parts of `prepare`:
|
|
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
|
*
|
package/dist/prepare/index.js
CHANGED
|
@@ -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
|
|
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:
|
|
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(
|
|
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);
|
package/dist/prepare/prompts.js
CHANGED
|
@@ -1,31 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
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
|
|
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(
|
|
10
|
+
* configurePrompt(); // "/cloud-ready configure"
|
|
20
11
|
*/
|
|
21
|
-
export function configurePrompt(
|
|
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
|
|
3
|
-
* the skill
|
|
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
|
-
|
|
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,
|
|
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 ${
|
|
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,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
|
|
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
|
-
|
|
37
|
-
|
|
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
|
-
- **
|
|
116
|
-
|
|
117
|
-
|
|
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`,
|