aiwf 0.3.0 → 0.3.2
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/.claude/commands/aiwf/aiwf_compress_aggressive_persona.md +53 -0
- package/.aiwf/.claude/commands/aiwf/aiwf_compress_minimal_persona.md +48 -0
- package/.aiwf/.claude/commands/aiwf/aiwf_compress_stats.md +79 -0
- package/.aiwf/.claude/commands/aiwf/aiwf_compress_with_persona.md +51 -0
- package/.aiwf/.claude/commands/aiwf/aiwf_evaluate.md +92 -0
- package/.aiwf/00_PROJECT_MANIFEST.md +183 -0
- package/.aiwf/01_PROJECT_DOCS/ARCHITECTURE.md +121 -0
- package/.aiwf/01_PROJECT_DOCS/FEATURE_LEDGER_ADVANCED_USE_CASES.md +412 -0
- package/.aiwf/01_PROJECT_DOCS/FEATURE_LEDGER_API_REFERENCE.md +361 -0
- package/.aiwf/01_PROJECT_DOCS/FEATURE_LEDGER_COMMANDS_GUIDE.md +254 -0
- package/.aiwf/01_PROJECT_DOCS/FEATURE_LEDGER_FAQ.md +365 -0
- package/.aiwf/01_PROJECT_DOCS/FEATURE_LEDGER_SYSTEM_OVERVIEW.md +305 -0
- package/.aiwf/01_PROJECT_DOCS/FEATURE_LEDGER_USER_GUIDE.md +416 -0
- package/.aiwf/01_PROJECT_DOCS/FEATURE_LEDGER_/354/213/234/354/236/221_/352/260/200/354/235/264/353/223/234.md +247 -0
- package/.aiwf/02_REQUIREMENTS/CLAUDE.md +78 -0
- package/.aiwf/02_REQUIREMENTS/M02_Context_Engineering_Enhancement/M02_milestone_meta.md +34 -0
- package/.aiwf/02_REQUIREMENTS/M02_Context_Engineering_Enhancement/PRD_Context_Engineering_Enhancement.md +108 -0
- package/.aiwf/02_REQUIREMENTS/M02_Context_Engineering_Enhancement/SPECS_AI_Persona_System.md +299 -0
- package/.aiwf/02_REQUIREMENTS/M02_Context_Engineering_Enhancement/SPECS_Feature_Ledger_System.md +330 -0
- package/.aiwf/02_REQUIREMENTS/M02_Context_Engineering_Enhancement/SPECS_Token_Optimization.md +833 -0
- package/.aiwf/03_SPRINTS/CLAUDE.md +83 -0
- package/.aiwf/03_SPRINTS/S01_M02_context_foundation/S01_M02_sprint_meta.md +95 -0
- package/.aiwf/03_SPRINTS/S01_M02_context_foundation/TX01_S01_Feature_Ledger_/353/215/260/354/235/264/355/204/260_/352/265/254/354/241/260_/354/204/244/352/263/204.md +111 -0
- package/.aiwf/03_SPRINTS/S01_M02_context_foundation/TX02_S01_Feature_Ledger_CLI_/353/252/205/353/240/271/354/226/264_/352/260/234/353/260/234.md +115 -0
- package/.aiwf/03_SPRINTS/S01_M02_context_foundation/TX03_S01_Git_/354/227/260/353/217/231_Feature_/354/266/224/354/240/201.md +141 -0
- package/.aiwf/03_SPRINTS/S01_M02_context_foundation/TX04_S01_Feature_Ledger_/353/254/270/354/204/234/355/231/224.md +114 -0
- package/.aiwf/03_SPRINTS/S01_M02_context_foundation/TX05_S01_AI_/355/216/230/353/245/264/354/206/214/353/202/230_/353/215/260/354/235/264/355/204/260_/352/265/254/354/241/260_/354/204/244/352/263/204.md +123 -0
- package/.aiwf/03_SPRINTS/S01_M02_context_foundation/TX06_S01_/355/216/230/353/245/264/354/206/214/353/202/230_/352/264/200/353/246/254_/353/252/205/353/240/271/354/226/264_/352/265/254/355/230/204.md +114 -0
- package/.aiwf/03_SPRINTS/S01_M02_context_foundation/TX07_S01_Context_/354/225/225/354/266/225_/354/225/204/355/202/244/355/205/215/354/262/230_/354/204/244/352/263/204.md +114 -0
- package/.aiwf/03_SPRINTS/S01_M02_context_foundation/TX08_S01_/355/206/240/355/201/260_/354/266/224/354/240/201_/354/213/234/354/212/244/355/205/234_/355/224/204/353/241/234/355/206/240/355/203/200/354/236/205.md +112 -0
- package/.aiwf/03_SPRINTS/S01_M02_context_foundation/TX09_S01_/354/225/225/354/266/225_/354/225/214/352/263/240/353/246/254/354/246/230_/355/224/204/353/241/234/355/206/240/355/203/200/354/236/205.md +118 -0
- package/.aiwf/03_SPRINTS/S01_M02_context_foundation/TX10_S01_update_docs_/353/252/205/353/240/271/354/226/264_/353/263/265/352/265/254.md +118 -0
- package/.aiwf/03_SPRINTS/S01_M02_context_foundation/TX11_S01_/355/206/265/355/225/251_/355/205/214/354/212/244/355/212/270_Suite_/352/265/254/354/266/225.md +128 -0
- package/.aiwf/03_SPRINTS/S01_M02_context_foundation/TX12_S01_/354/204/261/353/212/245_/354/265/234/354/240/201/355/231/224_/353/260/217_/353/254/270/354/204/234/355/231/224.md +122 -0
- package/.aiwf/03_SPRINTS/S02_M02_ai_enhancement/S02_M02_sprint_meta.md +107 -0
- package/.aiwf/03_SPRINTS/S02_M02_ai_enhancement/TX01_S02_AI_/355/216/230/353/245/264/354/206/214/353/202/230_/353/252/205/353/240/271/354/226/264_/352/265/254/355/230/204.md +129 -0
- package/.aiwf/03_SPRINTS/S02_M02_ai_enhancement/TX02_S02_/355/216/230/353/245/264/354/206/214/353/202/230_/354/273/250/355/205/215/354/212/244/355/212/270_/354/240/201/354/232/251_/354/213/234/354/212/244/355/205/234.md +152 -0
- package/.aiwf/03_SPRINTS/S02_M02_ai_enhancement/TX03_S02_Context_/354/225/225/354/266/225_/354/225/214/352/263/240/353/246/254/354/246/230_/352/265/254/355/230/204.md +186 -0
- package/.aiwf/03_SPRINTS/S02_M02_ai_enhancement/TX05_S02_S02_/355/206/265/355/225/251_/355/205/214/354/212/244/355/212/270_/353/260/217_/353/254/270/354/204/234/355/231/224.md +192 -0
- package/.aiwf/03_SPRINTS/S02_M02_ai_enhancement/TX4_S02_Feature_Git_/354/227/260/353/217/231_/353/260/217_/354/236/220/353/217/231/355/231/224.md +162 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/S03_FINAL_SPRINT_SUMMARY.md +137 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/S03_M02_sprint_meta.md +106 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/TX14_S03_M02_/353/247/210/354/235/274/354/212/244/355/206/244_/354/265/234/354/242/205_/352/262/200/354/246/235_/353/260/217_/353/254/270/354/204/234/355/231/224.md +214 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/TX15_S03_/352/270/260/353/263/270_/355/224/204/353/241/234/354/240/235/355/212/270_/355/205/234/355/224/214/353/246/277_/352/260/234/353/260/234.md +177 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/TX16_S03_/354/230/244/355/224/204/353/235/274/354/235/270_/355/205/234/355/224/214/353/246/277_/354/272/220/354/213/234_/354/213/234/354/212/244/355/205/234.md +206 -0
- package/.aiwf/03_SPRINTS/S03_M02_ecosystem_integration/TX_T13_S03_AI_/353/217/204/352/265/254_/355/206/265/355/225/251_/355/205/234/355/224/214/353/246/277_/352/260/234/353/260/234.md +151 -0
- package/.aiwf/04_GENERAL_TASKS/CLAUDE.md +96 -0
- package/.aiwf/04_GENERAL_TASKS/TX001_complete_english_translation.md +127 -0
- package/.aiwf/05_DOCUMENTATION/performance-report.md +33 -0
- package/.aiwf/06_FEATURE_LEDGERS/FEATURE_GIT_INTEGRATION.md +314 -0
- package/.aiwf/06_FEATURE_LEDGERS/FEATURE_INTEGRATION_GUIDE.md +227 -0
- package/.aiwf/06_FEATURE_LEDGERS/FEATURE_LEDGER_INDEX.md +23 -0
- package/.aiwf/06_FEATURE_LEDGERS/FEATURE_SCHEMA.md +205 -0
- package/.aiwf/06_FEATURE_LEDGERS/FEATURE_STATE_DIAGRAM.md +190 -0
- package/.aiwf/06_FEATURE_LEDGERS/active/FL001_user_authentication_system.md +47 -0
- package/.aiwf/06_FEATURE_LEDGERS/active/FL002_user_authentication_system.md +47 -0
- package/.aiwf/07_AI_PERSONAS/PERSONA_INDEX.md +57 -0
- package/.aiwf/07_AI_PERSONAS/architect/best_practices.md +104 -0
- package/.aiwf/07_AI_PERSONAS/architect/context_rules.md +46 -0
- package/.aiwf/07_AI_PERSONAS/architect/knowledge_base.md +235 -0
- package/.aiwf/07_AI_PERSONAS/backend/best_practices.md +363 -0
- package/.aiwf/07_AI_PERSONAS/backend/context_rules.md +61 -0
- package/.aiwf/07_AI_PERSONAS/backend/knowledge_base.md +623 -0
- package/.aiwf/07_AI_PERSONAS/data_analyst/best_practices.md +32 -0
- package/.aiwf/07_AI_PERSONAS/data_analyst/context_rules.md +43 -0
- package/.aiwf/07_AI_PERSONAS/data_analyst/knowledge_base.md +36 -0
- package/.aiwf/07_AI_PERSONAS/frontend/best_practices.md +31 -0
- package/.aiwf/07_AI_PERSONAS/frontend/context_rules.md +43 -0
- package/.aiwf/07_AI_PERSONAS/frontend/knowledge_base.md +32 -0
- package/.aiwf/07_AI_PERSONAS/security/best_practices.md +63 -0
- package/.aiwf/07_AI_PERSONAS/security/context_rules.md +53 -0
- package/.aiwf/07_AI_PERSONAS/security/knowledge_base.md +93 -0
- package/.aiwf/10_PERSONAS/active.json +1 -0
- package/.aiwf/10_PERSONAS/developer.md +37 -0
- package/.aiwf/10_STATE_OF_PROJECT/2025-07-09-07-20-solid-progress.md +144 -0
- package/.aiwf/98_PROMPTS/SAAS_DEVELOPMENT_GUIDE.md +302 -0
- package/.aiwf/98_PROMPTS/github_integration.md +130 -0
- package/.aiwf/98_PROMPTS/useful-prompts.md +31 -0
- package/.aiwf/98_PROMPTS/vibe-front-prompts.md +89 -0
- package/.aiwf/99_TEMPLATES/adr_template.md +49 -0
- package/.aiwf/99_TEMPLATES/feature_template.md +263 -0
- package/.aiwf/99_TEMPLATES/milestone_meta_template.md +25 -0
- package/.aiwf/99_TEMPLATES/project_manifest_template.md +39 -0
- package/.aiwf/99_TEMPLATES/sprint_meta_template.md +23 -0
- package/.aiwf/99_TEMPLATES/task_template.md +36 -0
- package/.aiwf/CLAUDE.md +76 -0
- package/.aiwf/ai-tools/README.md +105 -0
- package/.aiwf/ai-tools/augment/README.md +371 -0
- package/.aiwf/ai-tools/augment/config.json +30 -0
- package/.aiwf/ai-tools/augment/template/.augment/aiwf-integration.md +387 -0
- package/.aiwf/ai-tools/augment/template/.augment/augment.yaml +347 -0
- package/.aiwf/ai-tools/augment/template/augment.config.json +64 -0
- package/.aiwf/ai-tools/claude-code/README.md +151 -0
- package/.aiwf/ai-tools/claude-code/config.json +28 -0
- package/.aiwf/ai-tools/claude-code/template/CLAUDE.md +91 -0
- package/.aiwf/ai-tools/cursor/README.md +314 -0
- package/.aiwf/ai-tools/cursor/config.json +29 -0
- package/.aiwf/ai-tools/cursor/template/.cursorrules +362 -0
- package/.aiwf/ai-tools/github-copilot/README.md +195 -0
- package/.aiwf/ai-tools/github-copilot/config.json +24 -0
- package/.aiwf/ai-tools/github-copilot/template/.github/copilot-instructions.md +202 -0
- package/.aiwf/ai-tools/windsurf/README.md +355 -0
- package/.aiwf/ai-tools/windsurf/config.json +29 -0
- package/.aiwf/ai-tools/windsurf/template/.windsurf/aiwf-rules.md +260 -0
- package/.aiwf/ai-tools/windsurf/template/.windsurf/windsurf.config.js +312 -0
- package/.aiwf/ai-tools/windsurf/template/windsurf.config.json +63 -0
- package/.aiwf/config/language.json +6 -0
- package/.aiwf/feature-ledger/FL-001-authentication.json +52 -0
- package/.aiwf/feature-ledger/feature-index.json +20 -0
- package/.aiwf/personas/analyst.json +44 -0
- package/.aiwf/personas/architect/best_practices.md +136 -0
- package/.aiwf/personas/architect/knowledge_base.md +377 -0
- package/.aiwf/personas/architect.json +44 -0
- package/.aiwf/personas/backend/best_practices.md +766 -0
- package/.aiwf/personas/backend/knowledge_base.md +1070 -0
- package/.aiwf/personas/data_analyst/best_practices.md +594 -0
- package/.aiwf/personas/data_analyst/knowledge_base.md +1057 -0
- package/.aiwf/personas/developer.json +44 -0
- package/.aiwf/personas/evaluation_criteria.json +137 -0
- package/.aiwf/personas/frontend/best_practices.md +445 -0
- package/.aiwf/personas/frontend/knowledge_base.md +729 -0
- package/.aiwf/personas/persona-index.json +31 -0
- package/.aiwf/personas/reviewer.json +44 -0
- package/.aiwf/personas/security/best_practices.md +307 -0
- package/.aiwf/personas/security/knowledge_base.md +498 -0
- package/.aiwf/personas/tester.json +44 -0
- package/.aiwf/scripts/cache-templates.js +209 -0
- package/.aiwf/scripts/create-offline.js +86 -0
- package/.aiwf/scripts/create-project.js +151 -0
- package/.aiwf/scripts/feature-progress-calculator.cjs +236 -0
- package/.aiwf/scripts/git-integration.cjs +391 -0
- package/.aiwf/scripts/install-git-hooks.cjs +226 -0
- package/.aiwf/scripts/test-commit-parsing.cjs +125 -0
- package/.aiwf/scripts/update-feature-status.cjs +198 -0
- package/.aiwf/templates/README.md +78 -0
- package/.aiwf/templates/api-server/config.json +64 -0
- package/.aiwf/templates/api-server/template/.aiwf/config.json +56 -0
- package/.aiwf/templates/api-server/template/.aiwf/feature-ledger.json +42 -0
- package/.aiwf/templates/api-server/template/.aiwf/personas/backend-engineer.json +40 -0
- package/.aiwf/templates/api-server/template/.aiwf/scripts/cli.js +111 -0
- package/.aiwf/templates/api-server/template/.env.example +29 -0
- package/.aiwf/templates/api-server/template/.eslintrc.json +23 -0
- package/.aiwf/templates/api-server/template/README.md +171 -0
- package/.aiwf/templates/api-server/template/jest.config.js +26 -0
- package/.aiwf/templates/api-server/template/nodemon.json +9 -0
- package/.aiwf/templates/api-server/template/package.json +61 -0
- package/.aiwf/templates/api-server/template/src/app.ts +60 -0
- package/.aiwf/templates/api-server/template/src/config/swagger.ts +38 -0
- package/.aiwf/templates/api-server/template/src/controllers/aiwfController.ts +68 -0
- package/.aiwf/templates/api-server/template/src/controllers/authController.ts +128 -0
- package/.aiwf/templates/api-server/template/src/controllers/statusController.ts +28 -0
- package/.aiwf/templates/api-server/template/src/index.ts +28 -0
- package/.aiwf/templates/api-server/template/src/middleware/aiwfMiddleware.ts +50 -0
- package/.aiwf/templates/api-server/template/src/middleware/authMiddleware.ts +41 -0
- package/.aiwf/templates/api-server/template/src/middleware/errorHandler.ts +42 -0
- package/.aiwf/templates/api-server/template/src/middleware/notFoundHandler.ts +14 -0
- package/.aiwf/templates/api-server/template/src/middleware/requestLogger.ts +20 -0
- package/.aiwf/templates/api-server/template/src/routes/aiwf.ts +42 -0
- package/.aiwf/templates/api-server/template/src/routes/index.ts +13 -0
- package/.aiwf/templates/api-server/template/src/routes/v1/index.ts +67 -0
- package/.aiwf/templates/api-server/template/src/utils/logger.ts +37 -0
- package/.aiwf/templates/api-server/template/tests/app.test.ts +40 -0
- package/.aiwf/templates/api-server/template/tsconfig.json +43 -0
- package/.aiwf/templates/npm-library/config.json +61 -0
- package/.aiwf/templates/npm-library/template/LICENSE +21 -0
- package/.aiwf/templates/npm-library/template/README.md +201 -0
- package/.aiwf/templates/npm-library/template/package.json +78 -0
- package/.aiwf/templates/web-app/config.json +53 -0
- package/.aiwf/templates/web-app/template/.aiwf/config.json +54 -0
- package/.aiwf/templates/web-app/template/.aiwf/feature-ledger.json +37 -0
- package/.aiwf/templates/web-app/template/.aiwf/personas/fullstack-developer.json +40 -0
- package/.aiwf/templates/web-app/template/.aiwf/scripts/cli.js +110 -0
- package/.aiwf/templates/web-app/template/.eslintrc.cjs +20 -0
- package/.aiwf/templates/web-app/template/README.md +151 -0
- package/.aiwf/templates/web-app/template/index.html +14 -0
- package/.aiwf/templates/web-app/template/package.json +44 -0
- package/.aiwf/templates/web-app/template/postcss.config.js +6 -0
- package/.aiwf/templates/web-app/template/public/vite.svg +1 -0
- package/.aiwf/templates/web-app/template/src/App.tsx +21 -0
- package/.aiwf/templates/web-app/template/src/components/Layout.tsx +57 -0
- package/.aiwf/templates/web-app/template/src/components/aiwf/ContextStatus.tsx +107 -0
- package/.aiwf/templates/web-app/template/src/components/aiwf/FeatureLedger.tsx +93 -0
- package/.aiwf/templates/web-app/template/src/components/aiwf/TokenUsage.tsx +71 -0
- package/.aiwf/templates/web-app/template/src/index.css +60 -0
- package/.aiwf/templates/web-app/template/src/main.tsx +10 -0
- package/.aiwf/templates/web-app/template/src/pages/AiwfDashboard.tsx +60 -0
- package/.aiwf/templates/web-app/template/src/pages/HomePage.tsx +89 -0
- package/.aiwf/templates/web-app/template/src/pages/NotFound.tsx +25 -0
- package/.aiwf/templates/web-app/template/src/stores/aiwfStore.ts +126 -0
- package/.aiwf/templates/web-app/template/src/types/global.d.ts +9 -0
- package/.aiwf/templates/web-app/template/src/vite-env.d.ts +1 -0
- package/.aiwf/templates/web-app/template/tailwind.config.js +30 -0
- package/.aiwf/templates/web-app/template/tsconfig.json +37 -0
- package/.aiwf/templates/web-app/template/tsconfig.node.json +10 -0
- package/.aiwf/templates/web-app/template/vite.config.ts +23 -0
- package/.aiwf/test-cache/86c7f9e80251abb8bedd58953ab0d1779e46b4f43ea33b63bffdb778106373b0.json +6 -0
- package/.aiwf/test-cache/9e252a90b80fce0585d7ed0646e7a9b4343e109f661f42a3ae678ba1ec5e22c7.json +7 -0
- package/.aiwf/test-results-s02.json +36 -0
- package/.aiwf/token-data/alerts.json +293 -0
- package/.aiwf/token-data/monitor-config.json +12 -0
- package/CHANGELOG.md +119 -33
- package/CHANGELOG_M02.md +52 -0
- package/CLAUDE.md +133 -199
- package/README.ko.md +5 -0
- package/README.md +31 -5
- package/RELEASE_NOTES_M02.md +177 -0
- package/claude-code/aiwf/en/.claude/commands/aiwf/aiwf_create_feature_ledger.md +54 -0
- package/claude-code/aiwf/en/.claude/commands/aiwf/aiwf_default_mode.md +66 -0
- package/claude-code/aiwf/en/.claude/commands/aiwf/aiwf_docs.md +225 -0
- package/claude-code/aiwf/en/.claude/commands/aiwf/aiwf_get_feature_details.md +78 -0
- package/claude-code/aiwf/en/.claude/commands/aiwf/aiwf_link_feature_to_milestone.md +57 -0
- package/claude-code/aiwf/en/.claude/commands/aiwf/aiwf_list_features.md +54 -0
- package/claude-code/aiwf/en/.claude/commands/aiwf/aiwf_persona_architect.md +60 -0
- package/claude-code/aiwf/en/.claude/commands/aiwf/aiwf_persona_backend.md +60 -0
- package/claude-code/aiwf/en/.claude/commands/aiwf/aiwf_persona_data_analyst.md +60 -0
- package/claude-code/aiwf/en/.claude/commands/aiwf/aiwf_persona_frontend.md +60 -0
- package/claude-code/aiwf/en/.claude/commands/aiwf/aiwf_persona_security.md +60 -0
- package/claude-code/aiwf/en/.claude/commands/aiwf/aiwf_persona_status.md +72 -0
- package/claude-code/aiwf/en/.claude/commands/aiwf/aiwf_switch_language.md +160 -0
- package/claude-code/aiwf/en/.claude/commands/aiwf/aiwf_update_feature_status.md +53 -0
- package/claude-code/aiwf/en/commands/ai-persona.js +667 -0
- package/claude-code/aiwf/en/commands/compress-context.js +355 -0
- package/claude-code/aiwf/en/commands/feature-ledger.js +565 -0
- package/claude-code/aiwf/en/commands/feature_commit_report.js +370 -0
- package/claude-code/aiwf/en/commands/scan_git_history.js +234 -0
- package/claude-code/aiwf/en/commands/sync_feature_commits.js +154 -0
- package/claude-code/aiwf/en/commands/token-tracking.js +443 -0
- package/claude-code/aiwf/en/config/commit-patterns.js +103 -0
- package/claude-code/aiwf/en/hooks/install-hooks.sh +100 -0
- package/claude-code/aiwf/en/hooks/post-commit +84 -0
- package/claude-code/aiwf/en/tests/compression-test-suite.js +1252 -0
- package/claude-code/aiwf/en/tests/test-git-integration.js +164 -0
- package/claude-code/aiwf/en/tests/token-tracking.test.js +537 -0
- package/claude-code/aiwf/en/utils/compression-metrics.js +1031 -0
- package/claude-code/aiwf/en/utils/compression-strategies.js +557 -0
- package/claude-code/aiwf/en/utils/content-normalizer.js +455 -0
- package/claude-code/aiwf/en/utils/context-compressor.js +583 -0
- package/claude-code/aiwf/en/utils/feature-updater.js +271 -0
- package/claude-code/aiwf/en/utils/git-utils.js +220 -0
- package/claude-code/aiwf/en/utils/importance-classifier.js +645 -0
- package/claude-code/aiwf/en/utils/information-filter.js +710 -0
- package/claude-code/aiwf/en/utils/text-summarizer.js +487 -0
- package/claude-code/aiwf/en/utils/token-counter.js +177 -0
- package/claude-code/aiwf/en/utils/token-monitor.js +484 -0
- package/claude-code/aiwf/en/utils/token-reporter.js +453 -0
- package/claude-code/aiwf/en/utils/token-storage.js +433 -0
- package/claude-code/aiwf/en/utils/token-tracker.js +283 -0
- package/claude-code/aiwf/ko/.aiwf/06_FEATURE_LEDGERS/FEATURE_ID_GENERATOR.md +138 -0
- package/claude-code/aiwf/ko/.aiwf/06_FEATURE_LEDGERS/FEATURE_INDEX.md +186 -0
- package/claude-code/aiwf/ko/.aiwf/06_FEATURE_LEDGERS/FEATURE_METADATA.md +240 -0
- package/claude-code/aiwf/ko/.aiwf/06_FEATURE_LEDGERS/FEATURE_WORKFLOW.md +183 -0
- package/claude-code/aiwf/ko/.aiwf/06_FEATURE_LEDGERS/README.md +94 -0
- package/claude-code/aiwf/ko/.aiwf/06_FEATURE_LEDGERS/active/FL001_/354/202/254/354/232/251/354/236/220_/354/235/270/354/246/235_/354/213/234/354/212/244/355/205/234.md +154 -0
- package/claude-code/aiwf/ko/.aiwf/06_FEATURE_LEDGERS/active/FL002_ai_/355/216/230/353/245/264/354/206/214/353/202/230_/354/213/234/354/212/244/355/205/234.md +272 -0
- package/claude-code/aiwf/ko/.aiwf/06_FEATURE_LEDGERS/completed/FL003_/353/213/244/352/265/255/354/226/264_/353/252/205/353/240/271/354/226/264_/355/221/234/354/244/200/355/231/224.md +266 -0
- package/claude-code/aiwf/ko/.aiwf/06_FEATURE_LEDGERS/schemas/feature_schema.json +122 -0
- package/claude-code/aiwf/ko/.aiwf/06_FEATURE_LEDGERS/schemas/feature_validator.cjs +406 -0
- package/claude-code/aiwf/ko/.claude/commands/aiwf/aiwf_code_review.md +62 -62
- package/claude-code/aiwf/ko/.claude/commands/aiwf/aiwf_commit.md +111 -111
- package/claude-code/aiwf/ko/.claude/commands/aiwf/aiwf_compress_aggressive_persona.md +53 -0
- package/claude-code/aiwf/ko/.claude/commands/aiwf/aiwf_compress_context.md +116 -0
- package/claude-code/aiwf/ko/.claude/commands/aiwf/aiwf_compress_minimal_persona.md +48 -0
- package/claude-code/aiwf/ko/.claude/commands/aiwf/aiwf_compress_stats.md +79 -0
- package/claude-code/aiwf/ko/.claude/commands/aiwf/aiwf_compress_with_persona.md +51 -0
- package/claude-code/aiwf/ko/.claude/commands/aiwf/aiwf_create_feature_ledger.md +54 -0
- package/claude-code/aiwf/ko/.claude/commands/aiwf/aiwf_create_general_task.md +106 -106
- package/claude-code/aiwf/ko/.claude/commands/aiwf/aiwf_create_milestone_plan.md +127 -127
- package/claude-code/aiwf/ko/.claude/commands/aiwf/aiwf_create_sprint_tasks.md +130 -130
- package/claude-code/aiwf/ko/.claude/commands/aiwf/aiwf_create_sprints_from_milestone.md +87 -87
- package/claude-code/aiwf/ko/.claude/commands/aiwf/aiwf_default_mode.md +44 -0
- package/claude-code/aiwf/ko/.claude/commands/aiwf/aiwf_do_task.md +72 -72
- package/claude-code/aiwf/ko/.claude/commands/aiwf/aiwf_docs.md +225 -0
- package/claude-code/aiwf/ko/.claude/commands/aiwf/aiwf_evaluate.md +92 -0
- package/claude-code/aiwf/ko/.claude/commands/aiwf/aiwf_get_feature_details.md +78 -0
- package/claude-code/aiwf/ko/.claude/commands/aiwf/aiwf_initialize.md +86 -86
- package/claude-code/aiwf/ko/.claude/commands/aiwf/aiwf_issue_create.md +3 -3
- package/claude-code/aiwf/ko/.claude/commands/aiwf/aiwf_link_feature_to_milestone.md +57 -0
- package/claude-code/aiwf/ko/.claude/commands/aiwf/aiwf_list_features.md +54 -0
- package/claude-code/aiwf/ko/.claude/commands/aiwf/aiwf_persona_architect.md +48 -0
- package/claude-code/aiwf/ko/.claude/commands/aiwf/aiwf_persona_backend.md +37 -0
- package/claude-code/aiwf/ko/.claude/commands/aiwf/aiwf_persona_data_analyst.md +37 -0
- package/claude-code/aiwf/ko/.claude/commands/aiwf/aiwf_persona_frontend.md +37 -0
- package/claude-code/aiwf/ko/.claude/commands/aiwf/aiwf_persona_security.md +48 -0
- package/claude-code/aiwf/ko/.claude/commands/aiwf/aiwf_persona_status.md +50 -0
- package/claude-code/aiwf/ko/.claude/commands/aiwf/aiwf_pr_create.md +14 -14
- package/claude-code/aiwf/ko/.claude/commands/aiwf/aiwf_prime.md +5 -5
- package/claude-code/aiwf/ko/.claude/commands/aiwf/aiwf_project_review.md +39 -39
- package/claude-code/aiwf/ko/.claude/commands/aiwf/aiwf_switch_language.md +160 -0
- package/claude-code/aiwf/ko/.claude/commands/aiwf/aiwf_test.md +76 -77
- package/claude-code/aiwf/ko/.claude/commands/aiwf/aiwf_testing_review.md +120 -120
- package/claude-code/aiwf/ko/.claude/commands/aiwf/aiwf_ultrathink_general.md +209 -266
- package/claude-code/aiwf/ko/.claude/commands/aiwf/aiwf_update_docs_kr.md +25 -0
- package/claude-code/aiwf/ko/.claude/commands/aiwf/aiwf_update_feature_status.md +53 -0
- package/claude-code/aiwf/ko/.claude/commands/aiwf/aiwf_yolo.md +226 -226
- package/claude-code/aiwf/ko/CLAUDE.md +76 -0
- package/claude-code/aiwf/ko/ai-tools/README.md +105 -0
- package/claude-code/aiwf/ko/ai-tools/augment/README.md +371 -0
- package/claude-code/aiwf/ko/ai-tools/augment/config.json +30 -0
- package/claude-code/aiwf/ko/ai-tools/augment/template/.augment/aiwf-integration.md +387 -0
- package/claude-code/aiwf/ko/ai-tools/augment/template/.augment/augment.yaml +347 -0
- package/claude-code/aiwf/ko/ai-tools/augment/template/augment.config.json +64 -0
- package/claude-code/aiwf/ko/ai-tools/claude-code/README.md +151 -0
- package/claude-code/aiwf/ko/ai-tools/claude-code/config.json +28 -0
- package/claude-code/aiwf/ko/ai-tools/claude-code/template/CLAUDE.md +91 -0
- package/claude-code/aiwf/ko/ai-tools/cursor/README.md +314 -0
- package/claude-code/aiwf/ko/ai-tools/cursor/config.json +29 -0
- package/claude-code/aiwf/ko/ai-tools/cursor/template/.cursorrules +362 -0
- package/claude-code/aiwf/ko/ai-tools/github-copilot/README.md +195 -0
- package/claude-code/aiwf/ko/ai-tools/github-copilot/config.json +24 -0
- package/claude-code/aiwf/ko/ai-tools/github-copilot/template/.github/copilot-instructions.md +202 -0
- package/claude-code/aiwf/ko/ai-tools/windsurf/README.md +355 -0
- package/claude-code/aiwf/ko/ai-tools/windsurf/config.json +29 -0
- package/claude-code/aiwf/ko/ai-tools/windsurf/template/.windsurf/aiwf-rules.md +260 -0
- package/claude-code/aiwf/ko/ai-tools/windsurf/template/.windsurf/windsurf.config.js +312 -0
- package/claude-code/aiwf/ko/ai-tools/windsurf/template/windsurf.config.json +63 -0
- package/claude-code/aiwf/ko/bin/aiwf-create.js +56 -0
- package/claude-code/aiwf/ko/bin/aiwf.js +21 -0
- package/claude-code/aiwf/ko/commands/ai-persona.js +602 -0
- package/claude-code/aiwf/ko/commands/compress-context.js +389 -0
- package/claude-code/aiwf/ko/commands/evaluate.js +246 -0
- package/claude-code/aiwf/ko/commands/feature-ledger.js +565 -0
- package/claude-code/aiwf/ko/commands/feature_commit_report.js +370 -0
- package/claude-code/aiwf/ko/commands/persona-context-apply.js +562 -0
- package/claude-code/aiwf/ko/commands/scan_git_history.js +234 -0
- package/claude-code/aiwf/ko/commands/sync_feature_commits.js +154 -0
- package/claude-code/aiwf/ko/commands/token-tracking.js +443 -0
- package/claude-code/aiwf/ko/config/commit-patterns.js +103 -0
- package/claude-code/aiwf/ko/config/language.json +6 -0
- package/claude-code/aiwf/ko/docs/00_PROJECT_MANIFEST.md +183 -0
- package/claude-code/aiwf/ko/docs/ARCHITECTURE.md +121 -0
- package/claude-code/aiwf/ko/docs/FEATURE_LEDGER_ADVANCED_USE_CASES.md +412 -0
- package/claude-code/aiwf/ko/docs/FEATURE_LEDGER_API_REFERENCE.md +361 -0
- package/claude-code/aiwf/ko/docs/FEATURE_LEDGER_COMMANDS_GUIDE.md +254 -0
- package/claude-code/aiwf/ko/docs/FEATURE_LEDGER_FAQ.md +365 -0
- package/claude-code/aiwf/ko/docs/FEATURE_LEDGER_SYSTEM_OVERVIEW.md +305 -0
- package/claude-code/aiwf/ko/docs/FEATURE_LEDGER_USER_GUIDE.md +416 -0
- package/claude-code/aiwf/ko/docs/FEATURE_LEDGER_/354/213/234/354/236/221_/352/260/200/354/235/264/353/223/234.md +247 -0
- package/claude-code/aiwf/ko/feature-ledger/FL-001-authentication.json +52 -0
- package/claude-code/aiwf/ko/feature-ledger/feature-index.json +20 -0
- package/claude-code/aiwf/ko/hooks/install-hooks.sh +100 -0
- package/claude-code/aiwf/ko/hooks/post-commit +84 -0
- package/claude-code/aiwf/ko/personas/PERSONA_INDEX.md +57 -0
- package/claude-code/aiwf/ko/personas/analyst.json +44 -0
- package/claude-code/aiwf/ko/personas/architect/best_practices.md +136 -0
- package/claude-code/aiwf/ko/personas/architect/knowledge_base.md +377 -0
- package/claude-code/aiwf/ko/personas/architect.json +44 -0
- package/claude-code/aiwf/ko/personas/backend/best_practices.md +766 -0
- package/claude-code/aiwf/ko/personas/backend/knowledge_base.md +1070 -0
- package/claude-code/aiwf/ko/personas/data_analyst/best_practices.md +594 -0
- package/claude-code/aiwf/ko/personas/data_analyst/knowledge_base.md +1057 -0
- package/claude-code/aiwf/ko/personas/developer.json +44 -0
- package/claude-code/aiwf/ko/personas/developer.md +37 -0
- package/claude-code/aiwf/ko/personas/evaluation_criteria.json +137 -0
- package/claude-code/aiwf/ko/personas/frontend/best_practices.md +445 -0
- package/claude-code/aiwf/ko/personas/frontend/knowledge_base.md +729 -0
- package/claude-code/aiwf/ko/personas/persona-index.json +31 -0
- package/claude-code/aiwf/ko/personas/reviewer.json +44 -0
- package/claude-code/aiwf/ko/personas/security/best_practices.md +307 -0
- package/claude-code/aiwf/ko/personas/security/knowledge_base.md +498 -0
- package/claude-code/aiwf/ko/personas/tester.json +44 -0
- package/claude-code/aiwf/ko/scripts/cache-templates.js +209 -0
- package/claude-code/aiwf/ko/scripts/create-offline.js +86 -0
- package/claude-code/aiwf/ko/scripts/create-project.js +151 -0
- package/claude-code/aiwf/ko/scripts/feature-progress-calculator.cjs +236 -0
- package/claude-code/aiwf/ko/scripts/git-integration.cjs +391 -0
- package/claude-code/aiwf/ko/scripts/install-git-hooks.cjs +226 -0
- package/claude-code/aiwf/ko/scripts/test-commit-parsing.cjs +125 -0
- package/claude-code/aiwf/ko/scripts/update-feature-status.cjs +198 -0
- package/claude-code/aiwf/ko/templates/README.md +78 -0
- package/claude-code/aiwf/ko/templates/api-server/config.json +64 -0
- package/claude-code/aiwf/ko/templates/api-server/template/.aiwf/config.json +56 -0
- package/claude-code/aiwf/ko/templates/api-server/template/.aiwf/feature-ledger.json +42 -0
- package/claude-code/aiwf/ko/templates/api-server/template/.aiwf/personas/backend-engineer.json +40 -0
- package/claude-code/aiwf/ko/templates/api-server/template/.aiwf/scripts/cli.js +111 -0
- package/claude-code/aiwf/ko/templates/api-server/template/.env.example +29 -0
- package/claude-code/aiwf/ko/templates/api-server/template/.eslintrc.json +23 -0
- package/claude-code/aiwf/ko/templates/api-server/template/README.md +171 -0
- package/claude-code/aiwf/ko/templates/api-server/template/jest.config.js +26 -0
- package/claude-code/aiwf/ko/templates/api-server/template/nodemon.json +9 -0
- package/claude-code/aiwf/ko/templates/api-server/template/package.json +61 -0
- package/claude-code/aiwf/ko/templates/api-server/template/src/app.ts +60 -0
- package/claude-code/aiwf/ko/templates/api-server/template/src/config/swagger.ts +38 -0
- package/claude-code/aiwf/ko/templates/api-server/template/src/controllers/aiwfController.ts +68 -0
- package/claude-code/aiwf/ko/templates/api-server/template/src/controllers/authController.ts +128 -0
- package/claude-code/aiwf/ko/templates/api-server/template/src/controllers/statusController.ts +28 -0
- package/claude-code/aiwf/ko/templates/api-server/template/src/index.ts +28 -0
- package/claude-code/aiwf/ko/templates/api-server/template/src/middleware/aiwfMiddleware.ts +50 -0
- package/claude-code/aiwf/ko/templates/api-server/template/src/middleware/authMiddleware.ts +41 -0
- package/claude-code/aiwf/ko/templates/api-server/template/src/middleware/errorHandler.ts +42 -0
- package/claude-code/aiwf/ko/templates/api-server/template/src/middleware/notFoundHandler.ts +14 -0
- package/claude-code/aiwf/ko/templates/api-server/template/src/middleware/requestLogger.ts +20 -0
- package/claude-code/aiwf/ko/templates/api-server/template/src/routes/aiwf.ts +42 -0
- package/claude-code/aiwf/ko/templates/api-server/template/src/routes/index.ts +13 -0
- package/claude-code/aiwf/ko/templates/api-server/template/src/routes/v1/index.ts +67 -0
- package/claude-code/aiwf/ko/templates/api-server/template/src/utils/logger.ts +37 -0
- package/claude-code/aiwf/ko/templates/api-server/template/tests/app.test.ts +40 -0
- package/claude-code/aiwf/ko/templates/api-server/template/tsconfig.json +43 -0
- package/claude-code/aiwf/ko/templates/npm-library/config.json +61 -0
- package/claude-code/aiwf/ko/templates/npm-library/template/LICENSE +21 -0
- package/claude-code/aiwf/ko/templates/npm-library/template/README.md +201 -0
- package/claude-code/aiwf/ko/templates/npm-library/template/package.json +78 -0
- package/claude-code/aiwf/ko/templates/web-app/config.json +53 -0
- package/claude-code/aiwf/ko/templates/web-app/template/.aiwf/config.json +54 -0
- package/claude-code/aiwf/ko/templates/web-app/template/.aiwf/feature-ledger.json +37 -0
- package/claude-code/aiwf/ko/templates/web-app/template/.aiwf/personas/fullstack-developer.json +40 -0
- package/claude-code/aiwf/ko/templates/web-app/template/.aiwf/scripts/cli.js +110 -0
- package/claude-code/aiwf/ko/templates/web-app/template/.eslintrc.cjs +20 -0
- package/claude-code/aiwf/ko/templates/web-app/template/README.md +151 -0
- package/claude-code/aiwf/ko/templates/web-app/template/index.html +14 -0
- package/claude-code/aiwf/ko/templates/web-app/template/package.json +44 -0
- package/claude-code/aiwf/ko/templates/web-app/template/postcss.config.js +6 -0
- package/claude-code/aiwf/ko/templates/web-app/template/public/vite.svg +1 -0
- package/claude-code/aiwf/ko/templates/web-app/template/src/App.tsx +21 -0
- package/claude-code/aiwf/ko/templates/web-app/template/src/components/Layout.tsx +57 -0
- package/claude-code/aiwf/ko/templates/web-app/template/src/components/aiwf/ContextStatus.tsx +107 -0
- package/claude-code/aiwf/ko/templates/web-app/template/src/components/aiwf/FeatureLedger.tsx +93 -0
- package/claude-code/aiwf/ko/templates/web-app/template/src/components/aiwf/TokenUsage.tsx +71 -0
- package/claude-code/aiwf/ko/templates/web-app/template/src/index.css +60 -0
- package/claude-code/aiwf/ko/templates/web-app/template/src/main.tsx +10 -0
- package/claude-code/aiwf/ko/templates/web-app/template/src/pages/AiwfDashboard.tsx +60 -0
- package/claude-code/aiwf/ko/templates/web-app/template/src/pages/HomePage.tsx +89 -0
- package/claude-code/aiwf/ko/templates/web-app/template/src/pages/NotFound.tsx +25 -0
- package/claude-code/aiwf/ko/templates/web-app/template/src/stores/aiwfStore.ts +126 -0
- package/claude-code/aiwf/ko/templates/web-app/template/src/types/global.d.ts +9 -0
- package/claude-code/aiwf/ko/templates/web-app/template/src/vite-env.d.ts +1 -0
- package/claude-code/aiwf/ko/templates/web-app/template/tailwind.config.js +30 -0
- package/claude-code/aiwf/ko/templates/web-app/template/tsconfig.json +37 -0
- package/claude-code/aiwf/ko/templates/web-app/template/tsconfig.node.json +10 -0
- package/claude-code/aiwf/ko/templates/web-app/template/vite.config.ts +23 -0
- package/claude-code/aiwf/ko/tests/compression-test-suite.js +1252 -0
- package/claude-code/aiwf/ko/tests/test-git-integration.js +164 -0
- package/claude-code/aiwf/ko/tests/token-tracking.test.js +537 -0
- package/claude-code/aiwf/ko/token-data/alerts.json +293 -0
- package/claude-code/aiwf/ko/token-data/monitor-config.json +12 -0
- package/claude-code/aiwf/ko/utils/background-monitor.js +223 -0
- package/claude-code/aiwf/ko/utils/compression-metrics.js +1031 -0
- package/claude-code/aiwf/ko/utils/compression-strategies.js +557 -0
- package/claude-code/aiwf/ko/utils/content-normalizer.js +455 -0
- package/claude-code/aiwf/ko/utils/context-compressor.js +583 -0
- package/claude-code/aiwf/ko/utils/context-rule-parser.js +180 -0
- package/claude-code/aiwf/ko/utils/context-token-monitor.js +463 -0
- package/claude-code/aiwf/ko/utils/context-update-manager.js +502 -0
- package/claude-code/aiwf/ko/utils/feature-updater.js +271 -0
- package/claude-code/aiwf/ko/utils/git-utils.js +220 -0
- package/claude-code/aiwf/ko/utils/importance-classifier.js +645 -0
- package/claude-code/aiwf/ko/utils/information-filter.js +710 -0
- package/claude-code/aiwf/ko/utils/persona-aware-compressor.js +598 -0
- package/claude-code/aiwf/ko/utils/prompt-injector.js +242 -0
- package/claude-code/aiwf/ko/utils/simplified-evaluator.js +119 -0
- package/claude-code/aiwf/ko/utils/text-summarizer.js +492 -0
- package/claude-code/aiwf/ko/utils/token-counter.js +177 -0
- package/claude-code/aiwf/ko/utils/token-monitor.js +484 -0
- package/claude-code/aiwf/ko/utils/token-reporter.js +453 -0
- package/claude-code/aiwf/ko/utils/token-storage.js +433 -0
- package/claude-code/aiwf/ko/utils/token-tracker.js +283 -0
- package/docs/AI-WORKFLOW.ko.md +9 -2
- package/docs/AI-WORKFLOW.md +9 -2
- package/docs/AI_PERSONA_SYSTEM_DESIGN.md +516 -0
- package/docs/API_DOCUMENTATION.md +932 -0
- package/docs/API_REFERENCE.md +979 -0
- package/docs/COMMANDS_GUIDE.ko.md +101 -5
- package/docs/COMMANDS_GUIDE.md +289 -5
- package/docs/CONTRIBUTING.ko.md +408 -0
- package/docs/CONTRIBUTING.md +205 -203
- package/docs/EXAMPLES.md +691 -0
- package/docs/Enhanced_Installation_Flow_Design.md +498 -0
- package/docs/GETTING_STARTED.md +480 -0
- package/docs/PERFORMANCE_ARCHITECTURE.md +494 -0
- package/docs/PERFORMANCE_GUIDELINES.md +553 -0
- package/docs/PRD.ko.md +110 -58
- package/docs/PRD.md +110 -58
- package/docs/TROUBLESHOOTING.md +721 -0
- package/docs/git-feature-integration-guide.md +253 -0
- package/docs/guides/ai-personas-guide-ko.md +239 -0
- package/docs/guides/ai-personas-guide.md +239 -0
- package/docs/guides/context-compression-guide-ko.md +313 -0
- package/docs/guides/context-compression-guide.md +313 -0
- package/docs/guides/feature-git-integration-guide-ko.md +481 -0
- package/docs/guides/feature-git-integration-guide.md +481 -0
- package/docs/lightweight-evaluation.md +198 -0
- package/docs/m02-dod-checklist.md +125 -0
- package/docs/m02-gap-analysis.md +214 -0
- package/docs/m02-milestone-completion-report.md +186 -0
- package/docs/m02-milestone-executive-summary.md +68 -0
- package/docs/offline-template-cache.md +323 -0
- package/docs/performance-benchmark-report.md +159 -0
- package/docs/persona-aware-compression.md +168 -0
- package/docs/reports/S02-sprint-report.md +190 -0
- package/docs/usability-test-report.md +170 -0
- package/index.js +1349 -21
- package/jest.config.js +23 -0
- package/language-cli.js +279 -0
- package/language-utils.js +330 -0
- package/lib/ai-persona-manager.js +711 -0
- package/lib/cache-cli.js +459 -0
- package/lib/cache-integration.js +401 -0
- package/lib/cache-system.js +332 -0
- package/lib/context-engine.js +568 -0
- package/lib/file-batch-processor.js +401 -0
- package/lib/memory-profiler.js +471 -0
- package/lib/metrics-collector.js +885 -0
- package/lib/offline-detector.js +386 -0
- package/lib/performance-benchmark.js +621 -0
- package/lib/task-analyzer.js +599 -0
- package/lib/template-cache-system.js +559 -0
- package/lib/template-downloader.js +467 -0
- package/lib/template-manager.js +310 -0
- package/lib/template-version-manager.js +491 -0
- package/lib/token-optimizer.js +517 -0
- package/package.json +17 -6
- package/scripts/run-integration-tests.js +317 -0
- package/scripts/validate-commands.cjs +338 -0
- package/scripts/validate-commands.js +254 -0
- package/src/commands/ai-tool.js +383 -0
- package/test-token-system.js +88 -0
- package/tests/application.test.js +260 -0
- package/tests/basic.test.js +62 -0
- package/tests/commands.test.js +127 -0
- package/tests/installer.test.js +129 -0
- package/tests/integration/ai-persona-system.test.js +396 -0
- package/tests/integration/ai-persona.test.js +390 -0
- package/tests/integration/command-integration.test.js +600 -0
- package/tests/integration/context-compression.test.js +361 -0
- package/tests/integration/feature-ledger.test.js +226 -0
- package/tests/integration/git-integration.test.js +307 -0
- package/tests/integration/m02-milestone.test.js +420 -0
- package/tests/integration/persona-context-application.test.js +508 -0
- package/tests/integration/setup.js +174 -0
- package/tests/integration/test-persona-aware-compression.js +93 -0
- package/tests/language-utils.test.js +287 -0
- package/tests/s02-integration.test.js +422 -0
- package/tests/unit/ai-persona-manager.test.js +514 -0
- package/claude-code/aiwf/en/.claude/commands/aiwf/aiwf_prime_context.md +0 -5
- package/claude-code/aiwf/ko/.claude/commands/aiwf/aiwf_prime_context.md +0 -8
package/index.js
CHANGED
|
@@ -10,13 +10,23 @@ import { fileURLToPath } from 'url';
|
|
|
10
10
|
import https from 'https';
|
|
11
11
|
import { createWriteStream } from 'fs';
|
|
12
12
|
import { pipeline } from 'stream/promises';
|
|
13
|
+
import {
|
|
14
|
+
detectLanguage,
|
|
15
|
+
loadUserLanguageConfig,
|
|
16
|
+
saveUserLanguageConfig,
|
|
17
|
+
getInstallationLanguagePath,
|
|
18
|
+
SUPPORTED_LANGUAGES,
|
|
19
|
+
DEFAULT_LANGUAGE
|
|
20
|
+
} from './language-utils.js';
|
|
21
|
+
import AIToolCommand from './src/commands/ai-tool.js';
|
|
22
|
+
import { CacheCLI } from './lib/cache-cli.js';
|
|
13
23
|
|
|
14
24
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
15
25
|
|
|
16
26
|
const program = new Command();
|
|
17
27
|
|
|
18
28
|
const GITHUB_API_URL = 'https://api.github.com/repos/moonklabs/aiwf';
|
|
19
|
-
const GITHUB_RAW_URL = 'https://raw.githubusercontent.com/moonklabs/aiwf/
|
|
29
|
+
const GITHUB_RAW_URL = 'https://raw.githubusercontent.com/moonklabs/aiwf/main';
|
|
20
30
|
const GITHUB_CONTENT_PREFIX = 'claude-code/aiwf';
|
|
21
31
|
|
|
22
32
|
async function fetchGitHubContent(url) {
|
|
@@ -99,15 +109,34 @@ async function backupFile(filePath, backupDir) {
|
|
|
99
109
|
await fs.mkdir(backupDir, { recursive: true });
|
|
100
110
|
const backupPath = `${filePath}.bak`;
|
|
101
111
|
await fs.copyFile(filePath, backupPath);
|
|
102
|
-
|
|
112
|
+
|
|
113
|
+
// 도구별 백업 파일 명명 규칙 개선
|
|
103
114
|
let bakFileName;
|
|
104
|
-
if (filePath.startsWith(
|
|
105
|
-
|
|
115
|
+
if (filePath.startsWith('.claude/commands/aiwf/')) {
|
|
116
|
+
// Claude Code 명령어 파일
|
|
117
|
+
const relativePath = filePath.substring('.claude/commands/aiwf/'.length);
|
|
118
|
+
bakFileName = `claude-commands-aiwf-${relativePath.replace(/\//g, '-')}.bak`;
|
|
119
|
+
} else if (filePath.startsWith('.gemini/prompts/aiwf/')) {
|
|
120
|
+
// Gemini CLI 프롬프트 파일
|
|
121
|
+
const relativePath = filePath.substring('.gemini/prompts/aiwf/'.length);
|
|
122
|
+
bakFileName = `gemini-prompts-aiwf-${relativePath.replace(/\//g, '-')}.bak`;
|
|
123
|
+
} else if (filePath.startsWith('.cursor/rules/')) {
|
|
124
|
+
// Cursor 규칙 파일
|
|
125
|
+
const relativePath = filePath.substring('.cursor/rules/'.length);
|
|
126
|
+
bakFileName = `cursor-rules-${relativePath.replace(/\//g, '-')}.bak`;
|
|
127
|
+
} else if (filePath.startsWith('.windsurf/rules/')) {
|
|
128
|
+
// Windsurf 규칙 파일
|
|
129
|
+
const relativePath = filePath.substring('.windsurf/rules/'.length);
|
|
130
|
+
bakFileName = `windsurf-rules-${relativePath.replace(/\//g, '-')}.bak`;
|
|
106
131
|
} else if (filePath.startsWith('.aiwf/')) {
|
|
107
|
-
|
|
132
|
+
// AIWF 핵심 파일
|
|
133
|
+
const relativePath = filePath.substring('.aiwf/'.length);
|
|
134
|
+
bakFileName = `aiwf-${relativePath.replace(/\//g, '-')}.bak`;
|
|
108
135
|
} else {
|
|
136
|
+
// 기타 파일
|
|
109
137
|
bakFileName = path.basename(filePath) + '.bak';
|
|
110
138
|
}
|
|
139
|
+
|
|
111
140
|
const destPath = path.join(backupDir, bakFileName);
|
|
112
141
|
await fs.rename(backupPath, destPath);
|
|
113
142
|
return destPath;
|
|
@@ -131,6 +160,7 @@ async function backupCommandsAndDocs(msg) {
|
|
|
131
160
|
'.aiwf/03_SPRINTS/CLAUDE.md',
|
|
132
161
|
'.aiwf/04_GENERAL_TASKS/CLAUDE.md'
|
|
133
162
|
];
|
|
163
|
+
|
|
134
164
|
// Backup CLAUDE.md files
|
|
135
165
|
for (const file of filesToBackup) {
|
|
136
166
|
const backupPath = await backupFile(file, BACKUP_DIR);
|
|
@@ -138,6 +168,7 @@ async function backupCommandsAndDocs(msg) {
|
|
|
138
168
|
backedUpFiles.push(backupPath);
|
|
139
169
|
}
|
|
140
170
|
}
|
|
171
|
+
|
|
141
172
|
// Backup all command files
|
|
142
173
|
const commandsExist = await fs.access(COMMANDS_DIR).then(() => true).catch(() => false);
|
|
143
174
|
if (commandsExist) {
|
|
@@ -157,6 +188,45 @@ async function backupCommandsAndDocs(msg) {
|
|
|
157
188
|
// Commands directory might be empty or have issues
|
|
158
189
|
}
|
|
159
190
|
}
|
|
191
|
+
|
|
192
|
+
// Backup IDE rule files (Cursor)
|
|
193
|
+
const cursorRulesExist = await fs.access('.cursor/rules').then(() => true).catch(() => false);
|
|
194
|
+
if (cursorRulesExist) {
|
|
195
|
+
try {
|
|
196
|
+
const cursorFiles = await fs.readdir('.cursor/rules');
|
|
197
|
+
for (const file of cursorFiles) {
|
|
198
|
+
if (file.endsWith('.mdc')) {
|
|
199
|
+
const filePath = path.join('.cursor/rules', file);
|
|
200
|
+
const backupPath = await backupFile(filePath, BACKUP_DIR);
|
|
201
|
+
if (backupPath) {
|
|
202
|
+
backedUpFiles.push(backupPath);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
} catch (error) {
|
|
207
|
+
// Cursor rules directory might have issues
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// Backup IDE rule files (Windsurf)
|
|
212
|
+
const windsurfRulesExist = await fs.access('.windsurf/rules').then(() => true).catch(() => false);
|
|
213
|
+
if (windsurfRulesExist) {
|
|
214
|
+
try {
|
|
215
|
+
const windsurfFiles = await fs.readdir('.windsurf/rules');
|
|
216
|
+
for (const file of windsurfFiles) {
|
|
217
|
+
if (file.endsWith('.md')) {
|
|
218
|
+
const filePath = path.join('.windsurf/rules', file);
|
|
219
|
+
const backupPath = await backupFile(filePath, BACKUP_DIR);
|
|
220
|
+
if (backupPath) {
|
|
221
|
+
backedUpFiles.push(backupPath);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
} catch (error) {
|
|
226
|
+
// Windsurf rules directory might have issues
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
160
230
|
if (backedUpFiles.length > 0) {
|
|
161
231
|
spinner.succeed(chalk.green(msg.backupComplete.replace('{count}', backedUpFiles.length)));
|
|
162
232
|
} else {
|
|
@@ -310,24 +380,1128 @@ const messages = {
|
|
|
310
380
|
}
|
|
311
381
|
};
|
|
312
382
|
|
|
383
|
+
// =============================================================================
|
|
384
|
+
// INSTALLATION VALIDATION SYSTEM
|
|
385
|
+
// =============================================================================
|
|
386
|
+
|
|
387
|
+
// 각 도구별 필수 파일 목록 정의
|
|
388
|
+
const ESSENTIAL_FILES = {
|
|
389
|
+
claudeCode: {
|
|
390
|
+
baseDir: '.claude/commands/aiwf',
|
|
391
|
+
requiredFiles: [
|
|
392
|
+
'aiwf_initialize.md',
|
|
393
|
+
'aiwf_do_task.md',
|
|
394
|
+
'aiwf_commit.md',
|
|
395
|
+
'aiwf_create_sprint_tasks.md',
|
|
396
|
+
'aiwf_code_review.md'
|
|
397
|
+
],
|
|
398
|
+
minFileCount: 5,
|
|
399
|
+
description: 'Claude Code Commands'
|
|
400
|
+
},
|
|
401
|
+
geminiCLI: {
|
|
402
|
+
baseDir: '.gemini/prompts/aiwf',
|
|
403
|
+
requiredFiles: [
|
|
404
|
+
'README.md'
|
|
405
|
+
],
|
|
406
|
+
minFileCount: 1,
|
|
407
|
+
description: 'Gemini-CLI Prompts'
|
|
408
|
+
},
|
|
409
|
+
cursor: {
|
|
410
|
+
baseDir: '.cursor/rules',
|
|
411
|
+
requiredFiles: [],
|
|
412
|
+
minFileCount: 2,
|
|
413
|
+
fileExtension: '.mdc',
|
|
414
|
+
description: 'Cursor IDE Rules'
|
|
415
|
+
},
|
|
416
|
+
windsurf: {
|
|
417
|
+
baseDir: '.windsurf/rules',
|
|
418
|
+
requiredFiles: [],
|
|
419
|
+
minFileCount: 2,
|
|
420
|
+
fileExtension: '.md',
|
|
421
|
+
description: 'Windsurf IDE Rules'
|
|
422
|
+
},
|
|
423
|
+
aiwf: {
|
|
424
|
+
baseDir: '.aiwf',
|
|
425
|
+
requiredFiles: [
|
|
426
|
+
'CLAUDE.md',
|
|
427
|
+
'00_PROJECT_MANIFEST.md'
|
|
428
|
+
],
|
|
429
|
+
minFileCount: 2,
|
|
430
|
+
description: 'AIWF Core Structure'
|
|
431
|
+
}
|
|
432
|
+
};
|
|
433
|
+
|
|
434
|
+
// 범용 검증 함수 (모든 도구에서 사용)
|
|
435
|
+
async function validateToolInstallation(config) {
|
|
436
|
+
const results = {
|
|
437
|
+
success: true,
|
|
438
|
+
description: config.description,
|
|
439
|
+
baseDir: config.baseDir,
|
|
440
|
+
checks: {
|
|
441
|
+
directoryExists: false,
|
|
442
|
+
fileCount: 0,
|
|
443
|
+
requiredFiles: [],
|
|
444
|
+
totalSize: 0,
|
|
445
|
+
issues: []
|
|
446
|
+
}
|
|
447
|
+
};
|
|
448
|
+
|
|
449
|
+
try {
|
|
450
|
+
// 1. 디렉토리 존재 확인
|
|
451
|
+
await fs.access(config.baseDir);
|
|
452
|
+
const dirStat = await fs.stat(config.baseDir);
|
|
453
|
+
if (dirStat.isDirectory()) {
|
|
454
|
+
results.checks.directoryExists = true;
|
|
455
|
+
} else {
|
|
456
|
+
results.checks.issues.push(`${config.baseDir} is not a directory`);
|
|
457
|
+
results.success = false;
|
|
458
|
+
return results;
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
// 2. 파일 목록 가져오기
|
|
462
|
+
const actualFiles = await fs.readdir(config.baseDir);
|
|
463
|
+
results.checks.fileCount = actualFiles.length;
|
|
464
|
+
|
|
465
|
+
// 3. 필수 파일 존재 확인
|
|
466
|
+
for (const requiredFile of config.requiredFiles || []) {
|
|
467
|
+
const filePath = path.join(config.baseDir, requiredFile);
|
|
468
|
+
const fileCheck = {
|
|
469
|
+
file: requiredFile,
|
|
470
|
+
exists: false,
|
|
471
|
+
size: 0,
|
|
472
|
+
valid: false
|
|
473
|
+
};
|
|
474
|
+
|
|
475
|
+
if (actualFiles.includes(requiredFile)) {
|
|
476
|
+
fileCheck.exists = true;
|
|
477
|
+
try {
|
|
478
|
+
const stats = await fs.stat(filePath);
|
|
479
|
+
fileCheck.size = stats.size;
|
|
480
|
+
results.checks.totalSize += stats.size;
|
|
481
|
+
|
|
482
|
+
// 파일 크기 검증 (최소 10바이트)
|
|
483
|
+
if (stats.size < 10) {
|
|
484
|
+
results.checks.issues.push(`File ${requiredFile} is too small (${stats.size} bytes)`);
|
|
485
|
+
results.success = false;
|
|
486
|
+
} else {
|
|
487
|
+
fileCheck.valid = true;
|
|
488
|
+
}
|
|
489
|
+
} catch (error) {
|
|
490
|
+
results.checks.issues.push(`Cannot read stats for ${requiredFile}: ${error.message}`);
|
|
491
|
+
results.success = false;
|
|
492
|
+
}
|
|
493
|
+
} else {
|
|
494
|
+
results.checks.issues.push(`Required file ${requiredFile} is missing`);
|
|
495
|
+
results.success = false;
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
results.checks.requiredFiles.push(fileCheck);
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
// 4. 파일 확장자 기반 검증 (Cursor/Windsurf)
|
|
502
|
+
if (config.fileExtension) {
|
|
503
|
+
const matchingFiles = actualFiles.filter(f => f.endsWith(config.fileExtension));
|
|
504
|
+
if (matchingFiles.length < config.minFileCount) {
|
|
505
|
+
results.checks.issues.push(`Expected at least ${config.minFileCount} ${config.fileExtension} files, found ${matchingFiles.length}`);
|
|
506
|
+
results.success = false;
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
// 확장자별 파일 크기 검증
|
|
510
|
+
for (const file of matchingFiles) {
|
|
511
|
+
const filePath = path.join(config.baseDir, file);
|
|
512
|
+
try {
|
|
513
|
+
const stats = await fs.stat(filePath);
|
|
514
|
+
results.checks.totalSize += stats.size;
|
|
515
|
+
|
|
516
|
+
if (stats.size < 50) { // Rules 파일은 최소 50바이트
|
|
517
|
+
results.checks.issues.push(`Rules file ${file} is too small (${stats.size} bytes)`);
|
|
518
|
+
results.success = false;
|
|
519
|
+
}
|
|
520
|
+
} catch (error) {
|
|
521
|
+
results.checks.issues.push(`Cannot read ${file}: ${error.message}`);
|
|
522
|
+
results.success = false;
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
// 5. 최소 파일 개수 검증
|
|
528
|
+
if (results.checks.fileCount < config.minFileCount) {
|
|
529
|
+
results.checks.issues.push(`Expected at least ${config.minFileCount} files, found ${results.checks.fileCount}`);
|
|
530
|
+
results.success = false;
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
} catch (error) {
|
|
534
|
+
results.success = false;
|
|
535
|
+
results.checks.issues.push(`Validation error: ${error.message}`);
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
return results;
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
// 개별 도구 검증 함수들
|
|
542
|
+
async function validateClaudeInstall() {
|
|
543
|
+
return await validateToolInstallation(ESSENTIAL_FILES.claudeCode);
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
async function validateGeminiInstall() {
|
|
547
|
+
return await validateToolInstallation(ESSENTIAL_FILES.geminiCLI);
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
async function validateCursorInstall() {
|
|
551
|
+
return await validateToolInstallation(ESSENTIAL_FILES.cursor);
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
async function validateWindsurfInstall() {
|
|
555
|
+
return await validateToolInstallation(ESSENTIAL_FILES.windsurf);
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
async function validateAIWFCore() {
|
|
559
|
+
return await validateToolInstallation(ESSENTIAL_FILES.aiwf);
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
// Legacy detailed validation (for backward compatibility)
|
|
563
|
+
async function validateInstallationDetailed() {
|
|
564
|
+
const validationResults = {
|
|
565
|
+
overall: {
|
|
566
|
+
success: true,
|
|
567
|
+
toolsChecked: 0,
|
|
568
|
+
toolsPassed: 0,
|
|
569
|
+
toolsFailed: 0,
|
|
570
|
+
totalIssues: 0
|
|
571
|
+
},
|
|
572
|
+
tools: {}
|
|
573
|
+
};
|
|
574
|
+
|
|
575
|
+
// AIWF 코어는 항상 검증
|
|
576
|
+
const aiwfResult = await validateAIWFCore();
|
|
577
|
+
validationResults.tools.aiwf = aiwfResult;
|
|
578
|
+
validationResults.overall.toolsChecked++;
|
|
579
|
+
|
|
580
|
+
if (aiwfResult.success) {
|
|
581
|
+
validationResults.overall.toolsPassed++;
|
|
582
|
+
} else {
|
|
583
|
+
validationResults.overall.toolsFailed++;
|
|
584
|
+
validationResults.overall.success = false;
|
|
585
|
+
validationResults.overall.totalIssues += aiwfResult.checks.issues.length;
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
// 모든 도구 검증 (이 간단한 버전에서는 항상 모든 도구 설치)
|
|
589
|
+
const toolValidators = {
|
|
590
|
+
claudeCode: validateClaudeInstall,
|
|
591
|
+
geminiCLI: validateGeminiInstall,
|
|
592
|
+
cursor: validateCursorInstall,
|
|
593
|
+
windsurf: validateWindsurfInstall
|
|
594
|
+
};
|
|
595
|
+
|
|
596
|
+
for (const [toolName, validator] of Object.entries(toolValidators)) {
|
|
597
|
+
const result = await validator();
|
|
598
|
+
validationResults.tools[toolName] = result;
|
|
599
|
+
validationResults.overall.toolsChecked++;
|
|
600
|
+
|
|
601
|
+
if (result.success) {
|
|
602
|
+
validationResults.overall.toolsPassed++;
|
|
603
|
+
} else {
|
|
604
|
+
validationResults.overall.toolsFailed++;
|
|
605
|
+
validationResults.overall.success = false;
|
|
606
|
+
validationResults.overall.totalIssues += result.checks.issues.length;
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
return validationResults;
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
// 향상된 설치 검증 함수 (선택적 도구 지원)
|
|
614
|
+
async function validateInstallationEnhanced(selectedTools = null, language = 'en') {
|
|
615
|
+
const validationResults = {
|
|
616
|
+
overall: {
|
|
617
|
+
success: true,
|
|
618
|
+
toolsChecked: 0,
|
|
619
|
+
toolsPassed: 0,
|
|
620
|
+
toolsFailed: 0,
|
|
621
|
+
totalIssues: 0
|
|
622
|
+
},
|
|
623
|
+
tools: {}
|
|
624
|
+
};
|
|
625
|
+
|
|
626
|
+
// AIWF 코어는 항상 검증
|
|
627
|
+
const aiwfResult = await validateAIWFCore();
|
|
628
|
+
validationResults.tools.aiwf = aiwfResult;
|
|
629
|
+
validationResults.overall.toolsChecked++;
|
|
630
|
+
|
|
631
|
+
if (aiwfResult.success) {
|
|
632
|
+
validationResults.overall.toolsPassed++;
|
|
633
|
+
} else {
|
|
634
|
+
validationResults.overall.toolsFailed++;
|
|
635
|
+
validationResults.overall.success = false;
|
|
636
|
+
validationResults.overall.totalIssues += aiwfResult.checks.issues.length;
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
// 도구 목록 결정 (선택된 도구 또는 모든 도구)
|
|
640
|
+
const toolsToValidate = selectedTools || ['claudeCode', 'geminiCLI', 'cursor', 'windsurf'];
|
|
641
|
+
|
|
642
|
+
const toolValidators = {
|
|
643
|
+
claudeCode: validateClaudeInstall,
|
|
644
|
+
geminiCLI: validateGeminiInstall,
|
|
645
|
+
cursor: validateCursorInstall,
|
|
646
|
+
windsurf: validateWindsurfInstall
|
|
647
|
+
};
|
|
648
|
+
|
|
649
|
+
for (const toolName of toolsToValidate) {
|
|
650
|
+
if (toolValidators[toolName]) {
|
|
651
|
+
const result = await toolValidators[toolName]();
|
|
652
|
+
validationResults.tools[toolName] = result;
|
|
653
|
+
validationResults.overall.toolsChecked++;
|
|
654
|
+
|
|
655
|
+
if (result.success) {
|
|
656
|
+
validationResults.overall.toolsPassed++;
|
|
657
|
+
} else {
|
|
658
|
+
validationResults.overall.toolsFailed++;
|
|
659
|
+
validationResults.overall.success = false;
|
|
660
|
+
validationResults.overall.totalIssues += result.checks.issues.length;
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
return validationResults;
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
// Display validation results for specification-compliant format
|
|
669
|
+
function displaySpecCompliantValidationResults(validationResults, language) {
|
|
670
|
+
const msg = messages[language];
|
|
671
|
+
|
|
672
|
+
console.log(chalk.blue('\n=== Installation Validation Results ==='));
|
|
673
|
+
|
|
674
|
+
// Success summary
|
|
675
|
+
if (validationResults.success.length > 0) {
|
|
676
|
+
console.log(chalk.green(`\n✅ Successfully Validated Tools (${validationResults.success.length}):`));
|
|
677
|
+
validationResults.success.forEach(tool => {
|
|
678
|
+
console.log(chalk.green(` ✓ ${tool}`));
|
|
679
|
+
});
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
// Failed summary
|
|
683
|
+
if (validationResults.failed.length > 0) {
|
|
684
|
+
console.log(chalk.red(`\n❌ Failed Validations (${validationResults.failed.length}):`));
|
|
685
|
+
validationResults.failed.forEach(({tool, reason}) => {
|
|
686
|
+
console.log(chalk.red(` ✗ ${tool}: ${reason}`));
|
|
687
|
+
});
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
// Warnings summary
|
|
691
|
+
if (validationResults.warnings.length > 0) {
|
|
692
|
+
console.log(chalk.yellow(`\n⚠️ Warnings (${validationResults.warnings.length}):`));
|
|
693
|
+
validationResults.warnings.forEach(warning => {
|
|
694
|
+
console.log(chalk.yellow(` ⚠ ${warning}`));
|
|
695
|
+
});
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
// Overall status
|
|
699
|
+
const isSuccess = validationResults.failed.length === 0;
|
|
700
|
+
const statusIcon = isSuccess ? '✅' : '❌';
|
|
701
|
+
const statusColor = isSuccess ? chalk.green : chalk.red;
|
|
702
|
+
const statusText = isSuccess ? 'PASSED' : 'FAILED';
|
|
703
|
+
|
|
704
|
+
console.log(statusColor(`\n${statusIcon} Overall Validation: ${statusText}`));
|
|
705
|
+
|
|
706
|
+
if (isSuccess) {
|
|
707
|
+
console.log(chalk.green('🎉 All selected tools are properly installed and validated!'));
|
|
708
|
+
} else {
|
|
709
|
+
console.log(chalk.yellow('⚠️ Some installations failed. See details above.'));
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
// Enhanced validation function with simplified interface for T05_S02
|
|
714
|
+
async function validateInstallation(selectedTools, language) {
|
|
715
|
+
const results = {
|
|
716
|
+
success: [],
|
|
717
|
+
failed: [],
|
|
718
|
+
warnings: []
|
|
719
|
+
};
|
|
720
|
+
|
|
721
|
+
// Always validate common files (AIWF core)
|
|
722
|
+
const commonValid = await validateCommonFiles();
|
|
723
|
+
if (!commonValid.success) {
|
|
724
|
+
results.failed.push({ tool: 'aiwf', reason: commonValid.reason });
|
|
725
|
+
} else {
|
|
726
|
+
results.success.push('aiwf');
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
// Validate selected tools
|
|
730
|
+
if (selectedTools && selectedTools.length > 0) {
|
|
731
|
+
for (const tool of selectedTools) {
|
|
732
|
+
const validation = await validateTool(tool);
|
|
733
|
+
if (validation.success) {
|
|
734
|
+
results.success.push(tool);
|
|
735
|
+
} else {
|
|
736
|
+
results.failed.push({ tool, reason: validation.reason });
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
} else {
|
|
740
|
+
// Default: validate all tools if no selection provided
|
|
741
|
+
const allTools = ['claudeCode', 'geminiCLI', 'cursor', 'windsurf'];
|
|
742
|
+
for (const tool of allTools) {
|
|
743
|
+
const validation = await validateTool(tool);
|
|
744
|
+
if (validation.success) {
|
|
745
|
+
results.success.push(tool);
|
|
746
|
+
} else {
|
|
747
|
+
results.failed.push({ tool, reason: validation.reason });
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
return results;
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
// Helper function to validate common/core files
|
|
756
|
+
async function validateCommonFiles() {
|
|
757
|
+
try {
|
|
758
|
+
const requiredFiles = [
|
|
759
|
+
'.aiwf/CLAUDE.md',
|
|
760
|
+
'.aiwf/00_PROJECT_MANIFEST.md'
|
|
761
|
+
];
|
|
762
|
+
|
|
763
|
+
for (const file of requiredFiles) {
|
|
764
|
+
const exists = await fs.access(file).then(() => true).catch(() => false);
|
|
765
|
+
if (!exists) {
|
|
766
|
+
return { success: false, reason: `Missing core file: ${file}` };
|
|
767
|
+
}
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
return { success: true };
|
|
771
|
+
} catch (error) {
|
|
772
|
+
return { success: false, reason: `Core validation error: ${error.message}` };
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
// Helper function to validate specific tools with simplified interface
|
|
777
|
+
async function validateTool(tool) {
|
|
778
|
+
switch (tool) {
|
|
779
|
+
case 'claudeCode':
|
|
780
|
+
case 'claude-code':
|
|
781
|
+
return validateClaudeCode();
|
|
782
|
+
case 'geminiCLI':
|
|
783
|
+
case 'gemini-cli':
|
|
784
|
+
return validateGeminiCLI();
|
|
785
|
+
case 'cursor':
|
|
786
|
+
return validateCursorTool();
|
|
787
|
+
case 'windsurf':
|
|
788
|
+
return validateWindsurfTool();
|
|
789
|
+
case 'aiwf':
|
|
790
|
+
return validateCommonFiles();
|
|
791
|
+
default:
|
|
792
|
+
return { success: false, reason: `Unknown tool: ${tool}` };
|
|
793
|
+
}
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
// Simplified tool validation functions
|
|
797
|
+
async function validateClaudeCode() {
|
|
798
|
+
try {
|
|
799
|
+
const requiredFiles = [
|
|
800
|
+
'.claude/commands/aiwf/aiwf_initialize.md',
|
|
801
|
+
'.claude/commands/aiwf/aiwf_do_task.md',
|
|
802
|
+
'.claude/commands/aiwf/aiwf_commit.md',
|
|
803
|
+
'.claude/commands/aiwf/aiwf_code_review.md'
|
|
804
|
+
];
|
|
805
|
+
|
|
806
|
+
for (const file of requiredFiles) {
|
|
807
|
+
const exists = await fs.access(file).then(() => true).catch(() => false);
|
|
808
|
+
if (!exists) {
|
|
809
|
+
return { success: false, reason: `Missing file: ${file}` };
|
|
810
|
+
}
|
|
811
|
+
}
|
|
812
|
+
|
|
813
|
+
return { success: true };
|
|
814
|
+
} catch (error) {
|
|
815
|
+
return { success: false, reason: `Claude Code validation error: ${error.message}` };
|
|
816
|
+
}
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
async function validateGeminiCLI() {
|
|
820
|
+
try {
|
|
821
|
+
// Check if .gemini/prompts/aiwf directory exists
|
|
822
|
+
const dirExists = await fs.access('.gemini/prompts/aiwf').then(() => true).catch(() => false);
|
|
823
|
+
if (!dirExists) {
|
|
824
|
+
return { success: false, reason: 'Missing Gemini-CLI prompts directory: .gemini/prompts/aiwf' };
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
return { success: true };
|
|
828
|
+
} catch (error) {
|
|
829
|
+
return { success: false, reason: `Gemini-CLI validation error: ${error.message}` };
|
|
830
|
+
}
|
|
831
|
+
}
|
|
832
|
+
|
|
833
|
+
async function validateCursorTool() {
|
|
834
|
+
try {
|
|
835
|
+
const dirExists = await fs.access('.cursor/rules').then(() => true).catch(() => false);
|
|
836
|
+
if (!dirExists) {
|
|
837
|
+
return { success: false, reason: 'Missing Cursor rules directory: .cursor/rules' };
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
return { success: true };
|
|
841
|
+
} catch (error) {
|
|
842
|
+
return { success: false, reason: `Cursor validation error: ${error.message}` };
|
|
843
|
+
}
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
async function validateWindsurfTool() {
|
|
847
|
+
try {
|
|
848
|
+
const dirExists = await fs.access('.windsurf/rules').then(() => true).catch(() => false);
|
|
849
|
+
if (!dirExists) {
|
|
850
|
+
return { success: false, reason: 'Missing Windsurf rules directory: .windsurf/rules' };
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
return { success: true };
|
|
854
|
+
} catch (error) {
|
|
855
|
+
return { success: false, reason: `Windsurf validation error: ${error.message}` };
|
|
856
|
+
}
|
|
857
|
+
}
|
|
858
|
+
|
|
859
|
+
// Enhanced rollback function for T05_S02
|
|
860
|
+
async function rollbackToolEnhanced(tool, backupDir, language = 'ko') {
|
|
861
|
+
const spinner = ora(`Rolling back ${tool}...`).start();
|
|
862
|
+
|
|
863
|
+
try {
|
|
864
|
+
// Get tool directory mapping
|
|
865
|
+
const toolDir = getToolDirectory(tool);
|
|
866
|
+
if (!toolDir) {
|
|
867
|
+
spinner.fail(`Unknown tool: ${tool}`);
|
|
868
|
+
return false;
|
|
869
|
+
}
|
|
870
|
+
|
|
871
|
+
// Remove installed directory
|
|
872
|
+
try {
|
|
873
|
+
await fs.access(toolDir);
|
|
874
|
+
await fs.rm(toolDir, { recursive: true, force: true });
|
|
875
|
+
spinner.text = `Removed ${toolDir}`;
|
|
876
|
+
} catch (error) {
|
|
877
|
+
// Directory doesn't exist, skip
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
// Restore from backup if available
|
|
881
|
+
if (backupDir) {
|
|
882
|
+
const backupFiles = await getBackupFilesForTool(tool, backupDir);
|
|
883
|
+
for (const backup of backupFiles) {
|
|
884
|
+
await restoreBackupFile(backup);
|
|
885
|
+
spinner.text = `Restored ${backup.originalPath}`;
|
|
886
|
+
}
|
|
887
|
+
}
|
|
888
|
+
|
|
889
|
+
spinner.succeed(`${tool} rolled back successfully`);
|
|
890
|
+
return true;
|
|
891
|
+
} catch (error) {
|
|
892
|
+
spinner.fail(`Failed to rollback ${tool}: ${error.message}`);
|
|
893
|
+
return false;
|
|
894
|
+
}
|
|
895
|
+
}
|
|
896
|
+
|
|
897
|
+
// Helper function to get tool directories
|
|
898
|
+
function getToolDirectory(tool) {
|
|
899
|
+
const toolDirs = {
|
|
900
|
+
claudeCode: '.claude/commands/aiwf',
|
|
901
|
+
'claude-code': '.claude/commands/aiwf',
|
|
902
|
+
geminiCLI: '.gemini/prompts/aiwf',
|
|
903
|
+
'gemini-cli': '.gemini/prompts/aiwf',
|
|
904
|
+
cursor: '.cursor/rules',
|
|
905
|
+
windsurf: '.windsurf/rules',
|
|
906
|
+
aiwf: '.aiwf'
|
|
907
|
+
};
|
|
908
|
+
|
|
909
|
+
return toolDirs[tool] || null;
|
|
910
|
+
}
|
|
911
|
+
|
|
912
|
+
// Helper function to restore backup file
|
|
913
|
+
async function restoreBackupFile(backup) {
|
|
914
|
+
try {
|
|
915
|
+
// Ensure target directory exists
|
|
916
|
+
const targetDir = path.dirname(backup.originalPath);
|
|
917
|
+
await fs.mkdir(targetDir, { recursive: true });
|
|
918
|
+
|
|
919
|
+
// Copy backup file to original location
|
|
920
|
+
await fs.copyFile(backup.backupFile, backup.originalPath);
|
|
921
|
+
} catch (error) {
|
|
922
|
+
throw new Error(`Failed to restore ${backup.originalPath}: ${error.message}`);
|
|
923
|
+
}
|
|
924
|
+
}
|
|
925
|
+
|
|
926
|
+
// Enhanced installation report generation function for T05_S02
|
|
927
|
+
function generateInstallationReportEnhanced(results, language) {
|
|
928
|
+
const msg = messages[language];
|
|
929
|
+
|
|
930
|
+
console.log('\n' + chalk.bold(language === 'ko' ? '📋 설치 리포트' : '📋 Installation Report'));
|
|
931
|
+
console.log('─'.repeat(50));
|
|
932
|
+
|
|
933
|
+
if (results.success.length > 0) {
|
|
934
|
+
console.log(chalk.green(language === 'ko' ? '✅ 성공적으로 설치된 도구:' : '✅ Successfully Installed Tools:'));
|
|
935
|
+
results.success.forEach(tool => {
|
|
936
|
+
console.log(chalk.green(` ✓ ${getToolName(tool, language)}`));
|
|
937
|
+
});
|
|
938
|
+
}
|
|
939
|
+
|
|
940
|
+
if (results.failed.length > 0) {
|
|
941
|
+
console.log(chalk.red(language === 'ko' ? '\n❌ 설치 실패한 도구:' : '\n❌ Failed to Install:'));
|
|
942
|
+
results.failed.forEach(({ tool, reason }) => {
|
|
943
|
+
console.log(chalk.red(` ✗ ${getToolName(tool, language)}: ${reason}`));
|
|
944
|
+
});
|
|
945
|
+
}
|
|
946
|
+
|
|
947
|
+
if (results.warnings.length > 0) {
|
|
948
|
+
console.log(chalk.yellow(language === 'ko' ? '\n⚠️ 경고:' : '\n⚠️ Warnings:'));
|
|
949
|
+
results.warnings.forEach(warning => {
|
|
950
|
+
console.log(chalk.yellow(` ⚠ ${warning}`));
|
|
951
|
+
});
|
|
952
|
+
}
|
|
953
|
+
|
|
954
|
+
console.log('─'.repeat(50));
|
|
955
|
+
}
|
|
956
|
+
|
|
957
|
+
// Helper function to get localized tool names
|
|
958
|
+
function getToolName(tool, language) {
|
|
959
|
+
const toolNames = {
|
|
960
|
+
ko: {
|
|
961
|
+
aiwf: 'AIWF 코어 구조',
|
|
962
|
+
claudeCode: 'Claude Code 명령어',
|
|
963
|
+
'claude-code': 'Claude Code 명령어',
|
|
964
|
+
geminiCLI: 'Gemini-CLI 프롬프트',
|
|
965
|
+
'gemini-cli': 'Gemini-CLI 프롬프트',
|
|
966
|
+
cursor: 'Cursor IDE 규칙',
|
|
967
|
+
windsurf: 'Windsurf IDE 규칙'
|
|
968
|
+
},
|
|
969
|
+
en: {
|
|
970
|
+
aiwf: 'AIWF Core Structure',
|
|
971
|
+
claudeCode: 'Claude Code Commands',
|
|
972
|
+
'claude-code': 'Claude Code Commands',
|
|
973
|
+
geminiCLI: 'Gemini-CLI Prompts',
|
|
974
|
+
'gemini-cli': 'Gemini-CLI Prompts',
|
|
975
|
+
cursor: 'Cursor IDE Rules',
|
|
976
|
+
windsurf: 'Windsurf IDE Rules'
|
|
977
|
+
}
|
|
978
|
+
};
|
|
979
|
+
|
|
980
|
+
return toolNames[language]?.[tool] || tool;
|
|
981
|
+
}
|
|
982
|
+
|
|
983
|
+
// Enhanced installation flow with validation and rollback for T05_S02
|
|
984
|
+
async function performInstallationStepEnhanced(language, selectedTools) {
|
|
985
|
+
try {
|
|
986
|
+
// ... installation performed by existing code ...
|
|
987
|
+
// This function would be integrated into the main installation flow
|
|
988
|
+
|
|
989
|
+
// After installation, perform validation
|
|
990
|
+
const validation = await validateInstallation(selectedTools, language);
|
|
991
|
+
|
|
992
|
+
// Handle failed tools with rollback
|
|
993
|
+
if (validation.failed.length > 0) {
|
|
994
|
+
console.log(chalk.yellow('\n⚠️ Some installations failed. Initiating rollback...'));
|
|
995
|
+
|
|
996
|
+
for (const { tool } of validation.failed) {
|
|
997
|
+
console.log(chalk.yellow(`Rolling back ${tool}...`));
|
|
998
|
+
await rollbackToolEnhanced(tool, BACKUP_DIR, language);
|
|
999
|
+
}
|
|
1000
|
+
}
|
|
1001
|
+
|
|
1002
|
+
// Generate installation report
|
|
1003
|
+
generateInstallationReportEnhanced(validation, language);
|
|
1004
|
+
|
|
1005
|
+
// Throw error if complete failure
|
|
1006
|
+
if (validation.success.length === 0) {
|
|
1007
|
+
const errorMsg = language === 'ko' ?
|
|
1008
|
+
'모든 설치가 실패했습니다.' :
|
|
1009
|
+
'All installations failed.';
|
|
1010
|
+
throw new Error(errorMsg);
|
|
1011
|
+
}
|
|
1012
|
+
|
|
1013
|
+
return validation;
|
|
1014
|
+
} catch (error) {
|
|
1015
|
+
console.error(chalk.red(`Installation step failed: ${error.message}`));
|
|
1016
|
+
throw error;
|
|
1017
|
+
}
|
|
1018
|
+
}
|
|
1019
|
+
|
|
1020
|
+
// 설치 리포트 생성 함수 (통합된 버전)
|
|
1021
|
+
function generateInstallationReport(validationResults, language, installationType = 'install') {
|
|
1022
|
+
const msg = messages[language];
|
|
1023
|
+
|
|
1024
|
+
// 상단 헤더
|
|
1025
|
+
console.log(chalk.blue.bold('\n' + '='.repeat(60)));
|
|
1026
|
+
console.log(chalk.blue.bold(
|
|
1027
|
+
language === 'ko' ?
|
|
1028
|
+
'🔍 AIWF 설치 검증 및 리포트' :
|
|
1029
|
+
'🔍 AIWF Installation Validation & Report'
|
|
1030
|
+
));
|
|
1031
|
+
console.log(chalk.blue.bold('='.repeat(60)));
|
|
1032
|
+
|
|
1033
|
+
// 설치 유형 표시
|
|
1034
|
+
const installTypeText = {
|
|
1035
|
+
install: language === 'ko' ? '새 설치' : 'Fresh Installation',
|
|
1036
|
+
update: language === 'ko' ? '업데이트' : 'Update',
|
|
1037
|
+
reinstall: language === 'ko' ? '재설치' : 'Reinstallation'
|
|
1038
|
+
};
|
|
1039
|
+
console.log(chalk.gray(`설치 유형 / Installation Type: ${installTypeText[installationType] || installTypeText.install}`));
|
|
1040
|
+
console.log(chalk.gray(`검증 시간 / Validation Time: ${new Date().toLocaleString()}`));
|
|
1041
|
+
|
|
1042
|
+
// 전체 요약
|
|
1043
|
+
const { overall } = validationResults;
|
|
1044
|
+
const statusIcon = overall.success ? '✅' : '❌';
|
|
1045
|
+
const statusColor = overall.success ? chalk.green : chalk.red;
|
|
1046
|
+
|
|
1047
|
+
console.log(statusColor(`\n${statusIcon} 전체 상태 / Overall Status: ${overall.success ? 'PASSED' : 'FAILED'}`));
|
|
1048
|
+
console.log(chalk.gray(` 검증한 도구 / Tools Checked: ${overall.toolsChecked}`));
|
|
1049
|
+
console.log(chalk.gray(` 성공한 도구 / Tools Passed: ${overall.toolsPassed}`));
|
|
1050
|
+
|
|
1051
|
+
if (overall.toolsFailed > 0) {
|
|
1052
|
+
console.log(chalk.red(` 실패한 도구 / Tools Failed: ${overall.toolsFailed}`));
|
|
1053
|
+
console.log(chalk.red(` 총 이슈 수 / Total Issues: ${overall.totalIssues}`));
|
|
1054
|
+
}
|
|
1055
|
+
|
|
1056
|
+
// 개별 도구 결과
|
|
1057
|
+
console.log(chalk.blue('\n=== 개별 도구 결과 / Individual Tool Results ==='));
|
|
1058
|
+
|
|
1059
|
+
for (const [toolName, result] of Object.entries(validationResults.tools)) {
|
|
1060
|
+
const toolIcon = result.success ? '✅' : '❌';
|
|
1061
|
+
const toolColor = result.success ? chalk.green : chalk.red;
|
|
1062
|
+
|
|
1063
|
+
console.log(toolColor(`\n${toolIcon} ${result.description} (${toolName})`));
|
|
1064
|
+
console.log(chalk.gray(` 디렉토리 / Directory: ${result.baseDir}`));
|
|
1065
|
+
console.log(chalk.gray(` 파일 수 / Files Found: ${result.checks.fileCount}`));
|
|
1066
|
+
console.log(chalk.gray(` 총 크기 / Total Size: ${(result.checks.totalSize / 1024).toFixed(2)} KB`));
|
|
1067
|
+
|
|
1068
|
+
if (result.checks.issues.length > 0) {
|
|
1069
|
+
console.log(chalk.red(` 이슈 / Issues:`));
|
|
1070
|
+
for (const issue of result.checks.issues) {
|
|
1071
|
+
console.log(chalk.red(` • ${issue}`));
|
|
1072
|
+
}
|
|
1073
|
+
}
|
|
1074
|
+
|
|
1075
|
+
if (result.checks.requiredFiles.length > 0) {
|
|
1076
|
+
console.log(chalk.gray(` 필수 파일 / Required Files:`));
|
|
1077
|
+
for (const fileCheck of result.checks.requiredFiles) {
|
|
1078
|
+
const fileIcon = fileCheck.valid ? '✅' : '❌';
|
|
1079
|
+
const fileColor = fileCheck.valid ? chalk.gray : chalk.red;
|
|
1080
|
+
console.log(fileColor(` ${fileIcon} ${fileCheck.file} (${(fileCheck.size / 1024).toFixed(2)} KB)`));
|
|
1081
|
+
}
|
|
1082
|
+
}
|
|
1083
|
+
}
|
|
1084
|
+
|
|
1085
|
+
// 권장사항 섹션
|
|
1086
|
+
console.log(chalk.blue('\n=== 권장사항 / Recommendations ==='));
|
|
1087
|
+
if (overall.success) {
|
|
1088
|
+
console.log(chalk.green('🎉 모든 도구가 올바르게 설치되어 검증되었습니다!'));
|
|
1089
|
+
console.log(chalk.green('🎉 All tools are properly installed and validated!'));
|
|
1090
|
+
console.log(chalk.blue('\n다음 단계 / Next Steps:'));
|
|
1091
|
+
console.log(chalk.white(' 1. Claude Code에서 프로젝트를 열어보세요'));
|
|
1092
|
+
console.log(chalk.white(' 2. /project:aiwf:initialize 명령어로 프로젝트를 초기화하세요'));
|
|
1093
|
+
console.log(chalk.white(' 3. 프로젝트 관리를 시작하세요!'));
|
|
1094
|
+
} else {
|
|
1095
|
+
console.log(chalk.yellow('⚠️ 일부 이슈가 발견되었습니다. 위의 세부사항을 확인하세요.'));
|
|
1096
|
+
console.log(chalk.yellow('⚠️ Some issues were found. See details above.'));
|
|
1097
|
+
|
|
1098
|
+
// 실패한 도구별 해결 방안 제시
|
|
1099
|
+
const failedTools = Object.entries(validationResults.tools)
|
|
1100
|
+
.filter(([_, result]) => !result.success)
|
|
1101
|
+
.map(([tool, _]) => tool);
|
|
1102
|
+
|
|
1103
|
+
if (failedTools.length > 0) {
|
|
1104
|
+
console.log(chalk.blue('\n해결 방안 / Solutions:'));
|
|
1105
|
+
console.log(chalk.yellow(' • 전체 재설치를 시도해보세요'));
|
|
1106
|
+
console.log(chalk.yellow(' • 실패한 도구만 롤백 후 다시 설치하세요'));
|
|
1107
|
+
console.log(chalk.yellow(' • 네트워크 연결을 확인하고 다시 시도하세요'));
|
|
1108
|
+
}
|
|
1109
|
+
}
|
|
1110
|
+
|
|
1111
|
+
console.log(chalk.blue.bold('\n' + '='.repeat(60)));
|
|
1112
|
+
}
|
|
1113
|
+
|
|
1114
|
+
// 검증 결과 표시 함수 (기존 함수는 유지, 새로운 리포트 함수와 함께 사용)
|
|
1115
|
+
function displayValidationResults(validationResults, language) {
|
|
1116
|
+
return generateInstallationReport(validationResults, language, 'install');
|
|
1117
|
+
}
|
|
1118
|
+
|
|
1119
|
+
// 도구별 디렉토리 매핑 함수 (중복 제거됨 - 위의 함수 사용)
|
|
1120
|
+
|
|
1121
|
+
// 특정 도구의 백업 파일 목록 가져오기
|
|
1122
|
+
async function getBackupFilesForTool(tool, backupDir) {
|
|
1123
|
+
const toolBackupFiles = [];
|
|
1124
|
+
|
|
1125
|
+
try {
|
|
1126
|
+
const backupFiles = await fs.readdir(backupDir);
|
|
1127
|
+
const toolDir = getToolDirectory(tool);
|
|
1128
|
+
|
|
1129
|
+
if (!toolDir) return toolBackupFiles;
|
|
1130
|
+
|
|
1131
|
+
// 도구별 백업 파일 패턴 매칭
|
|
1132
|
+
const patterns = {
|
|
1133
|
+
claudeCode: /^claude-commands-aiwf-.*\.bak$/,
|
|
1134
|
+
geminiCLI: /^gemini-prompts-aiwf-.*\.bak$/,
|
|
1135
|
+
cursor: /^cursor-rules-.*\.bak$/,
|
|
1136
|
+
windsurf: /^windsurf-rules-.*\.bak$/,
|
|
1137
|
+
aiwf: /^aiwf-.*\.bak$/
|
|
1138
|
+
};
|
|
1139
|
+
|
|
1140
|
+
const pattern = patterns[tool];
|
|
1141
|
+
if (pattern) {
|
|
1142
|
+
const matchingFiles = backupFiles.filter(file => pattern.test(file));
|
|
1143
|
+
for (const file of matchingFiles) {
|
|
1144
|
+
toolBackupFiles.push({
|
|
1145
|
+
backupFile: path.join(backupDir, file),
|
|
1146
|
+
originalPath: restoreOriginalPath(file, tool)
|
|
1147
|
+
});
|
|
1148
|
+
}
|
|
1149
|
+
}
|
|
1150
|
+
|
|
1151
|
+
} catch (error) {
|
|
1152
|
+
// 백업 디렉토리가 없거나 읽을 수 없는 경우
|
|
1153
|
+
}
|
|
1154
|
+
|
|
1155
|
+
return toolBackupFiles;
|
|
1156
|
+
}
|
|
1157
|
+
|
|
1158
|
+
// 백업 파일명에서 원본 경로 복원
|
|
1159
|
+
function restoreOriginalPath(backupFileName, tool) {
|
|
1160
|
+
const toolDirs = {
|
|
1161
|
+
claudeCode: '.claude/commands/aiwf',
|
|
1162
|
+
geminiCLI: '.gemini/prompts/aiwf',
|
|
1163
|
+
cursor: '.cursor/rules',
|
|
1164
|
+
windsurf: '.windsurf/rules',
|
|
1165
|
+
aiwf: '.aiwf'
|
|
1166
|
+
};
|
|
1167
|
+
|
|
1168
|
+
const baseDir = toolDirs[tool];
|
|
1169
|
+
if (!baseDir) return null;
|
|
1170
|
+
|
|
1171
|
+
// 백업 파일명에서 원본 파일명 추출
|
|
1172
|
+
let originalFileName = backupFileName;
|
|
1173
|
+
|
|
1174
|
+
// 도구별 프리픽스 제거
|
|
1175
|
+
const prefixes = {
|
|
1176
|
+
claudeCode: 'claude-commands-aiwf-',
|
|
1177
|
+
geminiCLI: 'gemini-prompts-aiwf-',
|
|
1178
|
+
cursor: 'cursor-rules-',
|
|
1179
|
+
windsurf: 'windsurf-rules-',
|
|
1180
|
+
aiwf: 'aiwf-'
|
|
1181
|
+
};
|
|
1182
|
+
|
|
1183
|
+
const prefix = prefixes[tool];
|
|
1184
|
+
if (prefix && originalFileName.startsWith(prefix)) {
|
|
1185
|
+
originalFileName = originalFileName.substring(prefix.length);
|
|
1186
|
+
}
|
|
1187
|
+
|
|
1188
|
+
// .bak 확장자 제거
|
|
1189
|
+
if (originalFileName.endsWith('.bak')) {
|
|
1190
|
+
originalFileName = originalFileName.substring(0, originalFileName.length - 4);
|
|
1191
|
+
}
|
|
1192
|
+
|
|
1193
|
+
// 하이픈을 슬래시로 복원 (하위 디렉토리 구조)
|
|
1194
|
+
originalFileName = originalFileName.replace(/-/g, '/');
|
|
1195
|
+
|
|
1196
|
+
return path.join(baseDir, originalFileName);
|
|
1197
|
+
}
|
|
1198
|
+
|
|
1199
|
+
// 개별 백업 파일 복원 (중복 제거됨 - 위의 함수 사용)
|
|
1200
|
+
|
|
1201
|
+
// 특정 도구 롤백 함수
|
|
1202
|
+
async function rollbackTool(tool, backupDir, language = 'ko') {
|
|
1203
|
+
const msg = messages[language];
|
|
1204
|
+
const spinner = ora(
|
|
1205
|
+
language === 'ko' ?
|
|
1206
|
+
`${tool} 도구를 롤백하는 중...` :
|
|
1207
|
+
`Rolling back ${tool}...`
|
|
1208
|
+
).start();
|
|
1209
|
+
|
|
1210
|
+
try {
|
|
1211
|
+
// 1. 해당 도구의 디렉토리 삭제
|
|
1212
|
+
const toolDir = getToolDirectory(tool);
|
|
1213
|
+
if (toolDir) {
|
|
1214
|
+
const dirExists = await fs.access(toolDir).then(() => true).catch(() => false);
|
|
1215
|
+
if (dirExists) {
|
|
1216
|
+
await fs.rm(toolDir, { recursive: true, force: true });
|
|
1217
|
+
spinner.text = language === 'ko' ?
|
|
1218
|
+
`${tool} 디렉토리 삭제 완료` :
|
|
1219
|
+
`${tool} directory removed`;
|
|
1220
|
+
}
|
|
1221
|
+
}
|
|
1222
|
+
|
|
1223
|
+
// 2. 백업에서 복원
|
|
1224
|
+
const backupFiles = await getBackupFilesForTool(tool, backupDir);
|
|
1225
|
+
let restoredCount = 0;
|
|
1226
|
+
|
|
1227
|
+
for (const backup of backupFiles) {
|
|
1228
|
+
const restored = await restoreBackupFile(backup);
|
|
1229
|
+
if (restored) {
|
|
1230
|
+
restoredCount++;
|
|
1231
|
+
}
|
|
1232
|
+
}
|
|
1233
|
+
|
|
1234
|
+
if (restoredCount > 0) {
|
|
1235
|
+
spinner.succeed(chalk.green(
|
|
1236
|
+
language === 'ko' ?
|
|
1237
|
+
`${tool} 롤백 완료 (${restoredCount}개 파일 복원)` :
|
|
1238
|
+
`${tool} rolled back successfully (${restoredCount} files restored)`
|
|
1239
|
+
));
|
|
1240
|
+
return { success: true, restoredCount };
|
|
1241
|
+
} else {
|
|
1242
|
+
spinner.warn(chalk.yellow(
|
|
1243
|
+
language === 'ko' ?
|
|
1244
|
+
`${tool} 롤백: 복원할 백업 파일이 없음` :
|
|
1245
|
+
`${tool} rollback: No backup files to restore`
|
|
1246
|
+
));
|
|
1247
|
+
return { success: true, restoredCount: 0 };
|
|
1248
|
+
}
|
|
1249
|
+
|
|
1250
|
+
} catch (error) {
|
|
1251
|
+
spinner.fail(chalk.red(
|
|
1252
|
+
language === 'ko' ?
|
|
1253
|
+
`${tool} 롤백 실패: ${error.message}` :
|
|
1254
|
+
`Failed to rollback ${tool}: ${error.message}`
|
|
1255
|
+
));
|
|
1256
|
+
return { success: false, error: error.message };
|
|
1257
|
+
}
|
|
1258
|
+
}
|
|
1259
|
+
|
|
1260
|
+
// =============================================================================
|
|
1261
|
+
// ROLLBACK SYSTEM IMPLEMENTATION
|
|
1262
|
+
// =============================================================================
|
|
1263
|
+
|
|
1264
|
+
// 도구별 디렉토리 경로 가져오기 (중복 제거됨 - 위의 getToolDirectory 함수 사용)
|
|
1265
|
+
|
|
1266
|
+
// 백업에서 특정 도구의 파일들 찾기 (중복 제거됨 - 위의 함수 사용)
|
|
1267
|
+
|
|
1268
|
+
// 백업 파일명에서 원래 경로 복원
|
|
1269
|
+
function restoreBackupPath(backupFileName, tool) {
|
|
1270
|
+
const toolDir = getToolDirectory(tool);
|
|
1271
|
+
if (!toolDir) return null;
|
|
1272
|
+
|
|
1273
|
+
// 백업 파일명 패턴: claude-commands-aiwf-foo.md.bak -> .claude/commands/aiwf/foo.md
|
|
1274
|
+
if (backupFileName.startsWith('claude-commands-aiwf-')) {
|
|
1275
|
+
const relativePath = backupFileName
|
|
1276
|
+
.replace('claude-commands-aiwf-', '')
|
|
1277
|
+
.replace('.bak', '')
|
|
1278
|
+
.replace(/-/g, '/');
|
|
1279
|
+
return path.join('.claude/commands/aiwf', relativePath);
|
|
1280
|
+
}
|
|
1281
|
+
|
|
1282
|
+
// 백업 파일명 패턴: aiwf-foo-bar.md.bak -> .aiwf/foo/bar.md
|
|
1283
|
+
if (backupFileName.startsWith('aiwf-')) {
|
|
1284
|
+
const relativePath = backupFileName
|
|
1285
|
+
.replace('aiwf-', '')
|
|
1286
|
+
.replace('.bak', '')
|
|
1287
|
+
.replace(/-/g, '/');
|
|
1288
|
+
return path.join('.aiwf', relativePath);
|
|
1289
|
+
}
|
|
1290
|
+
|
|
1291
|
+
// 기타 패턴
|
|
1292
|
+
return backupFileName.replace('.bak', '');
|
|
1293
|
+
}
|
|
1294
|
+
|
|
1295
|
+
// 개별 백업 파일 복원 (중복 제거됨 - 위의 함수 사용)
|
|
1296
|
+
|
|
1297
|
+
// 특정 도구 롤백 함수
|
|
1298
|
+
|
|
1299
|
+
// 다중 도구 롤백 함수
|
|
1300
|
+
async function rollbackMultipleTools(failedTools, backupDir, language = 'en') {
|
|
1301
|
+
const results = {
|
|
1302
|
+
success: [],
|
|
1303
|
+
failed: [],
|
|
1304
|
+
partial: []
|
|
1305
|
+
};
|
|
1306
|
+
|
|
1307
|
+
console.log(chalk.blue('\n🔄 Starting rollback process...'));
|
|
1308
|
+
|
|
1309
|
+
for (const toolInfo of failedTools) {
|
|
1310
|
+
const toolName = typeof toolInfo === 'string' ? toolInfo : toolInfo.tool;
|
|
1311
|
+
const rollbackResult = await rollbackTool(toolName, backupDir, language);
|
|
1312
|
+
|
|
1313
|
+
if (rollbackResult === true) {
|
|
1314
|
+
results.success.push(toolName);
|
|
1315
|
+
} else if (rollbackResult === false) {
|
|
1316
|
+
results.failed.push(toolName);
|
|
1317
|
+
} else {
|
|
1318
|
+
results.partial.push(toolName);
|
|
1319
|
+
}
|
|
1320
|
+
}
|
|
1321
|
+
|
|
1322
|
+
// 롤백 결과 요약
|
|
1323
|
+
console.log(chalk.blue('\n📋 Rollback Summary:'));
|
|
1324
|
+
if (results.success.length > 0) {
|
|
1325
|
+
console.log(chalk.green(`✅ Successfully rolled back: ${results.success.join(', ')}`));
|
|
1326
|
+
}
|
|
1327
|
+
if (results.partial.length > 0) {
|
|
1328
|
+
console.log(chalk.yellow(`⚠️ Partially rolled back: ${results.partial.join(', ')}`));
|
|
1329
|
+
}
|
|
1330
|
+
if (results.failed.length > 0) {
|
|
1331
|
+
console.log(chalk.red(`❌ Failed to rollback: ${results.failed.join(', ')}`));
|
|
1332
|
+
}
|
|
1333
|
+
|
|
1334
|
+
return results;
|
|
1335
|
+
}
|
|
1336
|
+
|
|
1337
|
+
// 개선된 재설치 옵션 제공 함수
|
|
1338
|
+
async function offerReinstallationOptions(validationResults, language) {
|
|
1339
|
+
console.log(chalk.yellow(
|
|
1340
|
+
language === 'ko' ?
|
|
1341
|
+
'\n⚠️ 일부 설치가 실패했습니다. 무엇을 하시겠습니까?' :
|
|
1342
|
+
'\n⚠️ Some installations failed. What would you like to do?'
|
|
1343
|
+
));
|
|
1344
|
+
|
|
1345
|
+
// 실패한 도구들 나열 - 새로운 형식에 맞게 수정
|
|
1346
|
+
const failedTools = validationResults.failed.map(({tool}) => tool);
|
|
1347
|
+
|
|
1348
|
+
if (failedTools.length > 0) {
|
|
1349
|
+
console.log(chalk.red(
|
|
1350
|
+
language === 'ko' ?
|
|
1351
|
+
`실패한 도구: ${failedTools.join(', ')}` :
|
|
1352
|
+
`Failed tools: ${failedTools.join(', ')}`
|
|
1353
|
+
));
|
|
1354
|
+
}
|
|
1355
|
+
|
|
1356
|
+
const response = await prompts({
|
|
1357
|
+
type: 'select',
|
|
1358
|
+
name: 'action',
|
|
1359
|
+
message: language === 'ko' ? '어떤 작업을 수행하시겠습니까?' : 'What would you like to do?',
|
|
1360
|
+
choices: [
|
|
1361
|
+
{
|
|
1362
|
+
title: language === 'ko' ? '전체 재설치' : 'Full reinstallation',
|
|
1363
|
+
value: 'reinstall'
|
|
1364
|
+
},
|
|
1365
|
+
{
|
|
1366
|
+
title: language === 'ko' ? '실패한 도구만 롤백' : 'Rollback failed tools only',
|
|
1367
|
+
value: 'rollback'
|
|
1368
|
+
},
|
|
1369
|
+
{
|
|
1370
|
+
title: language === 'ko' ? '현재 상태 유지' : 'Keep current state',
|
|
1371
|
+
value: 'keep'
|
|
1372
|
+
}
|
|
1373
|
+
]
|
|
1374
|
+
});
|
|
1375
|
+
|
|
1376
|
+
return response.action;
|
|
1377
|
+
}
|
|
1378
|
+
|
|
1379
|
+
// =============================================================================
|
|
1380
|
+
// ROLLBACK SYSTEM
|
|
1381
|
+
// =============================================================================
|
|
1382
|
+
|
|
1383
|
+
// 도구별 롤백 함수
|
|
1384
|
+
// 도구별 백업 복원 함수
|
|
1385
|
+
async function restoreToolFromBackup(tool, backupDir) {
|
|
1386
|
+
try {
|
|
1387
|
+
const backupFiles = await fs.readdir(backupDir);
|
|
1388
|
+
const toolBackups = backupFiles.filter(f => f.endsWith('.bak'));
|
|
1389
|
+
|
|
1390
|
+
for (const backup of toolBackups) {
|
|
1391
|
+
let shouldRestore = false;
|
|
1392
|
+
let originalPath = '';
|
|
1393
|
+
|
|
1394
|
+
// 도구별 백업 파일 패턴 매칭
|
|
1395
|
+
switch (tool) {
|
|
1396
|
+
case 'claudeCode':
|
|
1397
|
+
if (backup.startsWith('claude-commands-aiwf-')) {
|
|
1398
|
+
shouldRestore = true;
|
|
1399
|
+
const fileName = backup.replace('claude-commands-aiwf-', '').replace('.bak', '');
|
|
1400
|
+
originalPath = path.join('.claude/commands/aiwf', fileName);
|
|
1401
|
+
}
|
|
1402
|
+
break;
|
|
1403
|
+
case 'aiwf':
|
|
1404
|
+
if (backup.startsWith('aiwf-')) {
|
|
1405
|
+
shouldRestore = true;
|
|
1406
|
+
const relativePath = backup.replace('aiwf-', '').replace(/-/g, '/').replace('.bak', '');
|
|
1407
|
+
originalPath = '.aiwf/' + relativePath;
|
|
1408
|
+
}
|
|
1409
|
+
break;
|
|
1410
|
+
// cursor와 windsurf는 현재 백업하지 않음 (rules 파일은 동적 생성)
|
|
1411
|
+
}
|
|
1412
|
+
|
|
1413
|
+
if (shouldRestore) {
|
|
1414
|
+
const backupPath = path.join(backupDir, backup);
|
|
1415
|
+
await fs.mkdir(path.dirname(originalPath), { recursive: true });
|
|
1416
|
+
await fs.copyFile(backupPath, originalPath);
|
|
1417
|
+
}
|
|
1418
|
+
}
|
|
1419
|
+
} catch (error) {
|
|
1420
|
+
// 백업 복원 실패는 심각하지 않음
|
|
1421
|
+
console.warn(`Warning: Could not restore ${tool} from backup: ${error.message}`);
|
|
1422
|
+
}
|
|
1423
|
+
}
|
|
1424
|
+
|
|
1425
|
+
// 실패한 도구들에 대한 일괄 롤백
|
|
1426
|
+
async function rollbackFailedTools(failedTools, language) {
|
|
1427
|
+
const results = {
|
|
1428
|
+
success: [],
|
|
1429
|
+
failed: []
|
|
1430
|
+
};
|
|
1431
|
+
|
|
1432
|
+
for (const toolInfo of failedTools) {
|
|
1433
|
+
const tool = typeof toolInfo === 'object' ? toolInfo.tool : toolInfo;
|
|
1434
|
+
const rollbackSuccess = await rollbackTool(tool, language);
|
|
1435
|
+
|
|
1436
|
+
if (rollbackSuccess) {
|
|
1437
|
+
results.success.push(tool);
|
|
1438
|
+
} else {
|
|
1439
|
+
results.failed.push(tool);
|
|
1440
|
+
}
|
|
1441
|
+
}
|
|
1442
|
+
|
|
1443
|
+
return results;
|
|
1444
|
+
}
|
|
1445
|
+
|
|
1446
|
+
// =============================================================================
|
|
1447
|
+
// MAIN INSTALLATION FUNCTION
|
|
1448
|
+
// =============================================================================
|
|
1449
|
+
|
|
313
1450
|
async function installAIWF(options = {}) {
|
|
314
1451
|
const debugLog = options.debugLog || false;
|
|
315
1452
|
|
|
316
|
-
// 언어 선택
|
|
317
|
-
let selectedLanguage =
|
|
1453
|
+
// 지능적 언어 선택 시스템
|
|
1454
|
+
let selectedLanguage = DEFAULT_LANGUAGE;
|
|
1455
|
+
|
|
318
1456
|
if (!options.force) {
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
1457
|
+
// 1. 기존 설정이 있는지 확인
|
|
1458
|
+
const existingConfig = await loadUserLanguageConfig();
|
|
1459
|
+
|
|
1460
|
+
if (existingConfig && existingConfig.language) {
|
|
1461
|
+
selectedLanguage = existingConfig.language;
|
|
1462
|
+
console.log(chalk.blue(`🌐 기존 언어 설정을 사용합니다 / Using existing language setting: ${selectedLanguage}`));
|
|
1463
|
+
} else {
|
|
1464
|
+
// 2. 자동 언어 감지 시도
|
|
1465
|
+
const detectedLang = await detectLanguage();
|
|
1466
|
+
|
|
1467
|
+
console.log(chalk.gray(`🔍 시스템 언어 감지 / System language detected: ${detectedLang}`));
|
|
1468
|
+
|
|
1469
|
+
// 3. 사용자에게 언어 선택 제공 (감지된 언어를 기본값으로)
|
|
1470
|
+
const languageResponse = await prompts({
|
|
1471
|
+
type: 'select',
|
|
1472
|
+
name: 'language',
|
|
1473
|
+
message: 'Please select language / 언어를 선택해주세요:',
|
|
1474
|
+
choices: [
|
|
1475
|
+
{ title: 'English', value: 'en' },
|
|
1476
|
+
{ title: '한국어 (Korean)', value: 'ko' }
|
|
1477
|
+
],
|
|
1478
|
+
initial: SUPPORTED_LANGUAGES.indexOf(detectedLang) !== -1 ?
|
|
1479
|
+
SUPPORTED_LANGUAGES.indexOf(detectedLang) : 0
|
|
1480
|
+
});
|
|
328
1481
|
|
|
329
|
-
|
|
330
|
-
|
|
1482
|
+
if (languageResponse.language) {
|
|
1483
|
+
selectedLanguage = languageResponse.language;
|
|
1484
|
+
} else {
|
|
1485
|
+
selectedLanguage = detectedLang;
|
|
1486
|
+
}
|
|
1487
|
+
|
|
1488
|
+
// 4. 선택된 언어를 설정으로 저장
|
|
1489
|
+
try {
|
|
1490
|
+
await saveUserLanguageConfig(selectedLanguage, {
|
|
1491
|
+
autoDetect: true,
|
|
1492
|
+
fallback: DEFAULT_LANGUAGE
|
|
1493
|
+
});
|
|
1494
|
+
console.log(chalk.green(`✅ 언어 설정이 저장되었습니다 / Language preference saved: ${selectedLanguage}`));
|
|
1495
|
+
} catch (error) {
|
|
1496
|
+
console.warn(chalk.yellow(`⚠️ 언어 설정 저장 실패 / Failed to save language preference: ${error.message}`));
|
|
1497
|
+
}
|
|
1498
|
+
}
|
|
1499
|
+
} else {
|
|
1500
|
+
// Force 모드일 때도 자동 감지 시도
|
|
1501
|
+
try {
|
|
1502
|
+
selectedLanguage = await detectLanguage();
|
|
1503
|
+
} catch (error) {
|
|
1504
|
+
selectedLanguage = DEFAULT_LANGUAGE;
|
|
331
1505
|
}
|
|
332
1506
|
}
|
|
333
1507
|
|
|
@@ -337,8 +1511,8 @@ async function installAIWF(options = {}) {
|
|
|
337
1511
|
console.log(chalk.gray(msg.description));
|
|
338
1512
|
console.log(chalk.gray(msg.optimized));
|
|
339
1513
|
|
|
340
|
-
// 언어별 경로 설정
|
|
341
|
-
const languagePath = selectedLanguage
|
|
1514
|
+
// 언어별 경로 설정 (언어 유틸리티 사용)
|
|
1515
|
+
const languagePath = getInstallationLanguagePath(selectedLanguage);
|
|
342
1516
|
const GITHUB_CONTENT_LANGUAGE_PREFIX = `${GITHUB_CONTENT_PREFIX}/${languagePath}`;
|
|
343
1517
|
|
|
344
1518
|
const hasExisting = await checkExistingInstallation();
|
|
@@ -547,6 +1721,54 @@ async function installAIWF(options = {}) {
|
|
|
547
1721
|
console.log(chalk.gray(`\n${msg.checkDocs}`));
|
|
548
1722
|
}
|
|
549
1723
|
|
|
1724
|
+
// 설치 검증 실행
|
|
1725
|
+
console.log(chalk.blue('\n🔍 Installation Validation / 설치 검증을 시작합니다...'));
|
|
1726
|
+
// Use specification-compliant validation function
|
|
1727
|
+
const selectedTools = ['claude-code', 'cursor', 'windsurf']; // Default tools for this version
|
|
1728
|
+
const validationResults = await validateInstallation(selectedTools, selectedLanguage);
|
|
1729
|
+
displaySpecCompliantValidationResults(validationResults, selectedLanguage);
|
|
1730
|
+
|
|
1731
|
+
// 부분 실패 시 재설치/롤백 옵션 제공
|
|
1732
|
+
if (validationResults.failed.length > 0) {
|
|
1733
|
+
const action = await offerReinstallationOptions(validationResults, selectedLanguage);
|
|
1734
|
+
|
|
1735
|
+
if (action === 'reinstall') {
|
|
1736
|
+
console.log(chalk.blue('\n🔄 재설치를 시작합니다... / Starting reinstallation...'));
|
|
1737
|
+
// 재귀적으로 설치를 다시 시도 (한 번만)
|
|
1738
|
+
if (!options.isRetry) {
|
|
1739
|
+
return await installAIWF({ ...options, isRetry: true });
|
|
1740
|
+
}
|
|
1741
|
+
} else if (action === 'rollback') {
|
|
1742
|
+
console.log(chalk.blue('\n↩️ 실패한 도구를 롤백합니다... / Rolling back failed tools...'));
|
|
1743
|
+
|
|
1744
|
+
// 실패한 도구들만 롤백 - 새로운 형식에 맞게 수정
|
|
1745
|
+
const failedTools = validationResults.failed.map(({tool}) => tool);
|
|
1746
|
+
|
|
1747
|
+
let rollbackResults = {};
|
|
1748
|
+
for (const tool of failedTools) {
|
|
1749
|
+
if (BACKUP_DIR) {
|
|
1750
|
+
const rollbackResult = await rollbackTool(tool, BACKUP_DIR, selectedLanguage);
|
|
1751
|
+
rollbackResults[tool] = rollbackResult;
|
|
1752
|
+
}
|
|
1753
|
+
}
|
|
1754
|
+
|
|
1755
|
+
// 롤백 후 다시 검증
|
|
1756
|
+
console.log(chalk.blue('\n🔍 롤백 후 재검증... / Re-validating after rollback...'));
|
|
1757
|
+
const postRollbackValidation = await validateInstallation(selectedTools, selectedLanguage);
|
|
1758
|
+
displaySpecCompliantValidationResults(postRollbackValidation, selectedLanguage);
|
|
1759
|
+
|
|
1760
|
+
// 롤백 결과 요약
|
|
1761
|
+
console.log(chalk.blue('\n=== Rollback Summary / 롤백 요약 ==='));
|
|
1762
|
+
for (const [tool, result] of Object.entries(rollbackResults)) {
|
|
1763
|
+
if (result.success) {
|
|
1764
|
+
console.log(chalk.green(`✅ ${tool}: ${result.restoredCount} files restored`));
|
|
1765
|
+
} else {
|
|
1766
|
+
console.log(chalk.red(`❌ ${tool}: ${result.error}`));
|
|
1767
|
+
}
|
|
1768
|
+
}
|
|
1769
|
+
}
|
|
1770
|
+
}
|
|
1771
|
+
|
|
550
1772
|
console.log(chalk.green(msg.enjoy));
|
|
551
1773
|
|
|
552
1774
|
} catch (error) {
|
|
@@ -612,8 +1834,114 @@ async function restoreFromBackup(spinner, msg) {
|
|
|
612
1834
|
program
|
|
613
1835
|
.name('aiwf')
|
|
614
1836
|
.version('1.0.1')
|
|
615
|
-
.description('AIWF
|
|
1837
|
+
.description('AIWF - AI Workflow Framework');
|
|
1838
|
+
|
|
1839
|
+
// Install command (default action)
|
|
1840
|
+
program
|
|
1841
|
+
.command('install', { isDefault: true })
|
|
1842
|
+
.description('Install AIWF framework')
|
|
616
1843
|
.option('-f, --force', 'Force install without prompts')
|
|
617
1844
|
.action((options) => installAIWF({ ...options, debugLog: true }));
|
|
618
1845
|
|
|
1846
|
+
// AI Tool command
|
|
1847
|
+
program
|
|
1848
|
+
.command('ai-tool <subcommand> [tool-name]')
|
|
1849
|
+
.description('Manage AI tool integrations')
|
|
1850
|
+
.action(async (subcommand, toolName) => {
|
|
1851
|
+
const aiToolCmd = new AIToolCommand();
|
|
1852
|
+
const args = [subcommand];
|
|
1853
|
+
if (toolName) args.push(toolName);
|
|
1854
|
+
await aiToolCmd.execute(args);
|
|
1855
|
+
});
|
|
1856
|
+
|
|
1857
|
+
// Cache management commands
|
|
1858
|
+
const cache = program.command('cache');
|
|
1859
|
+
cache.description('Manage offline template cache');
|
|
1860
|
+
|
|
1861
|
+
cache
|
|
1862
|
+
.command('download')
|
|
1863
|
+
.description('Download templates for offline use')
|
|
1864
|
+
.option('--all', 'Download all templates')
|
|
1865
|
+
.option('--type <type>', 'Download specific type (ai-tools, projects)')
|
|
1866
|
+
.action(async (options) => {
|
|
1867
|
+
const cacheCLI = new CacheCLI();
|
|
1868
|
+
try {
|
|
1869
|
+
await cacheCLI.init();
|
|
1870
|
+
await cacheCLI.downloadCommand(options);
|
|
1871
|
+
} catch (error) {
|
|
1872
|
+
console.error(chalk.red('Cache download failed:', error.message));
|
|
1873
|
+
process.exit(1);
|
|
1874
|
+
} finally {
|
|
1875
|
+
await cacheCLI.cleanup();
|
|
1876
|
+
}
|
|
1877
|
+
});
|
|
1878
|
+
|
|
1879
|
+
cache
|
|
1880
|
+
.command('list')
|
|
1881
|
+
.description('List cached templates')
|
|
1882
|
+
.option('--type <type>', 'Filter by type (ai-tools, projects)')
|
|
1883
|
+
.action(async (options) => {
|
|
1884
|
+
const cacheCLI = new CacheCLI();
|
|
1885
|
+
try {
|
|
1886
|
+
await cacheCLI.init();
|
|
1887
|
+
await cacheCLI.listCommand(options);
|
|
1888
|
+
} catch (error) {
|
|
1889
|
+
console.error(chalk.red('Cache list failed:', error.message));
|
|
1890
|
+
process.exit(1);
|
|
1891
|
+
} finally {
|
|
1892
|
+
await cacheCLI.cleanup();
|
|
1893
|
+
}
|
|
1894
|
+
});
|
|
1895
|
+
|
|
1896
|
+
cache
|
|
1897
|
+
.command('clean')
|
|
1898
|
+
.description('Clean up cached templates')
|
|
1899
|
+
.option('--all', 'Clear all cached templates')
|
|
1900
|
+
.option('--max-age <days>', 'Maximum age in days (default: 7)', '7')
|
|
1901
|
+
.action(async (options) => {
|
|
1902
|
+
const cacheCLI = new CacheCLI();
|
|
1903
|
+
try {
|
|
1904
|
+
await cacheCLI.init();
|
|
1905
|
+
await cacheCLI.cleanCommand(options);
|
|
1906
|
+
} catch (error) {
|
|
1907
|
+
console.error(chalk.red('Cache clean failed:', error.message));
|
|
1908
|
+
process.exit(1);
|
|
1909
|
+
} finally {
|
|
1910
|
+
await cacheCLI.cleanup();
|
|
1911
|
+
}
|
|
1912
|
+
});
|
|
1913
|
+
|
|
1914
|
+
cache
|
|
1915
|
+
.command('update')
|
|
1916
|
+
.description('Check for template updates')
|
|
1917
|
+
.option('--install', 'Install available updates')
|
|
1918
|
+
.action(async (options) => {
|
|
1919
|
+
const cacheCLI = new CacheCLI();
|
|
1920
|
+
try {
|
|
1921
|
+
await cacheCLI.init();
|
|
1922
|
+
await cacheCLI.updateCommand(options);
|
|
1923
|
+
} catch (error) {
|
|
1924
|
+
console.error(chalk.red('Cache update failed:', error.message));
|
|
1925
|
+
process.exit(1);
|
|
1926
|
+
} finally {
|
|
1927
|
+
await cacheCLI.cleanup();
|
|
1928
|
+
}
|
|
1929
|
+
});
|
|
1930
|
+
|
|
1931
|
+
cache
|
|
1932
|
+
.command('status')
|
|
1933
|
+
.description('Show cache system status')
|
|
1934
|
+
.action(async () => {
|
|
1935
|
+
const cacheCLI = new CacheCLI();
|
|
1936
|
+
try {
|
|
1937
|
+
await cacheCLI.init();
|
|
1938
|
+
await cacheCLI.statusCommand();
|
|
1939
|
+
} catch (error) {
|
|
1940
|
+
console.error(chalk.red('Cache status failed:', error.message));
|
|
1941
|
+
process.exit(1);
|
|
1942
|
+
} finally {
|
|
1943
|
+
await cacheCLI.cleanup();
|
|
1944
|
+
}
|
|
1945
|
+
});
|
|
1946
|
+
|
|
619
1947
|
program.parse(process.argv);
|