kaizen-agent 1.3.2 → 1.3.4

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.
Files changed (3) hide show
  1. package/README.md +42 -11
  2. package/cli/dashboard.ts +41 -14
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -15,8 +15,9 @@
15
15
  ---
16
16
 
17
17
  ```bash
18
- # 1. Install Bun (prerequisite)
18
+ # 1. Install Bun (prerequisite) — macOS, Linux, WSL
19
19
  curl -fsSL https://bun.sh/install | bash
20
+ # Windows PowerShell: powershell -c "irm bun.sh/install.ps1 | iex"
20
21
 
21
22
  # 2. Install Kaizen
22
23
  bunx kaizen-agent
@@ -284,28 +285,58 @@ leave. Hold **Shift** and drag to select text anyway.
284
285
 
285
286
  ## Install
286
287
 
287
- ### Prerequisites: Bun
288
+ Kaizen's installer and interactive dashboard require [Bun](https://bun.sh) — it is
289
+ the only prerequisite. Pick your platform:
288
290
 
289
- Kaizen's installer and interactive dashboard require [Bun](https://bun.sh). If you don't have Bun installed yet:
291
+ <details open>
292
+ <summary><b>Windows</b></summary>
293
+
294
+ In PowerShell:
295
+
296
+ ```powershell
297
+ # 1. Install Bun
298
+ powershell -c "irm bun.sh/install.ps1 | iex"
299
+
300
+ # 2. Reopen PowerShell so bun is on your PATH, then:
301
+ bunx kaizen-agent
302
+ ```
303
+
304
+ Git is not required. Where it is missing, kaizen copies itself into `%USERPROFILE%\kaizen`
305
+ instead of cloning, and `bunx kaizen-agent` is also how you update. Links are made as
306
+ directory junctions and file copies, so no administrator rights or Developer Mode are
307
+ needed. WSL users can follow the Linux instructions instead.
308
+
309
+ </details>
310
+
311
+ <details>
312
+ <summary><b>macOS</b></summary>
290
313
 
291
314
  ```bash
292
- # macOS, Linux, WSL
315
+ # 1. Install Bun
293
316
  curl -fsSL https://bun.sh/install | bash
317
+ # or: brew install oven-sh/bun/bun
294
318
 
295
- # or via Homebrew
296
- brew install oven-sh/bun/bun
297
-
298
- # or via npm
299
- npm install -g bun
319
+ # 2. Install Kaizen
320
+ bunx kaizen-agent
300
321
  ```
301
322
 
302
- ### Install Kaizen
323
+ </details>
324
+
325
+ <details>
326
+ <summary><b>Linux</b></summary>
303
327
 
304
328
  ```bash
329
+ # 1. Install Bun
330
+ curl -fsSL https://bun.sh/install | bash
331
+ # or: npm install -g bun
332
+
333
+ # 2. Install Kaizen
305
334
  bunx kaizen-agent
306
335
  ```
307
336
 
308
- It walks you through where to install, prompts for your workflow preset (`medium`, `low`, or `ultra`), then tells you what to type next. Restart your editor afterwards.
337
+ </details>
338
+
339
+ The installer walks you through where to install, prompts for your workflow preset (`medium`, `low`, or `ultra`), then tells you what to type next. Restart your editor afterwards.
309
340
 
310
341
  Run from inside a project it asks whether to install globally or for that project
311
342
  alone; anywhere else — your home directory, a plain folder, a script — it installs
package/cli/dashboard.ts CHANGED
@@ -79,6 +79,20 @@ function findTerminal(cwd: string, fullCmd: string[]): { cmd: string[]; detached
79
79
  const hasDisplay = Boolean(process.env.WAYLAND_DISPLAY || process.env.DISPLAY);
80
80
  const inTmux = Boolean(process.env.TMUX);
81
81
 
82
+ // Windows has no xdg anything, and none of the terminals below exist there.
83
+ // PowerShell is what a Windows user has open anyway: one -Command string,
84
+ // where a single quote is doubled rather than escaped. Windows Terminal hosts
85
+ // it when installed; otherwise `start` gives it a window of its own.
86
+ if (process.platform === "win32") {
87
+ const q = (a: string) => `'${a.replace(/'/g, "''")}'`;
88
+ const shell = Bun.which("pwsh.exe") ? "pwsh.exe" : "powershell.exe";
89
+ const ps = `Set-Location -LiteralPath ${q(cwd)}; & ${fullCmd.map(q).join(" ")}`;
90
+ if (Bun.which("wt.exe")) {
91
+ return { cmd: ["wt.exe", "-d", cwd, shell, "-NoExit", "-Command", ps], detached: true };
92
+ }
93
+ return { cmd: ["cmd.exe", "/c", "start", "kaizen", shell, "-NoExit", "-Command", ps], detached: true };
94
+ }
95
+
82
96
  if (process.env.TERMINAL && Bun.which(process.env.TERMINAL)) {
83
97
  const term = process.env.TERMINAL;
84
98
  if (term.includes("kitty")) return { cmd: [term, "--directory", cwd, ...fullCmd], detached: true };
@@ -209,13 +223,15 @@ export async function dashboard(
209
223
  ...(state ? [
210
224
  { key: "board", label: "Board", hint: "ideas and runs, by stage" },
211
225
  { key: "runs", label: "Runs", hint: "every run, and what each is waiting on" },
212
- { key: "backlog", label: "Backlog", hint: "what runs noticed and did not do" },
226
+ { key: "backlog", label: "Backlog", hint: "things to do later" },
213
227
  ] : []),
214
- { key: "settings", label: "Settings", hint: "modes, approvals, who builds" },
215
- ...(state && !existsSync(join(state, "spec.md"))
216
- ? [{ key: "init", label: "Set up this project", hint: "write .kaizen/ here" }] : []),
217
- ...(!state ? [{ key: "init", label: "Set up this project", hint: "write .kaizen/ here" }] : []),
218
- { key: "upgrade", label: "Upgrade", hint: "pull, relink, clear the installer cache" },
228
+ { key: "settings", label: "Settings", hint: "change how kaizen works" },
229
+ // ~/.kaizen is the global state, not a project: there is nothing to set up
230
+ // there, and it never holds the spec files a project copy does.
231
+ ...(state && state !== join(home, ".kaizen") && !existsSync(join(state, "spec.md"))
232
+ ? [{ key: "init", label: "Set up this project", hint: "add kaizen to this folder" }] : []),
233
+ ...(!state ? [{ key: "init", label: "Set up this project", hint: "add kaizen to this folder" }] : []),
234
+ { key: "upgrade", label: "Upgrade", hint: "get the latest version" },
219
235
  { key: "quit", label: "Quit", hint: "" },
220
236
  ];
221
237
 
@@ -428,14 +444,18 @@ export async function dashboard(
428
444
  for (;;) {
429
445
  const here = from ?? state!;
430
446
  const runs = readRuns(here);
431
- const width = Math.max(...runs.map((r) => r.id.length));
447
+ const now = Date.now();
448
+ // The dot the board already uses, a four-letter word for anyone not reading
449
+ // colour, and the date dropped from the id: every run made the same day
450
+ // repeated it, which is ten columns saying nothing.
451
+ const width = Math.max(0, ...runs.map((r) => short(r.id).length));
432
452
  const rows = runs.map((r) => {
433
- const mark = r.stage === "done" ? c.dim("done ")
434
- : r.stage === "abandoned" ? c.dim("dropped")
435
- : r.awaiting ? c.amber("waiting") : c.cyan("running");
453
+ const { dot, status } = dotFor(r, now);
454
+ const word = { waiting: "wait", running: "run", stalled: "idle", done: "done", abandoned: "drop" }[status] ?? status;
455
+ const mark = status === "waiting" ? c.amber(word.padEnd(4)) : c.dim(word.padEnd(4));
436
456
  // The mark already says done or dropped; repeating the stage beside it is noise.
437
457
  const tail = r.stage === "done" || r.stage === "abandoned" ? "" : (r.awaiting ?? r.stage);
438
- return `${mark} ${r.id.padEnd(width)} ${c.dim(tail)}`;
458
+ return `${dot} ${mark} ${short(r.id).padEnd(width)} ${c.dim(tail)}`;
439
459
  });
440
460
  const { index } = await pick(from ? `Runs — ${label(from)}` : "Runs", rows);
441
461
  if (index === null) return;
@@ -635,7 +655,10 @@ export async function dashboard(
635
655
  stdout.write(`\n ${c.bold("Board")} ${c.dim(scope)}\n\n`);
636
656
  stdout.write(" " + cols.map(({ meta }, n) =>
637
657
  pad(n === col ? c.cyan(meta.title) : c.dim(meta.title), inner)).join(" ") + "\n");
638
- stdout.write(" " + cols.map(() => c.dim("─".repeat(inner))).join(" ") + "\n");
658
+ // Only the column you are in gets a solid rule; the rest fade to a dotted one,
659
+ // which says where the cursor is without painting a block over the card.
660
+ stdout.write(" " + cols.map((_, n) =>
661
+ n === col ? c.cyan("─".repeat(inner)) : c.dim("┈".repeat(inner))).join(" ") + "\n");
639
662
  const height = Math.max(4, (stdout.rows ?? 24) - 11);
640
663
  const deep = Math.max(0, ...cols.map((x) => x.lines.length));
641
664
  // The selected card drags the viewport with it; a cursor that can leave the
@@ -1009,10 +1032,14 @@ export async function dashboard(
1009
1032
  await report([
1010
1033
  c.bold("Could not open terminal"),
1011
1034
  "",
1012
- c.dim("No supported terminal emulator found (xdg-terminal-exec, kitty, ghostty, alacritty, tmux)."),
1035
+ c.dim(process.platform === "darwin"
1036
+ ? "Terminal.app could not be driven from here."
1037
+ : "No supported terminal emulator found (xdg-terminal-exec, kitty, ghostty, alacritty, tmux)."),
1013
1038
  "",
1014
1039
  "Run manually:",
1015
- ` ${c.cyan(`cd "${projectDir}" && ${agent.cmd} "${prompt}"`)}`,
1040
+ ` ${c.cyan(process.platform === "win32"
1041
+ ? `Set-Location '${projectDir}'; & ${agent.cmd} '${prompt.replace(/'/g, "''")}'`
1042
+ : `cd "${projectDir}" && ${agent.cmd} "${prompt}"`)}`,
1016
1043
  ]);
1017
1044
  return;
1018
1045
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kaizen-agent",
3
- "version": "1.3.2",
3
+ "version": "1.3.4",
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": {