mycontext-cli 0.4.19 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (98) hide show
  1. package/README.md +14 -11
  2. package/dist/agents/implementations/BackendDevAgent.d.ts +39 -0
  3. package/dist/agents/implementations/BackendDevAgent.d.ts.map +1 -0
  4. package/dist/agents/implementations/BackendDevAgent.js +821 -0
  5. package/dist/agents/implementations/BackendDevAgent.js.map +1 -0
  6. package/dist/agents/implementations/CodeGenSubAgent.d.ts +1 -1
  7. package/dist/agents/implementations/CodeGenSubAgent.d.ts.map +1 -1
  8. package/dist/agents/implementations/CodeGenSubAgent.js +34 -22
  9. package/dist/agents/implementations/CodeGenSubAgent.js.map +1 -1
  10. package/dist/agents/implementations/DocsSubAgent.d.ts +7 -0
  11. package/dist/agents/implementations/DocsSubAgent.d.ts.map +1 -1
  12. package/dist/agents/implementations/DocsSubAgent.js +20 -11
  13. package/dist/agents/implementations/DocsSubAgent.js.map +1 -1
  14. package/dist/agents/implementations/EnhancementAgent.d.ts +1 -1
  15. package/dist/agents/implementations/EnhancementAgent.d.ts.map +1 -1
  16. package/dist/agents/implementations/EnhancementAgent.js +17 -12
  17. package/dist/agents/implementations/EnhancementAgent.js.map +1 -1
  18. package/dist/cli.js +191 -39
  19. package/dist/cli.js.map +1 -1
  20. package/dist/commands/analyze.d.ts +52 -0
  21. package/dist/commands/analyze.d.ts.map +1 -0
  22. package/dist/commands/analyze.js +740 -0
  23. package/dist/commands/analyze.js.map +1 -0
  24. package/dist/commands/auth.d.ts +19 -26
  25. package/dist/commands/auth.d.ts.map +1 -1
  26. package/dist/commands/auth.js +187 -180
  27. package/dist/commands/auth.js.map +1 -1
  28. package/dist/commands/build-app.d.ts +33 -0
  29. package/dist/commands/build-app.d.ts.map +1 -0
  30. package/dist/commands/build-app.js +507 -0
  31. package/dist/commands/build-app.js.map +1 -0
  32. package/dist/commands/generate-components.d.ts +2 -0
  33. package/dist/commands/generate-components.d.ts.map +1 -1
  34. package/dist/commands/generate-components.js +95 -49
  35. package/dist/commands/generate-components.js.map +1 -1
  36. package/dist/commands/generate.d.ts +3 -0
  37. package/dist/commands/generate.d.ts.map +1 -1
  38. package/dist/commands/generate.js +250 -93
  39. package/dist/commands/generate.js.map +1 -1
  40. package/dist/commands/init.d.ts +5 -0
  41. package/dist/commands/init.d.ts.map +1 -1
  42. package/dist/commands/init.js +86 -7
  43. package/dist/commands/init.js.map +1 -1
  44. package/dist/commands/list.d.ts.map +1 -1
  45. package/dist/commands/list.js +10 -7
  46. package/dist/commands/list.js.map +1 -1
  47. package/dist/commands/migrate.d.ts +29 -0
  48. package/dist/commands/migrate.d.ts.map +1 -0
  49. package/dist/commands/migrate.js +485 -0
  50. package/dist/commands/migrate.js.map +1 -0
  51. package/dist/commands/model.d.ts +13 -16
  52. package/dist/commands/model.d.ts.map +1 -1
  53. package/dist/commands/model.js +86 -320
  54. package/dist/commands/model.js.map +1 -1
  55. package/dist/commands/playbooks.d.ts +33 -0
  56. package/dist/commands/playbooks.d.ts.map +1 -0
  57. package/dist/commands/playbooks.js +662 -0
  58. package/dist/commands/playbooks.js.map +1 -0
  59. package/dist/commands/pricing.d.ts +15 -0
  60. package/dist/commands/pricing.d.ts.map +1 -0
  61. package/dist/commands/pricing.js +129 -0
  62. package/dist/commands/pricing.js.map +1 -0
  63. package/dist/commands/promote.d.ts +22 -0
  64. package/dist/commands/promote.d.ts.map +1 -0
  65. package/dist/commands/promote.js +204 -0
  66. package/dist/commands/promote.js.map +1 -0
  67. package/dist/commands/setup.d.ts +5 -18
  68. package/dist/commands/setup.d.ts.map +1 -1
  69. package/dist/commands/setup.js +180 -340
  70. package/dist/commands/setup.js.map +1 -1
  71. package/dist/config/ai-providers.json +37 -28
  72. package/dist/config/api.d.ts +9 -0
  73. package/dist/config/api.d.ts.map +1 -0
  74. package/dist/config/api.js +25 -0
  75. package/dist/config/api.js.map +1 -0
  76. package/dist/config/api.ts +29 -0
  77. package/dist/config/pricing.json +55 -0
  78. package/dist/types/index.d.ts +1 -1
  79. package/dist/types/index.d.ts.map +1 -1
  80. package/dist/utils/apiKeyManager.d.ts.map +1 -1
  81. package/dist/utils/apiKeyManager.js +7 -0
  82. package/dist/utils/apiKeyManager.js.map +1 -1
  83. package/dist/utils/fileSystem.d.ts.map +1 -1
  84. package/dist/utils/fileSystem.js +3 -1
  85. package/dist/utils/fileSystem.js.map +1 -1
  86. package/dist/utils/hostedApiClient.d.ts +32 -0
  87. package/dist/utils/hostedApiClient.d.ts.map +1 -0
  88. package/dist/utils/hostedApiClient.js +231 -0
  89. package/dist/utils/hostedApiClient.js.map +1 -0
  90. package/dist/utils/hybridAIClient.d.ts +7 -3
  91. package/dist/utils/hybridAIClient.d.ts.map +1 -1
  92. package/dist/utils/hybridAIClient.js +103 -27
  93. package/dist/utils/hybridAIClient.js.map +1 -1
  94. package/dist/utils/qwenClient.d.ts +22 -0
  95. package/dist/utils/qwenClient.d.ts.map +1 -0
  96. package/dist/utils/qwenClient.js +180 -0
  97. package/dist/utils/qwenClient.js.map +1 -0
  98. 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