@damper/cli 0.9.20 → 0.10.0

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.
@@ -31,33 +31,52 @@ export function getConfiguredApiKey() {
31
31
  if (process.env.DAMPER_API_KEY) {
32
32
  return process.env.DAMPER_API_KEY;
33
33
  }
34
- // Then check Claude settings (legacy global key)
34
+ // Then check Claude settings (global MCP config)
35
35
  if (!fs.existsSync(CLAUDE_SETTINGS_FILE)) {
36
36
  return undefined;
37
37
  }
38
38
  try {
39
39
  const settings = JSON.parse(fs.readFileSync(CLAUDE_SETTINGS_FILE, 'utf-8'));
40
- return settings.mcpServers?.damper?.env?.DAMPER_API_KEY;
40
+ const config = settings.mcpServers?.damper;
41
+ if (!config)
42
+ return undefined;
43
+ // HTTP config: extract from Authorization header
44
+ if ('type' in config && config.type === 'http') {
45
+ const auth = config.headers?.Authorization;
46
+ return auth?.startsWith('Bearer ') ? auth.slice(7) : undefined;
47
+ }
48
+ // Legacy stdio config: extract from env
49
+ if ('env' in config) {
50
+ return config.env?.DAMPER_API_KEY;
51
+ }
52
+ return undefined;
41
53
  }
42
54
  catch {
43
55
  return undefined;
44
56
  }
45
57
  }
58
+ /** MCP endpoint URL (matches server /mcp route) */
59
+ const MCP_URL = process.env.DAMPER_API_URL
60
+ ? `${process.env.DAMPER_API_URL}/mcp`
61
+ : 'https://api.usedamper.com/mcp';
46
62
  /**
47
- * Get the recommended MCP configuration
48
- * Note: API key is passed via environment when launching Claude, not stored in config
63
+ * Get the recommended MCP configuration (hosted Streamable HTTP)
49
64
  */
50
- export function getDamperMcpConfig() {
51
- return {
52
- command: 'npx',
53
- args: ['-y', '@damper/mcp'],
65
+ export function getDamperMcpConfig(apiKey) {
66
+ const config = {
67
+ type: 'http',
68
+ url: MCP_URL,
54
69
  };
70
+ if (apiKey) {
71
+ config.headers = { Authorization: `Bearer ${apiKey}` };
72
+ }
73
+ return config;
55
74
  }
56
75
  /**
57
76
  * Configure Damper MCP in Claude settings (global)
58
- * Note: API key is NOT stored here - it's passed via environment when launching Claude
77
+ * With HTTP transport, the API key is stored in the config headers.
59
78
  */
60
- export function configureDamperMcp() {
79
+ export function configureDamperMcp(apiKey) {
61
80
  // Ensure directory exists
62
81
  if (!fs.existsSync(CLAUDE_SETTINGS_DIR)) {
63
82
  fs.mkdirSync(CLAUDE_SETTINGS_DIR, { recursive: true });
@@ -73,11 +92,11 @@ export function configureDamperMcp() {
73
92
  settings = {};
74
93
  }
75
94
  }
76
- // Add/update MCP config (without API key - it comes from env)
95
+ // Add/update MCP config
77
96
  if (!settings.mcpServers) {
78
97
  settings.mcpServers = {};
79
98
  }
80
- settings.mcpServers.damper = getDamperMcpConfig();
99
+ settings.mcpServers.damper = getDamperMcpConfig(apiKey);
81
100
  // Write back
82
101
  fs.writeFileSync(CLAUDE_SETTINGS_FILE, JSON.stringify(settings, null, 2));
83
102
  }
@@ -120,7 +139,7 @@ export async function launchClaude(options) {
120
139
  if (!isResume) {
121
140
  // Show workflow explanation only for new tasks
122
141
  console.log(pc.bold('Workflow:'));
123
- console.log(pc.dim(' 1. Claude reads TASK_CONTEXT.md and creates a plan'));
142
+ console.log(pc.dim(' 1. Claude fetches task details from Damper MCP and creates a plan'));
124
143
  if (!yolo) {
125
144
  console.log(pc.dim(' 2. You approve the plan before Claude makes changes'));
126
145
  }
@@ -130,8 +149,6 @@ export async function launchClaude(options) {
130
149
  }
131
150
  console.log(pc.bold('When finished:'));
132
151
  console.log(pc.dim(' • Push your branch and create a PR if needed'));
133
- console.log(pc.dim(' • Run: npx @damper/cli cleanup'));
134
- console.log(pc.dim(' (removes worktree and branch)'));
135
152
  console.log();
136
153
  if (yolo) {
137
154
  console.log(pc.yellow('Mode: YOLO (plan then auto-execute)'));
@@ -144,7 +161,7 @@ export async function launchClaude(options) {
144
161
  let args;
145
162
  if (isResume) {
146
163
  // Resume previous conversation so Claude continues where it left off
147
- const resumePrompt = `TASK_CONTEXT.md has been refreshed with the latest notes from Damper. Continue working on task #${taskId}: ${taskTitle}`;
164
+ const resumePrompt = `Continue working on task #${taskId}: ${taskTitle}. Call get_project_context via Damper MCP to refresh context if needed.`;
148
165
  args = yolo
149
166
  ? ['--continue', '--dangerously-skip-permissions', resumePrompt]
150
167
  : ['--continue', resumePrompt];
@@ -153,9 +170,9 @@ export async function launchClaude(options) {
153
170
  else {
154
171
  // New task - enter plan mode first
155
172
  const planInstruction = yolo
156
- ? ' After reading TASK_CONTEXT.md, use the EnterPlanMode tool to create an implementation plan, then execute it without waiting for user approval.'
157
- : ' After reading TASK_CONTEXT.md, use the EnterPlanMode tool to create an implementation plan for user approval before making any code changes.';
158
- const initialPrompt = `IMPORTANT: Start by reading TASK_CONTEXT.md completely. It contains the task description, implementation plan, critical rules, and architecture context.${planInstruction} Task #${taskId}: ${taskTitle}`;
173
+ ? ' Then use the EnterPlanMode tool to create an implementation plan, then execute it without waiting for user approval.'
174
+ : ' Then use the EnterPlanMode tool to create an implementation plan for user approval before making any code changes.';
175
+ const initialPrompt = `IMPORTANT: Start by calling get_project_context via Damper MCP to fetch architecture and conventions, then call start_task to get task details for task #${taskId}: ${taskTitle}.${planInstruction}`;
159
176
  args = yolo ? ['--dangerously-skip-permissions', initialPrompt] : [initialPrompt];
160
177
  console.log(pc.dim(`Launching Claude in ${cwd}...`));
161
178
  }
@@ -194,8 +211,6 @@ export async function postTaskFlow(options) {
194
211
  const { cwd, taskId, apiKey, projectRoot, isNewTask } = options;
195
212
  const { confirm, select } = await import('@inquirer/prompts');
196
213
  const { createDamperApi } = await import('./damper-api.js');
197
- const { removeWorktreeDir } = await import('./worktree.js');
198
- const { removeWorktree } = await import('./state.js');
199
214
  // Check task status from Damper
200
215
  let taskStatus;
201
216
  let taskTitle;
@@ -212,23 +227,6 @@ export async function postTaskFlow(options) {
212
227
  catch {
213
228
  console.log(pc.yellow('Could not fetch task status from Damper.'));
214
229
  }
215
- // Clean up CLI-generated modifications to tracked files before checking git status
216
- // The CLI appends a "## Current Task:" section to CLAUDE.md which is never meant to be committed
217
- try {
218
- const claudeMdPath = path.join(cwd, 'CLAUDE.md');
219
- if (fs.existsSync(claudeMdPath)) {
220
- const content = fs.readFileSync(claudeMdPath, 'utf-8');
221
- const marker = '## Current Task:';
222
- const markerIndex = content.indexOf(marker);
223
- if (markerIndex !== -1) {
224
- const restored = content.slice(0, markerIndex).trimEnd() + '\n';
225
- fs.writeFileSync(claudeMdPath, restored, 'utf-8');
226
- }
227
- }
228
- }
229
- catch {
230
- // Ignore cleanup errors
231
- }
232
230
  // Check git status
233
231
  let hasUnpushedCommits = false;
234
232
  let hasUncommittedChanges = false;
@@ -288,7 +286,6 @@ export async function postTaskFlow(options) {
288
286
  }
289
287
  // Offer actions based on state
290
288
  const hasChanges = hasUnpushedCommits || hasUncommittedChanges;
291
- let worktreeRemoved = false;
292
289
  if (hasChanges) {
293
290
  if (hasUncommittedChanges) {
294
291
  console.log(pc.yellow('⚠ There are uncommitted changes. You may want to commit them first.\n'));
@@ -316,7 +313,7 @@ export async function postTaskFlow(options) {
316
313
  console.log(pc.red('Failed to fetch origin/main. Check your network connection.\n'));
317
314
  return;
318
315
  }
319
- // Step 1: Merge origin/main INTO the feature branch (in worktree)
316
+ // Step 1: Merge origin/main INTO the feature branch
320
317
  console.log(pc.dim('Merging main into feature branch...'));
321
318
  let mainMergedIntoFeature = false;
322
319
  try {
@@ -391,36 +388,17 @@ export async function postTaskFlow(options) {
391
388
  }
392
389
  }
393
390
  }
394
- // Offer cleanup if task is done, in_review, or abandoned
395
- if (taskStatus === 'done' || taskStatus === 'in_review' || taskStatus === 'planned') {
396
- const statusText = taskStatus === 'done' ? 'completed' : taskStatus === 'in_review' ? 'in review' : 'not started/abandoned';
397
- const shouldCleanup = await confirm({
398
- message: `Task is ${statusText}. Remove worktree and branch?`,
399
- default: taskStatus === 'done',
400
- });
401
- if (shouldCleanup) {
402
- try {
403
- await removeWorktreeDir(cwd, projectRoot);
404
- worktreeRemoved = true;
405
- console.log(pc.green('✓ Worktree and branch removed\n'));
406
- }
407
- catch (err) {
408
- const error = err;
409
- console.log(pc.red(`Failed to remove worktree: ${error.message}\n`));
410
- }
411
- }
412
- }
413
- else if (taskStatus === 'in_progress') {
391
+ // Handle task lock based on status
392
+ if (taskStatus === 'in_progress') {
414
393
  // Task not completed - ask whether to keep lock for later resumption
415
394
  const exitAction = await select({
416
395
  message: 'Task is still in progress. What would you like to do?',
417
396
  choices: [
418
397
  { name: 'Keep lock (resume later)', value: 'keep' },
419
398
  { name: 'Release lock (let others pick it up)', value: 'release' },
420
- { name: 'Release lock and remove worktree', value: 'release_cleanup' },
421
399
  ],
422
400
  });
423
- if (exitAction === 'release' || exitAction === 'release_cleanup') {
401
+ if (exitAction === 'release') {
424
402
  console.log(pc.dim('\nReleasing task lock...'));
425
403
  try {
426
404
  const api = createDamperApi(apiKey);
@@ -431,17 +409,6 @@ export async function postTaskFlow(options) {
431
409
  const error = err;
432
410
  console.log(pc.yellow(`Could not release task: ${error.message}`));
433
411
  }
434
- if (exitAction === 'release_cleanup') {
435
- try {
436
- await removeWorktreeDir(cwd, projectRoot);
437
- worktreeRemoved = true;
438
- console.log(pc.green('✓ Worktree and branch removed\n'));
439
- }
440
- catch (err) {
441
- const error = err;
442
- console.log(pc.red(`Failed to remove worktree: ${error.message}\n`));
443
- }
444
- }
445
412
  }
446
413
  else {
447
414
  console.log(pc.green('✓ Lock kept — resume with:'));
@@ -477,11 +444,9 @@ export async function postTaskFlow(options) {
477
444
  const statusColor = taskStatus === 'done' ? pc.green : (taskStatus === 'in_progress' || taskStatus === 'in_review') ? pc.yellow : pc.dim;
478
445
  const statusLabel = taskStatus || 'unknown';
479
446
  console.log(pc.bold(`\n #${shortIdRaw(taskId)} ${taskTitle || 'Unknown task'}`) + ` ${statusColor(statusLabel)}`);
480
- if (!worktreeRemoved) {
481
- console.log(pc.dim(` ${cwd}`));
447
+ if (taskStatus === 'in_progress') {
482
448
  console.log(`\n To continue, run:`);
483
- console.log(pc.cyan(` cd ${cwd} && claude -c`));
484
- console.log(pc.dim(` or: npx @damper/cli --task ${taskId}`));
449
+ console.log(pc.cyan(` npx @damper/cli --task ${taskId}`));
485
450
  }
486
451
  }
487
452
  console.log();
@@ -556,12 +521,13 @@ export async function launchClaudeForReview(options) {
556
521
  `Review task #${taskId} and determine if it is ready to be marked as complete.`,
557
522
  '',
558
523
  'Steps:',
559
- '1. Read TASK_CONTEXT.md (if it exists) to understand the requirements',
560
- '2. Check git log and git diff main...HEAD to review what was done',
561
- '3. Run the project tests (use `bun run test` from the monorepo root, NEVER `bun test`)',
562
- '4. Check the completion checklist via get_project_settings MCP tool',
563
- '5. If everything looks good, call complete_task via MCP with a summary and confirmations',
564
- '6. If NOT ready, explain what is missing or broken do NOT call complete_task',
524
+ '1. Call get_project_context via Damper MCP to understand the project',
525
+ '2. Call get_task via Damper MCP to get the task details and requirements',
526
+ '3. Check git log and git diff main...HEAD to review what was done',
527
+ '4. Run the project tests (use `bun run test` from the monorepo root, NEVER `bun test`)',
528
+ '5. Check the completion checklist via get_project_settings MCP tool',
529
+ '6. If everything looks good, call complete_task via MCP with a summary and confirmations',
530
+ '7. If NOT ready, explain what is missing or broken — do NOT call complete_task',
565
531
  '',
566
532
  'IMPORTANT: Do NOT make any code changes. This is a review-only session.',
567
533
  ].join('\n');
@@ -599,7 +565,6 @@ async function launchClaudeForMerge(options) {
599
565
  '1. Run: git merge origin/main --no-edit',
600
566
  '2. If there are conflicts, identify all conflicted files with: git diff --name-only --diff-filter=U',
601
567
  '3. Read each conflicted file and resolve the conflicts:',
602
- ' - For CLAUDE.md: keep the main (origin/main) version entirely — the feature branch appends a temporary task section that must not be merged',
603
568
  ' - For code conflicts: combine both sides logically, preserving the intent of both the feature branch changes and main branch updates',
604
569
  ' - For package.json / lock files: accept the version that satisfies both sides, preferring the newer version',
605
570
  '4. Stage all resolved files with: git add <file>',
@@ -607,7 +572,6 @@ async function launchClaudeForMerge(options) {
607
572
  '6. Verify no conflicts remain with: git diff --name-only --diff-filter=U',
608
573
  '',
609
574
  'IMPORTANT:',
610
- '- Do NOT read TASK_CONTEXT.md or work on the task itself',
611
575
  '- Do NOT use any MCP tools — only use Bash, Read, Write, Edit, Glob, Grep',
612
576
  '- Do NOT make any changes beyond resolving the merge conflicts',
613
577
  '- If a conflict is too complex to resolve confidently, leave it and explain what needs manual attention',
@@ -1,7 +1,7 @@
1
1
  import * as fs from 'node:fs';
2
2
  import * as path from 'node:path';
3
3
  import * as os from 'node:os';
4
- import { getGitRoot } from './worktree.js';
4
+ import { getGitRoot } from './git.js';
5
5
  const CONFIG_DIR = '.damper';
6
6
  const CONFIG_FILE = 'config.json';
7
7
  /**
@@ -66,7 +66,8 @@ export function getApiKey(projectRoot) {
66
66
  return getGlobalApiKey();
67
67
  }
68
68
  /**
69
- * Get API key from global MCP settings (legacy)
69
+ * Get API key from global MCP settings (fallback)
70
+ * Supports both HTTP (headers.Authorization) and legacy stdio (env.DAMPER_API_KEY) configs.
70
71
  */
71
72
  function getGlobalApiKey() {
72
73
  const settingsPath = path.join(os.homedir(), '.claude', 'settings.json');
@@ -75,7 +76,16 @@ function getGlobalApiKey() {
75
76
  }
76
77
  try {
77
78
  const settings = JSON.parse(fs.readFileSync(settingsPath, 'utf-8'));
78
- return settings.mcpServers?.damper?.env?.DAMPER_API_KEY;
79
+ const config = settings.mcpServers?.damper;
80
+ if (!config)
81
+ return undefined;
82
+ // HTTP config: extract from Authorization header
83
+ if (config.type === 'http') {
84
+ const auth = config.headers?.Authorization;
85
+ return auth?.startsWith('Bearer ') ? auth.slice(7) : undefined;
86
+ }
87
+ // Legacy stdio config: extract from env
88
+ return config.env?.DAMPER_API_KEY;
79
89
  }
80
90
  catch {
81
91
  return undefined;
@@ -18,6 +18,7 @@ export interface Task {
18
18
  export interface TaskDetail extends Task {
19
19
  description?: string | null;
20
20
  implementationPlan?: string | null;
21
+ userStories?: string | null;
21
22
  voteScore: number;
22
23
  subtasks?: Array<{
23
24
  id: string;
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Get the git root directory for the given path
3
+ */
4
+ export declare function getGitRoot(dir: string): Promise<string>;
@@ -0,0 +1,11 @@
1
+ import { execa } from 'execa';
2
+ /**
3
+ * Get the git root directory for the given path
4
+ */
5
+ export async function getGitRoot(dir) {
6
+ const { stdout } = await execa('git', ['rev-parse', '--show-toplevel'], {
7
+ cwd: dir,
8
+ stdio: 'pipe',
9
+ });
10
+ return stdout.trim();
11
+ }
@@ -9,7 +9,7 @@ export declare function padStart(str: string, width: number): string;
9
9
  export declare function shortId(id: string): string;
10
10
  /** Plain 8-char slice (for use inside other color wrappers) */
11
11
  export declare function shortIdRaw(id: string): string;
12
- /** Type emoji icon */
12
+ /** Type indicator colored circles */
13
13
  export declare function getTypeIcon(type: string): string;
14
14
  /** Priority prefix: red/yellow circle + space, or empty */
15
15
  export declare function getPriorityIcon(priority: string): string;
package/dist/ui/format.js CHANGED
@@ -22,13 +22,13 @@ export function shortId(id) {
22
22
  export function shortIdRaw(id) {
23
23
  return id.slice(0, 8);
24
24
  }
25
- /** Type emoji icon */
25
+ /** Type indicator colored circles */
26
26
  export function getTypeIcon(type) {
27
27
  switch (type) {
28
- case 'bug': return '\u{1F41B}';
29
- case 'feature': return '\u{2728}';
30
- case 'improvement': return '\u{1F4A1}';
31
- default: return '\u{1F4CC}';
28
+ case 'bug': return '\u{1F534}';
29
+ case 'feature': return '\u{1F535}';
30
+ case 'improvement': return '\u{1F7E3}';
31
+ default: return '\u{26AA}';
32
32
  }
33
33
  }
34
34
  /** Priority prefix: red/yellow circle + space, or empty */
@@ -1,14 +1,11 @@
1
1
  import type { Task, DamperApi } from '../services/damper-api.js';
2
- import type { WorktreeState } from '../services/state.js';
3
2
  interface TaskPickerOptions {
4
3
  api: DamperApi;
5
- worktrees: WorktreeState[];
6
4
  typeFilter?: 'bug' | 'feature' | 'improvement' | 'task';
7
5
  statusFilter?: 'planned' | 'in_progress' | 'in_review' | 'done' | 'all';
8
6
  }
9
7
  interface TaskPickerResult {
10
8
  task: Task;
11
- worktree?: WorktreeState;
12
9
  isResume: boolean;
13
10
  forceTakeover?: boolean;
14
11
  isNewTask?: boolean;
@@ -1,7 +1,7 @@
1
1
  import { search, select, confirm, input, Separator } from '@inquirer/prompts';
2
2
  import pc from 'picocolors';
3
3
  import * as readline from 'readline';
4
- import { shortId, shortIdRaw, getTypeIcon, getPriorityIcon, formatEffort, formatProgressCompact, formatDueDate, sectionHeader, relativeTime, getTerminalWidth, padEnd, padStart, } from './format.js';
4
+ import { shortId, shortIdRaw, getTypeIcon, getPriorityIcon, formatEffort, formatProgressCompact, formatDueDate, sectionHeader, getTerminalWidth, padEnd, padStart, } from './format.js';
5
5
  // Layout constants (terminal column widths)
6
6
  const CURSOR_WIDTH = 2; // inquirer select prefix (❯ or )
7
7
  const PRIORITY_WIDTH = 3; // emoji(2) + space(1), or 3 spaces
@@ -88,18 +88,7 @@ function formatTaskChoice(choice, titleWidth, layout) {
88
88
  const firstLine = formatTableRow(choice.task, titleWidth, layout);
89
89
  const indent = ' '.repeat(INDENT_WIDTH);
90
90
  if (choice.type === 'in_progress') {
91
- const worktreeName = choice.worktree.path.split('/').pop() || choice.worktree.path;
92
- const time = relativeTime(choice.worktree.createdAt);
93
- const metaParts = [worktreeName];
94
- if (time)
95
- metaParts.push(time);
96
- let description = `${firstLine}\n${indent}${pc.dim(metaParts.join(' \u00B7 '))}`;
97
- if (choice.lastNote) {
98
- const maxNoteWidth = titleWidth;
99
- const note = choice.lastNote.length > maxNoteWidth ? choice.lastNote.slice(0, maxNoteWidth - 3) + '...' : choice.lastNote;
100
- description += `\n${indent}${pc.dim(`Last: "${note}"`)}`;
101
- }
102
- return description;
91
+ return firstLine;
103
92
  }
104
93
  if (choice.type === 'locked') {
105
94
  return `${firstLine}\n${indent}${pc.yellow(`locked by ${choice.lockedBy}`)}`;
@@ -118,7 +107,7 @@ function formatTaskChoice(choice, titleWidth, layout) {
118
107
  return firstLine;
119
108
  }
120
109
  export async function pickTask(options) {
121
- const { api, worktrees, typeFilter, statusFilter } = options;
110
+ const { api, typeFilter, statusFilter } = options;
122
111
  // Fetch all tasks from Damper (paginated)
123
112
  const { tasks, project } = await api.listAllTasks({
124
113
  status: statusFilter || 'all',
@@ -128,33 +117,15 @@ export async function pickTask(options) {
128
117
  // Filter out completed tasks unless specifically requested
129
118
  const availableTasks = tasks.filter(t => statusFilter === 'done' || statusFilter === 'all' ||
130
119
  (t.status === 'planned' || t.status === 'in_progress' || t.status === 'in_review'));
131
- // Match worktrees with tasks
120
+ // Categorize tasks
132
121
  const inProgressChoices = [];
133
- const worktreeTaskIds = new Set();
134
- for (const worktree of worktrees) {
135
- const task = tasks.find(t => t.id === worktree.taskId);
136
- if (task) {
137
- worktreeTaskIds.add(task.id);
138
- inProgressChoices.push({
139
- type: 'in_progress',
140
- task,
141
- worktree,
142
- });
143
- }
144
- }
145
- // Separate available tasks from locked tasks
146
122
  const availableChoices = [];
147
123
  const lockedChoices = [];
148
124
  for (const task of availableTasks) {
149
- if (worktreeTaskIds.has(task.id))
150
- continue;
151
125
  const taskAny = task;
152
126
  if (task.status === 'in_progress' && taskAny.lockedBy) {
153
- lockedChoices.push({
154
- type: 'locked',
155
- task,
156
- lockedBy: taskAny.lockedBy,
157
- });
127
+ // Show as "in progress" (resumable) or "locked" depending on who locked it
128
+ inProgressChoices.push({ type: 'in_progress', task });
158
129
  }
159
130
  else if (task.status === 'planned' || task.status === 'in_progress' || task.status === 'in_review') {
160
131
  availableChoices.push({ type: 'available', task });
@@ -229,7 +200,6 @@ export async function pickTask(options) {
229
200
  });
230
201
  return {
231
202
  task: selected.task,
232
- worktree: selected.worktree,
233
203
  isResume: true,
234
204
  action,
235
205
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@damper/cli",
3
- "version": "0.9.20",
3
+ "version": "0.10.0",
4
4
  "description": "CLI tool for orchestrating Damper task workflows with Claude Code",
5
5
  "author": "Damper <hello@usedamper.com>",
6
6
  "repository": {
@@ -44,8 +44,7 @@
44
44
  "cli",
45
45
  "claude",
46
46
  "ai",
47
- "task-management",
48
- "worktree"
47
+ "task-management"
49
48
  ],
50
49
  "license": "MIT"
51
50
  }
@@ -1 +0,0 @@
1
- export declare function cleanupCommand(): Promise<void>;