kaizen-agent 1.2.2 → 1.3.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.
Files changed (2) hide show
  1. package/cli/install.ts +38 -7
  2. package/package.json +2 -2
package/cli/install.ts CHANGED
@@ -2,9 +2,10 @@
2
2
  import {
3
3
  symlinkSync, mkdirSync, readdirSync, lstatSync, readlinkSync, unlinkSync,
4
4
  existsSync, copyFileSync, readFileSync, appendFileSync, rmSync, writeFileSync,
5
+ statSync, cpSync,
5
6
  } from "node:fs";
6
7
  import { join, dirname, basename } from "node:path";
7
- import { homedir } from "node:os";
8
+ import { homedir, tmpdir } from "node:os";
8
9
  import { applyPreset, detectPreset, PRESETS, type PresetName } from "./settings.ts";
9
10
 
10
11
  const home = homedir();
@@ -319,8 +320,18 @@ async function resolveRepo() {
319
320
  }
320
321
  return dest;
321
322
  }
322
- step(`cloning into ${tilde(dest)}`);
323
- await Bun.$`git clone --quiet ${REPO_URL} ${dest}`;
323
+ if (Bun.which("git")) {
324
+ step(`cloning into ${tilde(dest)}`);
325
+ await Bun.$`git clone --quiet ${REPO_URL} ${dest}`;
326
+ return dest;
327
+ }
328
+ // No git: the bunx download already holds everything a clone would, so copy it
329
+ // in place. Upgrades then come from re-running bunx rather than a pull.
330
+ step(`copying into ${tilde(dest)} ${c.dim("(no git)")}`);
331
+ cpSync(here, dest, {
332
+ recursive: true, dereference: true,
333
+ filter: (src) => basename(src) !== "node_modules",
334
+ });
324
335
  return dest;
325
336
  }
326
337
 
@@ -356,10 +367,30 @@ const links = targets.flatMap((a) => [
356
367
  ] : []),
357
368
  ]);
358
369
 
370
+ const isWindows = process.platform === "win32";
371
+
372
+ // Windows only hands out file symlinks to an admin or a Developer Mode box, so
373
+ // there the link is a directory junction (allowed for everyone) or, for a plain
374
+ // file, a copy that is refreshed whenever the source moves ahead.
375
+ function makeLink(src: string, dest: string) {
376
+ if (!isWindows) { symlinkSync(src, dest); return; }
377
+ if (statSync(src).isDirectory()) { symlinkSync(src, dest, "junction"); return; }
378
+ copyFileSync(src, dest);
379
+ }
380
+
381
+ function sameFile(a: string, b: string) {
382
+ try { return readFileSync(a).equals(readFileSync(b)); } catch { return false; }
383
+ }
384
+
359
385
  function linkState(src: string, dest: string) {
360
386
  try {
361
387
  const st = lstatSync(dest);
362
- if (!st.isSymbolicLink()) return "occupied";
388
+ if (!st.isSymbolicLink()) {
389
+ // A copied link on Windows is a real file; it is ours as long as it still
390
+ // matches the source, and stale once the source changes.
391
+ if (isWindows && st.isFile()) return sameFile(src, dest) ? "linked" : "stale";
392
+ return "occupied";
393
+ }
363
394
  return readlinkSync(dest) === src ? "linked" : "stale";
364
395
  } catch {
365
396
  return "missing";
@@ -385,8 +416,8 @@ for (const [src, sub] of links) {
385
416
  continue;
386
417
  }
387
418
  mkdirSync(dir, { recursive: true });
388
- if (state !== "missing") unlinkSync(dest);
389
- symlinkSync(src, dest);
419
+ if (state !== "missing") rmSync(dest, { recursive: true, force: true });
420
+ makeLink(src, dest);
390
421
  wrote++;
391
422
  if (verbose) console.log(c.dim(` link ${name}`));
392
423
  }
@@ -603,7 +634,7 @@ function clean(out: string) {
603
634
  // without re-resolving, so an upgrade that only pulls the clone still leaves the
604
635
  // next `bunx kaizen-agent` running whatever was cached the first time.
605
636
  async function clearBunxCache() {
606
- const tmp = process.env.TMPDIR ?? "/tmp";
637
+ const tmp = process.env.TMPDIR ?? tmpdir();
607
638
  let removed = 0;
608
639
  try {
609
640
  for (const name of readdirSync(tmp)) {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "kaizen-agent",
3
- "version": "1.2.2",
4
- "description": "Staged workflow for AI agents \u2014 code, writing, research, operations: plan, human approval, build, independent review, bounded fix loop.",
3
+ "version": "1.3.0",
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": {
7
7
  "kaizen-agent": "./cli/install.ts",