@damper/cli 0.9.5 → 0.9.7
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/release.js
CHANGED
|
@@ -23,10 +23,15 @@ export async function releaseCommand() {
|
|
|
23
23
|
process.exit(1);
|
|
24
24
|
}
|
|
25
25
|
const api = createDamperApi(apiKey);
|
|
26
|
-
// Get tasks that are in_progress (locked)
|
|
27
|
-
const
|
|
26
|
+
// Get tasks that are in_progress or in_review (locked)
|
|
27
|
+
const [ipResult, irResult] = await Promise.all([
|
|
28
|
+
api.listTasks({ status: 'in_progress' }),
|
|
29
|
+
api.listTasks({ status: 'in_review' }),
|
|
30
|
+
]);
|
|
31
|
+
const tasks = [...ipResult.tasks, ...irResult.tasks];
|
|
32
|
+
const project = ipResult.project;
|
|
28
33
|
if (tasks.length === 0) {
|
|
29
|
-
console.log(pc.yellow('\nNo in-progress tasks to release.\n'));
|
|
34
|
+
console.log(pc.yellow('\nNo in-progress or in-review tasks to release.\n'));
|
|
30
35
|
return;
|
|
31
36
|
}
|
|
32
37
|
console.log(pc.bold(`\nProject: ${project}`));
|
package/dist/commands/start.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export interface StartOptions {
|
|
2
2
|
taskId?: string;
|
|
3
3
|
type?: 'bug' | 'feature' | 'improvement' | 'task';
|
|
4
|
-
status?: 'planned' | 'in_progress' | 'done' | 'all';
|
|
4
|
+
status?: 'planned' | 'in_progress' | 'in_review' | 'done' | 'all';
|
|
5
5
|
yolo?: boolean;
|
|
6
6
|
force?: boolean;
|
|
7
7
|
}
|
package/dist/services/claude.js
CHANGED
|
@@ -243,7 +243,7 @@ export async function postTaskFlow(options) {
|
|
|
243
243
|
}
|
|
244
244
|
// Show status
|
|
245
245
|
if (taskStatus) {
|
|
246
|
-
const statusColor = taskStatus === 'done' ? pc.green : taskStatus === 'in_progress' ? pc.yellow : pc.dim;
|
|
246
|
+
const statusColor = taskStatus === 'done' ? pc.green : (taskStatus === 'in_progress' || taskStatus === 'in_review') ? pc.yellow : pc.dim;
|
|
247
247
|
console.log(`Task status: ${statusColor(taskStatus)}`);
|
|
248
248
|
}
|
|
249
249
|
if (currentBranch) {
|
|
@@ -256,8 +256,8 @@ export async function postTaskFlow(options) {
|
|
|
256
256
|
console.log(pc.yellow('⚠ Unpushed commits detected'));
|
|
257
257
|
}
|
|
258
258
|
console.log();
|
|
259
|
-
// Offer to add to changelog if task is completed
|
|
260
|
-
if (taskStatus === 'done') {
|
|
259
|
+
// Offer to add to changelog if task is completed (done or in_review)
|
|
260
|
+
if (taskStatus === 'done' || taskStatus === 'in_review') {
|
|
261
261
|
await offerChangelogFlow({ taskId, taskTitle, apiKey, isPublic: isPublicTask, confirm, select });
|
|
262
262
|
}
|
|
263
263
|
// Offer actions based on state
|
|
@@ -352,9 +352,9 @@ export async function postTaskFlow(options) {
|
|
|
352
352
|
}
|
|
353
353
|
}
|
|
354
354
|
}
|
|
355
|
-
// Offer cleanup if task is done or abandoned
|
|
356
|
-
if (taskStatus === 'done' || taskStatus === 'planned') {
|
|
357
|
-
const statusText = taskStatus === 'done' ? 'completed' : 'not started/abandoned';
|
|
355
|
+
// Offer cleanup if task is done, in_review, or abandoned
|
|
356
|
+
if (taskStatus === 'done' || taskStatus === 'in_review' || taskStatus === 'planned') {
|
|
357
|
+
const statusText = taskStatus === 'done' ? 'completed' : taskStatus === 'in_review' ? 'in review' : 'not started/abandoned';
|
|
358
358
|
const shouldCleanup = await confirm({
|
|
359
359
|
message: `Task is ${statusText}. Remove worktree and branch?`,
|
|
360
360
|
default: taskStatus === 'done',
|
|
@@ -435,7 +435,7 @@ export async function postTaskFlow(options) {
|
|
|
435
435
|
console.log(pc.dim(`\n Task removed. No changes saved.\n`));
|
|
436
436
|
}
|
|
437
437
|
else {
|
|
438
|
-
const statusColor = taskStatus === 'done' ? pc.green : taskStatus === 'in_progress' ? pc.yellow : pc.dim;
|
|
438
|
+
const statusColor = taskStatus === 'done' ? pc.green : (taskStatus === 'in_progress' || taskStatus === 'in_review') ? pc.yellow : pc.dim;
|
|
439
439
|
const statusLabel = taskStatus || 'unknown';
|
|
440
440
|
console.log(pc.bold(`\n #${shortIdRaw(taskId)} ${taskTitle || 'Unknown task'}`) + ` ${statusColor(statusLabel)}`);
|
|
441
441
|
if (!worktreeRemoved) {
|
|
@@ -111,7 +111,7 @@ export declare class DamperApi {
|
|
|
111
111
|
constructor(apiKey: string);
|
|
112
112
|
private request;
|
|
113
113
|
listTasks(filters?: {
|
|
114
|
-
status?: 'planned' | 'in_progress' | 'done' | 'all';
|
|
114
|
+
status?: 'planned' | 'in_progress' | 'in_review' | 'done' | 'all';
|
|
115
115
|
type?: 'bug' | 'feature' | 'improvement' | 'task';
|
|
116
116
|
quarter?: string;
|
|
117
117
|
sort?: 'importance' | 'newest' | 'votes';
|
|
@@ -123,7 +123,7 @@ export declare class DamperApi {
|
|
|
123
123
|
total: number;
|
|
124
124
|
}>;
|
|
125
125
|
listAllTasks(filters?: {
|
|
126
|
-
status?: 'planned' | 'in_progress' | 'done' | 'all';
|
|
126
|
+
status?: 'planned' | 'in_progress' | 'in_review' | 'done' | 'all';
|
|
127
127
|
type?: 'bug' | 'feature' | 'improvement' | 'task';
|
|
128
128
|
quarter?: string;
|
|
129
129
|
sort?: 'importance' | 'newest' | 'votes';
|
package/dist/ui/task-picker.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ interface TaskPickerOptions {
|
|
|
4
4
|
api: DamperApi;
|
|
5
5
|
worktrees: WorktreeState[];
|
|
6
6
|
typeFilter?: 'bug' | 'feature' | 'improvement' | 'task';
|
|
7
|
-
statusFilter?: 'planned' | 'in_progress' | 'done' | 'all';
|
|
7
|
+
statusFilter?: 'planned' | 'in_progress' | 'in_review' | 'done' | 'all';
|
|
8
8
|
}
|
|
9
9
|
interface TaskPickerResult {
|
|
10
10
|
task: Task;
|
package/dist/ui/task-picker.js
CHANGED
|
@@ -126,7 +126,7 @@ export async function pickTask(options) {
|
|
|
126
126
|
});
|
|
127
127
|
// Filter out completed tasks unless specifically requested
|
|
128
128
|
const availableTasks = tasks.filter(t => statusFilter === 'done' || statusFilter === 'all' ||
|
|
129
|
-
(t.status === 'planned' || t.status === 'in_progress'));
|
|
129
|
+
(t.status === 'planned' || t.status === 'in_progress' || t.status === 'in_review'));
|
|
130
130
|
// Match worktrees with tasks
|
|
131
131
|
const inProgressChoices = [];
|
|
132
132
|
const worktreeTaskIds = new Set();
|
|
@@ -155,7 +155,7 @@ export async function pickTask(options) {
|
|
|
155
155
|
lockedBy: taskAny.lockedBy,
|
|
156
156
|
});
|
|
157
157
|
}
|
|
158
|
-
else if (task.status === 'planned' || task.status === 'in_progress') {
|
|
158
|
+
else if (task.status === 'planned' || task.status === 'in_progress' || task.status === 'in_review') {
|
|
159
159
|
availableChoices.push({ type: 'available', task });
|
|
160
160
|
}
|
|
161
161
|
}
|
|
@@ -260,6 +260,34 @@ export async function pickTask(options) {
|
|
|
260
260
|
action,
|
|
261
261
|
};
|
|
262
262
|
}
|
|
263
|
+
async function generateTaskTitle(instructions, type) {
|
|
264
|
+
try {
|
|
265
|
+
const { execa } = await import('execa');
|
|
266
|
+
const prompt = [
|
|
267
|
+
`Generate a task title for a ${type} task.`,
|
|
268
|
+
'Rules:',
|
|
269
|
+
'- Max 60 characters, sentence case, no trailing period',
|
|
270
|
+
'- Verb prefix matching type: bug → "Fix …", feature → "Add …", improvement → "Improve …", task → "Set up …" / "Update …"',
|
|
271
|
+
'- Specific enough to understand without reading a description',
|
|
272
|
+
'- Examples: "Add dark mode support", "Fix login timeout on slow connections", "Improve search result ranking"',
|
|
273
|
+
'Return ONLY the title, nothing else.',
|
|
274
|
+
'',
|
|
275
|
+
`User input: ${instructions}`,
|
|
276
|
+
].join('\n');
|
|
277
|
+
const { stdout } = await execa('claude', ['--print', '--model', 'haiku', prompt], {
|
|
278
|
+
stdio: 'pipe',
|
|
279
|
+
timeout: 15000,
|
|
280
|
+
});
|
|
281
|
+
const title = stdout.trim();
|
|
282
|
+
if (title && title.length <= 80 && !title.includes('\n')) {
|
|
283
|
+
return title;
|
|
284
|
+
}
|
|
285
|
+
return null;
|
|
286
|
+
}
|
|
287
|
+
catch {
|
|
288
|
+
return null;
|
|
289
|
+
}
|
|
290
|
+
}
|
|
263
291
|
async function handleCreateNewTask(api) {
|
|
264
292
|
const instructions = await input({
|
|
265
293
|
message: 'What needs to be done?',
|
|
@@ -274,16 +302,23 @@ async function handleCreateNewTask(api) {
|
|
|
274
302
|
{ name: 'Task', value: 'task' },
|
|
275
303
|
],
|
|
276
304
|
});
|
|
277
|
-
// Use instructions as description; derive a placeholder title
|
|
278
305
|
const trimmed = instructions.trim();
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
306
|
+
// Generate title with Claude, fall back to truncation
|
|
307
|
+
console.log(pc.dim('\nGenerating title...'));
|
|
308
|
+
const generatedTitle = await generateTaskTitle(trimmed, type);
|
|
309
|
+
let title;
|
|
310
|
+
if (generatedTitle) {
|
|
311
|
+
title = generatedTitle;
|
|
312
|
+
}
|
|
313
|
+
else {
|
|
314
|
+
const maxTitleLen = 60;
|
|
315
|
+
title = trimmed.length <= maxTitleLen
|
|
316
|
+
? trimmed
|
|
317
|
+
: trimmed.slice(0, trimmed.lastIndexOf(' ', maxTitleLen) || maxTitleLen) + '…';
|
|
318
|
+
}
|
|
319
|
+
console.log(pc.dim('Creating task in Damper...'));
|
|
320
|
+
const task = await api.createTask(title, type, trimmed);
|
|
285
321
|
console.log(pc.green(`✓ Created task #${shortIdRaw(task.id)}: ${task.title}`));
|
|
286
|
-
console.log(pc.dim(' The agent will refine the title after planning.'));
|
|
287
322
|
return {
|
|
288
323
|
task,
|
|
289
324
|
isResume: false,
|