aiwf 0.3.6 → 0.3.8
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/.aiwf/00_PROJECT_MANIFEST.md +226 -2
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/S03_M02_sprint_meta.md +112 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/T01_S03_new_test_task.md +39 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/T02_S03_first_task.md +39 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/T03_S03_test_task.md +39 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/T04_S03_task_with_special_characters.md +39 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/T05_S03_test.md +39 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/T06_S03_test_task.md +39 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/T07_S03_next_task.md +39 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/T08_S03_next_task.md +39 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/T09_S03_new_test_task.md +39 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/T100_S03_task_with_special_characters.md +39 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/T101_S03_test.md +39 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/T102_S03_test_task.md +39 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/T103_S03_next_task.md +39 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/T104_S03_next_task.md +39 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/T105_S03_new_test_task.md +39 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/T106_S03_first_task.md +39 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/T107_S03_test_task.md +39 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/T108_S03_task_with_special_characters.md +39 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/T109_S03_test.md +39 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/T10_S03_first_task.md +39 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/T110_S03_test_task.md +39 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/T111_S03_next_task.md +39 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/T112_S03_next_task.md +39 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/T11_S03_test_task.md +39 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/T12_S03_task_with_special_characters.md +39 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/T13_S03_test.md +39 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/T14_S03_test_task.md +39 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/T15_S03_next_task.md +39 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/T16_S03_next_task.md +39 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/T17_S03_new_test_task.md +39 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/T18_S03_first_task.md +39 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/T19_S03_test_task.md +39 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/T20_S03_task_with_special_characters.md +39 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/T21_S03_test.md +39 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/T22_S03_test_task.md +39 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/T23_S03_next_task.md +39 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/T24_S03_next_task.md +39 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/T25_S03_new_test_task.md +39 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/T26_S03_first_task.md +39 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/T27_S03_test_task.md +39 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/T28_S03_task_with_special_characters.md +39 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/T29_S03_test.md +39 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/T30_S03_test_task.md +39 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/T31_S03_next_task.md +39 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/T32_S03_next_task.md +39 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/T33_S03_new_test_task.md +39 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/T34_S03_first_task.md +39 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/T35_S03_test_task.md +39 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/T36_S03_task_with_special_characters.md +39 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/T37_S03_test.md +39 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/T38_S03_test_task.md +39 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/T39_S03_next_task.md +39 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/T40_S03_next_task.md +39 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/T41_S03_new_test_task.md +39 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/T42_S03_first_task.md +39 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/T43_S03_test_task.md +39 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/T44_S03_task_with_special_characters.md +39 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/T45_S03_test.md +39 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/T46_S03_test_task.md +39 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/T47_S03_next_task.md +39 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/T48_S03_next_task.md +39 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/T49_S03_new_test_task.md +39 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/T50_S03_first_task.md +39 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/T51_S03_test_task.md +39 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/T52_S03_task_with_special_characters.md +39 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/T53_S03_test.md +39 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/T54_S03_test_task.md +39 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/T55_S03_next_task.md +39 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/T56_S03_next_task.md +39 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/T57_S03_new_test_task.md +39 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/T58_S03_first_task.md +39 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/T59_S03_test_task.md +39 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/T60_S03_task_with_special_characters.md +39 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/T61_S03_test.md +39 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/T62_S03_test_task.md +39 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/T63_S03_next_task.md +39 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/T64_S03_next_task.md +39 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/T65_S03_new_test_task.md +39 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/T66_S03_first_task.md +39 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/T67_S03_test_task.md +39 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/T68_S03_task_with_special_characters.md +39 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/T69_S03_test.md +39 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/T70_S03_test_task.md +39 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/T71_S03_next_task.md +39 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/T72_S03_next_task.md +39 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/T73_S03_new_test_task.md +39 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/T74_S03_first_task.md +39 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/T75_S03_test_task.md +39 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/T76_S03_task_with_special_characters.md +39 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/T77_S03_test.md +39 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/T78_S03_test_task.md +39 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/T79_S03_next_task.md +39 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/T80_S03_next_task.md +39 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/T81_S03_new_test_task.md +39 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/T82_S03_first_task.md +39 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/T83_S03_test_task.md +39 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/T84_S03_task_with_special_characters.md +39 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/T85_S03_test.md +39 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/T86_S03_test_task.md +39 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/T87_S03_next_task.md +39 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/T88_S03_next_task.md +39 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/T89_S03_new_test_task.md +39 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/T90_S03_first_task.md +39 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/T91_S03_test_task.md +39 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/T92_S03_task_with_special_characters.md +39 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/T93_S03_test.md +39 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/T94_S03_test_task.md +39 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/T95_S03_next_task.md +39 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/T96_S03_next_task.md +39 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/T97_S03_new_test_task.md +39 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/T98_S03_first_task.md +39 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/T99_S03_test_task.md +39 -0
- package/.aiwf/test-results-s02.json +5 -5
- package/.claude/commands/aiwf/aiwf_compress_aggressive_persona.md +3 -15
- package/.claude/commands/aiwf/aiwf_compress_minimal_persona.md +2 -15
- package/.claude/commands/aiwf/aiwf_compress_stats.md +2 -51
- package/.claude/commands/aiwf/aiwf_compress_with_persona.md +5 -18
- package/.claude/commands/aiwf/aiwf_create_feature_ledger.md +1 -1
- package/.claude/commands/aiwf/aiwf_default_mode.md +1 -1
- package/.claude/commands/aiwf/aiwf_evaluate.md +3 -16
- package/.claude/commands/aiwf/aiwf_get_feature_details.md +1 -1
- package/.claude/commands/aiwf/aiwf_link_feature_to_milestone.md +1 -1
- package/.claude/commands/aiwf/aiwf_list_features.md +1 -1
- package/.claude/commands/aiwf/aiwf_switch_language.md +48 -120
- package/.claude/commands/aiwf/aiwf_update_feature_status.md +1 -1
- package/claude-code/aiwf/en/.claude/commands/aiwf/aiwf_create_testcase.md +561 -0
- package/claude-code/aiwf/ko/.claude/commands/aiwf/aiwf_compress_aggressive_persona.md +2 -2
- package/claude-code/aiwf/ko/.claude/commands/aiwf/aiwf_compress_minimal_persona.md +2 -2
- package/claude-code/aiwf/ko/.claude/commands/aiwf/aiwf_compress_stats.md +10 -47
- package/claude-code/aiwf/ko/.claude/commands/aiwf/aiwf_compress_with_persona.md +2 -2
- package/claude-code/aiwf/ko/.claude/commands/aiwf/aiwf_create_feature_ledger.md +1 -1
- package/claude-code/aiwf/ko/.claude/commands/aiwf/aiwf_create_testcase.md +561 -0
- package/claude-code/aiwf/ko/.claude/commands/aiwf/aiwf_default_mode.md +1 -1
- package/claude-code/aiwf/ko/.claude/commands/aiwf/aiwf_evaluate.md +2 -2
- package/claude-code/aiwf/ko/.claude/commands/aiwf/aiwf_get_feature_details.md +1 -1
- package/claude-code/aiwf/ko/.claude/commands/aiwf/aiwf_link_feature_to_milestone.md +1 -1
- package/claude-code/aiwf/ko/.claude/commands/aiwf/aiwf_list_features.md +1 -1
- package/claude-code/aiwf/ko/.claude/commands/aiwf/aiwf_persona_architect.md +1 -1
- package/claude-code/aiwf/ko/.claude/commands/aiwf/aiwf_persona_backend.md +1 -1
- package/claude-code/aiwf/ko/.claude/commands/aiwf/aiwf_persona_data_analyst.md +1 -1
- package/claude-code/aiwf/ko/.claude/commands/aiwf/aiwf_persona_frontend.md +1 -1
- package/claude-code/aiwf/ko/.claude/commands/aiwf/aiwf_persona_security.md +1 -1
- package/claude-code/aiwf/ko/.claude/commands/aiwf/aiwf_persona_status.md +1 -1
- package/claude-code/aiwf/ko/.claude/commands/aiwf/aiwf_update_feature_status.md +1 -1
- package/package.json +1 -1
- package/src/cli/index.js +174 -0
- package/src/commands/compress.js +60 -0
- package/src/commands/create-project.js +23 -17
- package/src/commands/evaluate.js +459 -0
- package/src/commands/feature.js +365 -0
- package/src/commands/persona.js +37 -16
- package/src/commands/token.js +312 -0
- package/src/lib/file-downloader.js +189 -33
- package/src/lib/installer.js +38 -11
- package/src/lib/resource-loader.js +250 -0
- package/src/lib/resources/commands/ai-persona.js +602 -0
- package/src/lib/resources/commands/compress-context.js +389 -0
- package/src/lib/resources/commands/evaluate.js +246 -0
- package/src/lib/resources/commands/feature-ledger.js +565 -0
- package/src/lib/resources/commands/feature_commit_report.js +370 -0
- package/src/lib/resources/commands/persona-context-apply.js +562 -0
- package/src/lib/resources/commands/scan_git_history.js +234 -0
- package/src/lib/resources/commands/sync_feature_commits.js +154 -0
- package/src/lib/resources/commands/token-tracking.js +443 -0
- package/src/lib/resources/config/commit-patterns.js +103 -0
- package/src/lib/resources/config/language.json +6 -0
- package/src/lib/resources/personas/PERSONA_INDEX.md +57 -0
- package/src/lib/resources/personas/analyst.json +44 -0
- package/src/lib/resources/personas/architect/best_practices.md +136 -0
- package/src/lib/resources/personas/architect/knowledge_base.md +377 -0
- package/src/lib/resources/personas/architect.json +44 -0
- package/src/lib/resources/personas/backend/best_practices.md +766 -0
- package/src/lib/resources/personas/backend/knowledge_base.md +1070 -0
- package/src/lib/resources/personas/data_analyst/best_practices.md +594 -0
- package/src/lib/resources/personas/data_analyst/knowledge_base.md +1057 -0
- package/src/lib/resources/personas/developer.json +44 -0
- package/src/lib/resources/personas/developer.md +37 -0
- package/src/lib/resources/personas/evaluation_criteria.json +137 -0
- package/src/lib/resources/personas/frontend/best_practices.md +445 -0
- package/src/lib/resources/personas/frontend/knowledge_base.md +729 -0
- package/src/lib/resources/personas/persona-index.json +31 -0
- package/src/lib/resources/personas/reviewer.json +44 -0
- package/src/lib/resources/personas/security/best_practices.md +307 -0
- package/src/lib/resources/personas/security/knowledge_base.md +498 -0
- package/src/lib/resources/personas/tester.json +44 -0
- package/src/lib/resources/templates/README.md +78 -0
- package/src/lib/resources/templates/api-server/config.json +64 -0
- package/src/lib/resources/templates/api-server/template/.aiwf/config.json +56 -0
- package/src/lib/resources/templates/api-server/template/.aiwf/feature-ledger.json +42 -0
- package/src/lib/resources/templates/api-server/template/.aiwf/personas/backend-engineer.json +40 -0
- package/src/lib/resources/templates/api-server/template/.aiwf/scripts/cli.js +111 -0
- package/src/lib/resources/templates/api-server/template/.env.example +29 -0
- package/src/lib/resources/templates/api-server/template/.eslintrc.json +23 -0
- package/src/lib/resources/templates/api-server/template/README.md +171 -0
- package/src/lib/resources/templates/api-server/template/jest.config.js +26 -0
- package/src/lib/resources/templates/api-server/template/nodemon.json +9 -0
- package/src/lib/resources/templates/api-server/template/package.json +61 -0
- package/src/lib/resources/templates/api-server/template/src/app.ts +60 -0
- package/src/lib/resources/templates/api-server/template/src/config/swagger.ts +38 -0
- package/src/lib/resources/templates/api-server/template/src/controllers/aiwfController.ts +68 -0
- package/src/lib/resources/templates/api-server/template/src/controllers/authController.ts +128 -0
- package/src/lib/resources/templates/api-server/template/src/controllers/statusController.ts +28 -0
- package/src/lib/resources/templates/api-server/template/src/index.ts +28 -0
- package/src/lib/resources/templates/api-server/template/src/middleware/aiwfMiddleware.ts +50 -0
- package/src/lib/resources/templates/api-server/template/src/middleware/authMiddleware.ts +41 -0
- package/src/lib/resources/templates/api-server/template/src/middleware/errorHandler.ts +42 -0
- package/src/lib/resources/templates/api-server/template/src/middleware/notFoundHandler.ts +14 -0
- package/src/lib/resources/templates/api-server/template/src/middleware/requestLogger.ts +20 -0
- package/src/lib/resources/templates/api-server/template/src/routes/aiwf.ts +42 -0
- package/src/lib/resources/templates/api-server/template/src/routes/index.ts +13 -0
- package/src/lib/resources/templates/api-server/template/src/routes/v1/index.ts +67 -0
- package/src/lib/resources/templates/api-server/template/src/utils/logger.ts +37 -0
- package/src/lib/resources/templates/api-server/template/tests/app.test.ts +40 -0
- package/src/lib/resources/templates/api-server/template/tsconfig.json +43 -0
- package/src/lib/resources/templates/npm-library/config.json +61 -0
- package/src/lib/resources/templates/npm-library/template/LICENSE +21 -0
- package/src/lib/resources/templates/npm-library/template/README.md +201 -0
- package/src/lib/resources/templates/npm-library/template/package.json +78 -0
- package/src/lib/resources/templates/web-app/config.json +53 -0
- package/src/lib/resources/templates/web-app/template/.aiwf/config.json +54 -0
- package/src/lib/resources/templates/web-app/template/.aiwf/feature-ledger.json +37 -0
- package/src/lib/resources/templates/web-app/template/.aiwf/personas/fullstack-developer.json +40 -0
- package/src/lib/resources/templates/web-app/template/.aiwf/scripts/cli.js +110 -0
- package/src/lib/resources/templates/web-app/template/.eslintrc.cjs +20 -0
- package/src/lib/resources/templates/web-app/template/README.md +151 -0
- package/src/lib/resources/templates/web-app/template/index.html +14 -0
- package/src/lib/resources/templates/web-app/template/package.json +44 -0
- package/src/lib/resources/templates/web-app/template/postcss.config.js +6 -0
- package/src/lib/resources/templates/web-app/template/public/vite.svg +1 -0
- package/src/lib/resources/templates/web-app/template/src/App.tsx +21 -0
- package/src/lib/resources/templates/web-app/template/src/components/Layout.tsx +57 -0
- package/src/lib/resources/templates/web-app/template/src/components/aiwf/ContextStatus.tsx +107 -0
- package/src/lib/resources/templates/web-app/template/src/components/aiwf/FeatureLedger.tsx +93 -0
- package/src/lib/resources/templates/web-app/template/src/components/aiwf/TokenUsage.tsx +71 -0
- package/src/lib/resources/templates/web-app/template/src/index.css +60 -0
- package/src/lib/resources/templates/web-app/template/src/main.tsx +10 -0
- package/src/lib/resources/templates/web-app/template/src/pages/AiwfDashboard.tsx +60 -0
- package/src/lib/resources/templates/web-app/template/src/pages/HomePage.tsx +89 -0
- package/src/lib/resources/templates/web-app/template/src/pages/NotFound.tsx +25 -0
- package/src/lib/resources/templates/web-app/template/src/stores/aiwfStore.ts +126 -0
- package/src/lib/resources/templates/web-app/template/src/types/global.d.ts +9 -0
- package/src/lib/resources/templates/web-app/template/src/vite-env.d.ts +1 -0
- package/src/lib/resources/templates/web-app/template/tailwind.config.js +30 -0
- package/src/lib/resources/templates/web-app/template/tsconfig.json +37 -0
- package/src/lib/resources/templates/web-app/template/tsconfig.node.json +10 -0
- package/src/lib/resources/templates/web-app/template/vite.config.ts +23 -0
- package/src/lib/resources/utils/background-monitor.js +223 -0
- package/src/lib/resources/utils/compression-metrics.js +1031 -0
- package/src/lib/resources/utils/compression-strategies.js +557 -0
- package/src/lib/resources/utils/content-normalizer.js +455 -0
- package/src/lib/resources/utils/context-compressor.js +583 -0
- package/src/lib/resources/utils/context-rule-parser.js +180 -0
- package/src/lib/resources/utils/context-token-monitor.js +463 -0
- package/src/lib/resources/utils/context-update-manager.js +502 -0
- package/src/lib/resources/utils/feature-updater.js +271 -0
- package/src/lib/resources/utils/git-utils.js +220 -0
- package/src/lib/resources/utils/importance-classifier.js +645 -0
- package/src/lib/resources/utils/information-filter.js +710 -0
- package/src/lib/resources/utils/persona-aware-compressor.js +598 -0
- package/src/lib/resources/utils/prompt-injector.js +242 -0
- package/src/lib/resources/utils/simplified-evaluator.js +119 -0
- package/src/lib/resources/utils/text-summarizer.js +492 -0
- package/src/lib/resources/utils/token-counter.js +177 -0
- package/src/lib/resources/utils/token-monitor.js +484 -0
- package/src/lib/resources/utils/token-reporter.js +453 -0
- package/src/lib/resources/utils/token-storage.js +433 -0
- package/src/lib/resources/utils/token-tracker.js +283 -0
- package/claude-code/aiwf/ko/.claude/commands/aiwf/aiwf_switch_language.md +0 -160
- /package/claude-code/aiwf/ko/.claude/commands/aiwf/{aiwf_update_docs_kr.md → aiwf_update_docs.md} +0 -0
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
const fs = require('fs').promises;
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const yaml = require('yaml');
|
|
4
|
+
const { getCommitsByFeatureId } = require('./git-utils');
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Feature Ledger 파일 업데이트 메커니즘
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Feature 파일 경로 구성
|
|
12
|
+
* @param {string} featureId - Feature ID (예: 'FL001')
|
|
13
|
+
* @param {string} status - Feature 상태 (active, completed, archived)
|
|
14
|
+
* @returns {string} - Feature 파일 경로
|
|
15
|
+
*/
|
|
16
|
+
function getFeatureFilePath(featureId, status = 'active') {
|
|
17
|
+
const basePath = path.join(process.cwd(), '.aiwf', '06_FEATURE_LEDGERS');
|
|
18
|
+
const fileName = `${featureId}_*.md`;
|
|
19
|
+
return path.join(basePath, status, fileName);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Feature 파일 찾기
|
|
24
|
+
* @param {string} featureId - Feature ID
|
|
25
|
+
* @returns {Promise<{path: string, status: string}|null>} - 파일 경로와 상태
|
|
26
|
+
*/
|
|
27
|
+
async function findFeatureFile(featureId) {
|
|
28
|
+
const basePath = path.join(process.cwd(), '.aiwf', '06_FEATURE_LEDGERS');
|
|
29
|
+
const statuses = ['active', 'completed', 'archived'];
|
|
30
|
+
|
|
31
|
+
for (const status of statuses) {
|
|
32
|
+
const dirPath = path.join(basePath, status);
|
|
33
|
+
try {
|
|
34
|
+
const files = await fs.readdir(dirPath);
|
|
35
|
+
const featureFile = files.find(file => file.startsWith(`${featureId}_`));
|
|
36
|
+
if (featureFile) {
|
|
37
|
+
return {
|
|
38
|
+
path: path.join(dirPath, featureFile),
|
|
39
|
+
status: status
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
} catch (error) {
|
|
43
|
+
// 디렉토리가 없을 수 있음
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Feature 파일 읽기
|
|
53
|
+
* @param {string} filePath - 파일 경로
|
|
54
|
+
* @returns {Promise<{frontmatter: Object, content: string}>}
|
|
55
|
+
*/
|
|
56
|
+
async function readFeatureFile(filePath) {
|
|
57
|
+
const fileContent = await fs.readFile(filePath, 'utf8');
|
|
58
|
+
const lines = fileContent.split('\n');
|
|
59
|
+
|
|
60
|
+
// Frontmatter 파싱
|
|
61
|
+
let frontmatterEnd = -1;
|
|
62
|
+
let inFrontmatter = false;
|
|
63
|
+
for (let i = 0; i < lines.length; i++) {
|
|
64
|
+
if (lines[i] === '---') {
|
|
65
|
+
if (!inFrontmatter) {
|
|
66
|
+
inFrontmatter = true;
|
|
67
|
+
} else {
|
|
68
|
+
frontmatterEnd = i;
|
|
69
|
+
break;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const frontmatterText = lines.slice(1, frontmatterEnd).join('\n');
|
|
75
|
+
const frontmatter = yaml.parse(frontmatterText);
|
|
76
|
+
const content = lines.slice(frontmatterEnd + 1).join('\n');
|
|
77
|
+
|
|
78
|
+
return { frontmatter, content };
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Feature 파일 작성
|
|
83
|
+
* @param {string} filePath - 파일 경로
|
|
84
|
+
* @param {Object} frontmatter - Frontmatter 데이터
|
|
85
|
+
* @param {string} content - 파일 내용
|
|
86
|
+
*/
|
|
87
|
+
async function writeFeatureFile(filePath, frontmatter, content) {
|
|
88
|
+
const frontmatterText = yaml.stringify(frontmatter);
|
|
89
|
+
const fileContent = `---\n${frontmatterText}---\n${content}`;
|
|
90
|
+
|
|
91
|
+
// 백업 생성
|
|
92
|
+
try {
|
|
93
|
+
const backupPath = `${filePath}.backup`;
|
|
94
|
+
await fs.copyFile(filePath, backupPath);
|
|
95
|
+
} catch (error) {
|
|
96
|
+
// 백업 실패는 무시
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
await fs.writeFile(filePath, fileContent, 'utf8');
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Git 커밋 정보를 Feature 파일에 추가
|
|
104
|
+
* @param {string} featureId - Feature ID
|
|
105
|
+
* @param {Array<Object>} commits - 커밋 정보 배열
|
|
106
|
+
* @returns {Promise<boolean>} - 성공 여부
|
|
107
|
+
*/
|
|
108
|
+
async function updateFeatureWithCommits(featureId, commits) {
|
|
109
|
+
try {
|
|
110
|
+
const featureFile = await findFeatureFile(featureId);
|
|
111
|
+
if (!featureFile) {
|
|
112
|
+
console.error(`Feature file not found for ${featureId}`);
|
|
113
|
+
return false;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const { frontmatter, content } = await readFeatureFile(featureFile.path);
|
|
117
|
+
|
|
118
|
+
// Frontmatter 업데이트
|
|
119
|
+
if (!frontmatter.git_commits) {
|
|
120
|
+
frontmatter.git_commits = [];
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// 커밋 객체로 저장 (사양에 맞게)
|
|
124
|
+
const existingHashes = new Set(frontmatter.git_commits.map(c =>
|
|
125
|
+
typeof c === 'string' ? c : c.hash
|
|
126
|
+
));
|
|
127
|
+
|
|
128
|
+
commits.forEach(commit => {
|
|
129
|
+
if (!existingHashes.has(commit.hash)) {
|
|
130
|
+
// 사양에 정의된 구조로 커밋 정보 저장
|
|
131
|
+
frontmatter.git_commits.push({
|
|
132
|
+
hash: commit.hash,
|
|
133
|
+
message: commit.message,
|
|
134
|
+
author: commit.author,
|
|
135
|
+
date: commit.date,
|
|
136
|
+
files_changed: 0, // 추후 git 명령어로 업데이트 가능
|
|
137
|
+
insertions: 0, // 추후 git 명령어로 업데이트 가능
|
|
138
|
+
deletions: 0 // 추후 git 명령어로 업데이트 가능
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
// 마지막 업데이트 시간 갱신
|
|
144
|
+
frontmatter.last_updated = new Date().toISOString().replace('T', ' ').substring(0, 16);
|
|
145
|
+
|
|
146
|
+
// Git History 섹션 업데이트
|
|
147
|
+
let updatedContent = content;
|
|
148
|
+
const gitHistorySection = '## Git History';
|
|
149
|
+
const gitHistoryIndex = content.indexOf(gitHistorySection);
|
|
150
|
+
|
|
151
|
+
if (gitHistoryIndex === -1) {
|
|
152
|
+
// Git History 섹션이 없으면 추가
|
|
153
|
+
updatedContent += '\n\n## Git History\n### Commits\n';
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// 커밋 정보 추가
|
|
157
|
+
const commitLines = commits.map(commit => {
|
|
158
|
+
const date = new Date(commit.date).toISOString().substring(0, 10);
|
|
159
|
+
return `- \`${commit.hash.substring(0, 7)}\`: ${commit.message.split('\n')[0]} [${date}]`;
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
if (gitHistoryIndex !== -1) {
|
|
163
|
+
// 기존 섹션에 추가
|
|
164
|
+
const sections = updatedContent.split('##');
|
|
165
|
+
const gitHistorySectionIndex = sections.findIndex(s => s.trim().startsWith('Git History'));
|
|
166
|
+
|
|
167
|
+
if (gitHistorySectionIndex !== -1) {
|
|
168
|
+
const commitsSectionIndex = sections[gitHistorySectionIndex].indexOf('### Commits');
|
|
169
|
+
if (commitsSectionIndex !== -1) {
|
|
170
|
+
sections[gitHistorySectionIndex] += '\n' + commitLines.join('\n');
|
|
171
|
+
}
|
|
172
|
+
updatedContent = sections.join('##');
|
|
173
|
+
}
|
|
174
|
+
} else {
|
|
175
|
+
updatedContent += commitLines.join('\n');
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
await writeFeatureFile(featureFile.path, frontmatter, updatedContent);
|
|
179
|
+
return true;
|
|
180
|
+
} catch (error) {
|
|
181
|
+
console.error(`Error updating feature ${featureId}:`, error);
|
|
182
|
+
return false;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Feature와 Git 커밋 동기화
|
|
188
|
+
* @param {string} featureId - Feature ID
|
|
189
|
+
* @returns {Promise<{success: boolean, commitCount: number}>}
|
|
190
|
+
*/
|
|
191
|
+
async function syncFeatureWithGit(featureId) {
|
|
192
|
+
try {
|
|
193
|
+
const commits = await getCommitsByFeatureId(featureId);
|
|
194
|
+
|
|
195
|
+
if (commits.length === 0) {
|
|
196
|
+
return { success: true, commitCount: 0 };
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
const success = await updateFeatureWithCommits(featureId, commits);
|
|
200
|
+
return { success, commitCount: commits.length };
|
|
201
|
+
} catch (error) {
|
|
202
|
+
console.error(`Error syncing feature ${featureId}:`, error);
|
|
203
|
+
return { success: false, commitCount: 0 };
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* 모든 활성 Feature를 Git과 동기화
|
|
209
|
+
* @returns {Promise<{total: number, synced: number, failed: number}>}
|
|
210
|
+
*/
|
|
211
|
+
async function syncAllActiveFeatures() {
|
|
212
|
+
const basePath = path.join(process.cwd(), '.aiwf', '06_FEATURE_LEDGERS', 'active');
|
|
213
|
+
const results = { total: 0, synced: 0, failed: 0 };
|
|
214
|
+
|
|
215
|
+
try {
|
|
216
|
+
const files = await fs.readdir(basePath);
|
|
217
|
+
const featureFiles = files.filter(f => f.endsWith('.md'));
|
|
218
|
+
results.total = featureFiles.length;
|
|
219
|
+
|
|
220
|
+
for (const file of featureFiles) {
|
|
221
|
+
const featureId = file.split('_')[0];
|
|
222
|
+
const { success } = await syncFeatureWithGit(featureId);
|
|
223
|
+
|
|
224
|
+
if (success) {
|
|
225
|
+
results.synced++;
|
|
226
|
+
} else {
|
|
227
|
+
results.failed++;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
} catch (error) {
|
|
231
|
+
console.error('Error syncing all features:', error);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
return results;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* Feature 진행률 업데이트
|
|
239
|
+
* @param {string} featureId - Feature ID
|
|
240
|
+
* @param {number} percentage - 진행률 (0-100)
|
|
241
|
+
* @returns {Promise<boolean>} - 성공 여부
|
|
242
|
+
*/
|
|
243
|
+
async function updateFeatureProgress(featureId, percentage) {
|
|
244
|
+
try {
|
|
245
|
+
const featureFile = await findFeatureFile(featureId);
|
|
246
|
+
if (!featureFile) {
|
|
247
|
+
return false;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
const { frontmatter, content } = await readFeatureFile(featureFile.path);
|
|
251
|
+
|
|
252
|
+
frontmatter.progress_percentage = Math.min(100, Math.max(0, percentage));
|
|
253
|
+
frontmatter.last_updated = new Date().toISOString().replace('T', ' ').substring(0, 16);
|
|
254
|
+
|
|
255
|
+
await writeFeatureFile(featureFile.path, frontmatter, content);
|
|
256
|
+
return true;
|
|
257
|
+
} catch (error) {
|
|
258
|
+
console.error(`Error updating progress for ${featureId}:`, error);
|
|
259
|
+
return false;
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
module.exports = {
|
|
264
|
+
findFeatureFile,
|
|
265
|
+
readFeatureFile,
|
|
266
|
+
writeFeatureFile,
|
|
267
|
+
updateFeatureWithCommits,
|
|
268
|
+
syncFeatureWithGit,
|
|
269
|
+
syncAllActiveFeatures,
|
|
270
|
+
updateFeatureProgress
|
|
271
|
+
};
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
const { exec } = require('child_process');
|
|
2
|
+
const { promisify } = require('util');
|
|
3
|
+
const execAsync = promisify(exec);
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const { extractFeatureIds, extractFeatureIdFromBranch } = require('../config/commit-patterns');
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Git 커밋 정보를 추출하는 유틸리티 모듈
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Git 명령어 실행
|
|
13
|
+
* @param {string} command - 실행할 git 명령어
|
|
14
|
+
* @param {string} cwd - 작업 디렉토리 (선택사항)
|
|
15
|
+
* @returns {Promise<string>} - 명령어 출력
|
|
16
|
+
*/
|
|
17
|
+
async function runGitCommand(command, cwd = process.cwd()) {
|
|
18
|
+
try {
|
|
19
|
+
const { stdout, stderr } = await execAsync(`git ${command}`, { cwd });
|
|
20
|
+
if (stderr && !stderr.includes('warning:')) {
|
|
21
|
+
throw new Error(`Git command failed: ${stderr}`);
|
|
22
|
+
}
|
|
23
|
+
return stdout.trim();
|
|
24
|
+
} catch (error) {
|
|
25
|
+
throw new Error(`Git command execution failed: ${error.message}`);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* 현재 브랜치 이름 가져오기
|
|
31
|
+
* @returns {Promise<string>} - 브랜치 이름
|
|
32
|
+
*/
|
|
33
|
+
async function getCurrentBranch() {
|
|
34
|
+
return await runGitCommand('rev-parse --abbrev-ref HEAD');
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* 커밋 정보 객체 구조
|
|
39
|
+
* @typedef {Object} CommitInfo
|
|
40
|
+
* @property {string} hash - 커밋 해시
|
|
41
|
+
* @property {string} author - 작성자
|
|
42
|
+
* @property {string} date - 커밋 날짜
|
|
43
|
+
* @property {string} message - 커밋 메시지
|
|
44
|
+
* @property {Array<string>} featureIds - 관련 Feature ID 목록
|
|
45
|
+
*/
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* 특정 커밋의 상세 정보 가져오기
|
|
49
|
+
* @param {string} commitHash - 커밋 해시
|
|
50
|
+
* @returns {Promise<CommitInfo>} - 커밋 정보
|
|
51
|
+
*/
|
|
52
|
+
async function getCommitInfo(commitHash) {
|
|
53
|
+
const format = '%H%n%an%n%aI%n%s%n%b';
|
|
54
|
+
const output = await runGitCommand(`show -s --format="${format}" ${commitHash}`);
|
|
55
|
+
const lines = output.split('\n');
|
|
56
|
+
|
|
57
|
+
const message = lines.slice(3).join('\n').trim();
|
|
58
|
+
const featureIds = extractFeatureIds(message);
|
|
59
|
+
|
|
60
|
+
return {
|
|
61
|
+
hash: lines[0],
|
|
62
|
+
author: lines[1],
|
|
63
|
+
date: lines[2],
|
|
64
|
+
message: message,
|
|
65
|
+
featureIds: featureIds
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* 커밋 범위에서 Feature 관련 커밋 찾기
|
|
71
|
+
* @param {string} since - 시작 날짜 (예: '2025-01-01')
|
|
72
|
+
* @param {string} until - 종료 날짜 (선택사항)
|
|
73
|
+
* @returns {Promise<Array<CommitInfo>>} - Feature 관련 커밋 목록
|
|
74
|
+
*/
|
|
75
|
+
async function getFeatureRelatedCommits(since, until = 'HEAD') {
|
|
76
|
+
try {
|
|
77
|
+
// git log 명령어 구성
|
|
78
|
+
let command = `log --since="${since}"`;
|
|
79
|
+
if (until !== 'HEAD') {
|
|
80
|
+
command += ` --until="${until}"`;
|
|
81
|
+
}
|
|
82
|
+
command += ' --pretty=format:"%H" --grep="FL[0-9]\\{3\\}"';
|
|
83
|
+
|
|
84
|
+
const output = await runGitCommand(command);
|
|
85
|
+
if (!output) {
|
|
86
|
+
return [];
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const commitHashes = output.split('\n').filter(Boolean);
|
|
90
|
+
const commits = [];
|
|
91
|
+
|
|
92
|
+
for (const hash of commitHashes) {
|
|
93
|
+
const commitInfo = await getCommitInfo(hash);
|
|
94
|
+
if (commitInfo.featureIds.length > 0) {
|
|
95
|
+
commits.push(commitInfo);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return commits;
|
|
100
|
+
} catch (error) {
|
|
101
|
+
console.error('Error getting feature related commits:', error);
|
|
102
|
+
return [];
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* 특정 Feature ID와 관련된 모든 커밋 찾기
|
|
108
|
+
* @param {string} featureId - Feature ID (예: 'FL001')
|
|
109
|
+
* @returns {Promise<Array<CommitInfo>>} - 해당 Feature의 커밋 목록
|
|
110
|
+
*/
|
|
111
|
+
async function getCommitsByFeatureId(featureId) {
|
|
112
|
+
try {
|
|
113
|
+
const command = `log --pretty=format:"%H" --grep="${featureId}"`;
|
|
114
|
+
const output = await runGitCommand(command);
|
|
115
|
+
|
|
116
|
+
if (!output) {
|
|
117
|
+
return [];
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const commitHashes = output.split('\n').filter(Boolean);
|
|
121
|
+
const commits = [];
|
|
122
|
+
|
|
123
|
+
for (const hash of commitHashes) {
|
|
124
|
+
const commitInfo = await getCommitInfo(hash);
|
|
125
|
+
if (commitInfo.featureIds.includes(featureId)) {
|
|
126
|
+
commits.push(commitInfo);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
return commits;
|
|
131
|
+
} catch (error) {
|
|
132
|
+
console.error(`Error getting commits for feature ${featureId}:`, error);
|
|
133
|
+
return [];
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* 현재 브랜치의 Feature ID 추출
|
|
139
|
+
* @returns {Promise<string|null>} - Feature ID 또는 null
|
|
140
|
+
*/
|
|
141
|
+
async function getCurrentFeatureId() {
|
|
142
|
+
try {
|
|
143
|
+
const branch = await getCurrentBranch();
|
|
144
|
+
return extractFeatureIdFromBranch(branch);
|
|
145
|
+
} catch (error) {
|
|
146
|
+
console.error('Error getting current feature ID:', error);
|
|
147
|
+
return null;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* 최근 N개의 커밋에서 Feature 관련 커밋 찾기
|
|
153
|
+
* @param {number} count - 확인할 커밋 수
|
|
154
|
+
* @returns {Promise<Array<CommitInfo>>} - Feature 관련 커밋 목록
|
|
155
|
+
*/
|
|
156
|
+
async function getRecentFeatureCommits(count = 10) {
|
|
157
|
+
try {
|
|
158
|
+
const command = `log -${count} --pretty=format:"%H"`;
|
|
159
|
+
const output = await runGitCommand(command);
|
|
160
|
+
|
|
161
|
+
if (!output) {
|
|
162
|
+
return [];
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
const commitHashes = output.split('\n').filter(Boolean);
|
|
166
|
+
const featureCommits = [];
|
|
167
|
+
|
|
168
|
+
for (const hash of commitHashes) {
|
|
169
|
+
const commitInfo = await getCommitInfo(hash);
|
|
170
|
+
if (commitInfo.featureIds.length > 0) {
|
|
171
|
+
featureCommits.push(commitInfo);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
return featureCommits;
|
|
176
|
+
} catch (error) {
|
|
177
|
+
console.error('Error getting recent feature commits:', error);
|
|
178
|
+
return [];
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Git 저장소인지 확인
|
|
184
|
+
* @param {string} dir - 확인할 디렉토리
|
|
185
|
+
* @returns {Promise<boolean>}
|
|
186
|
+
*/
|
|
187
|
+
async function isGitRepository(dir = process.cwd()) {
|
|
188
|
+
try {
|
|
189
|
+
await runGitCommand('rev-parse --git-dir', dir);
|
|
190
|
+
return true;
|
|
191
|
+
} catch (error) {
|
|
192
|
+
return false;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* 변경된 파일 목록 가져오기
|
|
198
|
+
* @returns {Promise<Array<string>>} - 변경된 파일 경로 목록
|
|
199
|
+
*/
|
|
200
|
+
async function getChangedFiles() {
|
|
201
|
+
try {
|
|
202
|
+
const output = await runGitCommand('diff --name-only HEAD');
|
|
203
|
+
return output ? output.split('\n').filter(Boolean) : [];
|
|
204
|
+
} catch (error) {
|
|
205
|
+
console.error('Error getting changed files:', error);
|
|
206
|
+
return [];
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
module.exports = {
|
|
211
|
+
runGitCommand,
|
|
212
|
+
getCurrentBranch,
|
|
213
|
+
getCommitInfo,
|
|
214
|
+
getFeatureRelatedCommits,
|
|
215
|
+
getCommitsByFeatureId,
|
|
216
|
+
getCurrentFeatureId,
|
|
217
|
+
getRecentFeatureCommits,
|
|
218
|
+
isGitRepository,
|
|
219
|
+
getChangedFiles
|
|
220
|
+
};
|