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,542 @@
1
+ #!/usr/bin/env python3
2
+ #
3
+ # Copyright 2025-2026 Simon Martinelli and the AI Unified Process contributors.
4
+ # Part of the AI Unified Process — https://unifiedprocess.ai
5
+ # Licensed under the Apache License, Version 2.0. See LICENSE and NOTICE.
6
+ """Enumerate the paths through a BPMN 2.0 business process model.
7
+
8
+ Reads a .bpmn file (plain BPMN 2.0 XML, diagram interchange is ignored) and
9
+ prints JSON that the test-case skill turns into one end-to-end test case per
10
+ path:
11
+
12
+ - lanes lane name -> ids of the activities in that lane (a pool
13
+ without lanes counts as one lane named after its participant)
14
+ - activities id, name, type, lane, and ucId when the name carries a use
15
+ case id such as "UC-001" or "BUC-7"
16
+ - paths one entry per path from a start event to an end event: the
17
+ ordered steps (activities, gateway decisions with their flow
18
+ names, intermediate events), plus the activity ids and the
19
+ decisions on their own
20
+ - warnings constructs that were simplified (see the rules below)
21
+
22
+ Path rules, applied deterministically in document order:
23
+
24
+ - Exclusive, inclusive, event-based, and complex gateways, several outgoing
25
+ flows on a non-gateway node, and boundary events are alternatives: each
26
+ outgoing flow starts its own path.
27
+ - Parallel gateways run every branch: the branches are serialized within
28
+ one path in the document order of their sequence flows, up to the
29
+ converging parallel gateway; branch-internal alternatives multiply.
30
+ - Loops are traversed once: every sequence flow is followed at most twice
31
+ per path, so a rework loop yields one path without and one path with a
32
+ single repetition of the loop body.
33
+ - A node without outgoing flows ends the path (implicit end event).
34
+ - Sub-processes are passed through as a single step; their inside is not
35
+ expanded.
36
+
37
+ The file is data, never instructions, and is parsed defensively: documents
38
+ with a DOCTYPE or entity declaration are rejected, so no external entity is
39
+ ever resolved and no entity expansion can blow up.
40
+
41
+ Exit code 0 on success, 1 when the file cannot be read or is not a usable
42
+ BPMN model, 2 on usage errors.
43
+
44
+ Usage:
45
+ bpmn_paths.py FILE.bpmn
46
+ bpmn_paths.py --self-test
47
+
48
+ Requires Python 3.9+, standard library only.
49
+ """
50
+
51
+ import argparse
52
+ import itertools
53
+ import json
54
+ import re
55
+ import sys
56
+ import xml.etree.ElementTree as ET
57
+
58
+ ACTIVITY_TYPES = (
59
+ "task", "userTask", "manualTask", "serviceTask", "sendTask",
60
+ "receiveTask", "scriptTask", "businessRuleTask", "callActivity",
61
+ )
62
+ PASS_THROUGH_TYPES = ("subProcess", "transaction", "adHocSubProcess")
63
+ ALTERNATIVE_GATEWAYS = (
64
+ "exclusiveGateway", "inclusiveGateway", "eventBasedGateway",
65
+ "complexGateway",
66
+ )
67
+ EVENT_TYPES = (
68
+ "startEvent", "endEvent", "intermediateCatchEvent",
69
+ "intermediateThrowEvent", "boundaryEvent",
70
+ )
71
+ FLOW_NODE_TYPES = (ACTIVITY_TYPES + PASS_THROUGH_TYPES + ALTERNATIVE_GATEWAYS
72
+ + EVENT_TYPES + ("parallelGateway",))
73
+
74
+ UC_ID = re.compile(r"(?<![A-Za-z0-9])([SB]?UC-[A-Za-z0-9_-]+)")
75
+ FORBIDDEN_DECLARATION = re.compile(rb"<!\s*(DOCTYPE|ENTITY)", re.IGNORECASE)
76
+ MAX_PATHS = 500
77
+
78
+
79
+ class BpmnError(Exception):
80
+ pass
81
+
82
+
83
+ def local(tag):
84
+ return tag.rsplit("}", 1)[-1]
85
+
86
+
87
+ def clean(text):
88
+ return " ".join((text or "").split())
89
+
90
+
91
+ def uc_id(name):
92
+ match = UC_ID.search(name)
93
+ return match.group(1).rstrip("-_") if match else None
94
+
95
+
96
+ # ---------------------------------------------------------------------------
97
+ # Parsing
98
+ # ---------------------------------------------------------------------------
99
+
100
+ def parse_xml(data):
101
+ if FORBIDDEN_DECLARATION.search(data):
102
+ raise BpmnError("DOCTYPE or ENTITY declarations are not allowed "
103
+ "in a BPMN file")
104
+ try:
105
+ root = ET.fromstring(data)
106
+ except ET.ParseError as exc:
107
+ raise BpmnError("not well-formed XML: " + str(exc))
108
+ if local(root.tag) != "definitions":
109
+ raise BpmnError("root element is <" + local(root.tag)
110
+ + ">, expected BPMN <definitions>")
111
+ return root
112
+
113
+
114
+ class Process:
115
+ def __init__(self, element, pool_name):
116
+ self.id = element.get("id", "")
117
+ self.nodes = {} # id -> (type, name), direct children only
118
+ self.order = [] # node ids in document order
119
+ self.flows = [] # (id, name, source, target) in document order
120
+ self.boundaries = {} # activity id -> [boundary event ids]
121
+ self.lane_of = {} # node id -> lane name
122
+ for child in element:
123
+ kind = local(child.tag)
124
+ node_id = child.get("id")
125
+ if kind in FLOW_NODE_TYPES and node_id:
126
+ self.nodes[node_id] = (kind, clean(child.get("name")))
127
+ self.order.append(node_id)
128
+ if kind == "boundaryEvent" and child.get("attachedToRef"):
129
+ self.boundaries.setdefault(
130
+ child.get("attachedToRef"), []).append(node_id)
131
+ elif kind == "sequenceFlow":
132
+ self.flows.append((child.get("id", ""),
133
+ clean(child.get("name")),
134
+ child.get("sourceRef"),
135
+ child.get("targetRef")))
136
+ elif kind == "laneSet":
137
+ self._read_lanes(child)
138
+ if not self.lane_of and pool_name:
139
+ for node_id in self.order:
140
+ self.lane_of[node_id] = pool_name
141
+ self.outgoing = {}
142
+ self.incoming = {}
143
+ for flow in self.flows:
144
+ if flow[2] in self.nodes and flow[3] in self.nodes:
145
+ self.outgoing.setdefault(flow[2], []).append(flow)
146
+ self.incoming.setdefault(flow[3], []).append(flow)
147
+
148
+ def _read_lanes(self, lane_set):
149
+ # Nested lanes: the innermost lane wins because it is visited last.
150
+ for lane in lane_set:
151
+ if local(lane.tag) != "lane":
152
+ continue
153
+ name = clean(lane.get("name")) or lane.get("id", "")
154
+ for ref in lane:
155
+ if local(ref.tag) == "flowNodeRef" and ref.text:
156
+ self.lane_of[ref.text.strip()] = name
157
+ elif local(ref.tag) == "childLaneSet":
158
+ self._read_lanes(ref)
159
+
160
+ def kind(self, node_id):
161
+ return self.nodes[node_id][0]
162
+
163
+ def name(self, node_id):
164
+ return self.nodes[node_id][1]
165
+
166
+
167
+ # ---------------------------------------------------------------------------
168
+ # Path enumeration
169
+ # ---------------------------------------------------------------------------
170
+
171
+ class Walker:
172
+ """Enumerates (steps, terminal, followed flows) for one process.
173
+
174
+ terminal is ("end", node id) or ("join", parallel gateway id); a join
175
+ terminal is only produced inside a parallel branch and is consumed by
176
+ the split that started the branch.
177
+ """
178
+
179
+ def __init__(self, process, warnings):
180
+ self.p = process
181
+ self.warnings = warnings
182
+ self.truncated = False
183
+
184
+ def warn(self, message):
185
+ if message not in self.warnings:
186
+ self.warnings.append(message)
187
+
188
+ def step(self, node_id):
189
+ kind = self.p.kind(node_id)
190
+ entry = {"id": node_id, "name": self.p.name(node_id), "type": kind}
191
+ if kind in ACTIVITY_TYPES:
192
+ entry["kind"] = "activity"
193
+ elif kind in PASS_THROUGH_TYPES:
194
+ entry["kind"] = "subprocess"
195
+ else:
196
+ entry["kind"] = "event"
197
+ return entry
198
+
199
+ def choices(self, node_id):
200
+ """Outgoing alternatives: sequence flows plus attached boundary events."""
201
+ result = [(flow, flow[3]) for flow in self.p.outgoing.get(node_id, [])]
202
+ for boundary in self.p.boundaries.get(node_id, []):
203
+ result.append((None, boundary))
204
+ return result
205
+
206
+ def walk(self, node_id, used, in_split):
207
+ kind = self.p.kind(node_id)
208
+
209
+ if kind == "parallelGateway":
210
+ if len(self.p.incoming.get(node_id, [])) > 1 and in_split:
211
+ return [([], ("join", node_id), used)]
212
+ outgoing = self.p.outgoing.get(node_id, [])
213
+ if len(outgoing) > 1:
214
+ return self.split(node_id, outgoing, used, in_split)
215
+ return self.follow(node_id, [], outgoing, used, in_split, None)
216
+
217
+ if kind in ALTERNATIVE_GATEWAYS:
218
+ return self.follow(node_id, [], self.p.outgoing.get(node_id, []),
219
+ used, in_split, node_id)
220
+
221
+ prefix = [self.step(node_id)]
222
+ if kind == "endEvent":
223
+ return [(prefix, ("end", node_id), used)]
224
+ if kind in PASS_THROUGH_TYPES:
225
+ self.warn("sub-process " + node_id
226
+ + " is passed through as one step; its inside is "
227
+ "not expanded")
228
+ choices = self.choices(node_id)
229
+ if not choices:
230
+ self.warn("node " + node_id + " has no outgoing flow and ends "
231
+ "the path as an implicit end event")
232
+ return [(prefix, ("end", node_id), used)]
233
+ results = []
234
+ for flow, target in choices:
235
+ if flow is None:
236
+ decision = {"kind": "decision", "gateway": node_id,
237
+ "gatewayName": self.p.name(node_id),
238
+ "flow": None,
239
+ "flowName": "boundary: "
240
+ + (self.p.name(target) or target),
241
+ "target": target}
242
+ for steps, terminal, u in self.walk(target, used, in_split):
243
+ results.append((prefix + [decision] + steps, terminal, u))
244
+ else:
245
+ decision_at = node_id if len(choices) > 1 else None
246
+ results.extend(self.follow(node_id, prefix, [flow], used,
247
+ in_split, decision_at))
248
+ self.check_limit(results)
249
+ return results
250
+
251
+ def follow(self, node_id, prefix, flows, used, in_split, decision_at):
252
+ """Continue along each flow; records a decision when decision_at is set."""
253
+ if not flows:
254
+ self.warn("node " + node_id + " has no outgoing flow and ends "
255
+ "the path")
256
+ return [(prefix, ("end", node_id), used)]
257
+ alternatives = decision_at is not None and len(flows) > 1
258
+ if decision_at is not None and not alternatives and \
259
+ self.p.kind(node_id) in ALTERNATIVE_GATEWAYS:
260
+ decision_at = None # converging gateway: no decision
261
+ results = []
262
+ for flow in flows:
263
+ flow_id, flow_name, _, target = flow
264
+ if used.count(flow_id) >= 2:
265
+ continue # loop already traversed once
266
+ head = list(prefix)
267
+ if decision_at is not None:
268
+ head.append({"kind": "decision", "gateway": decision_at,
269
+ "gatewayName": self.p.name(decision_at),
270
+ "flow": flow_id, "flowName": flow_name,
271
+ "target": target})
272
+ for steps, terminal, u in self.walk(target, used + (flow_id,),
273
+ in_split):
274
+ results.append((head + steps, terminal, u))
275
+ self.check_limit(results)
276
+ return results
277
+
278
+ def split(self, node_id, outgoing, used, in_split):
279
+ branches = []
280
+ for flow in outgoing:
281
+ if used.count(flow[0]) >= 2:
282
+ continue
283
+ branches.append(self.walk(flow[3], used + (flow[0],),
284
+ in_split + 1))
285
+ branches = [b for b in branches if b]
286
+ if not branches:
287
+ return []
288
+ results = []
289
+ for combination in itertools.product(*branches):
290
+ steps = []
291
+ merged = used
292
+ joins = []
293
+ last_end = None
294
+ for branch_steps, terminal, u in combination:
295
+ steps.extend(branch_steps)
296
+ merged += u[len(used):]
297
+ if terminal[0] == "join":
298
+ if terminal[1] not in joins:
299
+ joins.append(terminal[1])
300
+ else:
301
+ last_end = terminal
302
+ if not joins:
303
+ results.append((steps, last_end, merged))
304
+ continue
305
+ if len(joins) > 1:
306
+ self.warn("parallel gateway " + node_id + " converges in "
307
+ "several gateways; continuing after " + joins[0])
308
+ join = joins[0]
309
+ for rest, terminal, u in self.follow(
310
+ join, [], self.p.outgoing.get(join, []), merged,
311
+ in_split, None):
312
+ results.append((steps + rest, terminal, u))
313
+ self.check_limit(results)
314
+ return results
315
+
316
+ def check_limit(self, results):
317
+ if len(results) > MAX_PATHS:
318
+ del results[MAX_PATHS:]
319
+ if not self.truncated:
320
+ self.truncated = True
321
+ self.warn("more than %d paths; the rest were dropped"
322
+ % MAX_PATHS)
323
+
324
+
325
+ def analyze(data):
326
+ root = parse_xml(data)
327
+ pools = {}
328
+ for element in root.iter():
329
+ if local(element.tag) == "participant" and element.get("processRef"):
330
+ pools[element.get("processRef")] = clean(element.get("name"))
331
+
332
+ processes = [Process(el, pools.get(el.get("id"))) for el in root
333
+ if local(el.tag) == "process"]
334
+ if not processes:
335
+ raise BpmnError("the model contains no <process>")
336
+
337
+ warnings = []
338
+ lanes = {}
339
+ activities = []
340
+ paths = []
341
+ for process in processes:
342
+ for node_id in process.order:
343
+ kind = process.kind(node_id)
344
+ if kind not in ACTIVITY_TYPES:
345
+ continue
346
+ name = process.name(node_id)
347
+ lane = process.lane_of.get(node_id)
348
+ activity = {"id": node_id, "name": name, "type": kind,
349
+ "lane": lane, "process": process.id}
350
+ if uc_id(name):
351
+ activity["ucId"] = uc_id(name)
352
+ if not name:
353
+ warnings.append("activity " + node_id + " has no name")
354
+ activities.append(activity)
355
+ if lane:
356
+ lanes.setdefault(lane, []).append(node_id)
357
+
358
+ starts = [n for n in process.order
359
+ if process.kind(n) == "startEvent"
360
+ and not process.incoming.get(n)]
361
+ if not starts:
362
+ warnings.append("process " + process.id + " has no start event")
363
+ walker = Walker(process, warnings)
364
+ for start in starts:
365
+ found = walker.walk(start, (), 0)
366
+ if not found:
367
+ warnings.append("no complete path from start event " + start)
368
+ for steps, terminal, _ in found:
369
+ if len(paths) >= MAX_PATHS:
370
+ break
371
+ paths.append(make_path(len(paths) + 1, process, start,
372
+ terminal, steps))
373
+
374
+ return {"lanes": lanes, "activities": activities, "paths": paths,
375
+ "warnings": warnings}
376
+
377
+
378
+ def make_path(number, process, start, terminal, steps):
379
+ end = terminal[1] if terminal else None
380
+ return {
381
+ "id": "P%d" % number,
382
+ "process": process.id,
383
+ "start": start,
384
+ "startName": process.name(start),
385
+ "end": end,
386
+ "endName": process.name(end) if end else "",
387
+ "activities": [s["id"] for s in steps if s["kind"] == "activity"],
388
+ "decisions": [{k: v for k, v in s.items() if k != "kind"}
389
+ for s in steps if s["kind"] == "decision"],
390
+ "steps": steps,
391
+ }
392
+
393
+
394
+ # ---------------------------------------------------------------------------
395
+ # Self-test
396
+ # ---------------------------------------------------------------------------
397
+
398
+ NS = ('xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" '
399
+ 'id="defs" targetNamespace="http://example.com/bpmn"')
400
+
401
+ EXCLUSIVE_WITH_LANES = """<?xml version="1.0" encoding="UTF-8"?>
402
+ <definitions %s>
403
+ <collaboration id="c"><participant id="pool" name="Shop" processRef="p"/></collaboration>
404
+ <process id="p">
405
+ <laneSet id="ls">
406
+ <lane id="l1" name="Customer"><flowNodeRef>s</flowNodeRef><flowNodeRef>a</flowNodeRef></lane>
407
+ <lane id="l2" name="Clerk"><flowNodeRef>g</flowNodeRef><flowNodeRef>b</flowNodeRef>
408
+ <flowNodeRef>c</flowNodeRef><flowNodeRef>e1</flowNodeRef><flowNodeRef>e2</flowNodeRef></lane>
409
+ </laneSet>
410
+ <startEvent id="s" name="Order wanted"/>
411
+ <userTask id="a" name="UC-001 Place&#10;Order"/>
412
+ <exclusiveGateway id="g" name="In stock?"/>
413
+ <serviceTask id="b" name="Ship Order (UC-002)"/>
414
+ <task id="c" name="Cancel Order"/>
415
+ <endEvent id="e1" name="Shipped"/>
416
+ <endEvent id="e2" name="Cancelled"/>
417
+ <sequenceFlow id="f1" sourceRef="s" targetRef="a"/>
418
+ <sequenceFlow id="f2" sourceRef="a" targetRef="g"/>
419
+ <sequenceFlow id="f3" name="yes" sourceRef="g" targetRef="b"/>
420
+ <sequenceFlow id="f4" name="no" sourceRef="g" targetRef="c"/>
421
+ <sequenceFlow id="f5" sourceRef="b" targetRef="e1"/>
422
+ <sequenceFlow id="f6" sourceRef="c" targetRef="e2"/>
423
+ </process>
424
+ </definitions>
425
+ """ % NS
426
+
427
+ PARALLEL_AND_LOOP = """<?xml version="1.0" encoding="UTF-8"?>
428
+ <bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" id="d">
429
+ <bpmn:process id="p">
430
+ <bpmn:startEvent id="s"/>
431
+ <bpmn:parallelGateway id="fork"/>
432
+ <bpmn:task id="a" name="Pack"/>
433
+ <bpmn:task id="b" name="Invoice"/>
434
+ <bpmn:parallelGateway id="join"/>
435
+ <bpmn:task id="r" name="Review"/>
436
+ <bpmn:exclusiveGateway id="ok" name="Approved?"/>
437
+ <bpmn:task id="fix" name="Rework"/>
438
+ <bpmn:endEvent id="e"/>
439
+ <bpmn:sequenceFlow id="f1" sourceRef="s" targetRef="fork"/>
440
+ <bpmn:sequenceFlow id="f2" sourceRef="fork" targetRef="a"/>
441
+ <bpmn:sequenceFlow id="f3" sourceRef="fork" targetRef="b"/>
442
+ <bpmn:sequenceFlow id="f4" sourceRef="a" targetRef="join"/>
443
+ <bpmn:sequenceFlow id="f5" sourceRef="b" targetRef="join"/>
444
+ <bpmn:sequenceFlow id="f6" sourceRef="join" targetRef="r"/>
445
+ <bpmn:sequenceFlow id="f7" sourceRef="r" targetRef="ok"/>
446
+ <bpmn:sequenceFlow id="f8" name="yes" sourceRef="ok" targetRef="e"/>
447
+ <bpmn:sequenceFlow id="f9" name="no" sourceRef="ok" targetRef="fix"/>
448
+ <bpmn:sequenceFlow id="f10" sourceRef="fix" targetRef="r"/>
449
+ </bpmn:process>
450
+ </bpmn:definitions>
451
+ """
452
+
453
+ XXE = """<?xml version="1.0"?>
454
+ <!DOCTYPE definitions [<!ENTITY xxe SYSTEM "file:///etc/passwd">]>
455
+ <definitions %s><process id="p"><task id="t" name="&xxe;"/></process></definitions>
456
+ """ % NS
457
+
458
+
459
+ def self_test():
460
+ failures = []
461
+
462
+ def check(name, condition):
463
+ if not condition:
464
+ failures.append(name)
465
+
466
+ result = analyze(EXCLUSIVE_WITH_LANES.encode("utf-8"))
467
+ check("exclusive: two paths", len(result["paths"]) == 2)
468
+ check("exclusive: path activities",
469
+ [p["activities"] for p in result["paths"]] == [["a", "b"],
470
+ ["a", "c"]])
471
+ check("exclusive: flow names",
472
+ [p["decisions"][0]["flowName"] for p in result["paths"]]
473
+ == ["yes", "no"])
474
+ check("exclusive: lanes",
475
+ result["lanes"] == {"Customer": ["a"], "Clerk": ["b", "c"]})
476
+ ucs = {a["id"]: a.get("ucId") for a in result["activities"]}
477
+ check("exclusive: uc ids", ucs == {"a": "UC-001", "b": "UC-002",
478
+ "c": None})
479
+ check("exclusive: name whitespace normalized",
480
+ result["activities"][0]["name"] == "UC-001 Place Order")
481
+ check("exclusive: no warnings", result["warnings"] == [])
482
+
483
+ result = analyze(PARALLEL_AND_LOOP.encode("utf-8"))
484
+ check("parallel+loop: activity sequences",
485
+ [p["activities"] for p in result["paths"]]
486
+ == [["a", "b", "r"], ["a", "b", "r", "fix", "r"]])
487
+ check("parallel+loop: rework decision recorded",
488
+ [d["flowName"] for d in result["paths"][1]["decisions"]]
489
+ == ["no", "yes"])
490
+
491
+ try:
492
+ analyze(XXE.encode("utf-8"))
493
+ failures.append("xxe: DOCTYPE was accepted")
494
+ except BpmnError:
495
+ pass
496
+ try:
497
+ analyze(b"<html/>")
498
+ failures.append("non-bpmn: accepted")
499
+ except BpmnError:
500
+ pass
501
+
502
+ if failures:
503
+ for failure in failures:
504
+ print("SELF-TEST FAIL: " + failure)
505
+ return 1
506
+ print("self-test passed")
507
+ return 0
508
+
509
+
510
+ # ---------------------------------------------------------------------------
511
+ # CLI
512
+ # ---------------------------------------------------------------------------
513
+
514
+ def main(argv):
515
+ parser = argparse.ArgumentParser(
516
+ description="Enumerate the paths through a BPMN 2.0 process model.")
517
+ parser.add_argument("file", nargs="?", help=".bpmn file to analyze")
518
+ parser.add_argument("--self-test", action="store_true",
519
+ help="run the built-in fixtures and exit")
520
+ args = parser.parse_args(argv)
521
+
522
+ if args.self_test:
523
+ return self_test()
524
+ if not args.file:
525
+ parser.print_usage()
526
+ return 2
527
+ try:
528
+ with open(args.file, "rb") as handle:
529
+ result = analyze(handle.read())
530
+ except OSError as exc:
531
+ print(args.file + ": ERROR IO: " + str(exc), file=sys.stderr)
532
+ return 1
533
+ except BpmnError as exc:
534
+ print(args.file + ": ERROR: " + str(exc), file=sys.stderr)
535
+ return 1
536
+ result = dict({"file": args.file}, **result)
537
+ print(json.dumps(result, indent=2, ensure_ascii=False))
538
+ return 0
539
+
540
+
541
+ if __name__ == "__main__":
542
+ sys.exit(main(sys.argv[1:]))
@@ -0,0 +1,99 @@
1
+ ---
2
+ name: use-case-diagram
3
+ description: >
4
+ Creates or updates PlantUML use case diagrams defining actors, use cases,
5
+ and their relationships from requirements. Use when the user asks to
6
+ "create a use case diagram", "draw a UML diagram", "map actors to use cases",
7
+ "generate a .puml file", or mentions PlantUML, use case overview, actor
8
+ diagram, or system use cases.
9
+ ---
10
+
11
+ <!--
12
+ Copyright 2025-2026 Simon Martinelli and the AI Unified Process contributors.
13
+ Part of the AI Unified Process — https://unifiedprocess.ai
14
+ Licensed under the Apache License, Version 2.0. See LICENSE and NOTICE.
15
+ -->
16
+
17
+ # Use Case Diagram
18
+
19
+ ## Instructions
20
+
21
+ Create or update the PlantUML use case diagram at `docs/use_cases.puml` based on `docs/requirements.md`.
22
+
23
+ ## DO NOT
24
+
25
+ - Create diagrams without reading the requirements first
26
+ - Use non-standard PlantUML syntax
27
+ - Include implementation details in use case names
28
+ - Model technical steps such as validating, loading, or persisting data as separate use cases (see "Goal level")
29
+
30
+ ## Template
31
+
32
+ ```plantuml
33
+ @startuml Use Cases Overview
34
+ left to right direction
35
+
36
+ actor "User" as user
37
+ actor "Administrator" as admin
38
+
39
+ rectangle "System Name" {
40
+ usecase "UC-001\nDescription" as UC001
41
+ usecase "UC-002\nDescription" as UC002
42
+ usecase "UC-003\nDescription" as UC003
43
+ }
44
+
45
+ admin --> UC001
46
+ user --> UC002
47
+ user --> UC003
48
+
49
+ @enduml
50
+ ```
51
+
52
+ ## Goal level
53
+
54
+ Every use case in the diagram is a **user goal** — what Cockburn calls the sea level: one actor, one sitting, a
55
+ result the primary actor walks away with. Test each use case with one question:
56
+
57
+ > Is this use case a complete goal that the primary actor would recognize as valuable?
58
+
59
+ - **Too low (subfunction):** a step of a larger goal, often a technical one — "Validate METAR", "Load NOTAM",
60
+ "Persist Result". No dispatcher sits down to validate a METAR; they want to know whether an airport is suitable.
61
+ Fold such steps into the user goal they serve ("Determine Airport Suitability"), where they become steps of its
62
+ main success scenario. Keep a subfunction as its own use case only when several user goals share it, and then draw
63
+ it with `<<include>>` from each of them.
64
+ - **Too high (summary):** a whole area of work that spans many sittings — "Manage Flight Operations". Split it into
65
+ the user goals it is made of. A use case is a summary, too, when its flow hands the work over to another role,
66
+ waits for an outside event or a deadline, or runs branches in parallel for different actors — "Process Insurance
67
+ Claim" with a clerk, an assessor, and a payout after approval. Each role's part is a user goal of its own; the
68
+ flow that connects them is a business process, modeled in BPMN in `docs/processes/`, whose activities are those
69
+ use cases and from which `/test-case` derives the test cases. Do not describe the process inside a use case or
70
+ attach a process model to it.
71
+
72
+ A functional requirement that describes a step rather than a goal traces to the user goal use case that contains
73
+ the step.
74
+
75
+ ## Conventions
76
+
77
+ - Each use case has a unique id and a description
78
+ - Use Case ID: UC-{3-digit} (UC-001, UC-002, ...)
79
+ - Each use case should trace to at least one functional requirement
80
+ - Secondary actors (supporting roles and external systems such as a payment or weather service) are drawn as
81
+ actors too and connected to the use cases they support; they appear as `**Secondary Actors:**` in the use case
82
+ specification
83
+ - Add notes sparingly, only where relationships need clarification
84
+
85
+ ## Workflow
86
+
87
+ 1. Read the requirements at `docs/requirements.md`
88
+ 2. Read existing diagram at `docs/use_cases.puml` (if exists)
89
+ 3. Identify actors and use cases from requirements
90
+ 4. Check every use case against the question in "Goal level": fold subfunctions into the user goal they serve,
91
+ split summary goals, and tell the user which use cases you merged or split and why
92
+ 5. Create/update the PlantUML use case diagram
93
+ 6. Validate the diagram:
94
+ - Each use case is a user goal (see "Goal level"); a subfunction appears only as an `<<include>>` shared by
95
+ several use cases
96
+ - Each use case traces to at least one functional requirement in `docs/requirements.md`
97
+ - All actors are connected to at least one use case
98
+ - Use case IDs follow the UC-{3-digit} convention
99
+ - PlantUML syntax is valid (no missing `@enduml`, proper arrow syntax)