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 +411 -66
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
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
|
|
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) =>
|
|
73
|
-
//
|
|
74
|
-
|
|
75
|
-
const
|
|
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
|
-
${
|
|
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
|
-
//
|
|
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) => ` ${
|
|
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
|
-
|
|
103
|
-
let out = `
|
|
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
|
-
|
|
128
|
+
${chalk.dim("Get one at:")} ${warmStone(url)}`;
|
|
108
129
|
return out;
|
|
109
130
|
},
|
|
110
|
-
// Clarification question
|
|
111
|
-
question: (q, suggestion) =>
|
|
112
|
-
${
|
|
113
|
-
|
|
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
|
-
${
|
|
118
|
-
|
|
119
|
-
${
|
|
120
|
-
|
|
121
|
-
|
|
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
|
|
130
|
-
var
|
|
131
|
-
var
|
|
132
|
-
var
|
|
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") +
|
|
135
|
-
maroon2("\u2588\u2588\u2551 \u2588\u2588\u2554\u255D") +
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
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
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
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(
|
|
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")} ${
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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.
|
|
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);
|