agentrace 0.0.11 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -47,6 +47,19 @@ const SetPlanStatusSchema = z.object({
|
|
|
47
47
|
status: z.enum(["scratch", "draft", "planning", "pending", "ready", "implementation", "complete"]).describe("New status for the plan"),
|
|
48
48
|
message: z.string().optional().describe("One-line description of why the status is being changed"),
|
|
49
49
|
});
|
|
50
|
+
const GetPlanCommentsSchema = z.object({
|
|
51
|
+
plan_id: z.string().describe("Plan document ID"),
|
|
52
|
+
status: z.enum(["active", "resolved", "outdated", "all"]).optional().describe("Filter comments by status. Defaults to showing all comments."),
|
|
53
|
+
});
|
|
54
|
+
const AddPlanCommentSchema = z.object({
|
|
55
|
+
plan_id: z.string().describe("Plan document ID"),
|
|
56
|
+
target_text: z.string().describe("The text in the plan body that this comment refers to"),
|
|
57
|
+
content: z.string().describe("The comment content"),
|
|
58
|
+
});
|
|
59
|
+
const ResolvePlanCommentSchema = z.object({
|
|
60
|
+
plan_id: z.string().describe("Plan document ID"),
|
|
61
|
+
thread_id: z.string().describe("Comment thread ID to resolve"),
|
|
62
|
+
});
|
|
50
63
|
// Tool descriptions with usage guidance
|
|
51
64
|
const TOOL_DESCRIPTIONS = {
|
|
52
65
|
search_plans: `Search plan documents with filtering options.
|
|
@@ -62,7 +75,14 @@ WHEN TO USE:
|
|
|
62
75
|
WHEN TO USE:
|
|
63
76
|
- When the user asks you to check or review a specific plan by ID
|
|
64
77
|
- When you need to understand an existing plan before making changes
|
|
65
|
-
- When the user references a plan ID in their request
|
|
78
|
+
- When the user references a plan ID in their request
|
|
79
|
+
|
|
80
|
+
IMPORTANT - HANDLING COMMENTS:
|
|
81
|
+
- The response includes 'active_comments_count' showing how many unresolved comments exist
|
|
82
|
+
- If the plan is in 'planning' status AND has active comments (active_comments_count > 0):
|
|
83
|
+
- You SHOULD use get_plan_comments to read the comments
|
|
84
|
+
- Consider the feedback in the comments and reflect it in your plan updates
|
|
85
|
+
- Comments represent team feedback that should be addressed before moving to ready`,
|
|
66
86
|
create_plan: `Create a new plan document to record implementation or design plans.
|
|
67
87
|
|
|
68
88
|
WHEN TO USE:
|
|
@@ -108,6 +128,30 @@ STATUS TRANSITION GUIDELINES:
|
|
|
108
128
|
|
|
109
129
|
CAUTION:
|
|
110
130
|
- When a plan is in "implementation" status, someone else might already be working on it. Check with the team before starting work on such plans.`,
|
|
131
|
+
get_plan_comments: `Get comments for a plan document.
|
|
132
|
+
|
|
133
|
+
WHEN TO USE:
|
|
134
|
+
- When you need to see feedback or discussions on a specific plan
|
|
135
|
+
- When reviewing a plan that others have commented on
|
|
136
|
+
- Before making changes to understand any concerns or suggestions
|
|
137
|
+
|
|
138
|
+
Returns comments with their status (active, resolved, or outdated).`,
|
|
139
|
+
add_plan_comment: `Add a comment to a specific location in a plan.
|
|
140
|
+
|
|
141
|
+
WHEN TO USE:
|
|
142
|
+
- When you want to provide feedback on a specific part of a plan
|
|
143
|
+
- When you have a question or suggestion about the plan content
|
|
144
|
+
- When reviewing a plan and want to leave notes for the team
|
|
145
|
+
|
|
146
|
+
The comment is anchored to specific text in the plan body.`,
|
|
147
|
+
resolve_plan_comment: `Resolve a comment thread on a plan.
|
|
148
|
+
|
|
149
|
+
WHEN TO USE:
|
|
150
|
+
- When you have addressed the feedback in a comment
|
|
151
|
+
- When the issue raised in the comment has been fixed
|
|
152
|
+
- When the comment is no longer relevant after plan updates
|
|
153
|
+
|
|
154
|
+
Resolving a comment marks it as handled, keeping it visible but indicating it's been addressed.`,
|
|
111
155
|
};
|
|
112
156
|
export async function mcpServerCommand() {
|
|
113
157
|
const server = new McpServer({
|
|
@@ -154,6 +198,7 @@ IMPORTANT GUIDELINES:
|
|
|
154
198
|
id: plan.id,
|
|
155
199
|
description: plan.description,
|
|
156
200
|
status: plan.status,
|
|
201
|
+
active_comments_count: plan.active_comments_count,
|
|
157
202
|
git_remote_url: plan.project?.canonical_git_repository || null,
|
|
158
203
|
url: plan.url || null,
|
|
159
204
|
updated_at: plan.updated_at,
|
|
@@ -184,10 +229,14 @@ IMPORTANT GUIDELINES:
|
|
|
184
229
|
server.tool("read_plan", TOOL_DESCRIPTIONS.read_plan, ReadPlanSchema.shape, async (args) => {
|
|
185
230
|
try {
|
|
186
231
|
const plan = await getClient().getPlan(args.id);
|
|
187
|
-
let text = `# ${plan.description}\n\nStatus: ${plan.status}\n\n${plan.body}`;
|
|
232
|
+
let text = `# ${plan.description}\n\nStatus: ${plan.status}\nActive Comments: ${plan.active_comments_count}\n\n${plan.body}`;
|
|
188
233
|
if (plan.url) {
|
|
189
234
|
text += `\n\n---\nURL: ${plan.url}`;
|
|
190
235
|
}
|
|
236
|
+
// Add reminder if there are active comments on a planning status plan
|
|
237
|
+
if (plan.status === "planning" && plan.active_comments_count > 0) {
|
|
238
|
+
text += `\n\n---\n⚠️ This plan has ${plan.active_comments_count} active comment(s). Use get_plan_comments to review them and consider the feedback.`;
|
|
239
|
+
}
|
|
191
240
|
return {
|
|
192
241
|
content: [
|
|
193
242
|
{
|
|
@@ -316,6 +365,115 @@ IMPORTANT GUIDELINES:
|
|
|
316
365
|
};
|
|
317
366
|
}
|
|
318
367
|
});
|
|
368
|
+
// get_plan_comments tool
|
|
369
|
+
server.tool("get_plan_comments", TOOL_DESCRIPTIONS.get_plan_comments, GetPlanCommentsSchema.shape, async (args) => {
|
|
370
|
+
try {
|
|
371
|
+
const threads = await getClient().getThreads(args.plan_id, args.status);
|
|
372
|
+
if (threads.length === 0) {
|
|
373
|
+
return {
|
|
374
|
+
content: [
|
|
375
|
+
{
|
|
376
|
+
type: "text",
|
|
377
|
+
text: "No comments found for this plan.",
|
|
378
|
+
},
|
|
379
|
+
],
|
|
380
|
+
};
|
|
381
|
+
}
|
|
382
|
+
const threadList = threads.map((thread) => ({
|
|
383
|
+
id: thread.id,
|
|
384
|
+
target_text: thread.target_text,
|
|
385
|
+
status: thread.status,
|
|
386
|
+
position: thread.position ? {
|
|
387
|
+
start_line: thread.position.start_line,
|
|
388
|
+
start_column: thread.position.start_column,
|
|
389
|
+
end_line: thread.position.end_line,
|
|
390
|
+
end_column: thread.position.end_column,
|
|
391
|
+
found: thread.position.found,
|
|
392
|
+
} : null,
|
|
393
|
+
messages: thread.messages.map((msg) => ({
|
|
394
|
+
id: msg.id,
|
|
395
|
+
user_name: msg.user_name,
|
|
396
|
+
content: msg.content,
|
|
397
|
+
created_at: msg.created_at,
|
|
398
|
+
})),
|
|
399
|
+
created_at: thread.created_at,
|
|
400
|
+
}));
|
|
401
|
+
return {
|
|
402
|
+
content: [
|
|
403
|
+
{
|
|
404
|
+
type: "text",
|
|
405
|
+
text: JSON.stringify(threadList, null, 2),
|
|
406
|
+
},
|
|
407
|
+
],
|
|
408
|
+
};
|
|
409
|
+
}
|
|
410
|
+
catch (error) {
|
|
411
|
+
return {
|
|
412
|
+
content: [
|
|
413
|
+
{
|
|
414
|
+
type: "text",
|
|
415
|
+
text: `Error: ${error instanceof Error ? error.message : String(error)}`,
|
|
416
|
+
},
|
|
417
|
+
],
|
|
418
|
+
isError: true,
|
|
419
|
+
};
|
|
420
|
+
}
|
|
421
|
+
});
|
|
422
|
+
// add_plan_comment tool
|
|
423
|
+
server.tool("add_plan_comment", TOOL_DESCRIPTIONS.add_plan_comment, AddPlanCommentSchema.shape, async (args) => {
|
|
424
|
+
try {
|
|
425
|
+
const thread = await getClient().createThread(args.plan_id, {
|
|
426
|
+
target_text: args.target_text,
|
|
427
|
+
context_before: "",
|
|
428
|
+
context_after: "",
|
|
429
|
+
content: args.content,
|
|
430
|
+
});
|
|
431
|
+
return {
|
|
432
|
+
content: [
|
|
433
|
+
{
|
|
434
|
+
type: "text",
|
|
435
|
+
text: `Comment added successfully.\n\nThread ID: ${thread.id}\nStatus: ${thread.status}\nTarget: "${thread.target_text}"`,
|
|
436
|
+
},
|
|
437
|
+
],
|
|
438
|
+
};
|
|
439
|
+
}
|
|
440
|
+
catch (error) {
|
|
441
|
+
return {
|
|
442
|
+
content: [
|
|
443
|
+
{
|
|
444
|
+
type: "text",
|
|
445
|
+
text: `Error: ${error instanceof Error ? error.message : String(error)}`,
|
|
446
|
+
},
|
|
447
|
+
],
|
|
448
|
+
isError: true,
|
|
449
|
+
};
|
|
450
|
+
}
|
|
451
|
+
});
|
|
452
|
+
// resolve_plan_comment tool
|
|
453
|
+
server.tool("resolve_plan_comment", TOOL_DESCRIPTIONS.resolve_plan_comment, ResolvePlanCommentSchema.shape, async (args) => {
|
|
454
|
+
try {
|
|
455
|
+
const thread = await getClient().resolveThread(args.plan_id, args.thread_id);
|
|
456
|
+
return {
|
|
457
|
+
content: [
|
|
458
|
+
{
|
|
459
|
+
type: "text",
|
|
460
|
+
text: `Comment resolved successfully.\n\nThread ID: ${thread.id}\nStatus: ${thread.status}\nTarget: "${thread.target_text}"`,
|
|
461
|
+
},
|
|
462
|
+
],
|
|
463
|
+
};
|
|
464
|
+
}
|
|
465
|
+
catch (error) {
|
|
466
|
+
return {
|
|
467
|
+
content: [
|
|
468
|
+
{
|
|
469
|
+
type: "text",
|
|
470
|
+
text: `Error: ${error instanceof Error ? error.message : String(error)}`,
|
|
471
|
+
},
|
|
472
|
+
],
|
|
473
|
+
isError: true,
|
|
474
|
+
};
|
|
475
|
+
}
|
|
476
|
+
});
|
|
319
477
|
// Start the server with stdio transport
|
|
320
478
|
const transport = new StdioServerTransport();
|
|
321
479
|
await server.connect(transport);
|
|
@@ -16,6 +16,7 @@ export interface PlanDocument {
|
|
|
16
16
|
url?: string;
|
|
17
17
|
created_at: string;
|
|
18
18
|
updated_at: string;
|
|
19
|
+
active_comments_count: number;
|
|
19
20
|
}
|
|
20
21
|
export interface PlanDocumentEvent {
|
|
21
22
|
id: string;
|
|
@@ -53,6 +54,47 @@ export interface UpdatePlanRequest {
|
|
|
53
54
|
claude_session_id?: string;
|
|
54
55
|
tool_use_id?: string;
|
|
55
56
|
}
|
|
57
|
+
export type PlanCommentThreadStatus = "active" | "resolved" | "outdated";
|
|
58
|
+
export interface CommentPosition {
|
|
59
|
+
start_offset: number;
|
|
60
|
+
end_offset: number;
|
|
61
|
+
start_line: number;
|
|
62
|
+
start_column: number;
|
|
63
|
+
end_line: number;
|
|
64
|
+
end_column: number;
|
|
65
|
+
found: boolean;
|
|
66
|
+
}
|
|
67
|
+
export interface PlanCommentMessage {
|
|
68
|
+
id: string;
|
|
69
|
+
thread_id: string;
|
|
70
|
+
user_id: string;
|
|
71
|
+
user_name: string;
|
|
72
|
+
content: string;
|
|
73
|
+
created_at: string;
|
|
74
|
+
updated_at: string;
|
|
75
|
+
}
|
|
76
|
+
export interface PlanCommentThread {
|
|
77
|
+
id: string;
|
|
78
|
+
plan_document_id: string;
|
|
79
|
+
target_text: string;
|
|
80
|
+
status: PlanCommentThreadStatus;
|
|
81
|
+
position: CommentPosition | null;
|
|
82
|
+
messages: PlanCommentMessage[];
|
|
83
|
+
created_at: string;
|
|
84
|
+
updated_at: string;
|
|
85
|
+
}
|
|
86
|
+
export interface ListThreadsResponse {
|
|
87
|
+
threads: PlanCommentThread[];
|
|
88
|
+
}
|
|
89
|
+
export interface CreateThreadRequest {
|
|
90
|
+
target_text: string;
|
|
91
|
+
context_before: string;
|
|
92
|
+
context_after: string;
|
|
93
|
+
content: string;
|
|
94
|
+
}
|
|
95
|
+
export interface AddMessageRequest {
|
|
96
|
+
content: string;
|
|
97
|
+
}
|
|
56
98
|
export declare class PlanDocumentClient {
|
|
57
99
|
private serverUrl;
|
|
58
100
|
private apiKey;
|
|
@@ -65,4 +107,8 @@ export declare class PlanDocumentClient {
|
|
|
65
107
|
updatePlan(id: string, req: UpdatePlanRequest): Promise<PlanDocument>;
|
|
66
108
|
deletePlan(id: string): Promise<void>;
|
|
67
109
|
setStatus(id: string, status: PlanDocumentStatus, message?: string): Promise<PlanDocument>;
|
|
110
|
+
getThreads(planId: string, status?: PlanCommentThreadStatus | "all"): Promise<PlanCommentThread[]>;
|
|
111
|
+
createThread(planId: string, req: CreateThreadRequest): Promise<PlanCommentThread>;
|
|
112
|
+
resolveThread(planId: string, threadId: string): Promise<PlanCommentThread>;
|
|
113
|
+
addMessage(planId: string, threadId: string, req: AddMessageRequest): Promise<PlanCommentMessage>;
|
|
68
114
|
}
|
|
@@ -69,4 +69,24 @@ export class PlanDocumentClient {
|
|
|
69
69
|
async setStatus(id, status, message) {
|
|
70
70
|
return this.request("PATCH", `/api/plans/${id}/status`, { status, message });
|
|
71
71
|
}
|
|
72
|
+
// Comment Thread methods
|
|
73
|
+
async getThreads(planId, status) {
|
|
74
|
+
const params = new URLSearchParams();
|
|
75
|
+
if (status) {
|
|
76
|
+
params.set("status", status);
|
|
77
|
+
}
|
|
78
|
+
const query = params.toString();
|
|
79
|
+
const path = `/api/plans/${planId}/comments${query ? `?${query}` : ""}`;
|
|
80
|
+
const response = await this.request("GET", path);
|
|
81
|
+
return response.threads;
|
|
82
|
+
}
|
|
83
|
+
async createThread(planId, req) {
|
|
84
|
+
return this.request("POST", `/api/plans/${planId}/comments`, req);
|
|
85
|
+
}
|
|
86
|
+
async resolveThread(planId, threadId) {
|
|
87
|
+
return this.request("POST", `/api/plans/${planId}/comments/${threadId}/resolve`);
|
|
88
|
+
}
|
|
89
|
+
async addMessage(planId, threadId, req) {
|
|
90
|
+
return this.request("POST", `/api/plans/${planId}/comments/${threadId}/messages`, req);
|
|
91
|
+
}
|
|
72
92
|
}
|