agent-kitchen 0.6.0 → 0.7.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/commands/sync.d.ts +5 -4
- package/dist/commands/sync.js +40 -55
- package/dist/commit-texts.d.ts +18 -0
- package/dist/commit-texts.js +29 -0
- package/dist/git-finish.js +2 -3
- package/dist/menu.js +2 -1
- package/dist/piece.d.ts +8 -2
- package/dist/pieces/agents-md.js +1 -3
- package/dist/pieces/cloud.js +2 -2
- package/dist/pieces/guard.js +3 -3
- package/dist/pieces/issue-flow.js +6 -6
- package/dist/pieces/skills-manager.js +3 -3
- package/dist/pieces/skills.js +3 -4
- package/dist/progress.d.ts +29 -0
- package/dist/progress.js +75 -0
- package/dist/texts/catalog.d.ts +50 -0
- package/dist/texts/catalog.js +1 -0
- package/dist/texts/es.d.ts +7 -0
- package/dist/texts/es.js +139 -0
- package/dist/texts/index.d.ts +30 -0
- package/dist/texts/index.js +31 -0
- package/dist/texts/step-text.d.ts +85 -0
- package/dist/texts/step-text.js +7 -0
- package/package.json +1 -1
package/dist/commands/sync.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type Output } from "../output.js";
|
|
2
|
+
import type { Step } from "../piece.js";
|
|
2
3
|
/** Options of the command. */
|
|
3
4
|
export interface SyncOptions {
|
|
4
5
|
cwd: string;
|
|
@@ -26,13 +27,13 @@ export declare function pieceNames(): string[];
|
|
|
26
27
|
export declare function noStepsMessage(why: "leave" | "none", wrote: boolean): string;
|
|
27
28
|
/**
|
|
28
29
|
* What the commit of `--commit` lists: the steps that worked, and the decisions file if this
|
|
29
|
-
* run wrote it.
|
|
30
|
-
* @param done - The
|
|
30
|
+
* run wrote it, in the commit's texts (not the interface's).
|
|
31
|
+
* @param done - The steps that worked.
|
|
31
32
|
* @param wrote - Whether the decisions file was written in this run.
|
|
32
|
-
* @returns The
|
|
33
|
+
* @returns The lines.
|
|
33
34
|
* @example commitLabels([], true) // ["Guardar qué piezas usa el repo en .agents/kitchen.json"]
|
|
34
35
|
*/
|
|
35
|
-
export declare function commitLabels(done:
|
|
36
|
+
export declare function commitLabels(done: Pick<Step, "text">[], wrote: boolean): string[];
|
|
36
37
|
/**
|
|
37
38
|
* Runs the command; see the file's header.
|
|
38
39
|
* @param options - The options.
|
package/dist/commands/sync.js
CHANGED
|
@@ -23,7 +23,6 @@
|
|
|
23
23
|
* `--pieces` (terminal only, not with `--yes` or `--dry-run`) first asks which pieces the repo
|
|
24
24
|
* uses, writes all of them to the file, and then goes on as usual.
|
|
25
25
|
*/
|
|
26
|
-
import { spinner } from "@clack/prompts";
|
|
27
26
|
import { DECIDABLE, decide, DECISIONS, off, readDecisions, undecided, writeDecisions } from "../decisions.js";
|
|
28
27
|
import { baseBranch, branchName, changedPaths, checkReady, finish } from "../git-finish.js";
|
|
29
28
|
import { askFinish, askPath, askPieces, askReplace, askSkills, askSteps } from "../menu.js";
|
|
@@ -36,6 +35,9 @@ import { agentsMdStatus, NAME as AGENTS_MD } from "../pieces/agents-md.js";
|
|
|
36
35
|
import { NAME as SKILLS_MANAGER, skillsManagerStatus } from "../pieces/skills-manager.js";
|
|
37
36
|
import { mainCheckout, packageManager } from "../repo.js";
|
|
38
37
|
import { download, failedOutput, runInstall, setVerbose } from "../tools.js";
|
|
38
|
+
import { commitLine, DECISIONS_LINE } from "../commit-texts.js";
|
|
39
|
+
import { progressFor } from "../progress.js";
|
|
40
|
+
import { stepLabel, ui } from "../texts/index.js";
|
|
39
41
|
/** Every piece, in the order its steps run. */
|
|
40
42
|
const PIECES = [SKILLS_MANAGER, FLOW, CLOUD, GUARD, SKILLS, AGENTS_MD];
|
|
41
43
|
/**
|
|
@@ -115,9 +117,7 @@ function saveDecisions(root, saved, statuses, chosen, commits, out) {
|
|
|
115
117
|
* @example noStepsMessage("none", true) // "No elegiste pasos; solo guardé qué piezas usa el repo.\n"
|
|
116
118
|
*/
|
|
117
119
|
export function noStepsMessage(why, wrote) {
|
|
118
|
-
|
|
119
|
-
return wrote ? "No corrí ningún paso; solo guardé qué piezas usa el repo.\n" : "No se cambió nada.\n";
|
|
120
|
-
return wrote ? "No elegiste pasos; solo guardé qué piezas usa el repo.\n" : "No elegiste nada; no se cambió nada.\n";
|
|
120
|
+
return `${ui.noSteps(why, wrote)}\n`;
|
|
121
121
|
}
|
|
122
122
|
/**
|
|
123
123
|
* The line that says the decisions were saved.
|
|
@@ -125,20 +125,19 @@ export function noStepsMessage(why, wrote) {
|
|
|
125
125
|
* @returns The line.
|
|
126
126
|
*/
|
|
127
127
|
function savedMessage(commits) {
|
|
128
|
-
return
|
|
128
|
+
return `${ui.saved(DECISIONS, commits)}\n`;
|
|
129
129
|
}
|
|
130
|
-
/** The line the commit of `--commit` adds for the decisions file. */
|
|
131
|
-
const DECISIONS_STEP = `Guardar qué piezas usa el repo en ${DECISIONS}`;
|
|
132
130
|
/**
|
|
133
131
|
* What the commit of `--commit` lists: the steps that worked, and the decisions file if this
|
|
134
|
-
* run wrote it.
|
|
135
|
-
* @param done - The
|
|
132
|
+
* run wrote it, in the commit's texts (not the interface's).
|
|
133
|
+
* @param done - The steps that worked.
|
|
136
134
|
* @param wrote - Whether the decisions file was written in this run.
|
|
137
|
-
* @returns The
|
|
135
|
+
* @returns The lines.
|
|
138
136
|
* @example commitLabels([], true) // ["Guardar qué piezas usa el repo en .agents/kitchen.json"]
|
|
139
137
|
*/
|
|
140
138
|
export function commitLabels(done, wrote) {
|
|
141
|
-
|
|
139
|
+
const lines = done.map((step) => commitLine(step.text));
|
|
140
|
+
return wrote ? [...lines, DECISIONS_LINE] : lines;
|
|
142
141
|
}
|
|
143
142
|
/**
|
|
144
143
|
* Asks which pieces the repo uses and writes the answer for every decidable piece.
|
|
@@ -149,7 +148,7 @@ export function commitLabels(done, wrote) {
|
|
|
149
148
|
* @returns False if the person cancelled.
|
|
150
149
|
*/
|
|
151
150
|
async function choosePieces(root, saved, commits, out) {
|
|
152
|
-
out.stdout(
|
|
151
|
+
out.stdout(`${ui.checking}\n`);
|
|
153
152
|
// No skip here: an installed, undecided piece passed in --skip still starts ticked.
|
|
154
153
|
const statuses = await statusesOf(root, []);
|
|
155
154
|
const ticked = DECIDABLE.filter((name) => saved?.pieces[name] === true || (saved?.pieces[name] === undefined && statuses.some((status) => status.name === name && status.installed)));
|
|
@@ -173,7 +172,7 @@ function keepOwnSkills(root, step, out) {
|
|
|
173
172
|
if (own.length === 0)
|
|
174
173
|
return;
|
|
175
174
|
Object.assign(step.skills, keepOwn(step.skills, own));
|
|
176
|
-
out.stdout(
|
|
175
|
+
out.stdout(`${ui.ownSkillsKept(own)}\n`);
|
|
177
176
|
}
|
|
178
177
|
/**
|
|
179
178
|
* Asks, for a step that installs skills, which ones, and whether to replace the repo's own.
|
|
@@ -217,14 +216,13 @@ async function chooseSteps(root, steps, options, out) {
|
|
|
217
216
|
const suggested = steps.filter((step) => step.checked);
|
|
218
217
|
if (options.yes) {
|
|
219
218
|
if (suggested.length === 0)
|
|
220
|
-
out.stdout(
|
|
219
|
+
out.stdout(`${ui.onlyOptional(steps.map(stepLabel))}\n`);
|
|
221
220
|
for (const step of suggested)
|
|
222
221
|
keepOwnSkills(root, step, out);
|
|
223
222
|
return suggested;
|
|
224
223
|
}
|
|
225
224
|
if (options.dryRun || !out.interactive) {
|
|
226
|
-
|
|
227
|
-
out.stdout(`Pasos sugeridos${hint}:\n${steps.map((step) => ` [${step.checked ? "x" : " "}] ${step.label}\n`).join("")}`);
|
|
225
|
+
out.stdout(`${ui.suggested(options.dryRun)}\n${steps.map((step) => ` [${step.checked ? "x" : " "}] ${stepLabel(step)}\n`).join("")}`);
|
|
228
226
|
return null;
|
|
229
227
|
}
|
|
230
228
|
for (const step of suggested)
|
|
@@ -242,22 +240,6 @@ async function chooseSteps(root, steps, options, out) {
|
|
|
242
240
|
}
|
|
243
241
|
return chosen;
|
|
244
242
|
}
|
|
245
|
-
/**
|
|
246
|
-
* How progress is shown: a spinner in a terminal (unless the tools print with
|
|
247
|
-
* `--verbose`), plain lines otherwise. Only for the steps, after every question: a spinner
|
|
248
|
-
* shown before a question leaves the second question deaf to the keyboard (@clack/prompts
|
|
249
|
-
* 1.8.1).
|
|
250
|
-
* @param out - Where to write.
|
|
251
|
-
* @param verbose - Whether the tools print on the terminal.
|
|
252
|
-
* @returns The progress.
|
|
253
|
-
*/
|
|
254
|
-
function progressFor(out, verbose) {
|
|
255
|
-
if (out.interactive && !verbose) {
|
|
256
|
-
const spin = spinner();
|
|
257
|
-
return { start: (text) => spin.start(text), stop: (text, ok) => (ok ? spin.stop(text) : spin.error(text)) };
|
|
258
|
-
}
|
|
259
|
-
return { start: (text) => out.stdout(`→ ${text}\n`), stop: (text, ok) => out.stdout(`${ok ? "✓" : "✗"} ${text}\n`) };
|
|
260
|
-
}
|
|
261
243
|
/**
|
|
262
244
|
* Runs one step and shows how it went: its notes, and what to do if it failed.
|
|
263
245
|
* @param root - The repo.
|
|
@@ -275,19 +257,21 @@ async function runStep(root, step, progress, out) {
|
|
|
275
257
|
note: (text) => notes.push(text),
|
|
276
258
|
fail: (text, output) => failures.push(` ${text}\n${output === undefined ? "" : failedOutput(output)}`),
|
|
277
259
|
};
|
|
278
|
-
progress.start(step.
|
|
279
|
-
await Promise.all(step.downloads.map((spec) => download(root, spec)));
|
|
260
|
+
progress.start(step.text);
|
|
280
261
|
let ok;
|
|
281
262
|
try {
|
|
263
|
+
await Promise.all(step.downloads.map((spec) => download(root, spec)));
|
|
282
264
|
ok = await step.run(context);
|
|
283
265
|
}
|
|
284
266
|
catch (error) {
|
|
285
|
-
if (!(error instanceof KitError))
|
|
267
|
+
if (!(error instanceof KitError)) {
|
|
268
|
+
progress.stop(step.text, false);
|
|
286
269
|
throw error;
|
|
270
|
+
}
|
|
287
271
|
failures.push(` ${error.message}\n`);
|
|
288
272
|
ok = false;
|
|
289
273
|
}
|
|
290
|
-
progress.stop(step.
|
|
274
|
+
progress.stop(step.text, ok);
|
|
291
275
|
for (const note of notes)
|
|
292
276
|
out.stdout(` · ${note}\n`);
|
|
293
277
|
for (const failure of failures)
|
|
@@ -333,32 +317,33 @@ export async function sync(options, out) {
|
|
|
333
317
|
const asks = out.interactive && !options.yes && !options.dryRun;
|
|
334
318
|
const saves = asks && options.skip.length === 0;
|
|
335
319
|
if (out.interactive)
|
|
336
|
-
out.stdout(
|
|
320
|
+
out.stdout(`${ui.checking}\n`);
|
|
337
321
|
let statuses = await statusesOf(root, skip);
|
|
338
322
|
if (saved !== null && !asks && !options.dryRun) {
|
|
339
323
|
const left = undecided(saved).filter((name) => statuses.some((status) => status.name === name && !status.installed));
|
|
340
324
|
if (left.length > 0) {
|
|
341
325
|
skip.push(...left);
|
|
342
326
|
statuses = await statusesOf(root, skip);
|
|
343
|
-
out.stdout(
|
|
327
|
+
out.stdout(`${ui.undecided(left)}\n`);
|
|
344
328
|
}
|
|
345
329
|
}
|
|
346
330
|
if (saved !== null) {
|
|
347
331
|
const fresh = undecided(saved);
|
|
348
332
|
for (const status of statuses.filter((each) => fresh.includes(each.name))) {
|
|
349
|
-
status.state +=
|
|
333
|
+
status.state += ui.fresh;
|
|
350
334
|
for (const step of status.steps)
|
|
351
|
-
step.
|
|
335
|
+
step.fresh = true;
|
|
352
336
|
}
|
|
353
337
|
}
|
|
354
338
|
printStatus(statuses, off(saved).filter((name) => !options.skip.includes(name)), out);
|
|
355
339
|
const steps = statuses.flatMap((status) => status.steps);
|
|
356
340
|
// With --commit, a run that only wrote the decisions file still ends with the question.
|
|
357
|
-
const
|
|
341
|
+
const progress = progressFor(out, options.verbose, base !== null);
|
|
342
|
+
const endWithoutSteps = async () => (base !== null && wrote ? commitChanges(root, base, commitLabels([], true), [], progress, options, out) : 0);
|
|
358
343
|
if (steps.length === 0) {
|
|
359
344
|
if (saves)
|
|
360
345
|
wrote = saveDecisions(root, saved, statuses, [], base !== null, out) || wrote;
|
|
361
|
-
out.stdout(
|
|
346
|
+
out.stdout(`${ui.upToDate}\n`);
|
|
362
347
|
return endWithoutSteps();
|
|
363
348
|
}
|
|
364
349
|
const chosen = await chooseSteps(root, steps, options, out);
|
|
@@ -382,16 +367,15 @@ export async function sync(options, out) {
|
|
|
382
367
|
out.stdout(noStepsMessage("none", wrote));
|
|
383
368
|
return endWithoutSteps();
|
|
384
369
|
}
|
|
385
|
-
const
|
|
386
|
-
const failed = [];
|
|
370
|
+
const failedSteps = [];
|
|
387
371
|
for (const step of chosen) {
|
|
388
372
|
if (!(await runStep(root, step, progress, out)))
|
|
389
|
-
|
|
373
|
+
failedSteps.push(step);
|
|
390
374
|
}
|
|
375
|
+
const failed = failedSteps.map(stepLabel);
|
|
391
376
|
if (base !== null)
|
|
392
|
-
return commitChanges(root, base, commitLabels(chosen.filter((step) => !
|
|
393
|
-
|
|
394
|
-
out.stdout(`\n${failed.length === 0 ? "Listo." : `Terminó, pero fallaron: ${failed.join("; ")}.`} ${next}\n`);
|
|
377
|
+
return commitChanges(root, base, commitLabels(chosen.filter((step) => !failedSteps.includes(step)), wrote), failed, progress, options, out);
|
|
378
|
+
out.stdout(`\n${ui.summary(failed)} ${ui.next(packageManager(root))}\n`);
|
|
395
379
|
return failed.length === 0 ? 0 : 1;
|
|
396
380
|
}
|
|
397
381
|
/**
|
|
@@ -399,14 +383,15 @@ export async function sync(options, out) {
|
|
|
399
383
|
* the branch with a PR under --yes) and what git did.
|
|
400
384
|
* @param root - The repo.
|
|
401
385
|
* @param base - The base branch.
|
|
402
|
-
* @param done - What the commit lists: the
|
|
403
|
-
* @param failed - The
|
|
386
|
+
* @param done - What the commit lists: the steps that worked, and the decisions file if written.
|
|
387
|
+
* @param failed - The steps that failed, as the interface names them.
|
|
388
|
+
* @param progress - How progress is shown, for the install.
|
|
404
389
|
* @param options - The options.
|
|
405
390
|
* @param out - Where to write and ask.
|
|
406
391
|
* @returns 0, or 1 if a step, the install or git failed.
|
|
407
392
|
*/
|
|
408
|
-
async function commitChanges(root, base, done, failed, options, out) {
|
|
409
|
-
const summary =
|
|
393
|
+
async function commitChanges(root, base, done, failed, progress, options, out) {
|
|
394
|
+
const summary = ui.summary(failed);
|
|
410
395
|
const changed = changedPaths(root);
|
|
411
396
|
if (changed.length === 0) {
|
|
412
397
|
out.stdout(`\n${summary} No cambió ningún archivo: no hay nada que commitear.\n`);
|
|
@@ -415,10 +400,10 @@ async function commitChanges(root, base, done, failed, options, out) {
|
|
|
415
400
|
const manager = packageManager(root);
|
|
416
401
|
const packageChanged = changed.includes("package.json");
|
|
417
402
|
if (packageChanged) {
|
|
418
|
-
const
|
|
419
|
-
|
|
403
|
+
const text = { kind: "install-deps", manager };
|
|
404
|
+
progress.start(text);
|
|
420
405
|
const installed = await runInstall(root, manager);
|
|
421
|
-
|
|
406
|
+
progress.stop(text, installed.ok);
|
|
422
407
|
if (!installed.ok) {
|
|
423
408
|
out.stderr(failedOutput(installed.output));
|
|
424
409
|
out.stdout(`\n${summary} No commiteé: el install falló y los cambios quedan sin commit.\n`);
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { StepText } from "./texts/step-text.js";
|
|
2
|
+
/** The subject of the commit and the title of the PR. */
|
|
3
|
+
export declare const COMMIT_TITLE = "chore: agent-kitchen apply";
|
|
4
|
+
/** The line of the decisions file. */
|
|
5
|
+
export declare const DECISIONS_LINE = "Guardar qu\u00E9 piezas usa el repo en .agents/kitchen.json";
|
|
6
|
+
/**
|
|
7
|
+
* A step's line in the commit and the PR.
|
|
8
|
+
* @param text - What the step does.
|
|
9
|
+
* @returns The line, without the dash.
|
|
10
|
+
* @example commitLine({ kind: "flow-install", version: "0.2.0" }) // "Instalar issue-flow 0.2.0: config del flujo, hooks y scripts"
|
|
11
|
+
*/
|
|
12
|
+
export declare function commitLine(text: StepText): string;
|
|
13
|
+
/**
|
|
14
|
+
* The body of the PR.
|
|
15
|
+
* @param lines - What the commit lists.
|
|
16
|
+
* @returns The body.
|
|
17
|
+
*/
|
|
18
|
+
export declare function prBody(lines: string[]): string;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file The texts of the commit and the PR of `apply --commit`. They are always in Spanish,
|
|
3
|
+
* whatever language the interface shows: a repo's history should not change language with the
|
|
4
|
+
* terminal of whoever ran the command. A step reads as its Spanish menu order.
|
|
5
|
+
*/
|
|
6
|
+
import { DECISIONS } from "./decisions.js";
|
|
7
|
+
import { es } from "./texts/es.js";
|
|
8
|
+
import { phrasesIn } from "./texts/index.js";
|
|
9
|
+
/** The subject of the commit and the title of the PR. */
|
|
10
|
+
export const COMMIT_TITLE = "chore: agent-kitchen apply";
|
|
11
|
+
/** The line of the decisions file. */
|
|
12
|
+
export const DECISIONS_LINE = `Guardar qué piezas usa el repo en ${DECISIONS}`;
|
|
13
|
+
/**
|
|
14
|
+
* A step's line in the commit and the PR.
|
|
15
|
+
* @param text - What the step does.
|
|
16
|
+
* @returns The line, without the dash.
|
|
17
|
+
* @example commitLine({ kind: "flow-install", version: "0.2.0" }) // "Instalar issue-flow 0.2.0: config del flujo, hooks y scripts"
|
|
18
|
+
*/
|
|
19
|
+
export function commitLine(text) {
|
|
20
|
+
return phrasesIn(es, text).menu;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* The body of the PR.
|
|
24
|
+
* @param lines - What the commit lists.
|
|
25
|
+
* @returns The body.
|
|
26
|
+
*/
|
|
27
|
+
export function prBody(lines) {
|
|
28
|
+
return `Cambios de \`agent-kitchen apply\`:\n\n${lines.map((line) => `- ${line}`).join("\n")}\n`;
|
|
29
|
+
}
|
package/dist/git-finish.js
CHANGED
|
@@ -10,12 +10,11 @@ import { spawnSync } from "node:child_process";
|
|
|
10
10
|
import { mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
|
11
11
|
import { tmpdir } from "node:os";
|
|
12
12
|
import { join, relative } from "node:path";
|
|
13
|
+
import { COMMIT_TITLE as TITLE, prBody } from "./commit-texts.js";
|
|
13
14
|
import { KitError } from "./output.js";
|
|
14
15
|
import { FLOW_CONFIG } from "./piece.js";
|
|
15
16
|
import { dependencyVersion, readJson } from "./repo.js";
|
|
16
17
|
import { captureNpxWithout, isRelease, npmLatest } from "./tools.js";
|
|
17
|
-
/** The subject of the commit and the title of the PR. */
|
|
18
|
-
const TITLE = "chore: agent-kitchen apply";
|
|
19
18
|
/** github-rest on npm, which opens the PR (REST, never gh's GraphQL). */
|
|
20
19
|
const GITHUB_REST = "@ramon-sg/github-rest";
|
|
21
20
|
/**
|
|
@@ -153,7 +152,7 @@ async function openPr(root, branch, base, steps) {
|
|
|
153
152
|
return { error: `no sé qué versión de ${GITHUB_REST} usar.` };
|
|
154
153
|
const dir = mkdtempSync(join(tmpdir(), "agent-kitchen-pr-"));
|
|
155
154
|
const bodyFile = join(dir, "body.md");
|
|
156
|
-
writeFileSync(bodyFile,
|
|
155
|
+
writeFileSync(bodyFile, prBody(steps));
|
|
157
156
|
try {
|
|
158
157
|
const result = await captureNpxWithout(root, [`${GITHUB_REST}@${version}`, "pr", "create", "--head", branch, "--base", base, "--title", TITLE, "--body-file", bodyFile], ["GH_REPO"]);
|
|
159
158
|
const url = result.out.trim().split("\n").at(-1) ?? "";
|
package/dist/menu.js
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import { styleText } from "node:util";
|
|
8
8
|
import { confirm, groupMultiselect, isCancel, MULTISELECT_INSTRUCTIONS, multiselect, select, SELECT_INSTRUCTIONS } from "@clack/prompts";
|
|
9
|
+
import { stepLabel } from "./texts/index.js";
|
|
9
10
|
/** Width a skill's description is cut to in the menu. */
|
|
10
11
|
const DESCRIPTION_WIDTH = 70;
|
|
11
12
|
/**
|
|
@@ -24,7 +25,7 @@ function spanishKeys() {
|
|
|
24
25
|
*/
|
|
25
26
|
export function menuOptions(steps) {
|
|
26
27
|
return {
|
|
27
|
-
options: steps.map((step, index) => ({ value: index, label: step
|
|
28
|
+
options: steps.map((step, index) => ({ value: index, label: stepLabel(step) })),
|
|
28
29
|
initialValues: steps.flatMap((step, index) => (step.checked ? [index] : [])),
|
|
29
30
|
};
|
|
30
31
|
}
|
package/dist/piece.d.ts
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
* writes the few lines that join two pieces, the one line of AGENTS.md, which has no tool,
|
|
8
8
|
* and the version of skills-manager in package.json, which agent-kitchen is the one to run.
|
|
9
9
|
*/
|
|
10
|
+
import type { StepText } from "./texts/step-text.js";
|
|
10
11
|
/** The issue flow on npm. */
|
|
11
12
|
export declare const FLOW_PACKAGE = "@ramon-sg/issue-flow";
|
|
12
13
|
/** The GitHub repo of the issue flow, which is also the catalog of its skills. */
|
|
@@ -36,10 +37,15 @@ export interface SkillPick {
|
|
|
36
37
|
picked: string[];
|
|
37
38
|
replace: string[];
|
|
38
39
|
}
|
|
39
|
-
/**
|
|
40
|
+
/**
|
|
41
|
+
* One step a piece offers: what it does (as data; texts/ turns it into words for each place
|
|
42
|
+
* it shows), what it downloads, and how it runs. `fresh` marks a step of a piece the repo has
|
|
43
|
+
* not decided on yet.
|
|
44
|
+
*/
|
|
40
45
|
export interface Step {
|
|
41
46
|
piece: string;
|
|
42
|
-
|
|
47
|
+
text: StepText;
|
|
48
|
+
fresh?: boolean;
|
|
43
49
|
checked: boolean;
|
|
44
50
|
downloads: string[];
|
|
45
51
|
skills?: SkillPick;
|
package/dist/pieces/agents-md.js
CHANGED
|
@@ -100,10 +100,8 @@ export async function agentsMdStatus(root, flowComing) {
|
|
|
100
100
|
const summary = "regla de versiones instaladas en AGENTS.md";
|
|
101
101
|
if (!lack.rule && !lack.import)
|
|
102
102
|
return { name: NAME, summary, installed: true, state: "al día", steps: [] };
|
|
103
|
-
const files = [...(lack.rule ? ["AGENTS.md"] : []), ...(lack.import ? ["CLAUDE.md"] : [])];
|
|
104
|
-
const label = lack.rule ? `Agregar a AGENTS.md la regla de versiones instaladas${lack.import ? " (y @AGENTS.md en CLAUDE.md)" : ""}` : "Agregar @AGENTS.md a CLAUDE.md, para que Claude Code lea AGENTS.md";
|
|
105
103
|
const state = lack.rule ? "falta la regla" : "CLAUDE.md no importa AGENTS.md";
|
|
106
|
-
return { name: NAME, summary, installed: !lack.rule, state, steps: [{ piece: NAME, checked: true, downloads: [],
|
|
104
|
+
return { name: NAME, summary, installed: !lack.rule, state, steps: [{ piece: NAME, checked: true, downloads: [], text: { kind: "agents-md", rule: lack.rule, claudeImport: lack.import }, run: async (context) => write(context) }] };
|
|
107
105
|
}
|
|
108
106
|
/**
|
|
109
107
|
* Whether AGENTS.md has the rule and CLAUDE.md, if there is one, imports it. Only noted.
|
package/dist/pieces/cloud.js
CHANGED
|
@@ -28,7 +28,7 @@ function stepFor(config, latest) {
|
|
|
28
28
|
piece: NAME,
|
|
29
29
|
checked: true,
|
|
30
30
|
downloads: [spec],
|
|
31
|
-
|
|
31
|
+
text: { kind: "cloud-install", version: latest },
|
|
32
32
|
run: async (context) => {
|
|
33
33
|
const run = await runNpx(context.root, [spec, "init"]);
|
|
34
34
|
if (run.ok)
|
|
@@ -44,7 +44,7 @@ function stepFor(config, latest) {
|
|
|
44
44
|
piece: NAME,
|
|
45
45
|
checked: true,
|
|
46
46
|
downloads: [],
|
|
47
|
-
|
|
47
|
+
text: { kind: "cloud-update", from: version, to: latest, config: CONFIG },
|
|
48
48
|
run: async (context) => {
|
|
49
49
|
const current = readJson(context.root, CONFIG) ?? {};
|
|
50
50
|
const schema = typeof current.$schema === "string" ? current.$schema.replace(/@ramon-sg\/claude-cloud@[^/]+\//, `${PACKAGE}@${latest}/`) : undefined;
|
package/dist/pieces/guard.js
CHANGED
|
@@ -141,11 +141,11 @@ function installedVersion(root) {
|
|
|
141
141
|
*/
|
|
142
142
|
function stepFor(root, installed, latest, flowComing) {
|
|
143
143
|
if (installed === undefined)
|
|
144
|
-
return { piece: NAME, checked: true, downloads: [guardSpec(latest)],
|
|
144
|
+
return { piece: NAME, checked: true, downloads: [guardSpec(latest)], text: { kind: "guard-install", version: latest }, run: (context) => install(context, latest) };
|
|
145
145
|
if (latest !== null && (installed === null || compareVersions(latest, installed) > 0))
|
|
146
|
-
return { piece: NAME, checked: true, downloads: [guardSpec(latest)],
|
|
146
|
+
return { piece: NAME, checked: true, downloads: [guardSpec(latest)], text: { kind: "guard-update", from: installed, to: latest }, run: (context) => install(context, latest) };
|
|
147
147
|
if (flowComing || guardOptions(root, process.platform).changes.length > 0)
|
|
148
|
-
return { piece: NAME, checked: true, downloads: [guardSpec(installed)],
|
|
148
|
+
return { piece: NAME, checked: true, downloads: [guardSpec(installed)], text: { kind: "guard-adjust" }, run: (context) => addOptions(context, installed) };
|
|
149
149
|
return null;
|
|
150
150
|
}
|
|
151
151
|
/**
|
|
@@ -197,7 +197,7 @@ async function missingLabels(root, version) {
|
|
|
197
197
|
* @returns The step.
|
|
198
198
|
*/
|
|
199
199
|
function labelsStep(version, missing) {
|
|
200
|
-
return { piece: NAME, checked: true, downloads: [`${FLOW_PACKAGE}@${version}`],
|
|
200
|
+
return { piece: NAME, checked: true, downloads: [`${FLOW_PACKAGE}@${version}`], text: { kind: "flow-labels", missing }, run: async (context) => {
|
|
201
201
|
if (flowVersion(context.root) !== version) {
|
|
202
202
|
context.note(`no se crearon: el repo no tiene issue-flow ${version}`);
|
|
203
203
|
return true;
|
|
@@ -233,7 +233,7 @@ function restStep(root, version, minimum) {
|
|
|
233
233
|
const current = dependencyVersion(readJson(root, "package.json"), GITHUB_REST);
|
|
234
234
|
if (!below(current))
|
|
235
235
|
return null;
|
|
236
|
-
return { piece: NAME, checked: true, downloads: [],
|
|
236
|
+
return { piece: NAME, checked: true, downloads: [], text: { kind: "github-rest-bump", from: current, to: minimum, flow: version }, run: async (context) => {
|
|
237
237
|
if (flowVersion(context.root) !== version)
|
|
238
238
|
context.note(`no se subió: el repo no tiene issue-flow ${version}`);
|
|
239
239
|
else if (!below(dependencyVersion(readJson(context.root, "package.json"), GITHUB_REST)))
|
|
@@ -256,16 +256,16 @@ function restStep(root, version, minimum) {
|
|
|
256
256
|
function stepFor(installed, latest, root, repair) {
|
|
257
257
|
if (installed === null && latest !== null) {
|
|
258
258
|
const run = usesApply(latest) ? async (context) => (await applyFlow(context, latest)) && (await moveSkills(context, latest)) : (context) => runFlow(context, latest, ["init", "--yes"]);
|
|
259
|
-
return { piece: NAME, checked: true, downloads: [`${FLOW_PACKAGE}@${latest}`],
|
|
259
|
+
return { piece: NAME, checked: true, downloads: [`${FLOW_PACKAGE}@${latest}`], text: { kind: "flow-install", version: latest }, run };
|
|
260
260
|
}
|
|
261
261
|
if (installed !== null && latest !== null && compareVersions(latest, installed) > 0) {
|
|
262
262
|
const update = (context) => (usesApply(latest) ? applyFlow(context, latest) : runFlow(context, latest, ["upgrade"]));
|
|
263
|
-
return { piece: NAME, checked: true, downloads: [`${FLOW_PACKAGE}@${latest}`],
|
|
263
|
+
return { piece: NAME, checked: true, downloads: [`${FLOW_PACKAGE}@${latest}`], text: { kind: "flow-update", from: installed, to: latest }, run: async (context) => (await update(context)) && (await moveSkills(context, latest)) };
|
|
264
264
|
}
|
|
265
265
|
if (installed !== null && repair)
|
|
266
|
-
return { piece: NAME, checked: true, downloads: [`${FLOW_PACKAGE}@${installed}`],
|
|
266
|
+
return { piece: NAME, checked: true, downloads: [`${FLOW_PACKAGE}@${installed}`], text: { kind: "flow-repair", version: installed }, run: async (context) => (await applyFlow(context, installed)) && (skillsOff(context.root, installed).length === 0 || (await moveSkills(context, installed))) };
|
|
267
267
|
if (installed !== null && skillsOff(root, installed).length > 0)
|
|
268
|
-
return { piece: NAME, checked: true, downloads: [],
|
|
268
|
+
return { piece: NAME, checked: true, downloads: [], text: { kind: "flow-skills", version: installed }, run: (context) => moveSkills(context, installed) };
|
|
269
269
|
return null;
|
|
270
270
|
}
|
|
271
271
|
/**
|
|
@@ -66,7 +66,7 @@ export function skillsManagerStatus(root, withSkills, flowComing) {
|
|
|
66
66
|
piece: NAME,
|
|
67
67
|
checked: true,
|
|
68
68
|
downloads: [`${SKILLS_MANAGER}@${MIN_VERSION}`],
|
|
69
|
-
|
|
69
|
+
text: { kind: "skills-manager-create", version: MIN_VERSION },
|
|
70
70
|
run: async (context) => {
|
|
71
71
|
if (readJson(context.root, "package.json") === null)
|
|
72
72
|
writeJson(context.root, "package.json", { private: true, devDependencies: { [SKILLS_MANAGER]: MIN_VERSION } });
|
|
@@ -85,13 +85,13 @@ export function skillsManagerStatus(root, withSkills, flowComing) {
|
|
|
85
85
|
}
|
|
86
86
|
if (now.kind === "exact" && !below(now.version))
|
|
87
87
|
return { name: NAME, summary, installed: true, state: `${now.version}, al día`, steps: [] };
|
|
88
|
-
const
|
|
88
|
+
const text = now.kind === "missing" ? { kind: "skills-manager-add", version: MIN_VERSION } : { kind: "skills-manager-bump", from: now.version, to: MIN_VERSION };
|
|
89
89
|
const state = now.kind === "missing" ? "no está en package.json" : `${now.version}, bajo ${MIN_VERSION}`;
|
|
90
90
|
const step = {
|
|
91
91
|
piece: NAME,
|
|
92
92
|
checked: true,
|
|
93
93
|
downloads: [`${SKILLS_MANAGER}@${MIN_VERSION}`],
|
|
94
|
-
|
|
94
|
+
text,
|
|
95
95
|
run: async (context) => {
|
|
96
96
|
const current = pinned(context.root);
|
|
97
97
|
if (current.kind === "missing" || (current.kind === "exact" && below(current.version))) {
|
package/dist/pieces/skills.js
CHANGED
|
@@ -174,7 +174,7 @@ async function updateStep(root, catalog, ref) {
|
|
|
174
174
|
piece: NAME,
|
|
175
175
|
checked: true,
|
|
176
176
|
downloads: [skillsManagerSpec(root)],
|
|
177
|
-
|
|
177
|
+
text: { kind: "skills-update", catalog, from, to: latest, names: behind.map((skill) => skill.name) },
|
|
178
178
|
run: async (context) => {
|
|
179
179
|
if (ref !== null)
|
|
180
180
|
pinCatalog(context.root, catalog, `v${latest}`);
|
|
@@ -215,10 +215,9 @@ export async function skillsStatus(root, withFlow) {
|
|
|
215
215
|
});
|
|
216
216
|
const offered = candidates ?? fallback;
|
|
217
217
|
const catalogs = [...new Set(offered.map((candidate) => candidate.catalog))];
|
|
218
|
-
const label = `Instalar ${offered.length} skills de ${catalogs.join(" y ")}`;
|
|
219
218
|
const skills = { candidates: offered, picked: offered.map((candidate) => candidate.id), replace: [] };
|
|
220
219
|
const state = candidates === null ? "no instaladas (no se pudieron leer los catálogos)" : "no instaladas";
|
|
221
|
-
return { name: NAME, summary, installed: false, state, steps: [{ piece: NAME, checked: true, downloads: [],
|
|
220
|
+
return { name: NAME, summary, installed: false, state, steps: [{ piece: NAME, checked: true, downloads: [], text: { kind: "skills-install", count: offered.length, catalogs }, skills, run: (context) => install(context, skills) }] };
|
|
222
221
|
}
|
|
223
222
|
const general = manifestCatalogs(root).filter((source) => source.catalog !== FLOW_CATALOG);
|
|
224
223
|
const steps = (await Promise.all(general.map((source) => updateStep(root, source.catalog, source.ref)))).flatMap((step) => step ?? []);
|
|
@@ -227,7 +226,7 @@ export async function skillsStatus(root, withFlow) {
|
|
|
227
226
|
const fresh = (candidates ?? []).filter((candidate) => locked[candidate.name] === undefined);
|
|
228
227
|
if (fresh.length > 0) {
|
|
229
228
|
const skills = { candidates: fresh, picked: [], replace: [] };
|
|
230
|
-
steps.push({ piece: NAME, checked: false, downloads: [skillsManagerSpec(root)],
|
|
229
|
+
steps.push({ piece: NAME, checked: false, downloads: [skillsManagerSpec(root)], text: { kind: "skills-add", names: fresh.map((candidate) => candidate.name) }, skills, run: (context) => install(context, skills) });
|
|
231
230
|
}
|
|
232
231
|
const count = manifestCatalogs(root).reduce((total, source) => total + catalogSkills(root, source.catalog).length, 0);
|
|
233
232
|
const behind = steps.filter((step) => step.checked).length;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { Output } from "./output.js";
|
|
2
|
+
import type { StepText } from "./texts/step-text.js";
|
|
3
|
+
/** How a step's progress is shown. */
|
|
4
|
+
export interface Progress {
|
|
5
|
+
start: (text: StepText) => void;
|
|
6
|
+
stop: (text: StepText, ok: boolean) => void;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Progress as plain lines: the start, a line now and then while it runs, and the end.
|
|
10
|
+
* @param out - Where to write.
|
|
11
|
+
* @param options - Whether to print while it runs, how often, and the clock.
|
|
12
|
+
* @returns The progress.
|
|
13
|
+
* @example plainProgress(out, { ticks: true }).start({ kind: "guard-adjust" })
|
|
14
|
+
*/
|
|
15
|
+
export declare function plainProgress(out: Output, options: {
|
|
16
|
+
ticks: boolean;
|
|
17
|
+
tickMs?: number;
|
|
18
|
+
now?: () => number;
|
|
19
|
+
}): Progress;
|
|
20
|
+
/**
|
|
21
|
+
* How progress is shown: a spinner in a terminal, plain lines otherwise or when `plain` asks
|
|
22
|
+
* for them. Only for the steps, after every question: a spinner shown before a question
|
|
23
|
+
* leaves the second question deaf to the keyboard (@clack/prompts 1.8.1).
|
|
24
|
+
* @param out - Where to write.
|
|
25
|
+
* @param verbose - Whether the tools print on the terminal.
|
|
26
|
+
* @param plain - Whether a question may come after the steps (`--commit`).
|
|
27
|
+
* @returns The progress.
|
|
28
|
+
*/
|
|
29
|
+
export declare function progressFor(out: Output, verbose: boolean, plain: boolean): Progress;
|
package/dist/progress.js
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file How a step's progress is shown. Its start says what is happening ("Actualizando…") and
|
|
3
|
+
* its end what is left, with how long it took. In a terminal, a spinner; otherwise plain
|
|
4
|
+
* lines, and a step that takes a while prints how long it has been running, so it does not
|
|
5
|
+
* look stuck (unless the tools print their own output, with `--verbose`).
|
|
6
|
+
*/
|
|
7
|
+
import { spinner } from "@clack/prompts";
|
|
8
|
+
import { phrases, ui } from "./texts/index.js";
|
|
9
|
+
/** How often a plain step says it is still running. */
|
|
10
|
+
const TICK_MS = 10_000;
|
|
11
|
+
/**
|
|
12
|
+
* The end line of a step.
|
|
13
|
+
* @param text - What the step does.
|
|
14
|
+
* @param ok - Whether it worked.
|
|
15
|
+
* @param ms - How long it took.
|
|
16
|
+
* @returns The line, without the mark.
|
|
17
|
+
*/
|
|
18
|
+
function endLine(text, ok, ms) {
|
|
19
|
+
const said = phrases(text);
|
|
20
|
+
return `${ok ? said.done : ui.failed(said.menu)} (${ui.duration(ms)})`;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Progress as plain lines: the start, a line now and then while it runs, and the end.
|
|
24
|
+
* @param out - Where to write.
|
|
25
|
+
* @param options - Whether to print while it runs, how often, and the clock.
|
|
26
|
+
* @returns The progress.
|
|
27
|
+
* @example plainProgress(out, { ticks: true }).start({ kind: "guard-adjust" })
|
|
28
|
+
*/
|
|
29
|
+
export function plainProgress(out, options) {
|
|
30
|
+
const now = options.now ?? Date.now;
|
|
31
|
+
let started = 0;
|
|
32
|
+
let timer;
|
|
33
|
+
return {
|
|
34
|
+
start: (text) => {
|
|
35
|
+
started = now();
|
|
36
|
+
out.stdout(`${phrases(text).doing}\n`);
|
|
37
|
+
if (options.ticks)
|
|
38
|
+
timer = setInterval(() => out.stdout(`${ui.still(ui.duration(now() - started))}\n`), options.tickMs ?? TICK_MS);
|
|
39
|
+
},
|
|
40
|
+
stop: (text, ok) => {
|
|
41
|
+
clearInterval(timer);
|
|
42
|
+
timer = undefined;
|
|
43
|
+
out.stdout(`${ok ? "✓" : "✗"} ${endLine(text, ok, now() - started)}\n`);
|
|
44
|
+
},
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* How progress is shown: a spinner in a terminal, plain lines otherwise or when `plain` asks
|
|
49
|
+
* for them. Only for the steps, after every question: a spinner shown before a question
|
|
50
|
+
* leaves the second question deaf to the keyboard (@clack/prompts 1.8.1).
|
|
51
|
+
* @param out - Where to write.
|
|
52
|
+
* @param verbose - Whether the tools print on the terminal.
|
|
53
|
+
* @param plain - Whether a question may come after the steps (`--commit`).
|
|
54
|
+
* @returns The progress.
|
|
55
|
+
*/
|
|
56
|
+
export function progressFor(out, verbose, plain) {
|
|
57
|
+
if (out.interactive && !verbose && !plain) {
|
|
58
|
+
const spin = spinner();
|
|
59
|
+
let started = 0;
|
|
60
|
+
return {
|
|
61
|
+
start: (text) => {
|
|
62
|
+
started = Date.now();
|
|
63
|
+
spin.start(phrases(text).doing);
|
|
64
|
+
},
|
|
65
|
+
stop: (text, ok) => {
|
|
66
|
+
const line = endLine(text, ok, Date.now() - started);
|
|
67
|
+
if (ok)
|
|
68
|
+
spin.stop(line);
|
|
69
|
+
else
|
|
70
|
+
spin.error(line);
|
|
71
|
+
},
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
return plainProgress(out, { ticks: !verbose });
|
|
75
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file The shape of a catalog of the texts the person sees while `apply` runs its steps.
|
|
3
|
+
* Every language implements `Catalog`; the compiler then asks for every kind of step and every
|
|
4
|
+
* message. The interface uses `ui`; the commit and the PR do not (see commit-texts.ts).
|
|
5
|
+
*/
|
|
6
|
+
import type { StepKind, StepOf } from "./step-text.js";
|
|
7
|
+
/** One step's texts, one per place it shows. */
|
|
8
|
+
export interface StepPhrases {
|
|
9
|
+
/** In the menu and the lists of steps, as an order: "Actualizar issue-flow 0.2.7 → 0.3.0". */
|
|
10
|
+
menu: string;
|
|
11
|
+
/** While it runs: "Actualizando issue-flow de 0.2.7 a 0.3.0…". */
|
|
12
|
+
doing: string;
|
|
13
|
+
/** When it worked, saying what is left: "issue-flow actualizado de 0.2.7 a 0.3.0". */
|
|
14
|
+
done: string;
|
|
15
|
+
}
|
|
16
|
+
/** Every text of `apply` around its steps. */
|
|
17
|
+
export interface Catalog {
|
|
18
|
+
/** Each kind of step's texts. */
|
|
19
|
+
steps: {
|
|
20
|
+
[K in StepKind]: (step: StepOf<K>) => StepPhrases;
|
|
21
|
+
};
|
|
22
|
+
/** Added to a step of a piece the repo has not decided on yet. */
|
|
23
|
+
fresh: string;
|
|
24
|
+
/** The end line of a step that failed, from its menu text. */
|
|
25
|
+
failed: (menu: string) => string;
|
|
26
|
+
/** A duration, short: "0,4 s", "12 s", "1 min 5 s". */
|
|
27
|
+
duration: (ms: number) => string;
|
|
28
|
+
/** The line a long step prints while it runs, so it does not look stuck. */
|
|
29
|
+
still: (elapsed: string) => string;
|
|
30
|
+
/** The line before looking at the pieces. */
|
|
31
|
+
checking: string;
|
|
32
|
+
/** Nothing to install or update. */
|
|
33
|
+
upToDate: string;
|
|
34
|
+
/** With --yes and nothing suggested: the optional steps. */
|
|
35
|
+
onlyOptional: (menus: string[]) => string;
|
|
36
|
+
/** The heading of the steps listed without running them. */
|
|
37
|
+
suggested: (dryRun: boolean) => string;
|
|
38
|
+
/** The last line when every step worked or some failed. */
|
|
39
|
+
summary: (failed: string[]) => string;
|
|
40
|
+
/** What is left to do by hand after the steps, without --commit. */
|
|
41
|
+
next: (manager: string) => string;
|
|
42
|
+
/** A new piece left out because no one was asked about it. */
|
|
43
|
+
undecided: (names: string[]) => string;
|
|
44
|
+
/** The repo's own skills left out of a pick. */
|
|
45
|
+
ownSkillsKept: (names: string[]) => string;
|
|
46
|
+
/** The decisions were saved. */
|
|
47
|
+
saved: (file: string, commits: boolean) => string;
|
|
48
|
+
/** The closing line when no step ran: the person left, or picked none. */
|
|
49
|
+
noSteps: (why: "leave" | "none", wrote: boolean) => string;
|
|
50
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file The texts in Spanish. The menu orders ("Actualizar"), progress says what is happening
|
|
3
|
+
* ("Actualizando") and the end line says what is left ("actualizado").
|
|
4
|
+
*/
|
|
5
|
+
import type { Catalog } from "./catalog.js";
|
|
6
|
+
/** The texts in Spanish. */
|
|
7
|
+
export declare const es: Catalog;
|
package/dist/texts/es.js
ADDED
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A list of names, joined with commas.
|
|
3
|
+
* @param names - The names.
|
|
4
|
+
* @returns The list.
|
|
5
|
+
*/
|
|
6
|
+
const list = (names) => names.join(", ");
|
|
7
|
+
/** The texts in Spanish. */
|
|
8
|
+
export const es = {
|
|
9
|
+
steps: {
|
|
10
|
+
"skills-manager-create": ({ version }) => ({
|
|
11
|
+
menu: `Crear package.json con skills-manager ${version}`,
|
|
12
|
+
doing: `Creando package.json con skills-manager ${version}…`,
|
|
13
|
+
done: `package.json creado con skills-manager ${version}`,
|
|
14
|
+
}),
|
|
15
|
+
"skills-manager-add": ({ version }) => ({
|
|
16
|
+
menu: `Agregar skills-manager ${version} a package.json`,
|
|
17
|
+
doing: `Agregando skills-manager ${version} a package.json…`,
|
|
18
|
+
done: `skills-manager ${version} agregado a package.json`,
|
|
19
|
+
}),
|
|
20
|
+
"skills-manager-bump": ({ from, to }) => ({
|
|
21
|
+
menu: `Subir skills-manager ${from} → ${to}, el mínimo de agent-kitchen`,
|
|
22
|
+
doing: `Subiendo skills-manager de ${from} a ${to}…`,
|
|
23
|
+
done: `skills-manager subido de ${from} a ${to}`,
|
|
24
|
+
}),
|
|
25
|
+
"flow-install": ({ version }) => ({
|
|
26
|
+
menu: `Instalar issue-flow ${version}: config del flujo, hooks y scripts`,
|
|
27
|
+
doing: `Instalando issue-flow ${version}…`,
|
|
28
|
+
done: `issue-flow ${version} instalado: config del flujo, hooks y scripts`,
|
|
29
|
+
}),
|
|
30
|
+
"flow-update": ({ from, to }) => ({
|
|
31
|
+
menu: `Actualizar issue-flow ${from} → ${to}, con sus hooks y sus skills`,
|
|
32
|
+
doing: `Actualizando issue-flow de ${from} a ${to}…`,
|
|
33
|
+
done: `issue-flow actualizado de ${from} a ${to}, con sus hooks y sus skills`,
|
|
34
|
+
}),
|
|
35
|
+
"flow-repair": ({ version }) => ({
|
|
36
|
+
menu: `Reparar issue-flow ${version}: hooks y $schema`,
|
|
37
|
+
doing: `Reparando issue-flow ${version}…`,
|
|
38
|
+
done: `issue-flow ${version} reparado: hooks y $schema`,
|
|
39
|
+
}),
|
|
40
|
+
"flow-skills": ({ version }) => ({
|
|
41
|
+
menu: `Poner las skills del flujo en v${version}, la versión de issue-flow`,
|
|
42
|
+
doing: `Poniendo las skills del flujo en v${version}…`,
|
|
43
|
+
done: `Skills del flujo en v${version}, la versión de issue-flow`,
|
|
44
|
+
}),
|
|
45
|
+
"flow-labels": ({ missing }) => ({
|
|
46
|
+
menu: `Crear en GitHub los labels que faltan: ${list(missing)}`,
|
|
47
|
+
doing: `Creando en GitHub los labels que faltan: ${list(missing)}…`,
|
|
48
|
+
done: `Labels creados en GitHub: ${list(missing)}`,
|
|
49
|
+
}),
|
|
50
|
+
"github-rest-bump": ({ from, to, flow }) => ({
|
|
51
|
+
menu: `Subir github-rest ${from} → ${to}, el mínimo de issue-flow ${flow}`,
|
|
52
|
+
doing: `Subiendo github-rest de ${from} a ${to}…`,
|
|
53
|
+
done: `github-rest subido de ${from} a ${to}, el mínimo de issue-flow ${flow}`,
|
|
54
|
+
}),
|
|
55
|
+
"cloud-install": ({ version }) => ({
|
|
56
|
+
menu: `Instalar claude-cloud ${version ?? "1.x"}: prepara las sesiones en la nube de Claude`,
|
|
57
|
+
doing: `Instalando claude-cloud ${version ?? "1.x"}…`,
|
|
58
|
+
done: `claude-cloud ${version ?? "1.x"} instalado: prepara las sesiones en la nube de Claude`,
|
|
59
|
+
}),
|
|
60
|
+
"cloud-update": ({ from, to, config }) => ({
|
|
61
|
+
menu: `Actualizar claude-cloud ${from ?? "?"} → ${to} (la versión que fija ${config})`,
|
|
62
|
+
doing: `Actualizando claude-cloud de ${from ?? "?"} a ${to}…`,
|
|
63
|
+
done: `claude-cloud actualizado de ${from ?? "?"} a ${to} en ${config}`,
|
|
64
|
+
}),
|
|
65
|
+
"guard-install": ({ version }) => ({
|
|
66
|
+
menu: `Instalar claude-repo-guard ${version ?? "(main)"}: modo auto con sandbox, y un documento de qué protege`,
|
|
67
|
+
doing: `Instalando claude-repo-guard ${version ?? "(main)"}…`,
|
|
68
|
+
done: `claude-repo-guard ${version ?? "(main)"} instalado: modo auto con sandbox, y un documento de qué protege`,
|
|
69
|
+
}),
|
|
70
|
+
"guard-update": ({ from, to }) => ({
|
|
71
|
+
menu: `Actualizar claude-repo-guard ${from ?? "?"} → ${to}`,
|
|
72
|
+
doing: `Actualizando claude-repo-guard de ${from ?? "?"} a ${to}…`,
|
|
73
|
+
done: `claude-repo-guard actualizado de ${from ?? "?"} a ${to}`,
|
|
74
|
+
}),
|
|
75
|
+
"guard-adjust": () => ({
|
|
76
|
+
menu: "Ajustar claude-repo-guard a lo que necesita el flujo de issues",
|
|
77
|
+
doing: "Ajustando claude-repo-guard al flujo de issues…",
|
|
78
|
+
done: "claude-repo-guard ajustado a lo que necesita el flujo de issues",
|
|
79
|
+
}),
|
|
80
|
+
"skills-install": ({ count, catalogs }) => ({
|
|
81
|
+
menu: `Instalar ${count} skills de ${catalogs.join(" y ")}`,
|
|
82
|
+
doing: `Instalando ${count} skills de ${catalogs.join(" y ")}…`,
|
|
83
|
+
done: `${count} skills instaladas de ${catalogs.join(" y ")}`,
|
|
84
|
+
}),
|
|
85
|
+
"skills-update": ({ catalog, from, to, names }) => ({
|
|
86
|
+
menu: `Actualizar skills de ${catalog} ${from} → v${to}: ${list(names)}`,
|
|
87
|
+
doing: `Actualizando skills de ${catalog} de ${from} a v${to}…`,
|
|
88
|
+
done: `Skills de ${catalog} actualizadas a v${to}: ${list(names)}`,
|
|
89
|
+
}),
|
|
90
|
+
"skills-add": ({ names }) => ({
|
|
91
|
+
menu: `Agregar skills nuevas (${names.length}): ${list(names)}`,
|
|
92
|
+
doing: `Agregando skills nuevas: ${list(names)}…`,
|
|
93
|
+
done: `Skills nuevas agregadas: ${list(names)}`,
|
|
94
|
+
}),
|
|
95
|
+
"agents-md": ({ rule, claudeImport }) => {
|
|
96
|
+
const files = [...(rule ? ["AGENTS.md"] : []), ...(claudeImport ? ["CLAUDE.md"] : [])].join(", ");
|
|
97
|
+
if (!rule)
|
|
98
|
+
return {
|
|
99
|
+
menu: `Agregar @AGENTS.md a CLAUDE.md, para que Claude Code lea AGENTS.md: ${files}`,
|
|
100
|
+
doing: "Agregando @AGENTS.md a CLAUDE.md…",
|
|
101
|
+
done: "@AGENTS.md agregado a CLAUDE.md: Claude Code lee AGENTS.md",
|
|
102
|
+
};
|
|
103
|
+
const also = claudeImport ? " (y @AGENTS.md en CLAUDE.md)" : "";
|
|
104
|
+
return {
|
|
105
|
+
menu: `Agregar a AGENTS.md la regla de versiones instaladas${also}: ${files}`,
|
|
106
|
+
doing: `Agregando a AGENTS.md la regla de versiones instaladas${also}…`,
|
|
107
|
+
done: `Regla de versiones instaladas agregada a AGENTS.md${also}`,
|
|
108
|
+
};
|
|
109
|
+
},
|
|
110
|
+
"install-deps": ({ manager }) => ({
|
|
111
|
+
menu: `Instalar las dependencias con ${manager}`,
|
|
112
|
+
doing: `Instalando las dependencias con ${manager}…`,
|
|
113
|
+
done: `Dependencias instaladas con ${manager}`,
|
|
114
|
+
}),
|
|
115
|
+
},
|
|
116
|
+
fresh: " (nueva)",
|
|
117
|
+
failed: (menu) => `Falló: ${menu}`,
|
|
118
|
+
duration: (ms) => {
|
|
119
|
+
if (ms < 10_000)
|
|
120
|
+
return `${(ms / 1000).toFixed(1).replace(".", ",")} s`;
|
|
121
|
+
const seconds = Math.round(ms / 1000);
|
|
122
|
+
return seconds < 60 ? `${seconds} s` : `${Math.floor(seconds / 60)} min${seconds % 60 === 0 ? "" : ` ${seconds % 60} s`}`;
|
|
123
|
+
},
|
|
124
|
+
still: (elapsed) => ` … sigue (${elapsed})`,
|
|
125
|
+
checking: "Revisando el repo y las últimas versiones…",
|
|
126
|
+
upToDate: "Todo al día: no hay nada que instalar ni actualizar.",
|
|
127
|
+
onlyOptional: (menus) => `Todo al día. Opcional, para elegir en una terminal: ${menus.join("; ")}.`,
|
|
128
|
+
suggested: (dryRun) => `Pasos sugeridos${dryRun ? "" : " (para hacerlos, corre agent-kitchen apply en una terminal, o con --yes)"}:`,
|
|
129
|
+
summary: (failed) => (failed.length === 0 ? "Listo." : `Terminó, pero fallaron: ${failed.join("; ")}.`),
|
|
130
|
+
next: (manager) => `Falta: corre '${manager} install', revisa el diff y haz commit.`,
|
|
131
|
+
undecided: (names) => `Pieza nueva sin decisión: ${list(names)}. Corre agent-kitchen apply en una terminal para elegir.`,
|
|
132
|
+
ownSkillsKept: (names) => `Se dejan fuera las skills que el repo ya tiene como propias: ${list(names)}. Para reemplazarlas, corre agent-kitchen apply en una terminal.`,
|
|
133
|
+
saved: (file, commits) => `Guardé qué piezas usa el repo en ${file}${commits ? "" : "; commitéalo"}.`,
|
|
134
|
+
noSteps: (why, wrote) => {
|
|
135
|
+
if (why === "leave")
|
|
136
|
+
return wrote ? "No corrí ningún paso; solo guardé qué piezas usa el repo." : "No se cambió nada.";
|
|
137
|
+
return wrote ? "No elegiste pasos; solo guardé qué piezas usa el repo." : "No elegiste nada; no se cambió nada.";
|
|
138
|
+
},
|
|
139
|
+
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file The interface's texts, and how a step reads in a list. Another language is a file
|
|
3
|
+
* like es.ts that implements `Catalog`, chosen here.
|
|
4
|
+
*/
|
|
5
|
+
import type { Step } from "../piece.js";
|
|
6
|
+
import type { Catalog, StepPhrases } from "./catalog.js";
|
|
7
|
+
import type { StepText } from "./step-text.js";
|
|
8
|
+
/** The catalog the interface uses. */
|
|
9
|
+
export declare const ui: Catalog;
|
|
10
|
+
/**
|
|
11
|
+
* A step's texts in a catalog.
|
|
12
|
+
* @param catalog - The catalog.
|
|
13
|
+
* @param text - What the step does.
|
|
14
|
+
* @returns Its texts.
|
|
15
|
+
* @example phrasesIn(es, { kind: "guard-adjust" }).doing // "Ajustando claude-repo-guard al flujo de issues…"
|
|
16
|
+
*/
|
|
17
|
+
export declare function phrasesIn(catalog: Catalog, text: StepText): StepPhrases;
|
|
18
|
+
/**
|
|
19
|
+
* A step's texts in the interface.
|
|
20
|
+
* @param text - What the step does.
|
|
21
|
+
* @returns Its texts.
|
|
22
|
+
*/
|
|
23
|
+
export declare function phrases(text: StepText): StepPhrases;
|
|
24
|
+
/**
|
|
25
|
+
* How a step reads in the menu and in lists: its order, marked if its piece is new.
|
|
26
|
+
* @param step - The step.
|
|
27
|
+
* @returns The text.
|
|
28
|
+
* @example stepLabel(step) // "Actualizar issue-flow 0.2.7 → 0.3.0, con sus hooks y sus skills"
|
|
29
|
+
*/
|
|
30
|
+
export declare function stepLabel(step: Pick<Step, "text" | "fresh">): string;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { es } from "./es.js";
|
|
2
|
+
/** The catalog the interface uses. */
|
|
3
|
+
export const ui = es;
|
|
4
|
+
/**
|
|
5
|
+
* A step's texts in a catalog.
|
|
6
|
+
* @param catalog - The catalog.
|
|
7
|
+
* @param text - What the step does.
|
|
8
|
+
* @returns Its texts.
|
|
9
|
+
* @example phrasesIn(es, { kind: "guard-adjust" }).doing // "Ajustando claude-repo-guard al flujo de issues…"
|
|
10
|
+
*/
|
|
11
|
+
export function phrasesIn(catalog, text) {
|
|
12
|
+
const render = catalog.steps[text.kind];
|
|
13
|
+
return render(text);
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* A step's texts in the interface.
|
|
17
|
+
* @param text - What the step does.
|
|
18
|
+
* @returns Its texts.
|
|
19
|
+
*/
|
|
20
|
+
export function phrases(text) {
|
|
21
|
+
return phrasesIn(ui, text);
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* How a step reads in the menu and in lists: its order, marked if its piece is new.
|
|
25
|
+
* @param step - The step.
|
|
26
|
+
* @returns The text.
|
|
27
|
+
* @example stepLabel(step) // "Actualizar issue-flow 0.2.7 → 0.3.0, con sus hooks y sus skills"
|
|
28
|
+
*/
|
|
29
|
+
export function stepLabel(step) {
|
|
30
|
+
return `${phrases(step.text).menu}${step.fresh === true ? ui.fresh : ""}`;
|
|
31
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file What a step does, as data: its kind, the piece's versions and what it brings. No
|
|
3
|
+
* words here; each place that shows a step (the menu, the start and end of its progress, the
|
|
4
|
+
* commit) turns this into its own text, so the interface can change language without the
|
|
5
|
+
* commits changing too.
|
|
6
|
+
*/
|
|
7
|
+
/** A version that may be unknown (`null`), shown as `?` or as the place it comes from. */
|
|
8
|
+
type MaybeVersion = string | null;
|
|
9
|
+
/** What a step does, one kind per thing a piece can offer. */
|
|
10
|
+
export type StepText = {
|
|
11
|
+
kind: "skills-manager-create";
|
|
12
|
+
version: string;
|
|
13
|
+
} | {
|
|
14
|
+
kind: "skills-manager-add";
|
|
15
|
+
version: string;
|
|
16
|
+
} | {
|
|
17
|
+
kind: "skills-manager-bump";
|
|
18
|
+
from: string;
|
|
19
|
+
to: string;
|
|
20
|
+
} | {
|
|
21
|
+
kind: "flow-install";
|
|
22
|
+
version: string;
|
|
23
|
+
} | {
|
|
24
|
+
kind: "flow-update";
|
|
25
|
+
from: string;
|
|
26
|
+
to: string;
|
|
27
|
+
} | {
|
|
28
|
+
kind: "flow-repair";
|
|
29
|
+
version: string;
|
|
30
|
+
} | {
|
|
31
|
+
kind: "flow-skills";
|
|
32
|
+
version: string;
|
|
33
|
+
} | {
|
|
34
|
+
kind: "flow-labels";
|
|
35
|
+
missing: string[];
|
|
36
|
+
} | {
|
|
37
|
+
kind: "github-rest-bump";
|
|
38
|
+
from: string;
|
|
39
|
+
to: string;
|
|
40
|
+
flow: string;
|
|
41
|
+
} | {
|
|
42
|
+
kind: "cloud-install";
|
|
43
|
+
version: MaybeVersion;
|
|
44
|
+
} | {
|
|
45
|
+
kind: "cloud-update";
|
|
46
|
+
from: MaybeVersion;
|
|
47
|
+
to: string;
|
|
48
|
+
config: string;
|
|
49
|
+
} | {
|
|
50
|
+
kind: "guard-install";
|
|
51
|
+
version: MaybeVersion;
|
|
52
|
+
} | {
|
|
53
|
+
kind: "guard-update";
|
|
54
|
+
from: MaybeVersion;
|
|
55
|
+
to: string;
|
|
56
|
+
} | {
|
|
57
|
+
kind: "guard-adjust";
|
|
58
|
+
} | {
|
|
59
|
+
kind: "skills-install";
|
|
60
|
+
count: number;
|
|
61
|
+
catalogs: string[];
|
|
62
|
+
} | {
|
|
63
|
+
kind: "skills-update";
|
|
64
|
+
catalog: string;
|
|
65
|
+
from: string;
|
|
66
|
+
to: string;
|
|
67
|
+
names: string[];
|
|
68
|
+
} | {
|
|
69
|
+
kind: "skills-add";
|
|
70
|
+
names: string[];
|
|
71
|
+
} | {
|
|
72
|
+
kind: "agents-md";
|
|
73
|
+
rule: boolean;
|
|
74
|
+
claudeImport: boolean;
|
|
75
|
+
} | {
|
|
76
|
+
kind: "install-deps";
|
|
77
|
+
manager: string;
|
|
78
|
+
};
|
|
79
|
+
/** The kinds of step. */
|
|
80
|
+
export type StepKind = StepText["kind"];
|
|
81
|
+
/** The data of one kind of step. */
|
|
82
|
+
export type StepOf<K extends StepKind> = Extract<StepText, {
|
|
83
|
+
kind: K;
|
|
84
|
+
}>;
|
|
85
|
+
export {};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file What a step does, as data: its kind, the piece's versions and what it brings. No
|
|
3
|
+
* words here; each place that shows a step (the menu, the start and end of its progress, the
|
|
4
|
+
* commit) turns this into its own text, so the interface can change language without the
|
|
5
|
+
* commits changing too.
|
|
6
|
+
*/
|
|
7
|
+
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agent-kitchen",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"description": "One command to install, update and check a repo's agent tooling: the issue flow and its skills, the general skills, Claude cloud sessions, claude-repo-guard and the installed-versions rule in AGENTS.md.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|