aw-spec-cli 0.1.8 → 0.1.10

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 (257) hide show
  1. package/assets/.appweaver/DESIGN-FORMAT.md +200 -0
  2. package/assets/.appweaver/ORCH-DIALECT.md +156 -0
  3. package/assets/.appweaver/RULE-PARTITION.md +175 -0
  4. package/assets/.appweaver/STACK-PROFILES.md +461 -0
  5. package/assets/.appweaver/ai-rules.md +180 -0
  6. package/assets/.appweaver/domain.json +1 -0
  7. package/assets/.appweaver/extensions/.registry +19 -0
  8. package/assets/.appweaver/extensions/agent-context/README.md +57 -0
  9. package/assets/.appweaver/extensions/agent-context/agent-context-config.yml +4 -0
  10. package/assets/.appweaver/extensions/agent-context/commands/aw-spec.agent-context.update.md +26 -0
  11. package/assets/.appweaver/extensions/agent-context/extension.yml +37 -0
  12. package/assets/.appweaver/extensions/agent-context/scripts/bash/update-agent-context.sh +201 -0
  13. package/assets/.appweaver/extensions/agent-context/scripts/powershell/update-agent-context.ps1 +237 -0
  14. package/assets/.appweaver/extensions.yml +16 -0
  15. package/assets/.appweaver/feature.json +3 -0
  16. package/assets/.appweaver/init-options.json +9 -0
  17. package/assets/.appweaver/integration.json +15 -0
  18. package/assets/.appweaver/integrations/aw-spec.manifest.json +9 -0
  19. package/assets/.appweaver/interpreter/run-skill.py +1176 -0
  20. package/assets/.appweaver/memory/constitution.md +50 -0
  21. package/assets/.appweaver/orchestrator/.smoke-out/smoke.md +6 -0
  22. package/assets/.appweaver/orchestrator/AGENT-PROFILE.md +94 -0
  23. package/assets/.appweaver/orchestrator/README.md +300 -0
  24. package/assets/.appweaver/orchestrator/adapters/claude_agent_sdk.py +74 -0
  25. package/assets/.appweaver/orchestrator/adapters/google_antigravity.py +74 -0
  26. package/assets/.appweaver/orchestrator/modules/delta-design.orch.yaml +105 -0
  27. package/assets/.appweaver/orchestrator/modules/delta-spec.orch.yaml +101 -0
  28. package/assets/.appweaver/orchestrator/modules/domain-select.orch.yaml +90 -0
  29. package/assets/.appweaver/orchestrator/modules/lane-gate.orch.yaml +126 -0
  30. package/assets/.appweaver/orchestrator/modules/tech-select.orch.yaml +123 -0
  31. package/assets/.appweaver/orchestrator/orchestrator.py +1721 -0
  32. package/assets/.appweaver/orchestrator/rev-templates/ai-rules.reference.md +40 -0
  33. package/assets/.appweaver/orchestrator/rev-templates/delta-design-template.skeleton.md +101 -0
  34. package/assets/.appweaver/orchestrator/rev-templates/design-template.skeleton.md +245 -0
  35. package/assets/.appweaver/orchestrator/rev-templates/domain-constitution.skeleton.md +63 -0
  36. package/assets/.appweaver/orchestrator/rev-templates/domain-requirements.skeleton.md +48 -0
  37. package/assets/.appweaver/orchestrator/rev-templates/domain-rule-bindings.skeleton.md +59 -0
  38. package/assets/.appweaver/orchestrator/rev-templates/domain-rule-file.skeleton.md +39 -0
  39. package/assets/.appweaver/orchestrator/rev-templates/frontend-rule-file.skeleton.md +63 -0
  40. package/assets/.appweaver/orchestrator/rev-templates/tech-rule-bindings.skeleton.md +116 -0
  41. package/assets/.appweaver/orchestrator/rev-templates/technical-constitution.skeleton.md +106 -0
  42. package/assets/.appweaver/orchestrator/rev-templates/technical-rule-file.skeleton.md +54 -0
  43. package/assets/.appweaver/orchestrator/rev-templates/ui-constitution.skeleton.md +125 -0
  44. package/assets/.appweaver/orchestrator/rev-templates/ui-delta-design-template.skeleton.md +123 -0
  45. package/assets/.appweaver/orchestrator/rev-templates/ui-design-template.skeleton.md +294 -0
  46. package/assets/.appweaver/orchestrator/workflows/_smoke.orch.yaml +160 -0
  47. package/assets/.appweaver/orchestrator/workflows/aw-spec-add-component.orch.yaml +270 -0
  48. package/assets/.appweaver/orchestrator/workflows/aw-spec-adopt.orch.yaml +934 -0
  49. package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-delta-design.orch.yaml +251 -0
  50. package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-design.orch.yaml +265 -0
  51. package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-slice.orch.yaml +437 -0
  52. package/assets/.appweaver/orchestrator/workflows/aw-spec-build.orch.yaml +197 -0
  53. package/assets/.appweaver/orchestrator/workflows/aw-spec-characterize.orch.yaml +475 -0
  54. package/assets/.appweaver/orchestrator/workflows/aw-spec-close-delta.orch.yaml +181 -0
  55. package/assets/.appweaver/orchestrator/workflows/aw-spec-constitution.orch.yaml +727 -0
  56. package/assets/.appweaver/orchestrator/workflows/aw-spec-demo.orch.yaml +100 -0
  57. package/assets/.appweaver/orchestrator/workflows/aw-spec-dependency-tree.orch.yaml +69 -0
  58. package/assets/.appweaver/orchestrator/workflows/aw-spec-deploy.orch.yaml +85 -0
  59. package/assets/.appweaver/orchestrator/workflows/aw-spec-design-ui.orch.yaml +386 -0
  60. package/assets/.appweaver/orchestrator/workflows/aw-spec-design.orch.yaml +382 -0
  61. package/assets/.appweaver/orchestrator/workflows/aw-spec-finalize-delta.orch.yaml +462 -0
  62. package/assets/.appweaver/orchestrator/workflows/aw-spec-foundation.orch.yaml +265 -0
  63. package/assets/.appweaver/orchestrator/workflows/aw-spec-implement-delta.orch.yaml +253 -0
  64. package/assets/.appweaver/orchestrator/workflows/aw-spec-implement-ui.orch.yaml +267 -0
  65. package/assets/.appweaver/orchestrator/workflows/aw-spec-implement.orch.yaml +287 -0
  66. package/assets/.appweaver/orchestrator/workflows/aw-spec-inventory.orch.yaml +238 -0
  67. package/assets/.appweaver/orchestrator/workflows/aw-spec-onboard.orch.yaml +1822 -0
  68. package/assets/.appweaver/orchestrator/workflows/aw-spec-parity.orch.yaml +293 -0
  69. package/assets/.appweaver/orchestrator/workflows/aw-spec-run.orch.yaml +194 -0
  70. package/assets/.appweaver/orchestrator/workflows/aw-spec-select-domain.orch.yaml +83 -0
  71. package/assets/.appweaver/orchestrator/workflows/aw-spec-select-feature.orch.yaml +128 -0
  72. package/assets/.appweaver/orchestrator/workflows/aw-spec-select-stack.orch.yaml +296 -0
  73. package/assets/.appweaver/orchestrator/workflows/aw-spec-specify.orch.yaml +439 -0
  74. package/assets/.appweaver/scripts/bash/aw-inventory.sh +17 -0
  75. package/assets/.appweaver/scripts/bash/aw-parity.sh +13 -0
  76. package/assets/.appweaver/scripts/bash/aw-rev-constitution.sh +13 -0
  77. package/assets/.appweaver/scripts/bash/aw-spec-actions.sh +2626 -0
  78. package/assets/.appweaver/scripts/bash/aw-xref.sh +15 -0
  79. package/assets/.appweaver/scripts/bash/common.sh +533 -0
  80. package/assets/.appweaver/scripts/powershell/aw-inventory.ps1 +17 -0
  81. package/assets/.appweaver/scripts/powershell/aw-parity.ps1 +13 -0
  82. package/assets/.appweaver/scripts/powershell/aw-rev-constitution.ps1 +13 -0
  83. package/assets/.appweaver/scripts/powershell/aw-spec-actions.ps1 +2232 -0
  84. package/assets/.appweaver/scripts/powershell/aw-xref.ps1 +15 -0
  85. package/assets/.appweaver/scripts/python/aw-component-catalog.py +121 -0
  86. package/assets/.appweaver/scripts/python/aw-inventory.py +1180 -0
  87. package/assets/.appweaver/scripts/python/aw-parity.py +380 -0
  88. package/assets/.appweaver/scripts/python/aw-rev-constitution.py +329 -0
  89. package/assets/.appweaver/scripts/python/aw-stack.py +1251 -0
  90. package/assets/.appweaver/scripts/python/aw-xref.py +1330 -0
  91. package/assets/.appweaver/scripts/python/validate_okf.py +352 -0
  92. package/assets/.appweaver/stack-profiles/angular.json +16 -0
  93. package/assets/.appweaver/stack-profiles/blazor-wasm.json +17 -0
  94. package/assets/.appweaver/stack-profiles/dotnet-webapi.json +15 -0
  95. package/assets/.appweaver/stack-profiles/go-chi.json +14 -0
  96. package/assets/.appweaver/stack-profiles/java-spring.json +16 -0
  97. package/assets/.appweaver/stack-profiles/nextjs.json +16 -0
  98. package/assets/.appweaver/stack-profiles/node-express.json +15 -0
  99. package/assets/.appweaver/stack-profiles/python-fastapi.json +16 -0
  100. package/assets/.appweaver/stack-profiles/react-vite.json +17 -0
  101. package/assets/.appweaver/stack-profiles/sveltekit.json +16 -0
  102. package/assets/.appweaver/stack-profiles/vue-vite.json +17 -0
  103. package/assets/.appweaver/stacks.json +3 -0
  104. package/assets/.appweaver/templates/constitution-domain-template.md +116 -0
  105. package/assets/.appweaver/templates/constitution-technical-template.md +108 -0
  106. package/assets/.appweaver/templates/constitution-ui-template.md +116 -0
  107. package/assets/.appweaver/templates/delta-design-template.md +69 -0
  108. package/assets/.appweaver/templates/delta-spec-template.md +63 -0
  109. package/assets/.appweaver/templates/design-template.md +383 -0
  110. package/assets/.appweaver/templates/okf-concept-template.md +114 -0
  111. package/assets/.appweaver/templates/parity-manifest-template.json +49 -0
  112. package/assets/.appweaver/templates/source-map-template.md +85 -0
  113. package/assets/.appweaver/templates/spec-template.md +309 -0
  114. package/assets/.appweaver/templates/ui-design-template.md +273 -0
  115. package/assets/foundations/dotnet/ModularMonolith/ModularMonolith.Reference.pack.txt +25248 -0
  116. package/assets/foundations/dotnet/ModularMonolith/ModularMonolith.pack.txt +5726 -0
  117. package/assets/foundations/dotnet/ModularMonolith/pack-foundation.ps1 +145 -0
  118. package/assets/foundations/dotnet/ModularMonolith/pack-foundation.sh +196 -0
  119. package/assets/foundations/dotnet/ModularMonolith/pack-reference-foundation.ps1 +157 -0
  120. package/assets/foundations/dotnet/ModularMonolith/pack-reference-foundation.sh +209 -0
  121. package/assets/foundations/dotnet/ModularMonolith/unpack-foundation.ps1 +126 -0
  122. package/assets/foundations/dotnet/ModularMonolith/unpack-foundation.sh +217 -0
  123. package/assets/foundations/dotnet/ModularMonolith/unpack-reference-foundation.ps1 +129 -0
  124. package/assets/foundations/dotnet/ModularMonolith/unpack-reference-foundation.sh +218 -0
  125. package/assets/foundations/dotnet/VerticalSlice/VerticalSlice.Reference.pack.txt +19318 -0
  126. package/assets/foundations/dotnet/VerticalSlice/VerticalSlice.pack.txt +2833 -0
  127. package/assets/foundations/dotnet/VerticalSlice/pack-foundation.ps1 +145 -0
  128. package/assets/foundations/dotnet/VerticalSlice/pack-foundation.sh +196 -0
  129. package/assets/foundations/dotnet/VerticalSlice/pack-reference-foundation.ps1 +157 -0
  130. package/assets/foundations/dotnet/VerticalSlice/pack-reference-foundation.sh +209 -0
  131. package/assets/foundations/dotnet/VerticalSlice/unpack-foundation.ps1 +126 -0
  132. package/assets/foundations/dotnet/VerticalSlice/unpack-foundation.sh +217 -0
  133. package/assets/foundations/dotnet/VerticalSlice/unpack-reference-foundation.ps1 +129 -0
  134. package/assets/foundations/dotnet/VerticalSlice/unpack-reference-foundation.sh +218 -0
  135. package/assets/foundations/dotnet/components/Email/README.md +119 -0
  136. package/assets/foundations/dotnet/components/Email/ReferenceEndpoints/SendEmailEndpoint.cs +84 -0
  137. package/assets/foundations/dotnet/components/Email/integration.md +300 -0
  138. package/assets/foundations/dotnet/components/Jobs/README.md +113 -0
  139. package/assets/foundations/dotnet/components/Jobs/integration.md +259 -0
  140. package/assets/foundations/dotnet/components/QrGenerator/README.md +85 -0
  141. package/assets/foundations/dotnet/components/QrGenerator/ReferenceEndpoints/GenerateQrEndpoint.cs +57 -0
  142. package/assets/foundations/dotnet/components/QrGenerator/integration.md +230 -0
  143. package/assets/foundations/dotnet/components/README.md +74 -0
  144. package/assets/guardrails/README.md +222 -0
  145. package/assets/guardrails/domain/healthcare/ai-rules.domain.md +34 -0
  146. package/assets/guardrails/domain/healthcare/api-versioning.domain.md +17 -0
  147. package/assets/guardrails/domain/healthcare/auditing.domain.md +97 -0
  148. package/assets/guardrails/domain/healthcare/authorization.domain.md +26 -0
  149. package/assets/guardrails/domain/healthcare/clinical-terms.md +20 -0
  150. package/assets/guardrails/domain/healthcare/coding-standards.domain.md +26 -0
  151. package/assets/guardrails/domain/healthcare/consent.md +19 -0
  152. package/assets/guardrails/domain/healthcare/cqrs.domain.md +12 -0
  153. package/assets/guardrails/domain/healthcare/data-classification.domain.md +28 -0
  154. package/assets/guardrails/domain/healthcare/dependency-policy.domain.md +11 -0
  155. package/assets/guardrails/domain/healthcare/dicom.md +15 -0
  156. package/assets/guardrails/domain/healthcare/domain-constitution.md +119 -0
  157. package/assets/guardrails/domain/healthcare/domain-driven-design.domain.md +28 -0
  158. package/assets/guardrails/domain/healthcare/eventing.domain.md +18 -0
  159. package/assets/guardrails/domain/healthcare/fhir.md +36 -0
  160. package/assets/guardrails/domain/healthcare/folder-structure.domain.md +25 -0
  161. package/assets/guardrails/domain/healthcare/hipaa.md +34 -0
  162. package/assets/guardrails/domain/healthcare/hl7.md +15 -0
  163. package/assets/guardrails/domain/healthcare/ihe-conformance.md +31 -0
  164. package/assets/guardrails/domain/healthcare/integration-terms.md +21 -0
  165. package/assets/guardrails/domain/healthcare/persistence.domain.md +20 -0
  166. package/assets/guardrails/domain/healthcare/terminology.md +30 -0
  167. package/assets/guardrails/domain/healthcare/testing.domain.md +15 -0
  168. package/assets/guardrails/domain/healthcare/ux/accessibility-standards.md +36 -0
  169. package/assets/guardrails/domain/healthcare/ux/content-design.md +32 -0
  170. package/assets/guardrails/domain/healthcare/ux/interaction-states.md +44 -0
  171. package/assets/guardrails/domain/healthcare/ux/journey-mapping.md +40 -0
  172. package/assets/guardrails/domain/healthcare/vertical-slices.domain.md +18 -0
  173. package/assets/guardrails/domain/healthcare/zero-trust.domain.md +12 -0
  174. package/assets/guardrails/domain/pharma/ai-rules.domain.md +32 -0
  175. package/assets/guardrails/domain/pharma/api-versioning.domain.md +20 -0
  176. package/assets/guardrails/domain/pharma/atc.md +22 -0
  177. package/assets/guardrails/domain/pharma/auditing.domain.md +90 -0
  178. package/assets/guardrails/domain/pharma/authorization.domain.md +25 -0
  179. package/assets/guardrails/domain/pharma/coding-standards.domain.md +28 -0
  180. package/assets/guardrails/domain/pharma/cqrs.domain.md +16 -0
  181. package/assets/guardrails/domain/pharma/data-classification.domain.md +24 -0
  182. package/assets/guardrails/domain/pharma/data-provenance.md +21 -0
  183. package/assets/guardrails/domain/pharma/dependency-policy.domain.md +11 -0
  184. package/assets/guardrails/domain/pharma/domain-constitution.md +113 -0
  185. package/assets/guardrails/domain/pharma/domain-driven-design.domain.md +36 -0
  186. package/assets/guardrails/domain/pharma/domain-requirements.sample.md +103 -0
  187. package/assets/guardrails/domain/pharma/eventing.domain.md +18 -0
  188. package/assets/guardrails/domain/pharma/fhir.md +31 -0
  189. package/assets/guardrails/domain/pharma/folder-structure.domain.md +26 -0
  190. package/assets/guardrails/domain/pharma/hl7.md +17 -0
  191. package/assets/guardrails/domain/pharma/idmp.md +26 -0
  192. package/assets/guardrails/domain/pharma/integration-terms.md +21 -0
  193. package/assets/guardrails/domain/pharma/ndc.md +28 -0
  194. package/assets/guardrails/domain/pharma/persistence.domain.md +23 -0
  195. package/assets/guardrails/domain/pharma/pharma-terms.md +27 -0
  196. package/assets/guardrails/domain/pharma/product-lifecycle.domain.md +30 -0
  197. package/assets/guardrails/domain/pharma/regulatory-compliance.md +19 -0
  198. package/assets/guardrails/domain/pharma/terminology.md +32 -0
  199. package/assets/guardrails/domain/pharma/testing.domain.md +19 -0
  200. package/assets/guardrails/domain/pharma/vertical-slices.domain.md +17 -0
  201. package/assets/guardrails/domain/pharma/zero-trust.domain.md +12 -0
  202. package/assets/guardrails/projects/dotnet-default-project/domain/domain-requirements.md +58 -0
  203. package/assets/guardrails/projects/dotnet-default-project/domain-rule-bindings.md +113 -0
  204. package/assets/guardrails/projects/dotnet-default-project/frontend/ui-requirements.md +43 -0
  205. package/assets/guardrails/projects/dotnet-default-project/service/technical-requirements.md +40 -0
  206. package/assets/guardrails/projects/dotnet-default-project/tech-rule-bindings.md +263 -0
  207. package/assets/guardrails/requirement-spec.txt +27 -0
  208. package/assets/guardrails/technology/dotnet-webapi/PACKAGING.md +184 -0
  209. package/assets/guardrails/technology/dotnet-webapi/api-versioning.md +44 -0
  210. package/assets/guardrails/technology/dotnet-webapi/auditing.md +96 -0
  211. package/assets/guardrails/technology/dotnet-webapi/authorization-matrix.md +14 -0
  212. package/assets/guardrails/technology/dotnet-webapi/authorization.md +39 -0
  213. package/assets/guardrails/technology/dotnet-webapi/clean-architecture.md +54 -0
  214. package/assets/guardrails/technology/dotnet-webapi/coding-standards.md +87 -0
  215. package/assets/guardrails/technology/dotnet-webapi/cqrs.md +63 -0
  216. package/assets/guardrails/technology/dotnet-webapi/data-classification.md +38 -0
  217. package/assets/guardrails/technology/dotnet-webapi/dependency-policy.md +40 -0
  218. package/assets/guardrails/technology/dotnet-webapi/domain-driven-design.md +91 -0
  219. package/assets/guardrails/technology/dotnet-webapi/eventing.md +57 -0
  220. package/assets/guardrails/technology/dotnet-webapi/examples/api-versioning.md +75 -0
  221. package/assets/guardrails/technology/dotnet-webapi/examples/auditing.md +84 -0
  222. package/assets/guardrails/technology/dotnet-webapi/examples/authorization.md +68 -0
  223. package/assets/guardrails/technology/dotnet-webapi/examples/clean-architecture.md +37 -0
  224. package/assets/guardrails/technology/dotnet-webapi/examples/cqrs.md +97 -0
  225. package/assets/guardrails/technology/dotnet-webapi/examples/domain-driven-design.md +141 -0
  226. package/assets/guardrails/technology/dotnet-webapi/examples/eventing.md +46 -0
  227. package/assets/guardrails/technology/dotnet-webapi/examples/persistence.md +207 -0
  228. package/assets/guardrails/technology/dotnet-webapi/examples/vertical-slices.md +151 -0
  229. package/assets/guardrails/technology/dotnet-webapi/examples/zero-trust.md +48 -0
  230. package/assets/guardrails/technology/dotnet-webapi/folder-structure.md +61 -0
  231. package/assets/guardrails/technology/dotnet-webapi/modular-monolith.md +47 -0
  232. package/assets/guardrails/technology/dotnet-webapi/persistence.md +82 -0
  233. package/assets/guardrails/technology/dotnet-webapi/technology-constitution.md +162 -0
  234. package/assets/guardrails/technology/dotnet-webapi/testing.md +55 -0
  235. package/assets/guardrails/technology/dotnet-webapi/vertical-slices.md +70 -0
  236. package/assets/guardrails/technology/dotnet-webapi/zero-trust.md +48 -0
  237. package/assets/guardrails/technology/java-spring/README.md +62 -0
  238. package/assets/guardrails/technology/nextjs/accessibility-implementation.md +56 -0
  239. package/assets/guardrails/technology/nextjs/api-client.md +56 -0
  240. package/assets/guardrails/technology/nextjs/api-integration.dotnet-webapi.md +174 -0
  241. package/assets/guardrails/technology/nextjs/api-integration.java-spring.md +203 -0
  242. package/assets/guardrails/technology/nextjs/auth-session.md +68 -0
  243. package/assets/guardrails/technology/nextjs/client-security.md +69 -0
  244. package/assets/guardrails/technology/nextjs/component-architecture.md +60 -0
  245. package/assets/guardrails/technology/nextjs/component-conventions.md +58 -0
  246. package/assets/guardrails/technology/nextjs/design-system.md +60 -0
  247. package/assets/guardrails/technology/nextjs/error-handling.md +72 -0
  248. package/assets/guardrails/technology/nextjs/forms-and-validation.md +75 -0
  249. package/assets/guardrails/technology/nextjs/frontend-testing.md +94 -0
  250. package/assets/guardrails/technology/nextjs/i18n.md +57 -0
  251. package/assets/guardrails/technology/nextjs/observability.md +67 -0
  252. package/assets/guardrails/technology/nextjs/performance-budgets.md +66 -0
  253. package/assets/guardrails/technology/nextjs/routing-navigation.md +52 -0
  254. package/assets/guardrails/technology/nextjs/state-management.md +70 -0
  255. package/assets/guardrails/technology/nextjs/ui-constitution.md +166 -0
  256. package/package.json +1 -1
  257. package/assets/docs/pharma-constitution.my-ref.md +0 -86
@@ -0,0 +1,218 @@
1
+ #!/usr/bin/env bash
2
+ #
3
+ # unpack-reference-foundation.sh — bash/macOS port of unpack-reference-foundation.ps1
4
+ #
5
+ # SYNOPSIS
6
+ # Unpack an AW-Spec reference pack file into a target project, renaming the
7
+ # sentinel app name to the caller's app name.
8
+ #
9
+ # DESCRIPTION
10
+ # Reads --pack-file (produced by pack-reference-foundation.sh/.ps1), takes the sentinel
11
+ # from its header (override with --sentinel), derives four case forms of the target app
12
+ # name, and writes every file block to --out-dir with the sentinel rewritten in both file
13
+ # CONTENTS and file/dir PATHS. Text blocks are rewritten and written as UTF-8; base64
14
+ # blocks are decoded as-is. Refuses to overwrite existing files unless --force.
15
+ #
16
+ # EXAMPLE
17
+ # ./unpack-reference-foundation.sh \
18
+ # --pack-file ./VerticalSlice.Reference.pack.txt \
19
+ # --target-app-name AppWeaver.Pharma \
20
+ # --out-dir ../../../
21
+ #
22
+ set -euo pipefail
23
+
24
+ # ------------------------------------------------------------------ defaults ---
25
+ PACK_FILE=''
26
+ TARGET_APP_NAME=''
27
+ OUT_DIR='.'
28
+ SENTINEL=''
29
+ FORCE=0
30
+ DRYRUN=0
31
+
32
+ usage() {
33
+ cat >&2 <<'EOF'
34
+ Usage: unpack-reference-foundation.sh --pack-file <file> --target-app-name <name>
35
+ [--out-dir <dir>] [--sentinel <name>]
36
+ [--force] [--dry-run]
37
+
38
+ -p, --pack-file <file> Reference pack file to unpack (required)
39
+ -t, --target-app-name <name> New app name to rename the sentinel into (required)
40
+ -o, --out-dir <dir> Output root (default: .)
41
+ --sentinel <name> Override the sentinel from the pack header
42
+ --force Overwrite files that already exist
43
+ --dry-run List what would be written, write nothing
44
+ -h, --help Show this help
45
+
46
+ Positional fallback: unpack-reference-foundation.sh <pack-file> <target-app-name> [out-dir]
47
+ EOF
48
+ }
49
+
50
+ # -------------------------------------------------------------- arg parsing ---
51
+ while [ $# -gt 0 ]; do
52
+ case "$1" in
53
+ -p|--pack-file) PACK_FILE="${2:?--pack-file needs a value}"; shift 2 ;;
54
+ -t|--target-app-name) TARGET_APP_NAME="${2:?--target-app-name needs a value}"; shift 2 ;;
55
+ -o|--out-dir) OUT_DIR="${2:?--out-dir needs a value}"; shift 2 ;;
56
+ --sentinel) SENTINEL="${2:?--sentinel needs a value}"; shift 2 ;;
57
+ --force) FORCE=1; shift ;;
58
+ --dry-run) DRYRUN=1; shift ;;
59
+ -h|--help) usage; exit 0 ;;
60
+ --) shift; break ;;
61
+ -*) echo "Error: unknown option: $1" >&2; usage; exit 2 ;;
62
+ *)
63
+ if [ -z "$PACK_FILE" ]; then PACK_FILE="$1"
64
+ elif [ -z "$TARGET_APP_NAME" ]; then TARGET_APP_NAME="$1"
65
+ else OUT_DIR="$1"
66
+ fi
67
+ shift ;;
68
+ esac
69
+ done
70
+
71
+ [ -n "$PACK_FILE" ] || { echo "Error: --pack-file is required." >&2; usage; exit 2; }
72
+ [ -n "$TARGET_APP_NAME" ] || { echo "Error: --target-app-name is required." >&2; usage; exit 2; }
73
+ [ -f "$PACK_FILE" ] || { echo "Error: pack file not found: $PACK_FILE" >&2; exit 1; }
74
+
75
+ case "$TARGET_APP_NAME" in
76
+ *[!A-Za-z0-9._-]*)
77
+ echo "Error: --target-app-name may contain only letters, digits, '.', '_' or '-': $TARGET_APP_NAME" >&2
78
+ exit 2 ;;
79
+ esac
80
+
81
+ # ------------------------------------------------ sentinel from header --------
82
+ if [ -z "$SENTINEL" ]; then
83
+ SENTINEL="$(LC_ALL=C sed -n 's/^#[[:space:]]*sentinel:[[:space:]]*\(.*[^[:space:]]\)[[:space:]]*$/\1/p' "$PACK_FILE" | head -n1)"
84
+ fi
85
+ [ -n "$SENTINEL" ] || { echo "Error: Sentinel not found in pack header; supply it with --sentinel." >&2; exit 1; }
86
+
87
+ # ------------------------------------------------ derive case forms -----------
88
+ to_lower() { printf '%s' "$1" | LC_ALL=C tr '[:upper:]' '[:lower:]'; }
89
+
90
+ S_DOT="$SENTINEL"; T_DOT="$TARGET_APP_NAME"
91
+ S_UND="${SENTINEL//./_}"; T_UND="${TARGET_APP_NAME//./_}"
92
+ s_low="$(to_lower "$SENTINEL")"; t_low="$(to_lower "$TARGET_APP_NAME")"
93
+ S_HYP="${s_low//./-}"; T_HYP="${t_low//./-}"
94
+ S_LDOT="$s_low"; T_LDOT="$t_low"
95
+
96
+ FROM=(); TO=()
97
+ add_form() {
98
+ local from="$1" to="$2" e
99
+ [ -n "$from" ] || return 0
100
+ [ "$from" = "$to" ] && return 0
101
+ if [ "${#FROM[@]}" -gt 0 ]; then
102
+ for e in "${FROM[@]}"; do [ "$e" = "$from" ] && return 0; done
103
+ fi
104
+ FROM+=("$from"); TO+=("$to")
105
+ }
106
+ add_form "$S_DOT" "$T_DOT"
107
+ add_form "$S_UND" "$T_UND"
108
+ add_form "$S_HYP" "$T_HYP"
109
+ add_form "$S_LDOT" "$T_LDOT"
110
+
111
+ # Sort indices by FROM length descending
112
+ ORDER=()
113
+ {
114
+ local_n="${#FROM[@]}"
115
+ used=(); for ((k = 0; k < local_n; k++)); do used[$k]=0; done
116
+ for ((pass = 0; pass < local_n; pass++)); do
117
+ best=-1; bestlen=-1
118
+ for ((j = 0; j < local_n; j++)); do
119
+ if [ "${used[$j]}" -eq 0 ] && [ "${#FROM[$j]}" -gt "$bestlen" ]; then
120
+ bestlen="${#FROM[$j]}"; best="$j"
121
+ fi
122
+ done
123
+ used[$best]=1; ORDER+=("$best")
124
+ done
125
+ }
126
+
127
+ REPL_OUT=''
128
+ apply_repl() {
129
+ local text="$1" idx from to
130
+ if [ "${#ORDER[@]}" -gt 0 ]; then
131
+ for idx in "${ORDER[@]}"; do
132
+ from="${FROM[$idx]}"; to="${TO[$idx]}"
133
+ text="${text//"$from"/$to}"
134
+ done
135
+ fi
136
+ REPL_OUT="$text"
137
+ }
138
+
139
+ # ------------------------------------------------ output root ----------------
140
+ [ -d "$OUT_DIR" ] || mkdir -p "$OUT_DIR"
141
+ OUT_ROOT="$(cd "$OUT_DIR" && pwd -P)"
142
+
143
+ # ------------------------------------------------ base64 decoder (portable) --
144
+ B64D=()
145
+ if printf 'aGk=' | base64 -d >/dev/null 2>&1; then B64D=(base64 -d)
146
+ elif printf 'aGk=' | base64 -D >/dev/null 2>&1; then B64D=(base64 -D)
147
+ elif printf 'aGk=' | base64 --decode >/dev/null 2>&1; then B64D=(base64 --decode)
148
+ else B64D=(openssl base64 -d -A)
149
+ fi
150
+
151
+ # ------------------------------------------------ parse file blocks ----------
152
+ rels=(); encs=(); contents=()
153
+ in_block=0; cur_rel=''; cur_enc=''; cur_content=''; first_line=1
154
+ file_re='^<<<FILE path="([^"]+)"( encoding="([^"]+)")?>>>[[:space:]]*$'
155
+
156
+ while IFS= read -r line || [ -n "$line" ]; do
157
+ line="${line%$'\r'}"
158
+ if [ "$in_block" -eq 0 ]; then
159
+ if [[ "$line" =~ $file_re ]]; then
160
+ cur_rel="${BASH_REMATCH[1]}"
161
+ cur_enc="${BASH_REMATCH[3]:-}"
162
+ in_block=1; first_line=1; cur_content=''
163
+ fi
164
+ else
165
+ if [ "$line" = '<<<ENDFILE>>>' ]; then
166
+ rels+=("$cur_rel"); encs+=("$cur_enc"); contents+=("$cur_content")
167
+ in_block=0
168
+ elif [ "$first_line" -eq 1 ]; then
169
+ cur_content="$line"; first_line=0
170
+ else
171
+ cur_content="$cur_content"$'\n'"$line"
172
+ fi
173
+ fi
174
+ done < "$PACK_FILE"
175
+
176
+ [ "${#rels[@]}" -gt 0 ] || { echo "Error: No <<<FILE>>> blocks found in pack: $PACK_FILE" >&2; exit 1; }
177
+
178
+ # ------------------------------------------------ resolve destinations -------
179
+ dests=()
180
+ for ((i = 0; i < ${#rels[@]}; i++)); do
181
+ apply_repl "${rels[$i]}"
182
+ dests+=("$OUT_ROOT/$REPL_OUT")
183
+ done
184
+
185
+ # ------------------------------------------------ conflict guard -------------
186
+ if [ "$FORCE" -eq 0 ] && [ "$DRYRUN" -eq 0 ]; then
187
+ conflicts=()
188
+ for d in "${dests[@]}"; do [ -e "$d" ] && conflicts+=("$d"); done
189
+ if [ "${#conflicts[@]}" -gt 0 ]; then
190
+ echo "Error: Refusing to overwrite existing files (re-run with --force):" >&2
191
+ printf ' %s\n' "${conflicts[@]}" >&2
192
+ exit 1
193
+ fi
194
+ fi
195
+
196
+ # ------------------------------------------------ write ----------------------
197
+ written=0
198
+ for ((i = 0; i < ${#rels[@]}; i++)); do
199
+ rel="${rels[$i]}"; enc="${encs[$i]}"; dest="${dests[$i]}"
200
+ if [ "$DRYRUN" -eq 1 ]; then
201
+ echo "WOULD WRITE $rel -> $dest"
202
+ continue
203
+ fi
204
+ mkdir -p "$(dirname "$dest")"
205
+ if [ "$enc" = 'base64' ]; then
206
+ printf '%s' "${contents[$i]}" | tr -d '[:space:]' | "${B64D[@]}" > "$dest"
207
+ else
208
+ apply_repl "${contents[$i]}"
209
+ printf '%s' "$REPL_OUT" > "$dest"
210
+ fi
211
+ written=$((written + 1))
212
+ done
213
+
214
+ if [ "$DRYRUN" -eq 1 ]; then
215
+ echo "DryRun: ${#rels[@]} file(s) would be written to $OUT_ROOT (sentinel '$SENTINEL' -> '$TARGET_APP_NAME')."
216
+ else
217
+ echo "Unpacked $written file(s) to $OUT_ROOT (sentinel '$SENTINEL' -> '$TARGET_APP_NAME')."
218
+ fi
@@ -0,0 +1,119 @@
1
+ # Email Component (`AppWeaver.Messaging.Email`)
2
+
3
+ > Pure technology (domain-agnostic). Reference sheet for the Email messaging component.
4
+ > To wire it into a project, follow the agent runbook in [integration.md](./integration.md).
5
+ > Commands: `/appweaver add-component`.
6
+
7
+ ## What it is
8
+
9
+ A provider-agnostic email-sending component. Application code depends on a single abstraction,
10
+ `IEmailService`; the transport (Microsoft Graph, SMTP, SendGrid, OAuth2-SMTP, or a local File
11
+ sink) is chosen once during DI registration via `AddEmailMessaging(...)`.
12
+
13
+ **Use when:** a feature must send transactional or notification email (user-created alerts,
14
+ confirmations, admin notices, password flows, attachments).
15
+
16
+ ## Public contract (`AppWeaver.Messaging.Email`)
17
+
18
+ ```csharp
19
+ namespace AppWeaver.Messaging.Email;
20
+
21
+ public interface IEmailService
22
+ {
23
+ // Convenience overload — single recipient.
24
+ Task SendAsync(string from, string to, string subject, string body,
25
+ bool isHtml = true, CancellationToken cancellationToken = default);
26
+
27
+ // Full message — multi-recipient, Cc/Bcc, attachments.
28
+ Task SendAsync(EmailMessage message, CancellationToken cancellationToken = default);
29
+ }
30
+ ```
31
+
32
+ ```csharp
33
+ namespace AppWeaver.Messaging.Email.Entities;
34
+
35
+ public class EmailMessage
36
+ {
37
+ public string From { get; set; } // falls back to provider DefaultFrom if empty
38
+ public List<string> To { get; set; } = new();
39
+ public List<string> Cc { get; set; } = new();
40
+ public List<string> Bcc { get; set; } = new();
41
+ public string Subject { get; set; }
42
+ public string Body { get; set; }
43
+ public bool IsHtml { get; set; } = true;
44
+ public List<EmailAttachment> Attachments { get; set; } = new();
45
+ }
46
+
47
+ public class EmailAttachment
48
+ {
49
+ public string FileName { get; set; }
50
+ public byte[] Content { get; set; }
51
+ public string ContentType { get; set; } = "application/octet-stream";
52
+ }
53
+ ```
54
+
55
+ ## Packages
56
+
57
+ | Package | Version | Role | Builder method | Provider key |
58
+ |---|---|---|---|---|
59
+ | `AppWeaver.Messaging.Email` | `0.1.3` | **Required.** Abstraction + `AddEmailMessaging` + facade. | — | — |
60
+ | `AppWeaver.Messaging.Email.MsGraph` | `0.1.2` | Microsoft 365 / Graph API (recommended for prod). | `UseMsGraph` | `MsGraph` |
61
+ | `AppWeaver.Messaging.Email.Smtp` | `0.1.3` | Classic SMTP (host/port/user/password). | `UseSmtp` | `Smtp` |
62
+ | `AppWeaver.Messaging.Email.SendGrid` | `0.1.2` | SendGrid API key. | `UseSendGrid` | `SendGrid` |
63
+ | `AppWeaver.Messaging.Email.OAuth2` | `0.1.3` | OAuth2-authenticated SMTP (O365). | `UseOAuth2` | `OAuth2` |
64
+ | `AppWeaver.Messaging.Email.File` | `0.1.2` | Writes email to a local `.txt` file — local dev / tests. | `UseFile` | `File` |
65
+
66
+ Install the abstraction **plus exactly one provider** for the environment you are wiring.
67
+
68
+ ## Provider option shapes
69
+
70
+ | Provider | Options type | Key fields | Bound config section |
71
+ |---|---|---|---|
72
+ | MsGraph | `MsGraphEmailOptions` | `TenantId`, `ClientId`, `ClientSecret`, `DefaultFrom`, `Scopes` | `Messaging.Email.MsGraph` |
73
+ | Smtp | `SmtpEmailOptions` | `Host`, `Port`, `Username`, `Password`, `EnableSsl`, `DefaultFrom` | `Messaging.Email.Smtp` |
74
+ | SendGrid | `SendGridEmailOptions` | `ApiKey` *(required)*, `DefaultFrom` | `Messaging.Email.SendGrid` |
75
+ | OAuth2 | `OAuth2EmailOptions` | `TenantId`, `ClientId`, `ClientSecret`, `Host`, `Port`, `Scopes`, `DefaultFrom` | `Messaging.Email.OAuth2` |
76
+ | File | `FileEmailOptions` | `DefaultFrom` | `Messaging.Email.Smtp` *(quirk — pass options inline)* |
77
+
78
+ ## Registration entry point
79
+
80
+ ```csharp
81
+ // In AppWeaver.Messaging.Email.Extensions
82
+ IComponentBuilder<IEmailService> AddEmailMessaging(
83
+ this IServiceCollection services,
84
+ Action<IComponentBuilder<IEmailService>> configureBuilder, // required
85
+ Action<MessagingEmailConfiguration>? configureOptions = null,// set Provider here
86
+ IConfiguration? configuration = null); // OR bind from config
87
+ ```
88
+
89
+ `MessagingEmailConfiguration` exposes a single `[Required] string Provider`. The facade
90
+ (`DefaultImplementation`) resolves the keyed provider whose key equals `Provider`.
91
+
92
+ ## Source map (framework)
93
+
94
+ ```
95
+ framework/Messaging.Email/
96
+ Integration.md ← original MsGraph tutorial (reference)
97
+ src/
98
+ AppWeaver.Messaging.Email/ ← IEmailService, EmailMessage, AddEmailMessaging, facade
99
+ AppWeaver.Messaging.Email.MsGraph/ ← UseMsGraph + MsGraphEmailService
100
+ AppWeaver.Messaging.Email.Smtp/ ← UseSmtp + SmtpEmailService
101
+ AppWeaver.Messaging.Email.SendGrid/ ← UseSendGrid + SendGridEmailService
102
+ AppWeaver.Messaging.Email.OAuth2/ ← UseOAuth2 + OAuth2EmailService
103
+ AppWeaver.Messaging.Email.File/ ← UseFile + FileEmailService
104
+ test/
105
+ MsGraphTest/Program.cs ← MsGraph end-to-end sample
106
+ TestApp/Program.cs ← OAuth2 + File multi-provider sample
107
+ ```
108
+
109
+ ## Sample reference endpoint
110
+
111
+ A ready-to-run FastEndpoint that sends mail inline (no command/handler) is bundled at
112
+ [`ReferenceEndpoints/SendEmailEndpoint.cs`](./ReferenceEndpoints/SendEmailEndpoint.cs). It is offered
113
+ (opt-in) at the end of the [integration.md](./integration.md) runbook and, if accepted, copied into
114
+ the host project's `ReferenceEndpoints/` folder. Endpoint: `POST /reference/email/send`.
115
+
116
+ ## Related
117
+
118
+ - [integration.md](./integration.md) · [[components-readme]] · [[cqrs]] ·
119
+ [[clean-architecture]] · [[dependency-policy]]
@@ -0,0 +1,84 @@
1
+ using FastEndpoints;
2
+ using Microsoft.Extensions.Configuration;
3
+ using AppWeaver.Messaging.Email;
4
+
5
+ // NOTE: This is a bundled SAMPLE endpoint for the AppWeaver Email component.
6
+ // It lives under foundations/dotnet/components/ and is NOT compiled here. `/appweaver add-component`
7
+ // copies it into the host project's ReferenceEndpoints/ folder and replaces the __HOSTPROJECT__ token
8
+ // with the host project's root namespace (e.g. AppWeaver.Health.Service).
9
+ namespace __HOSTPROJECT__.ReferenceEndpoints;
10
+
11
+ /// <summary>
12
+ /// Sample reference endpoint for the AppWeaver Email component.
13
+ ///
14
+ /// Demonstrates the full send sequence inline — it injects the <see cref="IEmailService"/>
15
+ /// abstraction directly and calls <c>SendAsync</c> with the provider wired during DI
16
+ /// registration (see the component's integration runbook). There is intentionally no
17
+ /// command / command-handler / mediator: this is a copy-paste sample only.
18
+ ///
19
+ /// The active transport is whatever <c>options.Provider</c> was set to when
20
+ /// <c>AddEmailMessaging(...)</c> was registered. With the <c>File</c> provider the message is
21
+ /// written to <c>Emails_&lt;yyyy-MM-dd&gt;.txt</c> in the application base directory.
22
+ /// </summary>
23
+ public class SendEmailEndpoint(IEmailService _email, IConfiguration _config)
24
+ : Endpoint<SendEmailRequest>
25
+ {
26
+ public override void Configure()
27
+ {
28
+ Post("/reference/email/send");
29
+ AllowAnonymous();
30
+ Summary(s =>
31
+ {
32
+ s.Summary = "Send a sample email via the configured Email provider";
33
+ s.Description = "Reference endpoint for the AppWeaver Email component. Injects "
34
+ + "IEmailService directly (no command/handler). 'from' falls back to "
35
+ + "Messaging:Email:DefaultFrom when omitted.";
36
+ });
37
+ Options(o => o.WithTags("Reference - Email"));
38
+ }
39
+
40
+ public override async Task HandleAsync(SendEmailRequest req, CancellationToken ct)
41
+ {
42
+ if (string.IsNullOrWhiteSpace(req.To) || string.IsNullOrWhiteSpace(req.Subject))
43
+ {
44
+ HttpContext.Response.StatusCode = 400;
45
+ await HttpContext.Response.WriteAsJsonAsync(
46
+ new { error = "'to' and 'subject' are required." }, ct);
47
+ return;
48
+ }
49
+
50
+ // 'from' is optional in the request — fall back to the configured DefaultFrom.
51
+ var from = string.IsNullOrWhiteSpace(req.From)
52
+ ? _config["Messaging:Email:DefaultFrom"] ?? "no-reply@your-domain.com"
53
+ : req.From;
54
+
55
+ await _email.SendAsync(from, req.To, req.Subject, req.Body ?? string.Empty, req.IsHtml, ct);
56
+
57
+ await HttpContext.Response.WriteAsJsonAsync(new
58
+ {
59
+ status = "sent",
60
+ from,
61
+ to = req.To,
62
+ note = "With the File provider, output is written to Emails_<yyyy-MM-dd>.txt "
63
+ + "in the app base directory."
64
+ }, ct);
65
+ }
66
+ }
67
+
68
+ public class SendEmailRequest
69
+ {
70
+ /// <summary>Recipient address (required).</summary>
71
+ public string To { get; set; } = string.Empty;
72
+
73
+ /// <summary>Subject line (required).</summary>
74
+ public string Subject { get; set; } = string.Empty;
75
+
76
+ /// <summary>HTML or plain-text body.</summary>
77
+ public string Body { get; set; } = string.Empty;
78
+
79
+ /// <summary>Treat <see cref="Body"/> as HTML. Defaults to true.</summary>
80
+ public bool IsHtml { get; set; } = true;
81
+
82
+ /// <summary>Optional sender; falls back to Messaging:Email:DefaultFrom when omitted.</summary>
83
+ public string? From { get; set; }
84
+ }