kaizen-agent 0.5.1 → 0.6.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/README.md CHANGED
@@ -239,9 +239,14 @@ Agent Skills standard, so the same workflow runs under any of them:
239
239
  | Antigravity | Skills | Parallel agents where available, else sequentially |
240
240
  | OpenCode, Cursor, Gemini CLI | Skills | Sequentially, one session |
241
241
 
242
- Only directories that already exist are touched — installing does not create
243
- `~/.opencode` for someone who does not use OpenCode. Install again after adding an
244
- agent and it picks the new one up.
242
+ An agent counts as present if it has a config directory or a command on your PATH.
243
+ Only what is already there is touched — installing does not create `~/.opencode` for
244
+ someone who does not use OpenCode. Install again after adding an agent and it picks
245
+ the new one up.
246
+
247
+ **No agent yet?** kaizen does nothing on its own — it is a workflow an agent runs.
248
+ If none is found, the installer says so and offers the list above, opening the
249
+ install page for whichever you pick. Install it, run `kaizen` again, and carry on.
245
250
 
246
251
  The stage agents and slash commands are Claude Code's own formats and are not copied
247
252
  elsewhere; under the others you invoke the skill by name. `.kaizen/` is plain files
package/cli/install.ts CHANGED
@@ -27,18 +27,75 @@ const c = {
27
27
  // Skills standard, so every one of these can run the workflow; agents/ and
28
28
  // commands/ are Claude Code's own formats and go nowhere else.
29
29
  const AGENTS = [
30
- { name: "Claude Code", dir: ".claude", full: true },
31
- { name: "Codex", dir: ".codex", full: false },
32
- { name: "Antigravity", dir: ".agents", full: false },
33
- { name: "OpenCode", dir: ".opencode", full: false },
34
- { name: "Cursor", dir: ".cursor", full: false },
35
- { name: "Gemini CLI", dir: ".gemini", full: false },
30
+ { name: "Claude Code", dir: ".claude", cmd: "claude", full: true,
31
+ docs: "https://docs.claude.com/en/docs/claude-code" },
32
+ { name: "Codex", dir: ".codex", cmd: "codex", full: false,
33
+ docs: "https://github.com/openai/codex" },
34
+ { name: "Antigravity", dir: ".agents", cmd: "agy", full: false,
35
+ docs: "https://antigravity.google" },
36
+ { name: "OpenCode", dir: ".opencode", cmd: "opencode", full: false,
37
+ docs: "https://opencode.ai" },
38
+ { name: "Cursor", dir: ".cursor", cmd: "cursor", full: false,
39
+ docs: "https://cursor.com" },
40
+ { name: "Gemini CLI", dir: ".gemini", cmd: "gemini", full: false,
41
+ docs: "https://github.com/google-gemini/gemini-cli" },
36
42
  ];
37
43
 
38
- // Install into an agent that is actually present. Creating ~/.opencode for someone
39
- // who does not use OpenCode leaves litter that looks like configuration. Claude Code
40
- // is always a target: it is the one this is installed from.
41
- const found = (r: string) => AGENTS.filter((a) => a.dir === ".claude" || existsSync(join(r, a.dir)));
44
+ // An agent counts as present if it has a directory or a command. The directory
45
+ // alone misses someone who installed the agent and has not run it yet; the command
46
+ // alone misses one that is not on this shell's PATH.
47
+ const onPath = new Set(
48
+ AGENTS.filter((a) => Bun.which(a.cmd)).map((a) => a.dir),
49
+ );
50
+ const found = (r: string) =>
51
+ AGENTS.filter((a) => existsSync(join(r, a.dir)) || onPath.has(a.dir));
52
+
53
+ // Nothing to install into. kaizen is a workflow an agent runs; on its own it does
54
+ // nothing, so send them to the agent first rather than laying out files no reader
55
+ // will ever load.
56
+ if (!found(home).length && !args.has("--force")) {
57
+ await noAgent();
58
+ process.exit(0);
59
+ }
60
+
61
+ async function noAgent() {
62
+ console.log(` ${c.bold("No AI coding agent found on this machine.")}\n`);
63
+ console.log(` ${c.dim("kaizen is a workflow that an agent runs — it plans, you approve, it builds,")}`);
64
+ console.log(` ${c.dim("and a second agent reviews. So an agent has to be installed first.")}\n`);
65
+
66
+ if (!interactive) {
67
+ for (const a of AGENTS) console.log(` ${a.name.padEnd(14)} ${a.docs}`);
68
+ console.log(`\n ${c.dim("Install one, then run this again.")}`);
69
+ return;
70
+ }
71
+
72
+ const pick = await select("Which one would you like to install?", [
73
+ ...AGENTS.map((a) => ({ label: a.name, hint: a.docs, value: a as (typeof AGENTS)[number] | null })),
74
+ { label: "None of these — just show me the list", hint: "", value: null },
75
+ ]);
76
+
77
+ if (!pick) {
78
+ for (const a of AGENTS) console.log(` ${a.name.padEnd(14)} ${a.docs}`);
79
+ console.log(`\n ${c.dim("Install one, then run this again.")}`);
80
+ return;
81
+ }
82
+
83
+ console.log(` ${c.bold(pick.name)}`);
84
+ console.log(` ${c.cyan(pick.docs)}\n`);
85
+ const opened = await openUrl(pick.docs);
86
+ console.log(opened
87
+ ? ` ${c.dim("Opened in your browser. Install it, then run")} ${c.cyan("kaizen")} ${c.dim("again.")}`
88
+ : ` ${c.dim("Open that page to install it, then run")} ${c.cyan("kaizen")} ${c.dim("again.")}`);
89
+ }
90
+
91
+ // Best effort: a headless box or a locked-down desktop has no opener, and the URL
92
+ // is printed either way.
93
+ async function openUrl(url: string) {
94
+ const opener = process.platform === "darwin" ? "open"
95
+ : process.platform === "win32" ? "start" : "xdg-open";
96
+ if (!Bun.which(opener)) return false;
97
+ try { await Bun.$`${opener} ${url}`.quiet(); return true; } catch { return false; }
98
+ }
42
99
 
43
100
  if (wantSettings) {
44
101
  const { settings } = await import("./settings.ts");
@@ -52,7 +109,7 @@ if (wantSettings) {
52
109
  if (interactive && !upgrade && Bun.argv.length === 2) {
53
110
  const repoDir = await resolveRepoQuietly();
54
111
  const here = found(home);
55
- const linked = here.every((a) =>
112
+ const linked = here.length > 0 && here.every((a) =>
56
113
  ["kaizen", "kaizen-help"].every((n) => existsSync(join(home, a.dir, "skills", n))));
57
114
  if (linked) {
58
115
  const { dashboard } = await import("./dashboard.ts");
package/cli/release.sh ADDED
@@ -0,0 +1,34 @@
1
+ #!/bin/sh
2
+ # Runs after `npm publish`: tag the published version and open a GitHub release
3
+ # for it, so a version can never exist on npm with nothing to read on GitHub.
4
+ #
5
+ # Never fails the publish. The package is already public by the time this runs;
6
+ # exiting non-zero here would report a failure that did not happen.
7
+ set -u
8
+ v="${npm_package_version:-$(node -p "require('./package.json').version" 2>/dev/null)}"
9
+ [ -n "$v" ] || { echo "release: no version, skipping"; exit 0; }
10
+ tag="v$v"
11
+
12
+ git rev-parse --git-dir >/dev/null 2>&1 || { echo "release: not a git checkout, skipping"; exit 0; }
13
+
14
+ if git rev-parse "$tag" >/dev/null 2>&1; then
15
+ echo "release: $tag already tagged"
16
+ else
17
+ git tag -a "$tag" -m "kaizen-agent $tag" || { echo "release: could not tag"; exit 0; }
18
+ git push origin "$tag" >/dev/null 2>&1 || echo "release: tag made but not pushed"
19
+ fi
20
+
21
+ command -v gh >/dev/null 2>&1 || { echo "release: gh not installed — tag pushed, write the release by hand"; exit 0; }
22
+ gh auth status >/dev/null 2>&1 || { echo "release: gh not logged in — tag pushed, write the release by hand"; exit 0; }
23
+
24
+ if gh release view "$tag" >/dev/null 2>&1; then
25
+ echo "release: $tag already released"
26
+ exit 0
27
+ fi
28
+
29
+ # --generate-notes lists the commits since the last tag. Good enough to never be
30
+ # empty; rewrite it with what actually changed when the release matters.
31
+ gh release create "$tag" --title "$tag" --generate-notes >/dev/null 2>&1 \
32
+ && echo "release: published $tag https://github.com/hfadhlullah/kaizen/releases/tag/$tag" \
33
+ || echo "release: tag pushed, release not created"
34
+ exit 0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kaizen-agent",
3
- "version": "0.5.1",
3
+ "version": "0.6.0",
4
4
  "description": "Staged workflow for AI agents \u2014 code, writing, research, operations: plan, human approval, build, independent review, bounded fix loop.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -17,7 +17,8 @@
17
17
  ],
18
18
  "scripts": {
19
19
  "install-links": "bun run cli/install.ts",
20
- "check": "bun run cli/install.ts --check"
20
+ "check": "bun run cli/install.ts --check",
21
+ "postpublish": "sh cli/release.sh"
21
22
  },
22
23
  "repository": {
23
24
  "type": "git",