feat: ProjectLocalConfig に concurrency を追加
This commit is contained in:
parent
6a28929497
commit
95cd36037a
@ -123,6 +123,7 @@ piece: default # このプロジェクトの現在の piece
|
|||||||
provider: claude # このプロジェクトの provider 上書き
|
provider: claude # このプロジェクトの provider 上書き
|
||||||
auto_pr: true # worktree 実行後に PR を自動作成
|
auto_pr: true # worktree 実行後に PR を自動作成
|
||||||
verbose: false # 詳細出力モード
|
verbose: false # 詳細出力モード
|
||||||
|
concurrency: 2 # このプロジェクトでの takt run 並列タスク数(1-10)
|
||||||
|
|
||||||
# provider 固有オプション(グローバルを上書き、piece/movement で上書き可能)
|
# provider 固有オプション(グローバルを上書き、piece/movement で上書き可能)
|
||||||
# provider_options:
|
# provider_options:
|
||||||
@ -145,6 +146,7 @@ verbose: false # 詳細出力モード
|
|||||||
| `provider` | `"claude"` \| `"codex"` \| `"opencode"` \| `"mock"` | - | provider 上書き |
|
| `provider` | `"claude"` \| `"codex"` \| `"opencode"` \| `"mock"` | - | provider 上書き |
|
||||||
| `auto_pr` | boolean | - | worktree 実行後に PR を自動作成 |
|
| `auto_pr` | boolean | - | worktree 実行後に PR を自動作成 |
|
||||||
| `verbose` | boolean | - | 詳細出力モード |
|
| `verbose` | boolean | - | 詳細出力モード |
|
||||||
|
| `concurrency` | number (1-10) | `1`(global 設定由来) | `takt run` の並列タスク数 |
|
||||||
| `provider_options` | object | - | provider 固有オプション |
|
| `provider_options` | object | - | provider 固有オプション |
|
||||||
| `provider_profiles` | object | - | provider 固有のパーミッションプロファイル |
|
| `provider_profiles` | object | - | provider 固有のパーミッションプロファイル |
|
||||||
|
|
||||||
|
|||||||
@ -123,6 +123,7 @@ piece: default # Current piece for this project
|
|||||||
provider: claude # Override provider for this project
|
provider: claude # Override provider for this project
|
||||||
auto_pr: true # Auto-create PR after worktree execution
|
auto_pr: true # Auto-create PR after worktree execution
|
||||||
verbose: false # Verbose output mode
|
verbose: false # Verbose output mode
|
||||||
|
concurrency: 2 # Parallel task count for takt run in this project (1-10)
|
||||||
|
|
||||||
# Provider-specific options (overrides global, overridden by piece/movement)
|
# Provider-specific options (overrides global, overridden by piece/movement)
|
||||||
# provider_options:
|
# provider_options:
|
||||||
@ -145,6 +146,7 @@ verbose: false # Verbose output mode
|
|||||||
| `provider` | `"claude"` \| `"codex"` \| `"opencode"` \| `"mock"` | - | Override provider |
|
| `provider` | `"claude"` \| `"codex"` \| `"opencode"` \| `"mock"` | - | Override provider |
|
||||||
| `auto_pr` | boolean | - | Auto-create PR after worktree execution |
|
| `auto_pr` | boolean | - | Auto-create PR after worktree execution |
|
||||||
| `verbose` | boolean | - | Verbose output mode |
|
| `verbose` | boolean | - | Verbose output mode |
|
||||||
|
| `concurrency` | number (1-10) | `1` (from global) | Parallel task count for `takt run` |
|
||||||
| `provider_options` | object | - | Provider-specific options |
|
| `provider_options` | object | - | Provider-specific options |
|
||||||
| `provider_profiles` | object | - | Provider-specific permission profiles |
|
| `provider_profiles` | object | - | Provider-specific permission profiles |
|
||||||
|
|
||||||
|
|||||||
@ -53,12 +53,14 @@ describe('config env overrides', () => {
|
|||||||
|
|
||||||
it('should apply project env overrides from generated env names', () => {
|
it('should apply project env overrides from generated env names', () => {
|
||||||
process.env.TAKT_VERBOSE = 'true';
|
process.env.TAKT_VERBOSE = 'true';
|
||||||
|
process.env.TAKT_CONCURRENCY = '3';
|
||||||
process.env.TAKT_ANALYTICS_EVENTS_PATH = '/tmp/project-analytics';
|
process.env.TAKT_ANALYTICS_EVENTS_PATH = '/tmp/project-analytics';
|
||||||
|
|
||||||
const raw: Record<string, unknown> = {};
|
const raw: Record<string, unknown> = {};
|
||||||
applyProjectConfigEnvOverrides(raw);
|
applyProjectConfigEnvOverrides(raw);
|
||||||
|
|
||||||
expect(raw.verbose).toBe(true);
|
expect(raw.verbose).toBe(true);
|
||||||
|
expect(raw.concurrency).toBe(3);
|
||||||
expect(raw.analytics).toEqual({
|
expect(raw.analytics).toEqual({
|
||||||
events_path: '/tmp/project-analytics',
|
events_path: '/tmp/project-analytics',
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1246,6 +1246,14 @@ describe('saveProjectConfig snake_case denormalization', () => {
|
|||||||
expect((saved as Record<string, unknown>).base_branch).toBeUndefined();
|
expect((saved as Record<string, unknown>).base_branch).toBeUndefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should persist concurrency and reload correctly', () => {
|
||||||
|
saveProjectConfig(testDir, { piece: 'default', concurrency: 3 });
|
||||||
|
|
||||||
|
const saved = loadProjectConfig(testDir);
|
||||||
|
|
||||||
|
expect(saved.concurrency).toBe(3);
|
||||||
|
});
|
||||||
|
|
||||||
it('should not write camelCase keys to YAML file', () => {
|
it('should not write camelCase keys to YAML file', () => {
|
||||||
saveProjectConfig(testDir, { piece: 'default', autoPr: true, draftPr: false, baseBranch: 'develop' });
|
saveProjectConfig(testDir, { piece: 'default', autoPr: true, draftPr: false, baseBranch: 'develop' });
|
||||||
|
|
||||||
@ -1261,7 +1269,7 @@ describe('saveProjectConfig snake_case denormalization', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('resolveConfigValue autoPr/draftPr/baseBranch from project config', () => {
|
describe('resolveConfigValue autoPr/draftPr/baseBranch/concurrency from project config', () => {
|
||||||
let testDir: string;
|
let testDir: string;
|
||||||
let originalTaktConfigDir: string | undefined;
|
let originalTaktConfigDir: string | undefined;
|
||||||
|
|
||||||
@ -1309,4 +1317,12 @@ describe('resolveConfigValue autoPr/draftPr/baseBranch from project config', ()
|
|||||||
|
|
||||||
expect(resolveConfigValue(testDir, 'baseBranch')).toBe('main');
|
expect(resolveConfigValue(testDir, 'baseBranch')).toBe('main');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should resolve concurrency from project config', () => {
|
||||||
|
const projectConfigDir = getProjectConfigDir(testDir);
|
||||||
|
mkdirSync(projectConfigDir, { recursive: true });
|
||||||
|
writeFileSync(join(projectConfigDir, 'config.yaml'), 'concurrency: 3\n');
|
||||||
|
|
||||||
|
expect(resolveConfigValue(testDir, 'concurrency')).toBe(3);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -36,6 +36,11 @@ describe('Schemas accept opencode provider', () => {
|
|||||||
expect(result.provider).toBe('opencode');
|
expect(result.provider).toBe('opencode');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should accept concurrency in ProjectConfigSchema', () => {
|
||||||
|
const result = ProjectConfigSchema.parse({ concurrency: 3 });
|
||||||
|
expect(result.concurrency).toBe(3);
|
||||||
|
});
|
||||||
|
|
||||||
it('should accept opencode in CustomAgentConfigSchema', () => {
|
it('should accept opencode in CustomAgentConfigSchema', () => {
|
||||||
const result = CustomAgentConfigSchema.parse({
|
const result = CustomAgentConfigSchema.parse({
|
||||||
name: 'test',
|
name: 'test',
|
||||||
|
|||||||
@ -137,6 +137,8 @@ export interface ProjectConfig {
|
|||||||
providerOptions?: MovementProviderOptions;
|
providerOptions?: MovementProviderOptions;
|
||||||
/** Provider-specific permission profiles */
|
/** Provider-specific permission profiles */
|
||||||
providerProfiles?: ProviderPermissionProfiles;
|
providerProfiles?: ProviderPermissionProfiles;
|
||||||
|
/** Number of tasks to run concurrently in takt run (1-10) */
|
||||||
|
concurrency?: number;
|
||||||
/** Base branch to clone from (overrides global baseBranch) */
|
/** Base branch to clone from (overrides global baseBranch) */
|
||||||
baseBranch?: string;
|
baseBranch?: string;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -494,6 +494,8 @@ export const ProjectConfigSchema = z.object({
|
|||||||
model: z.string().optional(),
|
model: z.string().optional(),
|
||||||
provider_options: MovementProviderOptionsSchema,
|
provider_options: MovementProviderOptionsSchema,
|
||||||
provider_profiles: ProviderPermissionProfilesSchema,
|
provider_profiles: ProviderPermissionProfilesSchema,
|
||||||
|
/** Number of tasks to run concurrently in takt run (default from global: 1, max: 10) */
|
||||||
|
concurrency: z.number().int().min(1).max(10).optional(),
|
||||||
/** Base branch to clone from (overrides global base_branch) */
|
/** Base branch to clone from (overrides global base_branch) */
|
||||||
base_branch: z.string().optional(),
|
base_branch: z.string().optional(),
|
||||||
});
|
});
|
||||||
|
|||||||
1
src/infra/config/env/config-env-overrides.ts
vendored
1
src/infra/config/env/config-env-overrides.ts
vendored
@ -132,6 +132,7 @@ const PROJECT_ENV_SPECS: readonly EnvSpec[] = [
|
|||||||
{ path: 'piece', type: 'string' },
|
{ path: 'piece', type: 'string' },
|
||||||
{ path: 'provider', type: 'string' },
|
{ path: 'provider', type: 'string' },
|
||||||
{ path: 'verbose', type: 'boolean' },
|
{ path: 'verbose', type: 'boolean' },
|
||||||
|
{ path: 'concurrency', type: 'number' },
|
||||||
{ path: 'analytics', type: 'json' },
|
{ path: 'analytics', type: 'json' },
|
||||||
{ path: 'analytics.enabled', type: 'boolean' },
|
{ path: 'analytics.enabled', type: 'boolean' },
|
||||||
{ path: 'analytics.events_path', type: 'string' },
|
{ path: 'analytics.events_path', type: 'string' },
|
||||||
|
|||||||
@ -20,6 +20,8 @@ export interface ProjectLocalConfig {
|
|||||||
baseBranch?: string;
|
baseBranch?: string;
|
||||||
/** Verbose output mode */
|
/** Verbose output mode */
|
||||||
verbose?: boolean;
|
verbose?: boolean;
|
||||||
|
/** Number of tasks to run concurrently in takt run (1-10) */
|
||||||
|
concurrency?: number;
|
||||||
/** Project-level analytics overrides */
|
/** Project-level analytics overrides */
|
||||||
analytics?: AnalyticsConfig;
|
analytics?: AnalyticsConfig;
|
||||||
/** Provider-specific options (overrides global, overridden by piece/movement) */
|
/** Provider-specific options (overrides global, overridden by piece/movement) */
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user