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
@@ -0,0 +1,126 @@
1
+ #!/usr/bin/env node
2
+ import { cpSync, existsSync, lstatSync, mkdirSync, readFileSync, readdirSync, writeFileSync } from 'node:fs';
3
+ import { dirname, join, resolve } from 'node:path';
4
+ import { fileURLToPath, pathToFileURL } from 'node:url';
5
+
6
+ const plugins = resolve(dirname(fileURLToPath(import.meta.url)), '../plugins');
7
+ export const supportedStacks = ['vaadin-jooq', 'angular-jpa', 'blazor-dotnet', 'nestjs-nextjs'];
8
+ export const supportedDelegates = ['claude', 'codex'];
9
+
10
+ function markdownFiles(directory) {
11
+ return readdirSync(directory, { withFileTypes: true }).flatMap(entry => {
12
+ const file = join(directory, entry.name);
13
+ return entry.isDirectory() ? markdownFiles(file) : entry.name.endsWith('.md') ? [file] : [];
14
+ });
15
+ }
16
+
17
+ function rejectSymlink(path) {
18
+ if (existsSync(path) && lstatSync(path).isSymbolicLink()) {
19
+ throw new Error(`Refusing symbolic link: ${path}`);
20
+ }
21
+ }
22
+
23
+ export function installSpecSkills(project, { dryRun = false, stack, delegates = [] } = {}) {
24
+ if (stack !== undefined && !supportedStacks.includes(stack)) {
25
+ throw new Error(`Unknown stack: ${stack}; choose ${supportedStacks.join(', ')}`);
26
+ }
27
+ if (!Array.isArray(delegates) || delegates.some(target => !supportedDelegates.includes(target))) {
28
+ throw new Error(`Unknown delegate: choose ${supportedDelegates.join(', ')}`);
29
+ }
30
+ delegates = [...new Set(delegates)];
31
+ const root = resolve(project);
32
+ rejectSymlink(root);
33
+ if (!existsSync(root) || !lstatSync(root).isDirectory()) {
34
+ throw new Error(`Project directory does not exist: ${root}`);
35
+ }
36
+ const target = join(root, '.agents', 'skills');
37
+ for (const path of [join(root, '.agents'), target]) {
38
+ rejectSymlink(path);
39
+ if (existsSync(path) && !lstatSync(path).isDirectory()) {
40
+ throw new Error(`Expected directory: ${path}`);
41
+ }
42
+ }
43
+ const bundles = [
44
+ { plugin: join(plugins, 'aiwf-core'), prefix: 'aiwf-' },
45
+ { plugin: join(plugins, 'aiwf-spec'), prefix: 'aiwf-' }
46
+ ];
47
+ if (stack) { bundles.push({ plugin: join(plugins, `aiwf-${stack}`), prefix: `aiwf-${stack}-` }); }
48
+ for (const target of delegates) {
49
+ bundles.push({ plugin: join(plugins, `aiwf-delegate-${target}`), prefix: 'aiwf-' });
50
+ }
51
+ const entries = bundles.flatMap(bundle => readdirSync(join(bundle.plugin, 'skills')).sort()
52
+ .map(name => ({ ...bundle, name, installedName: `${bundle.prefix}${name}` })));
53
+ const destinations = entries.map(entry => join(target, entry.installedName));
54
+ for (const destination of destinations) {
55
+ // lstat detects dangling symlinks too.
56
+ try {
57
+ lstatSync(destination);
58
+ throw new Error(`Skill already exists; no files overwritten: ${destination}`);
59
+ } catch (error) {
60
+ if (error.code !== 'ENOENT') { throw error; }
61
+ }
62
+ }
63
+ if (dryRun) { return { dry_run: true, destinations }; }
64
+ mkdirSync(target, { recursive: true });
65
+ for (let index = 0; index < entries.length; index++) {
66
+ const entry = entries[index];
67
+ const destination = destinations[index];
68
+ cpSync(join(entry.plugin, 'skills', entry.name), destination, { recursive: true, errorOnExist: true, force: false });
69
+ for (const notice of ['LICENSE', 'NOTICE']) { cpSync(join(entry.plugin, notice), join(destination, notice)); }
70
+ for (const resources of ['rules', 'agents']) {
71
+ if (existsSync(join(entry.plugin, resources))) {
72
+ cpSync(join(entry.plugin, resources), join(destination, resources), { recursive: true, errorOnExist: true, force: false });
73
+ }
74
+ }
75
+ // Stack-local names take precedence; shared core commands retain their core names.
76
+ const mapping = new Map(entries.filter(item => item.prefix === 'aiwf-').map(item => [item.name, item.installedName]));
77
+ for (const item of entries.filter(item => item.plugin === entry.plugin)) {
78
+ mapping.set(item.name, item.installedName);
79
+ }
80
+ const commands = new RegExp(`(?<![.\\w-])/(${[...mapping.keys()].join('|')})(?![\\w-])`, 'g');
81
+ const namedSkills = new RegExp('`(' + [...mapping.keys()].join('|') + ')`', 'g');
82
+ for (const file of markdownFiles(destination)) {
83
+ const original = readFileSync(file, 'utf8');
84
+ let text = original;
85
+ if (file === join(destination, 'SKILL.md')) {
86
+ text = text.replace(/^name: .+$/m, `name: ${entry.installedName}`);
87
+ }
88
+ text = text.replace(commands, (_, name) => `/${mapping.get(name)}`)
89
+ .replace(namedSkills, (_, name) => '`' + mapping.get(name) + '`');
90
+ if (text !== original) {
91
+ text += '\n<!-- AIWF installation modification: prefixed skill names and command references throughout bundled Markdown. -->\n';
92
+ writeFileSync(file, text);
93
+ }
94
+ }
95
+ }
96
+ return { dry_run: false, installed: destinations };
97
+ }
98
+
99
+ if (process.argv[1] && import.meta.url === pathToFileURL(resolve(process.argv[1])).href) {
100
+ try {
101
+ const args = process.argv.slice(2);
102
+ let project;
103
+ let dryRun = false;
104
+ let stack;
105
+ const delegates = [];
106
+ for (let index = 0; index < args.length; index++) {
107
+ if (args[index] === '--project' && args[index + 1] && !args[index + 1].startsWith('--') && !project) {
108
+ project = args[++index];
109
+ } else if (args[index] === '--dry-run' && !dryRun) {
110
+ dryRun = true;
111
+ } else if (args[index] === '--stack' && args[index + 1] && !args[index + 1].startsWith('--') && !stack) {
112
+ stack = args[++index];
113
+ } else if (args[index] === '--delegate' && args[index + 1] && !args[index + 1].startsWith('--')) {
114
+ delegates.push(args[++index]);
115
+ } else if (args[index] === '--help') {
116
+ console.log(`node scripts/install-spec-skills.mjs --project <existing-project> [--stack <${supportedStacks.join('|')}>] [--delegate <${supportedDelegates.join('|')}> ...] [--dry-run]`);
117
+ process.exit(0);
118
+ } else { throw new Error(`Unknown or incomplete argument: ${args[index]}`); }
119
+ }
120
+ if (!project) { throw new Error('--project is required'); }
121
+ console.log(JSON.stringify(installSpecSkills(project, { dryRun, stack, delegates }), null, 2));
122
+ } catch (error) {
123
+ console.error(error.message);
124
+ process.exitCode = 1;
125
+ }
126
+ }
@@ -0,0 +1,145 @@
1
+ #!/usr/bin/env node
2
+ import assert from 'node:assert/strict';
3
+ import { createHash } from 'node:crypto';
4
+ import { existsSync, readFileSync, readdirSync } from 'node:fs';
5
+ import { dirname, join, resolve } from 'node:path';
6
+ import { fileURLToPath } from 'node:url';
7
+ import { supportedStacks } from './install-spec-skills.mjs';
8
+
9
+ const root = resolve(dirname(fileURLToPath(import.meta.url)), '..');
10
+ const read = path => readFileSync(path, 'utf8');
11
+ const digest = bytes => createHash('sha256').update(bytes).digest('hex');
12
+ const market = JSON.parse(read(join(root, '.claude-plugin/marketplace.json')));
13
+ const pkg = JSON.parse(read(join(root, 'package.json')));
14
+ let verified = 0;
15
+ let modified = 0;
16
+ let skills = 0;
17
+ let importedSkills = 0;
18
+ let commit;
19
+
20
+ // AIWF-owned skill directories in aiwf-spec are authored here, not imported, so they
21
+ // carry no upstream provenance. Keep this list narrow: only the named skill roots are
22
+ // exempt, never arbitrary untracked resources in the plugin.
23
+ const aiwfOwnedSkillRoots = ['skills/workflow/', 'skills/sync-docs/'];
24
+ const isAiwfOwned = relative => aiwfOwnedSkillRoots.some(directory => relative.startsWith(directory));
25
+
26
+ function files(directory) {
27
+ return readdirSync(directory, { withFileTypes: true }).flatMap(entry => {
28
+ const file = join(directory, entry.name);
29
+ return entry.isDirectory() ? files(file) : [file];
30
+ });
31
+ }
32
+
33
+ for (const name of ['aiwf-core', 'aiwf-spec', ...supportedStacks.map(stack => `aiwf-${stack}`)]) {
34
+ const plugin = join(root, 'plugins', name);
35
+ const provenance = name === 'aiwf-spec' ? { upstream_sha256: {}, modified_sha256: {} }
36
+ : JSON.parse(read(join(plugin, 'UPSTREAM.json')));
37
+ if (name !== 'aiwf-spec') {
38
+ assert.equal(provenance.repository, 'https://github.com/AI-Unified-Process/marketplace');
39
+ assert.match(provenance.commit, /^[0-9a-f]{40}$/);
40
+ commit ??= provenance.commit;
41
+ assert.equal(provenance.commit, commit, `Mixed upstream versions: ${name}`);
42
+ }
43
+ const allowedModifications = name === 'aiwf-core' ? ['NOTICE'] : [];
44
+ for (const [path, expected] of Object.entries(provenance.modified_sha256)) {
45
+ assert.ok(allowedModifications.includes(path), `Upstream sources must stay unchanged: ${name}/${path}`);
46
+ assert.equal(digest(readFileSync(join(plugin, path))), expected, `Modified resource changed: ${name}/${path}`);
47
+ modified++;
48
+ }
49
+ for (const [path, expected] of Object.entries(provenance.upstream_sha256)) {
50
+ const bytes = readFileSync(join(plugin, path));
51
+ if (Object.hasOwn(provenance.modified_sha256, path)) {
52
+ assert.equal(path, 'NOTICE');
53
+ assert.match(bytes.toString(), /derived from the AI Unified Process Marketplace by Simon Martinelli/);
54
+ } else {
55
+ assert.equal(digest(bytes), expected, `Upstream resource changed: ${name}/${path}`);
56
+ verified++;
57
+ }
58
+ if (path.endsWith('/SKILL.md')) { importedSkills++; }
59
+ }
60
+ for (const directory of ['skills', 'rules', 'agents']) {
61
+ if (!existsSync(join(plugin, directory))) { continue; }
62
+ for (const file of files(join(plugin, directory))) {
63
+ const relative = file.slice(plugin.length + 1);
64
+ if (name === 'aiwf-spec' && isAiwfOwned(relative)) { continue; }
65
+ assert.ok(Object.hasOwn(provenance.upstream_sha256, relative), `Resource missing provenance: ${name}/${relative}`);
66
+ }
67
+ }
68
+ const names = readdirSync(join(plugin, 'skills')).sort();
69
+ if (name === 'aiwf-core') { assert.equal(names.length, 7); }
70
+ if (name === 'aiwf-spec') { assert.deepEqual(names, ['sync-docs', 'workflow']); }
71
+ skills += names.length;
72
+ for (const skill of names) {
73
+ const file = join(plugin, 'skills', skill, 'SKILL.md');
74
+ const text = read(file);
75
+ assert.match(text, new RegExp(`^---\\nname: ${skill}\\n`, 'm'), `Skill name mismatch: ${name}/${skill}`);
76
+ assert.match(text, /^description: .+/m);
77
+ assert.match(text, /Apache(-| License, Version )2\.0/);
78
+ for (const markdown of files(dirname(file)).filter(path => path.endsWith('.md'))) {
79
+ const prose = read(markdown).replace(/^```[^\n]*\n[\s\S]*?^```\s*$/gm, '');
80
+ for (const match of prose.matchAll(/\]\(([^\s)]+)\)/g)) {
81
+ const ref = match[1].split('#')[0];
82
+ // Project-artifact links in template examples are not bundled resources.
83
+ if (!/^(references|scripts)\//.test(ref)) { continue; }
84
+ assert.ok(existsSync(resolve(dirname(markdown), ref)), `Broken bundled reference: ${name}/${skill}: ${ref}`);
85
+ }
86
+ }
87
+ }
88
+ const entry = market.plugins.find(p => p.name === name);
89
+ assert.ok(entry, `Marketplace entry missing: ${name}`);
90
+ assert.equal(entry.source, `./plugins/${name}`);
91
+ const manifest = JSON.parse(read(join(plugin, '.claude-plugin/plugin.json')));
92
+ assert.equal(manifest.name, entry.name);
93
+ assert.equal(manifest.version, entry.version);
94
+ assert.ok(pkg.files.includes(`plugins/${name}/`), `Package excludes plugin: ${name}`);
95
+ }
96
+ assert.equal(importedSkills, 31);
97
+ const delegationTargets = ['claude', 'codex'];
98
+ for (const target of delegationTargets) {
99
+ const name = `aiwf-delegate-${target}`;
100
+ const plugin = join(root, 'plugins', name);
101
+ const expectedSkill = `delegate-${target}`;
102
+ assert.deepEqual(readdirSync(join(plugin, 'skills')), [expectedSkill]);
103
+ const skill = read(join(plugin, 'skills', expectedSkill, 'SKILL.md'));
104
+ assert.match(skill, new RegExp(`^name: ${expectedSkill}$`, 'm'));
105
+ assert.match(skill, /^disable-model-invocation: true$/m);
106
+ assert.match(read(join(plugin, 'skills', expectedSkill, 'agents/openai.yaml')), /allow_implicit_invocation: false/);
107
+ for (const requiredPolicy of [
108
+ /current user request contains the literal token `--cross-cli`/,
109
+ /does not consent to starting a separate CLI process/,
110
+ /For cross-CLI work, default to read-only/,
111
+ /explicitly asks for file changes, with the files or directory scope stated/,
112
+ /Native subagents follow the current host's normal permission policy/,
113
+ /If the native subagent tool is unavailable, report that route as unavailable and stop, even when `--cross-cli` is present/,
114
+ /Do not substitute this host's native agents, another provider, or do the task yourself/,
115
+ /Do not substitute `npx`, a bundled or renamed binary, or another provider's CLI/,
116
+ /same operating-system account and inherits the current working directory and environment/,
117
+ /not a security-isolation boundary/,
118
+ /Do not expose environment secrets in prompts or output/,
119
+ /instead of retrying through another tool, broader access, or `sudo`/
120
+ ]) {
121
+ assert.match(skill, requiredPolicy, `Missing delegation safety policy: ${name} ${requiredPolicy}`);
122
+ }
123
+ if (target === 'claude') {
124
+ assert.match(skill, /--permission-mode plan/);
125
+ assert.match(skill, /Never add `--dangerously-skip-permissions`/);
126
+ } else {
127
+ assert.match(skill, /Codex `exec` defaults to a read-only sandbox/);
128
+ assert.match(skill, /Add `--sandbox workspace-write` only if the current user request explicitly authorizes writes/);
129
+ assert.match(skill, /Never add `--full-auto`, `--danger-full-access`/);
130
+ }
131
+ const entry = market.plugins.find(item => item.name === name);
132
+ assert.ok(entry, `Marketplace entry missing: ${name}`);
133
+ assert.equal(entry.source, `./plugins/${name}`);
134
+ assert.equal(entry.version, '0.1.0');
135
+ for (const manifestPath of ['.claude-plugin/plugin.json', 'plugin.json']) {
136
+ const manifest = JSON.parse(read(join(plugin, manifestPath)));
137
+ assert.equal(manifest.name, name);
138
+ assert.equal(manifest.version, entry.version);
139
+ }
140
+ assert.ok(pkg.files.includes(`plugins/${name}/`), `Package excludes plugin: ${name}`);
141
+ skills++;
142
+ }
143
+ assert.equal(skills, 35);
144
+ assert.equal(pkg.bin['aiwf-spec'], './src/cli/spec-cli.js');
145
+ console.log(`AIWF: ${importedSkills} unchanged upstream skills + ${skills - importedSkills} AIWF skills (workflow, sync-docs and optional delegates); ${verified} unchanged upstream resources, ${modified} attributed NOTICE modification; references and manifests validated.`);
@@ -0,0 +1,292 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * aiwf-spec - bounded AIWF specification workflow CLI.
5
+ *
6
+ * Commands: init, pin, check, packet. Built-in Node modules only.
7
+ * This CLI records local snapshots and evidence; it never claims approval.
8
+ */
9
+
10
+ import { existsSync, realpathSync } from 'node:fs';
11
+ import { pathToFileURL } from 'node:url';
12
+
13
+ import {
14
+ initSpec,
15
+ pinSpec,
16
+ checkSpec,
17
+ createReviewPacket,
18
+ writeReviewPacket
19
+ } from '../lib/spec-workflow.js';
20
+
21
+ const EXIT_OK = 0;
22
+ const EXIT_FAILURE = 1;
23
+ const EXIT_USAGE = 2;
24
+
25
+ export class UsageError extends Error {
26
+ constructor(message) {
27
+ super(message);
28
+ this.name = 'UsageError';
29
+ this.code = 'usage_error';
30
+ }
31
+ }
32
+
33
+ export const COMMANDS = {
34
+ init: {
35
+ summary: 'Create minimal Draft AIUP-compatible spec files (never overwrites).',
36
+ string: ['root', 'name'],
37
+ boolean: ['json'],
38
+ required: ['root', 'name']
39
+ },
40
+ pin: {
41
+ summary: 'Snapshot the spec into .aiwf/spec-pin.json.',
42
+ string: ['root'],
43
+ boolean: ['json', 'refresh'],
44
+ required: ['root']
45
+ },
46
+ check: {
47
+ summary: 'Compare the pinned spec against the current working tree (read-only).',
48
+ string: ['root'],
49
+ boolean: ['json'],
50
+ required: ['root']
51
+ },
52
+ packet: {
53
+ summary: 'Build a local review packet from a pinned spec and an evidence file.',
54
+ string: ['root', 'evidence', 'output'],
55
+ boolean: ['json', 'force'],
56
+ required: ['root', 'evidence']
57
+ }
58
+ };
59
+
60
+ function camel(key) {
61
+ return key.replace(/-([a-z])/g, (_, char) => char.toUpperCase());
62
+ }
63
+
64
+ /**
65
+ * Strict option parser: unknown options, missing values, and stray positionals are rejected.
66
+ */
67
+ export function parseOptions(args, config) {
68
+ const options = {};
69
+ const positionals = [];
70
+
71
+ for (let i = 0; i < args.length; i += 1) {
72
+ const arg = args[i];
73
+ if (arg === '-h' || arg === '--help') {
74
+ options.help = true;
75
+ continue;
76
+ }
77
+ if (arg.startsWith('--')) {
78
+ let key = arg.slice(2);
79
+ let value;
80
+ const eq = key.indexOf('=');
81
+ if (eq !== -1) {
82
+ value = key.slice(eq + 1);
83
+ key = key.slice(0, eq);
84
+ }
85
+ const name = camel(key);
86
+ if (config.boolean.includes(name)) {
87
+ if (value !== undefined) {
88
+ throw new UsageError(`Option --${key} does not take a value.`);
89
+ }
90
+ options[name] = true;
91
+ } else if (config.string.includes(name)) {
92
+ if (value === undefined) {
93
+ value = args[i + 1];
94
+ i += 1;
95
+ }
96
+ if (value === undefined || value === '' || value.startsWith('--')) {
97
+ throw new UsageError(`Missing value for option --${key}.`);
98
+ }
99
+ options[name] = value;
100
+ } else {
101
+ throw new UsageError(`Unknown option: --${key}`);
102
+ }
103
+ } else if (arg.startsWith('-') && arg.length > 1) {
104
+ throw new UsageError(`Unknown option: ${arg}`);
105
+ } else {
106
+ positionals.push(arg);
107
+ }
108
+ }
109
+
110
+ if (positionals.length > 0) {
111
+ throw new UsageError(`Unexpected argument: ${positionals[0]}`);
112
+ }
113
+
114
+ return options;
115
+ }
116
+
117
+ function printHelp(stream = process.stdout) {
118
+ const lines = [
119
+ 'aiwf-spec - bounded AIWF specification workflow',
120
+ '',
121
+ 'Usage: aiwf-spec <command> [options]',
122
+ '',
123
+ 'Commands:'
124
+ ];
125
+ for (const [name, config] of Object.entries(COMMANDS)) {
126
+ lines.push(` ${name.padEnd(8)} ${config.summary}`);
127
+ }
128
+ lines.push(
129
+ '',
130
+ 'Options:',
131
+ ' --root <path> Project root directory (required for all commands).',
132
+ ' --name <title> Product title for init.',
133
+ ' --evidence <file> Evidence JSON file for packet.',
134
+ ' --output <path> Packet output path (default .aiwf/review-packet.json).',
135
+ ' --refresh Overwrite an existing, differing pin (pin).',
136
+ ' --force Overwrite an existing review packet (packet).',
137
+ ' --json Emit machine-readable JSON on stdout.',
138
+ ' -h, --help Show this help.',
139
+ '',
140
+ 'Notes:',
141
+ ' Snapshots cover docs/vision.md, requirements.md, glossary.md, entity_model.md,',
142
+ ' use_cases.puml, *.md under use_cases/test_cases/architecture/plans,',
143
+ ' *.bpmn under docs/processes, and docs/.spec-lint-baseline.json when present.',
144
+ ' Only unresolved TODO / NEEDS CLARIFICATION markers block pinning; Draft and',
145
+ ' Reviewed status words are recorded as written and are not approvals.',
146
+ ' Structural and semantic lint is not performed here; it remains an upstream step.',
147
+ '',
148
+ 'Exit codes: 0 success, 1 spec/pin failure, 2 usage error.'
149
+ );
150
+ stream.write(`${lines.join('\n')}\n`);
151
+ }
152
+
153
+ function emitJson(payload) {
154
+ process.stdout.write(`${JSON.stringify(payload, null, 2)}\n`);
155
+ }
156
+
157
+ function emitError(command, error, json) {
158
+ const code = error.code || 'error';
159
+ if (json) {
160
+ emitJson({ command, error: { code, message: error.message } });
161
+ } else {
162
+ process.stderr.write(`${code}: ${error.message}\n`);
163
+ }
164
+ }
165
+
166
+ function runInit(options) {
167
+ const result = initSpec(options.root, options.name);
168
+ if (options.json) {
169
+ return { code: EXIT_OK, payload: result };
170
+ }
171
+ process.stdout.write(
172
+ `Initialized spec at ${result.root}\nCreated: ${result.created.length}, preserved: ${result.preserved.length}\n`
173
+ );
174
+ return { code: EXIT_OK };
175
+ }
176
+
177
+ function runPin(options) {
178
+ const result = pinSpec(options.root, { refresh: Boolean(options.refresh) });
179
+ if (options.json) {
180
+ return { code: EXIT_OK, payload: result };
181
+ }
182
+ const verb = result.unchanged ? 'Pin unchanged' : 'Pinned';
183
+ process.stdout.write(`${verb} ${result.pin.files.length} files (digest ${result.digest}).\n`);
184
+ return { code: EXIT_OK };
185
+ }
186
+
187
+ function runCheck(options) {
188
+ const result = checkSpec(options.root);
189
+ const code = result.in_sync ? EXIT_OK : EXIT_FAILURE;
190
+ if (options.json) {
191
+ return { code, payload: result };
192
+ }
193
+ process.stdout.write(`status: ${result.status}\n`);
194
+ if (result.added.length > 0) {
195
+ process.stdout.write(`added: ${result.added.join(', ')}\n`);
196
+ }
197
+ if (result.changed.length > 0) {
198
+ process.stdout.write(`changed: ${result.changed.join(', ')}\n`);
199
+ }
200
+ if (result.deleted.length > 0) {
201
+ process.stdout.write(`deleted: ${result.deleted.join(', ')}\n`);
202
+ }
203
+ if (result.draft_markers.length > 0) {
204
+ process.stdout.write(`draft markers: ${result.draft_markers.map(m => m.path).join(', ')}\n`);
205
+ }
206
+ return { code };
207
+ }
208
+
209
+ function runPacket(options) {
210
+ const packet = createReviewPacket(options.root, options.evidence, { cwd: process.cwd() });
211
+ const written = writeReviewPacket(options.root, packet, {
212
+ output: options.output,
213
+ force: Boolean(options.force),
214
+ cwd: process.cwd()
215
+ });
216
+ if (options.json) {
217
+ return { code: EXIT_OK, payload: packet };
218
+ }
219
+ process.stdout.write(`Wrote review packet: ${written.output} (status: ${packet.status})\n`);
220
+ return { code: EXIT_OK };
221
+ }
222
+
223
+ const RUNNERS = {
224
+ init: runInit,
225
+ pin: runPin,
226
+ check: runCheck,
227
+ packet: runPacket
228
+ };
229
+
230
+ /**
231
+ * Execute the CLI. Returns the process exit code and writes all output.
232
+ */
233
+ export function run(argv = process.argv.slice(2)) {
234
+ const [command, ...rest] = argv;
235
+
236
+ if (!command || command === 'help' || command === '--help' || command === '-h') {
237
+ printHelp();
238
+ return EXIT_OK;
239
+ }
240
+
241
+ const config = COMMANDS[command];
242
+ if (!config) {
243
+ process.stderr.write(`Unknown command: ${command}\n`);
244
+ printHelp(process.stderr);
245
+ return EXIT_USAGE;
246
+ }
247
+
248
+ let options;
249
+ try {
250
+ options = parseOptions(rest, config);
251
+ } catch (error) {
252
+ process.stderr.write(`${error.message}\n`);
253
+ return EXIT_USAGE;
254
+ }
255
+
256
+ if (options.help) {
257
+ printHelp();
258
+ return EXIT_OK;
259
+ }
260
+
261
+ for (const required of config.required) {
262
+ if (options[required] === undefined) {
263
+ process.stderr.write(`Missing required option: --${required.replace(/[A-Z]/g, c => `-${c.toLowerCase()}`)}\n`);
264
+ return EXIT_USAGE;
265
+ }
266
+ }
267
+
268
+ try {
269
+ const result = RUNNERS[command](options);
270
+ if (result.payload !== undefined) {
271
+ emitJson(result.payload);
272
+ }
273
+ return result.code;
274
+ } catch (error) {
275
+ emitError(command, error, Boolean(options.json));
276
+ return EXIT_FAILURE;
277
+ }
278
+ }
279
+
280
+ export function main(argv = process.argv.slice(2)) {
281
+ const code = run(argv);
282
+ process.exitCode = code;
283
+ return code;
284
+ }
285
+
286
+ const isDirect = process.argv[1] && existsSync(process.argv[1])
287
+ && import.meta.url === pathToFileURL(realpathSync(process.argv[1])).href;
288
+ if (isDirect) {
289
+ main();
290
+ }
291
+
292
+ export default { run, main, parseOptions, COMMANDS };