kaizen-agent 1.7.9 → 1.8.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/LICENSE +21 -21
- package/README.md +694 -658
- package/agents/kaizen-builder.md +82 -77
- package/agents/kaizen-planner.md +250 -250
- package/agents/kaizen-reviewer.md +127 -127
- package/cli/board.test.ts +55 -0
- package/cli/dashboard.ts +1188 -1187
- package/cli/install.ts +76 -3
- package/cli/publish-gh.sh +27 -27
- package/cli/release.sh +45 -45
- package/cli/settings.ts +7 -3
- package/cli/sources.test.ts +494 -0
- package/cli/sources.ts +323 -0
- package/cli/state.test.ts +427 -197
- package/cli/state.ts +1013 -700
- package/cli/web.ts +188 -11
- package/commands/kaizen-abort.md +5 -5
- package/commands/kaizen-approve.md +5 -5
- package/commands/kaizen-auto.md +6 -6
- package/commands/kaizen-backlog.md +5 -5
- package/commands/kaizen-config.md +5 -5
- package/commands/kaizen-full.md +5 -5
- package/commands/kaizen-gather.md +5 -0
- package/commands/kaizen-init.md +5 -5
- package/commands/kaizen-install.md +5 -5
- package/commands/kaizen-lite.md +5 -5
- package/commands/kaizen-plan.md +6 -6
- package/commands/kaizen-reject.md +6 -6
- package/commands/kaizen-review.md +6 -6
- package/commands/kaizen-run.md +5 -5
- package/commands/kaizen-status.md +5 -5
- package/package.json +3 -1
- package/skills/kaizen/README.md +283 -281
- package/skills/kaizen/SKILL.md +334 -440
- package/skills/kaizen/adapters.md +84 -77
- package/skills/kaizen/config.default.yml +181 -167
- package/skills/kaizen/gather.md +50 -0
- package/skills/kaizen/install.md +42 -0
- package/skills/kaizen/settings.md +52 -0
- package/skills/kaizen/spec-build.md +131 -119
- package/skills/kaizen/spec-main.md +109 -104
- package/skills/kaizen/spec-plan.md +201 -201
- package/skills/kaizen/spec-review.md +121 -121
- package/skills/kaizen/spec.md +154 -153
- package/skills/kaizen/status.md +43 -0
- package/skills/kaizen-help/SKILL.md +131 -129
- package/web/board.html +296 -125
package/cli/web.ts
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
// `kaizen web`: the board in a browser. A loopback HTTP server over state.ts and
|
|
2
2
|
// one HTML page; the page never sees the filesystem, only JSON.
|
|
3
|
-
import { existsSync, readFileSync, readdirSync, statSync, watch, appendFileSync, type FSWatcher } from "node:fs";
|
|
3
|
+
import { existsSync, readFileSync, readdirSync, statSync, watch, appendFileSync, mkdirSync, type FSWatcher } from "node:fs";
|
|
4
4
|
import { join, dirname } from "node:path";
|
|
5
5
|
import {
|
|
6
|
-
home, type Item, boardCards, knownProjects, remember, locate, label, tilde,
|
|
6
|
+
home, type Item, type Card, boardCards, knownProjects, remember, locate, label, tilde, searchRoots, findProjects,
|
|
7
7
|
readInbox, writeInbox, replaceIdea, abandonRun, launchRun, parseItem, short, setArchived, writeNotes,
|
|
8
|
-
appendNote, saveAttachment, pidOnPort,
|
|
8
|
+
appendNote, saveAttachment, pidOnPort, runGit, cardsGit, readCommit, commitPush, notice, notifier, LOGO,
|
|
9
|
+
reviewFindings, pickFindings, fixPrompt,
|
|
9
10
|
} from "./state.ts";
|
|
11
|
+
import { readSources, addSource, removeSource, moveSource, gatherSource, gatherAll, gatherDirs, due } from "./sources.ts";
|
|
10
12
|
|
|
11
13
|
const PAGE = join(dirname(import.meta.dir), "web", "board.html");
|
|
12
14
|
const DEFAULT_PORT = 7420;
|
|
@@ -25,9 +27,32 @@ export async function web(repoDir: string, opts: Opts = {}) {
|
|
|
25
27
|
if (ev === "uncaughtException") process.exit(1);
|
|
26
28
|
});
|
|
27
29
|
}
|
|
28
|
-
|
|
30
|
+
// Not fixed for the life of the board: picking a project in the page moves here.
|
|
31
|
+
let state = locate();
|
|
29
32
|
if (state && dirname(state) !== home) remember(dirname(state));
|
|
30
|
-
|
|
33
|
+
let project = state ? label(state) : null;
|
|
34
|
+
// Folders under the "Projects folder" setting that have no .kaizen yet, offered in
|
|
35
|
+
// the project list so one can be chosen without a terminal. A folder that does not
|
|
36
|
+
// look like a project itself (no .git, no package.json) is taken for a group of
|
|
37
|
+
// them, and its own folders are offered too: ~/Projects/<client>/<project>.
|
|
38
|
+
const fresh = async () => {
|
|
39
|
+
const { listSettings } = await import("./settings.ts");
|
|
40
|
+
let root = listSettings(repoDir).rows.find((r) => r.key === "board.projects_dir")?.value ?? "";
|
|
41
|
+
if (root.startsWith("~")) root = home + root.slice(1);
|
|
42
|
+
if (!root) return [];
|
|
43
|
+
const dirs = (d: string) => {
|
|
44
|
+
try {
|
|
45
|
+
return readdirSync(d).filter((n) => !n.startsWith(".") && n !== "node_modules")
|
|
46
|
+
.map((n) => join(d, n)).filter((p) => { try { return statSync(p).isDirectory(); } catch { return false; } });
|
|
47
|
+
} catch { return []; }
|
|
48
|
+
};
|
|
49
|
+
// .kaizen is not a sign of one: a group folder that was chosen once has it, and
|
|
50
|
+
// must keep showing what is inside.
|
|
51
|
+
const isProject = (d: string) => [".git", "package.json"].some((m) => existsSync(join(d, m)));
|
|
52
|
+
// One already set up but never opened joins the known projects instead.
|
|
53
|
+
return dirs(root).flatMap((d) => isProject(d) ? [d] : [d, ...dirs(d)])
|
|
54
|
+
.filter((d) => existsSync(join(d, ".kaizen")) ? (remember(d), false) : true).sort();
|
|
55
|
+
};
|
|
31
56
|
|
|
32
57
|
const states = (all: boolean) => (all || !state
|
|
33
58
|
? [...knownProjects().map((d) => join(d, ".kaizen")), join(home, ".kaizen")]
|
|
@@ -78,7 +103,7 @@ export async function web(repoDir: string, opts: Opts = {}) {
|
|
|
78
103
|
const fingerprint = () => {
|
|
79
104
|
let sum = 0;
|
|
80
105
|
for (const dir of states(true)) {
|
|
81
|
-
for (const f of ["inbox.md", "backlog.md", "archive.md"]) { try { sum += statSync(join(dir, f)).mtimeMs; } catch { /* absent */ } }
|
|
106
|
+
for (const f of ["inbox.md", "backlog.md", "archive.md", "sources.json"]) { try { sum += statSync(join(dir, f)).mtimeMs; } catch { /* absent */ } }
|
|
82
107
|
const runs = join(dir, "runs");
|
|
83
108
|
if (!existsSync(runs)) continue;
|
|
84
109
|
for (const id of readdirSync(runs)) { try { sum += statSync(join(runs, id, "state.json")).mtimeMs; } catch { /* absent */ } }
|
|
@@ -93,6 +118,28 @@ export async function web(repoDir: string, opts: Opts = {}) {
|
|
|
93
118
|
const fp = fingerprint(); if (fp !== last) { last = fp; changed(); }
|
|
94
119
|
}, 2000);
|
|
95
120
|
|
|
121
|
+
// The schedule: once a minute, gather every request source that is due. It writes
|
|
122
|
+
// inbox.md and sources.json only, never a state.json, and starts nothing. All of
|
|
123
|
+
// it sits in a try: an uncaught error here would end the board.
|
|
124
|
+
const every = async () => {
|
|
125
|
+
const { listSettings } = await import("./settings.ts");
|
|
126
|
+
return listSettings(repoDir).rows.find((r) => r.key === "sources.every")?.value ?? "off";
|
|
127
|
+
};
|
|
128
|
+
let busy = false;
|
|
129
|
+
const gather = setInterval(async () => {
|
|
130
|
+
if (busy) return;
|
|
131
|
+
busy = true;
|
|
132
|
+
try {
|
|
133
|
+
const ms = (parseInt(await every()) || 0) * 3600_000; // "off" parses to nothing
|
|
134
|
+
if (ms) for (const dir of states(true)) {
|
|
135
|
+
let list;
|
|
136
|
+
try { list = readSources(dir); } catch { continue; } // unreadable: left as it is
|
|
137
|
+
for (const s of list) if (due(s, ms, Date.now()) && (await gatherSource(dir, s.url)).added) changed();
|
|
138
|
+
}
|
|
139
|
+
} catch { /* the next tick tries again */ }
|
|
140
|
+
busy = false;
|
|
141
|
+
}, 60_000);
|
|
142
|
+
|
|
96
143
|
const BOOT = Date.now().toString(36);
|
|
97
144
|
const ping = setInterval(() => { for (const c of clients) { try { c.enqueue(": ping\n\n"); } catch { clients.delete(c); } } }, 8000);
|
|
98
145
|
// A launcher clicked while a board is already up should show that board, not die.
|
|
@@ -133,18 +180,34 @@ export async function web(repoDir: string, opts: Opts = {}) {
|
|
|
133
180
|
|
|
134
181
|
if (req.method === "GET" && path === "/") {
|
|
135
182
|
if (!existsSync(PAGE)) return new Response("web/board.html missing", { status: 500 });
|
|
136
|
-
|
|
183
|
+
// The page gets the notify rule from state.ts rather than keeping its own copy.
|
|
184
|
+
return new Response(readFileSync(PAGE, "utf8").replace("/*notifier*/", () => notifier.toString()), {
|
|
137
185
|
headers: { "content-type": "text/html; charset=utf-8", "cache-control": "no-store" },
|
|
138
186
|
});
|
|
139
187
|
}
|
|
140
188
|
|
|
189
|
+
// The icon on a web notification; this one file and nothing beside it.
|
|
190
|
+
if (req.method === "GET" && path === "/logo.png") {
|
|
191
|
+
if (!existsSync(LOGO)) return bad("no logo", 404);
|
|
192
|
+
return new Response(Bun.file(LOGO), { headers: { "content-type": "image/png", "cache-control": "max-age=86400" } });
|
|
193
|
+
}
|
|
194
|
+
|
|
141
195
|
if (req.method === "GET" && path === "/state") {
|
|
142
196
|
const all = url.searchParams.get("all") === "1";
|
|
197
|
+
// Before the project list: it registers folders that turn out to be set up.
|
|
198
|
+
const unset = await fresh();
|
|
143
199
|
const dirs = states(all);
|
|
200
|
+
const cards = boardCards(dirs, Date.now());
|
|
201
|
+
// The git mark, for the cards whose panel offers commit and push: one status per project.
|
|
202
|
+
const marks = new Map<string, Record<string, string>>();
|
|
203
|
+
const markable = (c: Card) => c.kind === "run" && !c.archived && (c.status === "done" || c.awaiting === "approvals.review") && c.state !== join(home, ".kaizen");
|
|
204
|
+
for (const d of new Set(cards.filter(markable).map((c) => c.state)))
|
|
205
|
+
marks.set(d, cardsGit(d, cards.filter((c) => markable(c) && c.state === d).map((c) => c.id!)));
|
|
144
206
|
return json({
|
|
145
|
-
project, all,
|
|
207
|
+
project, all, dir: state,
|
|
146
208
|
projects: states(true).map((d) => ({ dir: d, label: label(d) })),
|
|
147
|
-
|
|
209
|
+
fresh: unset.map((d) => ({ dir: join(d, ".kaizen"), label: tilde(d) })),
|
|
210
|
+
cards: cards.map((c) => ({ ...c, notice: notice(c), git: markable(c) ? marks.get(c.state)?.[c.id!] : undefined })),
|
|
148
211
|
now: Date.now(),
|
|
149
212
|
});
|
|
150
213
|
}
|
|
@@ -161,9 +224,27 @@ export async function web(repoDir: string, opts: Opts = {}) {
|
|
|
161
224
|
request: read("00-request.md"), plan: read("01-plan.md"), approval: read("02-approval.md"),
|
|
162
225
|
impl: read("03-impl.md"), review: read("04-review.md"), backlog: read("06-backlog.md"),
|
|
163
226
|
notes: read("notes.md"),
|
|
227
|
+
// Nothing to pick in the global state dir: /fix refuses it.
|
|
228
|
+
findings: dir === join(home, ".kaizen") ? [] : reviewFindings(dir, id),
|
|
229
|
+
// The global state dir sits in $HOME, which is not a project to commit.
|
|
230
|
+
commit: readCommit(dir, id), git: dir === join(home, ".kaizen") ? { repo: false } : runGit(dir, id),
|
|
164
231
|
});
|
|
165
232
|
}
|
|
166
233
|
|
|
234
|
+
if (req.method === "GET" && path === "/sources") {
|
|
235
|
+
// One project's sources, or with no dir every known project's: each entry
|
|
236
|
+
// says which project it belongs to. Nothing is assumed from where the board started.
|
|
237
|
+
const dir = url.searchParams.get("dir");
|
|
238
|
+
if (dir && !states(true).includes(dir)) return bad("unknown state dir", 404);
|
|
239
|
+
const sources = [], failed = [];
|
|
240
|
+
for (const d of dir ? [dir] : states(true)) {
|
|
241
|
+
// The seen list is bookkeeping, not something the page shows.
|
|
242
|
+
try { sources.push(...readSources(d).map(({ seen, ...s }) => ({ ...s, dir: d }))); }
|
|
243
|
+
catch { failed.push(label(d)); }
|
|
244
|
+
}
|
|
245
|
+
return json({ sources, failed, every: await every() });
|
|
246
|
+
}
|
|
247
|
+
|
|
167
248
|
if (req.method === "GET" && path === "/settings") {
|
|
168
249
|
const { listSettings } = await import("./settings.ts");
|
|
169
250
|
return json(listSettings(repoDir));
|
|
@@ -208,10 +289,38 @@ export async function web(repoDir: string, opts: Opts = {}) {
|
|
|
208
289
|
if (!local(req)) return bad("cross-origin write refused", 403);
|
|
209
290
|
let body: any;
|
|
210
291
|
try { body = await req.json(); } catch { return bad("json body expected"); }
|
|
292
|
+
|
|
293
|
+
// The same search as the TUI's "find more": every .kaizen under $HOME, the
|
|
294
|
+
// drives, and where the board was started, added to the registry.
|
|
295
|
+
// ponytail: synchronous walk, the board stalls for its length; move to a worker if a big disk makes that seconds.
|
|
296
|
+
if (path === "/find") {
|
|
297
|
+
const before = knownProjects().length;
|
|
298
|
+
const roots = searchRoots([dirname(state ?? process.cwd()), process.cwd()]);
|
|
299
|
+
for (const d of new Set(roots.flatMap((r) => findProjects(r)))) remember(d);
|
|
300
|
+
changed();
|
|
301
|
+
return json({ ok: true, added: knownProjects().length - before });
|
|
302
|
+
}
|
|
303
|
+
|
|
211
304
|
// No project here means the global inbox, which is where the TUI puts ideas too.
|
|
212
305
|
const dir: string = body.dir ?? state ?? join(home, ".kaizen");
|
|
306
|
+
// Choosing a folder from the projects folder is what sets it up: an empty
|
|
307
|
+
// .kaizen, which the first run fills in. Only folders the board offered.
|
|
308
|
+
if (path === "/cd" && dir === join(dirname(dir), ".kaizen") && (await fresh()).includes(dirname(dir))) {
|
|
309
|
+
mkdirSync(dir, { recursive: true });
|
|
310
|
+
remember(dirname(dir));
|
|
311
|
+
}
|
|
213
312
|
if (!dir || !states(true).includes(dir)) return bad("unknown state dir", 404);
|
|
214
313
|
|
|
314
|
+
// The board moves to the chosen project: new ideas and runs default to it,
|
|
315
|
+
// and the process follows so anything resolved from cwd agrees.
|
|
316
|
+
if (path === "/cd") {
|
|
317
|
+
state = dir;
|
|
318
|
+
project = label(dir);
|
|
319
|
+
try { process.chdir(dirname(dir)); } catch { /* the state dir is what matters */ }
|
|
320
|
+
changed();
|
|
321
|
+
return json({ ok: true, project });
|
|
322
|
+
}
|
|
323
|
+
|
|
215
324
|
if (path === "/inbox") {
|
|
216
325
|
const text = String(body.text ?? "").trim();
|
|
217
326
|
// Absent means untouched; an empty string clears. replaceIdea keeps the
|
|
@@ -235,6 +344,40 @@ export async function web(repoDir: string, opts: Opts = {}) {
|
|
|
235
344
|
return json({ ok: true });
|
|
236
345
|
}
|
|
237
346
|
|
|
347
|
+
// Request sources. Gathering adds ideas and nothing else: no run starts here.
|
|
348
|
+
if (path === "/sources") {
|
|
349
|
+
const link = String(body.url ?? "").trim();
|
|
350
|
+
// A source belongs to the project the request names. The fallback above
|
|
351
|
+
// (where the board started, or the global dir) is a guess, and a guess
|
|
352
|
+
// here puts someone's requests in the wrong project.
|
|
353
|
+
const named = typeof body.dir === "string" && body.dir !== "";
|
|
354
|
+
try {
|
|
355
|
+
let results;
|
|
356
|
+
if (body.op === "gather" && !named && !link) {
|
|
357
|
+
results = await gatherDirs(states(true));
|
|
358
|
+
changed();
|
|
359
|
+
return json({ ok: true, results });
|
|
360
|
+
}
|
|
361
|
+
if (!named) return bad(body.op === "add" ? "choose the project this source belongs to" : "say which project's source this is");
|
|
362
|
+
if (body.op === "add") {
|
|
363
|
+
const why = addSource(dir, link, typeof body.label === "string" ? body.label : undefined);
|
|
364
|
+
if (why) return bad(why);
|
|
365
|
+
} else if (body.op === "remove") {
|
|
366
|
+
const why = removeSource(dir, link);
|
|
367
|
+
if (why) return bad(why, 404);
|
|
368
|
+
} else if (body.op === "move") {
|
|
369
|
+
if (typeof body.to !== "string" || !states(true).includes(body.to)) return bad("unknown state dir", 404);
|
|
370
|
+
const why = moveSource(dir, body.to, link);
|
|
371
|
+
if (why) return bad(why, why === "no such source" ? 404 : 409);
|
|
372
|
+
} else if (body.op === "gather") {
|
|
373
|
+
if (link && !readSources(dir).some((s) => s.url === link)) return bad("no such source", 404);
|
|
374
|
+
results = link ? [await gatherSource(dir, link)] : await gatherAll(dir);
|
|
375
|
+
} else return bad("unknown op");
|
|
376
|
+
changed();
|
|
377
|
+
return json({ ok: true, sources: readSources(dir).map(({ seen, ...s }) => s), results });
|
|
378
|
+
} catch (e) { return bad((e as Error).message, 500); }
|
|
379
|
+
}
|
|
380
|
+
|
|
238
381
|
if (path === "/run") {
|
|
239
382
|
const text = String(body.text ?? "").trim();
|
|
240
383
|
const kind = body.kind === "full" || body.kind === "lite" ? body.kind : "";
|
|
@@ -299,6 +442,40 @@ export async function web(repoDir: string, opts: Opts = {}) {
|
|
|
299
442
|
return failed ? bad(failed, 404) : json({ ok: true });
|
|
300
443
|
}
|
|
301
444
|
|
|
445
|
+
// Only a finished run, or one waiting at the final approval, and never the
|
|
446
|
+
// global state dir: $HOME may be a repository, and it is not the run's project.
|
|
447
|
+
if (path === "/commit") {
|
|
448
|
+
const id = String(body.id ?? "");
|
|
449
|
+
if (!/^[\w.-]+$/.test(id)) return bad("bad run id");
|
|
450
|
+
if (dir === join(home, ".kaizen")) return bad("no project to commit", 409);
|
|
451
|
+
let run: any;
|
|
452
|
+
try { run = JSON.parse(readFileSync(join(dir, "runs", id, "state.json"), "utf8")); } catch { return bad("no such run", 404); }
|
|
453
|
+
if (run.stage !== "done" && run.awaiting !== "approvals.review") return bad("this run is not finished", 409);
|
|
454
|
+
const r = await commitPush(dir, id, String(body.message ?? ""), Array.isArray(body.files) ? body.files.map(String) : []);
|
|
455
|
+
changed();
|
|
456
|
+
return json(r, r.ok ? 200 : 409);
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
// Fix picked findings, on the same runs /commit takes and for the same reason
|
|
460
|
+
// never in the global state dir: the agent starts in a project, and the run is
|
|
461
|
+
// not there. Only numbers the review itself holds reach the prompt.
|
|
462
|
+
if (path === "/fix") {
|
|
463
|
+
const id = String(body.id ?? "");
|
|
464
|
+
if (!/^[\w.-]+$/.test(id)) return bad("bad run id");
|
|
465
|
+
if (dir === join(home, ".kaizen")) return bad("no project to fix in", 409);
|
|
466
|
+
let run: any;
|
|
467
|
+
try { run = JSON.parse(readFileSync(join(dir, "runs", id, "state.json"), "utf8")); } catch { return bad("no such run", 404); }
|
|
468
|
+
if (run.stage !== "done" && run.awaiting !== "approvals.review" && run.awaiting !== "findings") return bad("this run is still being worked on", 409);
|
|
469
|
+
const nums = pickFindings(dir, id, body.nums);
|
|
470
|
+
if (!nums) return bad("pick open findings of this review");
|
|
471
|
+
const text = fixPrompt(id, nums);
|
|
472
|
+
const r = launchRun({ severity: null, where: null, text, raw: text }, dir);
|
|
473
|
+
changed();
|
|
474
|
+
return json(r.ok
|
|
475
|
+
? { ok: true, agent: r.agent }
|
|
476
|
+
: { ok: false, why: r.why, manual: r.manual, agent: r.agent }, r.ok ? 200 : 500);
|
|
477
|
+
}
|
|
478
|
+
|
|
302
479
|
if (path === "/abort") {
|
|
303
480
|
const id = String(body.id ?? "");
|
|
304
481
|
const why = String(body.why ?? "").trim() || "abandoned from the web board";
|
|
@@ -320,7 +497,7 @@ export async function web(repoDir: string, opts: Opts = {}) {
|
|
|
320
497
|
if (opts.open !== false) await openApp(url);
|
|
321
498
|
|
|
322
499
|
await new Promise<void>((resolve) => {
|
|
323
|
-
const stop = () => { clearInterval(poll); clearInterval(ping); for (const w of watchers) { try { w.close(); } catch { /* gone */ } } server.stop(true); resolve(); };
|
|
500
|
+
const stop = () => { clearInterval(poll); clearInterval(ping); clearInterval(gather); for (const w of watchers) { try { w.close(); } catch { /* gone */ } } server.stop(true); resolve(); };
|
|
324
501
|
process.on("SIGINT", stop);
|
|
325
502
|
process.on("SIGTERM", stop);
|
|
326
503
|
});
|
|
@@ -378,7 +555,7 @@ function winChrome(exe: string) {
|
|
|
378
555
|
export async function shortcut() {
|
|
379
556
|
const bun = process.execPath;
|
|
380
557
|
const script = Bun.argv[1]!;
|
|
381
|
-
const icon =
|
|
558
|
+
const icon = LOGO;
|
|
382
559
|
const hasIcon = existsSync(icon);
|
|
383
560
|
const { mkdirSync, writeFileSync, chmodSync } = await import("node:fs");
|
|
384
561
|
|
package/commands/kaizen-abort.md
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: Mark the current kaizen run abandoned
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
Invoke the `kaizen` skill with argument `abort`.
|
|
1
|
+
---
|
|
2
|
+
description: Mark the current kaizen run abandoned
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
Invoke the `kaizen` skill with argument `abort`.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: Approve whatever the current kaizen run is waiting on
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
Invoke the `kaizen` skill with argument `approve`.
|
|
1
|
+
---
|
|
2
|
+
description: Approve whatever the current kaizen run is waiting on
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
Invoke the `kaizen` skill with argument `approve`.
|
package/commands/kaizen-auto.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: Start a kaizen run in auto mode — every stage back to back, no approval stops
|
|
3
|
-
argument-hint: "<request>"
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
Invoke the `kaizen` skill with argument `auto $ARGUMENTS`.
|
|
1
|
+
---
|
|
2
|
+
description: Start a kaizen run in auto mode — every stage back to back, no approval stops
|
|
3
|
+
argument-hint: "<request>"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Invoke the `kaizen` skill with argument `auto $ARGUMENTS`.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: Print open kaizen backlog items across all runs, grouped by source run
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
Invoke the `kaizen` skill with argument `backlog`.
|
|
1
|
+
---
|
|
2
|
+
description: Print open kaizen backlog items across all runs, grouped by source run
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
Invoke the `kaizen` skill with argument `backlog`.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: Show the kaizen settings for this project and change them interactively
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
Invoke the `kaizen` skill with argument `config`.
|
|
1
|
+
---
|
|
2
|
+
description: Show the kaizen settings for this project and change them interactively
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
Invoke the `kaizen` skill with argument `config`.
|
package/commands/kaizen-full.md
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: Run kaizen with every stage as its own cold agent — the independent review
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
Invoke the `kaizen` skill with argument `full $ARGUMENTS`.
|
|
1
|
+
---
|
|
2
|
+
description: Run kaizen with every stage as its own cold agent — the independent review
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
Invoke the `kaizen` skill with argument `full $ARGUMENTS`.
|
package/commands/kaizen-init.md
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: Set up this project folder for kaizen (spec, config, and a gitignore entry when it is a git repo)
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
Invoke the `kaizen` skill with argument `init`.
|
|
1
|
+
---
|
|
2
|
+
description: Set up this project folder for kaizen (spec, config, and a gitignore entry when it is a git repo)
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
Invoke the `kaizen` skill with argument `init`.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: Install the kaizen workflow itself, globally or per-project
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
Invoke the `kaizen` skill with argument `install`.
|
|
1
|
+
---
|
|
2
|
+
description: Install the kaizen workflow itself, globally or per-project
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
Invoke the `kaizen` skill with argument `install`.
|
package/commands/kaizen-lite.md
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: Run kaizen with every stage in this session — cheaper, and the reviewer has seen the work
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
Invoke the `kaizen` skill with argument `lite $ARGUMENTS`.
|
|
1
|
+
---
|
|
2
|
+
description: Run kaizen with every stage in this session — cheaper, and the reviewer has seen the work
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
Invoke the `kaizen` skill with argument `lite $ARGUMENTS`.
|
package/commands/kaizen-plan.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: Start a kaizen run and stop after the plan (plan-only)
|
|
3
|
-
argument-hint: "<request>"
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
Invoke the `kaizen` skill with argument `plan $ARGUMENTS`.
|
|
1
|
+
---
|
|
2
|
+
description: Start a kaizen run and stop after the plan (plan-only)
|
|
3
|
+
argument-hint: "<request>"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Invoke the `kaizen` skill with argument `plan $ARGUMENTS`.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: Reject the kaizen approval the current run is waiting on — reason decides revise (back to planner) vs kill (abandon)
|
|
3
|
-
argument-hint: "<reason>"
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
Invoke the `kaizen` skill with argument `reject $ARGUMENTS`.
|
|
1
|
+
---
|
|
2
|
+
description: Reject the kaizen approval the current run is waiting on — reason decides revise (back to planner) vs kill (abandon)
|
|
3
|
+
argument-hint: "<reason>"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Invoke the `kaizen` skill with argument `reject $ARGUMENTS`.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: Review-only kaizen run — audit existing code/work, no plan, no implementation
|
|
3
|
-
argument-hint: "[target]"
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
Invoke the `kaizen` skill with argument `review $ARGUMENTS`.
|
|
1
|
+
---
|
|
2
|
+
description: Review-only kaizen run — audit existing code/work, no plan, no implementation
|
|
3
|
+
argument-hint: "[target]"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Invoke the `kaizen` skill with argument `review $ARGUMENTS`.
|
package/commands/kaizen-run.md
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: Resume the current kaizen run and execute the approved plan
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
Invoke the `kaizen` skill with argument `run`.
|
|
1
|
+
---
|
|
2
|
+
description: Resume the current kaizen run and execute the approved plan
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
Invoke the `kaizen` skill with argument `run`.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: List every kaizen run grouped waiting-on-you / in flight / done / abandoned, plus open backlog count
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
Invoke the `kaizen` skill with argument `status`.
|
|
1
|
+
---
|
|
2
|
+
description: List every kaizen run grouped waiting-on-you / in flight / done / abandoned, plus open backlog count
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
Invoke the `kaizen` skill with argument `status`.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "kaizen-agent",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.8.1",
|
|
4
4
|
"description": "Staged workflow for AI agents — code, writing, research, operations: plan, human approval, build, independent review, bounded fix loop.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -21,6 +21,8 @@
|
|
|
21
21
|
"scripts": {
|
|
22
22
|
"install-links": "bun run cli/install.ts",
|
|
23
23
|
"check": "bun run cli/install.ts --check",
|
|
24
|
+
"test": "bun test",
|
|
25
|
+
"prepublishOnly": "bun test",
|
|
24
26
|
"postpublish": "sh cli/release.sh",
|
|
25
27
|
"publish:gh": "sh cli/publish-gh.sh",
|
|
26
28
|
"release": "bun publish && bun run publish:gh"
|