continuous-improvement 3.0.0 → 3.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +78 -0
- package/CHANGELOG.md +210 -0
- package/LICENSE +21 -21
- package/QUICKSTART.md +101 -81
- package/README.md +224 -198
- package/SKILL.md +87 -9
- package/action.yml +33 -0
- package/bin/analyze.sh +161 -153
- package/bin/backfill.mjs +172 -0
- package/bin/check-docs-substrings.mjs +333 -0
- package/bin/check-everything-mirror.mjs +145 -0
- package/bin/check-routing-targets.mjs +151 -0
- package/bin/check-skill-law-tag.mjs +128 -0
- package/bin/check-skill-mirror.mjs +119 -0
- package/bin/check-skill-tiers.mjs +116 -0
- package/bin/check-third-party-shape.mjs +202 -0
- package/bin/generate-plugin-manifests.mjs +169 -0
- package/bin/harvest-friction.mjs +279 -0
- package/bin/hook-stats.mjs +258 -0
- package/bin/install.mjs +418 -456
- package/bin/lint-transcript.mjs +239 -0
- package/bin/mcp-server.mjs +842 -499
- package/bin/observe.mjs +148 -0
- package/bin/pre-commit-block-strays.sh +49 -0
- package/bin/refresh-third-party.mjs +416 -0
- package/bin/unified-cli.mjs +533 -0
- package/commands/continuous-improvement.md +115 -74
- package/commands/dashboard.md +56 -0
- package/commands/discipline.md +51 -0
- package/commands/harvest.md +76 -0
- package/commands/learn-eval.md +117 -0
- package/commands/planning-with-files.md +66 -0
- package/commands/proceed-with-the-recommendation.md +62 -0
- package/commands/ralph.md +103 -0
- package/commands/release-train.md +81 -0
- package/commands/seven-laws.md +16 -0
- package/commands/superpowers.md +153 -0
- package/commands/swarm.md +101 -0
- package/commands/workspace-surface-audit.md +77 -0
- package/hooks/observe.sh +172 -134
- package/hooks/session.sh +106 -106
- package/hooks/three-section-close.mjs +181 -0
- package/instinct-packs/go.json +58 -0
- package/instinct-packs/meta.json +16 -0
- package/instinct-packs/python.json +58 -0
- package/instinct-packs/react.json +58 -0
- package/lib/cli-anything.mjs +401 -0
- package/lib/compound-engineering.mjs +831 -0
- package/lib/observe-event.mjs +128 -0
- package/lib/plugin-metadata.mjs +432 -0
- package/lib/pm-marketplace.mjs +61 -0
- package/lib/pm-skills.mjs +1274 -0
- package/lib/resolve-home-dir.mjs +43 -0
- package/lib/skill-tiers.mjs +137 -0
- package/lib/unified-plugin.mjs +924 -0
- package/llms.txt +68 -0
- package/package.json +38 -15
- package/plugins/beginner.json +17 -6
- package/plugins/continuous-improvement/.claude-plugin/marketplace.json +20 -0
- package/plugins/continuous-improvement/.claude-plugin/plugin.json +26 -0
- package/plugins/continuous-improvement/LICENSE +21 -0
- package/plugins/continuous-improvement/README.md +56 -0
- package/plugins/continuous-improvement/bin/backfill.mjs +172 -0
- package/plugins/continuous-improvement/bin/mcp-server.mjs +886 -0
- package/plugins/continuous-improvement/bin/observe.mjs +148 -0
- package/plugins/continuous-improvement/commands/continuous-improvement.md +115 -0
- package/plugins/continuous-improvement/commands/dashboard.md +56 -0
- package/plugins/continuous-improvement/commands/discipline.md +51 -0
- package/plugins/continuous-improvement/commands/harvest.md +76 -0
- package/plugins/continuous-improvement/commands/learn-eval.md +117 -0
- package/plugins/continuous-improvement/commands/planning-with-files.md +66 -0
- package/plugins/continuous-improvement/commands/proceed-with-the-recommendation.md +62 -0
- package/plugins/continuous-improvement/commands/ralph.md +103 -0
- package/plugins/continuous-improvement/commands/release-train.md +81 -0
- package/plugins/continuous-improvement/commands/seven-laws.md +16 -0
- package/plugins/continuous-improvement/commands/superpowers.md +153 -0
- package/plugins/continuous-improvement/commands/swarm.md +101 -0
- package/plugins/continuous-improvement/commands/workspace-surface-audit.md +77 -0
- package/plugins/continuous-improvement/hooks/hooks.json +60 -0
- package/plugins/continuous-improvement/hooks/observe.sh +172 -0
- package/plugins/continuous-improvement/hooks/session.sh +106 -0
- package/plugins/continuous-improvement/hooks/three-section-close.mjs +181 -0
- package/plugins/continuous-improvement/instinct-packs/go.json +58 -0
- package/plugins/continuous-improvement/instinct-packs/meta.json +16 -0
- package/plugins/continuous-improvement/instinct-packs/python.json +58 -0
- package/plugins/continuous-improvement/instinct-packs/react.json +58 -0
- package/plugins/continuous-improvement/lib/observe-event.mjs +128 -0
- package/plugins/continuous-improvement/lib/plugin-metadata.mjs +432 -0
- package/plugins/continuous-improvement/lib/resolve-home-dir.mjs +43 -0
- package/plugins/continuous-improvement/skills/README.md +34 -0
- package/plugins/continuous-improvement/skills/continuous-improvement/SKILL.md +249 -0
- package/plugins/continuous-improvement/skills/deploy-receipt/SKILL.md +131 -0
- package/plugins/continuous-improvement/skills/gateguard/SKILL.md +155 -0
- package/plugins/continuous-improvement/skills/para-memory-files/SKILL.md +108 -0
- package/plugins/continuous-improvement/skills/proceed-with-the-recommendation/SKILL.md +454 -0
- package/plugins/continuous-improvement/skills/ralph/SKILL.md +221 -0
- package/plugins/continuous-improvement/skills/safety-guard/SKILL.md +76 -0
- package/plugins/continuous-improvement/skills/strategic-compact/SKILL.md +104 -0
- package/plugins/continuous-improvement/skills/superpowers/SKILL.md +212 -0
- package/plugins/continuous-improvement/skills/tdd-workflow/SKILL.md +411 -0
- package/plugins/continuous-improvement/skills/token-budget-advisor/SKILL.md +136 -0
- package/plugins/continuous-improvement/skills/verification-loop/SKILL.md +192 -0
- package/plugins/continuous-improvement/skills/wild-risa-balance/SKILL.md +191 -0
- package/plugins/continuous-improvement/skills/workspace-surface-audit/SKILL.md +147 -0
- package/plugins/continuous-improvement/templates/planning-with-files/findings.md +8 -0
- package/plugins/continuous-improvement/templates/planning-with-files/progress.md +7 -0
- package/plugins/continuous-improvement/templates/planning-with-files/task_plan.md +23 -0
- package/plugins/expert.json +34 -5
- package/skills/README.md +79 -0
- package/skills/deploy-receipt.md +131 -0
- package/skills/gateguard.md +155 -0
- package/skills/para-memory-files.md +108 -0
- package/skills/proceed-with-the-recommendation.md +454 -0
- package/skills/ralph.md +221 -0
- package/skills/safety-guard.md +76 -0
- package/skills/strategic-compact.md +104 -0
- package/skills/superpowers.md +212 -0
- package/skills/tdd-workflow.md +411 -0
- package/skills/token-budget-advisor.md +136 -0
- package/skills/verification-loop.md +192 -0
- package/skills/wild-risa-balance.md +191 -0
- package/skills/workspace-surface-audit.md +147 -0
- package/templates/planning-with-files/findings.md +8 -0
- package/templates/planning-with-files/progress.md +7 -0
- package/templates/planning-with-files/task_plan.md +23 -0
- package/templates/verify-ladder.example.json +47 -0
|
@@ -0,0 +1,401 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* CLI-Anything: Turn open-source software into agent-native CLIs.
|
|
4
|
+
*
|
|
5
|
+
* Analyzes a repository and generates an agent-friendly CLI wrapper that
|
|
6
|
+
* language models can drive automatically.
|
|
7
|
+
*/
|
|
8
|
+
import { existsSync } from "node:fs";
|
|
9
|
+
import { access, chmod, mkdir, readFile, writeFile } from "node:fs/promises";
|
|
10
|
+
import { join } from "node:path";
|
|
11
|
+
const DEFAULT_OPTIONS = {
|
|
12
|
+
outputDir: "./generated-clis",
|
|
13
|
+
verbose: false,
|
|
14
|
+
};
|
|
15
|
+
function getErrorMessage(error) {
|
|
16
|
+
return error instanceof Error ? error.message : String(error);
|
|
17
|
+
}
|
|
18
|
+
export default class CLIAnything {
|
|
19
|
+
options;
|
|
20
|
+
constructor(options = {}) {
|
|
21
|
+
this.options = { ...DEFAULT_OPTIONS, ...options };
|
|
22
|
+
}
|
|
23
|
+
async generateCLI(repoPath, options = {}) {
|
|
24
|
+
try {
|
|
25
|
+
this.log(`Analyzing repository: ${repoPath}`);
|
|
26
|
+
const repoInfo = await this.analyzeRepository(repoPath);
|
|
27
|
+
const commands = await this.extractCommands(repoPath, repoInfo);
|
|
28
|
+
const cliWrapper = await this.generateCLIWrapper(repoInfo, commands, options);
|
|
29
|
+
const outputPath = await this.saveCLI(repoInfo, cliWrapper);
|
|
30
|
+
this.log(`✅ CLI generated: ${outputPath}`);
|
|
31
|
+
return { outputPath, repoInfo, commands };
|
|
32
|
+
}
|
|
33
|
+
catch (error) {
|
|
34
|
+
throw new Error(`Failed to generate CLI: ${getErrorMessage(error)}`);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
async analyzeRepository(repoPath) {
|
|
38
|
+
const packageJsonPath = join(repoPath, "package.json");
|
|
39
|
+
const readmePath = join(repoPath, "README.md");
|
|
40
|
+
let packageJson = {};
|
|
41
|
+
let readme = "";
|
|
42
|
+
try {
|
|
43
|
+
const packageContent = await readFile(packageJsonPath, "utf8");
|
|
44
|
+
packageJson = JSON.parse(packageContent);
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
// Not a Node.js project or no package.json.
|
|
48
|
+
}
|
|
49
|
+
try {
|
|
50
|
+
readme = await readFile(readmePath, "utf8");
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
// No README.
|
|
54
|
+
}
|
|
55
|
+
const projectType = this.detectProjectType(repoPath, packageJson);
|
|
56
|
+
const existingCLI = this.extractExistingCLI(packageJson);
|
|
57
|
+
const hasBin = !!packageJson.bin &&
|
|
58
|
+
(typeof packageJson.bin === "string" ||
|
|
59
|
+
Object.keys(packageJson.bin).length > 0);
|
|
60
|
+
return {
|
|
61
|
+
name: packageJson.name ?? this.extractRepoName(repoPath),
|
|
62
|
+
version: packageJson.version ?? "1.0.0",
|
|
63
|
+
description: packageJson.description ?? "",
|
|
64
|
+
projectType,
|
|
65
|
+
existingCLI,
|
|
66
|
+
hasBin,
|
|
67
|
+
scripts: packageJson.scripts ?? {},
|
|
68
|
+
dependencies: packageJson.dependencies ?? {},
|
|
69
|
+
readme,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
detectProjectType(repoPath, packageJson) {
|
|
73
|
+
const { dependencies = {}, devDependencies = {} } = packageJson;
|
|
74
|
+
const allDeps = { ...dependencies, ...devDependencies };
|
|
75
|
+
if (allDeps.express || allDeps.koa || allDeps.fastify)
|
|
76
|
+
return "node-server";
|
|
77
|
+
if (allDeps.react || allDeps["react-dom"])
|
|
78
|
+
return "react-app";
|
|
79
|
+
if (allDeps.vue)
|
|
80
|
+
return "vue-app";
|
|
81
|
+
if (allDeps.angular)
|
|
82
|
+
return "angular-app";
|
|
83
|
+
if (allDeps.next)
|
|
84
|
+
return "next-app";
|
|
85
|
+
if (allDeps.gatsby)
|
|
86
|
+
return "gatsby-app";
|
|
87
|
+
if (allDeps.python || allDeps["python-shell"])
|
|
88
|
+
return "python-wrapper";
|
|
89
|
+
if (allDeps.docker || allDeps["dockerode"])
|
|
90
|
+
return "docker-tool";
|
|
91
|
+
if (existsSync(join(repoPath, "Dockerfile")))
|
|
92
|
+
return "docker-project";
|
|
93
|
+
if (existsSync(join(repoPath, "requirements.txt")) ||
|
|
94
|
+
existsSync(join(repoPath, "setup.py")) ||
|
|
95
|
+
existsSync(join(repoPath, "pyproject.toml"))) {
|
|
96
|
+
return "python-project";
|
|
97
|
+
}
|
|
98
|
+
if (existsSync(join(repoPath, "Cargo.toml")))
|
|
99
|
+
return "rust-project";
|
|
100
|
+
if (existsSync(join(repoPath, "go.mod")))
|
|
101
|
+
return "go-project";
|
|
102
|
+
return "generic";
|
|
103
|
+
}
|
|
104
|
+
extractExistingCLI(packageJson) {
|
|
105
|
+
const cli = {
|
|
106
|
+
bin: packageJson.bin ?? {},
|
|
107
|
+
scripts: {},
|
|
108
|
+
mainCommand: null,
|
|
109
|
+
};
|
|
110
|
+
if (packageJson.scripts) {
|
|
111
|
+
for (const [name, script] of Object.entries(packageJson.scripts)) {
|
|
112
|
+
if (name.includes("start") ||
|
|
113
|
+
name.includes("build") ||
|
|
114
|
+
name.includes("test") ||
|
|
115
|
+
name.includes("dev") ||
|
|
116
|
+
name.includes("serve") ||
|
|
117
|
+
name.includes("run")) {
|
|
118
|
+
cli.scripts[name] = script;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
if (typeof cli.bin === "object") {
|
|
123
|
+
const keys = Object.keys(cli.bin);
|
|
124
|
+
if (keys.length > 0)
|
|
125
|
+
cli.mainCommand = keys[0] ?? null;
|
|
126
|
+
}
|
|
127
|
+
else if (typeof cli.bin === "string") {
|
|
128
|
+
cli.mainCommand = "main";
|
|
129
|
+
}
|
|
130
|
+
return cli;
|
|
131
|
+
}
|
|
132
|
+
async extractCommands(_repoPath, repoInfo) {
|
|
133
|
+
const commands = [];
|
|
134
|
+
for (const [name, script] of Object.entries(repoInfo.scripts)) {
|
|
135
|
+
commands.push({
|
|
136
|
+
type: "script",
|
|
137
|
+
name,
|
|
138
|
+
command: script,
|
|
139
|
+
description: this.generateScriptDescription(name),
|
|
140
|
+
category: this.categorizeScript(name),
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
const { bin } = repoInfo.existingCLI;
|
|
144
|
+
if (typeof bin === "object") {
|
|
145
|
+
for (const [name, path] of Object.entries(bin)) {
|
|
146
|
+
commands.push({
|
|
147
|
+
type: "binary",
|
|
148
|
+
name,
|
|
149
|
+
path,
|
|
150
|
+
description: `Execute ${name} command`,
|
|
151
|
+
category: "core",
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
commands.push(...this.generateProjectTypeCommands(repoInfo));
|
|
156
|
+
return commands;
|
|
157
|
+
}
|
|
158
|
+
generateProjectTypeCommands(repoInfo) {
|
|
159
|
+
const commands = [];
|
|
160
|
+
switch (repoInfo.projectType) {
|
|
161
|
+
case "node-server":
|
|
162
|
+
commands.push({ type: "generated", name: "start", command: "npm start", description: "Start the server", category: "lifecycle" }, { type: "generated", name: "dev", command: "npm run dev", description: "Start in development mode", category: "development" }, { type: "generated", name: "test", command: "npm test", description: "Run tests", category: "testing" });
|
|
163
|
+
break;
|
|
164
|
+
case "react-app":
|
|
165
|
+
case "next-app":
|
|
166
|
+
commands.push({ type: "generated", name: "dev", command: "npm run dev", description: "Start development server", category: "development" }, { type: "generated", name: "build", command: "npm run build", description: "Build for production", category: "build" }, { type: "generated", name: "test", command: "npm test", description: "Run tests", category: "testing" }, { type: "generated", name: "lint", command: "npm run lint", description: "Run linting", category: "quality" });
|
|
167
|
+
break;
|
|
168
|
+
case "python-project":
|
|
169
|
+
commands.push({ type: "generated", name: "install", command: "pip install -r requirements.txt", description: "Install dependencies", category: "setup" }, { type: "generated", name: "run", command: "python main.py", description: "Run main script", category: "core" }, { type: "generated", name: "test", command: "python -m pytest", description: "Run tests", category: "testing" });
|
|
170
|
+
break;
|
|
171
|
+
case "docker-project":
|
|
172
|
+
commands.push({ type: "generated", name: "build", command: "docker build -t app .", description: "Build Docker image", category: "build" }, { type: "generated", name: "run", command: "docker run -p 3000:3000 app", description: "Run Docker container", category: "core" });
|
|
173
|
+
break;
|
|
174
|
+
default:
|
|
175
|
+
break;
|
|
176
|
+
}
|
|
177
|
+
return commands;
|
|
178
|
+
}
|
|
179
|
+
async generateCLIWrapper(repoInfo, commands, options = {}) {
|
|
180
|
+
const template = await this.getTemplate(options.template ?? "default");
|
|
181
|
+
const className = repoInfo.name.replace(/[^a-zA-Z0-9]/g, "");
|
|
182
|
+
return template
|
|
183
|
+
.replace(/{{NAME}}/g, className)
|
|
184
|
+
.replace(/{{VERSION}}/g, repoInfo.version)
|
|
185
|
+
.replace(/{{DESCRIPTION}}/g, repoInfo.description)
|
|
186
|
+
.replace(/{{COMMANDS}}/g, this.generateCommandsCode(commands))
|
|
187
|
+
.replace(/{{PROJECT_TYPE}}/g, repoInfo.projectType)
|
|
188
|
+
.replace(/{{REPO_INFO}}/g, JSON.stringify(repoInfo, null, 2));
|
|
189
|
+
}
|
|
190
|
+
generateCommandsCode(commands) {
|
|
191
|
+
const commandGroups = this.groupCommands(commands);
|
|
192
|
+
let code = "";
|
|
193
|
+
for (const [category, categoryCommands] of Object.entries(commandGroups)) {
|
|
194
|
+
code += ` // ${category.toUpperCase()} COMMANDS\n`;
|
|
195
|
+
for (const cmd of categoryCommands) {
|
|
196
|
+
const safeName = cmd.name.replace(/[^a-zA-Z0-9]/g, "_");
|
|
197
|
+
code += ` ${safeName}: {
|
|
198
|
+
description: '${cmd.description}',
|
|
199
|
+
execute: async (args = []) => {
|
|
200
|
+
return await this.runCommand('${cmd.command ?? ""}', args);
|
|
201
|
+
}
|
|
202
|
+
},\n`;
|
|
203
|
+
}
|
|
204
|
+
code += "\n";
|
|
205
|
+
}
|
|
206
|
+
return code.trim();
|
|
207
|
+
}
|
|
208
|
+
groupCommands(commands) {
|
|
209
|
+
return commands.reduce((groups, cmd) => {
|
|
210
|
+
const category = cmd.category || "general";
|
|
211
|
+
if (!groups[category])
|
|
212
|
+
groups[category] = [];
|
|
213
|
+
groups[category].push(cmd);
|
|
214
|
+
return groups;
|
|
215
|
+
}, {});
|
|
216
|
+
}
|
|
217
|
+
async getTemplate(templateName) {
|
|
218
|
+
const templates = {
|
|
219
|
+
default: `#!/usr/bin/env node
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* Auto-generated CLI wrapper for {{NAME}}
|
|
223
|
+
* Generated by CLI-Anything tool
|
|
224
|
+
*/
|
|
225
|
+
|
|
226
|
+
import { spawn } from 'node:child_process';
|
|
227
|
+
|
|
228
|
+
const repoInfo = {{REPO_INFO}};
|
|
229
|
+
|
|
230
|
+
class {{NAME}}CLI {
|
|
231
|
+
constructor() {
|
|
232
|
+
this.commands = {
|
|
233
|
+
{{COMMANDS}}
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
async runCommand(command, args = []) {
|
|
238
|
+
return new Promise((resolve, reject) => {
|
|
239
|
+
const process = spawn(command, args, {
|
|
240
|
+
stdio: 'inherit',
|
|
241
|
+
shell: true
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
process.on('close', (code) => {
|
|
245
|
+
if (code === 0) {
|
|
246
|
+
resolve({ success: true, code });
|
|
247
|
+
} else {
|
|
248
|
+
reject(new Error(\`Command failed with code \${code}\`));
|
|
249
|
+
}
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
process.on('error', reject);
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
async execute(commandName, args = []) {
|
|
257
|
+
if (!this.commands[commandName]) {
|
|
258
|
+
throw new Error(\`Unknown command: \${commandName}\`);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
const command = this.commands[commandName];
|
|
262
|
+
console.log(\`Executing: \${command.description}\`);
|
|
263
|
+
|
|
264
|
+
try {
|
|
265
|
+
const result = await command.execute(args);
|
|
266
|
+
console.log(\`✅ \${command.description} completed successfully\`);
|
|
267
|
+
return result;
|
|
268
|
+
} catch (error) {
|
|
269
|
+
console.error(\`❌ \${command.description} failed:\`, error.message);
|
|
270
|
+
throw error;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
listCommands() {
|
|
275
|
+
console.log('Available commands for {{NAME}}:');
|
|
276
|
+
Object.entries(this.commands).forEach(([name, cmd]) => {
|
|
277
|
+
console.log(\` \${name.padEnd(15)} - \${cmd.description}\`);
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
if (import.meta.url === \`file://\${process.argv[1]}\`) {
|
|
283
|
+
const cli = new {{NAME}}CLI();
|
|
284
|
+
const [,, command, ...args] = process.argv;
|
|
285
|
+
|
|
286
|
+
if (!command || command === '--help' || command === '-h') {
|
|
287
|
+
cli.listCommands();
|
|
288
|
+
process.exit(0);
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
cli.execute(command, args).catch(error => {
|
|
292
|
+
console.error(error);
|
|
293
|
+
process.exit(1);
|
|
294
|
+
});
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
export default {{NAME}}CLI;`,
|
|
298
|
+
};
|
|
299
|
+
return templates[templateName] ?? templates.default;
|
|
300
|
+
}
|
|
301
|
+
async saveCLI(repoInfo, cliWrapper) {
|
|
302
|
+
const outputDir = this.options.outputDir;
|
|
303
|
+
const fileName = `${repoInfo.name.toLowerCase().replace(/[^a-z0-9]/g, "-")}-cli.mjs`;
|
|
304
|
+
const outputPath = join(outputDir, fileName);
|
|
305
|
+
try {
|
|
306
|
+
await access(outputDir);
|
|
307
|
+
}
|
|
308
|
+
catch {
|
|
309
|
+
await mkdir(outputDir, { recursive: true });
|
|
310
|
+
}
|
|
311
|
+
await writeFile(outputPath, cliWrapper, "utf8");
|
|
312
|
+
try {
|
|
313
|
+
await chmod(outputPath, 0o755);
|
|
314
|
+
}
|
|
315
|
+
catch {
|
|
316
|
+
// Ignore on Windows.
|
|
317
|
+
}
|
|
318
|
+
return outputPath;
|
|
319
|
+
}
|
|
320
|
+
extractRepoName(repoPath) {
|
|
321
|
+
const segments = repoPath.split(/[\\/]/);
|
|
322
|
+
const last = segments[segments.length - 1] ?? repoPath;
|
|
323
|
+
return last.replace(/[^a-zA-Z0-9]/g, "-");
|
|
324
|
+
}
|
|
325
|
+
generateScriptDescription(name) {
|
|
326
|
+
const descriptions = {
|
|
327
|
+
start: "Start the application",
|
|
328
|
+
dev: "Start in development mode",
|
|
329
|
+
build: "Build the application",
|
|
330
|
+
test: "Run tests",
|
|
331
|
+
lint: "Run linting",
|
|
332
|
+
serve: "Start the server",
|
|
333
|
+
deploy: "Deploy the application",
|
|
334
|
+
};
|
|
335
|
+
return descriptions[name] ?? `Execute script: ${name}`;
|
|
336
|
+
}
|
|
337
|
+
categorizeScript(name) {
|
|
338
|
+
if (["start", "dev", "serve"].includes(name))
|
|
339
|
+
return "lifecycle";
|
|
340
|
+
if (["build", "compile"].includes(name))
|
|
341
|
+
return "build";
|
|
342
|
+
if (["test", "spec"].includes(name))
|
|
343
|
+
return "testing";
|
|
344
|
+
if (["lint", "format", "type-check"].includes(name))
|
|
345
|
+
return "quality";
|
|
346
|
+
if (["deploy", "publish"].includes(name))
|
|
347
|
+
return "deployment";
|
|
348
|
+
return "general";
|
|
349
|
+
}
|
|
350
|
+
log(message) {
|
|
351
|
+
if (this.options.verbose) {
|
|
352
|
+
console.log(`[CLI-Anything] ${message}`);
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
357
|
+
const [, , repoPath, ...args] = process.argv;
|
|
358
|
+
if (!repoPath || repoPath === "--help" || repoPath === "-h") {
|
|
359
|
+
console.log(`
|
|
360
|
+
Usage: cli-anything <repository-path> [options]
|
|
361
|
+
|
|
362
|
+
Options:
|
|
363
|
+
--output-dir <dir> Output directory for generated CLIs (default: ./generated-clis)
|
|
364
|
+
--verbose Enable verbose logging
|
|
365
|
+
--template <name> Template to use (default: default)
|
|
366
|
+
--help Show this help
|
|
367
|
+
|
|
368
|
+
Examples:
|
|
369
|
+
cli-anything ./my-project
|
|
370
|
+
cli-anything ./my-project --output-dir ./tools --verbose
|
|
371
|
+
`);
|
|
372
|
+
process.exit(0);
|
|
373
|
+
}
|
|
374
|
+
const options = {};
|
|
375
|
+
for (let i = 0; i < args.length; i++) {
|
|
376
|
+
const flag = args[i];
|
|
377
|
+
if (flag === "--output-dir" && args[i + 1]) {
|
|
378
|
+
options.outputDir = args[i + 1];
|
|
379
|
+
i++;
|
|
380
|
+
}
|
|
381
|
+
else if (flag === "--verbose") {
|
|
382
|
+
options.verbose = true;
|
|
383
|
+
}
|
|
384
|
+
else if (flag === "--template" && args[i + 1]) {
|
|
385
|
+
options.template = args[i + 1];
|
|
386
|
+
i++;
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
const cliAnything = new CLIAnything(options);
|
|
390
|
+
cliAnything
|
|
391
|
+
.generateCLI(repoPath, { template: options.template })
|
|
392
|
+
.then((result) => {
|
|
393
|
+
console.log(`✅ CLI generated successfully!`);
|
|
394
|
+
console.log(`📁 Output: ${result.outputPath}`);
|
|
395
|
+
console.log(`📊 Commands found: ${result.commands.length}`);
|
|
396
|
+
})
|
|
397
|
+
.catch((error) => {
|
|
398
|
+
console.error(`❌ Error: ${getErrorMessage(error)}`);
|
|
399
|
+
process.exit(1);
|
|
400
|
+
});
|
|
401
|
+
}
|