@sk8metal/michi-cli 0.5.0 → 0.8.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.
- package/CHANGELOG.md +136 -1
- package/README.md +2 -1
- package/dist/scripts/config/config-schema.d.ts +35 -0
- package/dist/scripts/config/config-schema.d.ts.map +1 -1
- package/dist/scripts/config/config-schema.js +56 -0
- package/dist/scripts/config/config-schema.js.map +1 -1
- package/dist/scripts/confluence-sync.d.ts.map +1 -1
- package/dist/scripts/confluence-sync.js +15 -2
- package/dist/scripts/confluence-sync.js.map +1 -1
- package/dist/scripts/github-actions-client.d.ts +79 -0
- package/dist/scripts/github-actions-client.d.ts.map +1 -0
- package/dist/scripts/github-actions-client.js +182 -0
- package/dist/scripts/github-actions-client.js.map +1 -0
- package/dist/scripts/health-check-service.d.ts +46 -0
- package/dist/scripts/health-check-service.d.ts.map +1 -0
- package/dist/scripts/health-check-service.js +114 -0
- package/dist/scripts/health-check-service.js.map +1 -0
- package/dist/scripts/markdown-to-confluence.d.ts.map +1 -1
- package/dist/scripts/markdown-to-confluence.js +25 -3
- package/dist/scripts/markdown-to-confluence.js.map +1 -1
- package/dist/scripts/mermaid-converter.d.ts +24 -0
- package/dist/scripts/mermaid-converter.d.ts.map +1 -0
- package/dist/scripts/mermaid-converter.js +49 -0
- package/dist/scripts/mermaid-converter.js.map +1 -0
- package/dist/scripts/template/multi-repo-renderer.d.ts +67 -0
- package/dist/scripts/template/multi-repo-renderer.d.ts.map +1 -0
- package/dist/scripts/template/multi-repo-renderer.js +123 -0
- package/dist/scripts/template/multi-repo-renderer.js.map +1 -0
- package/dist/scripts/template/renderer.d.ts +4 -0
- package/dist/scripts/template/renderer.d.ts.map +1 -1
- package/dist/scripts/template/renderer.js.map +1 -1
- package/dist/scripts/test-execution-generator.d.ts.map +1 -1
- package/dist/scripts/test-execution-generator.js +94 -11
- package/dist/scripts/test-execution-generator.js.map +1 -1
- package/dist/scripts/test-script-runner.d.ts +33 -0
- package/dist/scripts/test-script-runner.d.ts.map +1 -0
- package/dist/scripts/test-script-runner.js +77 -0
- package/dist/scripts/test-script-runner.js.map +1 -0
- package/dist/scripts/utils/config-loader.d.ts +21 -1
- package/dist/scripts/utils/config-loader.d.ts.map +1 -1
- package/dist/scripts/utils/config-loader.js +149 -3
- package/dist/scripts/utils/config-loader.js.map +1 -1
- package/dist/scripts/utils/multi-repo-validator.d.ts +30 -0
- package/dist/scripts/utils/multi-repo-validator.d.ts.map +1 -0
- package/dist/scripts/utils/multi-repo-validator.js +105 -0
- package/dist/scripts/utils/multi-repo-validator.js.map +1 -0
- package/dist/scripts/utils/spec-archiver.d.ts +38 -0
- package/dist/scripts/utils/spec-archiver.d.ts.map +1 -0
- package/dist/scripts/utils/spec-archiver.js +210 -0
- package/dist/scripts/utils/spec-archiver.js.map +1 -0
- package/dist/scripts/utils/spec-updater.d.ts +4 -0
- package/dist/scripts/utils/spec-updater.d.ts.map +1 -1
- package/dist/scripts/utils/spec-updater.js.map +1 -1
- package/dist/src/cli.d.ts.map +1 -1
- package/dist/src/cli.js +262 -14
- package/dist/src/cli.js.map +1 -1
- package/dist/src/commands/multi-repo-add-repo.d.ts +26 -0
- package/dist/src/commands/multi-repo-add-repo.d.ts.map +1 -0
- package/dist/src/commands/multi-repo-add-repo.js +56 -0
- package/dist/src/commands/multi-repo-add-repo.js.map +1 -0
- package/dist/src/commands/multi-repo-ci-status.d.ts +46 -0
- package/dist/src/commands/multi-repo-ci-status.d.ts.map +1 -0
- package/dist/src/commands/multi-repo-ci-status.js +285 -0
- package/dist/src/commands/multi-repo-ci-status.js.map +1 -0
- package/dist/src/commands/multi-repo-confluence-sync.d.ts +45 -0
- package/dist/src/commands/multi-repo-confluence-sync.d.ts.map +1 -0
- package/dist/src/commands/multi-repo-confluence-sync.js +135 -0
- package/dist/src/commands/multi-repo-confluence-sync.js.map +1 -0
- package/dist/src/commands/multi-repo-init.d.ts +26 -0
- package/dist/src/commands/multi-repo-init.d.ts.map +1 -0
- package/dist/src/commands/multi-repo-init.js +101 -0
- package/dist/src/commands/multi-repo-init.js.map +1 -0
- package/dist/src/commands/multi-repo-list.d.ts +28 -0
- package/dist/src/commands/multi-repo-list.d.ts.map +1 -0
- package/dist/src/commands/multi-repo-list.js +38 -0
- package/dist/src/commands/multi-repo-list.js.map +1 -0
- package/dist/src/commands/multi-repo-test.d.ts +56 -0
- package/dist/src/commands/multi-repo-test.d.ts.map +1 -0
- package/dist/src/commands/multi-repo-test.js +70 -0
- package/dist/src/commands/multi-repo-test.js.map +1 -0
- package/dist/src/commands/setup-existing.d.ts.map +1 -1
- package/dist/src/commands/setup-existing.js +30 -8
- package/dist/src/commands/setup-existing.js.map +1 -1
- package/dist/src/commands/spec-archive.d.ts +17 -0
- package/dist/src/commands/spec-archive.d.ts.map +1 -0
- package/dist/src/commands/spec-archive.js +40 -0
- package/dist/src/commands/spec-archive.js.map +1 -0
- package/dist/src/commands/spec-list.d.ts +15 -0
- package/dist/src/commands/spec-list.d.ts.map +1 -0
- package/dist/src/commands/spec-list.js +55 -0
- package/dist/src/commands/spec-list.js.map +1 -0
- package/docs/user-guide/guides/multi-repo-guide.md +591 -0
- package/docs/user-guide/guides/multi-repo-migration-guide.md +516 -0
- package/docs/user-guide/reference/multi-repo-api.md +771 -0
- package/docs/user-guide/reference/quick-reference.md +22 -37
- package/package.json +1 -4
- package/scripts/__tests__/config-loader-multi-repo.test.ts +342 -0
- package/scripts/__tests__/github-actions-client.test.ts +543 -0
- package/scripts/__tests__/health-check-service.test.ts +142 -0
- package/scripts/__tests__/markdown-to-confluence.test.ts +262 -0
- package/scripts/__tests__/mermaid-converter.test.ts +236 -0
- package/scripts/__tests__/multi-repo-config-schema.test.ts +335 -0
- package/scripts/__tests__/multi-repo-validator.test.ts +524 -0
- package/scripts/__tests__/spec-archiver.test.ts +512 -0
- package/scripts/__tests__/test-script-runner.test.ts +217 -0
- package/scripts/config/config-schema.ts +64 -0
- package/scripts/confluence-sync.ts +16 -2
- package/scripts/github-actions-client.ts +258 -0
- package/scripts/health-check-service.ts +171 -0
- package/scripts/markdown-to-confluence.ts +37 -6
- package/scripts/mermaid-converter.ts +56 -0
- package/scripts/template/__tests__/multi-repo-renderer.test.ts +261 -0
- package/scripts/template/multi-repo-renderer.ts +172 -0
- package/scripts/template/renderer.ts +5 -0
- package/scripts/test-execution-generator.ts +104 -11
- package/scripts/test-script-runner.ts +130 -0
- package/scripts/utils/__tests__/config-validator.test.ts +104 -6
- package/scripts/utils/__tests__/multi-repo-validator.test.ts +335 -0
- package/scripts/utils/config-loader.ts +197 -3
- package/scripts/utils/multi-repo-validator.ts +141 -0
- package/scripts/utils/spec-archiver.ts +260 -0
- package/scripts/utils/spec-updater.ts +4 -0
- package/templates/claude/agents/pr-size-monitor/AGENT.md +330 -0
- package/templates/claude/commands/michi/spec-impl.md +208 -35
- package/templates/claude-agent/agents/doc-reviewer.md +176 -0
- package/templates/claude-agent/rules/doc-review-rules.md +98 -0
- package/templates/claude-agent/rules/doc-review.md +91 -0
- package/templates/multi-repo/docs/ci-status.md +51 -0
- package/templates/multi-repo/docs/release-notes.md +99 -0
- package/templates/multi-repo/overview/architecture.md +102 -0
- package/templates/multi-repo/overview/requirements.md +68 -0
- package/templates/multi-repo/overview/sequence.md +79 -0
- package/templates/multi-repo/steering/multi-repo.md +74 -0
- package/templates/multi-repo/tests/strategy.md +89 -0
- package/dist/scripts/__tests__/create-project.test.d.ts +0 -2
- package/dist/scripts/__tests__/create-project.test.d.ts.map +0 -1
- package/dist/scripts/__tests__/create-project.test.js +0 -243
- package/dist/scripts/__tests__/create-project.test.js.map +0 -1
- package/dist/scripts/__tests__/jira-transitions.test.d.ts +0 -5
- package/dist/scripts/__tests__/jira-transitions.test.d.ts.map +0 -1
- package/dist/scripts/__tests__/jira-transitions.test.js +0 -172
- package/dist/scripts/__tests__/jira-transitions.test.js.map +0 -1
- package/dist/scripts/__tests__/multi-project-estimate.test.d.ts +0 -2
- package/dist/scripts/__tests__/multi-project-estimate.test.d.ts.map +0 -1
- package/dist/scripts/__tests__/multi-project-estimate.test.js +0 -118
- package/dist/scripts/__tests__/multi-project-estimate.test.js.map +0 -1
- package/dist/scripts/__tests__/setup-existing-project.test.d.ts +0 -2
- package/dist/scripts/__tests__/setup-existing-project.test.d.ts.map +0 -1
- package/dist/scripts/__tests__/setup-existing-project.test.js +0 -208
- package/dist/scripts/__tests__/setup-existing-project.test.js.map +0 -1
- package/dist/scripts/__tests__/setup-interactive.test.d.ts +0 -2
- package/dist/scripts/__tests__/setup-interactive.test.d.ts.map +0 -1
- package/dist/scripts/__tests__/setup-interactive.test.js +0 -166
- package/dist/scripts/__tests__/setup-interactive.test.js.map +0 -1
- package/dist/scripts/__tests__/spec-impl-workflow.test.d.ts +0 -5
- package/dist/scripts/__tests__/spec-impl-workflow.test.d.ts.map +0 -1
- package/dist/scripts/__tests__/spec-impl-workflow.test.js +0 -323
- package/dist/scripts/__tests__/spec-impl-workflow.test.js.map +0 -1
- package/dist/scripts/__tests__/spec-loader.test.d.ts +0 -5
- package/dist/scripts/__tests__/spec-loader.test.d.ts.map +0 -1
- package/dist/scripts/__tests__/spec-loader.test.js +0 -153
- package/dist/scripts/__tests__/spec-loader.test.js.map +0 -1
- package/dist/scripts/__tests__/validate-phase.test.d.ts +0 -5
- package/dist/scripts/__tests__/validate-phase.test.d.ts.map +0 -1
- package/dist/scripts/__tests__/validate-phase.test.js +0 -249
- package/dist/scripts/__tests__/validate-phase.test.js.map +0 -1
- package/dist/scripts/constants/__tests__/environments.test.d.ts +0 -2
- package/dist/scripts/constants/__tests__/environments.test.d.ts.map +0 -1
- package/dist/scripts/constants/__tests__/environments.test.js +0 -125
- package/dist/scripts/constants/__tests__/environments.test.js.map +0 -1
- package/dist/scripts/constants/__tests__/languages.test.d.ts +0 -2
- package/dist/scripts/constants/__tests__/languages.test.d.ts.map +0 -1
- package/dist/scripts/constants/__tests__/languages.test.js +0 -82
- package/dist/scripts/constants/__tests__/languages.test.js.map +0 -1
- package/dist/scripts/create-project.d.ts +0 -16
- package/dist/scripts/create-project.d.ts.map +0 -1
- package/dist/scripts/create-project.js +0 -334
- package/dist/scripts/create-project.js.map +0 -1
- package/dist/scripts/list-projects.d.ts +0 -7
- package/dist/scripts/list-projects.d.ts.map +0 -1
- package/dist/scripts/list-projects.js +0 -88
- package/dist/scripts/list-projects.js.map +0 -1
- package/dist/scripts/template/__tests__/renderer.test.d.ts +0 -2
- package/dist/scripts/template/__tests__/renderer.test.d.ts.map +0 -1
- package/dist/scripts/template/__tests__/renderer.test.js +0 -165
- package/dist/scripts/template/__tests__/renderer.test.js.map +0 -1
- package/dist/scripts/utils/__tests__/aidlc-parser.test.d.ts +0 -5
- package/dist/scripts/utils/__tests__/aidlc-parser.test.d.ts.map +0 -1
- package/dist/scripts/utils/__tests__/aidlc-parser.test.js +0 -315
- package/dist/scripts/utils/__tests__/aidlc-parser.test.js.map +0 -1
- package/dist/scripts/utils/__tests__/business-days.test.d.ts +0 -5
- package/dist/scripts/utils/__tests__/business-days.test.d.ts.map +0 -1
- package/dist/scripts/utils/__tests__/business-days.test.js +0 -171
- package/dist/scripts/utils/__tests__/business-days.test.js.map +0 -1
- package/dist/scripts/utils/__tests__/config-loader.test.d.ts +0 -5
- package/dist/scripts/utils/__tests__/config-loader.test.d.ts.map +0 -1
- package/dist/scripts/utils/__tests__/config-loader.test.js +0 -314
- package/dist/scripts/utils/__tests__/config-loader.test.js.map +0 -1
- package/dist/scripts/utils/__tests__/config-validator.test.d.ts +0 -5
- package/dist/scripts/utils/__tests__/config-validator.test.d.ts.map +0 -1
- package/dist/scripts/utils/__tests__/config-validator.test.js +0 -396
- package/dist/scripts/utils/__tests__/config-validator.test.js.map +0 -1
- package/dist/scripts/utils/__tests__/env-config.test.d.ts +0 -5
- package/dist/scripts/utils/__tests__/env-config.test.d.ts.map +0 -1
- package/dist/scripts/utils/__tests__/env-config.test.js +0 -216
- package/dist/scripts/utils/__tests__/env-config.test.js.map +0 -1
- package/dist/scripts/utils/__tests__/feature-name-validator.test.d.ts +0 -5
- package/dist/scripts/utils/__tests__/feature-name-validator.test.d.ts.map +0 -1
- package/dist/scripts/utils/__tests__/feature-name-validator.test.js +0 -106
- package/dist/scripts/utils/__tests__/feature-name-validator.test.js.map +0 -1
- package/dist/scripts/utils/__tests__/jira-issue-type-fetcher.test.d.ts +0 -5
- package/dist/scripts/utils/__tests__/jira-issue-type-fetcher.test.d.ts.map +0 -1
- package/dist/scripts/utils/__tests__/jira-issue-type-fetcher.test.js +0 -202
- package/dist/scripts/utils/__tests__/jira-issue-type-fetcher.test.js.map +0 -1
- package/dist/scripts/utils/__tests__/project-meta.test.d.ts +0 -6
- package/dist/scripts/utils/__tests__/project-meta.test.d.ts.map +0 -1
- package/dist/scripts/utils/__tests__/project-meta.test.js +0 -154
- package/dist/scripts/utils/__tests__/project-meta.test.js.map +0 -1
- package/dist/scripts/utils/__tests__/security-validator.test.d.ts +0 -6
- package/dist/scripts/utils/__tests__/security-validator.test.d.ts.map +0 -1
- package/dist/scripts/utils/__tests__/security-validator.test.js +0 -219
- package/dist/scripts/utils/__tests__/security-validator.test.js.map +0 -1
- package/dist/scripts/utils/__tests__/spec-updater.test.d.ts +0 -5
- package/dist/scripts/utils/__tests__/spec-updater.test.d.ts.map +0 -1
- package/dist/scripts/utils/__tests__/spec-updater.test.js +0 -158
- package/dist/scripts/utils/__tests__/spec-updater.test.js.map +0 -1
- package/dist/scripts/utils/__tests__/tasks-converter.test.d.ts +0 -5
- package/dist/scripts/utils/__tests__/tasks-converter.test.d.ts.map +0 -1
- package/dist/scripts/utils/__tests__/tasks-converter.test.js +0 -500
- package/dist/scripts/utils/__tests__/tasks-converter.test.js.map +0 -1
- package/dist/scripts/utils/__tests__/tasks-format-validator.test.d.ts +0 -5
- package/dist/scripts/utils/__tests__/tasks-format-validator.test.d.ts.map +0 -1
- package/dist/scripts/utils/__tests__/tasks-format-validator.test.js +0 -314
- package/dist/scripts/utils/__tests__/tasks-format-validator.test.js.map +0 -1
- package/dist/scripts/utils/__tests__/test-runner.test.d.ts +0 -5
- package/dist/scripts/utils/__tests__/test-runner.test.d.ts.map +0 -1
- package/dist/scripts/utils/__tests__/test-runner.test.js +0 -64
- package/dist/scripts/utils/__tests__/test-runner.test.js.map +0 -1
- package/dist/src/__tests__/cli.test.d.ts +0 -5
- package/dist/src/__tests__/cli.test.d.ts.map +0 -1
- package/dist/src/__tests__/cli.test.js +0 -58
- package/dist/src/__tests__/cli.test.js.map +0 -1
- package/dist/src/__tests__/integration/internationalization.test.d.ts +0 -8
- package/dist/src/__tests__/integration/internationalization.test.d.ts.map +0 -1
- package/dist/src/__tests__/integration/internationalization.test.js +0 -333
- package/dist/src/__tests__/integration/internationalization.test.js.map +0 -1
- package/dist/src/__tests__/integration/setup/claude-agent.test.d.ts +0 -5
- package/dist/src/__tests__/integration/setup/claude-agent.test.d.ts.map +0 -1
- package/dist/src/__tests__/integration/setup/claude-agent.test.js +0 -122
- package/dist/src/__tests__/integration/setup/claude-agent.test.js.map +0 -1
- package/dist/src/__tests__/integration/setup/claude.test.d.ts +0 -5
- package/dist/src/__tests__/integration/setup/claude.test.d.ts.map +0 -1
- package/dist/src/__tests__/integration/setup/claude.test.js +0 -193
- package/dist/src/__tests__/integration/setup/claude.test.js.map +0 -1
- package/dist/src/__tests__/integration/setup/cursor.test.d.ts +0 -5
- package/dist/src/__tests__/integration/setup/cursor.test.d.ts.map +0 -1
- package/dist/src/__tests__/integration/setup/cursor.test.js +0 -166
- package/dist/src/__tests__/integration/setup/cursor.test.js.map +0 -1
- package/dist/src/__tests__/integration/setup/helpers/fs-assertions.d.ts +0 -32
- package/dist/src/__tests__/integration/setup/helpers/fs-assertions.d.ts.map +0 -1
- package/dist/src/__tests__/integration/setup/helpers/fs-assertions.js +0 -72
- package/dist/src/__tests__/integration/setup/helpers/fs-assertions.js.map +0 -1
- package/dist/src/__tests__/integration/setup/helpers/test-project.d.ts +0 -38
- package/dist/src/__tests__/integration/setup/helpers/test-project.d.ts.map +0 -1
- package/dist/src/__tests__/integration/setup/helpers/test-project.js +0 -83
- package/dist/src/__tests__/integration/setup/helpers/test-project.js.map +0 -1
- package/dist/src/__tests__/integration/setup/init.test.d.ts +0 -5
- package/dist/src/__tests__/integration/setup/init.test.d.ts.map +0 -1
- package/dist/src/__tests__/integration/setup/init.test.js +0 -352
- package/dist/src/__tests__/integration/setup/init.test.js.map +0 -1
- package/dist/src/__tests__/integration/setup/validation.test.d.ts +0 -5
- package/dist/src/__tests__/integration/setup/validation.test.d.ts.map +0 -1
- package/dist/src/__tests__/integration/setup/validation.test.js +0 -301
- package/dist/src/__tests__/integration/setup/validation.test.js.map +0 -1
- package/dist/src/commands/__tests__/init.test.d.ts +0 -5
- package/dist/src/commands/__tests__/init.test.d.ts.map +0 -1
- package/dist/src/commands/__tests__/init.test.js +0 -255
- package/dist/src/commands/__tests__/init.test.js.map +0 -1
- package/dist/src/commands/__tests__/migrate.test.d.ts +0 -5
- package/dist/src/commands/__tests__/migrate.test.d.ts.map +0 -1
- package/dist/src/commands/__tests__/migrate.test.js +0 -216
- package/dist/src/commands/__tests__/migrate.test.js.map +0 -1
- package/scripts/create-project.ts +0 -386
- package/scripts/list-projects.ts +0 -112
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 仕様書アーカイブユーティリティ
|
|
3
|
+
* 完了した仕様書を .kiro/specs/archive/ に移動する
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { existsSync, renameSync, mkdirSync, readdirSync, readFileSync, writeFileSync } from 'fs';
|
|
7
|
+
import { resolve } from 'path';
|
|
8
|
+
import { validateFeatureName as validateFeatureNameStrict } from './feature-name-validator.js';
|
|
9
|
+
|
|
10
|
+
export interface ArchiveResult {
|
|
11
|
+
success: boolean;
|
|
12
|
+
feature: string;
|
|
13
|
+
archivePath?: string;
|
|
14
|
+
error?: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface SpecInfo {
|
|
18
|
+
feature: string;
|
|
19
|
+
phase: string;
|
|
20
|
+
archived: boolean;
|
|
21
|
+
archivedAt?: string;
|
|
22
|
+
hasReleaseNotes: boolean;
|
|
23
|
+
archivePath?: string;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* featureName のバリデーション
|
|
28
|
+
* - kebab-case形式の検証(既存のバリデータを使用)
|
|
29
|
+
* - パストラバーサル攻撃を防止(追加のセキュリティチェック)
|
|
30
|
+
* @throws Error 不正な文字が含まれる場合
|
|
31
|
+
*/
|
|
32
|
+
function validateFeatureName(featureName: string): void {
|
|
33
|
+
// 空文字チェック(最初にチェック)
|
|
34
|
+
if (!featureName || featureName.trim().length === 0) {
|
|
35
|
+
throw new Error('Feature name cannot be empty');
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// パストラバーサル攻撃を防ぐ(セキュリティチェック)
|
|
39
|
+
if (featureName.includes('..') ||
|
|
40
|
+
featureName.includes('/') ||
|
|
41
|
+
featureName.includes('\\') ||
|
|
42
|
+
featureName.startsWith('.')) {
|
|
43
|
+
throw new Error(`Invalid feature name: path traversal detected in "${featureName}"`);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// kebab-case形式の厳密な検証(既存のバリデータを使用)
|
|
47
|
+
const result = validateFeatureNameStrict(featureName);
|
|
48
|
+
if (!result.valid) {
|
|
49
|
+
throw new Error(result.errors.join('\n'));
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* 仕様書がアーカイブ可能かチェック
|
|
55
|
+
*/
|
|
56
|
+
export function canArchiveSpec(
|
|
57
|
+
featureName: string,
|
|
58
|
+
projectRoot: string = process.cwd()
|
|
59
|
+
): { canArchive: boolean; reason?: string } {
|
|
60
|
+
try {
|
|
61
|
+
validateFeatureName(featureName);
|
|
62
|
+
} catch (error) {
|
|
63
|
+
return {
|
|
64
|
+
canArchive: false,
|
|
65
|
+
reason: error instanceof Error ? error.message : 'Invalid feature name',
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const specDir = resolve(projectRoot, `.kiro/specs/${featureName}`);
|
|
70
|
+
|
|
71
|
+
if (!existsSync(specDir)) {
|
|
72
|
+
return { canArchive: false, reason: 'Spec not found' };
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// spec.json を読み込み
|
|
76
|
+
const specJsonPath = resolve(specDir, 'spec.json');
|
|
77
|
+
if (!existsSync(specJsonPath)) {
|
|
78
|
+
return { canArchive: false, reason: 'spec.json not found' };
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
try {
|
|
82
|
+
const specContent = JSON.parse(readFileSync(specJsonPath, 'utf-8'));
|
|
83
|
+
|
|
84
|
+
// 既にアーカイブ済みかチェック
|
|
85
|
+
if (specContent.archived) {
|
|
86
|
+
return { canArchive: false, reason: 'Already archived' };
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// phase チェック
|
|
90
|
+
if (specContent.phase !== 'implementation-complete') {
|
|
91
|
+
return {
|
|
92
|
+
canArchive: false,
|
|
93
|
+
reason: `Phase is ${specContent.phase || 'unknown'}, not implementation-complete`,
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// release-notes チェック
|
|
98
|
+
const files = readdirSync(specDir);
|
|
99
|
+
const hasReleaseNotes = files.some(f => f.startsWith('release-notes-'));
|
|
100
|
+
|
|
101
|
+
if (!hasReleaseNotes) {
|
|
102
|
+
return { canArchive: false, reason: 'No release notes found' };
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return { canArchive: true };
|
|
106
|
+
} catch (error) {
|
|
107
|
+
return {
|
|
108
|
+
canArchive: false,
|
|
109
|
+
reason: `Error reading spec.json: ${error instanceof Error ? error.message : 'Unknown error'}`,
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* 仕様書をアーカイブ
|
|
116
|
+
*/
|
|
117
|
+
export function archiveSpec(
|
|
118
|
+
featureName: string,
|
|
119
|
+
options?: { reason?: string },
|
|
120
|
+
projectRoot: string = process.cwd()
|
|
121
|
+
): ArchiveResult {
|
|
122
|
+
// Defense in depth: 明示的に検証
|
|
123
|
+
try {
|
|
124
|
+
validateFeatureName(featureName);
|
|
125
|
+
} catch (error) {
|
|
126
|
+
return {
|
|
127
|
+
success: false,
|
|
128
|
+
feature: featureName,
|
|
129
|
+
error: error instanceof Error ? error.message : 'Invalid feature name',
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const check = canArchiveSpec(featureName, projectRoot);
|
|
134
|
+
|
|
135
|
+
if (!check.canArchive) {
|
|
136
|
+
return { success: false, feature: featureName, error: check.reason };
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const sourceDir = resolve(projectRoot, `.kiro/specs/${featureName}`);
|
|
140
|
+
const archiveDir = resolve(projectRoot, '.kiro/specs/archive');
|
|
141
|
+
const targetDir = resolve(archiveDir, featureName);
|
|
142
|
+
|
|
143
|
+
// archive ディレクトリ作成
|
|
144
|
+
if (!existsSync(archiveDir)) {
|
|
145
|
+
mkdirSync(archiveDir, { recursive: true });
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
try {
|
|
149
|
+
// ディレクトリ移動
|
|
150
|
+
renameSync(sourceDir, targetDir);
|
|
151
|
+
|
|
152
|
+
// spec.json に archived 情報を追加
|
|
153
|
+
const specJsonPath = resolve(targetDir, 'spec.json');
|
|
154
|
+
const spec = JSON.parse(readFileSync(specJsonPath, 'utf-8'));
|
|
155
|
+
spec.archived = {
|
|
156
|
+
at: new Date().toISOString(),
|
|
157
|
+
reason: options?.reason,
|
|
158
|
+
};
|
|
159
|
+
spec.lastUpdated = new Date().toISOString();
|
|
160
|
+
writeFileSync(specJsonPath, JSON.stringify(spec, null, 2), 'utf-8');
|
|
161
|
+
|
|
162
|
+
return { success: true, feature: featureName, archivePath: targetDir };
|
|
163
|
+
} catch (error) {
|
|
164
|
+
return {
|
|
165
|
+
success: false,
|
|
166
|
+
feature: featureName,
|
|
167
|
+
error: `Failed to archive: ${error instanceof Error ? error.message : 'Unknown error'}`,
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* すべての仕様書を一覧取得
|
|
174
|
+
*/
|
|
175
|
+
export function listSpecs(
|
|
176
|
+
options?: { includeArchived?: boolean },
|
|
177
|
+
projectRoot: string = process.cwd()
|
|
178
|
+
): SpecInfo[] {
|
|
179
|
+
const specs: SpecInfo[] = [];
|
|
180
|
+
const specsDir = resolve(projectRoot, '.kiro/specs');
|
|
181
|
+
|
|
182
|
+
if (!existsSync(specsDir)) {
|
|
183
|
+
return specs;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
const entries = readdirSync(specsDir, { withFileTypes: true });
|
|
187
|
+
|
|
188
|
+
for (const entry of entries) {
|
|
189
|
+
if (!entry.isDirectory()) continue;
|
|
190
|
+
|
|
191
|
+
if (entry.name === 'archive') {
|
|
192
|
+
if (options?.includeArchived) {
|
|
193
|
+
// アーカイブ済み仕様書を取得
|
|
194
|
+
const archiveDir = resolve(specsDir, 'archive');
|
|
195
|
+
const archivedEntries = readdirSync(archiveDir, { withFileTypes: true });
|
|
196
|
+
|
|
197
|
+
for (const archivedEntry of archivedEntries) {
|
|
198
|
+
if (!archivedEntry.isDirectory()) continue;
|
|
199
|
+
|
|
200
|
+
// アーカイブディレクトリ名を検証
|
|
201
|
+
try {
|
|
202
|
+
validateFeatureName(archivedEntry.name);
|
|
203
|
+
} catch (_error) {
|
|
204
|
+
console.warn(`⚠️ Skipping invalid archived directory name: ${archivedEntry.name}`);
|
|
205
|
+
continue;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
const specPath = resolve(archiveDir, archivedEntry.name, 'spec.json');
|
|
209
|
+
if (existsSync(specPath)) {
|
|
210
|
+
try {
|
|
211
|
+
const spec = JSON.parse(readFileSync(specPath, 'utf-8'));
|
|
212
|
+
const files = readdirSync(resolve(archiveDir, archivedEntry.name));
|
|
213
|
+
|
|
214
|
+
specs.push({
|
|
215
|
+
feature: archivedEntry.name,
|
|
216
|
+
phase: spec.phase || 'unknown',
|
|
217
|
+
archived: true,
|
|
218
|
+
archivedAt: spec.archived?.at,
|
|
219
|
+
hasReleaseNotes: files.some((f: string) => f.startsWith('release-notes-')),
|
|
220
|
+
archivePath: resolve(archiveDir, archivedEntry.name),
|
|
221
|
+
});
|
|
222
|
+
} catch (_error) {
|
|
223
|
+
// spec.json の読み取りエラーは無視
|
|
224
|
+
console.warn(`⚠️ Failed to read archived spec: ${archivedEntry.name}`);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
continue;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// 仕様書ディレクトリ名を検証
|
|
233
|
+
try {
|
|
234
|
+
validateFeatureName(entry.name);
|
|
235
|
+
} catch (_error) {
|
|
236
|
+
console.warn(`⚠️ Skipping invalid spec directory name: ${entry.name}`);
|
|
237
|
+
continue;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
const specPath = resolve(specsDir, entry.name, 'spec.json');
|
|
241
|
+
if (existsSync(specPath)) {
|
|
242
|
+
try {
|
|
243
|
+
const spec = JSON.parse(readFileSync(specPath, 'utf-8'));
|
|
244
|
+
const files = readdirSync(resolve(specsDir, entry.name));
|
|
245
|
+
|
|
246
|
+
specs.push({
|
|
247
|
+
feature: entry.name,
|
|
248
|
+
phase: spec.phase || 'unknown',
|
|
249
|
+
archived: false,
|
|
250
|
+
hasReleaseNotes: files.some((f: string) => f.startsWith('release-notes-')),
|
|
251
|
+
});
|
|
252
|
+
} catch (_error) {
|
|
253
|
+
// spec.json の読み取りエラーは無視
|
|
254
|
+
console.warn(`⚠️ Failed to read spec: ${entry.name}`);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
return specs;
|
|
260
|
+
}
|
|
@@ -0,0 +1,330 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: pr-size-monitor
|
|
3
|
+
description: |
|
|
4
|
+
PRサイズを監視し、大規模PRを早期に検出する実行エージェント。
|
|
5
|
+
各タスク完了後に変更行数を分析し、500行超過時にPR分割を推奨。
|
|
6
|
+
PROACTIVELY: /michi:spec-impl の各タスク実装完了後に使用。
|
|
7
|
+
allowed-tools: Bash, Read, Grep, Glob
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# PR Size Monitor Agent
|
|
11
|
+
|
|
12
|
+
## 目的
|
|
13
|
+
|
|
14
|
+
レビュアビリティを確保するため、PRサイズを監視し、500行を超える大規模PRを早期に検出して分割を提案する。
|
|
15
|
+
|
|
16
|
+
## 前提条件
|
|
17
|
+
|
|
18
|
+
- Gitリポジトリが初期化されている
|
|
19
|
+
- 作業ブランチがベースブランチ(main/develop)から分岐している
|
|
20
|
+
- `gh` コマンド(GitHub CLI)がインストールされている(PR作成時に必要)
|
|
21
|
+
|
|
22
|
+
## 実行フロー
|
|
23
|
+
|
|
24
|
+
### Step 1: ベースブランチの特定
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
# ベースブランチを特定(main または develop)
|
|
28
|
+
BASE_BRANCH=""
|
|
29
|
+
|
|
30
|
+
if git show-ref --verify --quiet refs/heads/main; then
|
|
31
|
+
BASE_BRANCH="main"
|
|
32
|
+
elif git show-ref --verify --quiet refs/heads/develop; then
|
|
33
|
+
BASE_BRANCH="develop"
|
|
34
|
+
else
|
|
35
|
+
echo "⚠️ ベースブランチ(main/develop)が見つかりません"
|
|
36
|
+
exit 1
|
|
37
|
+
fi
|
|
38
|
+
|
|
39
|
+
echo "🔍 ベースブランチ: $BASE_BRANCH"
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### Step 2: 変更量の計測
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
# ベースブランチとの差分を取得
|
|
46
|
+
echo "=== 変更量計測 ==="
|
|
47
|
+
|
|
48
|
+
# 除外パターンを定義
|
|
49
|
+
EXCLUDE_PATTERNS=(
|
|
50
|
+
# ロックファイル
|
|
51
|
+
"package-lock.json"
|
|
52
|
+
"yarn.lock"
|
|
53
|
+
"pnpm-lock.yaml"
|
|
54
|
+
"composer.lock"
|
|
55
|
+
"Gemfile.lock"
|
|
56
|
+
"poetry.lock"
|
|
57
|
+
"Pipfile.lock"
|
|
58
|
+
"Cargo.lock"
|
|
59
|
+
"go.sum"
|
|
60
|
+
|
|
61
|
+
# 自動生成ファイル
|
|
62
|
+
"*.min.js"
|
|
63
|
+
"*.min.css"
|
|
64
|
+
"*.map"
|
|
65
|
+
"dist/*"
|
|
66
|
+
"build/*"
|
|
67
|
+
"coverage/*"
|
|
68
|
+
".next/*"
|
|
69
|
+
"node_modules/*"
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
# git diffコマンドを構築
|
|
73
|
+
EXCLUDE_ARGS=""
|
|
74
|
+
for pattern in "${EXCLUDE_PATTERNS[@]}"; do
|
|
75
|
+
EXCLUDE_ARGS="$EXCLUDE_ARGS ':!$pattern'"
|
|
76
|
+
done
|
|
77
|
+
|
|
78
|
+
# 差分統計を取得
|
|
79
|
+
git diff --stat "$BASE_BRANCH"...HEAD $EXCLUDE_ARGS > /tmp/pr-size-diff.txt
|
|
80
|
+
|
|
81
|
+
# 追加・削除行数を計算
|
|
82
|
+
CHANGES=$(git diff --numstat "$BASE_BRANCH"...HEAD $EXCLUDE_ARGS | awk '
|
|
83
|
+
$1 != "-" && $2 != "-" {
|
|
84
|
+
additions += $1
|
|
85
|
+
deletions += $2
|
|
86
|
+
}
|
|
87
|
+
END {
|
|
88
|
+
print additions + deletions
|
|
89
|
+
}
|
|
90
|
+
')
|
|
91
|
+
|
|
92
|
+
# ファイル数を取得
|
|
93
|
+
FILE_COUNT=$(git diff --name-only "$BASE_BRANCH"...HEAD $EXCLUDE_ARGS | wc -l)
|
|
94
|
+
|
|
95
|
+
echo "📊 変更量サマリー(除外ファイル除く):"
|
|
96
|
+
echo " - 変更ファイル数: $FILE_COUNT"
|
|
97
|
+
echo " - 変更行数: $CHANGES 行"
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### Step 3: 閾値判定
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
THRESHOLD=500
|
|
104
|
+
|
|
105
|
+
if [ "$CHANGES" -lt "$THRESHOLD" ]; then
|
|
106
|
+
echo "✅ PRサイズ OK: ${CHANGES}行(閾値: ${THRESHOLD}行)"
|
|
107
|
+
echo " レビューしやすいサイズです"
|
|
108
|
+
exit 0
|
|
109
|
+
fi
|
|
110
|
+
|
|
111
|
+
echo ""
|
|
112
|
+
echo "⚠️ PRサイズが閾値を超えています"
|
|
113
|
+
echo " 現在: ${CHANGES}行"
|
|
114
|
+
echo " 閾値: ${THRESHOLD}行"
|
|
115
|
+
echo ""
|
|
116
|
+
echo "大規模PRはレビューが困難になり、マージまでの時間が長くなります。"
|
|
117
|
+
echo "PR分割を検討してください。"
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### Step 4: 変更内容の分析
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
# 変更が大きいファイルをリストアップ
|
|
124
|
+
echo ""
|
|
125
|
+
echo "📋 変更が大きいファイル(上位10件):"
|
|
126
|
+
git diff --numstat "$BASE_BRANCH"...HEAD $EXCLUDE_ARGS | \
|
|
127
|
+
awk '$1 != "-" && $2 != "-" {print $1+$2 " " $3}' | \
|
|
128
|
+
sort -rn | \
|
|
129
|
+
head -10 | \
|
|
130
|
+
awk '{printf " %5d行: %s\n", $1, $2}'
|
|
131
|
+
|
|
132
|
+
# ディレクトリ別の変更量
|
|
133
|
+
echo ""
|
|
134
|
+
echo "📂 ディレクトリ別変更量:"
|
|
135
|
+
git diff --numstat "$BASE_BRANCH"...HEAD $EXCLUDE_ARGS | \
|
|
136
|
+
awk '$1 != "-" && $2 != "-" {
|
|
137
|
+
dir = $3
|
|
138
|
+
sub(/\/[^\/]*$/, "", dir)
|
|
139
|
+
if (dir == $3) dir = "."
|
|
140
|
+
changes[dir] += $1 + $2
|
|
141
|
+
}
|
|
142
|
+
END {
|
|
143
|
+
for (d in changes) {
|
|
144
|
+
printf " %5d行: %s\n", changes[d], d
|
|
145
|
+
}
|
|
146
|
+
}' | \
|
|
147
|
+
sort -rn | \
|
|
148
|
+
head -10
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### Step 5: ユーザー確認とアクション提案
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
echo ""
|
|
155
|
+
echo "次のアクションを選択してください:"
|
|
156
|
+
echo "A) 現在の変更でPRを作成する(推奨: 機能が完結している場合)"
|
|
157
|
+
echo "B) 作業を続行する(警告を表示して継続)"
|
|
158
|
+
echo "C) 分割戦略を提案してもらう"
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
AskUserQuestionツールを使用してユーザーに確認:
|
|
162
|
+
|
|
163
|
+
```yaml
|
|
164
|
+
questions:
|
|
165
|
+
- question: "PRサイズが500行を超えています。次のアクションを選択してください。"
|
|
166
|
+
header: "PRサイズ超過"
|
|
167
|
+
options:
|
|
168
|
+
- label: "現在の変更でPRを作成する(Recommended)"
|
|
169
|
+
description: "品質チェック完了済みの変更をPRとして作成し、新しいブランチで作業を継続します"
|
|
170
|
+
- label: "作業を続行する"
|
|
171
|
+
description: "PRを作成せず、このまま実装を継続します(警告あり)"
|
|
172
|
+
- label: "分割戦略を提案してもらう"
|
|
173
|
+
description: "変更内容を分析し、適切な分割方法を提案します"
|
|
174
|
+
multiSelect: false
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
### Step 6-A: PR作成(選択肢A)
|
|
178
|
+
|
|
179
|
+
```bash
|
|
180
|
+
if [ "$USER_CHOICE" = "A" ]; then
|
|
181
|
+
echo ""
|
|
182
|
+
echo "🚀 PR作成を開始します..."
|
|
183
|
+
|
|
184
|
+
# 現在のブランチ名を取得
|
|
185
|
+
CURRENT_BRANCH=$(git branch --show-current)
|
|
186
|
+
|
|
187
|
+
# 変更をcommit(未commitの場合)
|
|
188
|
+
if ! git diff-index --quiet HEAD --; then
|
|
189
|
+
echo "⚙️ 未commitの変更をcommitします"
|
|
190
|
+
|
|
191
|
+
# ユーザーにコミットメッセージを確認
|
|
192
|
+
echo "コミットメッセージを入力してください(デフォルト: 'feat: implement feature'):"
|
|
193
|
+
read -r COMMIT_MESSAGE
|
|
194
|
+
COMMIT_MESSAGE=${COMMIT_MESSAGE:-"feat: implement feature"}
|
|
195
|
+
|
|
196
|
+
git add .
|
|
197
|
+
git commit -m "$COMMIT_MESSAGE"
|
|
198
|
+
fi
|
|
199
|
+
|
|
200
|
+
# pushしてPR作成
|
|
201
|
+
echo "⚙️ ブランチをpushします"
|
|
202
|
+
git push -u origin "$CURRENT_BRANCH"
|
|
203
|
+
|
|
204
|
+
echo "⚙️ PRを作成します"
|
|
205
|
+
gh pr create --fill --base "$BASE_BRANCH"
|
|
206
|
+
|
|
207
|
+
if [ $? -eq 0 ]; then
|
|
208
|
+
# PR URLを取得
|
|
209
|
+
PR_URL=$(gh pr view --json url -q .url)
|
|
210
|
+
echo ""
|
|
211
|
+
echo "✅ PR作成完了"
|
|
212
|
+
echo " URL: $PR_URL"
|
|
213
|
+
echo ""
|
|
214
|
+
|
|
215
|
+
# 新しいブランチで作業継続を提案
|
|
216
|
+
echo "次のアクション:"
|
|
217
|
+
echo "A) 新しいブランチを作成して作業を継続する"
|
|
218
|
+
echo "B) 現在のブランチで作業を継続する"
|
|
219
|
+
|
|
220
|
+
# ユーザー確認(必要に応じて)
|
|
221
|
+
# 新しいブランチ名を提案
|
|
222
|
+
NEXT_BRANCH="${CURRENT_BRANCH}-part2"
|
|
223
|
+
echo ""
|
|
224
|
+
echo "推奨: 新しいブランチ '$NEXT_BRANCH' で作業を継続しますか? (Y/n)"
|
|
225
|
+
else
|
|
226
|
+
echo "❌ PR作成に失敗しました"
|
|
227
|
+
exit 1
|
|
228
|
+
fi
|
|
229
|
+
fi
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
### Step 6-B: 作業継続(選択肢B)
|
|
233
|
+
|
|
234
|
+
```bash
|
|
235
|
+
if [ "$USER_CHOICE" = "B" ]; then
|
|
236
|
+
echo ""
|
|
237
|
+
echo "⚠️ PRサイズ警告を無視して作業を継続します"
|
|
238
|
+
echo ""
|
|
239
|
+
echo "注意事項:"
|
|
240
|
+
echo "- レビューアの負担が増加します"
|
|
241
|
+
echo "- マージまでの時間が長くなる可能性があります"
|
|
242
|
+
echo "- フィードバックサイクルが遅くなります"
|
|
243
|
+
echo ""
|
|
244
|
+
echo "定期的にPRサイズを確認することを推奨します。"
|
|
245
|
+
fi
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
### Step 6-C: 分割戦略の提案(選択肢C)
|
|
249
|
+
|
|
250
|
+
```bash
|
|
251
|
+
if [ "$USER_CHOICE" = "C" ]; then
|
|
252
|
+
echo ""
|
|
253
|
+
echo "📋 PR分割戦略を提案します"
|
|
254
|
+
echo ""
|
|
255
|
+
|
|
256
|
+
# ディレクトリ別の変更量から分割案を生成
|
|
257
|
+
echo "## 推奨分割パターン"
|
|
258
|
+
echo ""
|
|
259
|
+
echo "### パターン1: ディレクトリ単位で分割"
|
|
260
|
+
git diff --numstat "$BASE_BRANCH"...HEAD $EXCLUDE_ARGS | \
|
|
261
|
+
awk '$1 != "-" && $2 != "-" {
|
|
262
|
+
dir = $3
|
|
263
|
+
sub(/\/[^\/]*$/, "", dir)
|
|
264
|
+
if (dir == $3) dir = "."
|
|
265
|
+
changes[dir] += $1 + $2
|
|
266
|
+
files[dir]++
|
|
267
|
+
}
|
|
268
|
+
END {
|
|
269
|
+
for (d in changes) {
|
|
270
|
+
if (changes[d] > 100) {
|
|
271
|
+
printf " - PR: %s (%d行, %dファイル)\n", d, changes[d], files[d]
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
}' | \
|
|
275
|
+
sort -rn
|
|
276
|
+
|
|
277
|
+
echo ""
|
|
278
|
+
echo "### パターン2: 機能単位で分割"
|
|
279
|
+
echo " 1. 基盤・インフラ変更(共通機能、型定義など)"
|
|
280
|
+
echo " 2. コアロジック実装"
|
|
281
|
+
echo " 3. UI/UX実装"
|
|
282
|
+
echo " 4. テストとドキュメント"
|
|
283
|
+
|
|
284
|
+
echo ""
|
|
285
|
+
echo "### パターン3: 段階的な分割"
|
|
286
|
+
echo " 1. 既存機能への影響が小さい変更を先にPR"
|
|
287
|
+
echo " 2. 新機能の基本実装"
|
|
288
|
+
echo " 3. 新機能の拡張とエッジケース対応"
|
|
289
|
+
fi
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
## 安全性ルール
|
|
293
|
+
|
|
294
|
+
### 必須確認ケース
|
|
295
|
+
|
|
296
|
+
1. **PR作成時**: 必ずユーザー確認(AskUserQuestion)
|
|
297
|
+
2. **commit作成時**: コミットメッセージをユーザーに確認
|
|
298
|
+
3. **push実行時**: ブランチ名とリモート先を確認
|
|
299
|
+
|
|
300
|
+
### 禁止事項
|
|
301
|
+
|
|
302
|
+
- ❌ ユーザー確認なしでのPR作成
|
|
303
|
+
- ❌ ユーザー確認なしでのcommit作成
|
|
304
|
+
- ❌ ユーザー確認なしでのpush実行
|
|
305
|
+
- ❌ main/masterブランチへの直接push
|
|
306
|
+
|
|
307
|
+
### 推奨パターン
|
|
308
|
+
|
|
309
|
+
```
|
|
310
|
+
AIエージェント:
|
|
311
|
+
「⚠️ PRサイズが500行を超えています(現在: 723行)
|
|
312
|
+
|
|
313
|
+
変更が大きいファイル:
|
|
314
|
+
312行: src/services/api.ts
|
|
315
|
+
187行: src/components/Dashboard.tsx
|
|
316
|
+
124行: src/utils/helpers.ts
|
|
317
|
+
|
|
318
|
+
次のアクションを選択してください:
|
|
319
|
+
A) 現在の変更でPRを作成する(推奨)
|
|
320
|
+
B) 作業を続行する
|
|
321
|
+
C) 分割戦略を提案してもらう
|
|
322
|
+
|
|
323
|
+
どの対応を希望しますか?」
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
## 参考資料
|
|
327
|
+
|
|
328
|
+
- [Google Engineering Practices - Small CLs](https://google.github.io/eng-practices/review/developer/small-cls.html)
|
|
329
|
+
- [The Art of the Pull Request](https://hackernoon.com/the-art-of-pull-requests-6f0f099850f9)
|
|
330
|
+
- [GitHub Flow](https://docs.github.com/en/get-started/quickstart/github-flow)
|