@claudetree/cli 0.4.2 → 0.4.4
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/chain.d.ts +3 -0
- package/dist/commands/chain.d.ts.map +1 -0
- package/dist/commands/chain.js +284 -0
- package/dist/commands/chain.js.map +1 -0
- package/dist/commands/init.test.d.ts +2 -0
- package/dist/commands/init.test.d.ts.map +1 -0
- package/dist/commands/init.test.js +94 -0
- package/dist/commands/init.test.js.map +1 -0
- package/dist/commands/list.test.d.ts +2 -0
- package/dist/commands/list.test.d.ts.map +1 -0
- package/dist/commands/list.test.js +106 -0
- package/dist/commands/list.test.js.map +1 -0
- package/dist/commands/start/buildPrompt.d.ts +29 -0
- package/dist/commands/start/buildPrompt.d.ts.map +1 -0
- package/dist/commands/start/buildPrompt.js +142 -0
- package/dist/commands/start/buildPrompt.js.map +1 -0
- package/dist/commands/start/buildPrompt.test.d.ts +2 -0
- package/dist/commands/start/buildPrompt.test.d.ts.map +1 -0
- package/dist/commands/start/buildPrompt.test.js +182 -0
- package/dist/commands/start/buildPrompt.test.js.map +1 -0
- package/dist/commands/start/createWorktree.d.ts +21 -0
- package/dist/commands/start/createWorktree.d.ts.map +1 -0
- package/dist/commands/start/createWorktree.js +36 -0
- package/dist/commands/start/createWorktree.js.map +1 -0
- package/dist/commands/start/createWorktree.test.d.ts +2 -0
- package/dist/commands/start/createWorktree.test.d.ts.map +1 -0
- package/dist/commands/start/createWorktree.test.js +81 -0
- package/dist/commands/start/createWorktree.test.js.map +1 -0
- package/dist/commands/start/index.d.ts +4 -0
- package/dist/commands/start/index.d.ts.map +1 -0
- package/dist/commands/start/index.js +4 -0
- package/dist/commands/start/index.js.map +1 -0
- package/dist/commands/start/parseIssueInput.d.ts +21 -0
- package/dist/commands/start/parseIssueInput.d.ts.map +1 -0
- package/dist/commands/start/parseIssueInput.js +78 -0
- package/dist/commands/start/parseIssueInput.js.map +1 -0
- package/dist/commands/start/parseIssueInput.test.d.ts +2 -0
- package/dist/commands/start/parseIssueInput.test.d.ts.map +1 -0
- package/dist/commands/start/parseIssueInput.test.js +118 -0
- package/dist/commands/start/parseIssueInput.test.js.map +1 -0
- package/dist/commands/start.d.ts.map +1 -1
- package/dist/commands/start.js +144 -280
- package/dist/commands/start.js.map +1 -1
- package/dist/commands/start.test.d.ts +2 -0
- package/dist/commands/start.test.d.ts.map +1 -0
- package/dist/commands/start.test.js +260 -0
- package/dist/commands/start.test.js.map +1 -0
- package/dist/commands/status.test.d.ts +2 -0
- package/dist/commands/status.test.d.ts.map +1 -0
- package/dist/commands/status.test.js +172 -0
- package/dist/commands/status.test.js.map +1 -0
- package/dist/commands/stop.test.d.ts +2 -0
- package/dist/commands/stop.test.d.ts.map +1 -0
- package/dist/commands/stop.test.js +152 -0
- package/dist/commands/stop.test.js.map +1 -0
- package/dist/commands/web.d.ts.map +1 -1
- package/dist/commands/web.js +95 -1
- package/dist/commands/web.js.map +1 -1
- package/dist/commands/web.test.d.ts +2 -0
- package/dist/commands/web.test.d.ts.map +1 -0
- package/dist/commands/web.test.js +133 -0
- package/dist/commands/web.test.js.map +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/package.json +8 -5
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Format duration in milliseconds to human readable string
|
|
3
|
+
*/
|
|
4
|
+
export function formatDuration(ms) {
|
|
5
|
+
const seconds = Math.floor(ms / 1000);
|
|
6
|
+
const minutes = Math.floor(seconds / 60);
|
|
7
|
+
const hours = Math.floor(minutes / 60);
|
|
8
|
+
if (hours > 0)
|
|
9
|
+
return `${hours}h ${minutes % 60}m`;
|
|
10
|
+
if (minutes > 0)
|
|
11
|
+
return `${minutes}m ${seconds % 60}s`;
|
|
12
|
+
return `${seconds}s`;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Build the prompt for Claude session
|
|
16
|
+
*/
|
|
17
|
+
export function buildPrompt(options) {
|
|
18
|
+
const { issueNumber, issueData, branchName, taskDescription, tddEnabled, template, customPrompt } = options;
|
|
19
|
+
// Custom prompt takes precedence
|
|
20
|
+
if (customPrompt) {
|
|
21
|
+
return customPrompt;
|
|
22
|
+
}
|
|
23
|
+
let prompt;
|
|
24
|
+
if (issueData) {
|
|
25
|
+
prompt = `You are working on Issue #${issueNumber}: "${issueData.title}"
|
|
26
|
+
|
|
27
|
+
Issue Description:
|
|
28
|
+
${issueData.body || 'No description provided.'}
|
|
29
|
+
|
|
30
|
+
IMPORTANT: Do NOT just analyze or suggest. Actually IMPLEMENT the solution.
|
|
31
|
+
${tddEnabled ? '\nStart with TDD - write a failing test first!' : ''}`;
|
|
32
|
+
}
|
|
33
|
+
else if (issueNumber) {
|
|
34
|
+
prompt = `Working on issue #${issueNumber}. ${tddEnabled ? 'Start with TDD - write a failing test first!' : 'Implement the solution.'}`;
|
|
35
|
+
}
|
|
36
|
+
else if (taskDescription) {
|
|
37
|
+
prompt = `Your task: ${taskDescription}
|
|
38
|
+
|
|
39
|
+
IMPORTANT: Do NOT just analyze or suggest. Actually IMPLEMENT the solution.
|
|
40
|
+
${tddEnabled ? '\nStart with TDD - write a failing test first!' : ''}`;
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
prompt = `Working on ${branchName}. ${tddEnabled ? 'Start with TDD - write a failing test first!' : 'Implement any required changes.'}`;
|
|
44
|
+
}
|
|
45
|
+
// Apply template prefix/suffix
|
|
46
|
+
if (template) {
|
|
47
|
+
const prefix = template.promptPrefix ? `${template.promptPrefix}\n\n` : '';
|
|
48
|
+
const suffix = template.promptSuffix ? `\n\n${template.promptSuffix}` : '';
|
|
49
|
+
prompt = `${prefix}${prompt}${suffix}`;
|
|
50
|
+
}
|
|
51
|
+
return prompt;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Build system prompt based on mode and skill
|
|
55
|
+
*/
|
|
56
|
+
export function buildSystemPrompt(options) {
|
|
57
|
+
const { tddEnabled, tddConfig, skill, template } = options;
|
|
58
|
+
// Template system prompt takes precedence
|
|
59
|
+
if (template?.systemPrompt) {
|
|
60
|
+
return template.systemPrompt;
|
|
61
|
+
}
|
|
62
|
+
if (tddEnabled && tddConfig) {
|
|
63
|
+
return `You are in TDD (Test-Driven Development) mode. Follow this STRICT workflow:
|
|
64
|
+
|
|
65
|
+
## TDD Cycle (Repeat until done)
|
|
66
|
+
|
|
67
|
+
### 1. RED Phase - Write Failing Test
|
|
68
|
+
- Write ONE failing test that describes the expected behavior
|
|
69
|
+
- Run the test to confirm it fails
|
|
70
|
+
- Commit: "test: add test for <feature>"
|
|
71
|
+
|
|
72
|
+
### 2. GREEN Phase - Minimal Implementation
|
|
73
|
+
- Write the MINIMUM code to make the test pass
|
|
74
|
+
- Run tests to confirm they pass
|
|
75
|
+
- Commit: "feat: implement <feature>"
|
|
76
|
+
|
|
77
|
+
### 3. REFACTOR Phase (Optional)
|
|
78
|
+
- Clean up code while keeping tests green
|
|
79
|
+
- Commit: "refactor: improve <description>"
|
|
80
|
+
|
|
81
|
+
## Rules
|
|
82
|
+
- NEVER write implementation before tests
|
|
83
|
+
- ONE test at a time
|
|
84
|
+
- Run tests after EVERY change
|
|
85
|
+
- Stop when all requirements are met
|
|
86
|
+
|
|
87
|
+
## Validation Gates (Must Pass Before PR)
|
|
88
|
+
${tddConfig.gates.map(g => `- ${g.name}: \`${g.command}\` ${g.required ? '(REQUIRED)' : '(optional)'}`).join('\n')}
|
|
89
|
+
|
|
90
|
+
## Time Limits
|
|
91
|
+
- Total: ${formatDuration(tddConfig.timeout)}
|
|
92
|
+
- Idle: ${formatDuration(tddConfig.idleTimeout)}
|
|
93
|
+
|
|
94
|
+
When done, create a PR to the develop branch.`;
|
|
95
|
+
}
|
|
96
|
+
if (skill === 'review') {
|
|
97
|
+
return 'Review code thoroughly for security, quality, and best practices.';
|
|
98
|
+
}
|
|
99
|
+
if (skill === 'docs') {
|
|
100
|
+
return `You are a documentation specialist. Generate comprehensive documentation.
|
|
101
|
+
|
|
102
|
+
## Documentation Workflow
|
|
103
|
+
|
|
104
|
+
### 1. Analysis Phase
|
|
105
|
+
- Read package.json for project metadata
|
|
106
|
+
- Scan src/ directory structure
|
|
107
|
+
- Identify exported APIs and types
|
|
108
|
+
- Note configuration files
|
|
109
|
+
|
|
110
|
+
### 2. README Generation
|
|
111
|
+
Structure your README with:
|
|
112
|
+
- Project title and badges
|
|
113
|
+
- Description and features
|
|
114
|
+
- Installation instructions
|
|
115
|
+
- Quick start example
|
|
116
|
+
- API reference (if applicable)
|
|
117
|
+
- Configuration options
|
|
118
|
+
- Contributing guidelines
|
|
119
|
+
|
|
120
|
+
### 3. API Documentation
|
|
121
|
+
For each public module:
|
|
122
|
+
- Purpose and usage
|
|
123
|
+
- Function signatures with types
|
|
124
|
+
- Parameter descriptions
|
|
125
|
+
- Return value descriptions
|
|
126
|
+
- Code examples
|
|
127
|
+
|
|
128
|
+
### 4. Output
|
|
129
|
+
- Create/update README.md
|
|
130
|
+
- Create docs/ folder for detailed docs if needed
|
|
131
|
+
- Use Markdown formatting
|
|
132
|
+
- Include table of contents for long docs
|
|
133
|
+
|
|
134
|
+
## Rules
|
|
135
|
+
- Be concise but complete
|
|
136
|
+
- Use code blocks with proper language tags
|
|
137
|
+
- Include real, working examples
|
|
138
|
+
- Document edge cases and error handling`;
|
|
139
|
+
}
|
|
140
|
+
return undefined;
|
|
141
|
+
}
|
|
142
|
+
//# sourceMappingURL=buildPrompt.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"buildPrompt.js","sourceRoot":"","sources":["../../../src/commands/start/buildPrompt.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"buildPrompt.test.d.ts","sourceRoot":"","sources":["../../../src/commands/start/buildPrompt.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { buildPrompt, buildSystemPrompt, formatDuration } from './buildPrompt.js';
|
|
3
|
+
describe('buildPrompt', () => {
|
|
4
|
+
describe('with issue data', () => {
|
|
5
|
+
it('should build prompt from issue data', () => {
|
|
6
|
+
const issueData = {
|
|
7
|
+
number: 42,
|
|
8
|
+
title: 'Add feature X',
|
|
9
|
+
body: 'We need to implement feature X',
|
|
10
|
+
labels: ['enhancement'],
|
|
11
|
+
state: 'open',
|
|
12
|
+
url: 'https://github.com/owner/repo/issues/42',
|
|
13
|
+
};
|
|
14
|
+
const result = buildPrompt({
|
|
15
|
+
issueNumber: 42,
|
|
16
|
+
issueData,
|
|
17
|
+
branchName: 'issue-42-add-feature-x',
|
|
18
|
+
taskDescription: null,
|
|
19
|
+
tddEnabled: false,
|
|
20
|
+
});
|
|
21
|
+
expect(result).toContain('Issue #42');
|
|
22
|
+
expect(result).toContain('Add feature X');
|
|
23
|
+
expect(result).toContain('We need to implement feature X');
|
|
24
|
+
expect(result).toContain('IMPLEMENT the solution');
|
|
25
|
+
});
|
|
26
|
+
it('should add TDD instruction when enabled', () => {
|
|
27
|
+
const issueData = {
|
|
28
|
+
number: 42,
|
|
29
|
+
title: 'Add feature X',
|
|
30
|
+
body: 'Implement feature',
|
|
31
|
+
labels: [],
|
|
32
|
+
state: 'open',
|
|
33
|
+
url: '',
|
|
34
|
+
};
|
|
35
|
+
const result = buildPrompt({
|
|
36
|
+
issueNumber: 42,
|
|
37
|
+
issueData,
|
|
38
|
+
branchName: 'issue-42',
|
|
39
|
+
taskDescription: null,
|
|
40
|
+
tddEnabled: true,
|
|
41
|
+
});
|
|
42
|
+
expect(result).toContain('TDD');
|
|
43
|
+
expect(result).toContain('failing test');
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
describe('with issue number only', () => {
|
|
47
|
+
it('should build simple prompt with issue number', () => {
|
|
48
|
+
const result = buildPrompt({
|
|
49
|
+
issueNumber: 42,
|
|
50
|
+
issueData: null,
|
|
51
|
+
branchName: 'issue-42',
|
|
52
|
+
taskDescription: null,
|
|
53
|
+
tddEnabled: false,
|
|
54
|
+
});
|
|
55
|
+
expect(result).toContain('#42');
|
|
56
|
+
expect(result).toContain('Implement');
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
describe('with task description', () => {
|
|
60
|
+
it('should build prompt from task description', () => {
|
|
61
|
+
const result = buildPrompt({
|
|
62
|
+
issueNumber: null,
|
|
63
|
+
issueData: null,
|
|
64
|
+
branchName: 'task-add-auth',
|
|
65
|
+
taskDescription: 'add user authentication',
|
|
66
|
+
tddEnabled: false,
|
|
67
|
+
});
|
|
68
|
+
expect(result).toContain('add user authentication');
|
|
69
|
+
expect(result).toContain('IMPLEMENT');
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
describe('with template', () => {
|
|
73
|
+
it('should apply template prefix and suffix', () => {
|
|
74
|
+
const template = {
|
|
75
|
+
name: 'bugfix',
|
|
76
|
+
description: 'Bug fix template',
|
|
77
|
+
promptPrefix: 'DEBUG MODE:',
|
|
78
|
+
promptSuffix: 'Run tests after fix.',
|
|
79
|
+
};
|
|
80
|
+
const result = buildPrompt({
|
|
81
|
+
issueNumber: 1,
|
|
82
|
+
issueData: null,
|
|
83
|
+
branchName: 'issue-1',
|
|
84
|
+
taskDescription: null,
|
|
85
|
+
tddEnabled: false,
|
|
86
|
+
template,
|
|
87
|
+
});
|
|
88
|
+
expect(result).toMatch(/^DEBUG MODE:/);
|
|
89
|
+
expect(result).toMatch(/Run tests after fix\.$/);
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
describe('with custom prompt', () => {
|
|
93
|
+
it('should use custom prompt when provided', () => {
|
|
94
|
+
const result = buildPrompt({
|
|
95
|
+
issueNumber: 42,
|
|
96
|
+
issueData: null,
|
|
97
|
+
branchName: 'issue-42',
|
|
98
|
+
taskDescription: null,
|
|
99
|
+
tddEnabled: false,
|
|
100
|
+
customPrompt: 'Custom instruction here',
|
|
101
|
+
});
|
|
102
|
+
expect(result).toBe('Custom instruction here');
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
describe('buildSystemPrompt', () => {
|
|
107
|
+
describe('TDD mode', () => {
|
|
108
|
+
it('should build TDD system prompt with gates', () => {
|
|
109
|
+
const tddConfig = {
|
|
110
|
+
timeout: 7200000, // 2h
|
|
111
|
+
idleTimeout: 600000, // 10m
|
|
112
|
+
maxIterations: 10,
|
|
113
|
+
maxRetries: 3,
|
|
114
|
+
gates: [
|
|
115
|
+
{ name: 'test', command: 'pnpm test', required: true },
|
|
116
|
+
{ name: 'type', command: 'tsc --noEmit', required: true },
|
|
117
|
+
],
|
|
118
|
+
};
|
|
119
|
+
const result = buildSystemPrompt({
|
|
120
|
+
tddEnabled: true,
|
|
121
|
+
tddConfig,
|
|
122
|
+
});
|
|
123
|
+
expect(result).toContain('TDD');
|
|
124
|
+
expect(result).toContain('RED Phase');
|
|
125
|
+
expect(result).toContain('GREEN Phase');
|
|
126
|
+
expect(result).toContain('REFACTOR');
|
|
127
|
+
expect(result).toContain('pnpm test');
|
|
128
|
+
expect(result).toContain('tsc --noEmit');
|
|
129
|
+
});
|
|
130
|
+
});
|
|
131
|
+
describe('review skill', () => {
|
|
132
|
+
it('should build review system prompt', () => {
|
|
133
|
+
const result = buildSystemPrompt({
|
|
134
|
+
tddEnabled: false,
|
|
135
|
+
skill: 'review',
|
|
136
|
+
});
|
|
137
|
+
expect(result).toContain('Review');
|
|
138
|
+
expect(result).toContain('security');
|
|
139
|
+
});
|
|
140
|
+
});
|
|
141
|
+
describe('docs skill', () => {
|
|
142
|
+
it('should build docs system prompt', () => {
|
|
143
|
+
const result = buildSystemPrompt({
|
|
144
|
+
tddEnabled: false,
|
|
145
|
+
skill: 'docs',
|
|
146
|
+
});
|
|
147
|
+
expect(result).toContain('documentation');
|
|
148
|
+
expect(result).toContain('README');
|
|
149
|
+
});
|
|
150
|
+
});
|
|
151
|
+
describe('template system prompt', () => {
|
|
152
|
+
it('should use template system prompt when provided', () => {
|
|
153
|
+
const template = {
|
|
154
|
+
name: 'custom',
|
|
155
|
+
description: 'Custom template',
|
|
156
|
+
systemPrompt: 'Custom system instructions',
|
|
157
|
+
};
|
|
158
|
+
const result = buildSystemPrompt({
|
|
159
|
+
tddEnabled: false,
|
|
160
|
+
template,
|
|
161
|
+
});
|
|
162
|
+
expect(result).toBe('Custom system instructions');
|
|
163
|
+
});
|
|
164
|
+
});
|
|
165
|
+
});
|
|
166
|
+
describe('formatDuration', () => {
|
|
167
|
+
it('should format seconds', () => {
|
|
168
|
+
expect(formatDuration(5000)).toBe('5s');
|
|
169
|
+
expect(formatDuration(45000)).toBe('45s');
|
|
170
|
+
});
|
|
171
|
+
it('should format minutes and seconds', () => {
|
|
172
|
+
expect(formatDuration(60000)).toBe('1m 0s');
|
|
173
|
+
expect(formatDuration(90000)).toBe('1m 30s');
|
|
174
|
+
expect(formatDuration(125000)).toBe('2m 5s');
|
|
175
|
+
});
|
|
176
|
+
it('should format hours and minutes', () => {
|
|
177
|
+
expect(formatDuration(3600000)).toBe('1h 0m');
|
|
178
|
+
expect(formatDuration(5400000)).toBe('1h 30m');
|
|
179
|
+
expect(formatDuration(7320000)).toBe('2h 2m');
|
|
180
|
+
});
|
|
181
|
+
});
|
|
182
|
+
//# sourceMappingURL=buildPrompt.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"buildPrompt.test.js","sourceRoot":"","sources":["../../../src/commands/start/buildPrompt.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export interface WorktreeInfo {
|
|
2
|
+
id: string;
|
|
3
|
+
path: string;
|
|
4
|
+
branch: string;
|
|
5
|
+
}
|
|
6
|
+
export interface CreateWorktreeOptions {
|
|
7
|
+
cwd: string;
|
|
8
|
+
worktreeDir: string;
|
|
9
|
+
branchName: string;
|
|
10
|
+
issueNumber?: number;
|
|
11
|
+
baseBranch?: string;
|
|
12
|
+
}
|
|
13
|
+
export interface CreateWorktreeResult {
|
|
14
|
+
worktree: WorktreeInfo;
|
|
15
|
+
isExisting: boolean;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Create a new worktree or find existing one
|
|
19
|
+
*/
|
|
20
|
+
export declare function createOrFindWorktree(options: CreateWorktreeOptions): Promise<CreateWorktreeResult>;
|
|
21
|
+
//# sourceMappingURL=createWorktree.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"createWorktree.d.ts","sourceRoot":"","sources":["../../../src/commands/start/createWorktree.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,qBAAqB;IACpC,GAAG,EAAE,MAAM,CAAC;IACZ,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,EAAE,YAAY,CAAC;IACvB,UAAU,EAAE,OAAO,CAAC;CACrB;AAED;;GAEG;AACH,wBAAsB,oBAAoB,CACxC,OAAO,EAAE,qBAAqB,GAC7B,OAAO,CAAC,oBAAoB,CAAC,CAmC/B"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { join } from 'node:path';
|
|
2
|
+
import { randomUUID } from 'node:crypto';
|
|
3
|
+
import { GitWorktreeAdapter } from '@claudetree/core';
|
|
4
|
+
/**
|
|
5
|
+
* Create a new worktree or find existing one
|
|
6
|
+
*/
|
|
7
|
+
export async function createOrFindWorktree(options) {
|
|
8
|
+
const { cwd, worktreeDir, branchName, issueNumber, baseBranch } = options;
|
|
9
|
+
const worktreePath = join(cwd, worktreeDir, branchName);
|
|
10
|
+
const gitAdapter = new GitWorktreeAdapter(cwd);
|
|
11
|
+
// Check for existing worktree
|
|
12
|
+
const existingWorktrees = await gitAdapter.list();
|
|
13
|
+
const existingWorktree = existingWorktrees.find((wt) => wt.branch === branchName || wt.path.endsWith(branchName));
|
|
14
|
+
if (existingWorktree) {
|
|
15
|
+
return {
|
|
16
|
+
worktree: {
|
|
17
|
+
id: randomUUID(),
|
|
18
|
+
path: existingWorktree.path,
|
|
19
|
+
branch: existingWorktree.branch,
|
|
20
|
+
},
|
|
21
|
+
isExisting: true,
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
// Create new worktree with optional base branch
|
|
25
|
+
const worktree = await gitAdapter.create({
|
|
26
|
+
path: worktreePath,
|
|
27
|
+
branch: branchName,
|
|
28
|
+
issueNumber,
|
|
29
|
+
baseBranch,
|
|
30
|
+
});
|
|
31
|
+
return {
|
|
32
|
+
worktree,
|
|
33
|
+
isExisting: false,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=createWorktree.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"createWorktree.js","sourceRoot":"","sources":["../../../src/commands/start/createWorktree.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAqBtD;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,OAA8B;IAE9B,MAAM,EAAE,GAAG,EAAE,WAAW,EAAE,UAAU,EAAE,WAAW,EAAE,UAAU,EAAE,GAAG,OAAO,CAAC;IAE1E,MAAM,YAAY,GAAG,IAAI,CAAC,GAAG,EAAE,WAAW,EAAE,UAAU,CAAC,CAAC;IACxD,MAAM,UAAU,GAAG,IAAI,kBAAkB,CAAC,GAAG,CAAC,CAAC;IAE/C,8BAA8B;IAC9B,MAAM,iBAAiB,GAAG,MAAM,UAAU,CAAC,IAAI,EAAE,CAAC;IAClD,MAAM,gBAAgB,GAAG,iBAAiB,CAAC,IAAI,CAC7C,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,MAAM,KAAK,UAAU,IAAI,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,CACjE,CAAC;IAEF,IAAI,gBAAgB,EAAE,CAAC;QACrB,OAAO;YACL,QAAQ,EAAE;gBACR,EAAE,EAAE,UAAU,EAAE;gBAChB,IAAI,EAAE,gBAAgB,CAAC,IAAI;gBAC3B,MAAM,EAAE,gBAAgB,CAAC,MAAM;aAChC;YACD,UAAU,EAAE,IAAI;SACjB,CAAC;IACJ,CAAC;IAED,gDAAgD;IAChD,MAAM,QAAQ,GAAG,MAAM,UAAU,CAAC,MAAM,CAAC;QACvC,IAAI,EAAE,YAAY;QAClB,MAAM,EAAE,UAAU;QAClB,WAAW;QACX,UAAU;KACX,CAAC,CAAC;IAEH,OAAO;QACL,QAAQ;QACR,UAAU,EAAE,KAAK;KAClB,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"createWorktree.test.d.ts","sourceRoot":"","sources":["../../../src/commands/start/createWorktree.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
2
|
+
import { createOrFindWorktree } from './createWorktree.js';
|
|
3
|
+
import { GitWorktreeAdapter } from '@claudetree/core';
|
|
4
|
+
// Mock GitWorktreeAdapter
|
|
5
|
+
vi.mock('@claudetree/core', async () => {
|
|
6
|
+
const actual = await vi.importActual('@claudetree/core');
|
|
7
|
+
return {
|
|
8
|
+
...actual,
|
|
9
|
+
GitWorktreeAdapter: vi.fn().mockImplementation(() => ({
|
|
10
|
+
list: vi.fn().mockResolvedValue([
|
|
11
|
+
{ path: '/worktrees/existing-branch', branch: 'existing-branch' },
|
|
12
|
+
]),
|
|
13
|
+
create: vi.fn().mockImplementation(async (opts) => ({
|
|
14
|
+
id: 'mock-uuid-123',
|
|
15
|
+
path: opts.path,
|
|
16
|
+
branch: opts.branch,
|
|
17
|
+
})),
|
|
18
|
+
})),
|
|
19
|
+
};
|
|
20
|
+
});
|
|
21
|
+
describe('createOrFindWorktree', () => {
|
|
22
|
+
beforeEach(() => {
|
|
23
|
+
vi.clearAllMocks();
|
|
24
|
+
});
|
|
25
|
+
describe('existing worktree', () => {
|
|
26
|
+
it('should return existing worktree when branch already exists', async () => {
|
|
27
|
+
const result = await createOrFindWorktree({
|
|
28
|
+
cwd: '/project',
|
|
29
|
+
worktreeDir: '.worktrees',
|
|
30
|
+
branchName: 'existing-branch',
|
|
31
|
+
});
|
|
32
|
+
expect(result.isExisting).toBe(true);
|
|
33
|
+
expect(result.worktree.branch).toBe('existing-branch');
|
|
34
|
+
expect(result.worktree.path).toBe('/worktrees/existing-branch');
|
|
35
|
+
});
|
|
36
|
+
it('should match by path ending with branch name', async () => {
|
|
37
|
+
const result = await createOrFindWorktree({
|
|
38
|
+
cwd: '/project',
|
|
39
|
+
worktreeDir: '.worktrees',
|
|
40
|
+
branchName: 'existing-branch',
|
|
41
|
+
});
|
|
42
|
+
expect(result.isExisting).toBe(true);
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
describe('new worktree', () => {
|
|
46
|
+
it('should create new worktree when branch does not exist', async () => {
|
|
47
|
+
const result = await createOrFindWorktree({
|
|
48
|
+
cwd: '/project',
|
|
49
|
+
worktreeDir: '.worktrees',
|
|
50
|
+
branchName: 'new-branch',
|
|
51
|
+
});
|
|
52
|
+
expect(result.isExisting).toBe(false);
|
|
53
|
+
expect(result.worktree.branch).toBe('new-branch');
|
|
54
|
+
expect(result.worktree.path).toBe('/project/.worktrees/new-branch');
|
|
55
|
+
});
|
|
56
|
+
it('should pass issueNumber to create', async () => {
|
|
57
|
+
const result = await createOrFindWorktree({
|
|
58
|
+
cwd: '/project',
|
|
59
|
+
worktreeDir: '.worktrees',
|
|
60
|
+
branchName: 'issue-42-feature',
|
|
61
|
+
issueNumber: 42,
|
|
62
|
+
});
|
|
63
|
+
expect(result.isExisting).toBe(false);
|
|
64
|
+
expect(result.worktree.branch).toBe('issue-42-feature');
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
describe('error handling', () => {
|
|
68
|
+
it('should throw error when create fails', async () => {
|
|
69
|
+
vi.mocked(GitWorktreeAdapter).mockImplementationOnce(() => ({
|
|
70
|
+
list: vi.fn().mockResolvedValue([]),
|
|
71
|
+
create: vi.fn().mockRejectedValue(new Error('Git error: branch already exists')),
|
|
72
|
+
}));
|
|
73
|
+
await expect(createOrFindWorktree({
|
|
74
|
+
cwd: '/project',
|
|
75
|
+
worktreeDir: '.worktrees',
|
|
76
|
+
branchName: 'conflict-branch',
|
|
77
|
+
})).rejects.toThrow('Git error');
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
//# sourceMappingURL=createWorktree.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"createWorktree.test.js","sourceRoot":"","sources":["../../../src/commands/start/createWorktree.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AAC9D,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAEtD,0BAA0B;AAC1B,EAAE,CAAC,IAAI,CAAC,kBAAkB,EAAE,KAAK,IAAI,EAAE;IACrC,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC,YAAY,CAAC,kBAAkB,CAAC,CAAC;IACzD,OAAO;QACL,GAAG,MAAM;QACT,kBAAkB,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,kBAAkB,CAAC,GAAG,EAAE,CAAC,CAAC;YACpD,IAAI,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC;gBAC9B,EAAE,IAAI,EAAE,4BAA4B,EAAE,MAAM,EAAE,iBAAiB,EAAE;aAClE,CAAC;YACF,MAAM,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,kBAAkB,CAAC,KAAK,EAAE,IAA4D,EAAE,EAAE,CAAC,CAAC;gBAC1G,EAAE,EAAE,eAAe;gBACnB,IAAI,EAAE,IAAI,CAAC,IAAI;gBACf,MAAM,EAAE,IAAI,CAAC,MAAM;aACpB,CAAC,CAAC;SACJ,CAAC,CAAC;KACJ,CAAC;AACJ,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,sBAAsB,EAAE,GAAG,EAAE;IACpC,UAAU,CAAC,GAAG,EAAE;QACd,EAAE,CAAC,aAAa,EAAE,CAAC;IACrB,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,mBAAmB,EAAE,GAAG,EAAE;QACjC,EAAE,CAAC,4DAA4D,EAAE,KAAK,IAAI,EAAE;YAC1E,MAAM,MAAM,GAAG,MAAM,oBAAoB,CAAC;gBACxC,GAAG,EAAE,UAAU;gBACf,WAAW,EAAE,YAAY;gBACzB,UAAU,EAAE,iBAAiB;aAC9B,CAAC,CAAC;YAEH,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACrC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;YACvD,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,4BAA4B,CAAC,CAAC;QAClE,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,8CAA8C,EAAE,KAAK,IAAI,EAAE;YAC5D,MAAM,MAAM,GAAG,MAAM,oBAAoB,CAAC;gBACxC,GAAG,EAAE,UAAU;gBACf,WAAW,EAAE,YAAY;gBACzB,UAAU,EAAE,iBAAiB;aAC9B,CAAC,CAAC;YAEH,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACvC,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,cAAc,EAAE,GAAG,EAAE;QAC5B,EAAE,CAAC,uDAAuD,EAAE,KAAK,IAAI,EAAE;YACrE,MAAM,MAAM,GAAG,MAAM,oBAAoB,CAAC;gBACxC,GAAG,EAAE,UAAU;gBACf,WAAW,EAAE,YAAY;gBACzB,UAAU,EAAE,YAAY;aACzB,CAAC,CAAC;YAEH,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACtC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;YAClD,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,gCAAgC,CAAC,CAAC;QACtE,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,mCAAmC,EAAE,KAAK,IAAI,EAAE;YACjD,MAAM,MAAM,GAAG,MAAM,oBAAoB,CAAC;gBACxC,GAAG,EAAE,UAAU;gBACf,WAAW,EAAE,YAAY;gBACzB,UAAU,EAAE,kBAAkB;gBAC9B,WAAW,EAAE,EAAE;aAChB,CAAC,CAAC;YAEH,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACtC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;QAC1D,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,gBAAgB,EAAE,GAAG,EAAE;QAC9B,EAAE,CAAC,sCAAsC,EAAE,KAAK,IAAI,EAAE;YACpD,EAAE,CAAC,MAAM,CAAC,kBAAkB,CAAC,CAAC,sBAAsB,CAAC,GAAG,EAAE,CAAC,CAAC;gBAC1D,IAAI,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,EAAE,CAAC;gBACnC,MAAM,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC;aAC/C,CAAA,CAAC,CAAC;YAErC,MAAM,MAAM,CACV,oBAAoB,CAAC;gBACnB,GAAG,EAAE,UAAU;gBACf,WAAW,EAAE,YAAY;gBACzB,UAAU,EAAE,iBAAiB;aAC9B,CAAC,CACH,CAAC,OAAO,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;QACjC,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { parseIssueInput, type ParsedIssueInput, type ParseIssueOptions } from './parseIssueInput.js';
|
|
2
|
+
export { createOrFindWorktree, type WorktreeInfo, type CreateWorktreeOptions, type CreateWorktreeResult } from './createWorktree.js';
|
|
3
|
+
export { buildPrompt, buildSystemPrompt, formatDuration, type BuildPromptOptions, type BuildSystemPromptOptions } from './buildPrompt.js';
|
|
4
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/start/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,KAAK,gBAAgB,EAAE,KAAK,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AACtG,OAAO,EAAE,oBAAoB,EAAE,KAAK,YAAY,EAAE,KAAK,qBAAqB,EAAE,KAAK,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AACrI,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAE,cAAc,EAAE,KAAK,kBAAkB,EAAE,KAAK,wBAAwB,EAAE,MAAM,kBAAkB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/commands/start/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAiD,MAAM,sBAAsB,CAAC;AACtG,OAAO,EAAE,oBAAoB,EAA4E,MAAM,qBAAqB,CAAC;AACrI,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAE,cAAc,EAA0D,MAAM,kBAAkB,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { Issue } from '@claudetree/shared';
|
|
2
|
+
export interface ParsedIssueInput {
|
|
3
|
+
issueNumber: number | null;
|
|
4
|
+
issueData: Issue | null;
|
|
5
|
+
branchName: string;
|
|
6
|
+
taskDescription: string | null;
|
|
7
|
+
}
|
|
8
|
+
export interface ParseIssueOptions {
|
|
9
|
+
token?: string;
|
|
10
|
+
branch?: string;
|
|
11
|
+
githubConfig?: {
|
|
12
|
+
owner: string;
|
|
13
|
+
repo: string;
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Parse issue input from CLI argument
|
|
18
|
+
* Handles: GitHub URLs, issue numbers, natural language tasks
|
|
19
|
+
*/
|
|
20
|
+
export declare function parseIssueInput(input: string, options: ParseIssueOptions): Promise<ParsedIssueInput>;
|
|
21
|
+
//# sourceMappingURL=parseIssueInput.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parseIssueInput.d.ts","sourceRoot":"","sources":["../../../src/commands/start/parseIssueInput.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAEhD,MAAM,WAAW,gBAAgB;IAC/B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,SAAS,EAAE,KAAK,GAAG,IAAI,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;CAChC;AAED,MAAM,WAAW,iBAAiB;IAChC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE;QACb,KAAK,EAAE,MAAM,CAAC;QACd,IAAI,EAAE,MAAM,CAAC;KACd,CAAC;CACH;AAeD;;;GAGG;AACH,wBAAsB,eAAe,CACnC,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,iBAAiB,GACzB,OAAO,CAAC,gBAAgB,CAAC,CAwE3B"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { GitHubAdapter } from '@claudetree/core';
|
|
2
|
+
/**
|
|
3
|
+
* Sanitize natural language input to a valid branch name
|
|
4
|
+
*/
|
|
5
|
+
function sanitizeBranchName(input) {
|
|
6
|
+
return input
|
|
7
|
+
.toLowerCase()
|
|
8
|
+
.replace(/[^a-z0-9가-힣\s-]/g, '') // Allow Korean characters
|
|
9
|
+
.replace(/\s+/g, '-')
|
|
10
|
+
.replace(/-+/g, '-')
|
|
11
|
+
.replace(/^-|-$/g, '')
|
|
12
|
+
.slice(0, 50); // Max length
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Parse issue input from CLI argument
|
|
16
|
+
* Handles: GitHub URLs, issue numbers, natural language tasks
|
|
17
|
+
*/
|
|
18
|
+
export async function parseIssueInput(input, options) {
|
|
19
|
+
const { token, branch: customBranch, githubConfig } = options;
|
|
20
|
+
// Case 1: GitHub URL
|
|
21
|
+
if (input.includes('github.com')) {
|
|
22
|
+
if (!token) {
|
|
23
|
+
throw new Error('GitHub token required for URL. Set GITHUB_TOKEN or use --token.');
|
|
24
|
+
}
|
|
25
|
+
const ghAdapter = new GitHubAdapter(token);
|
|
26
|
+
const parsed = ghAdapter.parseIssueUrl(input);
|
|
27
|
+
if (!parsed) {
|
|
28
|
+
throw new Error('Invalid GitHub URL format.');
|
|
29
|
+
}
|
|
30
|
+
const issueData = await ghAdapter.getIssue(parsed.owner, parsed.repo, parsed.number);
|
|
31
|
+
const branchName = customBranch ?? ghAdapter.generateBranchName(issueData.number, issueData.title);
|
|
32
|
+
return {
|
|
33
|
+
issueNumber: issueData.number,
|
|
34
|
+
issueData,
|
|
35
|
+
branchName,
|
|
36
|
+
taskDescription: null,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
// Case 2: Issue number
|
|
40
|
+
const parsedNumber = parseInt(input, 10);
|
|
41
|
+
const isNumber = !isNaN(parsedNumber);
|
|
42
|
+
if (isNumber) {
|
|
43
|
+
// Try to fetch issue data if we have GitHub config
|
|
44
|
+
if (token && githubConfig) {
|
|
45
|
+
const ghAdapter = new GitHubAdapter(token);
|
|
46
|
+
try {
|
|
47
|
+
const issueData = await ghAdapter.getIssue(githubConfig.owner, githubConfig.repo, parsedNumber);
|
|
48
|
+
const branchName = customBranch ?? ghAdapter.generateBranchName(issueData.number, issueData.title);
|
|
49
|
+
return {
|
|
50
|
+
issueNumber: issueData.number,
|
|
51
|
+
issueData,
|
|
52
|
+
branchName,
|
|
53
|
+
taskDescription: null,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
// API failed, fallback to simple branch name
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
// Fallback: use issue number without API data
|
|
61
|
+
return {
|
|
62
|
+
issueNumber: parsedNumber,
|
|
63
|
+
issueData: null,
|
|
64
|
+
branchName: customBranch ?? `issue-${parsedNumber}`,
|
|
65
|
+
taskDescription: null,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
// Case 3: Natural language task
|
|
69
|
+
const taskDescription = input;
|
|
70
|
+
const branchName = customBranch ?? `task-${sanitizeBranchName(input)}`;
|
|
71
|
+
return {
|
|
72
|
+
issueNumber: null,
|
|
73
|
+
issueData: null,
|
|
74
|
+
branchName,
|
|
75
|
+
taskDescription,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=parseIssueInput.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parseIssueInput.js","sourceRoot":"","sources":["../../../src/commands/start/parseIssueInput.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parseIssueInput.test.d.ts","sourceRoot":"","sources":["../../../src/commands/start/parseIssueInput.test.ts"],"names":[],"mappings":""}
|