aiwf 0.3.23 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (321) hide show
  1. package/.claude-plugin/marketplace.json +146 -0
  2. package/CHANGELOG.md +49 -1
  3. package/README.ko.md +118 -309
  4. package/README.md +68 -254
  5. package/docs/modernization/BROWNFIELD-GREENFIELD.ko.md +105 -0
  6. package/docs/modernization/CLAUDE-PLAN-REVIEW-2026-10-03.ko.md +77 -0
  7. package/docs/modernization/CLI-PRODUCTIVITY-REVIEWED-2026-10-03.ko.md +177 -0
  8. package/docs/modernization/CLI-PRODUCTIVITY.ko.md +193 -0
  9. package/docs/modernization/CORE-PACKAGE-PLAN.md +7 -0
  10. package/docs/modernization/DEEP-REVERSE-ENGINEERING.ko.md +88 -0
  11. package/docs/modernization/DELEGATION-OPTIONAL.ko.md +57 -0
  12. package/docs/modernization/DIRECTION.ko.md +56 -0
  13. package/docs/modernization/FULL-TEST-2026-10-03.md +49 -0
  14. package/docs/modernization/LEGACY-REMOVAL-PLAN.md +9 -0
  15. package/docs/modernization/PILOT-RESULT-2026-10-03.ko.md +85 -0
  16. package/docs/modernization/PILOT-UC-001.ko.md +79 -0
  17. package/docs/modernization/PLAN.md +28 -0
  18. package/docs/modernization/SKILLS.ko.md +105 -0
  19. package/docs/modernization/SPRINTABLE.ko.md +47 -0
  20. package/docs/modernization/SYNC-DOCS-VALIDATION-2026-10-04.ko.md +38 -0
  21. package/docs/modernization/VALIDATION.md +79 -0
  22. package/docs/modernization/evidence/example-review-packet.json +115 -0
  23. package/docs/modernization/evidence/example-spec-pin.json +48 -0
  24. package/docs/modernization/evidence/full-test-20261003/claude-lint.md +22 -0
  25. package/docs/modernization/evidence/full-test-20261003/claude-review-retry.md +56 -0
  26. package/docs/modernization/evidence/full-test-20261003/codex-review-packet.json +159 -0
  27. package/docs/modernization/evidence/full-test-20261003/src/expense.mjs +40 -0
  28. package/docs/modernization/evidence/full-test-20261003/summary.json +106 -0
  29. package/docs/modernization/evidence/full-test-20261003/tests/expense.test.mjs +61 -0
  30. package/docs/modernization/evidence/local-pilot-20261003/README.ko.md +40 -0
  31. package/docs/modernization/evidence/local-pilot-20261003/execution.json +1055 -0
  32. package/docs/modernization/evidence/local-pilot-20261003/maintenance/dependencies.json +24 -0
  33. package/docs/modernization/evidence/local-pilot-20261003/maintenance/dependencies.stderr.txt +0 -0
  34. package/docs/modernization/evidence/local-pilot-20261003/maintenance/dependencies.stdout.txt +5 -0
  35. package/docs/modernization/evidence/local-pilot-20261003/maintenance/docs.json +24 -0
  36. package/docs/modernization/evidence/local-pilot-20261003/maintenance/docs.stderr.txt +0 -0
  37. package/docs/modernization/evidence/local-pilot-20261003/maintenance/docs.stdout.txt +6 -0
  38. package/docs/modernization/evidence/local-pilot-20261003/maintenance/example.json +24 -0
  39. package/docs/modernization/evidence/local-pilot-20261003/maintenance/example.stderr.txt +0 -0
  40. package/docs/modernization/evidence/local-pilot-20261003/maintenance/example.stdout.txt +5 -0
  41. package/docs/modernization/evidence/local-pilot-20261003/maintenance/local-docs.json +24 -0
  42. package/docs/modernization/evidence/local-pilot-20261003/maintenance/local-docs.stderr.txt +0 -0
  43. package/docs/modernization/evidence/local-pilot-20261003/maintenance/local-docs.stdout.txt +6 -0
  44. package/docs/modernization/evidence/local-pilot-20261003/maintenance/node.json +23 -0
  45. package/docs/modernization/evidence/local-pilot-20261003/maintenance/node.stderr.txt +0 -0
  46. package/docs/modernization/evidence/local-pilot-20261003/maintenance/node.stdout.txt +535 -0
  47. package/docs/modernization/evidence/local-pilot-20261003/maintenance/provenance.json +24 -0
  48. package/docs/modernization/evidence/local-pilot-20261003/maintenance/provenance.stderr.txt +0 -0
  49. package/docs/modernization/evidence/local-pilot-20261003/maintenance/provenance.stdout.txt +5 -0
  50. package/docs/modernization/evidence/local-pilot-20261003/maintenance/readme-replay.json +24 -0
  51. package/docs/modernization/evidence/local-pilot-20261003/maintenance/readme-replay.stderr.txt +0 -0
  52. package/docs/modernization/evidence/local-pilot-20261003/maintenance/readme-replay.stdout.txt +273 -0
  53. package/docs/modernization/evidence/local-pilot-20261003/maintenance/upstream.json +24 -0
  54. package/docs/modernization/evidence/local-pilot-20261003/maintenance/upstream.stderr.txt +0 -0
  55. package/docs/modernization/evidence/local-pilot-20261003/maintenance/upstream.stdout.txt +7 -0
  56. package/docs/modernization/evidence/local-pilot-20261003/project/artifacts/archive-service.stderr.txt +0 -0
  57. package/docs/modernization/evidence/local-pilot-20261003/project/artifacts/archive-service.stdout.txt +148 -0
  58. package/docs/modernization/evidence/local-pilot-20261003/project/artifacts/archive-structure.stderr.txt +0 -0
  59. package/docs/modernization/evidence/local-pilot-20261003/project/artifacts/archive-structure.stdout.txt +9 -0
  60. package/docs/modernization/evidence/local-pilot-20261003/project/artifacts/baseline-check.stderr.txt +0 -0
  61. package/docs/modernization/evidence/local-pilot-20261003/project/artifacts/baseline-check.stdout.txt +67 -0
  62. package/docs/modernization/evidence/local-pilot-20261003/project/artifacts/baseline-evidence.json +34 -0
  63. package/docs/modernization/evidence/local-pilot-20261003/project/artifacts/baseline-packet.json +128 -0
  64. package/docs/modernization/evidence/local-pilot-20261003/project/artifacts/baseline-packet.stderr.txt +0 -0
  65. package/docs/modernization/evidence/local-pilot-20261003/project/artifacts/baseline-packet.stdout.txt +128 -0
  66. package/docs/modernization/evidence/local-pilot-20261003/project/artifacts/baseline-pin.json +54 -0
  67. package/docs/modernization/evidence/local-pilot-20261003/project/artifacts/baseline-pin.stderr.txt +0 -0
  68. package/docs/modernization/evidence/local-pilot-20261003/project/artifacts/baseline-pin.stdout.txt +60 -0
  69. package/docs/modernization/evidence/local-pilot-20261003/project/artifacts/baseline-readback.json +15 -0
  70. package/docs/modernization/evidence/local-pilot-20261003/project/artifacts/baseline-service.stderr.txt +0 -0
  71. package/docs/modernization/evidence/local-pilot-20261003/project/artifacts/baseline-service.stdout.txt +82 -0
  72. package/docs/modernization/evidence/local-pilot-20261003/project/artifacts/baseline-structure.stderr.txt +0 -0
  73. package/docs/modernization/evidence/local-pilot-20261003/project/artifacts/baseline-structure.stdout.txt +9 -0
  74. package/docs/modernization/evidence/local-pilot-20261003/project/artifacts/changed-check.stderr.txt +0 -0
  75. package/docs/modernization/evidence/local-pilot-20261003/project/artifacts/changed-check.stdout.txt +79 -0
  76. package/docs/modernization/evidence/local-pilot-20261003/project/artifacts/changed-packet-refused.stderr.txt +0 -0
  77. package/docs/modernization/evidence/local-pilot-20261003/project/artifacts/changed-packet-refused.stdout.txt +7 -0
  78. package/docs/modernization/evidence/local-pilot-20261003/project/artifacts/changed-pin-refresh.stderr.txt +0 -0
  79. package/docs/modernization/evidence/local-pilot-20261003/project/artifacts/changed-pin-refresh.stdout.txt +66 -0
  80. package/docs/modernization/evidence/local-pilot-20261003/project/artifacts/changed-pin.json +60 -0
  81. package/docs/modernization/evidence/local-pilot-20261003/project/artifacts/changed-structure.stderr.txt +0 -0
  82. package/docs/modernization/evidence/local-pilot-20261003/project/artifacts/changed-structure.stdout.txt +9 -0
  83. package/docs/modernization/evidence/local-pilot-20261003/project/artifacts/final-check.stderr.txt +0 -0
  84. package/docs/modernization/evidence/local-pilot-20261003/project/artifacts/final-check.stdout.txt +73 -0
  85. package/docs/modernization/evidence/local-pilot-20261003/project/artifacts/final-evidence.json +34 -0
  86. package/docs/modernization/evidence/local-pilot-20261003/project/artifacts/final-packet.json +134 -0
  87. package/docs/modernization/evidence/local-pilot-20261003/project/artifacts/final-packet.stderr.txt +0 -0
  88. package/docs/modernization/evidence/local-pilot-20261003/project/artifacts/final-packet.stdout.txt +134 -0
  89. package/docs/modernization/evidence/local-pilot-20261003/project/artifacts/final-readback.json +15 -0
  90. package/docs/modernization/evidence/local-pilot-20261003/project/artifacts/final-service.stderr.txt +0 -0
  91. package/docs/modernization/evidence/local-pilot-20261003/project/artifacts/final-service.stdout.txt +148 -0
  92. package/docs/modernization/evidence/local-pilot-20261003/project/artifacts/final-structure.stderr.txt +0 -0
  93. package/docs/modernization/evidence/local-pilot-20261003/project/artifacts/final-structure.stdout.txt +9 -0
  94. package/docs/modernization/evidence/local-pilot-20261003/project/artifacts/node-version.stderr.txt +0 -0
  95. package/docs/modernization/evidence/local-pilot-20261003/project/artifacts/node-version.stdout.txt +1 -0
  96. package/docs/modernization/evidence/local-pilot-20261003/project/artifacts/python-version.stderr.txt +0 -0
  97. package/docs/modernization/evidence/local-pilot-20261003/project/artifacts/python-version.stdout.txt +1 -0
  98. package/docs/modernization/evidence/local-pilot-20261003/project/artifacts/red-evidence.json +34 -0
  99. package/docs/modernization/evidence/local-pilot-20261003/project/artifacts/red-packet.json +134 -0
  100. package/docs/modernization/evidence/local-pilot-20261003/project/artifacts/red-packet.stderr.txt +0 -0
  101. package/docs/modernization/evidence/local-pilot-20261003/project/artifacts/red-packet.stdout.txt +134 -0
  102. package/docs/modernization/evidence/local-pilot-20261003/project/artifacts/red-readback.json +15 -0
  103. package/docs/modernization/evidence/local-pilot-20261003/project/artifacts/red-service.stderr.txt +0 -0
  104. package/docs/modernization/evidence/local-pilot-20261003/project/artifacts/red-service.stdout.txt +266 -0
  105. package/docs/modernization/evidence/local-pilot-20261003/project/artifacts/red-structure.stderr.txt +0 -0
  106. package/docs/modernization/evidence/local-pilot-20261003/project/artifacts/red-structure.stdout.txt +9 -0
  107. package/docs/modernization/evidence/local-pilot-20261003/project/docs/entity_model.md +33 -0
  108. package/docs/modernization/evidence/local-pilot-20261003/project/docs/glossary.md +9 -0
  109. package/docs/modernization/evidence/local-pilot-20261003/project/docs/plans/UC-001.md +20 -0
  110. package/docs/modernization/evidence/local-pilot-20261003/project/docs/requirements.md +10 -0
  111. package/docs/modernization/evidence/local-pilot-20261003/project/docs/test_cases/TC-001-submit-expense.md +37 -0
  112. package/docs/modernization/evidence/local-pilot-20261003/project/docs/test_cases/TC-002-description-limit.md +42 -0
  113. package/docs/modernization/evidence/local-pilot-20261003/project/docs/use_cases/UC-001-submit-expense.md +76 -0
  114. package/docs/modernization/evidence/local-pilot-20261003/project/docs/use_cases.puml +12 -0
  115. package/docs/modernization/evidence/local-pilot-20261003/project/docs/vision.md +21 -0
  116. package/docs/modernization/evidence/local-pilot-20261003/project/src/expense.mjs +48 -0
  117. package/docs/modernization/evidence/local-pilot-20261003/project/tests/expense.test.mjs +116 -0
  118. package/docs/modernization/evidence/local-pilot-20261003/scope.json +31 -0
  119. package/docs/modernization/reviews/2026-10-03-claude-cli/CONTRACTS.ko.md +122 -0
  120. package/docs/modernization/reviews/2026-10-03-claude-cli/DIRECTION.ko.md +84 -0
  121. package/examples/spec-workflow/README.md +54 -0
  122. package/examples/spec-workflow/docs/entity_model.md +33 -0
  123. package/examples/spec-workflow/docs/glossary.md +9 -0
  124. package/examples/spec-workflow/docs/requirements.md +10 -0
  125. package/examples/spec-workflow/docs/test_cases/TC-001-submit-expense.md +37 -0
  126. package/examples/spec-workflow/docs/use_cases/UC-001-submit-expense.md +63 -0
  127. package/examples/spec-workflow/docs/use_cases.puml +12 -0
  128. package/examples/spec-workflow/docs/vision.md +21 -0
  129. package/package.json +37 -105
  130. package/plugins/aiwf-angular-jpa/.claude-plugin/plugin.json +11 -0
  131. package/plugins/aiwf-angular-jpa/LICENSE +201 -0
  132. package/plugins/aiwf-angular-jpa/NOTICE +16 -0
  133. package/plugins/aiwf-angular-jpa/README.md +54 -0
  134. package/plugins/aiwf-angular-jpa/UPSTREAM.json +35 -0
  135. package/plugins/aiwf-angular-jpa/agents/uc-coverage.md +263 -0
  136. package/plugins/aiwf-angular-jpa/rules/mcp-servers.md +64 -0
  137. package/plugins/aiwf-angular-jpa/skills/coverage-check/SKILL.md +190 -0
  138. package/plugins/aiwf-angular-jpa/skills/flyway-migration/SKILL.md +119 -0
  139. package/plugins/aiwf-angular-jpa/skills/implement/SKILL.md +528 -0
  140. package/plugins/aiwf-angular-jpa/skills/implement/references/module-layout.md +95 -0
  141. package/plugins/aiwf-angular-jpa/skills/playwright-test/SKILL.md +360 -0
  142. package/plugins/aiwf-angular-jpa/skills/spring-boot-test/SKILL.md +504 -0
  143. package/plugins/aiwf-angular-jpa/skills/vitest-test/SKILL.md +309 -0
  144. package/plugins/aiwf-blazor-dotnet/.claude-plugin/plugin.json +11 -0
  145. package/plugins/aiwf-blazor-dotnet/LICENSE +201 -0
  146. package/plugins/aiwf-blazor-dotnet/NOTICE +16 -0
  147. package/plugins/aiwf-blazor-dotnet/README.md +53 -0
  148. package/plugins/aiwf-blazor-dotnet/UPSTREAM.json +31 -0
  149. package/plugins/aiwf-blazor-dotnet/rules/mcp-servers.md +25 -0
  150. package/plugins/aiwf-blazor-dotnet/skills/bunit-test/SKILL.md +110 -0
  151. package/plugins/aiwf-blazor-dotnet/skills/dotnet-test/SKILL.md +108 -0
  152. package/plugins/aiwf-blazor-dotnet/skills/ef-migration/SKILL.md +43 -0
  153. package/plugins/aiwf-blazor-dotnet/skills/implement/SKILL.md +149 -0
  154. package/plugins/aiwf-blazor-dotnet/skills/playwright-test/SKILL.md +130 -0
  155. package/plugins/aiwf-core/.claude-plugin/plugin.json +11 -0
  156. package/plugins/aiwf-core/LICENSE +201 -0
  157. package/plugins/aiwf-core/NOTICE +20 -0
  158. package/plugins/aiwf-core/README.md +38 -0
  159. package/plugins/aiwf-core/UPSTREAM.json +50 -0
  160. package/plugins/aiwf-core/skills/entity-model/SKILL.md +160 -0
  161. package/plugins/aiwf-core/skills/entity-model/references/REFERENCE.md +36 -0
  162. package/plugins/aiwf-core/skills/requirements/SKILL.md +157 -0
  163. package/plugins/aiwf-core/skills/requirements/references/REFERENCE.md +70 -0
  164. package/plugins/aiwf-core/skills/requirements/references/glossary.md +7 -0
  165. package/plugins/aiwf-core/skills/reverse-engineer/SKILL.md +509 -0
  166. package/plugins/aiwf-core/skills/reverse-engineer/references/stack-signals.md +210 -0
  167. package/plugins/aiwf-core/skills/spec-review/SKILL.md +197 -0
  168. package/plugins/aiwf-core/skills/spec-review/references/lint-codes.md +63 -0
  169. package/plugins/aiwf-core/skills/spec-review/references/review-checklist.md +189 -0
  170. package/plugins/aiwf-core/skills/spec-review/scripts/spec_lint.py +1216 -0
  171. package/plugins/aiwf-core/skills/test-case/SKILL.md +138 -0
  172. package/plugins/aiwf-core/skills/test-case/references/example-process.bpmn +118 -0
  173. package/plugins/aiwf-core/skills/test-case/references/example.md +38 -0
  174. package/plugins/aiwf-core/skills/test-case/references/test-case.md +35 -0
  175. package/plugins/aiwf-core/skills/test-case/scripts/bpmn_paths.py +542 -0
  176. package/plugins/aiwf-core/skills/use-case-diagram/SKILL.md +99 -0
  177. package/plugins/aiwf-core/skills/use-case-spec/SKILL.md +257 -0
  178. package/plugins/aiwf-core/skills/use-case-spec/references/clarify-checklist.md +70 -0
  179. package/plugins/aiwf-core/skills/use-case-spec/references/example.md +88 -0
  180. package/plugins/aiwf-core/skills/use-case-spec/references/format-spec.md +246 -0
  181. package/plugins/aiwf-core/skills/use-case-spec/references/use-case.md +50 -0
  182. package/plugins/aiwf-core/skills/use-case-spec/scripts/validate_use_case.py +941 -0
  183. package/plugins/aiwf-delegate-claude/.claude-plugin/plugin.json +9 -0
  184. package/plugins/aiwf-delegate-claude/LICENSE +21 -0
  185. package/plugins/aiwf-delegate-claude/NOTICE +4 -0
  186. package/plugins/aiwf-delegate-claude/README.md +10 -0
  187. package/plugins/aiwf-delegate-claude/plugin.json +13 -0
  188. package/plugins/aiwf-delegate-claude/skills/delegate-claude/LICENSE +21 -0
  189. package/plugins/aiwf-delegate-claude/skills/delegate-claude/NOTICE +4 -0
  190. package/plugins/aiwf-delegate-claude/skills/delegate-claude/SKILL.md +49 -0
  191. package/plugins/aiwf-delegate-claude/skills/delegate-claude/agents/openai.yaml +2 -0
  192. package/plugins/aiwf-delegate-codex/.claude-plugin/plugin.json +9 -0
  193. package/plugins/aiwf-delegate-codex/LICENSE +21 -0
  194. package/plugins/aiwf-delegate-codex/NOTICE +4 -0
  195. package/plugins/aiwf-delegate-codex/README.md +10 -0
  196. package/plugins/aiwf-delegate-codex/plugin.json +13 -0
  197. package/plugins/aiwf-delegate-codex/skills/delegate-codex/LICENSE +21 -0
  198. package/plugins/aiwf-delegate-codex/skills/delegate-codex/NOTICE +4 -0
  199. package/plugins/aiwf-delegate-codex/skills/delegate-codex/SKILL.md +47 -0
  200. package/plugins/aiwf-delegate-codex/skills/delegate-codex/agents/openai.yaml +2 -0
  201. package/plugins/aiwf-nestjs-nextjs/.claude-plugin/plugin.json +11 -0
  202. package/plugins/aiwf-nestjs-nextjs/LICENSE +201 -0
  203. package/plugins/aiwf-nestjs-nextjs/NOTICE +16 -0
  204. package/plugins/aiwf-nestjs-nextjs/README.md +53 -0
  205. package/plugins/aiwf-nestjs-nextjs/UPSTREAM.json +32 -0
  206. package/plugins/aiwf-nestjs-nextjs/rules/mcp-servers.md +59 -0
  207. package/plugins/aiwf-nestjs-nextjs/skills/drizzle-migration/SKILL.md +222 -0
  208. package/plugins/aiwf-nestjs-nextjs/skills/implement/SKILL.md +393 -0
  209. package/plugins/aiwf-nestjs-nextjs/skills/implement/references/project-layout.md +158 -0
  210. package/plugins/aiwf-nestjs-nextjs/skills/nest-test/SKILL.md +300 -0
  211. package/plugins/aiwf-nestjs-nextjs/skills/playwright-test/SKILL.md +245 -0
  212. package/plugins/aiwf-nestjs-nextjs/skills/react-test/SKILL.md +217 -0
  213. package/plugins/aiwf-spec/.claude-plugin/plugin.json +9 -0
  214. package/plugins/aiwf-spec/LICENSE +201 -0
  215. package/plugins/aiwf-spec/NOTICE +20 -0
  216. package/plugins/aiwf-spec/README.md +36 -0
  217. package/plugins/aiwf-spec/skills/sync-docs/SKILL.md +47 -0
  218. package/plugins/aiwf-spec/skills/workflow/SKILL.md +42 -0
  219. package/plugins/aiwf-vaadin-jooq/.claude-plugin/plugin.json +11 -0
  220. package/plugins/aiwf-vaadin-jooq/LICENSE +201 -0
  221. package/plugins/aiwf-vaadin-jooq/NOTICE +16 -0
  222. package/plugins/aiwf-vaadin-jooq/README.md +56 -0
  223. package/plugins/aiwf-vaadin-jooq/UPSTREAM.json +43 -0
  224. package/plugins/aiwf-vaadin-jooq/agents/uc-coverage.md +260 -0
  225. package/plugins/aiwf-vaadin-jooq/rules/mcp-servers.md +44 -0
  226. package/plugins/aiwf-vaadin-jooq/skills/browserless-test/SKILL.md +407 -0
  227. package/plugins/aiwf-vaadin-jooq/skills/browserless-test/references/UC001ManagePersonsTest.java +111 -0
  228. package/plugins/aiwf-vaadin-jooq/skills/coverage-check/SKILL.md +190 -0
  229. package/plugins/aiwf-vaadin-jooq/skills/flyway-migration/SKILL.md +70 -0
  230. package/plugins/aiwf-vaadin-jooq/skills/hilla-test/SKILL.md +350 -0
  231. package/plugins/aiwf-vaadin-jooq/skills/hilla-test/references/UC001ManagePersonsServiceTest.java +81 -0
  232. package/plugins/aiwf-vaadin-jooq/skills/hilla-test/references/UC001ManagePersonsViewTest.tsx +87 -0
  233. package/plugins/aiwf-vaadin-jooq/skills/implement/SKILL.md +196 -0
  234. package/plugins/aiwf-vaadin-jooq/skills/implement-hilla/SKILL.md +216 -0
  235. package/plugins/aiwf-vaadin-jooq/skills/karibu-test/SKILL.md +298 -0
  236. package/plugins/aiwf-vaadin-jooq/skills/karibu-test/references/UC001ManagePersonsTest.java +93 -0
  237. package/plugins/aiwf-vaadin-jooq/skills/playwright-test/SKILL.md +237 -0
  238. package/plugins/aiwf-vaadin-jooq/skills/playwright-test/references/ExampleViewIT.java +143 -0
  239. package/plugins/aiwf-vaadin-jooq/skills/playwright-test/references/TC001CustomerOnboardingIT.java +144 -0
  240. package/plugins/aiwf-vaadin-jooq/skills/playwright-test/references/dramafinder-api.md +190 -0
  241. package/scripts/check-dependencies.js +26 -96
  242. package/scripts/install-spec-skills.mjs +126 -0
  243. package/scripts/validate-spec-plugin.mjs +145 -0
  244. package/src/cli/spec-cli.js +292 -0
  245. package/src/lib/spec-workflow.js +982 -0
  246. package/docs/ADR_MANAGEMENT_GUIDE.ko.md +0 -602
  247. package/docs/ADR_MANAGEMENT_GUIDE.md +0 -602
  248. package/docs/AI-WORKFLOW.ko.md +0 -299
  249. package/docs/AI-WORKFLOW.md +0 -401
  250. package/docs/API_REFERENCE_FULL.ko.md +0 -1135
  251. package/docs/API_REFERENCE_FULL.md +0 -1135
  252. package/docs/ARCHITECTURE.ko.md +0 -314
  253. package/docs/ARCHITECTURE.md +0 -314
  254. package/docs/CLI_USAGE_GUIDE.ko.md +0 -634
  255. package/docs/CLI_USAGE_GUIDE.md +0 -640
  256. package/docs/CODE_CLEANUP_GUIDE.ko.md +0 -415
  257. package/docs/CODE_CLEANUP_GUIDE.md +0 -415
  258. package/docs/COMMANDS_GUIDE.ko.md +0 -1037
  259. package/docs/COMMANDS_GUIDE.md +0 -1037
  260. package/docs/CONTRIBUTING.ko.md +0 -408
  261. package/docs/CONTRIBUTING.md +0 -408
  262. package/docs/DEVELOPMENT_GUIDE.ko.md +0 -440
  263. package/docs/DEVELOPMENT_GUIDE.md +0 -727
  264. package/docs/EXAMPLES.ko.md +0 -695
  265. package/docs/EXAMPLES.md +0 -693
  266. package/docs/GETTING_STARTED.ko.md +0 -219
  267. package/docs/GETTING_STARTED.md +0 -476
  268. package/docs/MODULE_MANAGEMENT_GUIDE.ko.md +0 -289
  269. package/docs/MODULE_MANAGEMENT_GUIDE.md +0 -289
  270. package/docs/PERFORMANCE_ARCHITECTURE.md +0 -494
  271. package/docs/PERFORMANCE_GUIDELINES.ko.md +0 -388
  272. package/docs/PERFORMANCE_GUIDELINES.md +0 -553
  273. package/docs/PRD.ko.md +0 -148
  274. package/docs/PRD.md +0 -150
  275. package/docs/ROADMAP_v0.4.0.md +0 -286
  276. package/docs/STATE_MANAGEMENT_GUIDE.ko.md +0 -278
  277. package/docs/STATE_MANAGEMENT_GUIDE.md +0 -278
  278. package/docs/TROUBLESHOOTING.ko.md +0 -366
  279. package/docs/TROUBLESHOOTING.md +0 -722
  280. package/docs/VALIDATOR_API.ko.md +0 -324
  281. package/docs/VALIDATOR_API.md +0 -324
  282. package/docs/YOLO_SYSTEM_GUIDE.ko.md +0 -542
  283. package/docs/YOLO_SYSTEM_GUIDE.md +0 -542
  284. package/docs/designs/AI_PERSONA_SYSTEM_DESIGN.md +0 -516
  285. package/docs/designs/API_DOCUMENTATION.md +0 -932
  286. package/docs/designs/API_REFERENCE.md +0 -979
  287. package/docs/designs/Enhanced_Installation_Flow_Design.md +0 -498
  288. package/docs/designs/aiwf-metadata-system-prd.md +0 -127
  289. package/docs/designs/offline-template-cache.md +0 -323
  290. package/docs/designs/persona-aware-compression.md +0 -168
  291. package/docs/guides/ai-personas-guide-ko.md +0 -239
  292. package/docs/guides/ai-personas-guide.md +0 -239
  293. package/docs/guides/checkpoint-system-guide-ko.md +0 -356
  294. package/docs/guides/checkpoint-system-guide.md +0 -356
  295. package/docs/guides/context-compression-guide-ko.md +0 -313
  296. package/docs/guides/context-compression-guide.md +0 -313
  297. package/docs/guides/independent-sprint-guide-ko.md +0 -321
  298. package/docs/guides/independent-sprint-guide.md +0 -321
  299. package/rules/global/aiwf-code-style-guide.md +0 -30
  300. package/rules/global/aiwf-coding-principles.md +0 -33
  301. package/rules/global/aiwf-development-process.md +0 -41
  302. package/rules/global/aiwf-global-rules.md +0 -84
  303. package/rules/manual/aiwf-generate-plan-docs.md +0 -280
  304. package/scripts/run-integration-tests.js +0 -317
  305. package/scripts/update-file-lists.js +0 -267
  306. package/scripts/validate-commands.js +0 -254
  307. package/src/cli/index.js +0 -184
  308. package/src/commands/sprint-independent.js +0 -393
  309. package/src/commands/state.js +0 -1164
  310. package/src/commands/yolo-config.js +0 -502
  311. package/src/config/file-lists.js +0 -147
  312. package/src/config/yolo-config-template.yaml +0 -168
  313. package/src/lib/backup-manager.js +0 -271
  314. package/src/lib/file-downloader.js +0 -304
  315. package/src/lib/installer.js +0 -1270
  316. package/src/lib/rollback-manager.js +0 -418
  317. package/src/lib/validator.js +0 -376
  318. package/src/utils/checkpoint-manager.js +0 -435
  319. package/src/utils/language-utils.js +0 -331
  320. package/src/utils/messages.js +0 -190
  321. package/src/utils/paths.js +0 -112
@@ -1,1270 +0,0 @@
1
- import fs from 'fs/promises';
2
- import path from 'path';
3
- import os from 'os';
4
- import ora from 'ora';
5
- import chalk from 'chalk';
6
- import prompts from 'prompts';
7
- import {
8
- fetchContent,
9
- downloadFile,
10
- downloadDirectory,
11
- GITHUB_RAW_URL,
12
- GITHUB_CONTENT_PREFIX
13
- } from './file-downloader.js';
14
- import {
15
- backupCommandsAndDocs,
16
- restoreFromBackup,
17
- getCurrentBackupDir,
18
- setBackupDir
19
- } from './backup-manager.js';
20
- import { getMessages } from '../utils/messages.js';
21
- import {
22
- validateInstallation,
23
- displaySpecCompliantValidationResults
24
- } from './validator.js';
25
- import { rollbackTool } from './rollback-manager.js';
26
- import {
27
- detectLanguage,
28
- loadUserLanguageConfig,
29
- saveUserLanguageConfig,
30
- getInstallationLanguagePath,
31
- SUPPORTED_LANGUAGES,
32
- DEFAULT_LANGUAGE
33
- } from '../utils/language-utils.js';
34
- import {
35
- FILES,
36
- TOOL_DIRS,
37
- AIWF_DIRS,
38
- BASE_DIRS,
39
- getAllAiwfDirectories,
40
- getAllClaudeMdFiles
41
- } from '../utils/paths.js';
42
-
43
- /**
44
- * Check if AIWF is already installed
45
- * @returns {Promise<boolean>} Installation status
46
- */
47
- async function checkExistingInstallation() {
48
- const flagExists = await fs
49
- .access(FILES.INSTALLED_FLAG)
50
- .then(() => true)
51
- .catch(() => false);
52
- return flagExists;
53
- }
54
-
55
- /**
56
- * Check if existing project files exist
57
- * @returns {Promise<{hasProject: boolean, projectFiles: string[]}>} Project status
58
- */
59
- async function checkExistingProject() {
60
- const projectFiles = [];
61
- let hasProject = false;
62
-
63
- // Check for key project files
64
- const keyFiles = [
65
- FILES.PROJECT_MANIFEST,
66
- path.join(AIWF_DIRS.PROJECT_DOCS, 'README.md'),
67
- path.join(AIWF_DIRS.REQUIREMENTS, 'requirements.md'),
68
- path.join(AIWF_DIRS.SPRINTS, 'sprint-01.md'),
69
- path.join(AIWF_DIRS.GENERAL_TASKS, 'tasks.md'),
70
- path.join(AIWF_DIRS.ARCHITECTURAL_DECISIONS, 'decisions.md'),
71
- path.join(AIWF_DIRS.STATE_OF_PROJECT, 'current-state.md')
72
- ];
73
-
74
- for (const file of keyFiles) {
75
- try {
76
- await fs.access(file);
77
- projectFiles.push(file);
78
- hasProject = true;
79
- } catch (error) {
80
- // File doesn't exist, continue
81
- }
82
- }
83
-
84
- // Check for any .md files in project directories
85
- const projectDirs = [
86
- AIWF_DIRS.PROJECT_DOCS,
87
- AIWF_DIRS.REQUIREMENTS,
88
- AIWF_DIRS.SPRINTS,
89
- AIWF_DIRS.GENERAL_TASKS,
90
- AIWF_DIRS.ARCHITECTURAL_DECISIONS,
91
- AIWF_DIRS.STATE_OF_PROJECT
92
- ];
93
-
94
- for (const dir of projectDirs) {
95
- try {
96
- const files = await fs.readdir(dir);
97
- const mdFiles = files.filter(file => file.endsWith('.md'));
98
- if (mdFiles.length > 0) {
99
- hasProject = true;
100
- projectFiles.push(...mdFiles.map(file => path.join(dir, file)));
101
- }
102
- } catch (error) {
103
- // Directory doesn't exist, continue
104
- }
105
- }
106
-
107
- return { hasProject, projectFiles };
108
- }
109
-
110
- /**
111
- * Log with spinner for debug mode
112
- * @param {Object} spinner - Ora spinner instance
113
- * @param {string} message - Message to log
114
- * @param {boolean} debugLog - Debug mode flag
115
- */
116
- function logWithSpinner(spinner, message, debugLog) {
117
- if (debugLog) console.log(chalk.gray(message));
118
- if (spinner) spinner.text = message;
119
- }
120
-
121
- /**
122
- * Select language for installation
123
- * @param {Object} options - Installation options
124
- * @returns {Promise<string>} Selected language
125
- */
126
- async function selectLanguage(options) {
127
- let selectedLanguage = DEFAULT_LANGUAGE;
128
-
129
- if (!options.force) {
130
- // 1. Check existing configuration
131
- const existingConfig = await loadUserLanguageConfig();
132
-
133
- if (existingConfig && existingConfig.language) {
134
- selectedLanguage = existingConfig.language;
135
- console.log(
136
- chalk.blue(
137
- `🌐 기존 언어 설정을 사용합니다 / Using existing language setting: ${selectedLanguage}`
138
- )
139
- );
140
- } else {
141
- // 2. Try auto-detection
142
- const detectedLang = await detectLanguage();
143
-
144
- console.log(
145
- chalk.gray(`🔍 시스템 언어 감지 / System language detected: ${detectedLang}`)
146
- );
147
-
148
- // 3. Prompt user for language selection
149
- const languageResponse = await prompts({
150
- type: 'select',
151
- name: 'language',
152
- message: 'Please select language / 언어를 선택해주세요:',
153
- choices: [
154
- { title: 'English', value: 'en' },
155
- { title: '한국어 (Korean)', value: 'ko' }
156
- ],
157
- initial:
158
- SUPPORTED_LANGUAGES.indexOf(detectedLang) !== -1
159
- ? SUPPORTED_LANGUAGES.indexOf(detectedLang)
160
- : 0
161
- });
162
-
163
- if (languageResponse.language) {
164
- selectedLanguage = languageResponse.language;
165
- } else {
166
- selectedLanguage = detectedLang;
167
- }
168
-
169
- // 4. Save selected language
170
- try {
171
- await saveUserLanguageConfig(selectedLanguage, {
172
- autoDetect: true,
173
- fallback: DEFAULT_LANGUAGE
174
- });
175
- console.log(
176
- chalk.green(
177
- `✅ 언어 설정이 저장되었습니다 / Language preference saved: ${selectedLanguage}`
178
- )
179
- );
180
- } catch (error) {
181
- console.warn(
182
- chalk.yellow(
183
- `⚠️ 언어 설정 저장 실패 / Failed to save language preference: ${error.message}`
184
- )
185
- );
186
- }
187
- }
188
- } else {
189
- // Force mode: try auto-detection
190
- try {
191
- selectedLanguage = await detectLanguage();
192
- } catch (error) {
193
- selectedLanguage = DEFAULT_LANGUAGE;
194
- }
195
- }
196
-
197
- return selectedLanguage;
198
- }
199
-
200
- /**
201
- * Handle existing installation
202
- * @param {Object} msg - Localized messages
203
- * @param {Object} options - Installation options
204
- * @returns {Promise<{continue: boolean, installType: string, preserveProject: boolean}>} Installation decision
205
- */
206
- async function handleExistingInstallation(msg, options) {
207
-
208
- if (options.force) {
209
- return { continue: true, installType: 'reinstall', preserveProject: false };
210
- }
211
-
212
- // First, ask about installation type
213
- const installResponse = await prompts({
214
- type: 'select',
215
- name: 'action',
216
- message: msg.existingDetected,
217
- choices: [
218
- { title: msg.updateOption, value: 'update' },
219
- { title: msg.reinstallOption, value: 'reinstall' },
220
- { title: msg.skipOption, value: 'skip' },
221
- { title: msg.cancelOption, value: 'cancel' }
222
- ]
223
- });
224
-
225
-
226
-
227
- if (installResponse.action === 'skip' || installResponse.action === 'cancel') {
228
- console.log(chalk.yellow(msg.installCancelled));
229
- process.exit(0);
230
- }
231
-
232
- let preserveProject = true; // Default to preserve
233
-
234
- // If reinstalling, don't preserve project (complete fresh install)
235
- if (installResponse.action === 'reinstall') {
236
- preserveProject = false;
237
- }
238
-
239
- // Backup if updating
240
- if (installResponse.action === 'update') {
241
- await backupCommandsAndDocs(msg);
242
- }
243
-
244
- return {
245
- continue: true,
246
- installType: installResponse.action,
247
- preserveProject
248
- };
249
- }
250
-
251
- /**
252
- * Backup project files
253
- * @param {string[]} projectFiles - List of project files to backup
254
- * @param {Object} msg - Localized messages
255
- * @returns {Promise<string>} Backup directory path
256
- */
257
- async function backupProjectFiles(projectFiles, msg) {
258
- if (projectFiles.length === 0) {
259
- return null;
260
- }
261
-
262
- const backupDir = path.join(os.tmpdir(), `aiwf-project-backup-${Date.now()}`);
263
- await fs.mkdir(backupDir, { recursive: true });
264
-
265
- console.log(chalk.cyan('💾 Backing up project files...'));
266
-
267
- for (const file of projectFiles) {
268
- try {
269
- const relativePath = path.relative(process.cwd(), file);
270
- const backupPath = path.join(backupDir, relativePath);
271
- const backupDirPath = path.dirname(backupPath);
272
-
273
- await fs.mkdir(backupDirPath, { recursive: true });
274
- await fs.copyFile(file, backupPath);
275
- } catch (error) {
276
- console.log(chalk.yellow(`Warning: Could not backup ${file}: ${error.message}`));
277
- }
278
- }
279
-
280
- console.log(chalk.green(`✅ Project files backed up to: ${backupDir}`));
281
- return backupDir;
282
- }
283
-
284
- /**
285
- * Restore project files from backup
286
- * @param {string} backupDir - Backup directory path
287
- * @param {Object} msg - Localized messages
288
- */
289
- async function restoreProjectFiles(backupDir, msg) {
290
- if (!backupDir) {
291
- return;
292
- }
293
-
294
- console.log(chalk.cyan('🔄 Restoring project files...'));
295
-
296
- try {
297
- const backupFiles = await fs.readdir(backupDir, { recursive: true });
298
-
299
- for (const file of backupFiles) {
300
- const backupFilePath = path.join(backupDir, file);
301
- const stat = await fs.stat(backupFilePath);
302
-
303
- if (stat.isFile()) {
304
- const targetPath = path.join(process.cwd(), file);
305
- const targetDir = path.dirname(targetPath);
306
-
307
- await fs.mkdir(targetDir, { recursive: true });
308
- await fs.copyFile(backupFilePath, targetPath);
309
- }
310
- }
311
-
312
- console.log(chalk.green(msg.projectPreserved));
313
-
314
- // Clean up backup directory
315
- await fs.rm(backupDir, { recursive: true, force: true });
316
- } catch (error) {
317
- console.log(chalk.yellow(`Warning: Could not restore some project files: ${error.message}`));
318
- console.log(chalk.yellow(`Backup preserved at: ${backupDir}`));
319
- }
320
- }
321
-
322
- /**
323
- * Remove project files
324
- * @param {string[]} projectFiles - List of project files to remove
325
- * @param {Object} msg - Localized messages
326
- */
327
- async function removeProjectFiles(projectFiles, msg) {
328
- if (projectFiles.length === 0) {
329
- return;
330
- }
331
-
332
- console.log(chalk.cyan('🗑️ Removing existing project files...'));
333
-
334
- for (const file of projectFiles) {
335
- try {
336
- await fs.unlink(file);
337
- } catch (error) {
338
- // File might already be deleted, continue
339
- }
340
- }
341
-
342
- console.log(chalk.green(msg.projectOverwritten));
343
- }
344
-
345
- /**
346
- * Create AIWF directory structure
347
- */
348
- async function createDirectoryStructure() {
349
- const aiwfDirs = getAllAiwfDirectories();
350
-
351
- // Create AIWF directories
352
- for (const dir of aiwfDirs) {
353
- await fs.mkdir(dir, { recursive: true });
354
- }
355
-
356
- // Create tool-specific directories
357
- await fs.mkdir(TOOL_DIRS.CURSOR_RULES, { recursive: true });
358
- await fs.mkdir(TOOL_DIRS.WINDSURF_RULES, { recursive: true });
359
- await fs.mkdir(TOOL_DIRS.CLAUDE_AGENTS, { recursive: true });
360
- }
361
-
362
- /**
363
- * Download manifest file
364
- * @param {string} languagePath - Language path
365
- * @param {Object} spinner - Ora spinner instance
366
- * @param {Object} msg - Localized messages
367
- * @param {boolean} debugLog - Debug mode flag
368
- */
369
- async function downloadManifest(languagePath, spinner, msg, debugLog) {
370
- logWithSpinner(spinner, msg.downloading, debugLog);
371
- try {
372
- const manifestUrl = `${GITHUB_RAW_URL}/${GITHUB_CONTENT_PREFIX}/${languagePath}/.aiwf/00_PROJECT_MANIFEST.md`;
373
- await downloadFile(manifestUrl, FILES.PROJECT_MANIFEST);
374
- } catch (error) {
375
- // If manifest doesn't exist, that's okay
376
- }
377
- }
378
-
379
- /**
380
- * Download templates
381
- * @param {string} languagePath - Language path
382
- * @param {Object} spinner - Ora spinner instance
383
- * @param {Object} msg - Localized messages
384
- * @param {boolean} debugLog - Debug mode flag
385
- */
386
- async function downloadTemplates(languagePath, spinner, msg, debugLog) {
387
- try {
388
- logWithSpinner(spinner, msg.downloadingTemplates, debugLog);
389
-
390
- // .aiwf 전체 디렉토리를 동적으로 다운로드
391
- logWithSpinner(spinner, `Downloading .aiwf directory structure...`, debugLog);
392
- await downloadDirectory(
393
- `${GITHUB_CONTENT_PREFIX}/${languagePath}/.aiwf`,
394
- AIWF_DIRS.ROOT,
395
- spinner,
396
- msg,
397
- languagePath,
398
- true // useDynamicFetch = true
399
- );
400
-
401
- logWithSpinner(spinner, `Successfully downloaded .aiwf directory`, debugLog);
402
- } catch (error) {
403
- logWithSpinner(spinner, `Error downloading .aiwf: ${error.message}`, debugLog);
404
-
405
- // Fallback: 개별 디렉토리 다운로드 시도
406
- try {
407
- logWithSpinner(spinner, `Trying individual directory downloads...`, debugLog);
408
-
409
- await downloadDirectory(
410
- `${GITHUB_CONTENT_PREFIX}/${languagePath}/.aiwf/98_PROMPTS`,
411
- AIWF_DIRS.PROMPTS,
412
- spinner,
413
- msg,
414
- languagePath,
415
- true
416
- );
417
-
418
- await downloadDirectory(
419
- `${GITHUB_CONTENT_PREFIX}/${languagePath}/.aiwf/99_TEMPLATES`,
420
- AIWF_DIRS.TEMPLATES,
421
- spinner,
422
- msg,
423
- languagePath,
424
- true
425
- );
426
- } catch (fallbackError) {
427
- logWithSpinner(spinner, msg.templatesNotFound, debugLog);
428
- }
429
- }
430
- }
431
-
432
- /**
433
- * Update CLAUDE.md documentation files
434
- * @param {string} languagePath - Language path
435
- * @param {Object} spinner - Ora spinner instance
436
- * @param {Object} msg - Localized messages
437
- * @param {boolean} debugLog - Debug mode flag
438
- */
439
- async function updateDocumentation(languagePath, spinner, msg, debugLog) {
440
- logWithSpinner(spinner, msg.updatingDocs, debugLog);
441
- const claudeFiles = getAllClaudeMdFiles();
442
-
443
- for (const claudeFile of claudeFiles) {
444
- try {
445
- const relativePath = claudeFile.replace(process.cwd() + '/', '');
446
- const claudeUrl = `${GITHUB_RAW_URL}/${GITHUB_CONTENT_PREFIX}/${languagePath}/${relativePath}`;
447
- await downloadFile(claudeUrl, claudeFile);
448
- } catch (error) {
449
- // If CLAUDE.md doesn't exist, that's okay
450
- }
451
- }
452
- }
453
-
454
- /**
455
- * Update Claude commands and agents
456
- * @param {string} languagePath - Language path
457
- * @param {Object} spinner - Ora spinner instance
458
- * @param {Object} msg - Localized messages
459
- * @param {boolean} debugLog - Debug mode flag
460
- */
461
- async function updateCommands(languagePath, spinner, msg, debugLog) {
462
- // Delete existing commands folder if it exists
463
- if (await fs.access(TOOL_DIRS.CLAUDE_COMMANDS).then(() => true).catch(() => false)) {
464
- logWithSpinner(spinner, msg.deletingOldCommands, debugLog);
465
- await fs.rm(TOOL_DIRS.CLAUDE_COMMANDS, { recursive: true, force: true });
466
- }
467
-
468
- // Delete existing agents folder if it exists
469
- if (await fs.access(TOOL_DIRS.CLAUDE_AGENTS).then(() => true).catch(() => false)) {
470
- logWithSpinner(spinner, 'Deleting old agents...', debugLog);
471
- await fs.rm(TOOL_DIRS.CLAUDE_AGENTS, { recursive: true, force: true });
472
- }
473
-
474
- await fs.mkdir(TOOL_DIRS.CLAUDE_COMMANDS, { recursive: true });
475
- await fs.mkdir(TOOL_DIRS.CLAUDE_AGENTS, { recursive: true });
476
-
477
- // Download commands
478
- logWithSpinner(spinner, msg.downloadingCommands, debugLog);
479
- try {
480
- await downloadDirectory(
481
- `${GITHUB_CONTENT_PREFIX}/${languagePath}/${TOOL_DIRS.CLAUDE_COMMANDS}`,
482
- TOOL_DIRS.CLAUDE_COMMANDS,
483
- spinner,
484
- msg,
485
- languagePath,
486
- true // commands도 동적 디렉터리 탐색 사용 (파일 리스트 의존 제거)
487
- );
488
- } catch (error) {
489
- logWithSpinner(spinner, msg.commandsNotFound, debugLog);
490
- }
491
-
492
- // Download agents
493
- logWithSpinner(spinner, 'Downloading agents...', debugLog);
494
- try {
495
- await downloadDirectory(
496
- `${GITHUB_CONTENT_PREFIX}/${languagePath}/${TOOL_DIRS.CLAUDE_AGENTS}`,
497
- TOOL_DIRS.CLAUDE_AGENTS,
498
- spinner,
499
- msg,
500
- languagePath,
501
- true // agents도 동적 디렉터리 탐색 사용 (파일 리스트 의존 제거)
502
- );
503
- logWithSpinner(spinner, 'Successfully downloaded agents', debugLog);
504
- } catch (error) {
505
- logWithSpinner(spinner, 'Agents not found or failed to download', debugLog);
506
- }
507
-
508
- // Download full .claude directory to include tools, workflow, and any other subfolders
509
- logWithSpinner(spinner, 'Downloading full .claude directory (tools, workflow, etc.)...', debugLog);
510
- try {
511
- await downloadDirectory(
512
- `${GITHUB_CONTENT_PREFIX}/${languagePath}/.claude`,
513
- '.claude',
514
- spinner,
515
- msg,
516
- languagePath,
517
- true // 전체 .claude 폴더 동적 다운로드
518
- );
519
- logWithSpinner(spinner, 'Successfully downloaded .claude directory', debugLog);
520
- } catch (error) {
521
- logWithSpinner(spinner, `Failed to download full .claude directory: ${error.message}`, debugLog);
522
- }
523
- }
524
-
525
- /**
526
- * Check if tool directories exist and handle them
527
- * @param {Object} spinner - Ora spinner instance
528
- * @param {Object} msg - Localized messages
529
- * @param {boolean} debugLog - Debug mode flag
530
- * @returns {Promise<Object>} Directory status info
531
- */
532
- async function checkAndHandleExistingToolDirs(spinner, msg, debugLog) {
533
- const toolDirStatus = {
534
- cursor: {
535
- exists: false,
536
- hadFiles: false,
537
- backedUp: false
538
- },
539
- windsurf: {
540
- exists: false,
541
- hadFiles: false,
542
- backedUp: false
543
- }
544
- };
545
-
546
- // Check Cursor directory
547
- try {
548
- await fs.access(TOOL_DIRS.CURSOR_RULES);
549
- toolDirStatus.cursor.exists = true;
550
-
551
- const cursorFiles = await fs.readdir(TOOL_DIRS.CURSOR_RULES);
552
- const mdcFiles = cursorFiles.filter(file => file.endsWith('.mdc'));
553
-
554
- if (mdcFiles.length > 0) {
555
- toolDirStatus.cursor.hadFiles = true;
556
- logWithSpinner(spinner, `${msg.foundExistingCursor} (${mdcFiles.length} files)`, debugLog);
557
-
558
- // Backup existing files
559
- logWithSpinner(spinner, msg.backingUpToolFiles, debugLog);
560
- const backupDir = path.join(TOOL_DIRS.CURSOR_RULES, `backup_${Date.now()}`);
561
- await fs.mkdir(backupDir, { recursive: true });
562
-
563
- for (const file of mdcFiles) {
564
- const srcPath = path.join(TOOL_DIRS.CURSOR_RULES, file);
565
- const backupPath = path.join(backupDir, file);
566
- await fs.copyFile(srcPath, backupPath);
567
- }
568
-
569
- toolDirStatus.cursor.backedUp = true;
570
- logWithSpinner(spinner, `${msg.toolBackupCreated}: ${backupDir}`, debugLog);
571
-
572
- // Remove existing files
573
- for (const file of mdcFiles) {
574
- await fs.unlink(path.join(TOOL_DIRS.CURSOR_RULES, file));
575
- }
576
- }
577
- } catch (error) {
578
- // Directory doesn't exist, that's fine
579
- logWithSpinner(spinner, `Cursor rules directory not found, will create new`, debugLog);
580
- }
581
-
582
- // Check Windsurf directory
583
- try {
584
- await fs.access(TOOL_DIRS.WINDSURF_RULES);
585
- toolDirStatus.windsurf.exists = true;
586
-
587
- const windsurfFiles = await fs.readdir(TOOL_DIRS.WINDSURF_RULES);
588
- const mdFiles = windsurfFiles.filter(file => file.endsWith('.md'));
589
-
590
- if (mdFiles.length > 0) {
591
- toolDirStatus.windsurf.hadFiles = true;
592
- logWithSpinner(spinner, `${msg.foundExistingWindsurf} (${mdFiles.length} files)`, debugLog);
593
-
594
- // Backup existing files
595
- logWithSpinner(spinner, msg.backingUpToolFiles, debugLog);
596
- const backupDir = path.join(TOOL_DIRS.WINDSURF_RULES, `backup_${Date.now()}`);
597
- await fs.mkdir(backupDir, { recursive: true });
598
-
599
- for (const file of mdFiles) {
600
- const srcPath = path.join(TOOL_DIRS.WINDSURF_RULES, file);
601
- const backupPath = path.join(backupDir, file);
602
- await fs.copyFile(srcPath, backupPath);
603
- }
604
-
605
- toolDirStatus.windsurf.backedUp = true;
606
- logWithSpinner(spinner, `${msg.toolBackupCreated}: ${backupDir}`, debugLog);
607
-
608
- // Remove existing files
609
- for (const file of mdFiles) {
610
- await fs.unlink(path.join(TOOL_DIRS.WINDSURF_RULES, file));
611
- }
612
- }
613
- } catch (error) {
614
- // Directory doesn't exist, that's fine
615
- logWithSpinner(spinner, `Windsurf rules directory not found, will create new`, debugLog);
616
- }
617
-
618
- return toolDirStatus;
619
- }
620
-
621
- /**
622
- * Download and process rules
623
- * @param {Object} spinner - Ora spinner instance
624
- * @param {Object} msg - Localized messages
625
- * @param {boolean} debugLog - Debug mode flag
626
- */
627
- async function downloadAndProcessRules(spinner, msg, debugLog) {
628
- // Check and handle existing tool directories first
629
- logWithSpinner(spinner, msg.checkingExistingTools, debugLog);
630
- const toolDirStatus = await checkAndHandleExistingToolDirs(spinner, msg, debugLog);
631
- // Try to download from GitHub first, fallback to local files
632
- const tmpRulesGlobal = path.join(os.tmpdir(), 'aiwf-rules-global');
633
- const tmpRulesManual = path.join(os.tmpdir(), 'aiwf-rules-manual');
634
-
635
- let useLocalGlobal = false;
636
- let useLocalManual = false;
637
-
638
- // Try to download rules/global from GitHub
639
- try {
640
- await downloadDirectory(
641
- `rules/global`,
642
- tmpRulesGlobal,
643
- spinner,
644
- debugLog
645
- );
646
- logWithSpinner(spinner, `Downloaded rules/global from GitHub`, debugLog);
647
- } catch (error) {
648
- logWithSpinner(spinner, `Failed to download rules/global from GitHub, trying local files`, debugLog);
649
- // Fallback to local files
650
- const localRulesGlobal = path.join(process.cwd(), 'rules/global');
651
- try {
652
- logWithSpinner(spinner, `Trying to access: ${localRulesGlobal}`, debugLog);
653
- await fs.access(localRulesGlobal);
654
- logWithSpinner(spinner, `Successfully accessed local rules/global`, debugLog);
655
- // Copy local files to temp directory
656
- await fs.mkdir(tmpRulesGlobal, { recursive: true });
657
- const files = await fs.readdir(localRulesGlobal);
658
- logWithSpinner(spinner, `Found ${files.length} files in rules/global: ${files.join(', ')}`, debugLog);
659
- for (const file of files) {
660
- const srcPath = path.join(localRulesGlobal, file);
661
- const destPath = path.join(tmpRulesGlobal, file);
662
- await fs.copyFile(srcPath, destPath);
663
- logWithSpinner(spinner, `Copied: ${file}`, debugLog);
664
- }
665
- useLocalGlobal = true;
666
- logWithSpinner(spinner, `Using local rules/global directory`, debugLog);
667
- } catch (localError) {
668
- logWithSpinner(spinner, `Local rules/global error: ${localError.message}`, debugLog);
669
- logWithSpinner(spinner, msg.rulesGlobalNotFound, debugLog);
670
- }
671
- }
672
-
673
- // Try to download rules/manual from GitHub
674
- try {
675
- await downloadDirectory(
676
- `rules/manual`,
677
- tmpRulesManual,
678
- spinner,
679
- debugLog
680
- );
681
- logWithSpinner(spinner, `Downloaded rules/manual from GitHub`, debugLog);
682
- } catch (error) {
683
- logWithSpinner(spinner, `Failed to download rules/manual from GitHub, trying local files`, debugLog);
684
- // Fallback to local files
685
- const localRulesManual = path.join(process.cwd(), 'rules/manual');
686
- try {
687
- await fs.access(localRulesManual);
688
- // Copy local files to temp directory
689
- await fs.mkdir(tmpRulesManual, { recursive: true });
690
- const files = await fs.readdir(localRulesManual);
691
- for (const file of files) {
692
- const srcPath = path.join(localRulesManual, file);
693
- const destPath = path.join(tmpRulesManual, file);
694
- await fs.copyFile(srcPath, destPath);
695
- }
696
- useLocalManual = true;
697
- logWithSpinner(spinner, `Using local rules/manual directory`, debugLog);
698
- } catch (localError) {
699
- logWithSpinner(spinner, msg.rulesManualNotFound, debugLog);
700
- }
701
- }
702
-
703
- // Process rules/global
704
- try {
705
- await fs.access(tmpRulesGlobal);
706
- await fs.mkdir(TOOL_DIRS.CURSOR_RULES, { recursive: true });
707
- await fs.mkdir(TOOL_DIRS.WINDSURF_RULES, { recursive: true });
708
- const files = await fs.readdir(tmpRulesGlobal);
709
- for (const file of files) {
710
- const srcPath = path.join(tmpRulesGlobal, file);
711
- const stat = await fs.stat(srcPath);
712
- if (!stat.isFile()) continue;
713
-
714
- // .cursor/rules: add .mdc extension and header
715
- const base = path.parse(file).name;
716
- const cursorTarget = path.join(TOOL_DIRS.CURSOR_RULES, base + '.mdc');
717
- const content = await fs.readFile(srcPath, 'utf8');
718
- const header = '---\ndescription: \nglobs: \nalwaysApply: true\n---\n';
719
- await fs.writeFile(cursorTarget, header + content, 'utf8');
720
- logWithSpinner(
721
- spinner,
722
- `[rules/global] ${file} -> ${TOOL_DIRS.CURSOR_RULES}/${base}.mdc`,
723
- debugLog
724
- );
725
-
726
- // .windsurf/rules: keep extension, no header
727
- const windsurfTarget = path.join(TOOL_DIRS.WINDSURF_RULES, file);
728
- const windsurfContent = await fs.readFile(srcPath, 'utf8');
729
- const windsurfHeader = '---\ntrigger: always_on\n---\n';
730
- await fs.writeFile(windsurfTarget, windsurfHeader + windsurfContent, 'utf8');
731
- logWithSpinner(
732
- spinner,
733
- `[rules/global] ${file} -> ${TOOL_DIRS.WINDSURF_RULES}/${file}`,
734
- debugLog
735
- );
736
- }
737
- // Clean up temp folder (only if not using local files)
738
- if (!useLocalGlobal) {
739
- await fs.rm(tmpRulesGlobal, { recursive: true, force: true });
740
- }
741
- } catch (error) {
742
- logWithSpinner(spinner, `No rules/global directory found`, debugLog);
743
- }
744
-
745
- // Process rules/manual
746
- try {
747
- await fs.access(tmpRulesManual);
748
- await fs.mkdir(TOOL_DIRS.CURSOR_RULES, { recursive: true });
749
- await fs.mkdir(TOOL_DIRS.WINDSURF_RULES, { recursive: true });
750
- const files = await fs.readdir(tmpRulesManual);
751
- for (const file of files) {
752
- const srcPath = path.join(tmpRulesManual, file);
753
- const stat = await fs.stat(srcPath);
754
- if (!stat.isFile()) continue;
755
-
756
- // .cursor/rules: add .mdc extension and header (alwaysApply: false)
757
- const base = path.parse(file).name;
758
- const cursorTarget = path.join(TOOL_DIRS.CURSOR_RULES, base + '.mdc');
759
- const content = await fs.readFile(srcPath, 'utf8');
760
- const header = '---\ndescription: \nglobs: \nalwaysApply: false\n---\n';
761
- await fs.writeFile(cursorTarget, header + content, 'utf8');
762
- logWithSpinner(
763
- spinner,
764
- `[rules/manual] ${file} -> ${TOOL_DIRS.CURSOR_RULES}/${base}.mdc`,
765
- debugLog
766
- );
767
-
768
- // .windsurf/rules: keep extension, no header
769
- const windsurfTarget = path.join(TOOL_DIRS.WINDSURF_RULES, file);
770
- const windsurfContent = await fs.readFile(srcPath, 'utf8');
771
- const windsurfHeader = '---\ntrigger: manual\n---\n';
772
- await fs.writeFile(windsurfTarget, windsurfHeader + windsurfContent, 'utf8');
773
- logWithSpinner(
774
- spinner,
775
- `[rules/manual] ${file} -> ${TOOL_DIRS.WINDSURF_RULES}/${file}`,
776
- debugLog
777
- );
778
- }
779
- // Clean up temp folder (only if not using local files)
780
- if (!useLocalManual) {
781
- await fs.rm(tmpRulesManual, { recursive: true, force: true });
782
- }
783
- } catch (error) {
784
- logWithSpinner(spinner, `No rules/manual directory found`, debugLog);
785
- }
786
-
787
- // Success message for tool rules installation
788
- logWithSpinner(spinner, msg.toolRulesInstalled, debugLog);
789
-
790
- // Display installation results for tool directories
791
- if (toolDirStatus.cursor.backedUp || toolDirStatus.windsurf.backedUp) {
792
- console.log(chalk.cyan(`\n📂 Tool Directory Installation Results:`));
793
-
794
- if (toolDirStatus.cursor.backedUp) {
795
- console.log(chalk.yellow(` • Cursor: Existing rules backed up and replaced`));
796
- } else if (toolDirStatus.cursor.exists) {
797
- console.log(chalk.green(` • Cursor: Rules installed (directory was empty)`));
798
- } else {
799
- console.log(chalk.green(` • Cursor: Rules installed (new directory)`));
800
- }
801
-
802
- if (toolDirStatus.windsurf.backedUp) {
803
- console.log(chalk.yellow(` • Windsurf: Existing rules backed up and replaced`));
804
- } else if (toolDirStatus.windsurf.exists) {
805
- console.log(chalk.green(` • Windsurf: Rules installed (directory was empty)`));
806
- } else {
807
- console.log(chalk.green(` • Windsurf: Rules installed (new directory)`));
808
- }
809
- }
810
-
811
- return toolDirStatus;
812
- }
813
-
814
- /**
815
- * Display installation summary
816
- * @param {boolean} hasExisting - Has existing installation
817
- * @param {Object} msg - Localized messages
818
- */
819
- function displaySummary(hasExisting, msg) {
820
- if (hasExisting) {
821
- console.log(chalk.blue(`\n${msg.updateHistory}`));
822
- console.log(chalk.gray(` • ${TOOL_DIRS.CLAUDE_COMMANDS}${msg.updatedCommands}`));
823
- console.log(chalk.gray(` • ${msg.updatedDocs}`));
824
- console.log(chalk.green(`\n${msg.workPreserved}`));
825
- console.log(chalk.gray(` • ${msg.allFilesPreserved}`));
826
- console.log(chalk.gray(` • ${msg.backupCreated}`));
827
- } else {
828
- console.log(chalk.blue(`\n${msg.structureCreated}`));
829
- console.log(chalk.gray(` ${AIWF_DIRS.ROOT}/ - ${msg.aiwfRoot}`));
830
- console.log(chalk.gray(` ${TOOL_DIRS.CLAUDE_COMMANDS}/ - ${msg.claudeCommands}`));
831
-
832
- console.log(chalk.green(`\n${msg.nextSteps}`));
833
- console.log(chalk.white(` 1. ${msg.nextStep1}`));
834
- console.log(chalk.white(` 2. ${msg.nextStep2}`));
835
- console.log(chalk.white(` 3. ${msg.nextStep3}\n`));
836
-
837
- console.log(chalk.blue(`\n${msg.gettingStarted}`));
838
- console.log(chalk.gray(` 1. ${msg.startStep1}`));
839
- console.log(chalk.gray(` 2. ${msg.startStep2}`));
840
- console.log(chalk.gray(`\n${msg.checkDocs}`));
841
- }
842
- }
843
-
844
- /**
845
- * Offer reinstallation options
846
- * @param {Object} validationResults - Validation results
847
- * @param {string} language - Language code
848
- * @returns {Promise<string>} Selected action
849
- */
850
- async function offerReinstallationOptions(validationResults, language) {
851
- console.log(
852
- chalk.yellow(
853
- language === 'ko'
854
- ? '\n⚠️ 일부 설치가 실패했습니다. 무엇을 하시겠습니까?'
855
- : '\n⚠️ Some installations failed. What would you like to do?'
856
- )
857
- );
858
-
859
- // List failed tools
860
- const failedTools = validationResults.failed.map(({ tool }) => tool);
861
-
862
- if (failedTools.length > 0) {
863
- console.log(
864
- chalk.red(
865
- language === 'ko'
866
- ? `실패한 도구: ${failedTools.join(', ')}`
867
- : `Failed tools: ${failedTools.join(', ')}`
868
- )
869
- );
870
- }
871
-
872
- const response = await prompts({
873
- type: 'select',
874
- name: 'action',
875
- message:
876
- language === 'ko' ? '어떤 작업을 수행하시겠습니까?' : 'What would you like to do?',
877
- choices: [
878
- {
879
- title: language === 'ko' ? '전체 재설치' : 'Full reinstallation',
880
- value: 'reinstall'
881
- },
882
- {
883
- title: language === 'ko' ? '실패한 도구만 롤백' : 'Rollback failed tools only',
884
- value: 'rollback'
885
- },
886
- {
887
- title: language === 'ko' ? '현재 상태 유지' : 'Keep current state',
888
- value: 'keep'
889
- }
890
- ]
891
- });
892
-
893
- return response.action;
894
- }
895
-
896
- /**
897
- * 사용자 설치 옵션 선택
898
- * @param {Object} msg - 지역화된 메시지
899
- * @returns {Promise<Array>} 선택된 설치 옵션 목록
900
- */
901
- async function selectInstallationOptions(msg) {
902
- console.log(chalk.cyan(`\n${msg.installationOptions}`));
903
-
904
- const installOptions = [
905
- {
906
- title: msg.aiwfDocs,
907
- value: 'aiwf-docs',
908
- description: 'AIWF 문서 폴더'
909
- },
910
- {
911
- title: msg.claudeCodeCommands,
912
- value: 'claude-code-commands',
913
- description: 'Claude Code 명령어 및 에이전트'
914
- },
915
- {
916
- title: msg.windsurfRules,
917
- value: 'windsurf-rules',
918
- description: 'Windsurf 규칙 파일'
919
- },
920
- {
921
- title: msg.cursorRules,
922
- value: 'cursor-rules',
923
- description: 'Cursor 규칙 파일'
924
- }
925
- ];
926
-
927
- // 1단계: 전체 설치 vs 개별 선택
928
- const installTypeResponse = await prompts({
929
- type: 'select',
930
- name: 'installType',
931
- message: msg.installationOptions || '설치 옵션을 선택하세요:',
932
- choices: [
933
- {
934
- title: msg.selectAll || '✅ 모든 항목 설치 (권장)',
935
- value: 'all',
936
- description: '모든 AIWF 컴포넌트를 설치합니다'
937
- },
938
- {
939
- title: '🎯 개별 항목 선택',
940
- value: 'custom',
941
- description: '원하는 항목만 선택하여 설치합니다'
942
- }
943
- ]
944
- });
945
-
946
- // 취소된 경우
947
- if (!installTypeResponse.installType) {
948
- console.log(chalk.yellow(msg.noOptionsSelected || '설치가 취소되었습니다.'));
949
- process.exit(0);
950
- }
951
-
952
- // 전체 설치 선택
953
- if (installTypeResponse.installType === 'all') {
954
- return installOptions.map(opt => opt.value);
955
- }
956
-
957
- // 2단계: 개별 항목 선택
958
- const customResponse = await prompts({
959
- type: 'multiselect',
960
- name: 'selectedOptions',
961
- message: '설치할 항목을 선택하세요 (스페이스로 선택/해제, 엔터로 확인):',
962
- choices: installOptions,
963
- hint: '↑↓ 이동, 스페이스 선택/해제, 엔터 확인',
964
- instructions: false
965
- });
966
-
967
- // 취소되거나 아무것도 선택하지 않은 경우
968
- if (!customResponse.selectedOptions || customResponse.selectedOptions.length === 0) {
969
- console.log(chalk.yellow(msg.noOptionsSelected || '선택된 항목이 없습니다.'));
970
- process.exit(0);
971
- }
972
-
973
- return customResponse.selectedOptions;
974
- }
975
-
976
- /**
977
- * 선택된 옵션별 설치 실행
978
- * @param {Array} selectedOptions - 선택된 설치 옵션들
979
- * @param {string} languagePath - 언어 경로
980
- * @param {Object} msg - 지역화된 메시지
981
- * @param {boolean} debugLog - 디버그 로그 여부
982
- */
983
- async function installSelectedOptions(selectedOptions, languagePath, msg, debugLog) {
984
- for (const option of selectedOptions) {
985
- const spinner = ora(`${msg.installingOption}${option}...`).start();
986
-
987
- try {
988
- switch (option) {
989
- case 'aiwf-docs':
990
- await installAIWFDocs(languagePath, debugLog);
991
- break;
992
- case 'claude-code-commands':
993
- await installClaudeCodeCommands(languagePath, debugLog);
994
- break;
995
- case 'windsurf-rules':
996
- await installWindsurfRules(debugLog);
997
- break;
998
- case 'cursor-rules':
999
- await installCursorRules(debugLog);
1000
- break;
1001
- default:
1002
- spinner.warn(`Unknown option: ${option}`);
1003
- continue;
1004
- }
1005
-
1006
- spinner.succeed(`${msg.optionInstalled}${option}`);
1007
- } catch (error) {
1008
- spinner.fail(`Failed to install ${option}: ${error.message}`);
1009
- if (debugLog) {
1010
- console.error(error);
1011
- }
1012
- }
1013
- }
1014
- }
1015
-
1016
- /**
1017
- * AIWF 문서 설치
1018
- */
1019
- async function installAIWFDocs(languagePath, debugLog) {
1020
- await createDirectoryStructure();
1021
- const spinner = ora('Downloading AIWF files...').start();
1022
- const msg = {
1023
- downloading: 'Downloading AIWF documentation...',
1024
- downloadingTemplates: 'Downloading templates...',
1025
- templatesNotFound: 'Templates not found'
1026
- };
1027
-
1028
- try {
1029
- // 매니페스트 다운로드
1030
- await downloadManifest(languagePath, spinner, msg, debugLog);
1031
-
1032
- // 전체 .aiwf 디렉토리 다운로드
1033
- await downloadTemplates(languagePath, spinner, msg, debugLog);
1034
-
1035
- spinner.succeed('AIWF documentation installed successfully');
1036
- } catch (error) {
1037
- spinner.fail('Failed to install AIWF documentation');
1038
- if (debugLog) {
1039
- console.error(error);
1040
- }
1041
- throw error;
1042
- }
1043
- }
1044
-
1045
- /**
1046
- * Claude Code 명령어 설치
1047
- */
1048
- async function installClaudeCodeCommands(languagePath, debugLog) {
1049
- const GITHUB_CONTENT_LANGUAGE_PREFIX = `${GITHUB_CONTENT_PREFIX}/${languagePath}`;
1050
- const dummySpinner = null;
1051
- const dummyMsg = { downloadingCommands: 'Downloading Claude Code commands...' };
1052
- await updateCommands(languagePath, dummySpinner, dummyMsg, debugLog);
1053
- }
1054
-
1055
- /**
1056
- * Windsurf 규칙 설치
1057
- */
1058
- async function installWindsurfRules(debugLog) {
1059
- const spinner = ora('Installing Windsurf rules...').start();
1060
- const msg = {
1061
- checkingExistingTools: 'Checking existing tools...',
1062
- foundExistingCursor: 'Found existing Cursor rules',
1063
- foundExistingWindsurf: 'Found existing Windsurf rules',
1064
- backingUpToolFiles: 'Backing up tool files...',
1065
- toolBackupCreated: 'Tool backup created',
1066
- rulesGlobalNotFound: 'Rules global not found',
1067
- rulesManualNotFound: 'Rules manual not found',
1068
- toolRulesInstalled: 'Tool rules installed successfully'
1069
- };
1070
-
1071
- try {
1072
- await downloadAndProcessRules(spinner, msg, debugLog);
1073
- spinner.succeed('Windsurf rules installed successfully');
1074
- } catch (error) {
1075
- spinner.fail('Failed to install Windsurf rules');
1076
- if (debugLog) {
1077
- console.error(error);
1078
- }
1079
- throw error;
1080
- }
1081
- }
1082
-
1083
- /**
1084
- * Cursor 규칙 설치
1085
- */
1086
- async function installCursorRules(debugLog) {
1087
- const spinner = ora('Installing Cursor rules...').start();
1088
- const msg = {
1089
- checkingExistingTools: 'Checking existing tools...',
1090
- foundExistingCursor: 'Found existing Cursor rules',
1091
- foundExistingWindsurf: 'Found existing Windsurf rules',
1092
- backingUpToolFiles: 'Backing up tool files...',
1093
- toolBackupCreated: 'Tool backup created',
1094
- rulesGlobalNotFound: 'Rules global not found',
1095
- rulesManualNotFound: 'Rules manual not found',
1096
- toolRulesInstalled: 'Tool rules installed successfully'
1097
- };
1098
-
1099
- try {
1100
- await downloadAndProcessRules(spinner, msg, debugLog);
1101
- spinner.succeed('Cursor rules installed successfully');
1102
- } catch (error) {
1103
- spinner.fail('Failed to install Cursor rules');
1104
- if (debugLog) {
1105
- console.error(error);
1106
- }
1107
- throw error;
1108
- }
1109
- }
1110
-
1111
- /**
1112
- * Main installation function
1113
- * @param {Object} options - Installation options
1114
- */
1115
- export async function installAIWF(options = {}) {
1116
- const debugLog = options.debugLog || false;
1117
-
1118
- // Select language
1119
- const selectedLanguage = await selectLanguage(options);
1120
- const msg = getMessages(selectedLanguage);
1121
-
1122
- console.log(chalk.blue.bold(msg.welcome));
1123
- console.log(chalk.gray(msg.description));
1124
- console.log(chalk.gray(msg.optimized));
1125
-
1126
- // Set language path
1127
- const languagePath = getInstallationLanguagePath(selectedLanguage);
1128
-
1129
- // Check existing installation
1130
- const hasExisting = await checkExistingInstallation();
1131
-
1132
- let installDecision = { continue: true, installType: 'fresh', preserveProject: false };
1133
- let projectBackupDir = null;
1134
-
1135
- if (hasExisting) {
1136
- installDecision = await handleExistingInstallation(msg, options);
1137
- if (!installDecision.continue) return;
1138
-
1139
- // If reinstalling and preserving project, backup project files
1140
- if (installDecision.installType === 'reinstall' && installDecision.preserveProject) {
1141
- const { hasProject, projectFiles } = await checkExistingProject();
1142
- if (hasProject) {
1143
- projectBackupDir = await backupProjectFiles(projectFiles, msg);
1144
- }
1145
- }
1146
- }
1147
-
1148
- // 설치 옵션 선택
1149
- let selectedOptions = ['aiwf-docs', 'claude-code-commands', 'windsurf-rules', 'cursor-rules'];
1150
-
1151
- if (options.preselectedOptions) {
1152
- // CLI에서 미리 선택된 옵션들을 사용
1153
- selectedOptions = options.preselectedOptions;
1154
- } else if (!options.force && !options.interactive) {
1155
- // 기본적으로는 대화형 선택을 사용
1156
- selectedOptions = await selectInstallationOptions(msg);
1157
- } else if (options.interactive) {
1158
- // --interactive 플래그가 명시적으로 설정된 경우
1159
- selectedOptions = await selectInstallationOptions(msg);
1160
- }
1161
-
1162
- console.log(chalk.blue(`\n설치할 옵션: ${selectedOptions.join(', ')}`));
1163
-
1164
- try {
1165
- // 선택된 옵션들을 설치
1166
- await installSelectedOptions(selectedOptions, languagePath, msg, debugLog);
1167
-
1168
- // Restore project files if needed
1169
- if (projectBackupDir) {
1170
- await restoreProjectFiles(projectBackupDir, msg);
1171
- }
1172
-
1173
- // Success message
1174
- if (hasExisting && installDecision.installType === 'update') {
1175
- console.log(chalk.green(`\n✅ ${msg.updateSuccess}`));
1176
- } else {
1177
- console.log(chalk.green(`\n✅ ${msg.installSuccess}`));
1178
- }
1179
-
1180
- // Display summary
1181
- displaySummary(hasExisting, msg);
1182
-
1183
- // Run validation based on selected options
1184
- console.log(
1185
- chalk.blue('\n🔍 Installation Validation / 설치 검증을 시작합니다...')
1186
- );
1187
-
1188
- // Map selected options to validation tools
1189
- const validationTools = [];
1190
- if (selectedOptions.includes('claude-code-commands')) {
1191
- validationTools.push('claude-code');
1192
- }
1193
- if (selectedOptions.includes('cursor-rules')) {
1194
- validationTools.push('cursor');
1195
- }
1196
- if (selectedOptions.includes('windsurf-rules')) {
1197
- validationTools.push('windsurf');
1198
- }
1199
-
1200
- if (validationTools.length > 0) {
1201
- const validationResults = await validateInstallation(
1202
- validationTools,
1203
- selectedLanguage
1204
- );
1205
- displaySpecCompliantValidationResults(validationResults, selectedLanguage);
1206
-
1207
- // Handle partial failures
1208
- if (validationResults.failed.length > 0) {
1209
- const action = await offerReinstallationOptions(
1210
- validationResults,
1211
- selectedLanguage
1212
- );
1213
-
1214
- if (action === 'reinstall') {
1215
- console.log(
1216
- chalk.blue('\n🔄 재설치를 시작합니다... / Starting reinstallation...')
1217
- );
1218
- // Retry installation once
1219
- if (!options.isRetry) {
1220
- return await installAIWF({ ...options, isRetry: true });
1221
- }
1222
- } else if (action === 'rollback') {
1223
- console.log(
1224
- chalk.blue('\n↩️ 실패한 도구를 롤백합니다... / Rolling back failed tools...')
1225
- );
1226
-
1227
- // Rollback failed tools
1228
- const failedTools = validationResults.failed.map(({ tool }) => tool);
1229
- const backupDir = getCurrentBackupDir();
1230
-
1231
- for (const tool of failedTools) {
1232
- if (backupDir) {
1233
- await rollbackTool(
1234
- tool,
1235
- backupDir,
1236
- selectedLanguage
1237
- );
1238
- }
1239
- }
1240
-
1241
- // Re-validate after rollback
1242
- console.log(
1243
- chalk.blue('\n🔍 롤백 후 재검증... / Re-validating after rollback...')
1244
- );
1245
- const postRollbackValidation = await validateInstallation(
1246
- validationTools,
1247
- selectedLanguage
1248
- );
1249
- displaySpecCompliantValidationResults(postRollbackValidation, selectedLanguage);
1250
- }
1251
- }
1252
- } else {
1253
- console.log(chalk.yellow('\n⚠️ 검증할 도구가 선택되지 않았습니다.'));
1254
- }
1255
-
1256
- console.log(chalk.green(msg.enjoy));
1257
- } catch (error) {
1258
- if (hasExisting) {
1259
- spinner.fail(chalk.red(msg.updateFailed));
1260
- await restoreFromBackup(spinner, msg);
1261
- } else {
1262
- spinner.fail(chalk.red(msg.installFailed));
1263
- }
1264
- console.error(chalk.red(error.message));
1265
- process.exit(1);
1266
- }
1267
-
1268
- // Create installation flag file
1269
- await fs.writeFile(FILES.INSTALLED_FLAG, 'installed', 'utf8');
1270
- }