@proletariat/cli 0.3.36 → 0.3.41
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/README.md +37 -2
- package/bin/dev.js +0 -0
- package/dist/commands/branch/where.js +6 -17
- package/dist/commands/epic/ticket.js +7 -24
- package/dist/commands/execution/config.js +4 -14
- package/dist/commands/execution/logs.js +6 -0
- package/dist/commands/execution/view.js +8 -0
- package/dist/commands/init.js +4 -8
- package/dist/commands/mcp-server.js +2 -1
- package/dist/commands/pmo/init.js +12 -40
- package/dist/commands/qa/index.d.ts +54 -0
- package/dist/commands/qa/index.js +762 -0
- package/dist/commands/repo/view.js +2 -8
- package/dist/commands/session/attach.js +4 -4
- package/dist/commands/session/health.js +4 -4
- package/dist/commands/session/list.js +1 -19
- package/dist/commands/session/peek.js +6 -6
- package/dist/commands/session/poke.js +2 -2
- package/dist/commands/ticket/epic.js +17 -43
- package/dist/commands/work/spawn-all.js +1 -1
- package/dist/commands/work/spawn.js +15 -4
- package/dist/commands/work/start.js +17 -9
- package/dist/commands/work/watch.js +1 -1
- package/dist/commands/workspace/prune.js +3 -3
- package/dist/hooks/init.js +21 -10
- package/dist/lib/agents/commands.d.ts +5 -0
- package/dist/lib/agents/commands.js +143 -97
- package/dist/lib/database/drizzle-schema.d.ts +465 -0
- package/dist/lib/database/drizzle-schema.js +53 -0
- package/dist/lib/database/index.d.ts +47 -1
- package/dist/lib/database/index.js +138 -20
- package/dist/lib/execution/runners.d.ts +34 -0
- package/dist/lib/execution/runners.js +134 -7
- package/dist/lib/execution/session-utils.d.ts +5 -0
- package/dist/lib/execution/session-utils.js +45 -3
- package/dist/lib/execution/spawner.js +15 -2
- package/dist/lib/execution/storage.d.ts +1 -1
- package/dist/lib/execution/storage.js +17 -2
- package/dist/lib/execution/types.d.ts +1 -0
- package/dist/lib/mcp/tools/index.d.ts +1 -0
- package/dist/lib/mcp/tools/index.js +1 -0
- package/dist/lib/mcp/tools/tmux.d.ts +16 -0
- package/dist/lib/mcp/tools/tmux.js +182 -0
- package/dist/lib/mcp/tools/work.js +52 -0
- package/dist/lib/pmo/schema.d.ts +1 -1
- package/dist/lib/pmo/schema.js +1 -0
- package/dist/lib/pmo/storage/base.js +207 -0
- package/dist/lib/pmo/storage/dependencies.d.ts +1 -0
- package/dist/lib/pmo/storage/dependencies.js +11 -3
- package/dist/lib/pmo/storage/epics.js +1 -1
- package/dist/lib/pmo/storage/helpers.d.ts +4 -4
- package/dist/lib/pmo/storage/helpers.js +36 -26
- package/dist/lib/pmo/storage/projects.d.ts +2 -0
- package/dist/lib/pmo/storage/projects.js +207 -119
- package/dist/lib/pmo/storage/specs.d.ts +2 -0
- package/dist/lib/pmo/storage/specs.js +274 -188
- package/dist/lib/pmo/storage/tickets.d.ts +2 -0
- package/dist/lib/pmo/storage/tickets.js +350 -290
- package/dist/lib/pmo/storage/views.d.ts +2 -0
- package/dist/lib/pmo/storage/views.js +183 -130
- package/dist/lib/prompt-json.d.ts +5 -0
- package/dist/lib/prompt-json.js +9 -0
- package/oclif.manifest.json +3293 -3190
- package/package.json +11 -6
- package/LICENSE +0 -190
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Board view operations.
|
|
3
|
+
*
|
|
4
|
+
* This module uses Drizzle ORM for type-safe database queries.
|
|
3
5
|
*/
|
|
4
|
-
import {
|
|
6
|
+
import { eq, and, like, or, asc, desc, sql } from 'drizzle-orm';
|
|
7
|
+
import { pmoBoardViews, pmoProjects, pmoTickets, pmoWorkflowStatuses, pmoSubtasks, pmoTicketMetadata, } from '../../database/drizzle-schema.js';
|
|
5
8
|
import { PMOError, } from '../types.js';
|
|
6
9
|
import { slugify } from '../utils.js';
|
|
7
10
|
import { getAcceptanceCriteriaSync } from './helpers.js';
|
|
8
|
-
const T = PMO_TABLES;
|
|
9
11
|
export class ViewStorage {
|
|
10
12
|
ctx;
|
|
11
13
|
constructor(ctx) {
|
|
@@ -24,33 +26,42 @@ export class ViewStorage {
|
|
|
24
26
|
if (!identifier)
|
|
25
27
|
return null;
|
|
26
28
|
// 1. Exact ID match
|
|
27
|
-
const exactMatch = this.ctx.
|
|
28
|
-
|
|
29
|
-
|
|
29
|
+
const exactMatch = this.ctx.drizzle
|
|
30
|
+
.select({ id: pmoProjects.id })
|
|
31
|
+
.from(pmoProjects)
|
|
32
|
+
.where(eq(pmoProjects.id, identifier))
|
|
33
|
+
.get();
|
|
30
34
|
if (exactMatch)
|
|
31
35
|
return exactMatch.id;
|
|
32
36
|
// 2. Case-insensitive ID match
|
|
33
|
-
const caseInsensitiveId = this.ctx.
|
|
34
|
-
|
|
35
|
-
|
|
37
|
+
const caseInsensitiveId = this.ctx.drizzle
|
|
38
|
+
.select({ id: pmoProjects.id })
|
|
39
|
+
.from(pmoProjects)
|
|
40
|
+
.where(sql `LOWER(${pmoProjects.id}) = LOWER(${identifier})`)
|
|
41
|
+
.get();
|
|
36
42
|
if (caseInsensitiveId)
|
|
37
43
|
return caseInsensitiveId.id;
|
|
38
44
|
// 3. Exact name match
|
|
39
|
-
const nameMatch = this.ctx.
|
|
40
|
-
|
|
41
|
-
|
|
45
|
+
const nameMatch = this.ctx.drizzle
|
|
46
|
+
.select({ id: pmoProjects.id })
|
|
47
|
+
.from(pmoProjects)
|
|
48
|
+
.where(eq(pmoProjects.name, identifier))
|
|
49
|
+
.get();
|
|
42
50
|
if (nameMatch)
|
|
43
51
|
return nameMatch.id;
|
|
44
52
|
// 4. Case-insensitive name match
|
|
45
|
-
const caseInsensitiveName = this.ctx.
|
|
46
|
-
|
|
47
|
-
|
|
53
|
+
const caseInsensitiveName = this.ctx.drizzle
|
|
54
|
+
.select({ id: pmoProjects.id })
|
|
55
|
+
.from(pmoProjects)
|
|
56
|
+
.where(sql `LOWER(${pmoProjects.name}) = LOWER(${identifier})`)
|
|
57
|
+
.get();
|
|
48
58
|
if (caseInsensitiveName)
|
|
49
59
|
return caseInsensitiveName.id;
|
|
50
60
|
// 5. Slugified name match
|
|
51
|
-
const allProjects = this.ctx.
|
|
52
|
-
|
|
53
|
-
|
|
61
|
+
const allProjects = this.ctx.drizzle
|
|
62
|
+
.select({ id: pmoProjects.id, name: pmoProjects.name })
|
|
63
|
+
.from(pmoProjects)
|
|
64
|
+
.all();
|
|
54
65
|
const identifierLower = identifier.toLowerCase();
|
|
55
66
|
for (const project of allProjects) {
|
|
56
67
|
const projectSlug = slugify(project.name);
|
|
@@ -64,34 +75,37 @@ export class ViewStorage {
|
|
|
64
75
|
* List board views.
|
|
65
76
|
*/
|
|
66
77
|
async listBoardViews(filter) {
|
|
67
|
-
let
|
|
78
|
+
let query = this.ctx.drizzle
|
|
79
|
+
.select()
|
|
80
|
+
.from(pmoBoardViews)
|
|
81
|
+
.$dynamic();
|
|
68
82
|
const conditions = [];
|
|
69
|
-
const params = [];
|
|
70
83
|
if (filter?.projectId) {
|
|
71
|
-
conditions.push(
|
|
72
|
-
params.push(filter.projectId);
|
|
84
|
+
conditions.push(eq(pmoBoardViews.projectId, filter.projectId));
|
|
73
85
|
}
|
|
74
86
|
if (filter?.isDefault !== undefined) {
|
|
75
|
-
conditions.push(
|
|
76
|
-
params.push(filter.isDefault ? 1 : 0);
|
|
87
|
+
conditions.push(eq(pmoBoardViews.isDefault, filter.isDefault));
|
|
77
88
|
}
|
|
78
89
|
if (filter?.search) {
|
|
79
|
-
conditions.push(
|
|
80
|
-
const searchTerm = `%${filter.search}%`;
|
|
81
|
-
params.push(searchTerm, searchTerm);
|
|
90
|
+
conditions.push(or(like(pmoBoardViews.name, `%${filter.search}%`), like(pmoBoardViews.description, `%${filter.search}%`)));
|
|
82
91
|
}
|
|
83
92
|
if (conditions.length > 0) {
|
|
84
|
-
|
|
93
|
+
query = query.where(and(...conditions));
|
|
85
94
|
}
|
|
86
|
-
|
|
87
|
-
|
|
95
|
+
const rows = query
|
|
96
|
+
.orderBy(desc(pmoBoardViews.isDefault), asc(pmoBoardViews.name))
|
|
97
|
+
.all();
|
|
88
98
|
return rows.map((row) => this.rowToBoardView(row));
|
|
89
99
|
}
|
|
90
100
|
/**
|
|
91
101
|
* Get a board view by ID.
|
|
92
102
|
*/
|
|
93
103
|
async getBoardView(id) {
|
|
94
|
-
const row = this.ctx.
|
|
104
|
+
const row = this.ctx.drizzle
|
|
105
|
+
.select()
|
|
106
|
+
.from(pmoBoardViews)
|
|
107
|
+
.where(eq(pmoBoardViews.id, id))
|
|
108
|
+
.get();
|
|
95
109
|
if (!row)
|
|
96
110
|
return null;
|
|
97
111
|
return this.rowToBoardView(row);
|
|
@@ -111,14 +125,24 @@ export class ViewStorage {
|
|
|
111
125
|
const filters = JSON.stringify(view.filters || {});
|
|
112
126
|
// If this is set as default, unset other defaults for this project
|
|
113
127
|
if (view.isDefault) {
|
|
114
|
-
this.ctx.
|
|
115
|
-
|
|
116
|
-
|
|
128
|
+
this.ctx.drizzle
|
|
129
|
+
.update(pmoBoardViews)
|
|
130
|
+
.set({ isDefault: false })
|
|
131
|
+
.where(eq(pmoBoardViews.projectId, view.projectId))
|
|
132
|
+
.run();
|
|
117
133
|
}
|
|
118
|
-
this.ctx.
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
134
|
+
this.ctx.drizzle.insert(pmoBoardViews).values({
|
|
135
|
+
id,
|
|
136
|
+
projectId: view.projectId,
|
|
137
|
+
name: view.name,
|
|
138
|
+
description: view.description || null,
|
|
139
|
+
isDefault: view.isDefault || false,
|
|
140
|
+
filters,
|
|
141
|
+
groupBy: view.groupBy || null,
|
|
142
|
+
sortBy: view.sortBy || null,
|
|
143
|
+
createdAt: String(now),
|
|
144
|
+
updatedAt: String(now),
|
|
145
|
+
}).run();
|
|
122
146
|
return (await this.getBoardView(id));
|
|
123
147
|
}
|
|
124
148
|
/**
|
|
@@ -129,47 +153,45 @@ export class ViewStorage {
|
|
|
129
153
|
if (!existing) {
|
|
130
154
|
throw new PMOError('NOT_FOUND', `Board view not found: ${id}`);
|
|
131
155
|
}
|
|
132
|
-
const updates =
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
updates.push('description = ?');
|
|
140
|
-
params.push(changes.description || null);
|
|
141
|
-
}
|
|
156
|
+
const updates = {
|
|
157
|
+
updatedAt: String(Date.now()),
|
|
158
|
+
};
|
|
159
|
+
if (changes.name !== undefined)
|
|
160
|
+
updates.name = changes.name;
|
|
161
|
+
if (changes.description !== undefined)
|
|
162
|
+
updates.description = changes.description || null;
|
|
142
163
|
if (changes.isDefault !== undefined) {
|
|
143
164
|
// If setting as default, unset other defaults for this project
|
|
144
165
|
if (changes.isDefault) {
|
|
145
|
-
this.ctx.
|
|
146
|
-
|
|
147
|
-
|
|
166
|
+
this.ctx.drizzle
|
|
167
|
+
.update(pmoBoardViews)
|
|
168
|
+
.set({ isDefault: false })
|
|
169
|
+
.where(eq(pmoBoardViews.projectId, existing.projectId))
|
|
170
|
+
.run();
|
|
148
171
|
}
|
|
149
|
-
updates.
|
|
150
|
-
params.push(changes.isDefault ? 1 : 0);
|
|
151
|
-
}
|
|
152
|
-
if (changes.filters !== undefined) {
|
|
153
|
-
updates.push('filters = ?');
|
|
154
|
-
params.push(JSON.stringify(changes.filters));
|
|
155
|
-
}
|
|
156
|
-
if (changes.groupBy !== undefined) {
|
|
157
|
-
updates.push('group_by = ?');
|
|
158
|
-
params.push(changes.groupBy || null);
|
|
159
|
-
}
|
|
160
|
-
if (changes.sortBy !== undefined) {
|
|
161
|
-
updates.push('sort_by = ?');
|
|
162
|
-
params.push(changes.sortBy || null);
|
|
172
|
+
updates.isDefault = changes.isDefault;
|
|
163
173
|
}
|
|
164
|
-
|
|
165
|
-
|
|
174
|
+
if (changes.filters !== undefined)
|
|
175
|
+
updates.filters = JSON.stringify(changes.filters);
|
|
176
|
+
if (changes.groupBy !== undefined)
|
|
177
|
+
updates.groupBy = changes.groupBy || null;
|
|
178
|
+
if (changes.sortBy !== undefined)
|
|
179
|
+
updates.sortBy = changes.sortBy || null;
|
|
180
|
+
this.ctx.drizzle
|
|
181
|
+
.update(pmoBoardViews)
|
|
182
|
+
.set(updates)
|
|
183
|
+
.where(eq(pmoBoardViews.id, id))
|
|
184
|
+
.run();
|
|
166
185
|
return (await this.getBoardView(id));
|
|
167
186
|
}
|
|
168
187
|
/**
|
|
169
188
|
* Delete a board view.
|
|
170
189
|
*/
|
|
171
190
|
async deleteBoardView(id) {
|
|
172
|
-
const result = this.ctx.
|
|
191
|
+
const result = this.ctx.drizzle
|
|
192
|
+
.delete(pmoBoardViews)
|
|
193
|
+
.where(eq(pmoBoardViews.id, id))
|
|
194
|
+
.run();
|
|
173
195
|
if (result.changes === 0) {
|
|
174
196
|
throw new PMOError('NOT_FOUND', `Board view not found: ${id}`);
|
|
175
197
|
}
|
|
@@ -178,9 +200,11 @@ export class ViewStorage {
|
|
|
178
200
|
* Get the default board view for a project.
|
|
179
201
|
*/
|
|
180
202
|
async getDefaultBoardView(projectId) {
|
|
181
|
-
const row = this.ctx.
|
|
182
|
-
|
|
183
|
-
|
|
203
|
+
const row = this.ctx.drizzle
|
|
204
|
+
.select()
|
|
205
|
+
.from(pmoBoardViews)
|
|
206
|
+
.where(and(eq(pmoBoardViews.projectId, projectId), eq(pmoBoardViews.isDefault, true)))
|
|
207
|
+
.get();
|
|
184
208
|
if (!row)
|
|
185
209
|
return null;
|
|
186
210
|
return this.rowToBoardView(row);
|
|
@@ -208,22 +232,32 @@ export class ViewStorage {
|
|
|
208
232
|
// Override with explicit filters if provided
|
|
209
233
|
const effectiveFilters = { ...viewFilters, ...filters };
|
|
210
234
|
// Get project metadata using resolved ID
|
|
211
|
-
const projectRow = this.ctx.
|
|
235
|
+
const projectRow = this.ctx.drizzle
|
|
236
|
+
.select({
|
|
237
|
+
id: pmoProjects.id,
|
|
238
|
+
name: pmoProjects.name,
|
|
239
|
+
workflowId: pmoProjects.workflowId,
|
|
240
|
+
updatedAt: pmoProjects.updatedAt,
|
|
241
|
+
})
|
|
242
|
+
.from(pmoProjects)
|
|
243
|
+
.where(eq(pmoProjects.id, resolvedId))
|
|
244
|
+
.get();
|
|
212
245
|
if (!projectRow) {
|
|
213
246
|
throw new PMOError('NOT_FOUND', `Project not found: ${projectIdOrName}. Run init() first.`);
|
|
214
247
|
}
|
|
215
|
-
|
|
216
|
-
const projectMeta = this.ctx.db.prepare(`
|
|
217
|
-
SELECT workflow_id FROM ${T.projects} WHERE id = ?
|
|
218
|
-
`).get(resolvedId);
|
|
219
|
-
const workflowId = projectMeta?.workflow_id || 'default';
|
|
248
|
+
const workflowId = projectRow.workflowId || 'default';
|
|
220
249
|
// Get workflow statuses as columns
|
|
221
|
-
const columnRows = this.ctx.
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
250
|
+
const columnRows = this.ctx.drizzle
|
|
251
|
+
.select({
|
|
252
|
+
id: pmoWorkflowStatuses.id,
|
|
253
|
+
workflowId: pmoWorkflowStatuses.workflowId,
|
|
254
|
+
name: pmoWorkflowStatuses.name,
|
|
255
|
+
position: pmoWorkflowStatuses.position,
|
|
256
|
+
})
|
|
257
|
+
.from(pmoWorkflowStatuses)
|
|
258
|
+
.where(eq(pmoWorkflowStatuses.workflowId, workflowId))
|
|
259
|
+
.orderBy(asc(pmoWorkflowStatuses.position))
|
|
260
|
+
.all();
|
|
227
261
|
// Filter columns if columnIds filter is set
|
|
228
262
|
const filteredColumnRows = effectiveFilters.columnIds?.length
|
|
229
263
|
? columnRows.filter((col) => effectiveFilters.columnIds.includes(col.id))
|
|
@@ -244,82 +278,101 @@ export class ViewStorage {
|
|
|
244
278
|
id: projectRow.id,
|
|
245
279
|
name: projectRow.name,
|
|
246
280
|
columns,
|
|
247
|
-
updatedAt: new Date(projectRow.
|
|
281
|
+
updatedAt: new Date(projectRow.updatedAt),
|
|
248
282
|
};
|
|
249
283
|
}
|
|
250
284
|
/**
|
|
251
285
|
* Get tickets for a column (workflow status) with filters applied.
|
|
252
286
|
*/
|
|
253
287
|
async getTicketsForColumnWithFilters(columnId, projectId, filters) {
|
|
254
|
-
//
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
ws.name as status_name,
|
|
260
|
-
ws.category as status_category
|
|
261
|
-
FROM ${T.tickets} t
|
|
262
|
-
LEFT JOIN ${T.workflow_statuses} ws ON t.status_id = ws.id
|
|
263
|
-
WHERE t.status_id = ? AND t.project_id = ?
|
|
264
|
-
`;
|
|
265
|
-
const params = [columnId, projectId];
|
|
288
|
+
// Build conditions array for dynamic WHERE clause
|
|
289
|
+
const conditions = [
|
|
290
|
+
eq(pmoTickets.statusId, columnId),
|
|
291
|
+
eq(pmoTickets.projectId, projectId),
|
|
292
|
+
];
|
|
266
293
|
// Apply filters
|
|
267
294
|
if (filters.assignee !== undefined) {
|
|
268
295
|
if (filters.assignee === 'unassigned') {
|
|
269
|
-
sql
|
|
296
|
+
conditions.push(or(sql `${pmoTickets.assignee} IS NULL`, eq(pmoTickets.assignee, '')));
|
|
270
297
|
}
|
|
271
298
|
else {
|
|
272
|
-
|
|
273
|
-
params.push(filters.assignee);
|
|
299
|
+
conditions.push(eq(pmoTickets.assignee, filters.assignee));
|
|
274
300
|
}
|
|
275
301
|
}
|
|
276
302
|
if (filters.owner !== undefined) {
|
|
277
|
-
|
|
278
|
-
params.push(filters.owner);
|
|
303
|
+
conditions.push(eq(pmoTickets.owner, filters.owner));
|
|
279
304
|
}
|
|
280
305
|
if (filters.priority !== undefined) {
|
|
281
|
-
sql
|
|
282
|
-
params.push(filters.priority);
|
|
306
|
+
conditions.push(sql `UPPER(${pmoTickets.priority}) = UPPER(${filters.priority})`);
|
|
283
307
|
}
|
|
284
308
|
if (filters.statusCategory !== undefined) {
|
|
285
|
-
|
|
286
|
-
params.push(filters.statusCategory);
|
|
309
|
+
conditions.push(eq(pmoWorkflowStatuses.category, filters.statusCategory));
|
|
287
310
|
}
|
|
288
311
|
if (filters.statusId !== undefined) {
|
|
289
|
-
|
|
290
|
-
params.push(filters.statusId);
|
|
312
|
+
conditions.push(eq(pmoTickets.statusId, filters.statusId));
|
|
291
313
|
}
|
|
292
314
|
if (filters.epicId !== undefined) {
|
|
293
|
-
|
|
294
|
-
params.push(filters.epicId);
|
|
315
|
+
conditions.push(eq(pmoTickets.epicId, filters.epicId));
|
|
295
316
|
}
|
|
296
317
|
if (filters.search !== undefined) {
|
|
297
|
-
sql += ' AND (t.title LIKE ? OR t.description LIKE ?)';
|
|
298
318
|
const searchTerm = `%${filters.search}%`;
|
|
299
|
-
|
|
319
|
+
conditions.push(or(like(pmoTickets.title, searchTerm), like(pmoTickets.description, searchTerm)));
|
|
300
320
|
}
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
321
|
+
const rows = this.ctx.drizzle
|
|
322
|
+
.select({
|
|
323
|
+
id: pmoTickets.id,
|
|
324
|
+
project_id: pmoTickets.projectId,
|
|
325
|
+
title: pmoTickets.title,
|
|
326
|
+
description: pmoTickets.description,
|
|
327
|
+
priority: pmoTickets.priority,
|
|
328
|
+
category: pmoTickets.category,
|
|
329
|
+
status: pmoTickets.status,
|
|
330
|
+
status_id: pmoTickets.statusId,
|
|
331
|
+
owner: pmoTickets.owner,
|
|
332
|
+
assignee: pmoTickets.assignee,
|
|
333
|
+
branch: pmoTickets.branch,
|
|
334
|
+
spec_id: pmoTickets.specId,
|
|
335
|
+
epic_id: pmoTickets.epicId,
|
|
336
|
+
labels: pmoTickets.labels,
|
|
337
|
+
position: pmoTickets.position,
|
|
338
|
+
created_at: pmoTickets.createdAt,
|
|
339
|
+
updated_at: pmoTickets.updatedAt,
|
|
340
|
+
last_synced_from_spec: pmoTickets.lastSyncedFromSpec,
|
|
341
|
+
last_synced_from_board: pmoTickets.lastSyncedFromBoard,
|
|
342
|
+
board_position: pmoWorkflowStatuses.position,
|
|
343
|
+
column_name: pmoWorkflowStatuses.name,
|
|
344
|
+
status_name: pmoWorkflowStatuses.name,
|
|
345
|
+
status_category: pmoWorkflowStatuses.category,
|
|
346
|
+
})
|
|
347
|
+
.from(pmoTickets)
|
|
348
|
+
.leftJoin(pmoWorkflowStatuses, eq(pmoTickets.statusId, pmoWorkflowStatuses.id))
|
|
349
|
+
.where(and(...conditions))
|
|
350
|
+
.orderBy(asc(pmoTickets.position), asc(pmoTickets.createdAt))
|
|
351
|
+
.all();
|
|
304
352
|
return Promise.all(rows.map((row) => this.rowToTicketWithColumn(row)));
|
|
305
353
|
}
|
|
306
354
|
async rowToTicketWithColumn(row) {
|
|
307
355
|
// Get subtasks
|
|
308
|
-
const subtaskRows = this.ctx.
|
|
309
|
-
|
|
310
|
-
|
|
356
|
+
const subtaskRows = this.ctx.drizzle
|
|
357
|
+
.select()
|
|
358
|
+
.from(pmoSubtasks)
|
|
359
|
+
.where(eq(pmoSubtasks.ticketId, row.id))
|
|
360
|
+
.orderBy(asc(pmoSubtasks.position))
|
|
361
|
+
.all();
|
|
311
362
|
const subtasks = subtaskRows.map((s) => ({
|
|
312
363
|
id: s.id,
|
|
313
364
|
title: s.title,
|
|
314
|
-
done: s.done
|
|
365
|
+
done: s.done ?? false,
|
|
315
366
|
}));
|
|
316
367
|
// Get metadata
|
|
317
|
-
const metadataRows = this.ctx.
|
|
318
|
-
|
|
319
|
-
|
|
368
|
+
const metadataRows = this.ctx.drizzle
|
|
369
|
+
.select({ key: pmoTicketMetadata.key, value: pmoTicketMetadata.value })
|
|
370
|
+
.from(pmoTicketMetadata)
|
|
371
|
+
.where(eq(pmoTicketMetadata.ticketId, row.id))
|
|
372
|
+
.all();
|
|
320
373
|
const metadata = {};
|
|
321
374
|
for (const m of metadataRows) {
|
|
322
|
-
metadata[m.key] = m.value;
|
|
375
|
+
metadata[m.key] = m.value || '';
|
|
323
376
|
}
|
|
324
377
|
// Parse labels from JSON
|
|
325
378
|
let labels = [];
|
|
@@ -347,9 +400,9 @@ export class ViewStorage {
|
|
|
347
400
|
subtasks,
|
|
348
401
|
labels,
|
|
349
402
|
metadata,
|
|
350
|
-
acceptanceCriteria: getAcceptanceCriteriaSync(this.ctx.
|
|
351
|
-
createdAt: new Date(row.created_at),
|
|
352
|
-
updatedAt: new Date(row.updated_at),
|
|
403
|
+
acceptanceCriteria: getAcceptanceCriteriaSync(this.ctx.drizzle, row.id),
|
|
404
|
+
createdAt: new Date(row.created_at || Date.now()),
|
|
405
|
+
updatedAt: new Date(row.updated_at || Date.now()),
|
|
353
406
|
lastSyncedFromSpec: row.last_synced_from_spec
|
|
354
407
|
? new Date(row.last_synced_from_spec)
|
|
355
408
|
: undefined,
|
|
@@ -388,15 +441,15 @@ export class ViewStorage {
|
|
|
388
441
|
rowToBoardView(row) {
|
|
389
442
|
return {
|
|
390
443
|
id: row.id,
|
|
391
|
-
projectId: row.
|
|
444
|
+
projectId: row.projectId,
|
|
392
445
|
name: row.name,
|
|
393
446
|
description: row.description || undefined,
|
|
394
|
-
isDefault: row.
|
|
447
|
+
isDefault: row.isDefault ?? false,
|
|
395
448
|
filters: row.filters ? JSON.parse(row.filters) : {},
|
|
396
|
-
groupBy: row.
|
|
397
|
-
sortBy: row.
|
|
398
|
-
createdAt: new Date(row.
|
|
399
|
-
updatedAt: new Date(row.
|
|
449
|
+
groupBy: row.groupBy,
|
|
450
|
+
sortBy: row.sortBy,
|
|
451
|
+
createdAt: new Date(row.createdAt || Date.now()),
|
|
452
|
+
updatedAt: new Date(row.updatedAt || Date.now()),
|
|
400
453
|
};
|
|
401
454
|
}
|
|
402
455
|
}
|
|
@@ -86,6 +86,8 @@ export interface OutputMetadata {
|
|
|
86
86
|
flags: Record<string, unknown>;
|
|
87
87
|
/** Timestamp of the output */
|
|
88
88
|
timestamp?: string;
|
|
89
|
+
/** Resolved PR mode after flag precedence ('create-pr' | 'no-pr') */
|
|
90
|
+
resolvedPRMode?: string;
|
|
89
91
|
}
|
|
90
92
|
/**
|
|
91
93
|
* JSON output when a prompt would be shown
|
|
@@ -243,6 +245,9 @@ export interface MachineOutputFlags {
|
|
|
243
245
|
* - stdout is not a TTY (e.g., piped output)
|
|
244
246
|
* - PRLT_JSON=1 environment variable is set (overrides TTY detection)
|
|
245
247
|
*
|
|
248
|
+
* Returns false if:
|
|
249
|
+
* - PRLT_FORCE_TEXT=1 is set (forces text output in non-TTY environments, useful for testing)
|
|
250
|
+
*
|
|
246
251
|
* @returns true if either stdin or stdout is not a TTY, or PRLT_JSON=1 is set
|
|
247
252
|
*/
|
|
248
253
|
export declare function isNonTTY(): boolean;
|
package/dist/lib/prompt-json.js
CHANGED
|
@@ -149,9 +149,18 @@ export function validateJsonEnvelope(obj) {
|
|
|
149
149
|
* - stdout is not a TTY (e.g., piped output)
|
|
150
150
|
* - PRLT_JSON=1 environment variable is set (overrides TTY detection)
|
|
151
151
|
*
|
|
152
|
+
* Returns false if:
|
|
153
|
+
* - PRLT_FORCE_TEXT=1 is set (forces text output in non-TTY environments, useful for testing)
|
|
154
|
+
*
|
|
152
155
|
* @returns true if either stdin or stdout is not a TTY, or PRLT_JSON=1 is set
|
|
153
156
|
*/
|
|
154
157
|
export function isNonTTY() {
|
|
158
|
+
// PRLT_FORCE_TEXT overrides non-TTY detection, forcing human-readable text output.
|
|
159
|
+
// Used in E2E tests where execSync creates a non-TTY child process but tests
|
|
160
|
+
// assert on styled text output.
|
|
161
|
+
if (process.env.PRLT_FORCE_TEXT === '1' || process.env.PRLT_FORCE_TEXT === 'true') {
|
|
162
|
+
return false;
|
|
163
|
+
}
|
|
155
164
|
if (process.env.PRLT_JSON === '1' || process.env.PRLT_JSON === 'true') {
|
|
156
165
|
return true;
|
|
157
166
|
}
|