@proletariat/cli 0.3.34 → 0.3.36
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/dist/commands/agent/auth.d.ts +15 -3
- package/dist/commands/agent/auth.js +136 -15
- package/dist/commands/agent/index.js +11 -2
- package/dist/commands/agent/list.js +16 -7
- package/dist/commands/agent/staff/add.d.ts +1 -0
- package/dist/commands/agent/staff/add.js +1 -0
- package/dist/commands/agent/staff/index.d.ts +15 -0
- package/dist/commands/agent/staff/index.js +83 -0
- package/dist/commands/agent/staff/list.d.ts +1 -0
- package/dist/commands/agent/staff/list.js +1 -0
- package/dist/commands/agent/staff/remove.d.ts +1 -0
- package/dist/commands/agent/staff/remove.js +1 -0
- package/dist/commands/agent/status.js +32 -4
- package/dist/commands/agent/themes/add-names.d.ts +1 -0
- package/dist/commands/agent/themes/add-names.js +1 -0
- package/dist/commands/agent/themes/create.d.ts +1 -0
- package/dist/commands/agent/themes/create.js +1 -0
- package/dist/commands/agent/themes/index.d.ts +10 -0
- package/dist/commands/agent/themes/index.js +144 -0
- package/dist/commands/agent/themes/list.d.ts +1 -0
- package/dist/commands/agent/themes/list.js +1 -0
- package/dist/commands/agent/themes/set.d.ts +1 -0
- package/dist/commands/agent/themes/set.js +1 -0
- package/dist/commands/agents/themes/add-names.d.ts +1 -0
- package/dist/commands/agents/themes/add-names.js +1 -0
- package/dist/commands/agents/themes/create.d.ts +1 -0
- package/dist/commands/agents/themes/create.js +1 -0
- package/dist/commands/agents/themes/list.d.ts +1 -0
- package/dist/commands/agents/themes/list.js +1 -0
- package/dist/commands/board/watch.js +6 -0
- package/dist/commands/branch/list.d.ts +1 -0
- package/dist/commands/branch/list.js +43 -12
- package/dist/commands/branch/where.js +3 -2
- package/dist/commands/category/list.d.ts +2 -1
- package/dist/commands/category/list.js +38 -13
- package/dist/commands/{claude.d.ts → claude/index.d.ts} +1 -1
- package/dist/commands/{claude.js → claude/index.js} +12 -12
- package/dist/commands/claude/open.d.ts +13 -0
- package/dist/commands/claude/open.js +175 -0
- package/dist/commands/diet.js +18 -2
- package/dist/commands/docker/logs.js +7 -3
- package/dist/commands/docker/shell.js +6 -0
- package/dist/commands/docker/start.js +20 -4
- package/dist/commands/docker/sync.d.ts +4 -0
- package/dist/commands/docker/sync.js +30 -2
- package/dist/commands/epic/show.d.ts +13 -0
- package/dist/commands/epic/show.js +16 -0
- package/dist/commands/epic/view.js +27 -0
- package/dist/commands/execution/config.d.ts +0 -4
- package/dist/commands/execution/config.js +10 -32
- package/dist/commands/execution/index.js +2 -1
- package/dist/commands/execution/logs.js +1 -1
- package/dist/commands/execution/stop.js +2 -1
- package/dist/commands/execution/view.js +22 -26
- package/dist/commands/init.js +2 -19
- package/dist/commands/label/create.d.ts +20 -0
- package/dist/commands/label/create.js +57 -0
- package/dist/commands/label/delete.d.ts +17 -0
- package/dist/commands/label/delete.js +32 -0
- package/dist/commands/label/group/create.d.ts +20 -0
- package/dist/commands/label/group/create.js +55 -0
- package/dist/commands/label/group/list.d.ts +14 -0
- package/dist/commands/label/group/list.js +52 -0
- package/dist/commands/label/index.d.ts +15 -0
- package/dist/commands/label/index.js +58 -0
- package/dist/commands/label/list.d.ts +16 -0
- package/dist/commands/label/list.js +83 -0
- package/dist/commands/link/list.js +3 -2
- package/dist/commands/mcp-server.js +27 -1
- package/dist/commands/phase/template/apply.d.ts +26 -0
- package/dist/commands/phase/template/apply.js +14 -0
- package/dist/commands/phase/template/create.d.ts +23 -0
- package/dist/commands/phase/template/create.js +14 -0
- package/dist/commands/phase/template/delete.d.ts +18 -0
- package/dist/commands/phase/template/delete.js +61 -0
- package/dist/commands/phase/template/list.d.ts +17 -0
- package/dist/commands/phase/template/list.js +89 -0
- package/dist/commands/phase/template/update.d.ts +1 -0
- package/dist/commands/phase/template/update.js +1 -0
- package/dist/commands/priority/add.js +1 -1
- package/dist/commands/project/create.js +3 -4
- package/dist/commands/project/update.js +5 -8
- package/dist/commands/pull.js +24 -0
- package/dist/commands/roadmap/generate.js +1 -2
- package/dist/commands/session/create.d.ts +19 -0
- package/dist/commands/session/create.js +102 -0
- package/dist/commands/session/health.js +2 -21
- package/dist/commands/session/index.js +14 -1
- package/dist/commands/session/list.js +26 -7
- package/dist/commands/session/peek.d.ts +38 -0
- package/dist/commands/session/peek.js +316 -0
- package/dist/commands/session/poke.d.ts +27 -0
- package/dist/commands/session/poke.js +219 -0
- package/dist/commands/spec/link/depends.d.ts +18 -0
- package/dist/commands/spec/link/depends.js +86 -0
- package/dist/commands/spec/link/index.d.ts +17 -0
- package/dist/commands/spec/link/index.js +92 -0
- package/dist/commands/spec/link/remove.d.ts +18 -0
- package/dist/commands/spec/link/remove.js +90 -0
- package/dist/commands/spec/view.js +29 -0
- package/dist/commands/support/logs.js +2 -2
- package/dist/commands/template/apply.js +5 -4
- package/dist/commands/template/create.js +1 -1
- package/dist/commands/template/list.js +2 -1
- package/dist/commands/theme/add-names.d.ts +4 -0
- package/dist/commands/theme/add-names.js +11 -1
- package/dist/commands/theme/create.d.ts +2 -0
- package/dist/commands/theme/create.js +8 -0
- package/dist/commands/ticket/bulk.js +2 -2
- package/dist/commands/ticket/complete.js +2 -2
- package/dist/commands/ticket/create.js +21 -0
- package/dist/commands/ticket/delete.js +8 -0
- package/dist/commands/ticket/edit.js +25 -0
- package/dist/commands/ticket/index.js +2 -2
- package/dist/commands/ticket/link/block.d.ts +15 -0
- package/dist/commands/ticket/link/block.js +95 -0
- package/dist/commands/ticket/link/index.d.ts +14 -0
- package/dist/commands/ticket/link/index.js +96 -0
- package/dist/commands/ticket/list.d.ts +1 -0
- package/dist/commands/ticket/list.js +6 -0
- package/dist/commands/ticket/move.js +25 -2
- package/dist/commands/ticket/resolve.js +4 -5
- package/dist/commands/ticket/show.d.ts +13 -0
- package/dist/commands/ticket/show.js +16 -0
- package/dist/commands/ticket/template/apply.d.ts +26 -0
- package/dist/commands/ticket/template/apply.js +14 -0
- package/dist/commands/ticket/template/delete.d.ts +18 -0
- package/dist/commands/ticket/template/delete.js +61 -0
- package/dist/commands/ticket/template/list.d.ts +17 -0
- package/dist/commands/ticket/template/list.js +78 -0
- package/dist/commands/ticket/template/save.d.ts +17 -0
- package/dist/commands/ticket/template/save.js +97 -0
- package/dist/commands/ticket/view.js +30 -0
- package/dist/commands/work/index.js +4 -0
- package/dist/commands/work/ready.js +17 -0
- package/dist/commands/work/resolve.js +1 -1
- package/dist/commands/work/spawn.js +4 -4
- package/dist/commands/work/start.d.ts +1 -0
- package/dist/commands/work/start.js +203 -93
- package/dist/commands/work/status.d.ts +14 -0
- package/dist/commands/work/status.js +60 -0
- package/dist/commands/workflow/index.js +2 -1
- package/dist/commands/workflow/show.d.ts +13 -0
- package/dist/commands/workflow/show.js +16 -0
- package/dist/commands/workspace/add.js +15 -0
- package/dist/commands/workspace/list.js +2 -1
- package/dist/commands/workspace/prune.js +5 -5
- package/dist/lib/branch/index.d.ts +1 -0
- package/dist/lib/database/index.d.ts +1 -1
- package/dist/lib/database/index.js +20 -0
- package/dist/lib/execution/config.d.ts +15 -1
- package/dist/lib/execution/config.js +28 -0
- package/dist/lib/execution/devcontainer.js +3 -1
- package/dist/lib/execution/runners.d.ts +18 -2
- package/dist/lib/execution/runners.js +71 -29
- package/dist/lib/execution/session-utils.d.ts +11 -1
- package/dist/lib/execution/session-utils.js +26 -1
- package/dist/lib/execution/storage.d.ts +5 -0
- package/dist/lib/execution/storage.js +18 -3
- package/dist/lib/execution/types.d.ts +3 -0
- package/dist/lib/flags/resolver.js +1 -0
- package/dist/lib/mcp/helpers.d.ts +1 -2
- package/dist/lib/mcp/tools/board.js +4 -6
- package/dist/lib/mcp/tools/cli-passthrough.js +25 -6
- package/dist/lib/mcp/tools/diet.js +1 -0
- package/dist/lib/mcp/tools/epic.js +8 -3
- package/dist/lib/mcp/tools/index.d.ts +1 -0
- package/dist/lib/mcp/tools/index.js +1 -0
- package/dist/lib/mcp/tools/label.d.ts +6 -0
- package/dist/lib/mcp/tools/label.js +338 -0
- package/dist/lib/mcp/tools/spec.js +1 -1
- package/dist/lib/mcp/tools/ticket.js +57 -19
- package/dist/lib/mcp/tools/work.js +96 -6
- package/dist/lib/mcp/types.d.ts +10 -0
- package/dist/lib/multiline-input.js +8 -19
- package/dist/lib/pmo/base-command.d.ts +0 -1
- package/dist/lib/pmo/base-command.js +4 -5
- package/dist/lib/pmo/schema.d.ts +6 -0
- package/dist/lib/pmo/schema.js +44 -0
- package/dist/lib/pmo/storage/actions.js +1 -1
- package/dist/lib/pmo/storage/base.d.ts +6 -0
- package/dist/lib/pmo/storage/base.js +311 -52
- package/dist/lib/pmo/storage/index.d.ts +23 -1
- package/dist/lib/pmo/storage/index.js +59 -1
- package/dist/lib/pmo/storage/labels.d.ts +55 -0
- package/dist/lib/pmo/storage/labels.js +346 -0
- package/dist/lib/pmo/storage/tickets.js +17 -0
- package/dist/lib/pmo/storage/types.d.ts +25 -0
- package/dist/lib/pmo/types.d.ts +44 -0
- package/dist/lib/pmo/utils.js +1 -1
- package/dist/lib/prompt-command.d.ts +20 -0
- package/dist/lib/prompt-command.js +38 -2
- package/dist/lib/prompt-json.d.ts +36 -4
- package/dist/lib/prompt-json.js +129 -7
- package/dist/lib/styles.d.ts +37 -0
- package/dist/lib/styles.js +73 -0
- package/oclif.manifest.json +6399 -3799
- package/package.json +1 -1
|
@@ -71,6 +71,11 @@ export declare class ExecutionStorage {
|
|
|
71
71
|
* Returns the number of stale executions cleaned up.
|
|
72
72
|
*/
|
|
73
73
|
cleanupStaleExecutions(): number;
|
|
74
|
+
/**
|
|
75
|
+
* Find container sessions using prefix matching.
|
|
76
|
+
* Handles cases where the stored containerId format differs from docker ps output.
|
|
77
|
+
*/
|
|
78
|
+
private findContainerSessionsByPrefix;
|
|
74
79
|
/**
|
|
75
80
|
* Get list of host tmux session names
|
|
76
81
|
*/
|
|
@@ -215,9 +215,9 @@ export class ExecutionStorage {
|
|
|
215
215
|
}
|
|
216
216
|
let sessionExists = false;
|
|
217
217
|
if (exec.environment === 'devcontainer' && exec.containerId) {
|
|
218
|
-
// Check if session exists in container
|
|
219
|
-
const containerSessions =
|
|
220
|
-
sessionExists = containerSessions
|
|
218
|
+
// Check if session exists in container (use prefix matching for ID format differences)
|
|
219
|
+
const containerSessions = this.findContainerSessionsByPrefix(containerTmuxSessions, exec.containerId);
|
|
220
|
+
sessionExists = containerSessions.includes(exec.sessionId);
|
|
221
221
|
}
|
|
222
222
|
else {
|
|
223
223
|
// Check if session exists on host
|
|
@@ -231,6 +231,21 @@ export class ExecutionStorage {
|
|
|
231
231
|
}
|
|
232
232
|
return cleanedCount;
|
|
233
233
|
}
|
|
234
|
+
/**
|
|
235
|
+
* Find container sessions using prefix matching.
|
|
236
|
+
* Handles cases where the stored containerId format differs from docker ps output.
|
|
237
|
+
*/
|
|
238
|
+
findContainerSessionsByPrefix(containerTmuxSessions, containerId) {
|
|
239
|
+
const exact = containerTmuxSessions.get(containerId);
|
|
240
|
+
if (exact)
|
|
241
|
+
return exact;
|
|
242
|
+
for (const [key, sessions] of containerTmuxSessions) {
|
|
243
|
+
if (key.startsWith(containerId) || containerId.startsWith(key)) {
|
|
244
|
+
return sessions;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
return [];
|
|
248
|
+
}
|
|
234
249
|
/**
|
|
235
250
|
* Get list of host tmux session names
|
|
236
251
|
*/
|
|
@@ -87,6 +87,7 @@ export interface ExecutionContext {
|
|
|
87
87
|
actionEndPrompt?: string;
|
|
88
88
|
modifiesCode?: boolean;
|
|
89
89
|
customMessage?: string;
|
|
90
|
+
useApiKey?: boolean;
|
|
90
91
|
prFeedback?: string;
|
|
91
92
|
isRevision?: boolean;
|
|
92
93
|
}
|
|
@@ -111,6 +112,7 @@ export declare function getBranchType(category?: string): string;
|
|
|
111
112
|
* - agent: the AI agent doing the work
|
|
112
113
|
*/
|
|
113
114
|
export declare function generateBranchName(ticketId: string, ticketTitle: string, ownerName: string, agentName: string, category?: string): string;
|
|
115
|
+
export type AuthMethod = 'oauth' | 'apikey';
|
|
114
116
|
export interface ExecutionConfig {
|
|
115
117
|
defaultEnvironment: ExecutionEnvironment;
|
|
116
118
|
defaultExecutor: ExecutorType;
|
|
@@ -118,6 +120,7 @@ export interface ExecutionConfig {
|
|
|
118
120
|
shell: Shell;
|
|
119
121
|
outputMode: OutputMode;
|
|
120
122
|
sandboxed: boolean;
|
|
123
|
+
authMethod?: AuthMethod;
|
|
121
124
|
tmux: {
|
|
122
125
|
session: string;
|
|
123
126
|
layout: 'split' | 'window';
|
|
@@ -3,9 +3,8 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import { z } from 'zod';
|
|
5
5
|
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
6
|
-
import type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';
|
|
6
|
+
import type { CallToolResult, ServerRequest, ServerNotification } from '@modelcontextprotocol/sdk/types.js';
|
|
7
7
|
import type { RequestHandlerExtra } from '@modelcontextprotocol/sdk/shared/protocol.js';
|
|
8
|
-
import type { ServerRequest, ServerNotification } from '@modelcontextprotocol/sdk/types.js';
|
|
9
8
|
import type { Ticket } from '../pmo/types.js';
|
|
10
9
|
import type { McpToolResult } from './types.js';
|
|
11
10
|
/**
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
* MCP Board Tools
|
|
3
3
|
*/
|
|
4
4
|
import { z } from 'zod';
|
|
5
|
-
import { errorResponse, strictTool } from '../helpers.js';
|
|
5
|
+
import { formatTicket, errorResponse, strictTool } from '../helpers.js';
|
|
6
6
|
export function registerBoardTools(server, ctx) {
|
|
7
|
-
strictTool(server, '
|
|
7
|
+
strictTool(server, 'board_view', 'Show the kanban board', { project: z.string().optional().describe('Project ID') }, async (params) => {
|
|
8
8
|
try {
|
|
9
9
|
let projectId = params.project;
|
|
10
10
|
if (!projectId) {
|
|
@@ -27,10 +27,8 @@ export function registerBoardTools(server, ctx) {
|
|
|
27
27
|
position: col.position,
|
|
28
28
|
ticketCount: col.tickets.length,
|
|
29
29
|
tickets: col.tickets.map((t) => ({
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
priority: t.priority,
|
|
33
|
-
assignee: t.assignee,
|
|
30
|
+
...formatTicket(t),
|
|
31
|
+
labels: t.labels,
|
|
34
32
|
})),
|
|
35
33
|
})),
|
|
36
34
|
updatedAt: board.updatedAt.toISOString(),
|
|
@@ -17,9 +17,26 @@ export function registerAgentTools(server, ctx) {
|
|
|
17
17
|
return errorResponse(error);
|
|
18
18
|
}
|
|
19
19
|
});
|
|
20
|
-
strictTool(server, 'agent_status', 'Check agent status', {}, async () => {
|
|
20
|
+
strictTool(server, 'agent_status', 'Check agent status. With agent param, returns that agent\'s status. Without, auto-detects current agent or returns all agent statuses.', { agent: z.string().optional().describe('Agent name. If omitted, auto-detects current agent or returns all.') }, async (params) => {
|
|
21
21
|
try {
|
|
22
|
-
|
|
22
|
+
if (params.agent) {
|
|
23
|
+
const output = ctx.runCommand(`prlt agent status ${params.agent} --json`);
|
|
24
|
+
return textResponse(output);
|
|
25
|
+
}
|
|
26
|
+
// Try auto-detecting current agent via whoami
|
|
27
|
+
try {
|
|
28
|
+
const whoamiOutput = ctx.runCommand('prlt whoami --json');
|
|
29
|
+
const whoami = JSON.parse(whoamiOutput);
|
|
30
|
+
if (whoami.agent) {
|
|
31
|
+
const output = ctx.runCommand(`prlt agent status ${whoami.agent} --json`);
|
|
32
|
+
return textResponse(output);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
// whoami failed or no agent detected, fall through
|
|
37
|
+
}
|
|
38
|
+
// No agent detected - return all agent statuses
|
|
39
|
+
const output = ctx.runCommand('prlt agent status --json');
|
|
23
40
|
return textResponse(output);
|
|
24
41
|
}
|
|
25
42
|
catch (error) {
|
|
@@ -139,7 +156,7 @@ export function registerRepoTools(server, ctx) {
|
|
|
139
156
|
});
|
|
140
157
|
}
|
|
141
158
|
export function registerBranchTools(server, ctx) {
|
|
142
|
-
strictTool(server, 'branch_list', 'List branches', {}, async () => {
|
|
159
|
+
strictTool(server, 'branch_list', 'List branches (across all HQ repos if not in a git repo)', {}, async () => {
|
|
143
160
|
try {
|
|
144
161
|
const output = ctx.runCommand('prlt branch list');
|
|
145
162
|
return textResponse(output);
|
|
@@ -161,9 +178,11 @@ export function registerBranchTools(server, ctx) {
|
|
|
161
178
|
return errorResponse(error);
|
|
162
179
|
}
|
|
163
180
|
});
|
|
164
|
-
strictTool(server, 'branch_where', '
|
|
181
|
+
strictTool(server, 'branch_where', 'Find which directory a branch is checked out in', {
|
|
182
|
+
search: z.string().describe('Branch name or ticket ID to search for'),
|
|
183
|
+
}, async (params) => {
|
|
165
184
|
try {
|
|
166
|
-
const output = ctx.runCommand(
|
|
185
|
+
const output = ctx.runCommand(`prlt branch where ${params.search}`);
|
|
167
186
|
return textResponse(output);
|
|
168
187
|
}
|
|
169
188
|
catch (error) {
|
|
@@ -314,7 +333,7 @@ export function registerUtilityTools(server, ctx) {
|
|
|
314
333
|
});
|
|
315
334
|
strictTool(server, 'session_list', 'List tmux sessions', {}, async () => {
|
|
316
335
|
try {
|
|
317
|
-
const output = ctx.runCommand('prlt session list');
|
|
336
|
+
const output = ctx.runCommand('prlt session list --json');
|
|
318
337
|
return textResponse(output);
|
|
319
338
|
}
|
|
320
339
|
catch (error) {
|
|
@@ -71,7 +71,7 @@ export function registerEpicTools(server, ctx) {
|
|
|
71
71
|
return errorResponse(error);
|
|
72
72
|
}
|
|
73
73
|
});
|
|
74
|
-
strictTool(server, '
|
|
74
|
+
strictTool(server, 'epic_view', 'Get epic details with tickets', { id: z.string().describe('Epic ID') }, async (params) => {
|
|
75
75
|
try {
|
|
76
76
|
const epic = await ctx.storage.getEpic(params.id);
|
|
77
77
|
if (!epic)
|
|
@@ -83,9 +83,14 @@ export function registerEpicTools(server, ctx) {
|
|
|
83
83
|
text: JSON.stringify({
|
|
84
84
|
success: true,
|
|
85
85
|
epic: {
|
|
86
|
-
|
|
86
|
+
id: epic.id,
|
|
87
|
+
projectId: epic.projectId,
|
|
88
|
+
title: epic.title,
|
|
89
|
+
status: epic.status,
|
|
90
|
+
position: epic.position,
|
|
91
|
+
specId: epic.specId,
|
|
87
92
|
ticketCount: tickets.length,
|
|
88
|
-
tickets: tickets.map((t) => ({ id: t.id, title: t.title, statusName: t.statusName, priority: t.priority })),
|
|
93
|
+
tickets: tickets.map((t) => ({ id: t.id, title: t.title, statusName: t.statusName, priority: t.priority, category: t.category })),
|
|
89
94
|
createdAt: epic.createdAt.toISOString(),
|
|
90
95
|
updatedAt: epic.updatedAt.toISOString(),
|
|
91
96
|
},
|
|
@@ -16,4 +16,5 @@ export { registerCategoryTools } from './category.js';
|
|
|
16
16
|
export { registerTemplateTools } from './template.js';
|
|
17
17
|
export { registerViewTools } from './view.js';
|
|
18
18
|
export { registerDietTools } from './diet.js';
|
|
19
|
+
export { registerLabelTools } from './label.js';
|
|
19
20
|
export { registerAgentTools, registerDockerTools, registerRepoTools, registerBranchTools, registerGitHubTools, registerInitTools, registerUtilityTools, } from './cli-passthrough.js';
|
|
@@ -16,5 +16,6 @@ export { registerCategoryTools } from './category.js';
|
|
|
16
16
|
export { registerTemplateTools } from './template.js';
|
|
17
17
|
export { registerViewTools } from './view.js';
|
|
18
18
|
export { registerDietTools } from './diet.js';
|
|
19
|
+
export { registerLabelTools } from './label.js';
|
|
19
20
|
// CLI passthrough tools
|
|
20
21
|
export { registerAgentTools, registerDockerTools, registerRepoTools, registerBranchTools, registerGitHubTools, registerInitTools, registerUtilityTools, } from './cli-passthrough.js';
|
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP Label Tools
|
|
3
|
+
*/
|
|
4
|
+
import { z } from 'zod';
|
|
5
|
+
import { errorResponse, strictTool } from '../helpers.js';
|
|
6
|
+
export function registerLabelTools(server, ctx) {
|
|
7
|
+
// ===========================================================================
|
|
8
|
+
// Label Group Tools
|
|
9
|
+
// ===========================================================================
|
|
10
|
+
strictTool(server, 'label_group_list', 'List all label groups', {
|
|
11
|
+
search: z.string().optional().describe('Search in name/description'),
|
|
12
|
+
}, async (params) => {
|
|
13
|
+
try {
|
|
14
|
+
const groups = await ctx.storage.listLabelGroups({
|
|
15
|
+
search: params.search,
|
|
16
|
+
});
|
|
17
|
+
return {
|
|
18
|
+
content: [{
|
|
19
|
+
type: 'text',
|
|
20
|
+
text: JSON.stringify({
|
|
21
|
+
success: true,
|
|
22
|
+
count: groups.length,
|
|
23
|
+
groups: groups.map(g => ({
|
|
24
|
+
id: g.id,
|
|
25
|
+
name: g.name,
|
|
26
|
+
description: g.description,
|
|
27
|
+
isExclusive: g.isExclusive,
|
|
28
|
+
isRequired: g.isRequired,
|
|
29
|
+
position: g.position,
|
|
30
|
+
})),
|
|
31
|
+
}, null, 2),
|
|
32
|
+
}],
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
catch (error) {
|
|
36
|
+
return errorResponse(error);
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
strictTool(server, 'label_group_create', 'Create a new label group', {
|
|
40
|
+
name: z.string().describe('Group name (must be unique)'),
|
|
41
|
+
description: z.string().optional().describe('Group description'),
|
|
42
|
+
is_exclusive: z.boolean().optional().describe('Only one label from this group per ticket (default: true)'),
|
|
43
|
+
is_required: z.boolean().optional().describe('Must have one label from this group (default: false)'),
|
|
44
|
+
}, async (params) => {
|
|
45
|
+
try {
|
|
46
|
+
const group = await ctx.storage.createLabelGroup({
|
|
47
|
+
name: params.name,
|
|
48
|
+
description: params.description,
|
|
49
|
+
isExclusive: params.is_exclusive,
|
|
50
|
+
isRequired: params.is_required,
|
|
51
|
+
});
|
|
52
|
+
return {
|
|
53
|
+
content: [{
|
|
54
|
+
type: 'text',
|
|
55
|
+
text: JSON.stringify({
|
|
56
|
+
success: true,
|
|
57
|
+
group: {
|
|
58
|
+
id: group.id,
|
|
59
|
+
name: group.name,
|
|
60
|
+
description: group.description,
|
|
61
|
+
isExclusive: group.isExclusive,
|
|
62
|
+
isRequired: group.isRequired,
|
|
63
|
+
},
|
|
64
|
+
}, null, 2),
|
|
65
|
+
}],
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
catch (error) {
|
|
69
|
+
return errorResponse(error);
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
strictTool(server, 'label_group_update', 'Update a label group', {
|
|
73
|
+
id: z.string().describe('Group ID'),
|
|
74
|
+
name: z.string().optional().describe('New name'),
|
|
75
|
+
description: z.string().optional().describe('New description'),
|
|
76
|
+
is_exclusive: z.boolean().optional().describe('Only one label from this group per ticket'),
|
|
77
|
+
is_required: z.boolean().optional().describe('Must have one label from this group'),
|
|
78
|
+
}, async (params) => {
|
|
79
|
+
try {
|
|
80
|
+
const changes = {};
|
|
81
|
+
if (params.name !== undefined)
|
|
82
|
+
changes.name = params.name;
|
|
83
|
+
if (params.description !== undefined)
|
|
84
|
+
changes.description = params.description;
|
|
85
|
+
if (params.is_exclusive !== undefined)
|
|
86
|
+
changes.isExclusive = params.is_exclusive;
|
|
87
|
+
if (params.is_required !== undefined)
|
|
88
|
+
changes.isRequired = params.is_required;
|
|
89
|
+
const group = await ctx.storage.updateLabelGroup(params.id, changes);
|
|
90
|
+
return {
|
|
91
|
+
content: [{
|
|
92
|
+
type: 'text',
|
|
93
|
+
text: JSON.stringify({
|
|
94
|
+
success: true,
|
|
95
|
+
group: {
|
|
96
|
+
id: group.id,
|
|
97
|
+
name: group.name,
|
|
98
|
+
description: group.description,
|
|
99
|
+
isExclusive: group.isExclusive,
|
|
100
|
+
isRequired: group.isRequired,
|
|
101
|
+
},
|
|
102
|
+
}, null, 2),
|
|
103
|
+
}],
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
catch (error) {
|
|
107
|
+
return errorResponse(error);
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
strictTool(server, 'label_group_delete', 'Delete a label group (labels in the group become ungrouped)', {
|
|
111
|
+
id: z.string().describe('Group ID'),
|
|
112
|
+
}, async (params) => {
|
|
113
|
+
try {
|
|
114
|
+
await ctx.storage.deleteLabelGroup(params.id);
|
|
115
|
+
return {
|
|
116
|
+
content: [{
|
|
117
|
+
type: 'text',
|
|
118
|
+
text: JSON.stringify({ success: true, message: `Deleted label group ${params.id}` }, null, 2),
|
|
119
|
+
}],
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
catch (error) {
|
|
123
|
+
return errorResponse(error);
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
// ===========================================================================
|
|
127
|
+
// Label Tools
|
|
128
|
+
// ===========================================================================
|
|
129
|
+
strictTool(server, 'label_list', 'List all labels, optionally filtered by group', {
|
|
130
|
+
group: z.string().optional().describe('Filter by group ID'),
|
|
131
|
+
search: z.string().optional().describe('Search in name/description'),
|
|
132
|
+
}, async (params) => {
|
|
133
|
+
try {
|
|
134
|
+
const labels = await ctx.storage.listLabels({
|
|
135
|
+
groupId: params.group,
|
|
136
|
+
search: params.search,
|
|
137
|
+
});
|
|
138
|
+
return {
|
|
139
|
+
content: [{
|
|
140
|
+
type: 'text',
|
|
141
|
+
text: JSON.stringify({
|
|
142
|
+
success: true,
|
|
143
|
+
count: labels.length,
|
|
144
|
+
labels: labels.map(l => ({
|
|
145
|
+
id: l.id,
|
|
146
|
+
name: l.name,
|
|
147
|
+
color: l.color,
|
|
148
|
+
description: l.description,
|
|
149
|
+
groupId: l.groupId,
|
|
150
|
+
groupName: l.groupName,
|
|
151
|
+
isBuiltin: l.isBuiltin,
|
|
152
|
+
})),
|
|
153
|
+
}, null, 2),
|
|
154
|
+
}],
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
catch (error) {
|
|
158
|
+
return errorResponse(error);
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
strictTool(server, 'label_create', 'Create a new label', {
|
|
162
|
+
name: z.string().describe('Label name'),
|
|
163
|
+
color: z.string().optional().describe('Label color (hex, e.g. #ff0000)'),
|
|
164
|
+
description: z.string().optional().describe('Label description'),
|
|
165
|
+
group_id: z.string().optional().describe('Label group ID to add this label to'),
|
|
166
|
+
}, async (params) => {
|
|
167
|
+
try {
|
|
168
|
+
const label = await ctx.storage.createLabel({
|
|
169
|
+
name: params.name,
|
|
170
|
+
color: params.color,
|
|
171
|
+
description: params.description,
|
|
172
|
+
groupId: params.group_id,
|
|
173
|
+
});
|
|
174
|
+
return {
|
|
175
|
+
content: [{
|
|
176
|
+
type: 'text',
|
|
177
|
+
text: JSON.stringify({
|
|
178
|
+
success: true,
|
|
179
|
+
label: {
|
|
180
|
+
id: label.id,
|
|
181
|
+
name: label.name,
|
|
182
|
+
color: label.color,
|
|
183
|
+
description: label.description,
|
|
184
|
+
groupId: label.groupId,
|
|
185
|
+
groupName: label.groupName,
|
|
186
|
+
},
|
|
187
|
+
}, null, 2),
|
|
188
|
+
}],
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
catch (error) {
|
|
192
|
+
return errorResponse(error);
|
|
193
|
+
}
|
|
194
|
+
});
|
|
195
|
+
strictTool(server, 'label_update', 'Update a label (rename, recolor, regroup)', {
|
|
196
|
+
id: z.string().describe('Label ID'),
|
|
197
|
+
name: z.string().optional().describe('New name'),
|
|
198
|
+
color: z.string().optional().describe('New color (hex)'),
|
|
199
|
+
description: z.string().optional().describe('New description'),
|
|
200
|
+
group_id: z.string().optional().describe('Move to different group'),
|
|
201
|
+
}, async (params) => {
|
|
202
|
+
try {
|
|
203
|
+
const changes = {};
|
|
204
|
+
if (params.name !== undefined)
|
|
205
|
+
changes.name = params.name;
|
|
206
|
+
if (params.color !== undefined)
|
|
207
|
+
changes.color = params.color;
|
|
208
|
+
if (params.description !== undefined)
|
|
209
|
+
changes.description = params.description;
|
|
210
|
+
if (params.group_id !== undefined)
|
|
211
|
+
changes.groupId = params.group_id;
|
|
212
|
+
const label = await ctx.storage.updateLabel(params.id, changes);
|
|
213
|
+
return {
|
|
214
|
+
content: [{
|
|
215
|
+
type: 'text',
|
|
216
|
+
text: JSON.stringify({
|
|
217
|
+
success: true,
|
|
218
|
+
label: {
|
|
219
|
+
id: label.id,
|
|
220
|
+
name: label.name,
|
|
221
|
+
color: label.color,
|
|
222
|
+
description: label.description,
|
|
223
|
+
groupId: label.groupId,
|
|
224
|
+
groupName: label.groupName,
|
|
225
|
+
},
|
|
226
|
+
}, null, 2),
|
|
227
|
+
}],
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
catch (error) {
|
|
231
|
+
return errorResponse(error);
|
|
232
|
+
}
|
|
233
|
+
});
|
|
234
|
+
strictTool(server, 'label_delete', 'Delete a label (removes from all tickets)', {
|
|
235
|
+
id: z.string().describe('Label ID'),
|
|
236
|
+
}, async (params) => {
|
|
237
|
+
try {
|
|
238
|
+
await ctx.storage.deleteLabel(params.id);
|
|
239
|
+
return {
|
|
240
|
+
content: [{
|
|
241
|
+
type: 'text',
|
|
242
|
+
text: JSON.stringify({ success: true, message: `Deleted label ${params.id}` }, null, 2),
|
|
243
|
+
}],
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
catch (error) {
|
|
247
|
+
return errorResponse(error);
|
|
248
|
+
}
|
|
249
|
+
});
|
|
250
|
+
// ===========================================================================
|
|
251
|
+
// Ticket-Label Association Tools
|
|
252
|
+
// ===========================================================================
|
|
253
|
+
strictTool(server, 'ticket_add_label', 'Add a label to a ticket. For exclusive groups, replaces existing label from same group.', {
|
|
254
|
+
ticket_id: z.string().describe('Ticket ID'),
|
|
255
|
+
label: z.string().describe('Label ID or name (supports group:name format)'),
|
|
256
|
+
}, async (params) => {
|
|
257
|
+
try {
|
|
258
|
+
// Try by ID first, then by name
|
|
259
|
+
const labelById = await ctx.storage.getLabel(params.label);
|
|
260
|
+
if (labelById) {
|
|
261
|
+
await ctx.storage.addLabelToTicket(params.ticket_id, labelById.id);
|
|
262
|
+
}
|
|
263
|
+
else {
|
|
264
|
+
await ctx.storage.addLabelToTicketByName(params.ticket_id, params.label);
|
|
265
|
+
}
|
|
266
|
+
const labels = await ctx.storage.getLabelsForTicket(params.ticket_id);
|
|
267
|
+
return {
|
|
268
|
+
content: [{
|
|
269
|
+
type: 'text',
|
|
270
|
+
text: JSON.stringify({
|
|
271
|
+
success: true,
|
|
272
|
+
message: `Label added to ${params.ticket_id}`,
|
|
273
|
+
labels: labels.map(l => ({
|
|
274
|
+
id: l.id,
|
|
275
|
+
name: l.name,
|
|
276
|
+
groupName: l.groupName,
|
|
277
|
+
})),
|
|
278
|
+
}, null, 2),
|
|
279
|
+
}],
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
catch (error) {
|
|
283
|
+
return errorResponse(error);
|
|
284
|
+
}
|
|
285
|
+
});
|
|
286
|
+
strictTool(server, 'ticket_remove_label', 'Remove a label from a ticket', {
|
|
287
|
+
ticket_id: z.string().describe('Ticket ID'),
|
|
288
|
+
label: z.string().describe('Label ID or name'),
|
|
289
|
+
}, async (params) => {
|
|
290
|
+
try {
|
|
291
|
+
const labelById = await ctx.storage.getLabel(params.label);
|
|
292
|
+
if (labelById) {
|
|
293
|
+
await ctx.storage.removeLabelFromTicket(params.ticket_id, labelById.id);
|
|
294
|
+
}
|
|
295
|
+
else {
|
|
296
|
+
await ctx.storage.removeLabelFromTicketByName(params.ticket_id, params.label);
|
|
297
|
+
}
|
|
298
|
+
return {
|
|
299
|
+
content: [{
|
|
300
|
+
type: 'text',
|
|
301
|
+
text: JSON.stringify({
|
|
302
|
+
success: true,
|
|
303
|
+
message: `Label removed from ${params.ticket_id}`,
|
|
304
|
+
}, null, 2),
|
|
305
|
+
}],
|
|
306
|
+
};
|
|
307
|
+
}
|
|
308
|
+
catch (error) {
|
|
309
|
+
return errorResponse(error);
|
|
310
|
+
}
|
|
311
|
+
});
|
|
312
|
+
strictTool(server, 'ticket_labels', 'List all labels on a ticket', {
|
|
313
|
+
ticket_id: z.string().describe('Ticket ID'),
|
|
314
|
+
}, async (params) => {
|
|
315
|
+
try {
|
|
316
|
+
const labels = await ctx.storage.getLabelsForTicket(params.ticket_id);
|
|
317
|
+
return {
|
|
318
|
+
content: [{
|
|
319
|
+
type: 'text',
|
|
320
|
+
text: JSON.stringify({
|
|
321
|
+
success: true,
|
|
322
|
+
count: labels.length,
|
|
323
|
+
labels: labels.map(l => ({
|
|
324
|
+
id: l.id,
|
|
325
|
+
name: l.name,
|
|
326
|
+
color: l.color,
|
|
327
|
+
groupId: l.groupId,
|
|
328
|
+
groupName: l.groupName,
|
|
329
|
+
})),
|
|
330
|
+
}, null, 2),
|
|
331
|
+
}],
|
|
332
|
+
};
|
|
333
|
+
}
|
|
334
|
+
catch (error) {
|
|
335
|
+
return errorResponse(error);
|
|
336
|
+
}
|
|
337
|
+
});
|
|
338
|
+
}
|
|
@@ -67,7 +67,7 @@ export function registerSpecTools(server, ctx) {
|
|
|
67
67
|
return errorResponse(error);
|
|
68
68
|
}
|
|
69
69
|
});
|
|
70
|
-
strictTool(server, '
|
|
70
|
+
strictTool(server, 'spec_view', 'Get spec details', { id: z.string().describe('Spec ID') }, async (params) => {
|
|
71
71
|
try {
|
|
72
72
|
const spec = await ctx.storage.getSpec(params.id);
|
|
73
73
|
if (!spec)
|