kairn-cli 1.8.0 → 1.9.1

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/dist/cli.js CHANGED
@@ -65,24 +65,47 @@ async function saveConfig(config) {
65
65
  // src/ui.ts
66
66
  import chalk from "chalk";
67
67
  var maroon = chalk.rgb(139, 0, 0);
68
- var warm = chalk.rgb(212, 165, 116);
68
+ var darkMaroon = chalk.rgb(100, 0, 0);
69
+ var warmStone = chalk.rgb(212, 165, 116);
70
+ var lightStone = chalk.rgb(220, 190, 160);
71
+ var dimStone = chalk.rgb(140, 100, 70);
69
72
  var ui = {
70
- // Brand
73
+ // Brand colors
71
74
  brand: (text) => maroon.bold(text),
72
- accent: (text) => warm(text),
73
- // Headers
74
- header: (text) => {
75
- const line = "\u2500".repeat(50);
75
+ accent: (text) => warmStone(text),
76
+ // Logos and banners
77
+ fullBanner: (subtitle) => {
78
+ const KAIRN_WORDMARK2 = [
79
+ maroon("\u2588\u2588\u2557 \u2588\u2588\u2557") + " " + maroon("\u2588\u2588\u2588\u2588\u2588\u2557 ") + " " + maroon("\u2588\u2588\u2557") + " " + maroon("\u2588\u2588\u2588\u2588\u2588\u2588\u2557 ") + " " + maroon("\u2588\u2588\u2588\u2557 \u2588\u2588\u2557"),
80
+ maroon("\u2588\u2588\u2551 \u2588\u2588\u2554\u255D") + " " + maroon("\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557") + " " + maroon("\u2588\u2588\u2551") + " " + maroon("\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557") + " " + maroon("\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2551"),
81
+ warmStone("\u2588\u2588\u2588\u2588\u2588\u2554\u255D ") + " " + warmStone("\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551") + " " + warmStone("\u2588\u2588\u2551") + " " + warmStone("\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D") + " " + warmStone("\u2588\u2588\u2554\u2588\u2588\u2557 \u2588\u2588\u2551"),
82
+ warmStone("\u2588\u2588\u2554\u2550\u2588\u2588\u2557 ") + " " + warmStone("\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2551") + " " + warmStone("\u2588\u2588\u2551") + " " + warmStone("\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557") + " " + warmStone("\u2588\u2588\u2551\u255A\u2588\u2588\u2557\u2588\u2588\u2551"),
83
+ lightStone("\u2588\u2588\u2551 \u2588\u2588\u2557") + " " + lightStone("\u2588\u2588\u2551 \u2588\u2588\u2551") + " " + lightStone("\u2588\u2588\u2551") + " " + lightStone("\u2588\u2588\u2551 \u2588\u2588\u2551") + " " + lightStone("\u2588\u2588\u2551 \u255A\u2588\u2588\u2588\u2588\u2551"),
84
+ lightStone("\u255A\u2550\u255D \u255A\u2550\u255D") + " " + lightStone("\u255A\u2550\u255D \u255A\u2550\u255D") + " " + lightStone("\u255A\u2550\u255D") + " " + lightStone("\u255A\u2550\u255D \u255A\u2550\u255D") + " " + lightStone("\u255A\u2550\u255D \u255A\u2550\u2550\u2550\u255D")
85
+ ];
86
+ console.log("");
87
+ for (const line of KAIRN_WORDMARK2) {
88
+ console.log(" " + line);
89
+ }
90
+ if (subtitle) {
91
+ console.log(dimStone(` ${subtitle}`));
92
+ }
93
+ console.log("");
94
+ },
95
+ compactBanner: (subtitle) => {
96
+ const line = maroon("\u2501").repeat(52);
97
+ console.log(` ${line}`);
98
+ console.log(` ${maroon(" \u25C6")} ${chalk.bold.rgb(139, 0, 0)("KAIRN")}` + (subtitle ? ` ${dimStone("\u2014 " + subtitle)}` : ""));
99
+ console.log(` ${line}`);
100
+ },
101
+ // Section headers
102
+ section: (title) => {
103
+ const len = chalk.dim(title).length;
104
+ const line = "\u2501".repeat(Math.max(0, 48 - len));
76
105
  return `
77
- ${maroon("\u250C" + line + "\u2510")}
78
- ${maroon("\u2502")} ${maroon.bold(text.padEnd(49))}${maroon("\u2502")}
79
- ${maroon("\u2514" + line + "\u2518")}
80
- `;
106
+ ${warmStone("\u2501\u2501")} ${chalk.bold(title)} ${chalk.dim(warmStone(line))}`;
81
107
  },
82
- // Sections
83
- section: (title) => `
84
- ${warm("\u2501\u2501")} ${chalk.bold(title)} ${warm("\u2501".repeat(Math.max(0, 44 - title.length)))}`,
85
- // Status
108
+ // Status messages
86
109
  success: (text) => chalk.green(` \u2713 ${text}`),
87
110
  warn: (text) => chalk.yellow(` \u26A0 ${text}`),
88
111
  error: (text) => chalk.red(` \u2717 ${text}`),
@@ -92,65 +115,68 @@ var ui = {
92
115
  // File list
93
116
  file: (path15) => chalk.dim(` ${path15}`),
94
117
  // Tool display
95
- tool: (name, reason) => ` ${warm("\u25CF")} ${chalk.bold(name)}
118
+ tool: (name, reason) => ` ${warmStone("\u25CF")} ${chalk.bold(name)}
96
119
  ${chalk.dim(reason)}`,
97
120
  // Divider
98
121
  divider: () => chalk.dim(` ${"\u2500".repeat(50)}`),
99
122
  // Command suggestion
100
123
  cmd: (command) => ` ${chalk.bold.white("$ " + command)}`,
101
- // Env var setup
102
- envVar: (name, desc, url) => {
103
- let out = ` ${chalk.bold(`export ${name}=`)}${chalk.dim('"your-key-here"')}
104
- `;
105
- out += chalk.dim(` ${desc}`);
124
+ // Env var setup with signupUrl
125
+ envVarPrompt: (name, desc, url) => {
126
+ let out = ` ${chalk.bold(name)}${chalk.dim(` (${desc})`)}`;
106
127
  if (url) out += `
107
- ${chalk.dim("Get one at:")} ${warm(url)}`;
128
+ ${chalk.dim("Get one at:")} ${warmStone(url)}`;
108
129
  return out;
109
130
  },
110
- // Clarification question display
111
- question: (q, suggestion) => ` ${warm("?")} ${chalk.bold(q)}
112
- ${chalk.dim(`suggested: ${suggestion}`)}`,
113
- // Branded error box
131
+ // Clarification question
132
+ question: (q, suggestion) => {
133
+ let msg = ` ${warmStone("?")} ${chalk.bold(q)}`;
134
+ if (suggestion) {
135
+ msg += `
136
+ ${chalk.dim(`(suggested: ${suggestion})`)}`;
137
+ }
138
+ return msg;
139
+ },
140
+ // Error box for compile failures
114
141
  errorBox: (title, message) => {
115
142
  const line = "\u2500".repeat(50);
116
- return `
117
- ${chalk.red("\u250C" + line + "\u2510")}
118
- ${chalk.red("\u2502")} ${chalk.red.bold(title.padEnd(49))}${chalk.red("\u2502")}
119
- ${chalk.red("\u2514" + line + "\u2518")}
120
-
121
- ${chalk.red("\u2717")} ${message}
122
- `;
143
+ return chalk.red(`
144
+ \u250C${line}\u2510
145
+ \u2502 ${title.padEnd(49)}\u2502
146
+ \u2502 ${message.padEnd(49)}\u2502
147
+ \u2514${line}\u2518
148
+ `);
123
149
  }
124
150
  };
125
151
 
126
152
  // src/logo.ts
127
153
  import chalk2 from "chalk";
128
154
  var maroon2 = chalk2.rgb(139, 0, 0);
129
- var darkMaroon = chalk2.rgb(100, 0, 0);
130
- var warmStone = chalk2.rgb(180, 120, 80);
131
- var lightStone = chalk2.rgb(212, 165, 116);
132
- var dimStone = chalk2.rgb(140, 100, 70);
155
+ var darkMaroon2 = chalk2.rgb(100, 0, 0);
156
+ var warmStone2 = chalk2.rgb(180, 120, 80);
157
+ var lightStone2 = chalk2.rgb(212, 165, 116);
158
+ var dimStone2 = chalk2.rgb(140, 100, 70);
133
159
  var KAIRN_WORDMARK = [
134
- maroon2("\u2588\u2588\u2557 \u2588\u2588\u2557") + darkMaroon(" ") + maroon2("\u2588\u2588\u2588\u2588\u2588\u2557 ") + darkMaroon(" ") + maroon2("\u2588\u2588\u2557") + darkMaroon(" ") + maroon2("\u2588\u2588\u2588\u2588\u2588\u2588\u2557 ") + darkMaroon(" ") + maroon2("\u2588\u2588\u2588\u2557 \u2588\u2588\u2557"),
135
- maroon2("\u2588\u2588\u2551 \u2588\u2588\u2554\u255D") + darkMaroon(" ") + maroon2("\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557") + darkMaroon(" ") + maroon2("\u2588\u2588\u2551") + darkMaroon(" ") + maroon2("\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557") + darkMaroon(" ") + maroon2("\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2551"),
136
- warmStone("\u2588\u2588\u2588\u2588\u2588\u2554\u255D ") + dimStone(" ") + warmStone("\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551") + dimStone(" ") + warmStone("\u2588\u2588\u2551") + dimStone(" ") + warmStone("\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D") + dimStone(" ") + warmStone("\u2588\u2588\u2554\u2588\u2588\u2557 \u2588\u2588\u2551"),
137
- warmStone("\u2588\u2588\u2554\u2550\u2588\u2588\u2557 ") + dimStone(" ") + warmStone("\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2551") + dimStone(" ") + warmStone("\u2588\u2588\u2551") + dimStone(" ") + warmStone("\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557") + dimStone(" ") + warmStone("\u2588\u2588\u2551\u255A\u2588\u2588\u2557\u2588\u2588\u2551"),
138
- lightStone("\u2588\u2588\u2551 \u2588\u2588\u2557") + dimStone(" ") + lightStone("\u2588\u2588\u2551 \u2588\u2588\u2551") + dimStone(" ") + lightStone("\u2588\u2588\u2551") + dimStone(" ") + lightStone("\u2588\u2588\u2551 \u2588\u2588\u2551") + dimStone(" ") + lightStone("\u2588\u2588\u2551 \u255A\u2588\u2588\u2588\u2588\u2551"),
139
- lightStone("\u255A\u2550\u255D \u255A\u2550\u255D") + dimStone(" ") + lightStone("\u255A\u2550\u255D \u255A\u2550\u255D") + dimStone(" ") + lightStone("\u255A\u2550\u255D") + dimStone(" ") + lightStone("\u255A\u2550\u255D \u255A\u2550\u255D") + dimStone(" ") + lightStone("\u255A\u2550\u255D \u255A\u2550\u2550\u2550\u255D")
160
+ maroon2("\u2588\u2588\u2557 \u2588\u2588\u2557") + darkMaroon2(" ") + maroon2("\u2588\u2588\u2588\u2588\u2588\u2557 ") + darkMaroon2(" ") + maroon2("\u2588\u2588\u2557") + darkMaroon2(" ") + maroon2("\u2588\u2588\u2588\u2588\u2588\u2588\u2557 ") + darkMaroon2(" ") + maroon2("\u2588\u2588\u2588\u2557 \u2588\u2588\u2557"),
161
+ maroon2("\u2588\u2588\u2551 \u2588\u2588\u2554\u255D") + darkMaroon2(" ") + maroon2("\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557") + darkMaroon2(" ") + maroon2("\u2588\u2588\u2551") + darkMaroon2(" ") + maroon2("\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557") + darkMaroon2(" ") + maroon2("\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2551"),
162
+ warmStone2("\u2588\u2588\u2588\u2588\u2588\u2554\u255D ") + dimStone2(" ") + warmStone2("\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551") + dimStone2(" ") + warmStone2("\u2588\u2588\u2551") + dimStone2(" ") + warmStone2("\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D") + dimStone2(" ") + warmStone2("\u2588\u2588\u2554\u2588\u2588\u2557 \u2588\u2588\u2551"),
163
+ warmStone2("\u2588\u2588\u2554\u2550\u2588\u2588\u2557 ") + dimStone2(" ") + warmStone2("\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2551") + dimStone2(" ") + warmStone2("\u2588\u2588\u2551") + dimStone2(" ") + warmStone2("\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557") + dimStone2(" ") + warmStone2("\u2588\u2588\u2551\u255A\u2588\u2588\u2557\u2588\u2588\u2551"),
164
+ lightStone2("\u2588\u2588\u2551 \u2588\u2588\u2557") + dimStone2(" ") + lightStone2("\u2588\u2588\u2551 \u2588\u2588\u2551") + dimStone2(" ") + lightStone2("\u2588\u2588\u2551") + dimStone2(" ") + lightStone2("\u2588\u2588\u2551 \u2588\u2588\u2551") + dimStone2(" ") + lightStone2("\u2588\u2588\u2551 \u255A\u2588\u2588\u2588\u2588\u2551"),
165
+ lightStone2("\u255A\u2550\u255D \u255A\u2550\u255D") + dimStone2(" ") + lightStone2("\u255A\u2550\u255D \u255A\u2550\u255D") + dimStone2(" ") + lightStone2("\u255A\u2550\u255D") + dimStone2(" ") + lightStone2("\u255A\u2550\u255D \u255A\u2550\u255D") + dimStone2(" ") + lightStone2("\u255A\u2550\u255D \u255A\u2550\u2550\u2550\u255D")
140
166
  ];
141
167
  var CAIRN_ART = [
142
- dimStone(" \u28C0\u28C0\u28C0 "),
143
- warmStone(" \u28F4\u28FF\u28FF\u28FF\u28E6 "),
144
- warmStone(" \u2819\u283F\u283F\u280B "),
145
- dimStone(" \u28C0\u28E4\u28E4\u28E4\u28E4\u28C0 "),
146
- lightStone(" \u28F4\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28E6 "),
147
- lightStone(" \u2819\u283B\u283F\u283F\u283F\u281F\u280B "),
148
- dimStone(" \u28C0\u28E4\u28E4\u28F6\u28F6\u28F6\u28F6\u28E4\u28E4\u28C0 "),
149
- warmStone(" \u28F4\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28E6 "),
150
- warmStone(" \u2819\u283B\u283F\u283F\u283F\u283F\u283F\u283F\u281F\u280B "),
151
- dimStone(" \u28C0\u28E4\u28F6\u28F6\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28F6\u28F6\u28E4\u28C0 "),
152
- lightStone(" \u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF "),
153
- dimStone(" \u2809\u2809\u2809\u2809\u2809\u2809\u2809\u2809\u2809\u2809\u2809\u2809\u2809\u2809\u2809 ")
168
+ dimStone2(" \u28C0\u28C0\u28C0 "),
169
+ warmStone2(" \u28F4\u28FF\u28FF\u28FF\u28E6 "),
170
+ warmStone2(" \u2819\u283F\u283F\u280B "),
171
+ dimStone2(" \u28C0\u28E4\u28E4\u28E4\u28E4\u28C0 "),
172
+ lightStone2(" \u28F4\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28E6 "),
173
+ lightStone2(" \u2819\u283B\u283F\u283F\u283F\u281F\u280B "),
174
+ dimStone2(" \u28C0\u28E4\u28E4\u28F6\u28F6\u28F6\u28F6\u28E4\u28E4\u28C0 "),
175
+ warmStone2(" \u28F4\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28E6 "),
176
+ warmStone2(" \u2819\u283B\u283F\u283F\u283F\u283F\u283F\u283F\u281F\u280B "),
177
+ dimStone2(" \u28C0\u28E4\u28F6\u28F6\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28F6\u28F6\u28E4\u28C0 "),
178
+ lightStone2(" \u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF\u28FF "),
179
+ dimStone2(" \u2809\u2809\u2809\u2809\u2809\u2809\u2809\u2809\u2809\u2809\u2809\u2809\u2809\u2809\u2809 ")
154
180
  ];
155
181
  function printFullBanner(subtitle) {
156
182
  console.log("");
@@ -158,7 +184,7 @@ function printFullBanner(subtitle) {
158
184
  console.log(" " + line);
159
185
  }
160
186
  if (subtitle) {
161
- console.log(dimStone(` ${subtitle}`));
187
+ console.log(dimStone2(` ${subtitle}`));
162
188
  }
163
189
  console.log("");
164
190
  }
@@ -166,7 +192,7 @@ function printCompactBanner() {
166
192
  const line = maroon2("\u2501").repeat(50);
167
193
  console.log(`
168
194
  ${line}`);
169
- console.log(` ${maroon2(" \u25C6")} ${chalk2.bold.rgb(139, 0, 0)("KAIRN")} ${dimStone("\u2014 Agent Environment Compiler")}`);
195
+ console.log(` ${maroon2(" \u25C6")} ${chalk2.bold.rgb(139, 0, 0)("KAIRN")} ${dimStone2("\u2014 Agent Environment Compiler")}`);
170
196
  console.log(` ${line}
171
197
  `);
172
198
  }
@@ -338,7 +364,7 @@ var initCommand = new Command("init").description("Set up Kairn with your API ke
338
364
 
339
365
  // src/commands/describe.ts
340
366
  import { Command as Command2 } from "commander";
341
- import { input, confirm } from "@inquirer/prompts";
367
+ import { input, confirm, select as select2 } from "@inquirer/prompts";
342
368
  import chalk5 from "chalk";
343
369
  import ora from "ora";
344
370
 
@@ -614,6 +640,19 @@ When generating for Hermes runtime, the same EnvironmentSpec JSON is produced. T
614
640
 
615
641
  The LLM output format does not change. Adapter-level conversion happens post-compilation.
616
642
 
643
+ ## Autonomy Levels
644
+
645
+ The user may specify an autonomy level (1-4). This affects CLAUDE.md content:
646
+
647
+ - **Level 1 (Guided):** Add a "Workflow" section showing recommended command flow (e.g., spec \u2192 sprint \u2192 plan \u2192 code \u2192 prove \u2192 grill \u2192 commit) and a "When to Use What" reference table.
648
+ - **Level 2 (Assisted):** Level 1 content + mention /project:loop in the workflow section and @pm in the agents section of CLAUDE.md.
649
+ - **Level 3 (Autonomous):** Level 2 content + mention /project:auto and worktree-based PR delivery workflow.
650
+ - **Level 4 (Full Auto):** Level 3 content + add a prominent warning section about autonomous operation.
651
+
652
+ The autonomy-specific commands, agents, and hooks are injected post-compilation. Focus on tailoring the CLAUDE.md content and workflow guidance for the selected level.
653
+
654
+ If no autonomy level is specified, assume Level 1 (Guided).
655
+
617
656
  ## Output Schema
618
657
 
619
658
  Return ONLY valid JSON matching this structure:
@@ -884,7 +923,8 @@ async function compile(intent, onProgress) {
884
923
  id: `env_${crypto.randomUUID()}`,
885
924
  intent,
886
925
  created_at: (/* @__PURE__ */ new Date()).toISOString(),
887
- ...parsed
926
+ ...parsed,
927
+ autonomy_level: parsed.autonomy_level ?? 1
888
928
  };
889
929
  validateSpec(spec, onProgress);
890
930
  await ensureDirs();
@@ -919,6 +959,290 @@ async function generateClarifications(intent, onProgress) {
919
959
  // src/adapter/claude-code.ts
920
960
  import fs5 from "fs/promises";
921
961
  import path5 from "path";
962
+
963
+ // src/autonomy.ts
964
+ var AUTONOMY_LABELS = {
965
+ 1: "Guided",
966
+ 2: "Assisted",
967
+ 3: "Autonomous",
968
+ 4: "Full Auto"
969
+ };
970
+ var WELCOME_HOOK = {
971
+ matcher: "",
972
+ hooks: [{
973
+ type: "command",
974
+ command: "if [ ! -f .claude/.toured ]; then echo '\\n Welcome to your Kairn environment!\\n Type /project:tour for a walkthrough, or /project:help for a quick reference.\\n'; fi"
975
+ }]
976
+ };
977
+ var TOUR_COMMAND = `# Environment Tour
978
+
979
+ Welcome! Let me show you around this Kairn environment.
980
+
981
+ ## Your Commands
982
+ Read .claude/commands/ and list each one with a one-line description.
983
+ Group them by workflow phase:
984
+
985
+ PLAN: /project:spec, /project:sprint, /project:plan
986
+ BUILD: (just start coding \u2014 Claude reads CLAUDE.md automatically)
987
+ VERIFY: /project:prove, /project:grill, /project:test
988
+ SHIP: /project:commit, /project:review
989
+ MANAGE: /project:status, /project:tasks, /project:reset
990
+
991
+ ## Your Agents
992
+ Read .claude/agents/ and explain each one with how to invoke it.
993
+
994
+ ## Your MCP Tools
995
+ !claude mcp list 2>/dev/null || echo "Run /mcp in Claude Code to see active tools"
996
+
997
+ ## Workflow
998
+ For this project, the recommended flow is:
999
+ spec \u2192 sprint \u2192 plan \u2192 code \u2192 prove \u2192 grill \u2192 commit
1000
+
1001
+ ## Tips
1002
+ - Type / to see all commands
1003
+ - Type @ to invoke an agent
1004
+ - Paste raw errors \u2014 don't summarize them
1005
+ - Use subagents for deep investigation
1006
+ - Say "update CLAUDE.md" after any correction
1007
+
1008
+ After showing the tour, create .claude/.toured to suppress the welcome message:
1009
+ !touch .claude/.toured
1010
+
1011
+ Ready to start? Try /project:spec to define your first feature.`;
1012
+ function buildQuickstart(spec) {
1013
+ const commands = Object.keys(spec.harness.commands || {});
1014
+ const agents = Object.keys(spec.harness.agents || {});
1015
+ const commandList = commands.map((c) => `- \`/project:${c}\``).join("\n");
1016
+ const agentList = agents.length > 0 ? agents.map((a) => `- \`@${a}\``).join("\n") : "- (none configured)";
1017
+ return `# Quick Start Guide
1018
+
1019
+ This environment was generated by Kairn. Here's how to use it.
1020
+
1021
+ ## First Time
1022
+ 1. Open terminal in this directory
1023
+ 2. Run \`claude\`
1024
+ 3. Type \`/project:tour\` for a guided walkthrough
1025
+
1026
+ ## Daily Workflow
1027
+ 1. \`/project:status\` \u2014 see where things stand
1028
+ 2. \`/project:spec\` \u2014 define what to build (Claude will interview you)
1029
+ 3. Start coding \u2014 Claude follows CLAUDE.md automatically
1030
+ 4. \`/project:prove\` \u2014 verify your work
1031
+ 5. \`/project:commit\` \u2014 ship it
1032
+
1033
+ ## Commands
1034
+ ${commandList}
1035
+
1036
+ ## Agents
1037
+ ${agentList}
1038
+
1039
+ ## Need Help?
1040
+ Type \`/project:help\` in Claude Code for a quick reference.
1041
+ `;
1042
+ }
1043
+ var LOOP_COMMAND_CODE = `# Development Loop
1044
+
1045
+ Run an assisted development cycle for the next feature.
1046
+
1047
+ ## Phase 1: SPEC
1048
+ Review docs/TODO.md and docs/SPRINT.md.
1049
+ If no sprint is defined, run /project:spec to interview the user.
1050
+ Wait for user approval of the spec.
1051
+
1052
+ ## Phase 2: PLAN
1053
+ Read the approved spec in docs/SPRINT.md.
1054
+ Plan the implementation: files to change, tests to write, approach.
1055
+ Write plan to docs/DECISIONS.md.
1056
+ Wait for user approval of the plan.
1057
+
1058
+ ## Phase 3: IMPLEMENT
1059
+ Follow the plan. Implement the feature.
1060
+ Run tests after each change.
1061
+ Commit each logical unit: "feat: description"
1062
+
1063
+ ## Phase 4: VERIFY
1064
+ Run /project:prove to verify the implementation.
1065
+ If confidence is LOW or MEDIUM, fix issues and re-verify.
1066
+
1067
+ ## Phase 5: REVIEW
1068
+ Run /project:grill for adversarial review.
1069
+ Fix any BLOCKERs.
1070
+
1071
+ ## Phase 6: SHIP
1072
+ Run /project:commit.
1073
+ Report what was built and what's next from docs/TODO.md.
1074
+
1075
+ Then ask: "Continue to next feature?"
1076
+ If yes, return to Phase 1.`;
1077
+ var LOOP_COMMAND_RESEARCH = `# Research Loop
1078
+
1079
+ Run an assisted research cycle.
1080
+
1081
+ ## Phase 1: QUESTION
1082
+ Review docs/TODO.md for the next research question.
1083
+ If none, ask the user what to investigate.
1084
+
1085
+ ## Phase 2: RESEARCH
1086
+ Search, extract, and analyze sources.
1087
+ Log findings to docs/SOURCES.md and docs/LEARNINGS.md.
1088
+
1089
+ ## Phase 3: SYNTHESIZE
1090
+ Review all findings. Write structured summary to docs/SUMMARY.md.
1091
+ Cite all sources.
1092
+
1093
+ ## Phase 4: REVIEW
1094
+ Present the summary. Ask the user for feedback.
1095
+ Revise based on feedback.
1096
+
1097
+ ## Phase 5: NEXT
1098
+ Update docs/TODO.md \u2014 mark question as done, identify follow-ups.
1099
+ Ask: "Continue to next question?"`;
1100
+ var PM_AGENT = `---
1101
+ name: pm
1102
+ description: Project manager agent. Maintains roadmap, specs features, prioritizes work.
1103
+ model: opus
1104
+ ---
1105
+
1106
+ You are a project manager for this codebase.
1107
+
1108
+ Your responsibilities:
1109
+ 1. Maintain docs/TODO.md \u2014 keep it prioritized and current
1110
+ 2. Write specs to docs/SPRINT.md when asked
1111
+ 3. Review completed work and suggest what's next
1112
+ 4. Track decisions in docs/DECISIONS.md
1113
+ 5. Track learnings in docs/LEARNINGS.md
1114
+
1115
+ When invoked:
1116
+ - Read all docs/ files to understand current state
1117
+ - Read recent git log for what changed
1118
+ - Suggest the highest-priority next task
1119
+ - If asked to spec something, interview the user (5-8 questions)
1120
+
1121
+ You do NOT write code. You plan, spec, and prioritize.`;
1122
+ var AUTO_COMMAND = `# Autonomous Development
1123
+
1124
+ PM-driven development loop with PR delivery.
1125
+
1126
+ ## Phase 1: PLAN (@pm)
1127
+ Use @pm to:
1128
+ - Read docs/TODO.md and docs/SPRINT.md
1129
+ - Select the highest-priority unfinished task
1130
+ - Write a spec to docs/SPRINT.md
1131
+ - Present the spec for approval
1132
+
1133
+ Wait for user approval. If approved, proceed.
1134
+
1135
+ ## Phase 2: BRANCH
1136
+ Create an isolated worktree:
1137
+ git worktree add ../project-feat-{name} -b feat/{name}
1138
+ All implementation happens in the worktree.
1139
+
1140
+ ## Phase 3: IMPLEMENT
1141
+ In the worktree directory:
1142
+ - Follow the spec in docs/SPRINT.md
1143
+ - Build, test, commit after each change
1144
+
1145
+ ## Phase 4: VERIFY
1146
+ Run verification:
1147
+ - Static analysis (linting, type checks)
1148
+ - Run functional tests
1149
+ - If NEEDS FIXES: fix and re-verify
1150
+
1151
+ ## Phase 5: PR
1152
+ Create a pull request:
1153
+ gh pr create --title "feat: {name}" --body "{spec + QA report}"
1154
+
1155
+ ## Phase 6: NEXT
1156
+ Report:
1157
+ "PR #{N} ready for review: {link}
1158
+ Next priority from TODO.md: {next task}
1159
+ Continue? (y/n)"
1160
+
1161
+ If yes, return to Phase 1 with next task.`;
1162
+ var AUTOPILOT_COMMAND = `# Autopilot Mode
1163
+
1164
+ Continuous autonomous development. The PM plans, the loop executes,
1165
+ PRs are opened automatically. You review when ready.
1166
+
1167
+ ## Configuration
1168
+ - Max features per session: 5 (prevent runaway)
1169
+ - Stop on: test failure, build error, or blocked dependency
1170
+ - All work in isolated worktrees
1171
+ - Every feature = one PR
1172
+
1173
+ ## The Loop
1174
+ Repeat until max features reached or stopped:
1175
+ 1. @pm selects next priority from docs/TODO.md
1176
+ 2. Create worktree + branch
1177
+ 3. Implement the feature
1178
+ 4. Run verification (build, test, lint)
1179
+ 5. Open PR via gh
1180
+ 6. Report status
1181
+ 7. Move to next feature
1182
+
1183
+ ## Stop Conditions
1184
+ - Max 5 features per autopilot session
1185
+ - Any BLOCKER from verification
1186
+ - Build failure that can't be resolved in 3 attempts
1187
+ - User presses Escape`;
1188
+ var AUTOPILOT_WARNING = `
1189
+ ## Autopilot Mode Active
1190
+ This environment is configured for autonomous operation.
1191
+ The @pm agent plans features and /project:autopilot executes them.
1192
+ All changes are delivered as PRs \u2014 review before merging.
1193
+ Stop conditions: max 5 features, test failure, or Escape.`;
1194
+ function isResearchProject(spec) {
1195
+ const commands = spec.harness.commands ?? {};
1196
+ return "research" in commands || "summarize" in commands;
1197
+ }
1198
+ function applyAutonomyLevel(spec) {
1199
+ const level = spec.autonomy_level ?? 1;
1200
+ const commands = spec.harness.commands ?? {};
1201
+ const agents = spec.harness.agents ?? {};
1202
+ const docs = spec.harness.docs ?? {};
1203
+ const settings = spec.harness.settings ?? {};
1204
+ if (level >= 1) {
1205
+ if (!("tour" in commands)) {
1206
+ commands.tour = TOUR_COMMAND;
1207
+ }
1208
+ docs.QUICKSTART = buildQuickstart(spec);
1209
+ const hooks = settings.hooks ?? {};
1210
+ const sessionStart = hooks.SessionStart ?? [];
1211
+ sessionStart.push(WELCOME_HOOK);
1212
+ hooks.SessionStart = sessionStart;
1213
+ settings.hooks = hooks;
1214
+ }
1215
+ if (level >= 2) {
1216
+ if (!("loop" in commands)) {
1217
+ commands.loop = isResearchProject(spec) ? LOOP_COMMAND_RESEARCH : LOOP_COMMAND_CODE;
1218
+ }
1219
+ if (!("pm" in agents)) {
1220
+ agents.pm = PM_AGENT;
1221
+ }
1222
+ }
1223
+ if (level >= 3) {
1224
+ if (!("auto" in commands)) {
1225
+ commands.auto = AUTO_COMMAND;
1226
+ }
1227
+ }
1228
+ if (level >= 4) {
1229
+ if (!("autopilot" in commands)) {
1230
+ commands.autopilot = AUTOPILOT_COMMAND;
1231
+ }
1232
+ if (spec.harness.claude_md && !spec.harness.claude_md.includes("Autopilot Mode")) {
1233
+ spec.harness.claude_md += "\n" + AUTOPILOT_WARNING;
1234
+ }
1235
+ }
1236
+ spec.harness.commands = commands;
1237
+ spec.harness.agents = agents;
1238
+ spec.harness.docs = docs;
1239
+ spec.harness.settings = settings;
1240
+ }
1241
+ function autonomyLabel(level) {
1242
+ return AUTONOMY_LABELS[level];
1243
+ }
1244
+
1245
+ // src/adapter/claude-code.ts
922
1246
  var STATUS_LINE = {
923
1247
  command: `printf '%s | %s tasks' "$(git branch --show-current 2>/dev/null || echo 'no-git')" "$(grep -c '\\- \\[ \\]' docs/TODO.md 2>/dev/null || echo 0)"`
924
1248
  };
@@ -954,6 +1278,7 @@ async function writeFile(filePath, content) {
954
1278
  await fs5.writeFile(filePath, content, "utf-8");
955
1279
  }
956
1280
  function buildFileMap(spec, options) {
1281
+ applyAutonomyLevel(spec);
957
1282
  const files = /* @__PURE__ */ new Map();
958
1283
  if (spec.harness.claude_md) {
959
1284
  files.set(".claude/CLAUDE.md", spec.harness.claude_md);
@@ -996,6 +1321,7 @@ function buildFileMap(spec, options) {
996
1321
  return files;
997
1322
  }
998
1323
  async function writeEnvironment(spec, targetDir, options) {
1324
+ applyAutonomyLevel(spec);
999
1325
  const claudeDir = path5.join(targetDir, ".claude");
1000
1326
  const written = [];
1001
1327
  if (spec.harness.claude_md) {
@@ -1360,6 +1686,23 @@ Clarifications:
1360
1686
  ${clarificationLines}`;
1361
1687
  }
1362
1688
  }
1689
+ let autonomyLevel = 1;
1690
+ if (!options.quick) {
1691
+ console.log(ui.section("Autonomy"));
1692
+ autonomyLevel = await select2({
1693
+ message: "Autonomy level",
1694
+ choices: [
1695
+ { name: "1. Guided \u2014 orientation + commands, you drive", value: 1 },
1696
+ { name: "2. Assisted \u2014 workflow loop, you approve phases", value: 2 },
1697
+ { name: "3. Autonomous \u2014 PM plans, loop executes, you review PRs", value: 3 },
1698
+ { name: "4. Full Auto \u2014 continuous execution (\u26A0 advanced)", value: 4 }
1699
+ ],
1700
+ default: 1
1701
+ });
1702
+ finalIntent += `
1703
+
1704
+ Autonomy level: ${autonomyLevel} (${autonomyLabel(autonomyLevel)})`;
1705
+ }
1363
1706
  console.log(ui.section("Compilation"));
1364
1707
  const spinner = ora({ text: "Loading tool registry...", indent: 2 }).start();
1365
1708
  let spec;
@@ -1367,6 +1710,7 @@ ${clarificationLines}`;
1367
1710
  spec = await compile(finalIntent, (msg) => {
1368
1711
  spinner.text = msg;
1369
1712
  });
1713
+ spec.autonomy_level = autonomyLevel;
1370
1714
  spinner.succeed("Environment compiled");
1371
1715
  } catch (err) {
1372
1716
  spinner.fail("Compilation failed");
@@ -1381,6 +1725,7 @@ ${clarificationLines}`;
1381
1725
  console.log("");
1382
1726
  console.log(ui.kv("Name:", spec.name));
1383
1727
  console.log(ui.kv("Description:", spec.description));
1728
+ console.log(ui.kv("Autonomy:", `Level ${spec.autonomy_level} (${autonomyLabel(spec.autonomy_level)})`));
1384
1729
  console.log(ui.kv("Tools:", String(summary.toolCount)));
1385
1730
  console.log(ui.kv("Commands:", String(summary.commandCount)));
1386
1731
  console.log(ui.kv("Rules:", String(summary.ruleCount)));
@@ -2080,7 +2425,7 @@ var optimizeCommand = new Command6("optimize").description("Scan an existing pro
2080
2425
  console.log(ui.file(file));
2081
2426
  }
2082
2427
  if (hasEnvVars) {
2083
- await collectAndWriteKeys(summary.envSetup, targetDir);
2428
+ await collectAndWriteKeys(summary.envSetup, targetDir, { quick: options.quick });
2084
2429
  console.log("");
2085
2430
  }
2086
2431
  if (summary.pluginCommands.length > 0) {
@@ -2274,7 +2619,7 @@ var doctorCommand = new Command7("doctor").description(
2274
2619
  // src/commands/registry.ts
2275
2620
  import { Command as Command8 } from "commander";
2276
2621
  import chalk11 from "chalk";
2277
- import { input as input2, select as select2 } from "@inquirer/prompts";
2622
+ import { input as input2, select as select3 } from "@inquirer/prompts";
2278
2623
  var listCommand2 = new Command8("list").description("List tools in the registry").option("--category <cat>", "Filter by category").option("--user-only", "Show only user-defined tools").action(async (options) => {
2279
2624
  printCompactBanner();
2280
2625
  let all;
@@ -2344,7 +2689,7 @@ var addCommand = new Command8("add").description("Add a tool to the user registr
2344
2689
  });
2345
2690
  const name = await input2({ message: "Display name" });
2346
2691
  const description = await input2({ message: "Description" });
2347
- const category = await select2({
2692
+ const category = await select3({
2348
2693
  message: "Category",
2349
2694
  choices: [
2350
2695
  { value: "universal" },
@@ -2358,7 +2703,7 @@ var addCommand = new Command8("add").description("Add a tool to the user registr
2358
2703
  { value: "sandbox" }
2359
2704
  ]
2360
2705
  });
2361
- const tier = await select2({
2706
+ const tier = await select3({
2362
2707
  message: "Tier",
2363
2708
  choices: [
2364
2709
  { name: "1 \u2014 Universal", value: 1 },
@@ -2366,7 +2711,7 @@ var addCommand = new Command8("add").description("Add a tool to the user registr
2366
2711
  { name: "3 \u2014 Specialized", value: 3 }
2367
2712
  ]
2368
2713
  });
2369
- const type = await select2({
2714
+ const type = await select3({
2370
2715
  message: "Type",
2371
2716
  choices: [
2372
2717
  { value: "mcp_server" },
@@ -2374,7 +2719,7 @@ var addCommand = new Command8("add").description("Add a tool to the user registr
2374
2719
  { value: "hook" }
2375
2720
  ]
2376
2721
  });
2377
- const auth = await select2({
2722
+ const auth = await select3({
2378
2723
  message: "Auth",
2379
2724
  choices: [
2380
2725
  { value: "none" },
@@ -2390,7 +2735,7 @@ var addCommand = new Command8("add").description("Add a tool to the user registr
2390
2735
  const varName = await input2({ message: "Env var name" });
2391
2736
  const varDesc = await input2({ message: "Env var description" });
2392
2737
  env_vars.push({ name: varName, description: varDesc });
2393
- const another = await select2({
2738
+ const another = await select3({
2394
2739
  message: "Add another env var?",
2395
2740
  choices: [
2396
2741
  { name: "No", value: false },
@@ -2654,7 +2999,7 @@ var keysCommand = new Command10("keys").description("Add or update API keys for
2654
2999
  var program = new Command11();
2655
3000
  program.name("kairn").description(
2656
3001
  "Compile natural language intent into optimized Claude Code environments"
2657
- ).version("1.8.0").option("--no-color", "Disable colored output");
3002
+ ).version("1.9.0").option("--no-color", "Disable colored output");
2658
3003
  program.addCommand(initCommand);
2659
3004
  program.addCommand(describeCommand);
2660
3005
  program.addCommand(optimizeCommand);