ExecutionMetadataからProject Rootを削除
worktreeモードでタスク実行時、エージェントがmainディレクトリで 作業してしまうバグの修正。metadataでProject Rootを見せていたため Claudeがそちらで作業していた可能性がある。 - ExecutionMetadataインターフェースからprojectRootを削除 - buildExecutionMetadataからprojectRoot設定を削除 - METADATA_STRINGSからprojectRootとmodeを削除 - renderExecutionMetadataからProject Root表示を削除 - 関連テストを更新
This commit is contained in:
parent
588d157daa
commit
277d490eeb
@ -47,7 +47,7 @@ describe('instruction-builder', () => {
|
|||||||
expect(result).toContain('Do some work');
|
expect(result).toContain('Do some work');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should include Project Root and Mode when cwd !== projectCwd', () => {
|
it('should NOT include Project Root even when cwd !== projectCwd', () => {
|
||||||
const step = createMinimalStep('Do some work');
|
const step = createMinimalStep('Do some work');
|
||||||
const context = createMinimalContext({
|
const context = createMinimalContext({
|
||||||
cwd: '/worktree-path',
|
cwd: '/worktree-path',
|
||||||
@ -58,36 +58,11 @@ describe('instruction-builder', () => {
|
|||||||
|
|
||||||
expect(result).toContain('## Execution Context');
|
expect(result).toContain('## Execution Context');
|
||||||
expect(result).toContain('Working Directory: /worktree-path');
|
expect(result).toContain('Working Directory: /worktree-path');
|
||||||
expect(result).toContain('Project Root: /project-path');
|
expect(result).not.toContain('Project Root');
|
||||||
expect(result).toContain('Mode: worktree');
|
expect(result).not.toContain('Mode:');
|
||||||
expect(result).toContain('Do some work');
|
expect(result).toContain('Do some work');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should NOT include Project Root or Mode when cwd === projectCwd', () => {
|
|
||||||
const step = createMinimalStep('Do some work');
|
|
||||||
const context = createMinimalContext({
|
|
||||||
cwd: '/project',
|
|
||||||
projectCwd: '/project',
|
|
||||||
});
|
|
||||||
|
|
||||||
const result = buildInstruction(step, context);
|
|
||||||
|
|
||||||
expect(result).toContain('Working Directory: /project');
|
|
||||||
expect(result).not.toContain('Project Root');
|
|
||||||
expect(result).not.toContain('Mode:');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should NOT include Project Root or Mode when projectCwd is not set', () => {
|
|
||||||
const step = createMinimalStep('Do some work');
|
|
||||||
const context = createMinimalContext({ cwd: '/project' });
|
|
||||||
|
|
||||||
const result = buildInstruction(step, context);
|
|
||||||
|
|
||||||
expect(result).toContain('Working Directory: /project');
|
|
||||||
expect(result).not.toContain('Project Root');
|
|
||||||
expect(result).not.toContain('Mode:');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should prepend metadata before the instruction body', () => {
|
it('should prepend metadata before the instruction body', () => {
|
||||||
const step = createMinimalStep('Do some work');
|
const step = createMinimalStep('Do some work');
|
||||||
const context = createMinimalContext({ cwd: '/project' });
|
const context = createMinimalContext({ cwd: '/project' });
|
||||||
@ -133,7 +108,8 @@ describe('instruction-builder', () => {
|
|||||||
'- Report: /project/.takt/reports/20260128-worktree-report/00-plan.md'
|
'- Report: /project/.takt/reports/20260128-worktree-report/00-plan.md'
|
||||||
);
|
);
|
||||||
expect(result).toContain('Working Directory: /project/.takt/worktrees/my-task');
|
expect(result).toContain('Working Directory: /project/.takt/worktrees/my-task');
|
||||||
expect(result).toContain('Project Root: /project');
|
// Project Root should NOT be included in metadata (to avoid agent confusion)
|
||||||
|
expect(result).not.toContain('Project Root');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should replace multiple .takt/reports/{report_dir} occurrences', () => {
|
it('should replace multiple .takt/reports/{report_dir} occurrences', () => {
|
||||||
@ -183,15 +159,14 @@ describe('instruction-builder', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('buildExecutionMetadata', () => {
|
describe('buildExecutionMetadata', () => {
|
||||||
it('should set workingDirectory and omit projectRoot in normal mode', () => {
|
it('should set workingDirectory', () => {
|
||||||
const context = createMinimalContext({ cwd: '/project' });
|
const context = createMinimalContext({ cwd: '/project' });
|
||||||
const metadata = buildExecutionMetadata(context);
|
const metadata = buildExecutionMetadata(context);
|
||||||
|
|
||||||
expect(metadata.workingDirectory).toBe('/project');
|
expect(metadata.workingDirectory).toBe('/project');
|
||||||
expect(metadata.projectRoot).toBeUndefined();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should set projectRoot in worktree mode', () => {
|
it('should use cwd as workingDirectory even in worktree mode', () => {
|
||||||
const context = createMinimalContext({
|
const context = createMinimalContext({
|
||||||
cwd: '/worktree-path',
|
cwd: '/worktree-path',
|
||||||
projectCwd: '/project-path',
|
projectCwd: '/project-path',
|
||||||
@ -199,27 +174,6 @@ describe('instruction-builder', () => {
|
|||||||
const metadata = buildExecutionMetadata(context);
|
const metadata = buildExecutionMetadata(context);
|
||||||
|
|
||||||
expect(metadata.workingDirectory).toBe('/worktree-path');
|
expect(metadata.workingDirectory).toBe('/worktree-path');
|
||||||
expect(metadata.projectRoot).toBe('/project-path');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should omit projectRoot when projectCwd is not set', () => {
|
|
||||||
const context = createMinimalContext({ cwd: '/project' });
|
|
||||||
// projectCwd is undefined by default
|
|
||||||
const metadata = buildExecutionMetadata(context);
|
|
||||||
|
|
||||||
expect(metadata.workingDirectory).toBe('/project');
|
|
||||||
expect(metadata.projectRoot).toBeUndefined();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should omit projectRoot when cwd equals projectCwd', () => {
|
|
||||||
const context = createMinimalContext({
|
|
||||||
cwd: '/same-path',
|
|
||||||
projectCwd: '/same-path',
|
|
||||||
});
|
|
||||||
const metadata = buildExecutionMetadata(context);
|
|
||||||
|
|
||||||
expect(metadata.workingDirectory).toBe('/same-path');
|
|
||||||
expect(metadata.projectRoot).toBeUndefined();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should default language to en when not specified', () => {
|
it('should default language to en when not specified', () => {
|
||||||
@ -238,7 +192,7 @@ describe('instruction-builder', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('renderExecutionMetadata', () => {
|
describe('renderExecutionMetadata', () => {
|
||||||
it('should render normal mode without Project Root or Mode', () => {
|
it('should render Working Directory only', () => {
|
||||||
const rendered = renderExecutionMetadata({ workingDirectory: '/project', language: 'en' });
|
const rendered = renderExecutionMetadata({ workingDirectory: '/project', language: 'en' });
|
||||||
|
|
||||||
expect(rendered).toContain('## Execution Context');
|
expect(rendered).toContain('## Execution Context');
|
||||||
@ -247,19 +201,6 @@ describe('instruction-builder', () => {
|
|||||||
expect(rendered).not.toContain('Mode:');
|
expect(rendered).not.toContain('Mode:');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should render worktree mode with Project Root and Mode', () => {
|
|
||||||
const rendered = renderExecutionMetadata({
|
|
||||||
workingDirectory: '/worktree',
|
|
||||||
projectRoot: '/project',
|
|
||||||
language: 'en',
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(rendered).toContain('## Execution Context');
|
|
||||||
expect(rendered).toContain('- Working Directory: /worktree');
|
|
||||||
expect(rendered).toContain('- Project Root: /project');
|
|
||||||
expect(rendered).toContain('- Mode: worktree');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should end with a trailing empty line', () => {
|
it('should end with a trailing empty line', () => {
|
||||||
const rendered = renderExecutionMetadata({ workingDirectory: '/project', language: 'en' });
|
const rendered = renderExecutionMetadata({ workingDirectory: '/project', language: 'en' });
|
||||||
|
|
||||||
@ -275,17 +216,6 @@ describe('instruction-builder', () => {
|
|||||||
expect(rendered).not.toContain('Working Directory');
|
expect(rendered).not.toContain('Working Directory');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should render worktree mode in Japanese', () => {
|
|
||||||
const rendered = renderExecutionMetadata({
|
|
||||||
workingDirectory: '/worktree',
|
|
||||||
projectRoot: '/project',
|
|
||||||
language: 'ja',
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(rendered).toContain('- プロジェクトルート: /project');
|
|
||||||
expect(rendered).toContain('モード: worktree');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should include English note only for en, not for ja', () => {
|
it('should include English note only for en, not for ja', () => {
|
||||||
const enRendered = renderExecutionMetadata({ workingDirectory: '/project', language: 'en' });
|
const enRendered = renderExecutionMetadata({ workingDirectory: '/project', language: 'en' });
|
||||||
const jaRendered = renderExecutionMetadata({ workingDirectory: '/project', language: 'ja' });
|
const jaRendered = renderExecutionMetadata({ workingDirectory: '/project', language: 'ja' });
|
||||||
|
|||||||
@ -39,8 +39,6 @@ export interface InstructionContext {
|
|||||||
export interface ExecutionMetadata {
|
export interface ExecutionMetadata {
|
||||||
/** The agent's working directory (may be a worktree) */
|
/** The agent's working directory (may be a worktree) */
|
||||||
readonly workingDirectory: string;
|
readonly workingDirectory: string;
|
||||||
/** Project root where .takt/ lives. Present only in worktree mode. */
|
|
||||||
readonly projectRoot?: string;
|
|
||||||
/** Language for metadata rendering */
|
/** Language for metadata rendering */
|
||||||
readonly language: Language;
|
readonly language: Language;
|
||||||
}
|
}
|
||||||
@ -49,15 +47,10 @@ export interface ExecutionMetadata {
|
|||||||
* Build execution metadata from instruction context.
|
* Build execution metadata from instruction context.
|
||||||
*
|
*
|
||||||
* Pure function: InstructionContext → ExecutionMetadata.
|
* Pure function: InstructionContext → ExecutionMetadata.
|
||||||
* Sets `projectRoot` only when cwd differs from projectCwd (worktree mode).
|
|
||||||
*/
|
*/
|
||||||
export function buildExecutionMetadata(context: InstructionContext): ExecutionMetadata {
|
export function buildExecutionMetadata(context: InstructionContext): ExecutionMetadata {
|
||||||
const projectRoot = context.projectCwd ?? context.cwd;
|
|
||||||
const isWorktree = context.cwd !== projectRoot;
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
workingDirectory: context.cwd,
|
workingDirectory: context.cwd,
|
||||||
...(isWorktree ? { projectRoot } : {}),
|
|
||||||
language: context.language ?? 'en',
|
language: context.language ?? 'en',
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -67,15 +60,11 @@ const METADATA_STRINGS = {
|
|||||||
en: {
|
en: {
|
||||||
heading: '## Execution Context',
|
heading: '## Execution Context',
|
||||||
workingDirectory: 'Working Directory',
|
workingDirectory: 'Working Directory',
|
||||||
projectRoot: 'Project Root',
|
|
||||||
mode: 'Mode: worktree (source edits in Working Directory, reports in Project Root)',
|
|
||||||
note: 'Note: This section is metadata. Follow the language used in the rest of the prompt.',
|
note: 'Note: This section is metadata. Follow the language used in the rest of the prompt.',
|
||||||
},
|
},
|
||||||
ja: {
|
ja: {
|
||||||
heading: '## 実行コンテキスト',
|
heading: '## 実行コンテキスト',
|
||||||
workingDirectory: '作業ディレクトリ',
|
workingDirectory: '作業ディレクトリ',
|
||||||
projectRoot: 'プロジェクトルート',
|
|
||||||
mode: 'モード: worktree(ソース編集は作業ディレクトリ、レポートはプロジェクトルート)',
|
|
||||||
note: '',
|
note: '',
|
||||||
},
|
},
|
||||||
} as const;
|
} as const;
|
||||||
@ -85,7 +74,6 @@ const METADATA_STRINGS = {
|
|||||||
*
|
*
|
||||||
* Pure function: ExecutionMetadata → string.
|
* Pure function: ExecutionMetadata → string.
|
||||||
* Always includes heading + Working Directory.
|
* Always includes heading + Working Directory.
|
||||||
* Adds Project Root and Mode only in worktree mode (when projectRoot is present).
|
|
||||||
* Language determines the output language; 'en' includes a note about language consistency.
|
* Language determines the output language; 'en' includes a note about language consistency.
|
||||||
*/
|
*/
|
||||||
export function renderExecutionMetadata(metadata: ExecutionMetadata): string {
|
export function renderExecutionMetadata(metadata: ExecutionMetadata): string {
|
||||||
@ -94,10 +82,6 @@ export function renderExecutionMetadata(metadata: ExecutionMetadata): string {
|
|||||||
strings.heading,
|
strings.heading,
|
||||||
`- ${strings.workingDirectory}: ${metadata.workingDirectory}`,
|
`- ${strings.workingDirectory}: ${metadata.workingDirectory}`,
|
||||||
];
|
];
|
||||||
if (metadata.projectRoot !== undefined) {
|
|
||||||
lines.push(`- ${strings.projectRoot}: ${metadata.projectRoot}`);
|
|
||||||
lines.push(`- ${strings.mode}`);
|
|
||||||
}
|
|
||||||
if (strings.note) {
|
if (strings.note) {
|
||||||
lines.push('');
|
lines.push('');
|
||||||
lines.push(strings.note);
|
lines.push(strings.note);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user