@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.
- package/LICENSE +21 -0
- package/README.md +81 -0
- package/dist/core/console-logger.d.ts +30 -0
- package/dist/core/console-logger.d.ts.map +1 -0
- package/dist/core/console-logger.js +101 -0
- package/dist/core/console-logger.js.map +1 -0
- package/dist/core/file-logger.d.ts +40 -0
- package/dist/core/file-logger.d.ts.map +1 -0
- package/dist/core/file-logger.js +223 -0
- package/dist/core/file-logger.js.map +1 -0
- package/dist/core/mcp-server.d.ts +54 -0
- package/dist/core/mcp-server.d.ts.map +1 -0
- package/dist/core/mcp-server.js +295 -0
- package/dist/core/mcp-server.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +37 -0
- package/dist/index.js.map +1 -0
- package/dist/prompts/index.d.ts +39 -0
- package/dist/prompts/index.d.ts.map +1 -0
- package/dist/prompts/index.js +5 -0
- package/dist/prompts/index.js.map +1 -0
- package/dist/prompts/memory/memory.prompt.d.ts +32 -0
- package/dist/prompts/memory/memory.prompt.d.ts.map +1 -0
- package/dist/prompts/memory/memory.prompt.js +204 -0
- package/dist/prompts/memory/memory.prompt.js.map +1 -0
- package/dist/prompts/persona/persona.prompt.d.ts +27 -0
- package/dist/prompts/persona/persona.prompt.d.ts.map +1 -0
- package/dist/prompts/persona/persona.prompt.js +592 -0
- package/dist/prompts/persona/persona.prompt.js.map +1 -0
- package/dist/prompts/planning/planning.prompt.d.ts +56 -0
- package/dist/prompts/planning/planning.prompt.d.ts.map +1 -0
- package/dist/prompts/planning/planning.prompt.js +1016 -0
- package/dist/prompts/planning/planning.prompt.js.map +1 -0
- package/dist/prompts/prompt-registry.d.ts +25 -0
- package/dist/prompts/prompt-registry.d.ts.map +1 -0
- package/dist/prompts/prompt-registry.js +68 -0
- package/dist/prompts/prompt-registry.js.map +1 -0
- package/dist/prompts/thinking/thinking.prompt.d.ts +29 -0
- package/dist/prompts/thinking/thinking.prompt.d.ts.map +1 -0
- package/dist/prompts/thinking/thinking.prompt.js +171 -0
- package/dist/prompts/thinking/thinking.prompt.js.map +1 -0
- package/dist/services/UpdateService.d.ts +29 -0
- package/dist/services/UpdateService.d.ts.map +1 -0
- package/dist/services/UpdateService.js +132 -0
- package/dist/services/UpdateService.js.map +1 -0
- package/dist/services/plan-watcher.service.d.ts +143 -0
- package/dist/services/plan-watcher.service.d.ts.map +1 -0
- package/dist/services/plan-watcher.service.js +914 -0
- package/dist/services/plan-watcher.service.js.map +1 -0
- package/dist/storage/local-filesystem-adapter.d.ts +39 -0
- package/dist/storage/local-filesystem-adapter.d.ts.map +1 -0
- package/dist/storage/local-filesystem-adapter.js +208 -0
- package/dist/storage/local-filesystem-adapter.js.map +1 -0
- package/dist/storage/storage-path-builder.d.ts +14 -0
- package/dist/storage/storage-path-builder.d.ts.map +1 -0
- package/dist/storage/storage-path-builder.js +43 -0
- package/dist/storage/storage-path-builder.js.map +1 -0
- package/dist/test-setup.d.ts +2 -0
- package/dist/test-setup.d.ts.map +1 -0
- package/dist/test-setup.js +12 -0
- package/dist/test-setup.js.map +1 -0
- package/dist/tools/analyse-request/analyse-request.tool.d.ts +8 -0
- package/dist/tools/analyse-request/analyse-request.tool.d.ts.map +1 -0
- package/dist/tools/analyse-request/analyse-request.tool.js +120 -0
- package/dist/tools/analyse-request/analyse-request.tool.js.map +1 -0
- package/dist/tools/index.d.ts +69 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +24 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/memory/memory.tool.d.ts +15 -0
- package/dist/tools/memory/memory.tool.d.ts.map +1 -0
- package/dist/tools/memory/memory.tool.js +110 -0
- package/dist/tools/memory/memory.tool.js.map +1 -0
- package/dist/tools/persona/as.tool.d.ts +25 -0
- package/dist/tools/persona/as.tool.d.ts.map +1 -0
- package/dist/tools/persona/as.tool.js +294 -0
- package/dist/tools/persona/as.tool.js.map +1 -0
- package/dist/tools/persona/persona.tool.d.ts +8 -0
- package/dist/tools/persona/persona.tool.d.ts.map +1 -0
- package/dist/tools/persona/persona.tool.js +193 -0
- package/dist/tools/persona/persona.tool.js.map +1 -0
- package/dist/tools/plan/plan.tool.d.ts +18 -0
- package/dist/tools/plan/plan.tool.d.ts.map +1 -0
- package/dist/tools/plan/plan.tool.js +643 -0
- package/dist/tools/plan/plan.tool.js.map +1 -0
- package/dist/tools/strategy/strategy.tool.d.ts +13 -0
- package/dist/tools/strategy/strategy.tool.d.ts.map +1 -0
- package/dist/tools/strategy/strategy.tool.js +199 -0
- package/dist/tools/strategy/strategy.tool.js.map +1 -0
- package/dist/tools/thinking/thinking.tool.d.ts +13 -0
- package/dist/tools/thinking/thinking.tool.d.ts.map +1 -0
- package/dist/tools/thinking/thinking.tool.js +226 -0
- package/dist/tools/thinking/thinking.tool.js.map +1 -0
- package/dist/tools/tool-registry.d.ts +20 -0
- package/dist/tools/tool-registry.d.ts.map +1 -0
- package/dist/tools/tool-registry.js +61 -0
- package/dist/tools/tool-registry.js.map +1 -0
- package/dist/tools/update/update.tool.d.ts +15 -0
- package/dist/tools/update/update.tool.d.ts.map +1 -0
- package/dist/tools/update/update.tool.js +86 -0
- package/dist/tools/update/update.tool.js.map +1 -0
- package/dist/tools/validate-response/validate-response.tool.d.ts +13 -0
- package/dist/tools/validate-response/validate-response.tool.d.ts.map +1 -0
- package/dist/tools/validate-response/validate-response.tool.js +142 -0
- package/dist/tools/validate-response/validate-response.tool.js.map +1 -0
- package/dist/types/request-context.d.ts +7 -0
- package/dist/types/request-context.d.ts.map +1 -0
- package/dist/types/request-context.js +7 -0
- package/dist/types/request-context.js.map +1 -0
- 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
|