fix: takt add #N でIssue内容がAI要約で壊れる問題を修正 (#46)

This commit is contained in:
nrslib 2026-01-31 01:40:07 +09:00
parent 26ac231435
commit 80a75004a4
3 changed files with 13 additions and 25 deletions

View File

@ -4,6 +4,13 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
## [0.3.3] - 2026-01-31
### Fixed
- `takt add #N` がIssue内容をAI要約に通してしまい、タスク内容が壊れる問題を修正 (#46)
- Issue参照時は `resolveIssueTask` の結果をそのままタスクとして使用するように変更
## [0.3.1] - 2026-01-31 ## [0.3.1] - 2026-01-31
### Added ### Added

View File

@ -291,15 +291,11 @@ describe('addTask', () => {
expect(content).not.toContain('workflow:'); expect(content).not.toContain('workflow:');
}); });
it('should fetch issue and summarize with AI when given issue reference', async () => { it('should fetch issue and use directly as task content when given issue reference', async () => {
// Given: issue reference "#99" // Given: issue reference "#99"
const issueText = 'Issue #99: Fix login timeout\n\nThe login page times out after 30 seconds.'; const issueText = 'Issue #99: Fix login timeout\n\nThe login page times out after 30 seconds.';
const summarized = '# ログインタイムアウト修正\nログインページの30秒タイムアウトを修正する';
mockResolveIssueTask.mockReturnValue(issueText); mockResolveIssueTask.mockReturnValue(issueText);
const mockProviderCall = vi.fn().mockResolvedValue({ content: summarized });
mockGetProvider.mockReturnValue({ call: mockProviderCall } as any);
mockSummarizeTaskName.mockResolvedValue('fix-login-timeout'); mockSummarizeTaskName.mockResolvedValue('fix-login-timeout');
mockConfirm.mockResolvedValue(false); mockConfirm.mockResolvedValue(false);
mockListWorkflows.mockReturnValue([]); mockListWorkflows.mockReturnValue([]);
@ -313,29 +309,16 @@ describe('addTask', () => {
// Then: resolveIssueTask was called // Then: resolveIssueTask was called
expect(mockResolveIssueTask).toHaveBeenCalledWith('#99'); expect(mockResolveIssueTask).toHaveBeenCalledWith('#99');
// Then: summarizeConversation was called with issue text // Then: task file created with issue text directly (no AI summarization)
expect(mockProviderCall).toHaveBeenCalledWith(
'task-summarizer',
issueText,
expect.objectContaining({
cwd: testDir,
maxTurns: 1,
allowedTools: [],
}),
);
// Then: task file created with summarized content
const taskFile = path.join(testDir, '.takt', 'tasks', 'fix-login-timeout.yaml'); const taskFile = path.join(testDir, '.takt', 'tasks', 'fix-login-timeout.yaml');
expect(fs.existsSync(taskFile)).toBe(true); expect(fs.existsSync(taskFile)).toBe(true);
const content = fs.readFileSync(taskFile, 'utf-8'); const content = fs.readFileSync(taskFile, 'utf-8');
expect(content).toContain('ログインタイムアウト修正'); expect(content).toContain('Fix login timeout');
}); });
it('should proceed to worktree/workflow settings after issue summarization', async () => { it('should proceed to worktree/workflow settings after issue fetch', async () => {
// Given: issue with worktree enabled // Given: issue with worktree enabled
mockResolveIssueTask.mockReturnValue('Issue text'); mockResolveIssueTask.mockReturnValue('Issue text');
const mockProviderCall = vi.fn().mockResolvedValue({ content: 'Summarized issue' });
mockGetProvider.mockReturnValue({ call: mockProviderCall } as any);
mockSummarizeTaskName.mockResolvedValue('issue-task'); mockSummarizeTaskName.mockResolvedValue('issue-task');
mockConfirm.mockResolvedValue(true); mockConfirm.mockResolvedValue(true);
mockPromptInput.mockResolvedValue(''); mockPromptInput.mockResolvedValue('');

View File

@ -82,18 +82,16 @@ export async function addTask(cwd: string, task?: string): Promise<void> {
let taskContent: string; let taskContent: string;
if (task && isIssueReference(task)) { if (task && isIssueReference(task)) {
// Issue reference: fetch issue and summarize with AI // Issue reference: fetch issue and use directly as task content
info('Fetching GitHub Issue...'); info('Fetching GitHub Issue...');
let issueText: string;
try { try {
issueText = resolveIssueTask(task); taskContent = resolveIssueTask(task);
} catch (e) { } catch (e) {
const msg = e instanceof Error ? e.message : String(e); const msg = e instanceof Error ? e.message : String(e);
log.error('Failed to fetch GitHub Issue', { task, error: msg }); log.error('Failed to fetch GitHub Issue', { task, error: msg });
info(`Failed to fetch issue ${task}: ${msg}`); info(`Failed to fetch issue ${task}: ${msg}`);
return; return;
} }
taskContent = await summarizeConversation(cwd, issueText);
} else { } else {
// Interactive mode: AI conversation to refine task // Interactive mode: AI conversation to refine task
const result = await interactiveMode(cwd); const result = await interactiveMode(cwd);