@proletariat/cli 0.3.82 → 0.3.84
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/pr/merge.d.ts +9 -0
- package/dist/commands/pr/merge.js +78 -48
- package/dist/commands/pr/merge.js.map +1 -1
- package/dist/commands/ticket/update.d.ts +9 -0
- package/dist/commands/ticket/update.js +174 -71
- package/dist/commands/ticket/update.js.map +1 -1
- package/dist/lib/database/drizzle-schema.d.ts +301 -0
- package/dist/lib/database/drizzle-schema.js +22 -0
- package/dist/lib/database/drizzle-schema.js.map +1 -1
- package/dist/lib/database/index.d.ts +3 -0
- package/dist/lib/database/index.js +556 -345
- package/dist/lib/database/index.js.map +1 -1
- package/dist/lib/telemetry/analytics.d.ts +5 -5
- package/dist/lib/telemetry/analytics.js +113 -28
- package/dist/lib/telemetry/analytics.js.map +1 -1
- package/oclif.manifest.json +769 -726
- package/package.json +3 -2
|
@@ -19,4 +19,13 @@ export default class PRMerge extends PMOCommand {
|
|
|
19
19
|
private hasPMO;
|
|
20
20
|
init(): Promise<void>;
|
|
21
21
|
execute(): Promise<void>;
|
|
22
|
+
/**
|
|
23
|
+
* Resolve the linked ticket for a merged PR.
|
|
24
|
+
*
|
|
25
|
+
* Lookup order:
|
|
26
|
+
* 1. PR metadata (pr_number / pr_url) on tickets
|
|
27
|
+
* 2. agent_work table (branch → ticket_id)
|
|
28
|
+
* 3. PR branch name parsing (extract ticket ID from conventional branch format)
|
|
29
|
+
*/
|
|
30
|
+
private resolveLinkedTicket;
|
|
22
31
|
}
|
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
import { Args, Flags } from '@oclif/core';
|
|
2
2
|
import { PMOCommand, pmoBaseFlags, } from '../../lib/pmo/index.js';
|
|
3
3
|
import { getWorkColumnSetting, findColumnByName } from '../../lib/pmo/utils.js';
|
|
4
|
-
import Database from 'better-sqlite3';
|
|
5
|
-
import * as path from 'node:path';
|
|
6
|
-
import { getWorkspaceInfo } from '../../lib/agents/commands.js';
|
|
7
4
|
import { styles } from '../../lib/styles.js';
|
|
8
5
|
import { isGHInstalled, isGHAuthenticated, getPRByNumber, listOpenPRs, mergePR, getGitHubRepo, } from '../../lib/pr/index.js';
|
|
9
6
|
import { shouldOutputJson, outputErrorAsJson, outputSuccessAsJson, createMetadata, } from '../../lib/prompt-json.js';
|
|
10
7
|
import { FlagResolver } from '../../lib/flags/index.js';
|
|
11
8
|
import { getEventBus } from '../../lib/events/event-bus.js';
|
|
9
|
+
import { validateBranchName } from '../../lib/branch/index.js';
|
|
10
|
+
import { PMO_TABLES } from '../../lib/pmo/schema.js';
|
|
12
11
|
export default class PRMerge extends PMOCommand {
|
|
13
12
|
static description = 'Merge a GitHub pull request by number';
|
|
14
13
|
static examples = [
|
|
@@ -110,69 +109,52 @@ export default class PRMerge extends PMOCommand {
|
|
|
110
109
|
if (!result.success) {
|
|
111
110
|
return handleError('MERGE_FAILED', `Failed to merge PR #${prNumber}: ${result.error}`);
|
|
112
111
|
}
|
|
113
|
-
//
|
|
112
|
+
// After successful merge, resolve the linked ticket and move it to Done
|
|
114
113
|
let linkedTicketId;
|
|
114
|
+
let ticketMovedToDone = false;
|
|
115
|
+
let ticketTransitionProvider;
|
|
115
116
|
if (this.hasPMO) {
|
|
116
117
|
try {
|
|
117
|
-
const
|
|
118
|
-
// Find linked ticket by pr_number or by extracting number from pr_url
|
|
119
|
-
const linkedTicket = allTickets.find(t => t.metadata?.pr_number === String(prNumber) ||
|
|
120
|
-
t.metadata?.pr_url?.endsWith(`/pull/${prNumber}`) ||
|
|
121
|
-
t.metadata?.pr_url?.endsWith(`/${prNumber}`));
|
|
118
|
+
const linkedTicket = await this.resolveLinkedTicket(prNumber, prInfo.headBranch, flags.project);
|
|
122
119
|
if (linkedTicket) {
|
|
123
120
|
linkedTicketId = linkedTicket.id;
|
|
121
|
+
// Update PR state metadata
|
|
124
122
|
await this.storage.updateTicket(linkedTicket.id, {
|
|
125
123
|
metadata: {
|
|
126
124
|
...linkedTicket.metadata,
|
|
127
125
|
pr_state: 'MERGED',
|
|
128
126
|
},
|
|
129
127
|
});
|
|
130
|
-
// Move ticket to Done column
|
|
128
|
+
// Move ticket to Done column
|
|
131
129
|
try {
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
catch {
|
|
137
|
-
workspaceInfo = null;
|
|
138
|
-
}
|
|
139
|
-
const dbPath = workspaceInfo
|
|
140
|
-
? path.join(workspaceInfo.path, '.proletariat', 'workspace.db')
|
|
130
|
+
const db = this.storage.getDatabase();
|
|
131
|
+
const targetColumnName = getWorkColumnSetting(db, 'done');
|
|
132
|
+
const board = linkedTicket.projectId
|
|
133
|
+
? await this.storage.getProjectBoard(linkedTicket.projectId)
|
|
141
134
|
: null;
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
// Sync to external provider (e.g., Linear)
|
|
155
|
-
const provider = await this.resolveTicketProvider(linkedTicket.id, linkedTicket.projectId);
|
|
156
|
-
if (provider.name !== 'pmo') {
|
|
157
|
-
const moveResult = await provider.moveTicket(linkedTicket.id, doneColumn);
|
|
158
|
-
if (moveResult.success) {
|
|
159
|
-
this.log(styles.muted(` Synced to ${moveResult.provider}: ${doneColumn}`));
|
|
160
|
-
}
|
|
161
|
-
}
|
|
135
|
+
const columnNames = board ? board.columns.map(col => col.name) : [];
|
|
136
|
+
const doneColumn = findColumnByName(columnNames, targetColumnName);
|
|
137
|
+
if (doneColumn && linkedTicket.projectId) {
|
|
138
|
+
// Move in local PMO
|
|
139
|
+
await this.storage.moveTicket(linkedTicket.projectId, linkedTicket.id, doneColumn);
|
|
140
|
+
ticketMovedToDone = true;
|
|
141
|
+
// Sync to external provider (e.g., Linear)
|
|
142
|
+
const provider = await this.resolveTicketProvider(linkedTicket.id, linkedTicket.projectId);
|
|
143
|
+
if (provider.name !== 'pmo') {
|
|
144
|
+
const moveResult = await provider.moveTicket(linkedTicket.id, doneColumn);
|
|
145
|
+
if (moveResult.success) {
|
|
146
|
+
ticketTransitionProvider = moveResult.provider;
|
|
162
147
|
}
|
|
163
148
|
}
|
|
164
|
-
finally {
|
|
165
|
-
db.close();
|
|
166
|
-
}
|
|
167
149
|
}
|
|
168
150
|
}
|
|
169
|
-
catch {
|
|
170
|
-
|
|
151
|
+
catch (err) {
|
|
152
|
+
this.warn(`Failed to move ticket ${linkedTicket.id} to Done: ${err instanceof Error ? err.message : err}`);
|
|
171
153
|
}
|
|
172
154
|
}
|
|
173
155
|
}
|
|
174
|
-
catch {
|
|
175
|
-
|
|
156
|
+
catch (err) {
|
|
157
|
+
this.warn(`Failed to resolve linked ticket: ${err instanceof Error ? err.message : err}`);
|
|
176
158
|
}
|
|
177
159
|
}
|
|
178
160
|
// Emit work:pr_merged event for outbound sync (e.g., Linear auto-transition)
|
|
@@ -202,7 +184,8 @@ export default class PRMerge extends PMOCommand {
|
|
|
202
184
|
method,
|
|
203
185
|
branchDeleted: flags['delete-branch'],
|
|
204
186
|
linkedTicket: linkedTicketId ?? null,
|
|
205
|
-
|
|
187
|
+
ticketMovedToDone,
|
|
188
|
+
ticketTransitionProvider: ticketTransitionProvider ?? null,
|
|
206
189
|
}, createMetadata('pr merge', flags));
|
|
207
190
|
return;
|
|
208
191
|
}
|
|
@@ -214,8 +197,55 @@ export default class PRMerge extends PMOCommand {
|
|
|
214
197
|
this.log(styles.muted(` Branch ${prInfo.headBranch} deleted`));
|
|
215
198
|
}
|
|
216
199
|
if (linkedTicketId) {
|
|
217
|
-
this.log(styles.muted(`
|
|
200
|
+
this.log(styles.muted(` Ticket ${linkedTicketId} → Done`));
|
|
201
|
+
if (ticketTransitionProvider) {
|
|
202
|
+
this.log(styles.muted(` Synced to ${ticketTransitionProvider}`));
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Resolve the linked ticket for a merged PR.
|
|
208
|
+
*
|
|
209
|
+
* Lookup order:
|
|
210
|
+
* 1. PR metadata (pr_number / pr_url) on tickets
|
|
211
|
+
* 2. agent_work table (branch → ticket_id)
|
|
212
|
+
* 3. PR branch name parsing (extract ticket ID from conventional branch format)
|
|
213
|
+
*/
|
|
214
|
+
async resolveLinkedTicket(prNumber, headBranch, projectId) {
|
|
215
|
+
// 1. Find by PR metadata on tickets
|
|
216
|
+
const allTickets = await this.storage.listTickets(projectId);
|
|
217
|
+
const byMetadata = allTickets.find(t => t.metadata?.pr_number === String(prNumber) ||
|
|
218
|
+
t.metadata?.pr_url?.endsWith(`/pull/${prNumber}`) ||
|
|
219
|
+
t.metadata?.pr_url?.endsWith(`/${prNumber}`));
|
|
220
|
+
if (byMetadata)
|
|
221
|
+
return byMetadata;
|
|
222
|
+
// 2. Look up from agent_work table by branch name
|
|
223
|
+
try {
|
|
224
|
+
const db = this.storage.getDatabase();
|
|
225
|
+
const row = db.prepare(`SELECT ticket_id FROM ${PMO_TABLES.agent_work} WHERE branch = ? LIMIT 1`).get(headBranch);
|
|
226
|
+
if (row?.ticket_id) {
|
|
227
|
+
const ticket = await this.storage.getTicket(row.ticket_id);
|
|
228
|
+
if (ticket)
|
|
229
|
+
return ticket;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
catch {
|
|
233
|
+
// agent_work lookup failed, continue to branch name parsing
|
|
234
|
+
}
|
|
235
|
+
// 3. Parse ticket ID from branch name (e.g., PRLT-1043/feat/owner/agent/desc)
|
|
236
|
+
const branchResult = validateBranchName(headBranch);
|
|
237
|
+
if (branchResult.valid && branchResult.parts?.ticketId) {
|
|
238
|
+
const ticketId = branchResult.parts.ticketId;
|
|
239
|
+
// Try direct lookup (works for TKT-xxx internal IDs)
|
|
240
|
+
const directTicket = await this.storage.getTicket(ticketId);
|
|
241
|
+
if (directTicket)
|
|
242
|
+
return directTicket;
|
|
243
|
+
// Search by external_key metadata (works for PRLT-xxx, LINEAR-xxx, etc.)
|
|
244
|
+
const byExternalKey = allTickets.find(t => t.metadata?.external_key === ticketId);
|
|
245
|
+
if (byExternalKey)
|
|
246
|
+
return byExternalKey;
|
|
218
247
|
}
|
|
248
|
+
return null;
|
|
219
249
|
}
|
|
220
250
|
}
|
|
221
251
|
//# sourceMappingURL=merge.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"merge.js","sourceRoot":"","sources":["../../../src/commands/pr/merge.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EACL,UAAU,EACV,YAAY,GACb,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAChF,OAAO,
|
|
1
|
+
{"version":3,"file":"merge.js","sourceRoot":"","sources":["../../../src/commands/pr/merge.ts"],"names":[],"mappings":"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"}
|
|
@@ -6,8 +6,13 @@ export default class TicketUpdate extends PMOCommand {
|
|
|
6
6
|
ticketId: import("@oclif/core/interfaces").Arg<string | undefined, Record<string, unknown>>;
|
|
7
7
|
};
|
|
8
8
|
static flags: {
|
|
9
|
+
title: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
10
|
+
description: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
11
|
+
'description-file': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
9
12
|
priority: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
10
13
|
category: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
14
|
+
labels: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
15
|
+
status: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
11
16
|
bulk: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
12
17
|
force: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
13
18
|
json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
@@ -15,5 +20,9 @@ export default class TicketUpdate extends PMOCommand {
|
|
|
15
20
|
project: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
16
21
|
};
|
|
17
22
|
execute(): Promise<void>;
|
|
23
|
+
/**
|
|
24
|
+
* Interactive mode when no flags are provided - original priority/category selection flow
|
|
25
|
+
*/
|
|
26
|
+
private executeInteractive;
|
|
18
27
|
private executeBulk;
|
|
19
28
|
}
|
|
@@ -1,16 +1,22 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs';
|
|
1
2
|
import { Args, Flags } from '@oclif/core';
|
|
2
3
|
import { PMOCommand, pmoBaseFlags, autoExportToBoard } from '../../lib/pmo/index.js';
|
|
3
4
|
import { getWorkspacePriorities } from '../../lib/pmo/utils.js';
|
|
4
5
|
import { styles } from '../../lib/styles.js';
|
|
5
6
|
import { shouldOutputJson, outputErrorAsJson, createMetadata, } from '../../lib/prompt-json.js';
|
|
7
|
+
import { formatTicket } from '../../lib/mcp/helpers.js';
|
|
6
8
|
export default class TicketUpdate extends PMOCommand {
|
|
7
|
-
static description = 'Update priority
|
|
9
|
+
static description = 'Update ticket fields (title, description, priority, category, labels, status)';
|
|
8
10
|
static examples = [
|
|
11
|
+
'<%= config.bin %> <%= command.id %> TKT-001 --title "New title"',
|
|
12
|
+
'<%= config.bin %> <%= command.id %> TKT-001 --description "Updated description"',
|
|
13
|
+
'<%= config.bin %> <%= command.id %> TKT-001 --description-file ./spec.md',
|
|
9
14
|
'<%= config.bin %> <%= command.id %> TKT-001 --priority P1',
|
|
10
15
|
'<%= config.bin %> <%= command.id %> TKT-001 --category bug',
|
|
11
|
-
'<%= config.bin %> <%= command.id %> --
|
|
16
|
+
'<%= config.bin %> <%= command.id %> TKT-001 --labels frontend,urgent',
|
|
17
|
+
'<%= config.bin %> <%= command.id %> TKT-001 --status "In Progress"',
|
|
18
|
+
'<%= config.bin %> <%= command.id %> TKT-001 --title "Fix auth" --priority P0 --status "In Progress" --json',
|
|
12
19
|
'<%= config.bin %> <%= command.id %> --bulk --priority P1',
|
|
13
|
-
'<%= config.bin %> <%= command.id %> --json # Output choices as JSON',
|
|
14
20
|
];
|
|
15
21
|
static args = {
|
|
16
22
|
ticketId: Args.string({
|
|
@@ -20,13 +26,32 @@ export default class TicketUpdate extends PMOCommand {
|
|
|
20
26
|
};
|
|
21
27
|
static flags = {
|
|
22
28
|
...pmoBaseFlags,
|
|
29
|
+
title: Flags.string({
|
|
30
|
+
char: 't',
|
|
31
|
+
description: 'Set ticket title',
|
|
32
|
+
}),
|
|
33
|
+
description: Flags.string({
|
|
34
|
+
char: 'd',
|
|
35
|
+
description: 'Set ticket description',
|
|
36
|
+
}),
|
|
37
|
+
'description-file': Flags.string({
|
|
38
|
+
description: 'Read ticket description from a file',
|
|
39
|
+
}),
|
|
23
40
|
priority: Flags.string({
|
|
24
41
|
char: 'p',
|
|
25
|
-
description: 'Set priority (uses workspace priority scale)',
|
|
42
|
+
description: 'Set priority (uses workspace priority scale, "none" to clear)',
|
|
26
43
|
}),
|
|
27
44
|
category: Flags.string({
|
|
28
45
|
char: 'c',
|
|
29
|
-
description: 'Set category (e.g., feature, bug, refactor)',
|
|
46
|
+
description: 'Set category (e.g., feature, bug, refactor, "none" to clear)',
|
|
47
|
+
}),
|
|
48
|
+
labels: Flags.string({
|
|
49
|
+
char: 'l',
|
|
50
|
+
description: 'Set labels (comma-separated, replaces existing labels; use "" to clear)',
|
|
51
|
+
}),
|
|
52
|
+
status: Flags.string({
|
|
53
|
+
char: 's',
|
|
54
|
+
description: 'Set status/column (e.g., "In Progress", "Done")',
|
|
30
55
|
}),
|
|
31
56
|
bulk: Flags.boolean({
|
|
32
57
|
char: 'b',
|
|
@@ -44,15 +69,22 @@ export default class TicketUpdate extends PMOCommand {
|
|
|
44
69
|
const projectId = flags.project;
|
|
45
70
|
// Check if JSON output mode is active
|
|
46
71
|
const jsonMode = shouldOutputJson(flags);
|
|
47
|
-
//
|
|
48
|
-
const
|
|
49
|
-
if (allTickets.length === 0) {
|
|
72
|
+
// Helper to handle errors in JSON mode
|
|
73
|
+
const handleError = (code, message) => {
|
|
50
74
|
if (jsonMode) {
|
|
51
|
-
outputErrorAsJson(
|
|
75
|
+
outputErrorAsJson(code, message, createMetadata('ticket update', flags));
|
|
52
76
|
return;
|
|
53
77
|
}
|
|
54
|
-
this.
|
|
55
|
-
|
|
78
|
+
this.error(message);
|
|
79
|
+
};
|
|
80
|
+
// Validate --description and --description-file are not both provided
|
|
81
|
+
if (flags.description !== undefined && flags['description-file'] !== undefined) {
|
|
82
|
+
return handleError('INVALID_FLAGS', 'Cannot use both --description and --description-file.');
|
|
83
|
+
}
|
|
84
|
+
// Get all tickets
|
|
85
|
+
const allTickets = await this.storage.listTickets(projectId);
|
|
86
|
+
if (allTickets.length === 0) {
|
|
87
|
+
return handleError('NO_TICKETS', 'No tickets found.');
|
|
56
88
|
}
|
|
57
89
|
// Bulk mode
|
|
58
90
|
if (flags.bulk) {
|
|
@@ -78,74 +110,145 @@ export default class TicketUpdate extends PMOCommand {
|
|
|
78
110
|
// Get ticket
|
|
79
111
|
const ticket = await this.storage.getTicket(ticketId);
|
|
80
112
|
if (!ticket) {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
113
|
+
return handleError('TICKET_NOT_FOUND', `Ticket "${ticketId}" not found.`);
|
|
114
|
+
}
|
|
115
|
+
// Check if any flags were provided
|
|
116
|
+
const hasFlags = flags.title !== undefined || flags.description !== undefined ||
|
|
117
|
+
flags['description-file'] !== undefined || flags.priority !== undefined ||
|
|
118
|
+
flags.category !== undefined || flags.labels !== undefined ||
|
|
119
|
+
flags.status !== undefined;
|
|
120
|
+
if (!hasFlags) {
|
|
121
|
+
// No flags provided - fall back to interactive priority/category selection
|
|
122
|
+
await this.executeInteractive(ticketId, ticket, projectId, jsonMode, flags);
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
// Build changes from flags
|
|
126
|
+
const changes = {};
|
|
127
|
+
const changedFields = [];
|
|
128
|
+
if (flags.title !== undefined) {
|
|
129
|
+
changes.title = flags.title;
|
|
130
|
+
changedFields.push(`Title: ${flags.title}`);
|
|
131
|
+
}
|
|
132
|
+
// Handle description (--description or --description-file)
|
|
133
|
+
if (flags['description-file'] !== undefined) {
|
|
134
|
+
try {
|
|
135
|
+
const content = readFileSync(flags['description-file'], 'utf-8');
|
|
136
|
+
changes.description = content;
|
|
137
|
+
changedFields.push(`Description: (from file ${flags['description-file']})`);
|
|
138
|
+
}
|
|
139
|
+
catch (error) {
|
|
140
|
+
return handleError('FILE_READ_ERROR', `Failed to read description file "${flags['description-file']}": ${error instanceof Error ? error.message : String(error)}`);
|
|
84
141
|
}
|
|
85
|
-
this.error(`Ticket "${ticketId}" not found.`);
|
|
86
142
|
}
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
143
|
+
else if (flags.description !== undefined) {
|
|
144
|
+
changes.description = flags.description;
|
|
145
|
+
changedFields.push(`Description: ${flags.description.length > 60 ? flags.description.slice(0, 60) + '...' : flags.description}`);
|
|
146
|
+
}
|
|
147
|
+
if (flags.priority !== undefined) {
|
|
148
|
+
changes.priority = flags.priority === 'none' ? null : flags.priority;
|
|
149
|
+
changedFields.push(`Priority: ${flags.priority === 'none' ? 'none' : flags.priority}`);
|
|
150
|
+
}
|
|
151
|
+
if (flags.category !== undefined) {
|
|
152
|
+
changes.category = flags.category === 'none' ? undefined : flags.category;
|
|
153
|
+
changedFields.push(`Category: ${flags.category === 'none' ? 'none' : flags.category}`);
|
|
154
|
+
}
|
|
155
|
+
if (flags.labels !== undefined) {
|
|
156
|
+
const labelList = flags.labels === '' ? [] : flags.labels.split(',').map(l => l.trim()).filter(Boolean);
|
|
157
|
+
changes.labels = labelList;
|
|
158
|
+
changedFields.push(`Labels: ${labelList.length > 0 ? labelList.join(', ') : 'none'}`);
|
|
159
|
+
}
|
|
160
|
+
// Apply field changes (everything except status)
|
|
161
|
+
if (Object.keys(changes).length > 0) {
|
|
162
|
+
await this.storage.updateTicket(ticketId, changes);
|
|
163
|
+
}
|
|
164
|
+
// Handle status change separately via provider
|
|
165
|
+
if (flags.status !== undefined) {
|
|
166
|
+
const provider = await this.resolveTicketProvider(ticketId, ticket.projectId || '');
|
|
167
|
+
const moveResult = await provider.moveTicket(ticketId, flags.status);
|
|
168
|
+
if (!moveResult.success) {
|
|
169
|
+
return handleError('STATUS_CHANGE_FAILED', `Failed to change status to "${flags.status}": ${moveResult.error}`);
|
|
170
|
+
}
|
|
171
|
+
changedFields.push(`Status: ${flags.status}`);
|
|
172
|
+
}
|
|
173
|
+
// Auto-export
|
|
174
|
+
await autoExportToBoard(this.pmoPath, this.storage, (msg) => this.log(styles.muted(msg)));
|
|
175
|
+
// Refresh ticket for output
|
|
176
|
+
const updatedTicket = await this.storage.getTicket(ticketId) || ticket;
|
|
177
|
+
// JSON output mode
|
|
178
|
+
if (jsonMode) {
|
|
179
|
+
this.log(JSON.stringify({
|
|
180
|
+
success: true,
|
|
181
|
+
ticket: formatTicket(updatedTicket),
|
|
182
|
+
}, null, 2));
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
this.log(styles.success(`\n✅ Updated ticket ${styles.emphasis(ticketId)}`));
|
|
186
|
+
for (const field of changedFields) {
|
|
187
|
+
this.log(styles.muted(` ${field}`));
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Interactive mode when no flags are provided - original priority/category selection flow
|
|
192
|
+
*/
|
|
193
|
+
async executeInteractive(ticketId, ticket, projectId, jsonMode, flags) {
|
|
194
|
+
const jsonModeConfig = jsonMode ? { flags, commandName: 'ticket update' } : null;
|
|
195
|
+
const { updateType } = await this.prompt([{
|
|
196
|
+
type: 'list',
|
|
197
|
+
name: 'updateType',
|
|
198
|
+
message: 'What would you like to update?',
|
|
199
|
+
choices: [
|
|
200
|
+
{ name: 'Priority', value: 'priority', command: `prlt ticket update ${ticketId} --priority <P0|P1|P2|P3>${projectId ? ` -P ${projectId}` : ''} --json` },
|
|
201
|
+
{ name: 'Category', value: 'category', command: `prlt ticket update ${ticketId} --category <category>${projectId ? ` -P ${projectId}` : ''} --json` },
|
|
202
|
+
{ name: 'Both', value: 'both', command: `prlt ticket update ${ticketId} --priority <P0|P1|P2|P3> --category <category>${projectId ? ` -P ${projectId}` : ''} --json` },
|
|
203
|
+
],
|
|
204
|
+
}], jsonModeConfig);
|
|
205
|
+
let updatePriority;
|
|
206
|
+
let updateCategory;
|
|
207
|
+
if (updateType === 'priority' || updateType === 'both') {
|
|
208
|
+
const db = this.storage.getDatabase();
|
|
209
|
+
const workspacePriorities = getWorkspacePriorities(db);
|
|
210
|
+
const { priority } = await this.prompt([{
|
|
94
211
|
type: 'list',
|
|
95
|
-
name: '
|
|
96
|
-
message: '
|
|
212
|
+
name: 'priority',
|
|
213
|
+
message: 'Set priority to:',
|
|
97
214
|
choices: [
|
|
98
|
-
{ name:
|
|
99
|
-
{ name:
|
|
100
|
-
{ name: '
|
|
215
|
+
{ name: `(Keep existing: ${ticket.priority || 'none'})`, value: null, command: '' },
|
|
216
|
+
...workspacePriorities.map(p => ({ name: p, value: p, command: `prlt ticket update ${ticketId} --priority ${p}${projectId ? ` -P ${projectId}` : ''} --json` })),
|
|
217
|
+
{ name: 'None (clear priority)', value: '', command: `prlt ticket update ${ticketId} --priority none${projectId ? ` -P ${projectId}` : ''} --json` },
|
|
101
218
|
],
|
|
102
219
|
}], jsonModeConfig);
|
|
103
|
-
if (
|
|
104
|
-
|
|
105
|
-
const workspacePriorities = getWorkspacePriorities(db);
|
|
106
|
-
const { priority } = await this.prompt([{
|
|
107
|
-
type: 'list',
|
|
108
|
-
name: 'priority',
|
|
109
|
-
message: 'Set priority to:',
|
|
110
|
-
choices: [
|
|
111
|
-
{ name: `(Keep existing: ${ticket.priority || 'none'})`, value: null, command: '' },
|
|
112
|
-
...workspacePriorities.map(p => ({ name: p, value: p, command: `prlt ticket update ${ticketId} --priority ${p}${projectId ? ` -P ${projectId}` : ''} --json` })),
|
|
113
|
-
{ name: 'None (clear priority)', value: '', command: `prlt ticket update ${ticketId} --priority none${projectId ? ` -P ${projectId}` : ''} --json` },
|
|
114
|
-
],
|
|
115
|
-
}], jsonModeConfig);
|
|
116
|
-
if (priority !== null) {
|
|
117
|
-
updatePriority = priority;
|
|
118
|
-
}
|
|
220
|
+
if (priority !== null) {
|
|
221
|
+
updatePriority = priority;
|
|
119
222
|
}
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
223
|
+
}
|
|
224
|
+
if (updateType === 'category' || updateType === 'both') {
|
|
225
|
+
const { categoryChoice } = await this.prompt([{
|
|
226
|
+
type: 'list',
|
|
227
|
+
name: 'categoryChoice',
|
|
228
|
+
message: 'Set category to:',
|
|
229
|
+
choices: [
|
|
230
|
+
{ name: `(Keep existing: ${ticket.category || 'none'})`, value: null, command: '' },
|
|
231
|
+
{ name: 'feature', value: 'feature', command: `prlt ticket update ${ticketId} --category feature${projectId ? ` -P ${projectId}` : ''} --json` },
|
|
232
|
+
{ name: 'bug', value: 'bug', command: `prlt ticket update ${ticketId} --category bug${projectId ? ` -P ${projectId}` : ''} --json` },
|
|
233
|
+
{ name: 'refactor', value: 'refactor', command: `prlt ticket update ${ticketId} --category refactor${projectId ? ` -P ${projectId}` : ''} --json` },
|
|
234
|
+
{ name: 'docs', value: 'docs', command: `prlt ticket update ${ticketId} --category docs${projectId ? ` -P ${projectId}` : ''} --json` },
|
|
235
|
+
{ name: 'test', value: 'test', command: `prlt ticket update ${ticketId} --category test${projectId ? ` -P ${projectId}` : ''} --json` },
|
|
236
|
+
{ name: 'chore', value: 'chore', command: `prlt ticket update ${ticketId} --category chore${projectId ? ` -P ${projectId}` : ''} --json` },
|
|
237
|
+
{ name: 'None (clear category)', value: '', command: `prlt ticket update ${ticketId} --category none${projectId ? ` -P ${projectId}` : ''} --json` },
|
|
238
|
+
{ name: 'Custom...', value: '__custom__', command: `prlt ticket update ${ticketId} --category <category>${projectId ? ` -P ${projectId}` : ''} --json` },
|
|
239
|
+
],
|
|
240
|
+
}], jsonModeConfig);
|
|
241
|
+
if (categoryChoice === '__custom__') {
|
|
242
|
+
const { customCategory } = await this.prompt([{
|
|
243
|
+
type: 'input',
|
|
244
|
+
name: 'customCategory',
|
|
245
|
+
message: 'Enter custom category:',
|
|
246
|
+
validate: (input) => input.length > 0 || 'Category is required',
|
|
136
247
|
}], jsonModeConfig);
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
message: 'Enter custom category:',
|
|
142
|
-
validate: (input) => input.length > 0 || 'Category is required',
|
|
143
|
-
}], jsonModeConfig);
|
|
144
|
-
updateCategory = customCategory;
|
|
145
|
-
}
|
|
146
|
-
else if (categoryChoice !== null) {
|
|
147
|
-
updateCategory = categoryChoice;
|
|
148
|
-
}
|
|
248
|
+
updateCategory = customCategory;
|
|
249
|
+
}
|
|
250
|
+
else if (categoryChoice !== null) {
|
|
251
|
+
updateCategory = categoryChoice;
|
|
149
252
|
}
|
|
150
253
|
}
|
|
151
254
|
// Check if anything to update
|