kaizen-agent 1.3.4 → 1.3.6

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 (2) hide show
  1. package/cli/install.ts +57 -23
  2. package/package.json +1 -1
package/cli/install.ts CHANGED
@@ -126,27 +126,49 @@ if (wantSettings) {
126
126
  // opened a terminal for.
127
127
  if (interactive && !upgrade && Bun.argv.length === 2) {
128
128
  const repoDir = await resolveRepoQuietly();
129
- const here = found(home);
130
- const linked = here.length > 0 && here.every((a) =>
131
- ["kaizen", "kaizen-help"].every((n) => existsSync(join(home, a.dir, "skills", n))));
132
- if (linked) {
133
- const { dashboard } = await import("./dashboard.ts");
134
- await dashboard(repoDir, here.map((a) => a.name), async (action) => {
135
- if (action === "settings") {
136
- const { settings } = await import("./settings.ts");
137
- await settings(repoDir, false);
138
- } else if (action === "upgrade") {
139
- return await runUpgrade(repoDir);
140
- } else if (action === "init") {
141
- const out = await Bun.$`bun run ${join(repoDir, "cli/install.ts")} --yes`.text();
142
- return clean(out);
143
- }
144
- });
145
- process.exit(0);
129
+ // `bunx kaizen-agent@1.4.0` on a machine that already has an older copy is a
130
+ // request to install that version, not to open the dashboard the old one links
131
+ // to -- opening it would hand the upgrade back to the very installer being
132
+ // replaced. Only skip to the dashboard when the two are the same version.
133
+ const running = dirname(import.meta.dir);
134
+ const stale = running !== repoDir && versionOf(running) !== versionOf(repoDir);
135
+ if (!stale) {
136
+ const here = found(home);
137
+ const linked = here.length > 0 && here.every((a) =>
138
+ ["kaizen", "kaizen-help"].every((n) => existsSync(join(home, a.dir, "skills", n))));
139
+ if (linked) {
140
+ const { dashboard } = await import("./dashboard.ts");
141
+ await dashboard(repoDir, here.map((a) => a.name), async (action) => {
142
+ if (action === "settings") {
143
+ const { settings } = await import("./settings.ts");
144
+ await settings(repoDir, false);
145
+ } else if (action === "upgrade") {
146
+ return await runUpgrade(repoDir);
147
+ } else if (action === "init") {
148
+ const out = await Bun.$`bun run ${join(repoDir, "cli/install.ts")} --yes`.text();
149
+ return clean(out);
150
+ }
151
+ });
152
+ process.exit(0);
153
+ }
146
154
  }
147
155
  }
148
156
 
149
157
  if (upgrade) await clearBunxCache();
158
+
159
+ // An install made without git is a copy, not a clone, so there is nothing to pull:
160
+ // upgrading itself would copy ~/kaizen over ~/kaizen and report "already up to
161
+ // date" forever. The new version comes from npm, and the installer inside it does
162
+ // the copying and relinking, so hand the job over and stop.
163
+ if (upgrade && !existsSync(join(dirname(import.meta.dir), ".git"))) {
164
+ const latest = await npmLatest();
165
+ const now = versionOf(dirname(import.meta.dir));
166
+ if (latest && latest !== now) {
167
+ step(`fetching kaizen ${latest} from npm`);
168
+ await Bun.$`${process.execPath} x kaizen-agent@${latest} --yes`.catch(() => {});
169
+ process.exit(0);
170
+ }
171
+ }
150
172
  if (!check && !upgrade) await welcome();
151
173
 
152
174
  async function welcome() {
@@ -448,17 +470,27 @@ if (!args.has("--project")) installLauncher();
448
470
  // type afterwards. A launcher pointed at the clone gives one, and keeps working
449
471
  // after the clone updates.
450
472
  function installLauncher() {
451
- const binDir = join(home, ".local", "bin");
452
- const bin = join(binDir, "kaizen");
453
- const script = `#!/bin/sh\n# kaizen launcher -- installed by kaizen-agent\nexec bun run ${join(repo, "cli/install.ts")} "$@"\n`;
473
+ const entry = join(repo, "cli/install.ts");
474
+ // Windows cannot run a shell script and has no ~/.local/bin on PATH. Bun's own
475
+ // bin directory is already there — bun put it there when it installed itself —
476
+ // so a .cmd beside bun is the launcher that works without touching PATH.
477
+ const win = process.platform === "win32";
478
+ const binDir = win
479
+ ? join(process.env.BUN_INSTALL ?? join(home, ".bun"), "bin")
480
+ : join(home, ".local", "bin");
481
+ const bin = join(binDir, win ? "kaizen.cmd" : "kaizen");
482
+ const script = win
483
+ ? `@echo off\r\nrem kaizen launcher -- installed by kaizen-agent\r\nbun run "${entry}" %*\r\n`
484
+ : `#!/bin/sh\n# kaizen launcher -- installed by kaizen-agent\nexec bun run ${entry} "$@"\n`;
454
485
  try {
455
486
  if (existsSync(bin) && readFileSync(bin, "utf8") === script) return;
456
487
  mkdirSync(binDir, { recursive: true });
457
488
  writeFileSync(bin, script, { mode: 0o755 });
458
- const onPath = (process.env.PATH ?? "").split(":").includes(binDir);
489
+ const onPath = (process.env.PATH ?? "").split(win ? ";" : ":")
490
+ .some((p) => p.replace(/[\\/]+$/, "").toLowerCase() === binDir.replace(/[\\/]+$/, "").toLowerCase());
459
491
  step(onPath
460
492
  ? `${c.cyan("kaizen upgrade")} is now on your PATH`
461
- : `wrote ${tilde(bin)} ${c.dim("— add ~/.local/bin to PATH to use it")}`);
493
+ : `wrote ${tilde(bin)} ${c.dim(`— add ${tilde(binDir)} to PATH to use it`)}`);
462
494
  } catch {
463
495
  /* a read-only home is not worth failing the install over */
464
496
  }
@@ -608,7 +640,9 @@ async function runUpgrade(repoDir: string) {
608
640
  .map((l) => c.dim(l.trim())),
609
641
  ];
610
642
  if (latest && latest !== after) {
611
- lines.push("", c.dim(`npm publishes ${latest}; this install follows the git clone.`));
643
+ lines.push("", c.dim(existsSync(join(repoDir, ".git"))
644
+ ? `npm publishes ${latest}; this install follows the git clone.`
645
+ : `npm publishes ${latest} — run: bunx kaizen-agent@${latest}`));
612
646
  }
613
647
  lines.push("", c.dim("Restart your agent to pick up new slash commands."));
614
648
  return lines;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kaizen-agent",
3
- "version": "1.3.4",
3
+ "version": "1.3.6",
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": {