mycontext-cli 0.4.20 → 1.0.2
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 +14 -11
- package/dist/agents/implementations/BackendDevAgent.d.ts +39 -0
- package/dist/agents/implementations/BackendDevAgent.d.ts.map +1 -0
- package/dist/agents/implementations/BackendDevAgent.js +821 -0
- package/dist/agents/implementations/BackendDevAgent.js.map +1 -0
- package/dist/agents/implementations/CodeGenSubAgent.d.ts +1 -1
- package/dist/agents/implementations/CodeGenSubAgent.d.ts.map +1 -1
- package/dist/agents/implementations/CodeGenSubAgent.js +47 -22
- package/dist/agents/implementations/CodeGenSubAgent.js.map +1 -1
- package/dist/agents/implementations/DocsSubAgent.d.ts +7 -0
- package/dist/agents/implementations/DocsSubAgent.d.ts.map +1 -1
- package/dist/agents/implementations/DocsSubAgent.js +20 -11
- package/dist/agents/implementations/DocsSubAgent.js.map +1 -1
- package/dist/agents/implementations/EnhancementAgent.d.ts +1 -1
- package/dist/agents/implementations/EnhancementAgent.d.ts.map +1 -1
- package/dist/agents/implementations/EnhancementAgent.js +17 -12
- package/dist/agents/implementations/EnhancementAgent.js.map +1 -1
- package/dist/cli.js +210 -39
- package/dist/cli.js.map +1 -1
- package/dist/commands/analyze.d.ts +52 -0
- package/dist/commands/analyze.d.ts.map +1 -0
- package/dist/commands/analyze.js +740 -0
- package/dist/commands/analyze.js.map +1 -0
- package/dist/commands/auth.d.ts +19 -26
- package/dist/commands/auth.d.ts.map +1 -1
- package/dist/commands/auth.js +187 -180
- package/dist/commands/auth.js.map +1 -1
- package/dist/commands/build-app.d.ts +33 -0
- package/dist/commands/build-app.d.ts.map +1 -0
- package/dist/commands/build-app.js +507 -0
- package/dist/commands/build-app.js.map +1 -0
- package/dist/commands/generate-components.d.ts +2 -0
- package/dist/commands/generate-components.d.ts.map +1 -1
- package/dist/commands/generate-components.js +96 -49
- package/dist/commands/generate-components.js.map +1 -1
- package/dist/commands/generate-todos.d.ts +25 -0
- package/dist/commands/generate-todos.d.ts.map +1 -0
- package/dist/commands/generate-todos.js +249 -0
- package/dist/commands/generate-todos.js.map +1 -0
- package/dist/commands/generate.d.ts +3 -0
- package/dist/commands/generate.d.ts.map +1 -1
- package/dist/commands/generate.js +251 -93
- package/dist/commands/generate.js.map +1 -1
- package/dist/commands/init.d.ts +5 -0
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +86 -7
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/list.d.ts.map +1 -1
- package/dist/commands/list.js +10 -7
- package/dist/commands/list.js.map +1 -1
- package/dist/commands/migrate.d.ts +29 -0
- package/dist/commands/migrate.d.ts.map +1 -0
- package/dist/commands/migrate.js +485 -0
- package/dist/commands/migrate.js.map +1 -0
- package/dist/commands/model.d.ts +13 -16
- package/dist/commands/model.d.ts.map +1 -1
- package/dist/commands/model.js +89 -320
- package/dist/commands/model.js.map +1 -1
- package/dist/commands/playbooks.d.ts +33 -0
- package/dist/commands/playbooks.d.ts.map +1 -0
- package/dist/commands/playbooks.js +662 -0
- package/dist/commands/playbooks.js.map +1 -0
- package/dist/commands/pricing.d.ts +15 -0
- package/dist/commands/pricing.d.ts.map +1 -0
- package/dist/commands/pricing.js +129 -0
- package/dist/commands/pricing.js.map +1 -0
- package/dist/commands/promote.d.ts +22 -0
- package/dist/commands/promote.d.ts.map +1 -0
- package/dist/commands/promote.js +204 -0
- package/dist/commands/promote.js.map +1 -0
- package/dist/commands/setup.d.ts +5 -18
- package/dist/commands/setup.d.ts.map +1 -1
- package/dist/commands/setup.js +180 -340
- package/dist/commands/setup.js.map +1 -1
- package/dist/config/ai-providers.json +81 -40
- package/dist/config/api.d.ts +9 -0
- package/dist/config/api.d.ts.map +1 -0
- package/dist/config/api.js +25 -0
- package/dist/config/api.js.map +1 -0
- package/dist/config/api.ts +29 -0
- package/dist/config/pricing.json +55 -0
- package/dist/types/index.d.ts +7 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/utils/apiKeyManager.d.ts.map +1 -1
- package/dist/utils/apiKeyManager.js +7 -0
- package/dist/utils/apiKeyManager.js.map +1 -1
- package/dist/utils/fileSystem.d.ts.map +1 -1
- package/dist/utils/fileSystem.js +3 -1
- package/dist/utils/fileSystem.js.map +1 -1
- package/dist/utils/geminiClient.d.ts +61 -0
- package/dist/utils/geminiClient.d.ts.map +1 -0
- package/dist/utils/geminiClient.js +173 -0
- package/dist/utils/geminiClient.js.map +1 -0
- package/dist/utils/hostedApiClient.d.ts +32 -0
- package/dist/utils/hostedApiClient.d.ts.map +1 -0
- package/dist/utils/hostedApiClient.js +231 -0
- package/dist/utils/hostedApiClient.js.map +1 -0
- package/dist/utils/hybridAIClient.d.ts +14 -3
- package/dist/utils/hybridAIClient.d.ts.map +1 -1
- package/dist/utils/hybridAIClient.js +190 -65
- package/dist/utils/hybridAIClient.js.map +1 -1
- package/dist/utils/qwenClient.d.ts +22 -0
- package/dist/utils/qwenClient.d.ts.map +1 -0
- package/dist/utils/qwenClient.js +185 -0
- package/dist/utils/qwenClient.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,662 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.PlaybooksCommand = void 0;
|
|
40
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
41
|
+
const prompts_1 = __importDefault(require("prompts"));
|
|
42
|
+
const fs = __importStar(require("fs-extra"));
|
|
43
|
+
const path = __importStar(require("path"));
|
|
44
|
+
const glob = __importStar(require("glob"));
|
|
45
|
+
class PlaybooksCommand {
|
|
46
|
+
constructor() {
|
|
47
|
+
this.playbooksDir = path.join(process.cwd(), ".mycontext", "playbooks");
|
|
48
|
+
this.templatesDir = path.join(__dirname, "..", "templates", "playbooks");
|
|
49
|
+
}
|
|
50
|
+
async execute(options) {
|
|
51
|
+
try {
|
|
52
|
+
// Ensure playbooks directory exists
|
|
53
|
+
await fs.ensureDir(this.playbooksDir);
|
|
54
|
+
if (options.add) {
|
|
55
|
+
await this.addPlaybook(options.add, options.category);
|
|
56
|
+
}
|
|
57
|
+
else if (options.list) {
|
|
58
|
+
await this.listPlaybooks();
|
|
59
|
+
}
|
|
60
|
+
else if (options.search) {
|
|
61
|
+
await this.searchPlaybooks(options.search);
|
|
62
|
+
}
|
|
63
|
+
else if (options.use) {
|
|
64
|
+
await this.usePlaybook(options.use);
|
|
65
|
+
}
|
|
66
|
+
else if (options.remove) {
|
|
67
|
+
await this.removePlaybook(options.remove);
|
|
68
|
+
}
|
|
69
|
+
else if (options.template) {
|
|
70
|
+
await this.createFromTemplate(options.template);
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
// Interactive mode
|
|
74
|
+
await this.interactiveMode();
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
catch (error) {
|
|
78
|
+
console.error(chalk_1.default.red(`❌ Playbooks error: ${error instanceof Error ? error.message : "Unknown error"}`));
|
|
79
|
+
process.exit(1);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
async interactiveMode() {
|
|
83
|
+
console.log(chalk_1.default.blue("\n📚 MyContext Playbooks"));
|
|
84
|
+
console.log(chalk_1.default.gray("Manage proven processes and technical flows"));
|
|
85
|
+
const response = await (0, prompts_1.default)({
|
|
86
|
+
type: "select",
|
|
87
|
+
name: "action",
|
|
88
|
+
message: "What would you like to do?",
|
|
89
|
+
choices: [
|
|
90
|
+
{ title: "Add new playbook", value: "add" },
|
|
91
|
+
{ title: "List all playbooks", value: "list" },
|
|
92
|
+
{ title: "Search playbooks", value: "search" },
|
|
93
|
+
{ title: "Use playbook in generation", value: "use" },
|
|
94
|
+
{ title: "Create from template", value: "template" },
|
|
95
|
+
{ title: "Remove playbook", value: "remove" },
|
|
96
|
+
],
|
|
97
|
+
});
|
|
98
|
+
if (!response.action) {
|
|
99
|
+
console.log(chalk_1.default.yellow("Operation cancelled."));
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
switch (response.action) {
|
|
103
|
+
case "add":
|
|
104
|
+
const title = await (0, prompts_1.default)({
|
|
105
|
+
type: "text",
|
|
106
|
+
name: "title",
|
|
107
|
+
message: "Playbook title:",
|
|
108
|
+
validate: (value) => value.length > 0 || "Title is required",
|
|
109
|
+
});
|
|
110
|
+
if (title.title) {
|
|
111
|
+
await this.addPlaybook(title.title);
|
|
112
|
+
}
|
|
113
|
+
break;
|
|
114
|
+
case "list":
|
|
115
|
+
await this.listPlaybooks();
|
|
116
|
+
break;
|
|
117
|
+
case "search":
|
|
118
|
+
const searchTerm = await (0, prompts_1.default)({
|
|
119
|
+
type: "text",
|
|
120
|
+
name: "term",
|
|
121
|
+
message: "Search term:",
|
|
122
|
+
});
|
|
123
|
+
if (searchTerm.term) {
|
|
124
|
+
await this.searchPlaybooks(searchTerm.term);
|
|
125
|
+
}
|
|
126
|
+
break;
|
|
127
|
+
case "use":
|
|
128
|
+
const playbookId = await (0, prompts_1.default)({
|
|
129
|
+
type: "text",
|
|
130
|
+
name: "id",
|
|
131
|
+
message: "Playbook ID to use:",
|
|
132
|
+
});
|
|
133
|
+
if (playbookId.id) {
|
|
134
|
+
await this.usePlaybook(playbookId.id);
|
|
135
|
+
}
|
|
136
|
+
break;
|
|
137
|
+
case "template":
|
|
138
|
+
await this.showTemplates();
|
|
139
|
+
break;
|
|
140
|
+
case "remove":
|
|
141
|
+
const removeId = await (0, prompts_1.default)({
|
|
142
|
+
type: "text",
|
|
143
|
+
name: "id",
|
|
144
|
+
message: "Playbook ID to remove:",
|
|
145
|
+
});
|
|
146
|
+
if (removeId.id) {
|
|
147
|
+
await this.removePlaybook(removeId.id);
|
|
148
|
+
}
|
|
149
|
+
break;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
async addPlaybook(title, category) {
|
|
153
|
+
console.log(chalk_1.default.blue(`\n📝 Adding playbook: ${title}`));
|
|
154
|
+
const id = this.generateId(title);
|
|
155
|
+
const playbookPath = path.join(this.playbooksDir, `${id}.md`);
|
|
156
|
+
// Check if playbook already exists
|
|
157
|
+
if (await fs.pathExists(playbookPath)) {
|
|
158
|
+
console.log(chalk_1.default.yellow(`⚠️ Playbook with ID '${id}' already exists`));
|
|
159
|
+
const overwrite = await (0, prompts_1.default)({
|
|
160
|
+
type: "confirm",
|
|
161
|
+
name: "value",
|
|
162
|
+
message: "Overwrite existing playbook?",
|
|
163
|
+
initial: false,
|
|
164
|
+
});
|
|
165
|
+
if (!overwrite.value) {
|
|
166
|
+
console.log(chalk_1.default.yellow("Operation cancelled."));
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
// Get playbook details
|
|
171
|
+
const details = await (0, prompts_1.default)([
|
|
172
|
+
{
|
|
173
|
+
type: "text",
|
|
174
|
+
name: "description",
|
|
175
|
+
message: "Description:",
|
|
176
|
+
validate: (value) => value.length > 0 || "Description is required",
|
|
177
|
+
},
|
|
178
|
+
{
|
|
179
|
+
type: "select",
|
|
180
|
+
name: "category",
|
|
181
|
+
message: "Category:",
|
|
182
|
+
choices: [
|
|
183
|
+
{ title: "Payment Integration", value: "payment" },
|
|
184
|
+
{ title: "Authentication", value: "auth" },
|
|
185
|
+
{ title: "Database", value: "database" },
|
|
186
|
+
{ title: "API Integration", value: "api" },
|
|
187
|
+
{ title: "UI/UX", value: "ui" },
|
|
188
|
+
{ title: "DevOps", value: "devops" },
|
|
189
|
+
{ title: "Security", value: "security" },
|
|
190
|
+
{ title: "Testing", value: "testing" },
|
|
191
|
+
{ title: "Other", value: "other" },
|
|
192
|
+
],
|
|
193
|
+
initial: category ? this.getCategoryIndex(category) : 0,
|
|
194
|
+
},
|
|
195
|
+
{
|
|
196
|
+
type: "text",
|
|
197
|
+
name: "tags",
|
|
198
|
+
message: "Tags (comma-separated):",
|
|
199
|
+
initial: "",
|
|
200
|
+
},
|
|
201
|
+
{
|
|
202
|
+
type: "select",
|
|
203
|
+
name: "difficulty",
|
|
204
|
+
message: "Difficulty level:",
|
|
205
|
+
choices: [
|
|
206
|
+
{ title: "Beginner", value: "beginner" },
|
|
207
|
+
{ title: "Intermediate", value: "intermediate" },
|
|
208
|
+
{ title: "Advanced", value: "advanced" },
|
|
209
|
+
],
|
|
210
|
+
},
|
|
211
|
+
{
|
|
212
|
+
type: "text",
|
|
213
|
+
name: "estimatedTime",
|
|
214
|
+
message: "Estimated time to implement:",
|
|
215
|
+
initial: "1-2 hours",
|
|
216
|
+
},
|
|
217
|
+
]);
|
|
218
|
+
// Get content
|
|
219
|
+
console.log(chalk_1.default.yellow("\n📝 Enter playbook content (markdown):"));
|
|
220
|
+
console.log(chalk_1.default.gray("Press Ctrl+D when finished"));
|
|
221
|
+
const content = await this.getMultilineInput();
|
|
222
|
+
// Create playbook object
|
|
223
|
+
const playbook = {
|
|
224
|
+
id,
|
|
225
|
+
title,
|
|
226
|
+
description: details.description,
|
|
227
|
+
category: details.category,
|
|
228
|
+
tags: details.tags
|
|
229
|
+
? details.tags.split(",").map((t) => t.trim())
|
|
230
|
+
: [],
|
|
231
|
+
author: "User",
|
|
232
|
+
version: "1.0.0",
|
|
233
|
+
createdAt: new Date().toISOString(),
|
|
234
|
+
updatedAt: new Date().toISOString(),
|
|
235
|
+
content,
|
|
236
|
+
metadata: {
|
|
237
|
+
difficulty: details.difficulty,
|
|
238
|
+
estimatedTime: details.estimatedTime,
|
|
239
|
+
prerequisites: [],
|
|
240
|
+
relatedPlaybooks: [],
|
|
241
|
+
},
|
|
242
|
+
};
|
|
243
|
+
// Save playbook
|
|
244
|
+
await this.savePlaybook(playbook);
|
|
245
|
+
console.log(chalk_1.default.green(`✅ Playbook '${title}' created successfully!`));
|
|
246
|
+
console.log(chalk_1.default.gray(` ID: ${id}`));
|
|
247
|
+
console.log(chalk_1.default.gray(` Category: ${details.category}`));
|
|
248
|
+
console.log(chalk_1.default.gray(` File: ${playbookPath}`));
|
|
249
|
+
}
|
|
250
|
+
async listPlaybooks() {
|
|
251
|
+
console.log(chalk_1.default.blue("\n📚 Available Playbooks"));
|
|
252
|
+
const playbooks = await this.getAllPlaybooks();
|
|
253
|
+
if (playbooks.length === 0) {
|
|
254
|
+
console.log(chalk_1.default.yellow("No playbooks found. Create one with 'mycontext playbooks add'"));
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
257
|
+
// Group by category
|
|
258
|
+
const grouped = playbooks.reduce((acc, playbook) => {
|
|
259
|
+
if (!acc[playbook.category]) {
|
|
260
|
+
acc[playbook.category] = [];
|
|
261
|
+
}
|
|
262
|
+
acc[playbook.category].push(playbook);
|
|
263
|
+
return acc;
|
|
264
|
+
}, {});
|
|
265
|
+
Object.entries(grouped).forEach(([category, categoryPlaybooks]) => {
|
|
266
|
+
console.log(chalk_1.default.cyan(`\n📁 ${category.toUpperCase()}`));
|
|
267
|
+
categoryPlaybooks.forEach((playbook) => {
|
|
268
|
+
console.log(chalk_1.default.gray(` ${playbook.id}`));
|
|
269
|
+
console.log(chalk_1.default.white(` ${playbook.title}`));
|
|
270
|
+
console.log(chalk_1.default.gray(` ${playbook.description}`));
|
|
271
|
+
console.log(chalk_1.default.gray(` Difficulty: ${playbook.metadata.difficulty} | Time: ${playbook.metadata.estimatedTime}`));
|
|
272
|
+
if (playbook.tags.length > 0) {
|
|
273
|
+
console.log(chalk_1.default.gray(` Tags: ${playbook.tags.join(", ")}`));
|
|
274
|
+
}
|
|
275
|
+
console.log();
|
|
276
|
+
});
|
|
277
|
+
});
|
|
278
|
+
}
|
|
279
|
+
async searchPlaybooks(term) {
|
|
280
|
+
console.log(chalk_1.default.blue(`\n🔍 Searching for: "${term}"`));
|
|
281
|
+
const playbooks = await this.getAllPlaybooks();
|
|
282
|
+
const results = playbooks.filter((playbook) => playbook.title.toLowerCase().includes(term.toLowerCase()) ||
|
|
283
|
+
playbook.description.toLowerCase().includes(term.toLowerCase()) ||
|
|
284
|
+
playbook.content.toLowerCase().includes(term.toLowerCase()) ||
|
|
285
|
+
playbook.tags.some((tag) => tag.toLowerCase().includes(term.toLowerCase())));
|
|
286
|
+
if (results.length === 0) {
|
|
287
|
+
console.log(chalk_1.default.yellow("No playbooks found matching your search."));
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
290
|
+
console.log(chalk_1.default.green(`Found ${results.length} playbook(s):`));
|
|
291
|
+
results.forEach((playbook) => {
|
|
292
|
+
console.log(chalk_1.default.gray(`\n${playbook.id}`));
|
|
293
|
+
console.log(chalk_1.default.white(` ${playbook.title}`));
|
|
294
|
+
console.log(chalk_1.default.gray(` ${playbook.description}`));
|
|
295
|
+
console.log(chalk_1.default.gray(` Category: ${playbook.category} | Difficulty: ${playbook.metadata.difficulty}`));
|
|
296
|
+
});
|
|
297
|
+
}
|
|
298
|
+
async usePlaybook(playbookId) {
|
|
299
|
+
console.log(chalk_1.default.blue(`\n🎯 Using playbook: ${playbookId}`));
|
|
300
|
+
const playbook = await this.getPlaybook(playbookId);
|
|
301
|
+
if (!playbook) {
|
|
302
|
+
console.log(chalk_1.default.red(`❌ Playbook '${playbookId}' not found`));
|
|
303
|
+
return;
|
|
304
|
+
}
|
|
305
|
+
console.log(chalk_1.default.green(`✅ Loaded playbook: ${playbook.title}`));
|
|
306
|
+
console.log(chalk_1.default.gray(` Category: ${playbook.category}`));
|
|
307
|
+
console.log(chalk_1.default.gray(` Difficulty: ${playbook.metadata.difficulty}`));
|
|
308
|
+
console.log(chalk_1.default.gray(` Estimated time: ${playbook.metadata.estimatedTime}`));
|
|
309
|
+
// Save to context for AI generation
|
|
310
|
+
const contextPath = path.join(process.cwd(), ".mycontext", "active-playbook.json");
|
|
311
|
+
await fs.writeJson(contextPath, {
|
|
312
|
+
id: playbook.id,
|
|
313
|
+
title: playbook.title,
|
|
314
|
+
content: playbook.content,
|
|
315
|
+
metadata: playbook.metadata,
|
|
316
|
+
usedAt: new Date().toISOString(),
|
|
317
|
+
}, { spaces: 2 });
|
|
318
|
+
console.log(chalk_1.default.green(`\n🎯 Playbook context saved to .mycontext/active-playbook.json`));
|
|
319
|
+
console.log(chalk_1.default.gray("This playbook will be used in your next AI generation."));
|
|
320
|
+
}
|
|
321
|
+
async removePlaybook(playbookId) {
|
|
322
|
+
console.log(chalk_1.default.blue(`\n🗑️ Removing playbook: ${playbookId}`));
|
|
323
|
+
const playbookPath = path.join(this.playbooksDir, `${playbookId}.md`);
|
|
324
|
+
if (!(await fs.pathExists(playbookPath))) {
|
|
325
|
+
console.log(chalk_1.default.red(`❌ Playbook '${playbookId}' not found`));
|
|
326
|
+
return;
|
|
327
|
+
}
|
|
328
|
+
const confirm = await (0, prompts_1.default)({
|
|
329
|
+
type: "confirm",
|
|
330
|
+
name: "value",
|
|
331
|
+
message: `Are you sure you want to remove playbook '${playbookId}'?`,
|
|
332
|
+
initial: false,
|
|
333
|
+
});
|
|
334
|
+
if (confirm.value) {
|
|
335
|
+
await fs.remove(playbookPath);
|
|
336
|
+
console.log(chalk_1.default.green(`✅ Playbook '${playbookId}' removed successfully`));
|
|
337
|
+
}
|
|
338
|
+
else {
|
|
339
|
+
console.log(chalk_1.default.yellow("Operation cancelled."));
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
async showTemplates() {
|
|
343
|
+
console.log(chalk_1.default.blue("\n📋 Available Templates"));
|
|
344
|
+
const templates = [
|
|
345
|
+
{
|
|
346
|
+
id: "mpesa-integration",
|
|
347
|
+
title: "M-Pesa Integration",
|
|
348
|
+
description: "Complete M-Pesa STK Push and C2B integration for Next.js",
|
|
349
|
+
category: "payment",
|
|
350
|
+
},
|
|
351
|
+
{
|
|
352
|
+
id: "stripe-integration",
|
|
353
|
+
title: "Stripe Payment Integration",
|
|
354
|
+
description: "Stripe payment processing with webhooks and subscriptions",
|
|
355
|
+
category: "payment",
|
|
356
|
+
},
|
|
357
|
+
{
|
|
358
|
+
id: "auth-nextjs",
|
|
359
|
+
title: "Next.js Authentication",
|
|
360
|
+
description: "Complete authentication system with NextAuth.js",
|
|
361
|
+
category: "auth",
|
|
362
|
+
},
|
|
363
|
+
{
|
|
364
|
+
id: "database-supabase",
|
|
365
|
+
title: "Supabase Database Setup",
|
|
366
|
+
description: "Database schema design and API integration with Supabase",
|
|
367
|
+
category: "database",
|
|
368
|
+
},
|
|
369
|
+
{
|
|
370
|
+
id: "api-rest",
|
|
371
|
+
title: "REST API Design",
|
|
372
|
+
description: "RESTful API design patterns and best practices",
|
|
373
|
+
category: "api",
|
|
374
|
+
},
|
|
375
|
+
];
|
|
376
|
+
templates.forEach((template) => {
|
|
377
|
+
console.log(chalk_1.default.gray(`\n${template.id}`));
|
|
378
|
+
console.log(chalk_1.default.white(` ${template.title}`));
|
|
379
|
+
console.log(chalk_1.default.gray(` ${template.description}`));
|
|
380
|
+
console.log(chalk_1.default.gray(` Category: ${template.category}`));
|
|
381
|
+
});
|
|
382
|
+
const response = await (0, prompts_1.default)({
|
|
383
|
+
type: "text",
|
|
384
|
+
name: "templateId",
|
|
385
|
+
message: "Enter template ID to create playbook:",
|
|
386
|
+
});
|
|
387
|
+
if (response.templateId) {
|
|
388
|
+
await this.createFromTemplate(response.templateId);
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
async createFromTemplate(templateId) {
|
|
392
|
+
console.log(chalk_1.default.blue(`\n📋 Creating playbook from template: ${templateId}`));
|
|
393
|
+
// This would load from a templates directory
|
|
394
|
+
// For now, we'll create a basic template
|
|
395
|
+
const templateContent = this.getTemplateContent(templateId);
|
|
396
|
+
if (!templateContent) {
|
|
397
|
+
console.log(chalk_1.default.red(`❌ Template '${templateId}' not found`));
|
|
398
|
+
return;
|
|
399
|
+
}
|
|
400
|
+
const title = await (0, prompts_1.default)({
|
|
401
|
+
type: "text",
|
|
402
|
+
name: "value",
|
|
403
|
+
message: "Playbook title:",
|
|
404
|
+
initial: templateContent.title,
|
|
405
|
+
});
|
|
406
|
+
if (title.value) {
|
|
407
|
+
await this.addPlaybook(title.value, templateContent.category);
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
async getAllPlaybooks() {
|
|
411
|
+
const files = glob.sync("*.md", { cwd: this.playbooksDir });
|
|
412
|
+
const playbooks = [];
|
|
413
|
+
for (const file of files) {
|
|
414
|
+
const playbook = await this.getPlaybook(path.basename(file, ".md"));
|
|
415
|
+
if (playbook) {
|
|
416
|
+
playbooks.push(playbook);
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
return playbooks.sort((a, b) => b.updatedAt.localeCompare(a.updatedAt));
|
|
420
|
+
}
|
|
421
|
+
async getPlaybook(id) {
|
|
422
|
+
try {
|
|
423
|
+
const playbookPath = path.join(this.playbooksDir, `${id}.md`);
|
|
424
|
+
const content = await fs.readFile(playbookPath, "utf-8");
|
|
425
|
+
// Parse frontmatter and content
|
|
426
|
+
const { frontmatter, content: body } = this.parseMarkdown(content);
|
|
427
|
+
return {
|
|
428
|
+
id,
|
|
429
|
+
title: frontmatter.title || id,
|
|
430
|
+
description: frontmatter.description || "",
|
|
431
|
+
category: frontmatter.category || "other",
|
|
432
|
+
tags: frontmatter.tags || [],
|
|
433
|
+
author: frontmatter.author || "User",
|
|
434
|
+
version: frontmatter.version || "1.0.0",
|
|
435
|
+
createdAt: frontmatter.createdAt || new Date().toISOString(),
|
|
436
|
+
updatedAt: frontmatter.updatedAt || new Date().toISOString(),
|
|
437
|
+
content: body,
|
|
438
|
+
metadata: {
|
|
439
|
+
difficulty: frontmatter.difficulty || "beginner",
|
|
440
|
+
estimatedTime: frontmatter.estimatedTime || "1-2 hours",
|
|
441
|
+
prerequisites: frontmatter.prerequisites || [],
|
|
442
|
+
relatedPlaybooks: frontmatter.relatedPlaybooks || [],
|
|
443
|
+
},
|
|
444
|
+
};
|
|
445
|
+
}
|
|
446
|
+
catch (error) {
|
|
447
|
+
return null;
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
async savePlaybook(playbook) {
|
|
451
|
+
const frontmatter = `---
|
|
452
|
+
id: ${playbook.id}
|
|
453
|
+
title: ${playbook.title}
|
|
454
|
+
description: ${playbook.description}
|
|
455
|
+
category: ${playbook.category}
|
|
456
|
+
tags: [${playbook.tags.map((t) => `"${t}"`).join(", ")}]
|
|
457
|
+
author: ${playbook.author}
|
|
458
|
+
version: ${playbook.version}
|
|
459
|
+
createdAt: ${playbook.createdAt}
|
|
460
|
+
updatedAt: ${playbook.updatedAt}
|
|
461
|
+
difficulty: ${playbook.metadata.difficulty}
|
|
462
|
+
estimatedTime: ${playbook.metadata.estimatedTime}
|
|
463
|
+
prerequisites: [${playbook.metadata.prerequisites
|
|
464
|
+
.map((p) => `"${p}"`)
|
|
465
|
+
.join(", ")}]
|
|
466
|
+
relatedPlaybooks: [${playbook.metadata.relatedPlaybooks
|
|
467
|
+
.map((r) => `"${r}"`)
|
|
468
|
+
.join(", ")}]
|
|
469
|
+
---
|
|
470
|
+
|
|
471
|
+
${playbook.content}`;
|
|
472
|
+
const playbookPath = path.join(this.playbooksDir, `${playbook.id}.md`);
|
|
473
|
+
await fs.writeFile(playbookPath, frontmatter);
|
|
474
|
+
}
|
|
475
|
+
parseMarkdown(content) {
|
|
476
|
+
const frontmatterRegex = /^---\n([\s\S]*?)\n---\n([\s\S]*)$/;
|
|
477
|
+
const match = content.match(frontmatterRegex);
|
|
478
|
+
if (!match) {
|
|
479
|
+
return { frontmatter: {}, content };
|
|
480
|
+
}
|
|
481
|
+
const frontmatterText = match[1];
|
|
482
|
+
const body = match[2];
|
|
483
|
+
const frontmatter = {};
|
|
484
|
+
frontmatterText.split("\n").forEach((line) => {
|
|
485
|
+
const [key, ...valueParts] = line.split(":");
|
|
486
|
+
if (key && valueParts.length > 0) {
|
|
487
|
+
const value = valueParts.join(":").trim();
|
|
488
|
+
if (value.startsWith("[") && value.endsWith("]")) {
|
|
489
|
+
frontmatter[key.trim()] = JSON.parse(value);
|
|
490
|
+
}
|
|
491
|
+
else if (value.startsWith('"') && value.endsWith('"')) {
|
|
492
|
+
frontmatter[key.trim()] = value.slice(1, -1);
|
|
493
|
+
}
|
|
494
|
+
else {
|
|
495
|
+
frontmatter[key.trim()] = value;
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
});
|
|
499
|
+
return { frontmatter, content: body };
|
|
500
|
+
}
|
|
501
|
+
generateId(title) {
|
|
502
|
+
return title
|
|
503
|
+
.toLowerCase()
|
|
504
|
+
.replace(/[^a-z0-9\s-]/g, "")
|
|
505
|
+
.replace(/\s+/g, "-")
|
|
506
|
+
.replace(/-+/g, "-")
|
|
507
|
+
.replace(/^-|-$/g, "");
|
|
508
|
+
}
|
|
509
|
+
getCategoryIndex(category) {
|
|
510
|
+
const categories = [
|
|
511
|
+
"payment",
|
|
512
|
+
"auth",
|
|
513
|
+
"database",
|
|
514
|
+
"api",
|
|
515
|
+
"ui",
|
|
516
|
+
"devops",
|
|
517
|
+
"security",
|
|
518
|
+
"testing",
|
|
519
|
+
"other",
|
|
520
|
+
];
|
|
521
|
+
return categories.indexOf(category);
|
|
522
|
+
}
|
|
523
|
+
async getMultilineInput() {
|
|
524
|
+
// This is a simplified version - in a real implementation,
|
|
525
|
+
// you'd want to use a proper multiline input method
|
|
526
|
+
const response = await (0, prompts_1.default)({
|
|
527
|
+
type: "text",
|
|
528
|
+
name: "content",
|
|
529
|
+
message: "Enter playbook content:",
|
|
530
|
+
});
|
|
531
|
+
return response.content || "";
|
|
532
|
+
}
|
|
533
|
+
getTemplateContent(templateId) {
|
|
534
|
+
const templates = {
|
|
535
|
+
"mpesa-integration": {
|
|
536
|
+
title: "M-Pesa Integration",
|
|
537
|
+
category: "payment",
|
|
538
|
+
content: `# M-Pesa Integration Guide
|
|
539
|
+
|
|
540
|
+
## Overview
|
|
541
|
+
Complete M-Pesa STK Push and C2B integration for Next.js applications.
|
|
542
|
+
|
|
543
|
+
## Prerequisites
|
|
544
|
+
- Safaricom Daraja API credentials
|
|
545
|
+
- Next.js application
|
|
546
|
+
- Database (Supabase/PostgreSQL)
|
|
547
|
+
|
|
548
|
+
## Implementation Steps
|
|
549
|
+
|
|
550
|
+
### 1. Environment Setup
|
|
551
|
+
\`\`\`bash
|
|
552
|
+
# Required environment variables
|
|
553
|
+
MPESA_CONSUMER_KEY=your_consumer_key
|
|
554
|
+
MPESA_CONSUMER_SECRET=your_consumer_secret
|
|
555
|
+
MPESA_BUSINESS_SHORT_CODE=your_shortcode
|
|
556
|
+
MPESA_PASSKEY=your_passkey
|
|
557
|
+
MPESA_CALLBACK_URL=https://your-domain.com/api/payment-callback
|
|
558
|
+
\`\`\`
|
|
559
|
+
|
|
560
|
+
### 2. Database Schema
|
|
561
|
+
\`\`\`sql
|
|
562
|
+
CREATE TABLE mpesa_transactions (
|
|
563
|
+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
564
|
+
checkout_request_id VARCHAR(255),
|
|
565
|
+
order_id UUID REFERENCES orders(id),
|
|
566
|
+
phone_number VARCHAR(20),
|
|
567
|
+
amount DECIMAL(10,2) NOT NULL,
|
|
568
|
+
status VARCHAR(50) DEFAULT 'pending',
|
|
569
|
+
mpesa_receipt_number VARCHAR(255),
|
|
570
|
+
created_at TIMESTAMP DEFAULT NOW()
|
|
571
|
+
);
|
|
572
|
+
\`\`\`
|
|
573
|
+
|
|
574
|
+
### 3. STK Push Implementation
|
|
575
|
+
\`\`\`typescript
|
|
576
|
+
// app/api/payment/stk/route.ts
|
|
577
|
+
export async function POST(request: NextRequest) {
|
|
578
|
+
const { orderId, phoneNumber, amount } = await request.json();
|
|
579
|
+
|
|
580
|
+
// Generate password
|
|
581
|
+
const password = Buffer.from(
|
|
582
|
+
\`\${businessShortCode}\${passkey}\${timestamp}\`
|
|
583
|
+
).toString('base64');
|
|
584
|
+
|
|
585
|
+
// STK Push payload
|
|
586
|
+
const stkPushPayload = {
|
|
587
|
+
BusinessShortCode: businessShortCode,
|
|
588
|
+
Password: password,
|
|
589
|
+
Timestamp: timestamp,
|
|
590
|
+
TransactionType: "CustomerPayBillOnline",
|
|
591
|
+
Amount: Math.round(amount),
|
|
592
|
+
PartyA: phoneNumber.replace("+", ""),
|
|
593
|
+
PartyB: businessShortCode,
|
|
594
|
+
PhoneNumber: phoneNumber.replace("+", ""),
|
|
595
|
+
CallBackURL: callbackUrl,
|
|
596
|
+
AccountReference: \`ORDER-\${orderId}\`,
|
|
597
|
+
TransactionDesc: "Payment",
|
|
598
|
+
};
|
|
599
|
+
|
|
600
|
+
// Make API call to M-Pesa
|
|
601
|
+
const response = await fetch(
|
|
602
|
+
\`https://sandbox.safaricom.co.ke/mpesa/stkpush/v1/processrequest\`,
|
|
603
|
+
{
|
|
604
|
+
method: "POST",
|
|
605
|
+
headers: {
|
|
606
|
+
"Authorization": \`Bearer \${accessToken}\`,
|
|
607
|
+
"Content-Type": "application/json",
|
|
608
|
+
},
|
|
609
|
+
body: JSON.stringify(stkPushPayload),
|
|
610
|
+
}
|
|
611
|
+
);
|
|
612
|
+
|
|
613
|
+
return NextResponse.json(await response.json());
|
|
614
|
+
}
|
|
615
|
+
\`\`\`
|
|
616
|
+
|
|
617
|
+
### 4. Callback Processing
|
|
618
|
+
\`\`\`typescript
|
|
619
|
+
// app/api/payment-callback/route.ts
|
|
620
|
+
export async function POST(request: NextRequest) {
|
|
621
|
+
const body = await request.json();
|
|
622
|
+
const stkCallback = body.Body?.stkCallback || body.stkCallback;
|
|
623
|
+
|
|
624
|
+
if (stkCallback.ResultCode === 0) {
|
|
625
|
+
// Payment successful
|
|
626
|
+
const amount = getMetadataValue("Amount");
|
|
627
|
+
const mpesaReceiptNumber = getMetadataValue("MpesaReceiptNumber");
|
|
628
|
+
|
|
629
|
+
// Update database
|
|
630
|
+
await supabase
|
|
631
|
+
.from("mpesa_transactions")
|
|
632
|
+
.update({
|
|
633
|
+
mpesa_receipt_number: mpesaReceiptNumber,
|
|
634
|
+
status: "completed",
|
|
635
|
+
actual_amount: amount,
|
|
636
|
+
})
|
|
637
|
+
.eq("checkout_request_id", stkCallback.CheckoutRequestID);
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
return NextResponse.json({ ResultCode: 0, ResultDesc: "Success" });
|
|
641
|
+
}
|
|
642
|
+
\`\`\`
|
|
643
|
+
|
|
644
|
+
## Best Practices
|
|
645
|
+
- Always validate phone numbers
|
|
646
|
+
- Implement proper error handling
|
|
647
|
+
- Use HTTPS for all endpoints
|
|
648
|
+
- Log all transactions
|
|
649
|
+
- Implement idempotency checks
|
|
650
|
+
|
|
651
|
+
## Common Issues
|
|
652
|
+
- STK Push timeout: Check network connectivity
|
|
653
|
+
- Invalid credentials: Verify API keys
|
|
654
|
+
- Callback not received: Check URL accessibility
|
|
655
|
+
`,
|
|
656
|
+
},
|
|
657
|
+
};
|
|
658
|
+
return templates[templateId];
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
exports.PlaybooksCommand = PlaybooksCommand;
|
|
662
|
+
//# sourceMappingURL=playbooks.js.map
|