@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
|
@@ -5,7 +5,7 @@ import { z } from 'zod';
|
|
|
5
5
|
import { formatTicket, formatTicketFull, errorResponse, strictTool } from '../helpers.js';
|
|
6
6
|
import { getWorkspacePriorities, setWorkspacePriorities } from '../../pmo/utils.js';
|
|
7
7
|
export function registerTicketTools(server, ctx) {
|
|
8
|
-
strictTool(server, 'ticket_list', 'List tickets with optional filters', {
|
|
8
|
+
strictTool(server, 'ticket_list', 'List tickets with optional filters. Returns summary fields only (no descriptions). Use ticket_show for full details.', {
|
|
9
9
|
project: z.string().optional().describe('Project ID'),
|
|
10
10
|
column: z.string().optional().describe('Filter by column/status'),
|
|
11
11
|
priority: z.string().optional().describe('Filter by priority (uses workspace priority scale)'),
|
|
@@ -14,10 +14,14 @@ export function registerTicketTools(server, ctx) {
|
|
|
14
14
|
owner: z.string().optional().describe('Filter by owner'),
|
|
15
15
|
search: z.string().optional().describe('Search in title/description'),
|
|
16
16
|
epic: z.string().optional().describe('Filter by epic ID'),
|
|
17
|
+
label: z.string().optional().describe('Filter by label name'),
|
|
18
|
+
label_group: z.string().optional().describe('Filter by label group name'),
|
|
17
19
|
all_projects: z.boolean().optional().describe('List from all projects'),
|
|
20
|
+
limit: z.number().min(1).optional().describe('Maximum number of tickets to return (default: 50)'),
|
|
21
|
+
offset: z.number().min(0).optional().describe('Number of tickets to skip for pagination (default: 0)'),
|
|
18
22
|
}, async (params) => {
|
|
19
23
|
try {
|
|
20
|
-
const
|
|
24
|
+
const allTickets = await ctx.storage.listTickets(params.all_projects ? undefined : params.project, {
|
|
21
25
|
column: params.column,
|
|
22
26
|
priority: params.priority,
|
|
23
27
|
category: params.category,
|
|
@@ -25,30 +29,36 @@ export function registerTicketTools(server, ctx) {
|
|
|
25
29
|
owner: params.owner,
|
|
26
30
|
search: params.search,
|
|
27
31
|
epic: params.epic,
|
|
32
|
+
label: params.label,
|
|
33
|
+
labelGroup: params.label_group,
|
|
28
34
|
allProjects: params.all_projects,
|
|
29
35
|
});
|
|
36
|
+
const total = allTickets.length;
|
|
37
|
+
const offset = params.offset ?? 0;
|
|
38
|
+
const limit = params.limit ?? 50;
|
|
39
|
+
const tickets = allTickets.slice(offset, offset + limit);
|
|
30
40
|
return {
|
|
31
41
|
content: [{
|
|
32
42
|
type: 'text',
|
|
33
43
|
text: JSON.stringify({
|
|
34
44
|
success: true,
|
|
45
|
+
total,
|
|
35
46
|
count: tickets.length,
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
updatedAt: t.updatedAt.toISOString(),
|
|
47
|
+
offset,
|
|
48
|
+
limit,
|
|
49
|
+
tickets: await Promise.all(tickets.map(async (t) => {
|
|
50
|
+
const ticketLabels = await ctx.storage.getLabelsForTicket(t.id);
|
|
51
|
+
return {
|
|
52
|
+
id: t.id,
|
|
53
|
+
title: t.title,
|
|
54
|
+
priority: t.priority,
|
|
55
|
+
category: t.category,
|
|
56
|
+
statusName: t.statusName,
|
|
57
|
+
statusCategory: t.statusCategory,
|
|
58
|
+
assignee: t.assignee,
|
|
59
|
+
position: t.position,
|
|
60
|
+
labels: ticketLabels.map(l => ({ id: l.id, name: l.name, groupName: l.groupName })),
|
|
61
|
+
};
|
|
52
62
|
})),
|
|
53
63
|
}, null, 2),
|
|
54
64
|
}],
|
|
@@ -91,6 +101,24 @@ export function registerTicketTools(server, ctx) {
|
|
|
91
101
|
labels: params.labels,
|
|
92
102
|
subtasks: params.subtasks?.map((title) => ({ id: '', title, done: false })),
|
|
93
103
|
});
|
|
104
|
+
// Add structured labels from the labels param via junction table
|
|
105
|
+
if (params.labels && params.labels.length > 0) {
|
|
106
|
+
for (const labelName of params.labels) {
|
|
107
|
+
try {
|
|
108
|
+
// Try to add as structured label (by name or ID)
|
|
109
|
+
const labelById = await ctx.storage.getLabel(labelName);
|
|
110
|
+
if (labelById) {
|
|
111
|
+
await ctx.storage.addLabelToTicket(ticket.id, labelById.id);
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
await ctx.storage.addLabelToTicketByName(ticket.id, labelName);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
catch {
|
|
118
|
+
// If label doesn't exist in the label system, it stays only in the legacy JSON array
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
94
122
|
return {
|
|
95
123
|
content: [{
|
|
96
124
|
type: 'text',
|
|
@@ -107,10 +135,20 @@ export function registerTicketTools(server, ctx) {
|
|
|
107
135
|
const ticket = await ctx.storage.getTicket(params.id);
|
|
108
136
|
if (!ticket)
|
|
109
137
|
throw new Error(`Ticket not found: ${params.id}`);
|
|
138
|
+
const ticketLabels = await ctx.storage.getLabelsForTicket(params.id);
|
|
139
|
+
const ticketData = formatTicketFull(ticket);
|
|
140
|
+
// Override labels with structured label data from junction table
|
|
141
|
+
ticketData.labels = ticketLabels.map(l => ({
|
|
142
|
+
id: l.id,
|
|
143
|
+
name: l.name,
|
|
144
|
+
color: l.color,
|
|
145
|
+
groupId: l.groupId,
|
|
146
|
+
groupName: l.groupName,
|
|
147
|
+
}));
|
|
110
148
|
return {
|
|
111
149
|
content: [{
|
|
112
150
|
type: 'text',
|
|
113
|
-
text: JSON.stringify({ success: true, ticket:
|
|
151
|
+
text: JSON.stringify({ success: true, ticket: ticketData }, null, 2),
|
|
114
152
|
}],
|
|
115
153
|
};
|
|
116
154
|
}
|
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import { z } from 'zod';
|
|
5
5
|
import { formatTicket, errorResponse, strictTool } from '../helpers.js';
|
|
6
|
+
import { spawnAgentForTicket } from '../../execution/spawner.js';
|
|
7
|
+
import { createEphemeralAgent } from '../../agents/commands.js';
|
|
6
8
|
export function registerWorkTools(server, ctx) {
|
|
7
9
|
strictTool(server, 'work_status', 'Get current work status (in-progress tickets)', {}, async () => {
|
|
8
10
|
try {
|
|
@@ -31,7 +33,7 @@ export function registerWorkTools(server, ctx) {
|
|
|
31
33
|
return errorResponse(error);
|
|
32
34
|
}
|
|
33
35
|
});
|
|
34
|
-
strictTool(server, '
|
|
36
|
+
strictTool(server, 'work_assign', 'Assign a ticket to someone for work preparation (does NOT move to In Progress — use the CLI "work start" command to actually start work with an agent/session)', {
|
|
35
37
|
ticket_id: z.string().describe('Ticket ID'),
|
|
36
38
|
assignee: z.string().optional().describe('Who is working'),
|
|
37
39
|
}, async (params) => {
|
|
@@ -42,16 +44,14 @@ export function registerWorkTools(server, ctx) {
|
|
|
42
44
|
if (params.assignee) {
|
|
43
45
|
await ctx.storage.updateTicket(params.ticket_id, { assignee: params.assignee });
|
|
44
46
|
}
|
|
45
|
-
const
|
|
46
|
-
const progressCol = columns.find((c) => c.toLowerCase().includes('progress') || c.toLowerCase().includes('doing')) || columns[Math.min(1, columns.length - 1)];
|
|
47
|
-
const moved = await ctx.storage.moveTicket(ticket.projectId, params.ticket_id, progressCol);
|
|
47
|
+
const updated = await ctx.storage.getTicket(params.ticket_id);
|
|
48
48
|
return {
|
|
49
49
|
content: [{
|
|
50
50
|
type: 'text',
|
|
51
51
|
text: JSON.stringify({
|
|
52
52
|
success: true,
|
|
53
|
-
ticket: formatTicket(
|
|
54
|
-
message: `
|
|
53
|
+
ticket: formatTicket(updated),
|
|
54
|
+
message: `Assigned ${updated.id}: ${updated.title}${params.assignee ? ` to ${params.assignee}` : ''}`,
|
|
55
55
|
}, null, 2),
|
|
56
56
|
}],
|
|
57
57
|
};
|
|
@@ -129,4 +129,94 @@ export function registerWorkTools(server, ctx) {
|
|
|
129
129
|
return errorResponse(error);
|
|
130
130
|
}
|
|
131
131
|
});
|
|
132
|
+
strictTool(server, 'work_start', 'Start work on a ticket — spawns an agent with a running container/session, creates a git branch, and moves ticket to In Progress only after successful spawn', {
|
|
133
|
+
ticket_id: z.string().describe('Ticket ID to start work on'),
|
|
134
|
+
agent: z.string().optional().describe('Agent name to assign (defaults to creating an ephemeral agent)'),
|
|
135
|
+
environment: z.enum(['devcontainer', 'host']).optional().describe('Execution environment (default: devcontainer if available)'),
|
|
136
|
+
display_mode: z.enum(['background', 'terminal']).optional().describe('Display mode (default: background — MCP runs headless)'),
|
|
137
|
+
skip_permissions: z.boolean().optional().describe('Skip permission prompts (danger mode, default: false)'),
|
|
138
|
+
create_pr: z.boolean().optional().describe('Create PR when work is ready (default: false)'),
|
|
139
|
+
}, async (params) => {
|
|
140
|
+
try {
|
|
141
|
+
// Require workspace context for spawn operations
|
|
142
|
+
if (!ctx.getWorkspaceContext) {
|
|
143
|
+
throw new Error('Workspace not initialized. work_start requires a workspace with agents. Run "prlt init" first.');
|
|
144
|
+
}
|
|
145
|
+
const { workspaceInfo, executionStorage, db, pmoPath } = ctx.getWorkspaceContext();
|
|
146
|
+
// Validate ticket exists
|
|
147
|
+
const ticket = await ctx.storage.getTicket(params.ticket_id);
|
|
148
|
+
if (!ticket)
|
|
149
|
+
throw new Error(`Ticket not found: ${params.ticket_id}`);
|
|
150
|
+
// Check ticket is not blocked
|
|
151
|
+
if (ticket.blockedBy && ticket.blockedBy.length > 0) {
|
|
152
|
+
throw new Error(`Ticket ${ticket.id} is blocked by: ${ticket.blockedBy.join(', ')}. Resolve blockers first.`);
|
|
153
|
+
}
|
|
154
|
+
// Check for existing running execution
|
|
155
|
+
const runningExec = executionStorage.getRunningExecution(ticket.id);
|
|
156
|
+
if (runningExec) {
|
|
157
|
+
throw new Error(`Ticket ${ticket.id} already has a running execution: ${runningExec.id} (agent: ${runningExec.agentName})`);
|
|
158
|
+
}
|
|
159
|
+
// Select or create agent
|
|
160
|
+
let agentName;
|
|
161
|
+
if (params.agent) {
|
|
162
|
+
// Use specified agent — verify it exists
|
|
163
|
+
const agentExists = workspaceInfo.agents.some(a => a.name === params.agent);
|
|
164
|
+
if (!agentExists) {
|
|
165
|
+
throw new Error(`Agent "${params.agent}" not found. Available agents: ${workspaceInfo.agents.map(a => a.name).join(', ') || 'none'}`);
|
|
166
|
+
}
|
|
167
|
+
agentName = params.agent;
|
|
168
|
+
}
|
|
169
|
+
else {
|
|
170
|
+
// Create an ephemeral agent (default for MCP)
|
|
171
|
+
const ephemeralResult = await createEphemeralAgent(workspaceInfo);
|
|
172
|
+
agentName = ephemeralResult.name;
|
|
173
|
+
}
|
|
174
|
+
// Spawn the agent with background mode (MCP is headless)
|
|
175
|
+
const displayMode = params.display_mode || 'background';
|
|
176
|
+
const environment = params.environment;
|
|
177
|
+
const result = await spawnAgentForTicket(ticket, agentName, ctx.storage, executionStorage, workspaceInfo, db, pmoPath, {
|
|
178
|
+
environment,
|
|
179
|
+
displayMode,
|
|
180
|
+
skipPermissions: params.skip_permissions ?? false,
|
|
181
|
+
createPR: params.create_pr ?? false,
|
|
182
|
+
skipRemoteCheck: false,
|
|
183
|
+
});
|
|
184
|
+
if (result.success) {
|
|
185
|
+
// Fetch updated ticket to return current state
|
|
186
|
+
const updatedTicket = await ctx.storage.getTicket(params.ticket_id);
|
|
187
|
+
return {
|
|
188
|
+
content: [{
|
|
189
|
+
type: 'text',
|
|
190
|
+
text: JSON.stringify({
|
|
191
|
+
success: true,
|
|
192
|
+
executionId: result.executionId,
|
|
193
|
+
ticketId: result.ticketId,
|
|
194
|
+
agent: result.agentName,
|
|
195
|
+
status: 'running',
|
|
196
|
+
ticket: updatedTicket ? formatTicket(updatedTicket) : undefined,
|
|
197
|
+
message: `Started work on ${ticket.id}: ${ticket.title} (agent: ${agentName})`,
|
|
198
|
+
}, null, 2),
|
|
199
|
+
}],
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
else {
|
|
203
|
+
return {
|
|
204
|
+
content: [{
|
|
205
|
+
type: 'text',
|
|
206
|
+
text: JSON.stringify({
|
|
207
|
+
success: false,
|
|
208
|
+
ticketId: result.ticketId,
|
|
209
|
+
agent: result.agentName,
|
|
210
|
+
error: result.error || 'Spawn failed',
|
|
211
|
+
message: `Failed to start work on ${ticket.id}: ${result.error}`,
|
|
212
|
+
}, null, 2),
|
|
213
|
+
}],
|
|
214
|
+
isError: true,
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
catch (error) {
|
|
219
|
+
return errorResponse(error);
|
|
220
|
+
}
|
|
221
|
+
});
|
|
132
222
|
}
|
package/dist/lib/mcp/types.d.ts
CHANGED
|
@@ -3,9 +3,19 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
5
5
|
import type { SQLiteStorage } from '../pmo/storage/index.js';
|
|
6
|
+
import type Database from 'better-sqlite3';
|
|
7
|
+
import type { WorkspaceInfo } from '../agents/commands.js';
|
|
8
|
+
import type { ExecutionStorage } from '../execution/storage.js';
|
|
6
9
|
export interface McpToolContext {
|
|
7
10
|
storage: SQLiteStorage;
|
|
8
11
|
runCommand: (cmd: string) => string;
|
|
12
|
+
/** Workspace info — available when running in a workspace with agents */
|
|
13
|
+
getWorkspaceContext?: () => {
|
|
14
|
+
workspaceInfo: WorkspaceInfo;
|
|
15
|
+
executionStorage: ExecutionStorage;
|
|
16
|
+
db: Database.Database;
|
|
17
|
+
pmoPath: string;
|
|
18
|
+
};
|
|
9
19
|
}
|
|
10
20
|
export type McpToolResult = {
|
|
11
21
|
content: Array<{
|
|
@@ -13,16 +13,17 @@
|
|
|
13
13
|
* });
|
|
14
14
|
* ```
|
|
15
15
|
*/
|
|
16
|
-
import * as readline from 'readline';
|
|
16
|
+
import * as readline from 'node:readline';
|
|
17
17
|
import chalk from 'chalk';
|
|
18
|
+
import { isNonTTY } from './prompt-json.js';
|
|
18
19
|
// ANSI escape codes for terminal control
|
|
19
|
-
const ESC = '\
|
|
20
|
+
const ESC = '\u001B';
|
|
20
21
|
const CSI = `${ESC}[`;
|
|
21
22
|
// Control characters
|
|
22
|
-
const CTRL_C = '\
|
|
23
|
-
const CTRL_D = '\
|
|
24
|
-
const BACKSPACE = '\
|
|
25
|
-
const DELETE = '\
|
|
23
|
+
const CTRL_C = '\u0003';
|
|
24
|
+
const CTRL_D = '\u0004';
|
|
25
|
+
const BACKSPACE = '\u007F';
|
|
26
|
+
const DELETE = '\u001B[3~';
|
|
26
27
|
const ENTER = '\r';
|
|
27
28
|
const NEWLINE = '\n';
|
|
28
29
|
// Arrow keys (CSI sequences)
|
|
@@ -60,18 +61,6 @@ function moveDown(n) {
|
|
|
60
61
|
function moveToColumn(col) {
|
|
61
62
|
process.stdout.write(`${CSI}${col + 1}G`);
|
|
62
63
|
}
|
|
63
|
-
/**
|
|
64
|
-
* Clear from cursor to end of screen
|
|
65
|
-
*/
|
|
66
|
-
function clearToEnd() {
|
|
67
|
-
process.stdout.write(`${CSI}J`);
|
|
68
|
-
}
|
|
69
|
-
/**
|
|
70
|
-
* Hide cursor
|
|
71
|
-
*/
|
|
72
|
-
function hideCursor() {
|
|
73
|
-
process.stdout.write(`${CSI}?25l`);
|
|
74
|
-
}
|
|
75
64
|
/**
|
|
76
65
|
* Show cursor
|
|
77
66
|
*/
|
|
@@ -95,7 +84,7 @@ function showCursor() {
|
|
|
95
84
|
export async function multiLineInput(options) {
|
|
96
85
|
const { message, default: defaultValue = '', hint = 'Ctrl+D to finish, Ctrl+C to cancel', required = false, validate, } = options;
|
|
97
86
|
// If not a TTY, return the default value
|
|
98
|
-
if (
|
|
87
|
+
if (isNonTTY()) {
|
|
99
88
|
return { value: defaultValue, cancelled: false };
|
|
100
89
|
}
|
|
101
90
|
return new Promise((resolve) => {
|
|
@@ -192,7 +192,6 @@ export declare abstract class PMOCommand extends PromptCommand {
|
|
|
192
192
|
* @param code - Error code for JSON output (e.g., 'NOT_FOUND', 'DOCKER_NOT_RUNNING')
|
|
193
193
|
* @param message - Human-readable error message (used in both modes)
|
|
194
194
|
* @param options - Configuration for error handling
|
|
195
|
-
* @returns never - always throws or exits
|
|
196
195
|
*
|
|
197
196
|
* @example
|
|
198
197
|
* ```typescript
|
|
@@ -3,7 +3,7 @@ import inquirer from 'inquirer';
|
|
|
3
3
|
import { getPMOContext } from './pmo-context.js';
|
|
4
4
|
import { styles } from '../styles.js';
|
|
5
5
|
import { PromptCommand } from '../prompt-command.js';
|
|
6
|
-
import { shouldOutputJson, outputPromptAsJson, outputErrorAsJson, createMetadata, } from '../prompt-json.js';
|
|
6
|
+
import { shouldOutputJson, isNonTTY, outputPromptAsJson, outputErrorAsJson, createMetadata, } from '../prompt-json.js';
|
|
7
7
|
/**
|
|
8
8
|
* Base flags for JSON/agent mode support
|
|
9
9
|
* Include these in your command's flags by spreading: ...jsonModeFlags
|
|
@@ -168,7 +168,7 @@ export class PMOCommand extends PromptCommand {
|
|
|
168
168
|
return numA - numB;
|
|
169
169
|
});
|
|
170
170
|
// Auto-detect non-TTY: switch to JSON mode when no TTY present
|
|
171
|
-
const effectiveJsonMode = options?.jsonMode ?? (
|
|
171
|
+
const effectiveJsonMode = options?.jsonMode ?? (isNonTTY()
|
|
172
172
|
? {
|
|
173
173
|
flags: { json: true },
|
|
174
174
|
commandName: this.id ?? 'unknown',
|
|
@@ -234,7 +234,7 @@ export class PMOCommand extends PromptCommand {
|
|
|
234
234
|
async selectFromList(options) {
|
|
235
235
|
const { message, items, getName, getValue, getCommand, jsonMode, allowCancel = false, cancelValue, } = options;
|
|
236
236
|
// Auto-detect non-TTY: switch to JSON mode when no TTY present
|
|
237
|
-
const effectiveJsonMode = jsonMode ?? (
|
|
237
|
+
const effectiveJsonMode = jsonMode ?? (isNonTTY()
|
|
238
238
|
? { flags: { json: true }, commandName: this.id ?? 'unknown' }
|
|
239
239
|
: null);
|
|
240
240
|
// Build choices with command field
|
|
@@ -285,7 +285,7 @@ export class PMOCommand extends PromptCommand {
|
|
|
285
285
|
async promptForInput(options) {
|
|
286
286
|
const { message, fieldName, defaultValue, validate, jsonMode } = options;
|
|
287
287
|
// Auto-detect non-TTY: switch to JSON mode when no TTY present
|
|
288
|
-
const effectiveJsonMode = jsonMode ?? (
|
|
288
|
+
const effectiveJsonMode = jsonMode ?? (isNonTTY()
|
|
289
289
|
? { flags: { json: true }, commandName: this.id ?? 'unknown', commandHint: '', example: undefined }
|
|
290
290
|
: null);
|
|
291
291
|
// Check for JSON mode
|
|
@@ -323,7 +323,6 @@ export class PMOCommand extends PromptCommand {
|
|
|
323
323
|
* @param code - Error code for JSON output (e.g., 'NOT_FOUND', 'DOCKER_NOT_RUNNING')
|
|
324
324
|
* @param message - Human-readable error message (used in both modes)
|
|
325
325
|
* @param options - Configuration for error handling
|
|
326
|
-
* @returns never - always throws or exits
|
|
327
326
|
*
|
|
328
327
|
* @example
|
|
329
328
|
* ```typescript
|
package/dist/lib/pmo/schema.d.ts
CHANGED
|
@@ -35,6 +35,9 @@ export declare const PMO_TABLES: {
|
|
|
35
35
|
readonly ticket_templates: "pmo_ticket_templates";
|
|
36
36
|
readonly roadmaps: "pmo_roadmaps";
|
|
37
37
|
readonly roadmap_projects: "pmo_roadmap_projects";
|
|
38
|
+
readonly label_groups: "pmo_label_groups";
|
|
39
|
+
readonly labels: "pmo_labels";
|
|
40
|
+
readonly ticket_labels: "pmo_ticket_labels";
|
|
38
41
|
readonly columns: "pmo_columns";
|
|
39
42
|
readonly board_tickets: "pmo_board_tickets";
|
|
40
43
|
readonly statuses: "pmo_statuses";
|
|
@@ -71,6 +74,9 @@ export declare const PMO_TABLE_SCHEMAS: {
|
|
|
71
74
|
readonly phase_templates: "\n CREATE TABLE IF NOT EXISTS pmo_phase_templates (\n id TEXT PRIMARY KEY,\n name TEXT NOT NULL UNIQUE,\n description TEXT,\n is_builtin INTEGER NOT NULL DEFAULT 0,\n phases TEXT NOT NULL,\n created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP\n )";
|
|
72
75
|
readonly actions: "\n CREATE TABLE IF NOT EXISTS pmo_actions (\n id TEXT PRIMARY KEY,\n name TEXT NOT NULL UNIQUE,\n description TEXT,\n prompt TEXT NOT NULL,\n end_prompt TEXT,\n suggested_for_categories TEXT,\n default_move_to_category TEXT,\n modifies_code INTEGER NOT NULL DEFAULT 1,\n is_builtin INTEGER NOT NULL DEFAULT 0,\n position INTEGER NOT NULL DEFAULT 0,\n created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP\n )";
|
|
73
76
|
readonly ticket_templates: "\n CREATE TABLE IF NOT EXISTS pmo_ticket_templates (\n id TEXT PRIMARY KEY,\n name TEXT NOT NULL UNIQUE,\n description TEXT,\n is_builtin INTEGER NOT NULL DEFAULT 0,\n title_pattern TEXT,\n description_template TEXT,\n default_priority TEXT,\n default_category TEXT,\n default_status_id TEXT,\n default_assignee TEXT,\n default_owner TEXT,\n default_labels TEXT NOT NULL DEFAULT '[]',\n suggested_subtasks TEXT NOT NULL DEFAULT '[]',\n created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP\n )";
|
|
77
|
+
readonly label_groups: "\n CREATE TABLE IF NOT EXISTS pmo_label_groups (\n id TEXT PRIMARY KEY,\n name TEXT NOT NULL UNIQUE,\n description TEXT,\n is_exclusive INTEGER NOT NULL DEFAULT 1,\n is_required INTEGER NOT NULL DEFAULT 0,\n position INTEGER NOT NULL DEFAULT 0,\n created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP\n )";
|
|
78
|
+
readonly labels: "\n CREATE TABLE IF NOT EXISTS pmo_labels (\n id TEXT PRIMARY KEY,\n name TEXT NOT NULL,\n color TEXT,\n description TEXT,\n group_id TEXT REFERENCES pmo_label_groups(id) ON DELETE SET NULL,\n position INTEGER NOT NULL DEFAULT 0,\n is_builtin INTEGER NOT NULL DEFAULT 0,\n created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,\n UNIQUE(name, group_id)\n )";
|
|
79
|
+
readonly ticket_labels: "\n CREATE TABLE IF NOT EXISTS pmo_ticket_labels (\n ticket_id TEXT NOT NULL REFERENCES pmo_tickets(id) ON DELETE CASCADE,\n label_id TEXT NOT NULL REFERENCES pmo_labels(id) ON DELETE CASCADE,\n PRIMARY KEY (ticket_id, label_id)\n )";
|
|
74
80
|
readonly roadmaps: "\n CREATE TABLE IF NOT EXISTS pmo_roadmaps (\n id TEXT PRIMARY KEY,\n name TEXT NOT NULL UNIQUE,\n description TEXT,\n is_default INTEGER NOT NULL DEFAULT 0,\n created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,\n updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP\n )";
|
|
75
81
|
readonly roadmap_projects: "\n CREATE TABLE IF NOT EXISTS pmo_roadmap_projects (\n roadmap_id TEXT NOT NULL REFERENCES pmo_roadmaps(id) ON DELETE CASCADE,\n project_id TEXT NOT NULL REFERENCES pmo_projects(id) ON DELETE CASCADE,\n position INTEGER NOT NULL DEFAULT 0,\n created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,\n PRIMARY KEY (roadmap_id, project_id)\n )";
|
|
76
82
|
};
|
package/dist/lib/pmo/schema.js
CHANGED
|
@@ -41,6 +41,10 @@ export const PMO_TABLES = {
|
|
|
41
41
|
// Roadmap tables (ordered collections of projects for documentation)
|
|
42
42
|
roadmaps: 'pmo_roadmaps', // Named roadmap definitions
|
|
43
43
|
roadmap_projects: 'pmo_roadmap_projects', // Many-to-many: roadmaps ↔ projects with ordering
|
|
44
|
+
// Label system tables
|
|
45
|
+
label_groups: 'pmo_label_groups',
|
|
46
|
+
labels: 'pmo_labels',
|
|
47
|
+
ticket_labels: 'pmo_ticket_labels',
|
|
44
48
|
// Legacy tables (deprecated, kept for migration)
|
|
45
49
|
columns: 'pmo_columns', // DEPRECATED: use workflow_statuses
|
|
46
50
|
board_tickets: 'pmo_board_tickets', // DEPRECATED: tickets now use status_id directly
|
|
@@ -427,6 +431,37 @@ export const PMO_TABLE_SCHEMAS = {
|
|
|
427
431
|
suggested_subtasks TEXT NOT NULL DEFAULT '[]',
|
|
428
432
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
429
433
|
)`,
|
|
434
|
+
// Label groups (workspace-scoped grouping for labels)
|
|
435
|
+
label_groups: `
|
|
436
|
+
CREATE TABLE IF NOT EXISTS ${PMO_TABLES.label_groups} (
|
|
437
|
+
id TEXT PRIMARY KEY,
|
|
438
|
+
name TEXT NOT NULL UNIQUE,
|
|
439
|
+
description TEXT,
|
|
440
|
+
is_exclusive INTEGER NOT NULL DEFAULT 1,
|
|
441
|
+
is_required INTEGER NOT NULL DEFAULT 0,
|
|
442
|
+
position INTEGER NOT NULL DEFAULT 0,
|
|
443
|
+
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
444
|
+
)`,
|
|
445
|
+
// Labels (workspace-scoped, optionally grouped)
|
|
446
|
+
labels: `
|
|
447
|
+
CREATE TABLE IF NOT EXISTS ${PMO_TABLES.labels} (
|
|
448
|
+
id TEXT PRIMARY KEY,
|
|
449
|
+
name TEXT NOT NULL,
|
|
450
|
+
color TEXT,
|
|
451
|
+
description TEXT,
|
|
452
|
+
group_id TEXT REFERENCES ${PMO_TABLES.label_groups}(id) ON DELETE SET NULL,
|
|
453
|
+
position INTEGER NOT NULL DEFAULT 0,
|
|
454
|
+
is_builtin INTEGER NOT NULL DEFAULT 0,
|
|
455
|
+
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
456
|
+
UNIQUE(name, group_id)
|
|
457
|
+
)`,
|
|
458
|
+
// Junction table: ticket-label associations (replaces JSON labels field)
|
|
459
|
+
ticket_labels: `
|
|
460
|
+
CREATE TABLE IF NOT EXISTS ${PMO_TABLES.ticket_labels} (
|
|
461
|
+
ticket_id TEXT NOT NULL REFERENCES ${PMO_TABLES.tickets}(id) ON DELETE CASCADE,
|
|
462
|
+
label_id TEXT NOT NULL REFERENCES ${PMO_TABLES.labels}(id) ON DELETE CASCADE,
|
|
463
|
+
PRIMARY KEY (ticket_id, label_id)
|
|
464
|
+
)`,
|
|
430
465
|
// Roadmap definitions (named collections of projects for documentation)
|
|
431
466
|
roadmaps: `
|
|
432
467
|
CREATE TABLE IF NOT EXISTS ${PMO_TABLES.roadmaps} (
|
|
@@ -502,6 +537,12 @@ export const PMO_INDEXES = `
|
|
|
502
537
|
CREATE INDEX IF NOT EXISTS idx_pmo_roadmap_projects_position ON ${PMO_TABLES.roadmap_projects}(roadmap_id, position);
|
|
503
538
|
CREATE INDEX IF NOT EXISTS idx_pmo_categories_type ON ${PMO_TABLES.categories}(type);
|
|
504
539
|
CREATE INDEX IF NOT EXISTS idx_pmo_categories_position ON ${PMO_TABLES.categories}(type, position);
|
|
540
|
+
CREATE INDEX IF NOT EXISTS idx_pmo_label_groups_position ON ${PMO_TABLES.label_groups}(position);
|
|
541
|
+
CREATE INDEX IF NOT EXISTS idx_pmo_labels_group ON ${PMO_TABLES.labels}(group_id);
|
|
542
|
+
CREATE INDEX IF NOT EXISTS idx_pmo_labels_position ON ${PMO_TABLES.labels}(group_id, position);
|
|
543
|
+
CREATE INDEX IF NOT EXISTS idx_pmo_labels_builtin ON ${PMO_TABLES.labels}(is_builtin);
|
|
544
|
+
CREATE INDEX IF NOT EXISTS idx_pmo_ticket_labels_ticket ON ${PMO_TABLES.ticket_labels}(ticket_id);
|
|
545
|
+
CREATE INDEX IF NOT EXISTS idx_pmo_ticket_labels_label ON ${PMO_TABLES.ticket_labels}(label_id);
|
|
505
546
|
`;
|
|
506
547
|
// =============================================================================
|
|
507
548
|
// Combined Schema
|
|
@@ -540,6 +581,9 @@ export const PMO_SCHEMA_SQL = [
|
|
|
540
581
|
PMO_TABLE_SCHEMAS.id_sequences, // Sequence counters for ID generation
|
|
541
582
|
PMO_TABLE_SCHEMAS.actions, // Work actions (reusable agent prompts)
|
|
542
583
|
PMO_TABLE_SCHEMAS.ticket_templates, // Ticket templates for quick creation
|
|
584
|
+
PMO_TABLE_SCHEMAS.label_groups, // Label groups (before labels for FK)
|
|
585
|
+
PMO_TABLE_SCHEMAS.labels, // Labels (before ticket_labels for FK)
|
|
586
|
+
PMO_TABLE_SCHEMAS.ticket_labels, // Ticket-label junction table
|
|
543
587
|
PMO_TABLE_SCHEMAS.roadmaps, // Named roadmap definitions
|
|
544
588
|
PMO_TABLE_SCHEMAS.roadmap_projects, // Roadmap-to-project associations
|
|
545
589
|
// Legacy tables (kept for migration, will be dropped after data migrated)
|
|
@@ -169,7 +169,7 @@ export class ActionStorage {
|
|
|
169
169
|
? JSON.parse(row.default_category)
|
|
170
170
|
: undefined,
|
|
171
171
|
defaultMoveToCategory: row.default_category,
|
|
172
|
-
modifiesCode: row.
|
|
172
|
+
modifiesCode: row.modifies_code === 1,
|
|
173
173
|
isBuiltin: row.is_builtin === 1,
|
|
174
174
|
createdAt: new Date(row.created_at),
|
|
175
175
|
};
|
|
@@ -42,6 +42,12 @@ export declare function seedBuiltinCategories(db: Database.Database): void;
|
|
|
42
42
|
* Preserves any existing user-defined priority scale.
|
|
43
43
|
*/
|
|
44
44
|
export declare function seedDefaultPriorities(db: Database.Database): void;
|
|
45
|
+
/**
|
|
46
|
+
* Seed built-in label groups and labels.
|
|
47
|
+
* Creates Function, Type, and Area groups with their labels.
|
|
48
|
+
* Migrates existing ticket category values to Function labels.
|
|
49
|
+
*/
|
|
50
|
+
export declare function seedBuiltinLabels(db: Database.Database): void;
|
|
45
51
|
/**
|
|
46
52
|
* Update board timestamp for a project.
|
|
47
53
|
*/
|