@magic-ingredients/tiny-brain-local 0.3.10

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 (111) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +81 -0
  3. package/dist/core/console-logger.d.ts +30 -0
  4. package/dist/core/console-logger.d.ts.map +1 -0
  5. package/dist/core/console-logger.js +101 -0
  6. package/dist/core/console-logger.js.map +1 -0
  7. package/dist/core/file-logger.d.ts +40 -0
  8. package/dist/core/file-logger.d.ts.map +1 -0
  9. package/dist/core/file-logger.js +223 -0
  10. package/dist/core/file-logger.js.map +1 -0
  11. package/dist/core/mcp-server.d.ts +54 -0
  12. package/dist/core/mcp-server.d.ts.map +1 -0
  13. package/dist/core/mcp-server.js +295 -0
  14. package/dist/core/mcp-server.js.map +1 -0
  15. package/dist/index.d.ts +8 -0
  16. package/dist/index.d.ts.map +1 -0
  17. package/dist/index.js +37 -0
  18. package/dist/index.js.map +1 -0
  19. package/dist/prompts/index.d.ts +39 -0
  20. package/dist/prompts/index.d.ts.map +1 -0
  21. package/dist/prompts/index.js +5 -0
  22. package/dist/prompts/index.js.map +1 -0
  23. package/dist/prompts/memory/memory.prompt.d.ts +32 -0
  24. package/dist/prompts/memory/memory.prompt.d.ts.map +1 -0
  25. package/dist/prompts/memory/memory.prompt.js +204 -0
  26. package/dist/prompts/memory/memory.prompt.js.map +1 -0
  27. package/dist/prompts/persona/persona.prompt.d.ts +27 -0
  28. package/dist/prompts/persona/persona.prompt.d.ts.map +1 -0
  29. package/dist/prompts/persona/persona.prompt.js +592 -0
  30. package/dist/prompts/persona/persona.prompt.js.map +1 -0
  31. package/dist/prompts/planning/planning.prompt.d.ts +56 -0
  32. package/dist/prompts/planning/planning.prompt.d.ts.map +1 -0
  33. package/dist/prompts/planning/planning.prompt.js +1016 -0
  34. package/dist/prompts/planning/planning.prompt.js.map +1 -0
  35. package/dist/prompts/prompt-registry.d.ts +25 -0
  36. package/dist/prompts/prompt-registry.d.ts.map +1 -0
  37. package/dist/prompts/prompt-registry.js +68 -0
  38. package/dist/prompts/prompt-registry.js.map +1 -0
  39. package/dist/prompts/thinking/thinking.prompt.d.ts +29 -0
  40. package/dist/prompts/thinking/thinking.prompt.d.ts.map +1 -0
  41. package/dist/prompts/thinking/thinking.prompt.js +171 -0
  42. package/dist/prompts/thinking/thinking.prompt.js.map +1 -0
  43. package/dist/services/UpdateService.d.ts +29 -0
  44. package/dist/services/UpdateService.d.ts.map +1 -0
  45. package/dist/services/UpdateService.js +132 -0
  46. package/dist/services/UpdateService.js.map +1 -0
  47. package/dist/services/plan-watcher.service.d.ts +143 -0
  48. package/dist/services/plan-watcher.service.d.ts.map +1 -0
  49. package/dist/services/plan-watcher.service.js +914 -0
  50. package/dist/services/plan-watcher.service.js.map +1 -0
  51. package/dist/storage/local-filesystem-adapter.d.ts +39 -0
  52. package/dist/storage/local-filesystem-adapter.d.ts.map +1 -0
  53. package/dist/storage/local-filesystem-adapter.js +208 -0
  54. package/dist/storage/local-filesystem-adapter.js.map +1 -0
  55. package/dist/storage/storage-path-builder.d.ts +14 -0
  56. package/dist/storage/storage-path-builder.d.ts.map +1 -0
  57. package/dist/storage/storage-path-builder.js +43 -0
  58. package/dist/storage/storage-path-builder.js.map +1 -0
  59. package/dist/test-setup.d.ts +2 -0
  60. package/dist/test-setup.d.ts.map +1 -0
  61. package/dist/test-setup.js +12 -0
  62. package/dist/test-setup.js.map +1 -0
  63. package/dist/tools/analyse-request/analyse-request.tool.d.ts +8 -0
  64. package/dist/tools/analyse-request/analyse-request.tool.d.ts.map +1 -0
  65. package/dist/tools/analyse-request/analyse-request.tool.js +120 -0
  66. package/dist/tools/analyse-request/analyse-request.tool.js.map +1 -0
  67. package/dist/tools/index.d.ts +69 -0
  68. package/dist/tools/index.d.ts.map +1 -0
  69. package/dist/tools/index.js +24 -0
  70. package/dist/tools/index.js.map +1 -0
  71. package/dist/tools/memory/memory.tool.d.ts +15 -0
  72. package/dist/tools/memory/memory.tool.d.ts.map +1 -0
  73. package/dist/tools/memory/memory.tool.js +110 -0
  74. package/dist/tools/memory/memory.tool.js.map +1 -0
  75. package/dist/tools/persona/as.tool.d.ts +25 -0
  76. package/dist/tools/persona/as.tool.d.ts.map +1 -0
  77. package/dist/tools/persona/as.tool.js +294 -0
  78. package/dist/tools/persona/as.tool.js.map +1 -0
  79. package/dist/tools/persona/persona.tool.d.ts +8 -0
  80. package/dist/tools/persona/persona.tool.d.ts.map +1 -0
  81. package/dist/tools/persona/persona.tool.js +193 -0
  82. package/dist/tools/persona/persona.tool.js.map +1 -0
  83. package/dist/tools/plan/plan.tool.d.ts +18 -0
  84. package/dist/tools/plan/plan.tool.d.ts.map +1 -0
  85. package/dist/tools/plan/plan.tool.js +643 -0
  86. package/dist/tools/plan/plan.tool.js.map +1 -0
  87. package/dist/tools/strategy/strategy.tool.d.ts +13 -0
  88. package/dist/tools/strategy/strategy.tool.d.ts.map +1 -0
  89. package/dist/tools/strategy/strategy.tool.js +199 -0
  90. package/dist/tools/strategy/strategy.tool.js.map +1 -0
  91. package/dist/tools/thinking/thinking.tool.d.ts +13 -0
  92. package/dist/tools/thinking/thinking.tool.d.ts.map +1 -0
  93. package/dist/tools/thinking/thinking.tool.js +226 -0
  94. package/dist/tools/thinking/thinking.tool.js.map +1 -0
  95. package/dist/tools/tool-registry.d.ts +20 -0
  96. package/dist/tools/tool-registry.d.ts.map +1 -0
  97. package/dist/tools/tool-registry.js +61 -0
  98. package/dist/tools/tool-registry.js.map +1 -0
  99. package/dist/tools/update/update.tool.d.ts +15 -0
  100. package/dist/tools/update/update.tool.d.ts.map +1 -0
  101. package/dist/tools/update/update.tool.js +86 -0
  102. package/dist/tools/update/update.tool.js.map +1 -0
  103. package/dist/tools/validate-response/validate-response.tool.d.ts +13 -0
  104. package/dist/tools/validate-response/validate-response.tool.d.ts.map +1 -0
  105. package/dist/tools/validate-response/validate-response.tool.js +142 -0
  106. package/dist/tools/validate-response/validate-response.tool.js.map +1 -0
  107. package/dist/types/request-context.d.ts +7 -0
  108. package/dist/types/request-context.d.ts.map +1 -0
  109. package/dist/types/request-context.js +7 -0
  110. package/dist/types/request-context.js.map +1 -0
  111. package/package.json +77 -0
@@ -0,0 +1,1016 @@
1
+ /**
2
+ * Planning Prompt Handler
3
+ *
4
+ * Thin dispatcher for planning-related prompt executions
5
+ * Validates args with Zod, dispatches to PlanningService, formats responses
6
+ */
7
+ import { z } from 'zod';
8
+ import { PlanningService } from '@magic-ingredients/tiny-brain-core';
9
+ // Zod schemas for each prompt handler
10
+ const CreatePlanArgsSchema = z.object({
11
+ title: z.string(),
12
+ overview: z.string(),
13
+ phases: z.string().optional(),
14
+ });
15
+ const UpdatePlanArgsSchema = z.object({
16
+ planId: z.string().optional(),
17
+ operation: z.enum(['add-phase', 'update-phase-status', 'add-todo', 'complete-todo']),
18
+ phaseNumber: z.number().optional(),
19
+ content: z.string().optional(),
20
+ status: z.enum(['pending', 'in_progress', 'completed']).optional(),
21
+ });
22
+ const PlanStatusArgsSchema = z.object({
23
+ planId: z.string().optional(),
24
+ verbose: z.boolean().optional(),
25
+ });
26
+ const ListPlansArgsSchema = z.object({
27
+ status: z.enum(['active', 'completed', 'archived', 'all']).optional().default('active'),
28
+ });
29
+ const PlanReportArgsSchema = z.object({
30
+ planId: z.string().optional(),
31
+ format: z.enum(['summary', 'detailed', 'markdown']).optional().default('detailed'),
32
+ });
33
+ const ArchivePlanArgsSchema = z.object({
34
+ planId: z.string().optional(),
35
+ reason: z.string().optional().default('Completed'),
36
+ });
37
+ const SwitchPlanArgsSchema = z.object({
38
+ planId: z.string(),
39
+ // Note: switchToPlan automatically unarchives if needed
40
+ });
41
+ const StartWatchArgsSchema = z.object({
42
+ port: z.number().optional().default(8765),
43
+ autoOpen: z.boolean().optional().default(true),
44
+ });
45
+ const StopWatchArgsSchema = z.object({});
46
+ // Singleton instance tracking for plan watcher
47
+ let watcherInstance = null;
48
+ export class PlanningPrompt {
49
+ /**
50
+ * Get all planning-related prompt definitions
51
+ */
52
+ static getPromptDefinitions() {
53
+ return [
54
+ {
55
+ name: 'create-plan',
56
+ description: '📋 Create a new structured plan with automatic phase extraction',
57
+ arguments: [
58
+ {
59
+ name: 'title',
60
+ description: 'Title for the new plan',
61
+ required: true,
62
+ },
63
+ {
64
+ name: 'overview',
65
+ description: 'Overview or description of the plan',
66
+ required: true,
67
+ },
68
+ {
69
+ name: 'phases',
70
+ description: 'Optional comma-separated list of initial phases',
71
+ required: false,
72
+ },
73
+ ],
74
+ },
75
+ {
76
+ name: 'update-plan',
77
+ description: '✏️ Update an existing plan with new phases, todos, or status changes',
78
+ arguments: [
79
+ {
80
+ name: 'planId',
81
+ description: 'ID of the plan to update (optional, uses active plan if not provided)',
82
+ required: false,
83
+ },
84
+ {
85
+ name: 'operation',
86
+ description: 'Operation to perform: add-phase, update-phase-status, add-todo, complete-todo',
87
+ required: true,
88
+ },
89
+ {
90
+ name: 'phaseNumber',
91
+ description: 'Phase number for phase-specific operations',
92
+ required: false,
93
+ },
94
+ {
95
+ name: 'content',
96
+ description: 'Content for the operation (phase title, todo content, etc.)',
97
+ required: false,
98
+ },
99
+ {
100
+ name: 'status',
101
+ description: 'New status for phase updates: pending, in_progress, completed',
102
+ required: false,
103
+ },
104
+ ],
105
+ },
106
+ {
107
+ name: 'plan-status',
108
+ description: '📊 Get current status and progress of a plan',
109
+ arguments: [
110
+ {
111
+ name: 'planId',
112
+ description: 'Plan ID (optional, uses active plan if not provided)',
113
+ required: false,
114
+ },
115
+ {
116
+ name: 'verbose',
117
+ description: 'Show detailed breakdown including all phases and todos',
118
+ required: false,
119
+ },
120
+ ],
121
+ },
122
+ {
123
+ name: 'list-plans',
124
+ description: '📋 List all plans for the current persona',
125
+ arguments: [
126
+ {
127
+ name: 'status',
128
+ description: 'Filter by status: active, completed, archived, all',
129
+ required: false,
130
+ },
131
+ ],
132
+ },
133
+ {
134
+ name: 'plan-report',
135
+ description: '📄 Generate a comprehensive markdown report for a plan',
136
+ arguments: [
137
+ {
138
+ name: 'planId',
139
+ description: 'Plan ID (optional, uses active plan if not provided)',
140
+ required: false,
141
+ },
142
+ {
143
+ name: 'format',
144
+ description: 'Report format: summary, detailed, markdown',
145
+ required: false,
146
+ },
147
+ ],
148
+ },
149
+ {
150
+ name: 'archive-plan',
151
+ description: '📦 Archive a completed plan',
152
+ arguments: [
153
+ {
154
+ name: 'planId',
155
+ description: 'Plan ID (optional, uses active plan if not provided)',
156
+ required: false,
157
+ },
158
+ {
159
+ name: 'reason',
160
+ description: 'Reason for archiving the plan',
161
+ required: false,
162
+ },
163
+ ],
164
+ },
165
+ {
166
+ name: 'switch-plan',
167
+ description: '🔄 Switch to a different plan as the active plan',
168
+ arguments: [
169
+ {
170
+ name: 'planId',
171
+ description: 'ID of the plan to switch to',
172
+ required: true,
173
+ },
174
+ {
175
+ name: 'force',
176
+ description: 'Allow switching to archived plans',
177
+ required: false,
178
+ },
179
+ ],
180
+ },
181
+ {
182
+ name: 'start-watch',
183
+ description: '🚀 Launch web dashboard to monitor plans in real-time',
184
+ arguments: [
185
+ {
186
+ name: 'port',
187
+ description: 'Port number for the dashboard (default: 8765)',
188
+ required: false,
189
+ },
190
+ {
191
+ name: 'autoOpen',
192
+ description: 'Automatically open browser when dashboard starts',
193
+ required: false,
194
+ },
195
+ ],
196
+ },
197
+ {
198
+ name: 'stop-watch',
199
+ description: '🛑 Stop the running plan watcher dashboard',
200
+ arguments: [],
201
+ },
202
+ ];
203
+ }
204
+ /**
205
+ * Main handler that routes to specific prompt handlers
206
+ */
207
+ static async handle(name, args, context) {
208
+ switch (name) {
209
+ case 'create-plan':
210
+ return await PlanningPrompt.handleCreatePlan(args, context);
211
+ case 'update-plan':
212
+ return await PlanningPrompt.handleUpdatePlan(args, context);
213
+ case 'plan-status':
214
+ return await PlanningPrompt.handlePlanStatus(args, context);
215
+ case 'list-plans':
216
+ return await PlanningPrompt.handleListPlans(args, context);
217
+ case 'plan-report':
218
+ return await PlanningPrompt.handlePlanReport(args, context);
219
+ case 'archive-plan':
220
+ return await PlanningPrompt.handleArchivePlan(args, context);
221
+ case 'switch-plan':
222
+ return await PlanningPrompt.handleSwitchPlan(args, context);
223
+ case 'start-watch':
224
+ return await PlanningPrompt.handleStartWatch(args, context);
225
+ case 'stop-watch':
226
+ return await PlanningPrompt.handleStopWatch(args, context);
227
+ default:
228
+ throw new Error(`Unknown planning prompt: ${name}`);
229
+ }
230
+ }
231
+ /**
232
+ * Handle create-plan prompt
233
+ */
234
+ static async handleCreatePlan(args, context) {
235
+ try {
236
+ // Validate args with Zod
237
+ const validatedArgs = CreatePlanArgsSchema.parse(args);
238
+ const { title, overview, phases: phasesArg } = validatedArgs;
239
+ if (!context.activePersona?.id) {
240
+ throw new Error('No active persona found. Use "as" tool to switch to a persona first.');
241
+ }
242
+ // Parse initial phases if provided
243
+ const initialPhases = phasesArg
244
+ ? phasesArg
245
+ .split(',')
246
+ .map((p) => p.trim())
247
+ .filter((p) => p.length > 0)
248
+ : undefined;
249
+ // Create service with RequestContext
250
+ const planningService = new PlanningService(context);
251
+ // Call service method with validated args
252
+ const plan = await planningService.createPlan({
253
+ title,
254
+ overview,
255
+ initialPhases,
256
+ });
257
+ const resultText = [
258
+ `✅ Created plan: "${plan.title}"`,
259
+ `Plan ID: ${plan.id}`,
260
+ `Persona: ${context.activePersona.id}`,
261
+ '',
262
+ `Phases: ${plan.phases.length}`,
263
+ ...plan.phases.map((phase, i) => `${i + 1}. ${phase.title}`),
264
+ '',
265
+ 'Use "plan-status" to see the current progress.',
266
+ ].join('\n');
267
+ return {
268
+ description: 'Create a new structured plan',
269
+ messages: [
270
+ {
271
+ role: 'user',
272
+ content: {
273
+ type: 'text',
274
+ text: `Create plan: ${title}${initialPhases ? ` with phases: ${initialPhases.join(', ')}` : ''}`,
275
+ },
276
+ },
277
+ {
278
+ role: 'assistant',
279
+ content: {
280
+ type: 'text',
281
+ text: resultText,
282
+ },
283
+ },
284
+ ],
285
+ };
286
+ }
287
+ catch (error) {
288
+ if (error instanceof z.ZodError) {
289
+ const errorText = `Invalid arguments: ${error.errors.map(e => e.message).join(', ')}`;
290
+ return {
291
+ description: 'Error creating plan',
292
+ messages: [
293
+ {
294
+ role: 'user',
295
+ content: {
296
+ type: 'text',
297
+ text: `Create plan: ${args.title}`,
298
+ },
299
+ },
300
+ {
301
+ role: 'assistant',
302
+ content: {
303
+ type: 'text',
304
+ text: errorText,
305
+ },
306
+ },
307
+ ],
308
+ };
309
+ }
310
+ const errorText = `Failed to create plan: ${error instanceof Error ? error.message : 'Unknown error'}`;
311
+ return {
312
+ description: 'Error creating plan',
313
+ messages: [
314
+ {
315
+ role: 'user',
316
+ content: {
317
+ type: 'text',
318
+ text: `Create plan: ${args.title}`,
319
+ },
320
+ },
321
+ {
322
+ role: 'assistant',
323
+ content: {
324
+ type: 'text',
325
+ text: errorText,
326
+ },
327
+ },
328
+ ],
329
+ };
330
+ }
331
+ }
332
+ /**
333
+ * Handle update-plan prompt
334
+ */
335
+ static async handleUpdatePlan(args, context) {
336
+ try {
337
+ // Validate args with Zod
338
+ const validatedArgs = UpdatePlanArgsSchema.parse(args);
339
+ const { planId, operation, phaseNumber, content, status } = validatedArgs;
340
+ if (!context.activePersona?.id) {
341
+ throw new Error('No active persona found. Use "as" tool to switch to a persona first.');
342
+ }
343
+ // Create service with RequestContext
344
+ const planningService = new PlanningService(context);
345
+ // Get the plan to update
346
+ let plan;
347
+ if (planId) {
348
+ plan = await planningService.loadPlan({ planId });
349
+ if (!plan) {
350
+ throw new Error(`Plan not found: ${planId}`);
351
+ }
352
+ }
353
+ else {
354
+ plan = await planningService.getActivePlan();
355
+ if (!plan) {
356
+ throw new Error('No active plan found. Specify a planId or create a new plan.');
357
+ }
358
+ }
359
+ // Build updates based on operation
360
+ const updates = {};
361
+ switch (operation) {
362
+ case 'add-phase':
363
+ if (!content) {
364
+ throw new Error('Content (phase title) is required for add-phase operation');
365
+ }
366
+ updates.addPhase = { title: content };
367
+ break;
368
+ case 'update-phase-status':
369
+ if (phaseNumber === undefined) {
370
+ throw new Error('Phase number is required for update-phase-status operation');
371
+ }
372
+ if (!status) {
373
+ throw new Error('Status is required for update-phase-status operation');
374
+ }
375
+ updates.updatePhase = { phaseNumber, status };
376
+ break;
377
+ case 'add-todo':
378
+ if (phaseNumber === undefined) {
379
+ throw new Error('Phase number is required for add-todo operation');
380
+ }
381
+ if (!content) {
382
+ throw new Error('Content (todo text) is required for add-todo operation');
383
+ }
384
+ updates.updatePhase = { phaseNumber, addTodo: content };
385
+ break;
386
+ case 'complete-todo':
387
+ if (phaseNumber === undefined) {
388
+ throw new Error('Phase number is required for complete-todo operation');
389
+ }
390
+ if (!content) {
391
+ throw new Error('Content (todo text) is required for complete-todo operation');
392
+ }
393
+ updates.updatePhase = { phaseNumber, completeTodo: content };
394
+ break;
395
+ default:
396
+ throw new Error(`Unknown operation: ${operation}`);
397
+ }
398
+ // Call service method with validated args
399
+ const updatedPlan = await planningService.updatePlan({
400
+ planId: plan.id,
401
+ updates,
402
+ });
403
+ // Format response
404
+ const statusReport = await planningService.generateStatusReport(updatedPlan);
405
+ const resultText = [
406
+ `✅ Updated plan: "${updatedPlan.title}"`,
407
+ '',
408
+ 'Plan updated successfully.',
409
+ '',
410
+ statusReport,
411
+ ].join('\n');
412
+ return {
413
+ description: 'Update plan with new information',
414
+ messages: [
415
+ {
416
+ role: 'user',
417
+ content: {
418
+ type: 'text',
419
+ text: `Update plan: ${operation}${content ? ` - ${content}` : ''}`,
420
+ },
421
+ },
422
+ {
423
+ role: 'assistant',
424
+ content: {
425
+ type: 'text',
426
+ text: resultText,
427
+ },
428
+ },
429
+ ],
430
+ };
431
+ }
432
+ catch (error) {
433
+ if (error instanceof z.ZodError) {
434
+ const errorText = `Invalid arguments: ${error.errors.map(e => e.message).join(', ')}`;
435
+ return {
436
+ description: 'Error updating plan',
437
+ messages: [
438
+ {
439
+ role: 'user',
440
+ content: {
441
+ type: 'text',
442
+ text: `Update plan: ${args.operation}`,
443
+ },
444
+ },
445
+ {
446
+ role: 'assistant',
447
+ content: {
448
+ type: 'text',
449
+ text: errorText,
450
+ },
451
+ },
452
+ ],
453
+ };
454
+ }
455
+ const errorText = `Failed to update plan: ${error instanceof Error ? error.message : 'Unknown error'}`;
456
+ return {
457
+ description: 'Error updating plan',
458
+ messages: [
459
+ {
460
+ role: 'user',
461
+ content: {
462
+ type: 'text',
463
+ text: `Update plan: ${args.operation}`,
464
+ },
465
+ },
466
+ {
467
+ role: 'assistant',
468
+ content: {
469
+ type: 'text',
470
+ text: errorText,
471
+ },
472
+ },
473
+ ],
474
+ };
475
+ }
476
+ }
477
+ /**
478
+ * Handle plan-status prompt
479
+ */
480
+ static async handlePlanStatus(args, context) {
481
+ try {
482
+ // Validate args with Zod
483
+ const validatedArgs = PlanStatusArgsSchema.parse(args);
484
+ const { planId, verbose } = validatedArgs;
485
+ if (!context.activePersona?.id) {
486
+ throw new Error('No active persona found. Use "as" tool to switch to a persona first.');
487
+ }
488
+ // Create service with RequestContext
489
+ const planningService = new PlanningService(context);
490
+ // Get the plan
491
+ let plan;
492
+ if (planId) {
493
+ plan = await planningService.loadPlan({ planId });
494
+ if (!plan) {
495
+ throw new Error(`Plan not found: ${planId}`);
496
+ }
497
+ }
498
+ else {
499
+ plan = await planningService.getActivePlan();
500
+ if (!plan) {
501
+ throw new Error(`No active plan found for persona "${context.activePersona.id}". Use "list-plans" to see all plans.`);
502
+ }
503
+ }
504
+ // Format response
505
+ const resultText = verbose
506
+ ? await planningService.formatPlan(plan)
507
+ : await planningService.generateStatusReport(plan);
508
+ return {
509
+ description: 'Show current plan status and progress',
510
+ messages: [
511
+ {
512
+ role: 'user',
513
+ content: {
514
+ type: 'text',
515
+ text: `Show plan status${verbose ? ' (detailed)' : ''}`,
516
+ },
517
+ },
518
+ {
519
+ role: 'assistant',
520
+ content: {
521
+ type: 'text',
522
+ text: resultText,
523
+ },
524
+ },
525
+ ],
526
+ };
527
+ }
528
+ catch (error) {
529
+ if (error instanceof z.ZodError) {
530
+ throw new Error(`Invalid arguments: ${error.errors.map(e => e.message).join(', ')}`);
531
+ }
532
+ const errorText = `Failed to get plan status: ${error instanceof Error ? error.message : 'Unknown error'}`;
533
+ return {
534
+ description: 'Error getting plan status',
535
+ messages: [
536
+ {
537
+ role: 'user',
538
+ content: {
539
+ type: 'text',
540
+ text: 'Show plan status',
541
+ },
542
+ },
543
+ {
544
+ role: 'assistant',
545
+ content: {
546
+ type: 'text',
547
+ text: errorText,
548
+ },
549
+ },
550
+ ],
551
+ };
552
+ }
553
+ }
554
+ /**
555
+ * Handle list-plans prompt
556
+ */
557
+ static async handleListPlans(args, context) {
558
+ try {
559
+ // Validate args with Zod
560
+ const validatedArgs = ListPlansArgsSchema.parse(args);
561
+ const statusFilter = validatedArgs.status;
562
+ if (!context.activePersona?.id) {
563
+ throw new Error('No active persona found. Use "as" tool to switch to a persona first.');
564
+ }
565
+ // Create service with RequestContext
566
+ const planningService = new PlanningService(context);
567
+ // Call service method with validated args
568
+ const plans = await planningService.listPlans({
569
+ type: statusFilter === 'all' ? undefined : statusFilter === 'completed' ? 'active' : statusFilter,
570
+ });
571
+ if (plans.length === 0) {
572
+ const resultText = `No ${statusFilter} plans found for persona "${context.activePersona.id}".`;
573
+ return {
574
+ description: 'List available plans',
575
+ messages: [
576
+ {
577
+ role: 'user',
578
+ content: {
579
+ type: 'text',
580
+ text: `List ${statusFilter} plans`,
581
+ },
582
+ },
583
+ {
584
+ role: 'assistant',
585
+ content: {
586
+ type: 'text',
587
+ text: resultText,
588
+ },
589
+ },
590
+ ],
591
+ };
592
+ }
593
+ // Format response
594
+ const formattedList = await planningService.formatPlan(plans[0]);
595
+ const resultText = [
596
+ `📋 Plans for persona "${context.activePersona.id}":`,
597
+ '',
598
+ formattedList,
599
+ ].join('\n');
600
+ return {
601
+ description: 'List available plans',
602
+ messages: [
603
+ {
604
+ role: 'user',
605
+ content: {
606
+ type: 'text',
607
+ text: `List ${statusFilter} plans`,
608
+ },
609
+ },
610
+ {
611
+ role: 'assistant',
612
+ content: {
613
+ type: 'text',
614
+ text: resultText,
615
+ },
616
+ },
617
+ ],
618
+ };
619
+ }
620
+ catch (error) {
621
+ if (error instanceof z.ZodError) {
622
+ throw new Error(`Invalid arguments: ${error.errors.map(e => e.message).join(', ')}`);
623
+ }
624
+ const errorText = `Failed to list plans: ${error instanceof Error ? error.message : 'Unknown error'}`;
625
+ return {
626
+ description: 'Error listing plans',
627
+ messages: [
628
+ {
629
+ role: 'user',
630
+ content: {
631
+ type: 'text',
632
+ text: 'List plans',
633
+ },
634
+ },
635
+ {
636
+ role: 'assistant',
637
+ content: {
638
+ type: 'text',
639
+ text: errorText,
640
+ },
641
+ },
642
+ ],
643
+ };
644
+ }
645
+ }
646
+ /**
647
+ * Handle plan-report prompt
648
+ */
649
+ static async handlePlanReport(args, context) {
650
+ try {
651
+ // Validate args with Zod
652
+ const validatedArgs = PlanReportArgsSchema.parse(args);
653
+ const { planId, format } = validatedArgs;
654
+ if (!context.activePersona?.id) {
655
+ throw new Error('No active persona found. Use "as" tool to switch to a persona first.');
656
+ }
657
+ // Create service with RequestContext
658
+ const planningService = new PlanningService(context);
659
+ // Get the plan
660
+ let plan;
661
+ if (planId) {
662
+ plan = await planningService.loadPlan({ planId });
663
+ if (!plan) {
664
+ throw new Error(`Plan not found: ${planId}`);
665
+ }
666
+ }
667
+ else {
668
+ plan = await planningService.getActivePlan();
669
+ if (!plan) {
670
+ throw new Error('No active plan found.');
671
+ }
672
+ }
673
+ // Format response based on format option
674
+ const report = format === 'summary'
675
+ ? await planningService.generateStatusReport(plan)
676
+ : await planningService.formatPlan(plan, format === 'markdown');
677
+ return {
678
+ description: 'Generate comprehensive plan report',
679
+ messages: [
680
+ {
681
+ role: 'user',
682
+ content: {
683
+ type: 'text',
684
+ text: `Generate ${format} report for plan`,
685
+ },
686
+ },
687
+ {
688
+ role: 'assistant',
689
+ content: {
690
+ type: 'text',
691
+ text: report,
692
+ },
693
+ },
694
+ ],
695
+ };
696
+ }
697
+ catch (error) {
698
+ if (error instanceof z.ZodError) {
699
+ throw new Error(`Invalid arguments: ${error.errors.map(e => e.message).join(', ')}`);
700
+ }
701
+ const errorText = `Failed to generate plan report: ${error instanceof Error ? error.message : 'Unknown error'}`;
702
+ return {
703
+ description: 'Error generating plan report',
704
+ messages: [
705
+ {
706
+ role: 'user',
707
+ content: {
708
+ type: 'text',
709
+ text: 'Generate plan report',
710
+ },
711
+ },
712
+ {
713
+ role: 'assistant',
714
+ content: {
715
+ type: 'text',
716
+ text: errorText,
717
+ },
718
+ },
719
+ ],
720
+ };
721
+ }
722
+ }
723
+ /**
724
+ * Handle archive-plan prompt
725
+ */
726
+ static async handleArchivePlan(args, context) {
727
+ try {
728
+ // Validate args with Zod
729
+ const validatedArgs = ArchivePlanArgsSchema.parse(args);
730
+ const { planId, reason } = validatedArgs;
731
+ if (!context.activePersona?.id) {
732
+ throw new Error('No active persona found. Use "as" tool to switch to a persona first.');
733
+ }
734
+ // Create service with RequestContext
735
+ const planningService = new PlanningService(context);
736
+ // Get the plan to archive
737
+ let plan;
738
+ if (planId) {
739
+ plan = await planningService.loadPlan({ planId });
740
+ if (!plan) {
741
+ throw new Error(`Plan not found: ${planId}`);
742
+ }
743
+ }
744
+ else {
745
+ plan = await planningService.getActivePlan();
746
+ if (!plan) {
747
+ throw new Error('No active plan found to archive.');
748
+ }
749
+ }
750
+ // Call service method with validated args
751
+ const archived = await planningService.archivePlan({
752
+ planId: plan.id,
753
+ reason,
754
+ });
755
+ if (!archived) {
756
+ throw new Error('Failed to archive plan.');
757
+ }
758
+ const resultText = `✅ Archived plan: "${plan.title}"\nReason: ${reason}`;
759
+ return {
760
+ description: 'Archive a completed plan',
761
+ messages: [
762
+ {
763
+ role: 'user',
764
+ content: {
765
+ type: 'text',
766
+ text: `Archive plan: ${reason}`,
767
+ },
768
+ },
769
+ {
770
+ role: 'assistant',
771
+ content: {
772
+ type: 'text',
773
+ text: resultText,
774
+ },
775
+ },
776
+ ],
777
+ };
778
+ }
779
+ catch (error) {
780
+ if (error instanceof z.ZodError) {
781
+ throw new Error(`Invalid arguments: ${error.errors.map(e => e.message).join(', ')}`);
782
+ }
783
+ const errorText = `Failed to archive plan: ${error instanceof Error ? error.message : 'Unknown error'}`;
784
+ return {
785
+ description: 'Error archiving plan',
786
+ messages: [
787
+ {
788
+ role: 'user',
789
+ content: {
790
+ type: 'text',
791
+ text: 'Archive plan',
792
+ },
793
+ },
794
+ {
795
+ role: 'assistant',
796
+ content: {
797
+ type: 'text',
798
+ text: errorText,
799
+ },
800
+ },
801
+ ],
802
+ };
803
+ }
804
+ }
805
+ /**
806
+ * Handle switch-plan prompt
807
+ */
808
+ static async handleSwitchPlan(args, context) {
809
+ try {
810
+ // Validate args with Zod
811
+ const validatedArgs = SwitchPlanArgsSchema.parse(args);
812
+ const { planId } = validatedArgs;
813
+ if (!context.activePersona?.id) {
814
+ throw new Error('No active persona found. Use "as" tool to switch to a persona first.');
815
+ }
816
+ // Create service with RequestContext
817
+ const planningService = new PlanningService(context);
818
+ // Use the new switchToPlan method which handles both active and archived plans
819
+ // It will automatically unarchive if needed
820
+ const switchedPlan = await planningService.switchToPlan(planId);
821
+ const state = switchedPlan.currentState;
822
+ const resultText = `✅ Switched active plan to: "${switchedPlan.title}"
823
+ Plan ID: ${switchedPlan.id}
824
+ Status: ${switchedPlan.status}
825
+ Progress: ${state.overallProgress.percentComplete}% (${state.overallProgress.completedPhases}/${state.overallProgress.totalPhases} phases, ${state.overallProgress.completedTodos}/${state.overallProgress.totalTodos} tasks)`;
826
+ return {
827
+ description: 'Switch to a different plan',
828
+ messages: [
829
+ {
830
+ role: 'user',
831
+ content: {
832
+ type: 'text',
833
+ text: `Switch to plan: ${planId}`,
834
+ },
835
+ },
836
+ {
837
+ role: 'assistant',
838
+ content: {
839
+ type: 'text',
840
+ text: resultText,
841
+ },
842
+ },
843
+ ],
844
+ };
845
+ }
846
+ catch (error) {
847
+ if (error instanceof z.ZodError) {
848
+ throw new Error(`Invalid arguments: ${error.errors.map(e => e.message).join(', ')}`);
849
+ }
850
+ const errorText = `Failed to switch plan: ${error instanceof Error ? error.message : 'Unknown error'}`;
851
+ return {
852
+ description: 'Error switching plan',
853
+ messages: [
854
+ {
855
+ role: 'user',
856
+ content: {
857
+ type: 'text',
858
+ text: 'Switch plan',
859
+ },
860
+ },
861
+ {
862
+ role: 'assistant',
863
+ content: {
864
+ type: 'text',
865
+ text: errorText,
866
+ },
867
+ },
868
+ ],
869
+ };
870
+ }
871
+ }
872
+ /**
873
+ * Handle start-watch prompt
874
+ */
875
+ static async handleStartWatch(args, context) {
876
+ try {
877
+ // Validate args with Zod
878
+ const validatedArgs = StartWatchArgsSchema.parse(args);
879
+ const { port, autoOpen } = validatedArgs;
880
+ if (!context.activePersona?.id) {
881
+ throw new Error('No active persona found. Use "as" tool to switch to a persona first.');
882
+ }
883
+ // Check if we have an existing watcher
884
+ if (watcherInstance) {
885
+ const isRunning = watcherInstance.isRunning();
886
+ if (isRunning) {
887
+ // Stop the old watcher before creating a new one
888
+ await watcherInstance.stop();
889
+ }
890
+ }
891
+ // Import PlanWatcherService dynamically to avoid circular dependencies
892
+ const { PlanWatcherService } = await import('../../services/plan-watcher.service.js');
893
+ // Create new watcher instance and store it
894
+ watcherInstance = new PlanWatcherService(context);
895
+ // Start the dashboard
896
+ const result = await watcherInstance.start({ port, autoOpen });
897
+ if (!result.success) {
898
+ watcherInstance = null;
899
+ throw new Error(result.error?.message || 'Failed to start plan watcher');
900
+ }
901
+ const resultText = `🚀 Plan watcher dashboard started successfully!
902
+
903
+ 📊 Dashboard URL: ${result.data?.url}
904
+ Port: ${port}
905
+
906
+ The dashboard is now running and will monitor your plans in real-time.
907
+ Use "stop-watch" to stop the dashboard when done.`;
908
+ return {
909
+ description: 'Start plan watcher dashboard',
910
+ messages: [
911
+ {
912
+ role: 'user',
913
+ content: {
914
+ type: 'text',
915
+ text: `Start plan watcher on port ${port}`,
916
+ },
917
+ },
918
+ {
919
+ role: 'assistant',
920
+ content: {
921
+ type: 'text',
922
+ text: resultText,
923
+ },
924
+ },
925
+ ],
926
+ };
927
+ }
928
+ catch (error) {
929
+ if (error instanceof z.ZodError) {
930
+ throw new Error(`Invalid arguments: ${error.errors.map(e => e.message).join(', ')}`);
931
+ }
932
+ const errorText = `Failed to start plan watcher: ${error instanceof Error ? error.message : 'Unknown error'}`;
933
+ return {
934
+ description: 'Error starting plan watcher',
935
+ messages: [
936
+ {
937
+ role: 'user',
938
+ content: {
939
+ type: 'text',
940
+ text: 'Start plan watcher',
941
+ },
942
+ },
943
+ {
944
+ role: 'assistant',
945
+ content: {
946
+ type: 'text',
947
+ text: errorText,
948
+ },
949
+ },
950
+ ],
951
+ };
952
+ }
953
+ }
954
+ /**
955
+ * Handle stop-watch prompt
956
+ */
957
+ static async handleStopWatch(args, _context) {
958
+ try {
959
+ // Validate args with Zod (even though there are no args, for consistency)
960
+ StopWatchArgsSchema.parse(args);
961
+ if (!watcherInstance) {
962
+ throw new Error('Plan watcher is not running');
963
+ }
964
+ // Stop the dashboard
965
+ const result = await watcherInstance.stop();
966
+ if (!result.success) {
967
+ throw new Error(result.error?.message || 'Failed to stop plan watcher');
968
+ }
969
+ // Clear the singleton instance
970
+ watcherInstance = null;
971
+ const resultText = `🛑 Plan watcher dashboard stopped successfully.`;
972
+ return {
973
+ description: 'Stop plan watcher dashboard',
974
+ messages: [
975
+ {
976
+ role: 'user',
977
+ content: {
978
+ type: 'text',
979
+ text: 'Stop plan watcher',
980
+ },
981
+ },
982
+ {
983
+ role: 'assistant',
984
+ content: {
985
+ type: 'text',
986
+ text: resultText,
987
+ },
988
+ },
989
+ ],
990
+ };
991
+ }
992
+ catch (error) {
993
+ const errorText = `Failed to stop plan watcher: ${error instanceof Error ? error.message : 'Unknown error'}`;
994
+ return {
995
+ description: 'Error stopping plan watcher',
996
+ messages: [
997
+ {
998
+ role: 'user',
999
+ content: {
1000
+ type: 'text',
1001
+ text: 'Stop plan watcher',
1002
+ },
1003
+ },
1004
+ {
1005
+ role: 'assistant',
1006
+ content: {
1007
+ type: 'text',
1008
+ text: errorText,
1009
+ },
1010
+ },
1011
+ ],
1012
+ };
1013
+ }
1014
+ }
1015
+ }
1016
+ //# sourceMappingURL=planning.prompt.js.map