@codebakers/cli 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +89 -0
- package/dist/chunk-7CKLRE2H.js +36 -0
- package/dist/config-R2H6JKGW.js +16 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +514 -0
- package/package.json +55 -0
package/README.md
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# @codebakers/cli
|
|
2
|
+
|
|
3
|
+
Official CLI for CodeBakers - AI prompt patterns for production-ready code.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npx @codebakers/cli setup
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Or install globally:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npm install -g @codebakers/cli
|
|
15
|
+
codebakers setup
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Commands
|
|
19
|
+
|
|
20
|
+
### Setup
|
|
21
|
+
|
|
22
|
+
Configure CodeBakers with your API key and set up your IDE:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
# Interactive setup
|
|
26
|
+
npx @codebakers/cli setup
|
|
27
|
+
|
|
28
|
+
# Setup for specific IDE
|
|
29
|
+
npx @codebakers/cli setup --ide cursor
|
|
30
|
+
npx @codebakers/cli setup --ide windsurf
|
|
31
|
+
npx @codebakers/cli setup --ide aider
|
|
32
|
+
npx @codebakers/cli setup --ide claude-code
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### Claude Code MCP Server
|
|
36
|
+
|
|
37
|
+
Add CodeBakers as an MCP server in Claude Code:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
/mcp add codebakers npx -y @codebakers/cli serve
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### Status
|
|
44
|
+
|
|
45
|
+
Check your configuration:
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
npx @codebakers/cli status
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Logout
|
|
52
|
+
|
|
53
|
+
Remove stored API key:
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
npx @codebakers/cli logout
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Supported IDEs
|
|
60
|
+
|
|
61
|
+
| IDE | Configuration File |
|
|
62
|
+
|-----|-------------------|
|
|
63
|
+
| Cursor | `.cursorrules` |
|
|
64
|
+
| Windsurf | `.windsurfrules` |
|
|
65
|
+
| Aider | `.aider.conf.yml` |
|
|
66
|
+
| Claude Code | `CLAUDE.md` + `.claude/` |
|
|
67
|
+
|
|
68
|
+
## Getting Your API Key
|
|
69
|
+
|
|
70
|
+
1. Sign up at [codebakers.ai](https://codebakers.ai)
|
|
71
|
+
2. Go to Settings to find your API key
|
|
72
|
+
3. Run `codebakers setup` and paste your key
|
|
73
|
+
|
|
74
|
+
## What's Included
|
|
75
|
+
|
|
76
|
+
CodeBakers provides 34 production-ready pattern modules:
|
|
77
|
+
|
|
78
|
+
- **00-core** - Required standards, types, error handling
|
|
79
|
+
- **01-database** - Drizzle ORM, queries, migrations
|
|
80
|
+
- **02-auth** - Authentication, OAuth, 2FA, security
|
|
81
|
+
- **03-api** - API routes, validation, rate limiting
|
|
82
|
+
- **04-frontend** - React, forms, states, i18n
|
|
83
|
+
- **05-payments** - Stripe, subscriptions, billing
|
|
84
|
+
- **06-integrations** - Email, files, background jobs
|
|
85
|
+
- And 27 more modules...
|
|
86
|
+
|
|
87
|
+
## License
|
|
88
|
+
|
|
89
|
+
MIT
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
// src/utils/config.ts
|
|
2
|
+
import Conf from "conf";
|
|
3
|
+
var config = new Conf({
|
|
4
|
+
projectName: "codebakers",
|
|
5
|
+
defaults: {
|
|
6
|
+
apiKey: null,
|
|
7
|
+
apiUrl: "https://codebakers.ai"
|
|
8
|
+
}
|
|
9
|
+
});
|
|
10
|
+
function getApiKey() {
|
|
11
|
+
return config.get("apiKey");
|
|
12
|
+
}
|
|
13
|
+
function setApiKey(key) {
|
|
14
|
+
config.set("apiKey", key);
|
|
15
|
+
}
|
|
16
|
+
function getApiUrl() {
|
|
17
|
+
return config.get("apiUrl");
|
|
18
|
+
}
|
|
19
|
+
function setApiUrl(url) {
|
|
20
|
+
config.set("apiUrl", url);
|
|
21
|
+
}
|
|
22
|
+
function clearConfig() {
|
|
23
|
+
config.clear();
|
|
24
|
+
}
|
|
25
|
+
function getConfigPath() {
|
|
26
|
+
return config.path;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export {
|
|
30
|
+
getApiKey,
|
|
31
|
+
setApiKey,
|
|
32
|
+
getApiUrl,
|
|
33
|
+
setApiUrl,
|
|
34
|
+
clearConfig,
|
|
35
|
+
getConfigPath
|
|
36
|
+
};
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,514 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
getApiKey,
|
|
4
|
+
getApiUrl,
|
|
5
|
+
getConfigPath,
|
|
6
|
+
setApiKey
|
|
7
|
+
} from "./chunk-7CKLRE2H.js";
|
|
8
|
+
|
|
9
|
+
// src/index.ts
|
|
10
|
+
import { Command } from "commander";
|
|
11
|
+
import chalk2 from "chalk";
|
|
12
|
+
|
|
13
|
+
// src/commands/setup.ts
|
|
14
|
+
import inquirer from "inquirer";
|
|
15
|
+
import chalk from "chalk";
|
|
16
|
+
import ora from "ora";
|
|
17
|
+
import { writeFile, mkdir } from "fs/promises";
|
|
18
|
+
import { existsSync } from "fs";
|
|
19
|
+
import { join } from "path";
|
|
20
|
+
|
|
21
|
+
// src/utils/api.ts
|
|
22
|
+
var ApiError = class extends Error {
|
|
23
|
+
constructor(message, statusCode, code) {
|
|
24
|
+
super(message);
|
|
25
|
+
this.statusCode = statusCode;
|
|
26
|
+
this.code = code;
|
|
27
|
+
this.name = "ApiError";
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
async function makeRequest(endpoint, options = {}) {
|
|
31
|
+
const apiKey = getApiKey();
|
|
32
|
+
if (!apiKey) {
|
|
33
|
+
throw new ApiError("No API key configured. Run: codebakers setup", 401);
|
|
34
|
+
}
|
|
35
|
+
const baseUrl = getApiUrl();
|
|
36
|
+
const url = `${baseUrl}${endpoint}`;
|
|
37
|
+
const response = await fetch(url, {
|
|
38
|
+
...options,
|
|
39
|
+
headers: {
|
|
40
|
+
"Content-Type": "application/json",
|
|
41
|
+
Authorization: `Bearer ${apiKey}`,
|
|
42
|
+
...options.headers
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
const data = await response.json();
|
|
46
|
+
if (!response.ok) {
|
|
47
|
+
throw new ApiError(
|
|
48
|
+
data.error || "API request failed",
|
|
49
|
+
response.status,
|
|
50
|
+
data.code
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
return data;
|
|
54
|
+
}
|
|
55
|
+
async function validateApiKey(apiKey) {
|
|
56
|
+
const baseUrl = getApiUrl();
|
|
57
|
+
const response = await fetch(`${baseUrl}/api/patterns`, {
|
|
58
|
+
headers: {
|
|
59
|
+
Authorization: `Bearer ${apiKey}`
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
return response.ok;
|
|
63
|
+
}
|
|
64
|
+
async function listPatterns() {
|
|
65
|
+
return makeRequest("/api/patterns");
|
|
66
|
+
}
|
|
67
|
+
async function fetchPatterns(patterns) {
|
|
68
|
+
return makeRequest("/api/patterns", {
|
|
69
|
+
method: "POST",
|
|
70
|
+
body: JSON.stringify({ patterns })
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
async function fetchAllPatterns() {
|
|
74
|
+
const list = await listPatterns();
|
|
75
|
+
const allPatterns = {};
|
|
76
|
+
const patternNames = list.patterns.map((p) => p.name);
|
|
77
|
+
for (let i = 0; i < patternNames.length; i += 5) {
|
|
78
|
+
const batch = patternNames.slice(i, i + 5);
|
|
79
|
+
const result = await fetchPatterns(batch);
|
|
80
|
+
Object.assign(allPatterns, result.patterns);
|
|
81
|
+
}
|
|
82
|
+
const routerResult = await fetchPatterns(["router"]);
|
|
83
|
+
Object.assign(allPatterns, routerResult.patterns);
|
|
84
|
+
return allPatterns;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// src/commands/setup.ts
|
|
88
|
+
var IDE_CONFIGS = {
|
|
89
|
+
cursor: {
|
|
90
|
+
file: ".cursorrules",
|
|
91
|
+
description: "Cursor AI IDE"
|
|
92
|
+
},
|
|
93
|
+
windsurf: {
|
|
94
|
+
file: ".windsurfrules",
|
|
95
|
+
description: "Windsurf (Codeium) IDE"
|
|
96
|
+
},
|
|
97
|
+
aider: {
|
|
98
|
+
file: ".aider.conf.yml",
|
|
99
|
+
description: "Aider CLI"
|
|
100
|
+
},
|
|
101
|
+
"claude-code": {
|
|
102
|
+
file: "CLAUDE.md",
|
|
103
|
+
description: "Claude Code CLI"
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
function setupCommand(program2) {
|
|
107
|
+
program2.command("setup").description("Configure CodeBakers with your API key").option("--ide <type>", "IDE to configure (cursor, windsurf, aider, claude-code)").option("--key <apiKey>", "API key (or enter interactively)").option("--force", "Overwrite existing configuration").action(async (options) => {
|
|
108
|
+
console.log(chalk.bold("\n\u{1F36A} CodeBakers Setup\n"));
|
|
109
|
+
let apiKey = options.key;
|
|
110
|
+
const existingKey = getApiKey();
|
|
111
|
+
if (existingKey && !options.key) {
|
|
112
|
+
const { useExisting } = await inquirer.prompt([
|
|
113
|
+
{
|
|
114
|
+
type: "confirm",
|
|
115
|
+
name: "useExisting",
|
|
116
|
+
message: "API key already configured. Use existing key?",
|
|
117
|
+
default: true
|
|
118
|
+
}
|
|
119
|
+
]);
|
|
120
|
+
if (useExisting) {
|
|
121
|
+
apiKey = existingKey;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
if (!apiKey) {
|
|
125
|
+
const answers = await inquirer.prompt([
|
|
126
|
+
{
|
|
127
|
+
type: "password",
|
|
128
|
+
name: "apiKey",
|
|
129
|
+
message: "Enter your CodeBakers API key:",
|
|
130
|
+
mask: "*",
|
|
131
|
+
validate: (input) => {
|
|
132
|
+
if (!input.startsWith("cb_")) {
|
|
133
|
+
return "Invalid key format. API keys start with cb_";
|
|
134
|
+
}
|
|
135
|
+
return true;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
]);
|
|
139
|
+
apiKey = answers.apiKey;
|
|
140
|
+
}
|
|
141
|
+
const spinner = ora("Validating API key...").start();
|
|
142
|
+
try {
|
|
143
|
+
const isValid = await validateApiKey(apiKey);
|
|
144
|
+
if (!isValid) {
|
|
145
|
+
spinner.fail("Invalid API key");
|
|
146
|
+
console.log(chalk.red("\nAPI key validation failed."));
|
|
147
|
+
console.log(chalk.dim("Get your key at: https://codebakers.ai/settings"));
|
|
148
|
+
process.exit(1);
|
|
149
|
+
}
|
|
150
|
+
spinner.succeed("API key validated");
|
|
151
|
+
} catch (error) {
|
|
152
|
+
spinner.fail("Failed to validate API key");
|
|
153
|
+
console.log(chalk.red("\nCould not connect to CodeBakers API."));
|
|
154
|
+
console.log(chalk.dim("Check your internet connection and try again."));
|
|
155
|
+
process.exit(1);
|
|
156
|
+
}
|
|
157
|
+
setApiKey(apiKey);
|
|
158
|
+
console.log(chalk.green("\n\u2713 API key saved\n"));
|
|
159
|
+
let ide = options.ide;
|
|
160
|
+
if (!ide) {
|
|
161
|
+
const { selectedIde } = await inquirer.prompt([
|
|
162
|
+
{
|
|
163
|
+
type: "list",
|
|
164
|
+
name: "selectedIde",
|
|
165
|
+
message: "Which AI coding tool are you using?",
|
|
166
|
+
choices: [
|
|
167
|
+
{ name: "Cursor", value: "cursor" },
|
|
168
|
+
{ name: "Claude Code (CLI)", value: "claude-code" },
|
|
169
|
+
{ name: "Windsurf (Codeium)", value: "windsurf" },
|
|
170
|
+
{ name: "Aider", value: "aider" },
|
|
171
|
+
{ name: "Skip for now", value: null }
|
|
172
|
+
]
|
|
173
|
+
}
|
|
174
|
+
]);
|
|
175
|
+
ide = selectedIde;
|
|
176
|
+
}
|
|
177
|
+
if (ide) {
|
|
178
|
+
await configureIDE(ide, options.force);
|
|
179
|
+
}
|
|
180
|
+
console.log(chalk.bold.green("\n\u{1F389} Setup complete!\n"));
|
|
181
|
+
if (ide === "claude-code") {
|
|
182
|
+
console.log(chalk.dim("Next step - add CodeBakers to Claude Code:"));
|
|
183
|
+
console.log(chalk.cyan(" /mcp add codebakers npx -y @codebakers/cli serve\n"));
|
|
184
|
+
} else if (ide) {
|
|
185
|
+
console.log(chalk.dim(`Pattern file created. Restart ${IDE_CONFIGS[ide].description} to load it.
|
|
186
|
+
`));
|
|
187
|
+
}
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
async function configureIDE(ide, force = false) {
|
|
191
|
+
const config = IDE_CONFIGS[ide];
|
|
192
|
+
const targetPath = join(process.cwd(), config.file);
|
|
193
|
+
const spinner = ora(`Fetching CodeBakers patterns...`).start();
|
|
194
|
+
try {
|
|
195
|
+
if (ide === "claude-code") {
|
|
196
|
+
const claudeDir = join(process.cwd(), ".claude");
|
|
197
|
+
if (!existsSync(claudeDir)) {
|
|
198
|
+
await mkdir(claudeDir, { recursive: true });
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
if (existsSync(targetPath) && !force) {
|
|
202
|
+
spinner.stop();
|
|
203
|
+
const { overwrite } = await inquirer.prompt([
|
|
204
|
+
{
|
|
205
|
+
type: "confirm",
|
|
206
|
+
name: "overwrite",
|
|
207
|
+
message: `${config.file} already exists. Overwrite?`,
|
|
208
|
+
default: false
|
|
209
|
+
}
|
|
210
|
+
]);
|
|
211
|
+
if (!overwrite) {
|
|
212
|
+
console.log(chalk.yellow("\nSetup cancelled. Use --force to overwrite."));
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
spinner.start();
|
|
216
|
+
}
|
|
217
|
+
const patterns = await fetchAllPatterns();
|
|
218
|
+
const patternList = await listPatterns();
|
|
219
|
+
spinner.text = "Generating configuration...";
|
|
220
|
+
let content;
|
|
221
|
+
if (ide === "claude-code") {
|
|
222
|
+
content = patterns["router"] || "";
|
|
223
|
+
for (const [name, patternContent] of Object.entries(patterns)) {
|
|
224
|
+
if (name !== "router") {
|
|
225
|
+
const patternPath = join(process.cwd(), ".claude", `${name}.md`);
|
|
226
|
+
await writeFile(patternPath, patternContent, "utf-8");
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
} else if (ide === "aider") {
|
|
230
|
+
content = generateAiderConfig(patterns);
|
|
231
|
+
} else {
|
|
232
|
+
content = generateRulesFile(patterns, patternList.version);
|
|
233
|
+
}
|
|
234
|
+
await writeFile(targetPath, content, "utf-8");
|
|
235
|
+
spinner.succeed(`Created ${config.file}`);
|
|
236
|
+
if (ide === "claude-code") {
|
|
237
|
+
console.log(chalk.dim(` + Created .claude/ folder with ${Object.keys(patterns).length - 1} pattern files`));
|
|
238
|
+
}
|
|
239
|
+
console.log(chalk.green(`
|
|
240
|
+
\u2713 ${IDE_CONFIGS[ide].description} configured`));
|
|
241
|
+
} catch (error) {
|
|
242
|
+
spinner.fail("Failed to configure IDE");
|
|
243
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
244
|
+
console.log(chalk.red(`
|
|
245
|
+
Error: ${message}`));
|
|
246
|
+
process.exit(1);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
function generateRulesFile(patterns, version) {
|
|
250
|
+
const router = patterns["router"] || "";
|
|
251
|
+
let content = `# CodeBakers Patterns v${version}
|
|
252
|
+
# Generated by @codebakers/cli
|
|
253
|
+
# https://codebakers.ai
|
|
254
|
+
|
|
255
|
+
${router}
|
|
256
|
+
|
|
257
|
+
---
|
|
258
|
+
|
|
259
|
+
# PATTERN MODULES (Auto-loaded based on context)
|
|
260
|
+
|
|
261
|
+
`;
|
|
262
|
+
for (const [name, patternContent] of Object.entries(patterns)) {
|
|
263
|
+
if (name !== "router" && patternContent) {
|
|
264
|
+
content += `
|
|
265
|
+
## Module: ${name}
|
|
266
|
+
|
|
267
|
+
${patternContent}
|
|
268
|
+
|
|
269
|
+
---
|
|
270
|
+
`;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
return content;
|
|
274
|
+
}
|
|
275
|
+
function generateAiderConfig(patterns) {
|
|
276
|
+
const router = patterns["router"] || "";
|
|
277
|
+
return `# CodeBakers Aider Configuration
|
|
278
|
+
# Generated by @codebakers/cli
|
|
279
|
+
# https://codebakers.ai
|
|
280
|
+
|
|
281
|
+
read:
|
|
282
|
+
- .codebakers-patterns.md
|
|
283
|
+
|
|
284
|
+
# System message with CodeBakers patterns
|
|
285
|
+
message: |
|
|
286
|
+
${router.split("\n").map((line) => " " + line).join("\n")}
|
|
287
|
+
`;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
// src/commands/serve.ts
|
|
291
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
292
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
293
|
+
import {
|
|
294
|
+
CallToolRequestSchema,
|
|
295
|
+
ListToolsRequestSchema,
|
|
296
|
+
ListResourcesRequestSchema,
|
|
297
|
+
ReadResourceRequestSchema
|
|
298
|
+
} from "@modelcontextprotocol/sdk/types.js";
|
|
299
|
+
function serveCommand(program2) {
|
|
300
|
+
program2.command("serve").description("Run CodeBakers as an MCP server for Claude Code").action(async () => {
|
|
301
|
+
const apiKey = getApiKey();
|
|
302
|
+
if (!apiKey) {
|
|
303
|
+
console.error("No API key configured. Run: npx @codebakers/cli setup");
|
|
304
|
+
process.exit(1);
|
|
305
|
+
}
|
|
306
|
+
const server = new Server(
|
|
307
|
+
{
|
|
308
|
+
name: "codebakers",
|
|
309
|
+
version: "1.0.0"
|
|
310
|
+
},
|
|
311
|
+
{
|
|
312
|
+
capabilities: {
|
|
313
|
+
tools: {},
|
|
314
|
+
resources: {}
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
);
|
|
318
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
319
|
+
return {
|
|
320
|
+
tools: [
|
|
321
|
+
{
|
|
322
|
+
name: "get_pattern",
|
|
323
|
+
description: "Fetch a CodeBakers pattern module for production-ready code patterns. Available patterns: 00-core, 01-database, 02-auth, 03-api, 04-frontend, 05-payments, 06-integrations, 07-performance, 08-testing, 09-design, 10-generators, 11-realtime, 12-saas, 14-ai, and more.",
|
|
324
|
+
inputSchema: {
|
|
325
|
+
type: "object",
|
|
326
|
+
properties: {
|
|
327
|
+
patterns: {
|
|
328
|
+
type: "array",
|
|
329
|
+
items: { type: "string" },
|
|
330
|
+
description: 'Pattern names to fetch (e.g., ["00-core", "02-auth"]). Max 5 per request.'
|
|
331
|
+
}
|
|
332
|
+
},
|
|
333
|
+
required: ["patterns"]
|
|
334
|
+
}
|
|
335
|
+
},
|
|
336
|
+
{
|
|
337
|
+
name: "list_patterns",
|
|
338
|
+
description: "List all available CodeBakers pattern modules",
|
|
339
|
+
inputSchema: {
|
|
340
|
+
type: "object",
|
|
341
|
+
properties: {}
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
]
|
|
345
|
+
};
|
|
346
|
+
});
|
|
347
|
+
server.setRequestHandler(ListResourcesRequestSchema, async () => {
|
|
348
|
+
try {
|
|
349
|
+
const result = await listPatterns();
|
|
350
|
+
return {
|
|
351
|
+
resources: result.patterns.map((p) => ({
|
|
352
|
+
uri: `codebakers://pattern/${p.name}`,
|
|
353
|
+
name: p.name,
|
|
354
|
+
description: `CodeBakers ${p.name} pattern module`,
|
|
355
|
+
mimeType: "text/markdown"
|
|
356
|
+
}))
|
|
357
|
+
};
|
|
358
|
+
} catch (error) {
|
|
359
|
+
return { resources: [] };
|
|
360
|
+
}
|
|
361
|
+
});
|
|
362
|
+
server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
|
|
363
|
+
const uri = request.params.uri;
|
|
364
|
+
const match = uri.match(/^codebakers:\/\/pattern\/(.+)$/);
|
|
365
|
+
if (!match) {
|
|
366
|
+
throw new Error(`Invalid resource URI: ${uri}`);
|
|
367
|
+
}
|
|
368
|
+
const patternName = match[1];
|
|
369
|
+
try {
|
|
370
|
+
const result = await fetchPatterns([patternName]);
|
|
371
|
+
const content = result.patterns[patternName];
|
|
372
|
+
if (!content) {
|
|
373
|
+
throw new Error(`Pattern not found: ${patternName}`);
|
|
374
|
+
}
|
|
375
|
+
return {
|
|
376
|
+
contents: [
|
|
377
|
+
{
|
|
378
|
+
uri,
|
|
379
|
+
mimeType: "text/markdown",
|
|
380
|
+
text: content
|
|
381
|
+
}
|
|
382
|
+
]
|
|
383
|
+
};
|
|
384
|
+
} catch (error) {
|
|
385
|
+
if (error instanceof ApiError) {
|
|
386
|
+
throw new Error(`API Error: ${error.message}`);
|
|
387
|
+
}
|
|
388
|
+
throw error;
|
|
389
|
+
}
|
|
390
|
+
});
|
|
391
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
392
|
+
const { name, arguments: args } = request.params;
|
|
393
|
+
if (name === "list_patterns") {
|
|
394
|
+
try {
|
|
395
|
+
const result = await listPatterns();
|
|
396
|
+
return {
|
|
397
|
+
content: [
|
|
398
|
+
{
|
|
399
|
+
type: "text",
|
|
400
|
+
text: `Available CodeBakers patterns (${result.total}):
|
|
401
|
+
|
|
402
|
+
${result.patterns.map((p) => `- ${p.name}`).join("\n")}
|
|
403
|
+
|
|
404
|
+
Use get_pattern to fetch specific patterns.`
|
|
405
|
+
}
|
|
406
|
+
]
|
|
407
|
+
};
|
|
408
|
+
} catch (error) {
|
|
409
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
410
|
+
return {
|
|
411
|
+
content: [{ type: "text", text: `Error: ${message}` }],
|
|
412
|
+
isError: true
|
|
413
|
+
};
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
if (name === "get_pattern") {
|
|
417
|
+
const patterns = args?.patterns || [];
|
|
418
|
+
if (patterns.length === 0) {
|
|
419
|
+
return {
|
|
420
|
+
content: [
|
|
421
|
+
{ type: "text", text: "Error: No patterns specified" }
|
|
422
|
+
],
|
|
423
|
+
isError: true
|
|
424
|
+
};
|
|
425
|
+
}
|
|
426
|
+
if (patterns.length > 5) {
|
|
427
|
+
return {
|
|
428
|
+
content: [
|
|
429
|
+
{ type: "text", text: "Error: Maximum 5 patterns per request" }
|
|
430
|
+
],
|
|
431
|
+
isError: true
|
|
432
|
+
};
|
|
433
|
+
}
|
|
434
|
+
try {
|
|
435
|
+
const result = await fetchPatterns(patterns);
|
|
436
|
+
const content = Object.entries(result.patterns).map(([name2, text]) => `# Pattern: ${name2}
|
|
437
|
+
|
|
438
|
+
${text}`).join("\n\n---\n\n");
|
|
439
|
+
return {
|
|
440
|
+
content: [
|
|
441
|
+
{
|
|
442
|
+
type: "text",
|
|
443
|
+
text: content || `No patterns found for: ${patterns.join(", ")}`
|
|
444
|
+
}
|
|
445
|
+
]
|
|
446
|
+
};
|
|
447
|
+
} catch (error) {
|
|
448
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
449
|
+
if (error instanceof ApiError) {
|
|
450
|
+
if (error.statusCode === 401) {
|
|
451
|
+
return {
|
|
452
|
+
content: [
|
|
453
|
+
{
|
|
454
|
+
type: "text",
|
|
455
|
+
text: "Error: Invalid API key. Run: npx @codebakers/cli setup"
|
|
456
|
+
}
|
|
457
|
+
],
|
|
458
|
+
isError: true
|
|
459
|
+
};
|
|
460
|
+
}
|
|
461
|
+
if (error.statusCode === 402) {
|
|
462
|
+
return {
|
|
463
|
+
content: [
|
|
464
|
+
{
|
|
465
|
+
type: "text",
|
|
466
|
+
text: `Error: ${message}. Upgrade at: https://codebakers.ai/billing`
|
|
467
|
+
}
|
|
468
|
+
],
|
|
469
|
+
isError: true
|
|
470
|
+
};
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
return {
|
|
474
|
+
content: [{ type: "text", text: `Error: ${message}` }],
|
|
475
|
+
isError: true
|
|
476
|
+
};
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
return {
|
|
480
|
+
content: [{ type: "text", text: `Unknown tool: ${name}` }],
|
|
481
|
+
isError: true
|
|
482
|
+
};
|
|
483
|
+
});
|
|
484
|
+
const transport = new StdioServerTransport();
|
|
485
|
+
await server.connect(transport);
|
|
486
|
+
});
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
// src/index.ts
|
|
490
|
+
var program = new Command();
|
|
491
|
+
program.name("codebakers").description("CodeBakers CLI - AI prompt patterns for production-ready code").version("1.0.0");
|
|
492
|
+
setupCommand(program);
|
|
493
|
+
serveCommand(program);
|
|
494
|
+
program.command("status").description("Check CodeBakers configuration status").action(() => {
|
|
495
|
+
console.log(chalk2.bold("\n\u{1F36A} CodeBakers Status\n"));
|
|
496
|
+
const apiKey = getApiKey();
|
|
497
|
+
if (apiKey) {
|
|
498
|
+
const maskedKey = apiKey.substring(0, 10) + "..." + apiKey.slice(-4);
|
|
499
|
+
console.log(chalk2.green("\u2713 API key configured"));
|
|
500
|
+
console.log(chalk2.dim(` Key: ${maskedKey}`));
|
|
501
|
+
} else {
|
|
502
|
+
console.log(chalk2.red("\u2717 No API key configured"));
|
|
503
|
+
console.log(chalk2.dim(" Run: codebakers setup"));
|
|
504
|
+
}
|
|
505
|
+
console.log(chalk2.dim(`
|
|
506
|
+
Config path: ${getConfigPath()}
|
|
507
|
+
`));
|
|
508
|
+
});
|
|
509
|
+
program.command("logout").description("Remove stored API key").action(async () => {
|
|
510
|
+
const { clearConfig } = await import("./config-R2H6JKGW.js");
|
|
511
|
+
clearConfig();
|
|
512
|
+
console.log(chalk2.green("\n\u2713 API key removed\n"));
|
|
513
|
+
});
|
|
514
|
+
program.parse();
|
package/package.json
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@codebakers/cli",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "CodeBakers CLI - AI prompt patterns for production-ready code",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"codebakers": "dist/index.js"
|
|
8
|
+
},
|
|
9
|
+
"type": "module",
|
|
10
|
+
"scripts": {
|
|
11
|
+
"build": "tsup src/index.ts --format esm --dts --clean",
|
|
12
|
+
"dev": "tsup src/index.ts --format esm --watch",
|
|
13
|
+
"prepublishOnly": "npm run build",
|
|
14
|
+
"test": "vitest run"
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"dist"
|
|
18
|
+
],
|
|
19
|
+
"keywords": [
|
|
20
|
+
"codebakers",
|
|
21
|
+
"ai",
|
|
22
|
+
"prompts",
|
|
23
|
+
"cursor",
|
|
24
|
+
"claude",
|
|
25
|
+
"aider",
|
|
26
|
+
"windsurf",
|
|
27
|
+
"mcp",
|
|
28
|
+
"cli"
|
|
29
|
+
],
|
|
30
|
+
"author": "CodeBakers",
|
|
31
|
+
"license": "MIT",
|
|
32
|
+
"repository": {
|
|
33
|
+
"type": "git",
|
|
34
|
+
"url": "https://github.com/codebakers/cli"
|
|
35
|
+
},
|
|
36
|
+
"homepage": "https://codebakers.ai",
|
|
37
|
+
"dependencies": {
|
|
38
|
+
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
39
|
+
"chalk": "^5.3.0",
|
|
40
|
+
"commander": "^12.1.0",
|
|
41
|
+
"conf": "^12.0.0",
|
|
42
|
+
"inquirer": "^9.2.23",
|
|
43
|
+
"ora": "^8.0.1"
|
|
44
|
+
},
|
|
45
|
+
"devDependencies": {
|
|
46
|
+
"@types/inquirer": "^9.0.7",
|
|
47
|
+
"@types/node": "^20.11.0",
|
|
48
|
+
"tsup": "^8.0.2",
|
|
49
|
+
"typescript": "^5.3.3",
|
|
50
|
+
"vitest": "^1.2.0"
|
|
51
|
+
},
|
|
52
|
+
"engines": {
|
|
53
|
+
"node": ">=18"
|
|
54
|
+
}
|
|
55
|
+
}
|