mother-brain 0.0.5 → 0.0.7
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.d.ts +1 -0
- package/dist/cli.js +594 -0
- package/package.json +48 -22
- package/{.github/skills → skills}/child-brain/SKILL.md +430 -430
- package/{.github/skills → skills}/mother-brain/SKILL.md +3081 -3069
- package/{.github/skills → skills}/mother-brain/examples/input-01.md +51 -51
- package/{.github/skills → skills}/mother-brain/examples/menu-examples.md +119 -119
- package/{.github/skills → skills}/mother-brain/examples/output-01.md +185 -185
- package/{.github/skills → skills}/mother-brain/references/resources.md +147 -147
- package/{.github/skills → skills}/mother-brain/references/tech-stack-guide.md +161 -161
- package/{.github/skills → skills}/mother-brain/scripts/vision-template.md +48 -48
- package/{.github/skills → skills}/skill-creator/SKILL.md +615 -615
- package/{.github/skills → skills}/skill-creator/references/resources.md +97 -97
- package/{.github/skills → skills}/skill-creator/scripts/validate-skill-name.ps1 +60 -60
- package/CODE_OF_CONDUCT.md +0 -119
- package/CONTRIBUTING.md +0 -352
- package/README.md +0 -162
- package/bin/mother-brain.js +0 -6
- package/docs/learning-log.md +0 -514
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,594 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
3
|
+
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
4
|
+
}) : x)(function(x) {
|
|
5
|
+
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
6
|
+
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
// src/cli.ts
|
|
10
|
+
import { Command } from "commander";
|
|
11
|
+
import chalk5 from "chalk";
|
|
12
|
+
|
|
13
|
+
// src/commands/init.ts
|
|
14
|
+
import path from "path";
|
|
15
|
+
import fs from "fs-extra";
|
|
16
|
+
import chalk from "chalk";
|
|
17
|
+
import { fileURLToPath } from "url";
|
|
18
|
+
var __filename = fileURLToPath(import.meta.url);
|
|
19
|
+
var __dirname = path.dirname(__filename);
|
|
20
|
+
async function init(options = {}) {
|
|
21
|
+
const cwd = process.cwd();
|
|
22
|
+
const skillsDir = path.join(cwd, ".github", "skills");
|
|
23
|
+
const motherBrainDir = path.join(cwd, ".mother-brain");
|
|
24
|
+
console.log(chalk.cyan("\n\u{1F9E0} Initializing Mother Brain...\n"));
|
|
25
|
+
const versionFile = path.join(motherBrainDir, "version.json");
|
|
26
|
+
if (await fs.pathExists(versionFile) && !options.force) {
|
|
27
|
+
const version = await fs.readJSON(versionFile);
|
|
28
|
+
console.log(chalk.yellow(`Mother Brain is already installed (v${version.installed})`));
|
|
29
|
+
console.log(chalk.dim("Use --force to reinstall, or run: mother-brain update\n"));
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
const packageRoot = path.resolve(__dirname, "..");
|
|
33
|
+
const sourceSkillsDir = path.join(packageRoot, "skills");
|
|
34
|
+
const coreSkills = ["mother-brain", "child-brain", "skill-creator"];
|
|
35
|
+
await fs.ensureDir(skillsDir);
|
|
36
|
+
await fs.ensureDir(path.join(motherBrainDir, "docs"));
|
|
37
|
+
let copiedCount = 0;
|
|
38
|
+
for (const skill of coreSkills) {
|
|
39
|
+
const sourcePath = path.join(sourceSkillsDir, skill);
|
|
40
|
+
const destPath = path.join(skillsDir, skill);
|
|
41
|
+
if (await fs.pathExists(sourcePath)) {
|
|
42
|
+
const exists = await fs.pathExists(destPath);
|
|
43
|
+
if (exists && !options.force) {
|
|
44
|
+
console.log(chalk.yellow(` \u26A0 ${skill} already exists (skipping)`));
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
await fs.copy(sourcePath, destPath, { overwrite: true });
|
|
48
|
+
console.log(chalk.green(` \u2713 ${skill}`));
|
|
49
|
+
copiedCount++;
|
|
50
|
+
} else {
|
|
51
|
+
console.log(chalk.red(` \u2717 ${skill} not found in package`));
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
const pkg = await fs.readJSON(path.join(packageRoot, "package.json"));
|
|
55
|
+
await fs.writeJSON(versionFile, {
|
|
56
|
+
installed: pkg.version,
|
|
57
|
+
installedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
58
|
+
}, { spaces: 2 });
|
|
59
|
+
const sessionFile = path.join(motherBrainDir, "session-state.json");
|
|
60
|
+
if (!await fs.pathExists(sessionFile)) {
|
|
61
|
+
await fs.writeJSON(sessionFile, {
|
|
62
|
+
project: null,
|
|
63
|
+
currentPhase: null,
|
|
64
|
+
currentTask: null,
|
|
65
|
+
tasksCompleted: [],
|
|
66
|
+
lastSession: (/* @__PURE__ */ new Date()).toISOString(),
|
|
67
|
+
installedVersion: pkg.version,
|
|
68
|
+
skills: []
|
|
69
|
+
}, { spaces: 2 });
|
|
70
|
+
}
|
|
71
|
+
console.log(chalk.cyan("\n\u2705 Mother Brain initialized!\n"));
|
|
72
|
+
console.log("Next steps:");
|
|
73
|
+
console.log(chalk.dim(" 1. Commit the new files to your repo"));
|
|
74
|
+
console.log(chalk.dim(" 2. Open GitHub Copilot CLI"));
|
|
75
|
+
console.log(chalk.dim(" 3. Type: /mother-brain\n"));
|
|
76
|
+
if (copiedCount > 0) {
|
|
77
|
+
console.log(chalk.green(`Added ${copiedCount} skill(s) to .github/skills/`));
|
|
78
|
+
}
|
|
79
|
+
console.log(chalk.green("Created .mother-brain/ for project state\n"));
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// src/commands/update.ts
|
|
83
|
+
import path2 from "path";
|
|
84
|
+
import fs2 from "fs-extra";
|
|
85
|
+
import chalk2 from "chalk";
|
|
86
|
+
import { exec } from "child_process";
|
|
87
|
+
import { promisify } from "util";
|
|
88
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
89
|
+
var execAsync = promisify(exec);
|
|
90
|
+
var __filename2 = fileURLToPath2(import.meta.url);
|
|
91
|
+
var __dirname2 = path2.dirname(__filename2);
|
|
92
|
+
async function update() {
|
|
93
|
+
const cwd = process.cwd();
|
|
94
|
+
const skillsDir = path2.join(cwd, ".github", "skills");
|
|
95
|
+
const motherBrainDir = path2.join(cwd, ".mother-brain");
|
|
96
|
+
const versionFile = path2.join(motherBrainDir, "version.json");
|
|
97
|
+
console.log(chalk2.cyan("\n\u{1F9E0} Updating Mother Brain...\n"));
|
|
98
|
+
if (!await fs2.pathExists(versionFile)) {
|
|
99
|
+
console.log(chalk2.yellow("Mother Brain is not initialized in this project."));
|
|
100
|
+
console.log(chalk2.dim("Run: mother-brain init\n"));
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
const currentVersion = await fs2.readJSON(versionFile);
|
|
104
|
+
let latestVersion;
|
|
105
|
+
try {
|
|
106
|
+
const { stdout } = await execAsync("npm view mother-brain version");
|
|
107
|
+
latestVersion = stdout.trim();
|
|
108
|
+
} catch {
|
|
109
|
+
console.log(chalk2.yellow("Could not check npm for latest version."));
|
|
110
|
+
console.log(chalk2.dim("Using bundled package version instead.\n"));
|
|
111
|
+
const packageRoot = path2.resolve(__dirname2, "..");
|
|
112
|
+
const pkg = await fs2.readJSON(path2.join(packageRoot, "package.json"));
|
|
113
|
+
latestVersion = pkg.version;
|
|
114
|
+
}
|
|
115
|
+
console.log(chalk2.dim(`Installed: v${currentVersion.installed}`));
|
|
116
|
+
console.log(chalk2.dim(`Latest: v${latestVersion}
|
|
117
|
+
`));
|
|
118
|
+
if (currentVersion.installed === latestVersion) {
|
|
119
|
+
console.log(chalk2.green("\u2705 Already on the latest version!\n"));
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
console.log(chalk2.dim("Downloading latest version..."));
|
|
123
|
+
try {
|
|
124
|
+
const tempDir = path2.join(cwd, ".mother-brain", ".update-temp");
|
|
125
|
+
await fs2.ensureDir(tempDir);
|
|
126
|
+
await execAsync(`npm pack mother-brain@${latestVersion} --pack-destination "${tempDir}"`);
|
|
127
|
+
const files = await fs2.readdir(tempDir);
|
|
128
|
+
const tarball = files.find((f) => f.endsWith(".tgz"));
|
|
129
|
+
if (!tarball) {
|
|
130
|
+
throw new Error("Could not find downloaded package");
|
|
131
|
+
}
|
|
132
|
+
await execAsync(`tar -xzf "${path2.join(tempDir, tarball)}" -C "${tempDir}"`);
|
|
133
|
+
const extractedSkillsDir = path2.join(tempDir, "package", "skills");
|
|
134
|
+
const coreSkills = ["mother-brain", "child-brain", "skill-creator"];
|
|
135
|
+
for (const skill of coreSkills) {
|
|
136
|
+
const sourcePath = path2.join(extractedSkillsDir, skill);
|
|
137
|
+
const destPath = path2.join(skillsDir, skill);
|
|
138
|
+
if (await fs2.pathExists(sourcePath)) {
|
|
139
|
+
await fs2.copy(sourcePath, destPath, { overwrite: true });
|
|
140
|
+
console.log(chalk2.green(` \u2713 Updated ${skill}`));
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
await fs2.remove(tempDir);
|
|
144
|
+
await fs2.writeJSON(versionFile, {
|
|
145
|
+
installed: latestVersion,
|
|
146
|
+
installedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
147
|
+
previousVersion: currentVersion.installed
|
|
148
|
+
}, { spaces: 2 });
|
|
149
|
+
console.log(chalk2.cyan(`
|
|
150
|
+
\u2705 Updated to v${latestVersion}!
|
|
151
|
+
`));
|
|
152
|
+
console.log(chalk2.dim("Don't forget to commit the updated files.\n"));
|
|
153
|
+
} catch (error) {
|
|
154
|
+
console.log(chalk2.red("Failed to download update."));
|
|
155
|
+
console.log(chalk2.dim("Try running: npx mother-brain@latest init --force\n"));
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// src/commands/status.ts
|
|
160
|
+
import path3 from "path";
|
|
161
|
+
import fs3 from "fs-extra";
|
|
162
|
+
import chalk3 from "chalk";
|
|
163
|
+
import { exec as exec2 } from "child_process";
|
|
164
|
+
import { promisify as promisify2 } from "util";
|
|
165
|
+
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
166
|
+
var execAsync2 = promisify2(exec2);
|
|
167
|
+
var __filename3 = fileURLToPath3(import.meta.url);
|
|
168
|
+
var __dirname3 = path3.dirname(__filename3);
|
|
169
|
+
async function status() {
|
|
170
|
+
const cwd = process.cwd();
|
|
171
|
+
const motherBrainDir = path3.join(cwd, ".mother-brain");
|
|
172
|
+
const versionFile = path3.join(motherBrainDir, "version.json");
|
|
173
|
+
const skillsDir = path3.join(cwd, ".github", "skills");
|
|
174
|
+
console.log(chalk3.cyan("\n\u{1F9E0} Mother Brain Status\n"));
|
|
175
|
+
if (!await fs3.pathExists(versionFile)) {
|
|
176
|
+
console.log(chalk3.yellow("Not initialized in this project."));
|
|
177
|
+
console.log(chalk3.dim("Run: mother-brain init\n"));
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
const currentVersion = await fs3.readJSON(versionFile);
|
|
181
|
+
const packageRoot = path3.resolve(__dirname3, "..");
|
|
182
|
+
const pkg = await fs3.readJSON(path3.join(packageRoot, "package.json"));
|
|
183
|
+
console.log(chalk3.white("Installed version: ") + chalk3.green(`v${currentVersion.installed}`));
|
|
184
|
+
console.log(chalk3.white("Package version: ") + chalk3.dim(`v${pkg.version}`));
|
|
185
|
+
try {
|
|
186
|
+
const { stdout } = await execAsync2("npm view @super-state/mother-brain version 2>/dev/null");
|
|
187
|
+
const latestVersion = stdout.trim();
|
|
188
|
+
if (latestVersion && latestVersion !== currentVersion.installed) {
|
|
189
|
+
console.log(chalk3.yellow(`
|
|
190
|
+
\u2B06\uFE0F Update available: v${latestVersion}`));
|
|
191
|
+
console.log(chalk3.dim("Run: mother-brain update\n"));
|
|
192
|
+
} else {
|
|
193
|
+
console.log(chalk3.green("\n\u2713 Up to date\n"));
|
|
194
|
+
}
|
|
195
|
+
} catch {
|
|
196
|
+
console.log(chalk3.dim("\n(Could not check for updates)\n"));
|
|
197
|
+
}
|
|
198
|
+
console.log(chalk3.white("Installed skills:"));
|
|
199
|
+
if (await fs3.pathExists(skillsDir)) {
|
|
200
|
+
const skills = await fs3.readdir(skillsDir);
|
|
201
|
+
const coreSkills = ["mother-brain", "child-brain", "skill-creator"];
|
|
202
|
+
for (const skill of skills) {
|
|
203
|
+
const skillPath = path3.join(skillsDir, skill);
|
|
204
|
+
const stat = await fs3.stat(skillPath);
|
|
205
|
+
if (stat.isDirectory()) {
|
|
206
|
+
const isCore = coreSkills.includes(skill);
|
|
207
|
+
const label = isCore ? chalk3.dim(" (core)") : chalk3.cyan(" (project)");
|
|
208
|
+
console.log(chalk3.green(` \u2713 ${skill}`) + label);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
} else {
|
|
212
|
+
console.log(chalk3.dim(" No skills found"));
|
|
213
|
+
}
|
|
214
|
+
const sessionFile = path3.join(motherBrainDir, "session-state.json");
|
|
215
|
+
if (await fs3.pathExists(sessionFile)) {
|
|
216
|
+
const session = await fs3.readJSON(sessionFile);
|
|
217
|
+
if (session.project) {
|
|
218
|
+
console.log(chalk3.white("\nProject: ") + chalk3.cyan(session.project));
|
|
219
|
+
if (session.currentPhase) {
|
|
220
|
+
console.log(chalk3.dim(` Phase ${session.currentPhase}`));
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
console.log("");
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// src/commands/analyze.ts
|
|
228
|
+
import { existsSync, readdirSync, readFileSync } from "fs";
|
|
229
|
+
import { join } from "path";
|
|
230
|
+
var EXPECTED_SECTIONS = [
|
|
231
|
+
{ name: "Frontmatter", required: true, pattern: /^---\r?\n[\s\S]*?\r?\n---/m, description: "YAML metadata block" },
|
|
232
|
+
{ name: "name", required: true, pattern: /^name:\s*.+$/m, description: "Skill name in frontmatter" },
|
|
233
|
+
{ name: "description", required: true, pattern: /^description:\s*.+$/m, description: "Skill description" },
|
|
234
|
+
{ name: "allowed-tools", required: false, pattern: /^allowed-tools:\s*.+$/m, description: "List of allowed tools" },
|
|
235
|
+
{ name: "Purpose section", required: true, pattern: /^##?\s*Purpose/im, description: "Explains what the skill does" },
|
|
236
|
+
{ name: "Steps section", required: false, pattern: /^##?\s*Steps/im, description: "Step-by-step instructions" },
|
|
237
|
+
{ name: "Examples", required: false, pattern: /(^##?\s*Example|```)/im, description: "Usage examples" }
|
|
238
|
+
];
|
|
239
|
+
function analyzeSkill(skillPath, skillName) {
|
|
240
|
+
const skillMdPath = join(skillPath, "SKILL.md");
|
|
241
|
+
const analysis = {
|
|
242
|
+
name: skillName,
|
|
243
|
+
path: skillPath,
|
|
244
|
+
issues: [],
|
|
245
|
+
suggestions: [],
|
|
246
|
+
score: 100
|
|
247
|
+
};
|
|
248
|
+
if (!existsSync(skillMdPath)) {
|
|
249
|
+
analysis.issues.push("Missing SKILL.md file");
|
|
250
|
+
analysis.score = 0;
|
|
251
|
+
return analysis;
|
|
252
|
+
}
|
|
253
|
+
const content = readFileSync(skillMdPath, "utf-8");
|
|
254
|
+
for (const section of EXPECTED_SECTIONS) {
|
|
255
|
+
if (!section.pattern.test(content)) {
|
|
256
|
+
if (section.required) {
|
|
257
|
+
analysis.issues.push(`Missing required: ${section.name} - ${section.description}`);
|
|
258
|
+
analysis.score -= 15;
|
|
259
|
+
} else {
|
|
260
|
+
analysis.suggestions.push(`Consider adding: ${section.name} - ${section.description}`);
|
|
261
|
+
analysis.score -= 5;
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
const lines = content.split("\n").length;
|
|
266
|
+
if (lines < 20) {
|
|
267
|
+
analysis.suggestions.push("Skill is quite short - consider adding more detail");
|
|
268
|
+
analysis.score -= 5;
|
|
269
|
+
} else if (lines > 2e3) {
|
|
270
|
+
analysis.suggestions.push("Skill is very long - consider splitting into sub-skills");
|
|
271
|
+
analysis.score -= 5;
|
|
272
|
+
}
|
|
273
|
+
if (!/wizard|ask_user|choices/i.test(content)) {
|
|
274
|
+
analysis.suggestions.push("Consider adding wizard-style prompts for user input");
|
|
275
|
+
}
|
|
276
|
+
if (!/validation|verify|check/i.test(content)) {
|
|
277
|
+
analysis.suggestions.push("Consider adding validation steps");
|
|
278
|
+
}
|
|
279
|
+
analysis.score = Math.max(0, analysis.score);
|
|
280
|
+
return analysis;
|
|
281
|
+
}
|
|
282
|
+
function printAnalysis(analysis) {
|
|
283
|
+
const scoreEmoji = analysis.score >= 80 ? "\u2705" : analysis.score >= 50 ? "\u26A0\uFE0F" : "\u274C";
|
|
284
|
+
console.log(`
|
|
285
|
+
${scoreEmoji} ${analysis.name} (Score: ${analysis.score}/100)`);
|
|
286
|
+
console.log(` Path: ${analysis.path}`);
|
|
287
|
+
if (analysis.issues.length > 0) {
|
|
288
|
+
console.log("\n Issues:");
|
|
289
|
+
analysis.issues.forEach((issue) => console.log(` \u274C ${issue}`));
|
|
290
|
+
}
|
|
291
|
+
if (analysis.suggestions.length > 0) {
|
|
292
|
+
console.log("\n Suggestions:");
|
|
293
|
+
analysis.suggestions.forEach((suggestion) => console.log(` \u{1F4A1} ${suggestion}`));
|
|
294
|
+
}
|
|
295
|
+
if (analysis.issues.length === 0 && analysis.suggestions.length === 0) {
|
|
296
|
+
console.log(" This skill looks great!");
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
function analyzeCommand(program2) {
|
|
300
|
+
program2.command("analyze").description("Analyze existing skills and suggest improvements").option("-s, --skill <name>", "Analyze a specific skill").action((options) => {
|
|
301
|
+
const skillsDir = join(process.cwd(), ".github", "skills");
|
|
302
|
+
if (!existsSync(skillsDir)) {
|
|
303
|
+
console.log("\u274C No skills found at .github/skills/");
|
|
304
|
+
console.log(' Run "npx mother-brain init" first to install skills.');
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
307
|
+
const skills = readdirSync(skillsDir, { withFileTypes: true }).filter((dirent) => dirent.isDirectory()).map((dirent) => dirent.name);
|
|
308
|
+
if (skills.length === 0) {
|
|
309
|
+
console.log("\u274C No skills found in .github/skills/");
|
|
310
|
+
return;
|
|
311
|
+
}
|
|
312
|
+
const targetSkills = options.skill ? skills.filter((s) => s === options.skill) : skills;
|
|
313
|
+
if (options.skill && targetSkills.length === 0) {
|
|
314
|
+
console.log(`\u274C Skill "${options.skill}" not found`);
|
|
315
|
+
return;
|
|
316
|
+
}
|
|
317
|
+
console.log("\n\u{1F50D} Analyzing skills...\n");
|
|
318
|
+
console.log("\u2501".repeat(50));
|
|
319
|
+
const analyses = [];
|
|
320
|
+
for (const skillName of targetSkills) {
|
|
321
|
+
const skillPath = join(skillsDir, skillName);
|
|
322
|
+
const analysis = analyzeSkill(skillPath, skillName);
|
|
323
|
+
analyses.push(analysis);
|
|
324
|
+
printAnalysis(analysis);
|
|
325
|
+
}
|
|
326
|
+
console.log("\n" + "\u2501".repeat(50));
|
|
327
|
+
const avgScore = Math.round(analyses.reduce((sum, a) => sum + a.score, 0) / analyses.length);
|
|
328
|
+
const totalIssues = analyses.reduce((sum, a) => sum + a.issues.length, 0);
|
|
329
|
+
const totalSuggestions = analyses.reduce((sum, a) => sum + a.suggestions.length, 0);
|
|
330
|
+
console.log(`
|
|
331
|
+
\u{1F4CA} Summary:`);
|
|
332
|
+
console.log(` Skills analyzed: ${analyses.length}`);
|
|
333
|
+
console.log(` Average score: ${avgScore}/100`);
|
|
334
|
+
console.log(` Total issues: ${totalIssues}`);
|
|
335
|
+
console.log(` Total suggestions: ${totalSuggestions}`);
|
|
336
|
+
if (totalIssues > 0 || totalSuggestions > 0) {
|
|
337
|
+
console.log(`
|
|
338
|
+
\u{1F4A1} Run "npx mother-brain upgrade <skill-name>" to apply improvements`);
|
|
339
|
+
}
|
|
340
|
+
});
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
// src/commands/upgrade.ts
|
|
344
|
+
import { existsSync as existsSync2, readFileSync as readFileSync2, writeFileSync } from "fs";
|
|
345
|
+
import { join as join2 } from "path";
|
|
346
|
+
import chalk4 from "chalk";
|
|
347
|
+
import readline from "readline";
|
|
348
|
+
function generateImprovements(skillPath) {
|
|
349
|
+
const skillMdPath = join2(skillPath, "SKILL.md");
|
|
350
|
+
const improvements = [];
|
|
351
|
+
if (!existsSync2(skillMdPath)) {
|
|
352
|
+
return improvements;
|
|
353
|
+
}
|
|
354
|
+
const content = readFileSync2(skillMdPath, "utf-8");
|
|
355
|
+
if (!/^---\r?\n[\s\S]*?\r?\n---/m.test(content)) {
|
|
356
|
+
improvements.push({
|
|
357
|
+
type: "add",
|
|
358
|
+
section: "Frontmatter",
|
|
359
|
+
description: "Add YAML frontmatter with skill metadata",
|
|
360
|
+
template: `---
|
|
361
|
+
name: ${extractSkillName(content)}
|
|
362
|
+
description: [Add description]
|
|
363
|
+
allowed-tools: powershell view grep glob create edit ask_user
|
|
364
|
+
---
|
|
365
|
+
|
|
366
|
+
`
|
|
367
|
+
});
|
|
368
|
+
}
|
|
369
|
+
if (!/^##?\s*Purpose/im.test(content)) {
|
|
370
|
+
improvements.push({
|
|
371
|
+
type: "add",
|
|
372
|
+
section: "Purpose",
|
|
373
|
+
description: "Add Purpose section explaining what the skill does",
|
|
374
|
+
template: `
|
|
375
|
+
## Purpose
|
|
376
|
+
|
|
377
|
+
[Describe what this skill does and when to use it]
|
|
378
|
+
|
|
379
|
+
`
|
|
380
|
+
});
|
|
381
|
+
}
|
|
382
|
+
if (!/^##?\s*Steps/im.test(content)) {
|
|
383
|
+
improvements.push({
|
|
384
|
+
type: "add",
|
|
385
|
+
section: "Steps",
|
|
386
|
+
description: "Add Steps section with structured workflow",
|
|
387
|
+
template: `
|
|
388
|
+
## Steps
|
|
389
|
+
|
|
390
|
+
### 1. [First Step]
|
|
391
|
+
- [Details]
|
|
392
|
+
|
|
393
|
+
### 2. [Second Step]
|
|
394
|
+
- [Details]
|
|
395
|
+
|
|
396
|
+
`
|
|
397
|
+
});
|
|
398
|
+
}
|
|
399
|
+
if (!/wizard|ask_user|choices/i.test(content)) {
|
|
400
|
+
improvements.push({
|
|
401
|
+
type: "add",
|
|
402
|
+
section: "Wizard Pattern",
|
|
403
|
+
description: "Add wizard-style user prompts for better interaction",
|
|
404
|
+
template: `
|
|
405
|
+
### User Interaction Pattern
|
|
406
|
+
|
|
407
|
+
Use \`ask_user\` tool with choices for all user decisions:
|
|
408
|
+
- Provide 2-3 clear options
|
|
409
|
+
- Allow freeform for custom inputs
|
|
410
|
+
- Never ask yes/no in plain text
|
|
411
|
+
|
|
412
|
+
`
|
|
413
|
+
});
|
|
414
|
+
}
|
|
415
|
+
if (!/validation|verify|check/i.test(content)) {
|
|
416
|
+
improvements.push({
|
|
417
|
+
type: "add",
|
|
418
|
+
section: "Validation",
|
|
419
|
+
description: "Add validation steps to verify output quality",
|
|
420
|
+
template: `
|
|
421
|
+
### Validation
|
|
422
|
+
|
|
423
|
+
Before marking complete:
|
|
424
|
+
- [ ] Output matches requirements
|
|
425
|
+
- [ ] User has reviewed and approved
|
|
426
|
+
- [ ] No errors in execution
|
|
427
|
+
|
|
428
|
+
`
|
|
429
|
+
});
|
|
430
|
+
}
|
|
431
|
+
return improvements;
|
|
432
|
+
}
|
|
433
|
+
function extractSkillName(content) {
|
|
434
|
+
const match = content.match(/^#\s*(.+)$/m);
|
|
435
|
+
if (match) {
|
|
436
|
+
return match[1].toLowerCase().replace(/[^a-z0-9\s-]/g, "").replace(/\s+/g, "-").substring(0, 30);
|
|
437
|
+
}
|
|
438
|
+
return "unnamed-skill";
|
|
439
|
+
}
|
|
440
|
+
async function promptUser(question) {
|
|
441
|
+
const rl = readline.createInterface({
|
|
442
|
+
input: process.stdin,
|
|
443
|
+
output: process.stdout
|
|
444
|
+
});
|
|
445
|
+
return new Promise((resolve) => {
|
|
446
|
+
rl.question(question, (answer) => {
|
|
447
|
+
rl.close();
|
|
448
|
+
resolve(answer.trim().toLowerCase());
|
|
449
|
+
});
|
|
450
|
+
});
|
|
451
|
+
}
|
|
452
|
+
function upgradeCommand(program2) {
|
|
453
|
+
program2.command("upgrade [skill]").description("Apply improvements to a skill based on analysis").option("-a, --all", "Upgrade all skills").option("-y, --yes", "Accept all improvements without prompting").action(async (skillName, options) => {
|
|
454
|
+
const skillsDir = join2(process.cwd(), ".github", "skills");
|
|
455
|
+
if (!existsSync2(skillsDir)) {
|
|
456
|
+
console.log(chalk4.red("\u274C No skills found at .github/skills/"));
|
|
457
|
+
console.log(' Run "npx mother-brain init" first.');
|
|
458
|
+
return;
|
|
459
|
+
}
|
|
460
|
+
if (!skillName && !options.all) {
|
|
461
|
+
console.log(chalk4.yellow("Usage: mother-brain upgrade <skill-name>"));
|
|
462
|
+
console.log(chalk4.yellow(" or: mother-brain upgrade --all"));
|
|
463
|
+
return;
|
|
464
|
+
}
|
|
465
|
+
const skills = options.all ? __require("fs").readdirSync(skillsDir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name) : [skillName];
|
|
466
|
+
let totalApplied = 0;
|
|
467
|
+
let totalSkipped = 0;
|
|
468
|
+
for (const skill of skills) {
|
|
469
|
+
const skillPath = join2(skillsDir, skill);
|
|
470
|
+
if (!existsSync2(skillPath)) {
|
|
471
|
+
console.log(chalk4.red(`\u274C Skill "${skill}" not found`));
|
|
472
|
+
continue;
|
|
473
|
+
}
|
|
474
|
+
console.log(chalk4.cyan(`
|
|
475
|
+
\u{1F527} Upgrading: ${skill}`));
|
|
476
|
+
console.log("\u2500".repeat(40));
|
|
477
|
+
const improvements = generateImprovements(skillPath);
|
|
478
|
+
if (improvements.length === 0) {
|
|
479
|
+
console.log(chalk4.green("\u2705 No improvements needed"));
|
|
480
|
+
continue;
|
|
481
|
+
}
|
|
482
|
+
const skillMdPath = join2(skillPath, "SKILL.md");
|
|
483
|
+
let content = readFileSync2(skillMdPath, "utf-8");
|
|
484
|
+
for (const improvement of improvements) {
|
|
485
|
+
console.log(`
|
|
486
|
+
${chalk4.yellow("\u{1F4A1}")} ${improvement.description}`);
|
|
487
|
+
console.log(chalk4.dim(` Section: ${improvement.section}`));
|
|
488
|
+
console.log(chalk4.dim(` Preview:`));
|
|
489
|
+
const previewLines = improvement.template.split("\n").slice(0, 5);
|
|
490
|
+
previewLines.forEach((line) => console.log(chalk4.dim(` ${line}`)));
|
|
491
|
+
if (improvement.template.split("\n").length > 5) {
|
|
492
|
+
console.log(chalk4.dim(" ..."));
|
|
493
|
+
}
|
|
494
|
+
let action = "a";
|
|
495
|
+
if (!options.yes) {
|
|
496
|
+
console.log(`
|
|
497
|
+
${chalk4.green("[a]")}ccept ${chalk4.yellow("[s]")}kip ${chalk4.blue("[t]")}weak`);
|
|
498
|
+
action = await promptUser(" Choice: ");
|
|
499
|
+
}
|
|
500
|
+
if (action === "a" || action === "accept" || action === "") {
|
|
501
|
+
if (improvement.section === "Frontmatter") {
|
|
502
|
+
content = improvement.template + content;
|
|
503
|
+
} else {
|
|
504
|
+
content = content.trimEnd() + "\n" + improvement.template;
|
|
505
|
+
}
|
|
506
|
+
console.log(chalk4.green(" \u2705 Applied"));
|
|
507
|
+
totalApplied++;
|
|
508
|
+
} else if (action === "t" || action === "tweak") {
|
|
509
|
+
console.log(chalk4.yellow(" \u{1F4DD} Tweaking is available in interactive mode"));
|
|
510
|
+
console.log(chalk4.yellow(" For now, edit the skill manually after upgrade"));
|
|
511
|
+
totalSkipped++;
|
|
512
|
+
} else {
|
|
513
|
+
console.log(chalk4.dim(" \u23ED\uFE0F Skipped"));
|
|
514
|
+
totalSkipped++;
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
writeFileSync(skillMdPath, content);
|
|
518
|
+
console.log(chalk4.green(`
|
|
519
|
+
\u2705 ${skill} saved`));
|
|
520
|
+
}
|
|
521
|
+
console.log(chalk4.cyan("\n" + "\u2550".repeat(40)));
|
|
522
|
+
console.log(chalk4.white(`\u{1F4CA} Summary:`));
|
|
523
|
+
console.log(` Applied: ${totalApplied} improvements`);
|
|
524
|
+
console.log(` Skipped: ${totalSkipped}`);
|
|
525
|
+
if (totalApplied > 0) {
|
|
526
|
+
console.log(chalk4.green("\n\u2705 Skills upgraded! Review changes before committing."));
|
|
527
|
+
}
|
|
528
|
+
});
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
// src/cli.ts
|
|
532
|
+
import { exec as exec3 } from "child_process";
|
|
533
|
+
var program = new Command();
|
|
534
|
+
var VERSION = "0.0.7";
|
|
535
|
+
program.name("mother-brain").description("AI-powered project management framework for GitHub Copilot CLI").version(VERSION);
|
|
536
|
+
program.command("init").description("Initialize Mother Brain in the current project").option("-f, --force", "Overwrite existing skills").action(init);
|
|
537
|
+
program.command("update").description("Update Mother Brain skills to the latest version").action(update);
|
|
538
|
+
program.command("status").description("Show installed version and available updates").action(status);
|
|
539
|
+
analyzeCommand(program);
|
|
540
|
+
upgradeCommand(program);
|
|
541
|
+
program.command("docs").description("Open Mother Brain documentation in browser").action(() => {
|
|
542
|
+
const url = "https://github.com/super-state/mother-brain#readme";
|
|
543
|
+
console.log(chalk5.cyan("\u{1F4D6} Opening documentation..."));
|
|
544
|
+
const cmd = process.platform === "win32" ? "start" : process.platform === "darwin" ? "open" : "xdg-open";
|
|
545
|
+
exec3(`${cmd} ${url}`, (err) => {
|
|
546
|
+
if (err) {
|
|
547
|
+
console.log(chalk5.yellow(`
|
|
548
|
+
Couldn't open browser. Visit: ${url}`));
|
|
549
|
+
}
|
|
550
|
+
});
|
|
551
|
+
});
|
|
552
|
+
program.command("quickstart").description("Show quick start guide").action(() => {
|
|
553
|
+
console.log(chalk5.cyan(`
|
|
554
|
+
\u2533\u2533\u2513\u250F\u2513\u250F\u2533\u2513\u2513\u250F\u250F\u2513\u2533\u2513 \u2533\u2513\u2533\u2513\u250F\u2513\u2533\u2533\u2513
|
|
555
|
+
\u2503\u2503\u2503\u2503\u2503 \u2503 \u2523\u252B\u2523 \u2523\u252B \u2523\u252B\u2523\u252B\u2523\u252B\u2503\u2503\u2503
|
|
556
|
+
\u251B \u2517\u2517\u251B \u253B \u251B\u2517\u2517\u251B\u251B\u2517 \u253B\u251B\u251B\u2517\u251B\u2517\u253B\u251B\u2517
|
|
557
|
+
`));
|
|
558
|
+
console.log(chalk5.white.bold("\u{1F680} Quick Start Guide\n"));
|
|
559
|
+
console.log(chalk5.yellow("Step 1:") + " Initialize Mother Brain in your project");
|
|
560
|
+
console.log(chalk5.dim(" npx mother-brain init\n"));
|
|
561
|
+
console.log(chalk5.yellow("Step 2:") + " Start using it with GitHub Copilot CLI");
|
|
562
|
+
console.log(chalk5.dim(' ghcs "/mother-brain"\n'));
|
|
563
|
+
console.log(chalk5.yellow("Step 3:") + " Follow the wizard to define your vision");
|
|
564
|
+
console.log(chalk5.dim(" Mother Brain will guide you through:\n"));
|
|
565
|
+
console.log(chalk5.dim(" - Vision Discovery (what are you building?)"));
|
|
566
|
+
console.log(chalk5.dim(" - Roadmap Generation (how to get there)"));
|
|
567
|
+
console.log(chalk5.dim(" - Skill Creation (automate repetitive tasks)"));
|
|
568
|
+
console.log(chalk5.dim(" - Task Execution (build it step by step)\n"));
|
|
569
|
+
console.log(chalk5.green("That's it!") + " Mother Brain will help you ship faster.\n");
|
|
570
|
+
console.log(chalk5.dim("For more info: mother-brain docs"));
|
|
571
|
+
});
|
|
572
|
+
program.action(() => {
|
|
573
|
+
console.log(chalk5.cyan(`
|
|
574
|
+
\u2533\u2533\u2513\u250F\u2513\u250F\u2533\u2513\u2513\u250F\u250F\u2513\u2533\u2513 \u2533\u2513\u2533\u2513\u250F\u2513\u2533\u2533\u2513
|
|
575
|
+
\u2503\u2503\u2503\u2503\u2503 \u2503 \u2523\u252B\u2523 \u2523\u252B \u2523\u252B\u2523\u252B\u2523\u252B\u2503\u2503\u2503
|
|
576
|
+
\u251B \u2517\u2517\u251B \u253B \u251B\u2517\u2517\u251B\u251B\u2517 \u253B\u251B\u251B\u2517\u251B\u2517\u253B\u251B\u2517
|
|
577
|
+
`));
|
|
578
|
+
console.log(chalk5.white("AI-powered project management for GitHub Copilot CLI"));
|
|
579
|
+
console.log(chalk5.dim(`v${VERSION}
|
|
580
|
+
`));
|
|
581
|
+
console.log(chalk5.white.bold("Getting Started:"));
|
|
582
|
+
console.log(chalk5.green(" npx mother-brain init ") + "Add to your project");
|
|
583
|
+
console.log(chalk5.green(" npx mother-brain quickstart ") + "Show quick start guide\n");
|
|
584
|
+
console.log(chalk5.white.bold("Commands:"));
|
|
585
|
+
console.log(chalk5.green(" init ") + "Add Mother Brain skills to project");
|
|
586
|
+
console.log(chalk5.green(" update ") + "Update to the latest version");
|
|
587
|
+
console.log(chalk5.green(" status ") + "Check installed version");
|
|
588
|
+
console.log(chalk5.green(" analyze ") + "Analyze skills and suggest improvements");
|
|
589
|
+
console.log(chalk5.green(" upgrade ") + "Apply improvements to skills");
|
|
590
|
+
console.log(chalk5.green(" docs ") + "Open documentation in browser");
|
|
591
|
+
console.log(chalk5.green(" quickstart ") + "Show quick start guide\n");
|
|
592
|
+
console.log(chalk5.dim("Run mother-brain <command> --help for command details"));
|
|
593
|
+
});
|
|
594
|
+
program.parse();
|
package/package.json
CHANGED
|
@@ -1,22 +1,48 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "mother-brain",
|
|
3
|
-
"version": "0.0.
|
|
4
|
-
"description": "
|
|
5
|
-
"
|
|
6
|
-
"
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
".
|
|
12
|
-
"
|
|
13
|
-
"
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
"
|
|
17
|
-
"
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
"
|
|
21
|
-
|
|
22
|
-
|
|
1
|
+
{
|
|
2
|
+
"name": "mother-brain",
|
|
3
|
+
"version": "0.0.7",
|
|
4
|
+
"description": "AI-powered project management framework for GitHub Copilot CLI",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"mother-brain": "dist/cli.js"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"build": "tsup src/cli.ts --format esm --dts --clean",
|
|
12
|
+
"dev": "tsup src/cli.ts --format esm --watch",
|
|
13
|
+
"prepublishOnly": "npm run build"
|
|
14
|
+
},
|
|
15
|
+
"keywords": [
|
|
16
|
+
"mother-brain",
|
|
17
|
+
"github-copilot",
|
|
18
|
+
"cli",
|
|
19
|
+
"ai",
|
|
20
|
+
"project-management",
|
|
21
|
+
"skills"
|
|
22
|
+
],
|
|
23
|
+
"author": "super-state",
|
|
24
|
+
"license": "MIT",
|
|
25
|
+
"repository": {
|
|
26
|
+
"type": "git",
|
|
27
|
+
"url": "https://github.com/super-state/mother-brain.git",
|
|
28
|
+
"directory": "cli"
|
|
29
|
+
},
|
|
30
|
+
"files": [
|
|
31
|
+
"dist",
|
|
32
|
+
"skills"
|
|
33
|
+
],
|
|
34
|
+
"engines": {
|
|
35
|
+
"node": ">=18"
|
|
36
|
+
},
|
|
37
|
+
"dependencies": {
|
|
38
|
+
"commander": "^12.0.0",
|
|
39
|
+
"chalk": "^5.3.0",
|
|
40
|
+
"fs-extra": "^11.2.0"
|
|
41
|
+
},
|
|
42
|
+
"devDependencies": {
|
|
43
|
+
"@types/fs-extra": "^11.0.4",
|
|
44
|
+
"@types/node": "^20.11.0",
|
|
45
|
+
"tsup": "^8.0.0",
|
|
46
|
+
"typescript": "^5.3.0"
|
|
47
|
+
}
|
|
48
|
+
}
|