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.
- package/cli/install.ts +38 -7
- 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
|
-
|
|
323
|
-
|
|
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())
|
|
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")
|
|
389
|
-
|
|
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 ??
|
|
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.
|
|
4
|
-
"description": "Staged workflow for AI agents
|
|
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",
|