@damper/cli 0.9.3 → 0.9.5
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/services/claude.js
CHANGED
|
@@ -174,12 +174,14 @@ export async function postTaskFlow(options) {
|
|
|
174
174
|
let taskStatus;
|
|
175
175
|
let taskTitle;
|
|
176
176
|
let hasCommits = false;
|
|
177
|
+
let isPublicTask = false;
|
|
177
178
|
try {
|
|
178
179
|
const api = createDamperApi(apiKey);
|
|
179
180
|
const task = await api.getTask(taskId);
|
|
180
181
|
taskStatus = task.status;
|
|
181
182
|
taskTitle = task.title;
|
|
182
183
|
hasCommits = (task.commits?.length ?? 0) > 0;
|
|
184
|
+
isPublicTask = !!task.publicUrl;
|
|
183
185
|
}
|
|
184
186
|
catch {
|
|
185
187
|
console.log(pc.yellow('Could not fetch task status from Damper.'));
|
|
@@ -254,6 +256,10 @@ export async function postTaskFlow(options) {
|
|
|
254
256
|
console.log(pc.yellow('⚠ Unpushed commits detected'));
|
|
255
257
|
}
|
|
256
258
|
console.log();
|
|
259
|
+
// Offer to add to changelog if task is completed
|
|
260
|
+
if (taskStatus === 'done') {
|
|
261
|
+
await offerChangelogFlow({ taskId, taskTitle, apiKey, isPublic: isPublicTask, confirm, select });
|
|
262
|
+
}
|
|
257
263
|
// Offer actions based on state
|
|
258
264
|
const hasChanges = hasUnpushedCommits || hasUncommittedChanges;
|
|
259
265
|
let worktreeRemoved = false;
|
|
@@ -441,6 +447,67 @@ export async function postTaskFlow(options) {
|
|
|
441
447
|
}
|
|
442
448
|
console.log();
|
|
443
449
|
}
|
|
450
|
+
/**
|
|
451
|
+
* Ask user if they want to add the completed task to a changelog
|
|
452
|
+
*/
|
|
453
|
+
async function offerChangelogFlow(options) {
|
|
454
|
+
const { taskId, taskTitle, apiKey, isPublic, confirm, select } = options;
|
|
455
|
+
const { input } = await import('@inquirer/prompts');
|
|
456
|
+
const addToChangelog = await confirm({
|
|
457
|
+
message: 'Add this task to a changelog?',
|
|
458
|
+
default: isPublic,
|
|
459
|
+
});
|
|
460
|
+
if (!addToChangelog)
|
|
461
|
+
return;
|
|
462
|
+
try {
|
|
463
|
+
const { createDamperApi } = await import('./damper-api.js');
|
|
464
|
+
const api = createDamperApi(apiKey);
|
|
465
|
+
// Fetch draft changelogs
|
|
466
|
+
const { changelogs } = await api.listChangelogs({ status: 'draft', limit: 10 });
|
|
467
|
+
let changelogId;
|
|
468
|
+
if (changelogs.length > 0) {
|
|
469
|
+
const choice = await select({
|
|
470
|
+
message: 'Which changelog?',
|
|
471
|
+
choices: [
|
|
472
|
+
...changelogs.map((cl) => ({
|
|
473
|
+
name: `${cl.title}${cl.version ? ` (${cl.version})` : ''} — ${cl.roadmapItemCount} item${cl.roadmapItemCount !== 1 ? 's' : ''}`,
|
|
474
|
+
value: cl.id,
|
|
475
|
+
})),
|
|
476
|
+
{ name: 'Create new changelog', value: '__new__' },
|
|
477
|
+
],
|
|
478
|
+
});
|
|
479
|
+
if (choice === '__new__') {
|
|
480
|
+
const title = await input({
|
|
481
|
+
message: 'Changelog title:',
|
|
482
|
+
default: `Release ${new Date().toISOString().slice(0, 10)}`,
|
|
483
|
+
});
|
|
484
|
+
const result = await api.createChangelog({ title });
|
|
485
|
+
changelogId = result.id;
|
|
486
|
+
console.log(pc.green(`✓ Created changelog: ${title}`));
|
|
487
|
+
}
|
|
488
|
+
else {
|
|
489
|
+
changelogId = choice;
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
else {
|
|
493
|
+
// No drafts — create one
|
|
494
|
+
const title = await input({
|
|
495
|
+
message: 'No draft changelogs found. Create one — title:',
|
|
496
|
+
default: `Release ${new Date().toISOString().slice(0, 10)}`,
|
|
497
|
+
});
|
|
498
|
+
const result = await api.createChangelog({ title });
|
|
499
|
+
changelogId = result.id;
|
|
500
|
+
console.log(pc.green(`✓ Created changelog: ${title}`));
|
|
501
|
+
}
|
|
502
|
+
// Add the task
|
|
503
|
+
const result = await api.addToChangelog(changelogId, [taskId]);
|
|
504
|
+
console.log(pc.green(`✓ Added "${taskTitle || taskId}" to changelog (${result.roadmapItemCount} total items)\n`));
|
|
505
|
+
}
|
|
506
|
+
catch (err) {
|
|
507
|
+
const error = err;
|
|
508
|
+
console.log(pc.yellow(`Could not add to changelog: ${error.message}\n`));
|
|
509
|
+
}
|
|
510
|
+
}
|
|
444
511
|
/**
|
|
445
512
|
* Launch Claude to review and complete a task
|
|
446
513
|
*/
|
|
@@ -37,6 +37,7 @@ export interface TaskDetail extends Task {
|
|
|
37
37
|
}>;
|
|
38
38
|
lockedBy?: string | null;
|
|
39
39
|
lockedAt?: string | null;
|
|
40
|
+
publicUrl?: string | null;
|
|
40
41
|
}
|
|
41
42
|
export interface ContextSection {
|
|
42
43
|
section: string;
|
|
@@ -76,6 +77,16 @@ export interface Module {
|
|
|
76
77
|
tags?: string[];
|
|
77
78
|
updatedAt: string;
|
|
78
79
|
}
|
|
80
|
+
export interface Changelog {
|
|
81
|
+
id: string;
|
|
82
|
+
title: string;
|
|
83
|
+
version?: string | null;
|
|
84
|
+
date?: string | null;
|
|
85
|
+
status: 'draft' | 'published';
|
|
86
|
+
publishedAt?: string | null;
|
|
87
|
+
roadmapItemCount: number;
|
|
88
|
+
contentPreview: string;
|
|
89
|
+
}
|
|
79
90
|
export interface AgentInstructions {
|
|
80
91
|
format: 'markdown' | 'section';
|
|
81
92
|
content: string;
|
|
@@ -105,6 +116,17 @@ export declare class DamperApi {
|
|
|
105
116
|
quarter?: string;
|
|
106
117
|
sort?: 'importance' | 'newest' | 'votes';
|
|
107
118
|
limit?: number;
|
|
119
|
+
offset?: number;
|
|
120
|
+
}): Promise<{
|
|
121
|
+
project: string;
|
|
122
|
+
tasks: Task[];
|
|
123
|
+
total: number;
|
|
124
|
+
}>;
|
|
125
|
+
listAllTasks(filters?: {
|
|
126
|
+
status?: 'planned' | 'in_progress' | 'done' | 'all';
|
|
127
|
+
type?: 'bug' | 'feature' | 'improvement' | 'task';
|
|
128
|
+
quarter?: string;
|
|
129
|
+
sort?: 'importance' | 'newest' | 'votes';
|
|
108
130
|
}): Promise<{
|
|
109
131
|
project: string;
|
|
110
132
|
tasks: Task[];
|
|
@@ -171,6 +193,32 @@ export declare class DamperApi {
|
|
|
171
193
|
}>;
|
|
172
194
|
getModule(name: string): Promise<Module>;
|
|
173
195
|
getAgentInstructions(format?: 'markdown' | 'section'): Promise<AgentInstructions>;
|
|
196
|
+
listChangelogs(filters?: {
|
|
197
|
+
status?: 'draft' | 'published';
|
|
198
|
+
limit?: number;
|
|
199
|
+
sort?: 'newest' | 'oldest';
|
|
200
|
+
}): Promise<{
|
|
201
|
+
changelogs: Changelog[];
|
|
202
|
+
}>;
|
|
203
|
+
createChangelog(data: {
|
|
204
|
+
title: string;
|
|
205
|
+
content?: string;
|
|
206
|
+
version?: string;
|
|
207
|
+
status?: 'draft' | 'published';
|
|
208
|
+
}): Promise<{
|
|
209
|
+
id: string;
|
|
210
|
+
title: string;
|
|
211
|
+
status: string;
|
|
212
|
+
}>;
|
|
213
|
+
addToChangelog(changelogId: string, taskIds: string[]): Promise<{
|
|
214
|
+
id: string;
|
|
215
|
+
title: string;
|
|
216
|
+
roadmapItemCount: number;
|
|
217
|
+
addedItems: Array<{
|
|
218
|
+
id: string;
|
|
219
|
+
title: string;
|
|
220
|
+
}>;
|
|
221
|
+
}>;
|
|
174
222
|
createTask(title: string, type?: 'bug' | 'feature' | 'improvement' | 'task', description?: string): Promise<Task>;
|
|
175
223
|
deleteTask(taskId: string): Promise<{
|
|
176
224
|
id: string;
|
|
@@ -40,9 +40,23 @@ export class DamperApi {
|
|
|
40
40
|
params.set('sort', filters.sort);
|
|
41
41
|
if (filters?.limit)
|
|
42
42
|
params.set('limit', String(filters.limit));
|
|
43
|
+
if (filters?.offset)
|
|
44
|
+
params.set('offset', String(filters.offset));
|
|
43
45
|
const query = params.toString();
|
|
44
46
|
const data = await this.request('GET', `/api/agent/tasks${query ? `?${query}` : ''}`);
|
|
45
|
-
return { project: data.project.name, tasks: data.tasks };
|
|
47
|
+
return { project: data.project.name, tasks: data.tasks, total: data.total };
|
|
48
|
+
}
|
|
49
|
+
async listAllTasks(filters) {
|
|
50
|
+
const pageSize = 100;
|
|
51
|
+
const first = await this.listTasks({ ...filters, limit: pageSize });
|
|
52
|
+
const allTasks = [...first.tasks];
|
|
53
|
+
while (allTasks.length < first.total) {
|
|
54
|
+
const page = await this.listTasks({ ...filters, limit: pageSize, offset: allTasks.length });
|
|
55
|
+
allTasks.push(...page.tasks);
|
|
56
|
+
if (page.tasks.length === 0)
|
|
57
|
+
break; // safety: avoid infinite loop
|
|
58
|
+
}
|
|
59
|
+
return { project: first.project, tasks: allTasks };
|
|
46
60
|
}
|
|
47
61
|
async getTask(taskId) {
|
|
48
62
|
return this.request('GET', `/api/agent/tasks/${taskId}`);
|
|
@@ -156,6 +170,24 @@ This project uses Damper MCP for task tracking. **You MUST follow this workflow.
|
|
|
156
170
|
lastModified,
|
|
157
171
|
};
|
|
158
172
|
}
|
|
173
|
+
// Changelogs
|
|
174
|
+
async listChangelogs(filters) {
|
|
175
|
+
const params = new URLSearchParams();
|
|
176
|
+
if (filters?.status)
|
|
177
|
+
params.set('status', filters.status);
|
|
178
|
+
if (filters?.limit)
|
|
179
|
+
params.set('limit', String(filters.limit));
|
|
180
|
+
if (filters?.sort)
|
|
181
|
+
params.set('sort', filters.sort);
|
|
182
|
+
const query = params.toString();
|
|
183
|
+
return this.request('GET', `/api/agent/changelogs${query ? `?${query}` : ''}`);
|
|
184
|
+
}
|
|
185
|
+
async createChangelog(data) {
|
|
186
|
+
return this.request('POST', '/api/agent/changelogs', data);
|
|
187
|
+
}
|
|
188
|
+
async addToChangelog(changelogId, taskIds) {
|
|
189
|
+
return this.request('POST', `/api/agent/changelogs/${changelogId}/items`, { taskIds });
|
|
190
|
+
}
|
|
159
191
|
// Create task
|
|
160
192
|
async createTask(title, type = 'task', description) {
|
|
161
193
|
return this.request('POST', '/api/agent/tasks', { title, type, status: 'planned', description });
|
package/dist/ui/task-picker.js
CHANGED
|
@@ -118,12 +118,11 @@ function formatTaskChoice(choice, titleWidth, layout) {
|
|
|
118
118
|
}
|
|
119
119
|
export async function pickTask(options) {
|
|
120
120
|
const { api, worktrees, typeFilter, statusFilter } = options;
|
|
121
|
-
// Fetch tasks from Damper
|
|
122
|
-
const { tasks, project } = await api.
|
|
121
|
+
// Fetch all tasks from Damper (paginated)
|
|
122
|
+
const { tasks, project } = await api.listAllTasks({
|
|
123
123
|
status: statusFilter || 'all',
|
|
124
124
|
type: typeFilter,
|
|
125
125
|
sort: 'importance',
|
|
126
|
-
limit: 100,
|
|
127
126
|
});
|
|
128
127
|
// Filter out completed tasks unless specifically requested
|
|
129
128
|
const availableTasks = tasks.filter(t => statusFilter === 'done' || statusFilter === 'all' ||
|