aw-spec-cli 0.1.4 → 0.1.6

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 (225) hide show
  1. package/assets/.agents/agent.json +28 -0
  2. package/assets/.agents/skills/appweaver/SKILL.md +56 -0
  3. package/assets/.agents/skills/appweaver-demo/SKILL.md +59 -0
  4. package/assets/.claude/agent.json +27 -0
  5. package/assets/.claude/skills/appweaver/SKILL.md +55 -0
  6. package/assets/.claude/skills/appweaver-demo/SKILL.md +59 -0
  7. package/assets/.kilocode/agent.json +28 -0
  8. package/assets/.kilocode/workflows/appweaver-demo.md +59 -0
  9. package/assets/.kilocode/workflows/appweaver.md +55 -0
  10. package/dist/commands/init.d.ts.map +1 -1
  11. package/dist/commands/init.js +7 -54
  12. package/dist/commands/init.js.map +1 -1
  13. package/dist/index.js +0 -2
  14. package/dist/index.js.map +1 -1
  15. package/package.json +1 -1
  16. package/assets/.agents/skills/aw-spec-addcomponent/SKILL.md +0 -129
  17. package/assets/.agents/skills/aw-spec-agent-context-update/SKILL.md +0 -31
  18. package/assets/.agents/skills/aw-spec-analyze/SKILL.md +0 -296
  19. package/assets/.agents/skills/aw-spec-checklist/SKILL.md +0 -374
  20. package/assets/.agents/skills/aw-spec-clarify/SKILL.md +0 -320
  21. package/assets/.agents/skills/aw-spec-constitution/SKILL.md +0 -194
  22. package/assets/.agents/skills/aw-spec-fast-implement/SKILL.md +0 -268
  23. package/assets/.agents/skills/aw-spec-foundation/SKILL.md +0 -358
  24. package/assets/.agents/skills/aw-spec-implement/SKILL.md +0 -279
  25. package/assets/.agents/skills/aw-spec-minimal-implementation/SKILL.md +0 -209
  26. package/assets/.agents/skills/aw-spec-plan/SKILL.md +0 -221
  27. package/assets/.agents/skills/aw-spec-select-domain/SKILL.md +0 -73
  28. package/assets/.agents/skills/aw-spec-specify/SKILL.md +0 -382
  29. package/assets/.agents/skills/aw-spec-tasks/SKILL.md +0 -259
  30. package/assets/.agents/skills/aw-spec-taskstoissues/SKILL.md +0 -107
  31. package/assets/.aw-spec/domain.json +0 -3
  32. package/assets/.aw-spec/extensions/.registry +0 -19
  33. package/assets/.aw-spec/extensions/agent-context/README.md +0 -57
  34. package/assets/.aw-spec/extensions/agent-context/agent-context-config.yml +0 -4
  35. package/assets/.aw-spec/extensions/agent-context/commands/aw-spec.agent-context.update.md +0 -26
  36. package/assets/.aw-spec/extensions/agent-context/extension.yml +0 -34
  37. package/assets/.aw-spec/extensions/agent-context/scripts/bash/update-agent-context.sh +0 -201
  38. package/assets/.aw-spec/extensions/agent-context/scripts/powershell/update-agent-context.ps1 +0 -237
  39. package/assets/.aw-spec/extensions.yml +0 -23
  40. package/assets/.aw-spec/feature.json +0 -3
  41. package/assets/.aw-spec/init-options.json +0 -9
  42. package/assets/.aw-spec/integration.json +0 -15
  43. package/assets/.aw-spec/integrations/aw-spec.manifest.json +0 -17
  44. package/assets/.aw-spec/integrations/claude.manifest.json +0 -17
  45. package/assets/.aw-spec/memory/constitution.md +0 -50
  46. package/assets/.aw-spec/scripts/bash/check-prerequisites.sh +0 -189
  47. package/assets/.aw-spec/scripts/bash/common.sh +0 -582
  48. package/assets/.aw-spec/scripts/bash/create-new-feature.sh +0 -299
  49. package/assets/.aw-spec/scripts/bash/setup-plan.sh +0 -84
  50. package/assets/.aw-spec/scripts/bash/setup-tasks.sh +0 -91
  51. package/assets/.aw-spec/templates/checklist-template.md +0 -40
  52. package/assets/.aw-spec/templates/constitution-template.md +0 -57
  53. package/assets/.aw-spec/templates/plan-template.md +0 -113
  54. package/assets/.aw-spec/templates/spec-template.md +0 -131
  55. package/assets/.aw-spec/templates/tasks-template.md +0 -252
  56. package/assets/.aw-spec/workflows/aw-spec/workflow.yml +0 -77
  57. package/assets/.aw-spec/workflows/workflow-registry.json +0 -13
  58. package/assets/.claude/skills/aw-spec-addcomponent/SKILL.md +0 -129
  59. package/assets/.claude/skills/aw-spec-agent-context-update/SKILL.md +0 -31
  60. package/assets/.claude/skills/aw-spec-analyze/SKILL.md +0 -296
  61. package/assets/.claude/skills/aw-spec-checklist/SKILL.md +0 -374
  62. package/assets/.claude/skills/aw-spec-clarify/SKILL.md +0 -320
  63. package/assets/.claude/skills/aw-spec-constitution/SKILL.md +0 -194
  64. package/assets/.claude/skills/aw-spec-fast-implement/SKILL.md +0 -268
  65. package/assets/.claude/skills/aw-spec-foundation/SKILL.md +0 -358
  66. package/assets/.claude/skills/aw-spec-implement/SKILL.md +0 -279
  67. package/assets/.claude/skills/aw-spec-minimal-implementation/SKILL.md +0 -209
  68. package/assets/.claude/skills/aw-spec-plan/SKILL.md +0 -221
  69. package/assets/.claude/skills/aw-spec-select-domain/SKILL.md +0 -73
  70. package/assets/.claude/skills/aw-spec-specify/SKILL.md +0 -382
  71. package/assets/.claude/skills/aw-spec-tasks/SKILL.md +0 -259
  72. package/assets/.claude/skills/aw-spec-taskstoissues/SKILL.md +0 -107
  73. package/assets/.kilocode/rules/specify-rules.md +0 -4
  74. package/assets/.kilocode/workflows/aw-spec-addcomponent.md +0 -129
  75. package/assets/.kilocode/workflows/aw-spec-agent-context.update.md +0 -31
  76. package/assets/.kilocode/workflows/aw-spec-analyze.md +0 -296
  77. package/assets/.kilocode/workflows/aw-spec-checklist.md +0 -374
  78. package/assets/.kilocode/workflows/aw-spec-clarify.md +0 -320
  79. package/assets/.kilocode/workflows/aw-spec-constitution.md +0 -194
  80. package/assets/.kilocode/workflows/aw-spec-fast-implement.md +0 -263
  81. package/assets/.kilocode/workflows/aw-spec-foundation.md +0 -358
  82. package/assets/.kilocode/workflows/aw-spec-implement.md +0 -279
  83. package/assets/.kilocode/workflows/aw-spec-minimal-implementation.md +0 -204
  84. package/assets/.kilocode/workflows/aw-spec-plan.md +0 -221
  85. package/assets/.kilocode/workflows/aw-spec-select-domain.md +0 -73
  86. package/assets/.kilocode/workflows/aw-spec-specify.md +0 -382
  87. package/assets/.kilocode/workflows/aw-spec-tasks.md +0 -259
  88. package/assets/.kilocode/workflows/aw-spec-taskstoissues.md +0 -107
  89. package/assets/docs/ModularMonolith/ModularMonolith.Reference.pack.txt +0 -25248
  90. package/assets/docs/ModularMonolith/ModularMonolith.pack.txt +0 -5726
  91. package/assets/docs/ModularMonolith/pack-foundation.ps1 +0 -145
  92. package/assets/docs/ModularMonolith/pack-foundation.sh +0 -196
  93. package/assets/docs/ModularMonolith/pack-reference-foundation.ps1 +0 -157
  94. package/assets/docs/ModularMonolith/pack-reference-foundation.sh +0 -209
  95. package/assets/docs/ModularMonolith/unpack-foundation.ps1 +0 -126
  96. package/assets/docs/ModularMonolith/unpack-foundation.sh +0 -217
  97. package/assets/docs/ModularMonolith/unpack-reference-foundation.ps1 +0 -129
  98. package/assets/docs/ModularMonolith/unpack-reference-foundation.sh +0 -218
  99. package/assets/docs/README.md +0 -106
  100. package/assets/docs/UI.Visualization/PACKAGING.md +0 -191
  101. package/assets/docs/UI.Visualization/UI.Visualization.Reference.pack.txt +0 -11768
  102. package/assets/docs/UI.Visualization/UI.Visualization.pack.txt +0 -11214
  103. package/assets/docs/UI.Visualization/pack-foundation.ps1 +0 -165
  104. package/assets/docs/UI.Visualization/pack-foundation.sh +0 -206
  105. package/assets/docs/UI.Visualization/pack-reference-foundation.ps1 +0 -159
  106. package/assets/docs/UI.Visualization/pack-reference-foundation.sh +0 -205
  107. package/assets/docs/UI.Visualization/unpack-foundation.ps1 +0 -126
  108. package/assets/docs/UI.Visualization/unpack-foundation.sh +0 -217
  109. package/assets/docs/UI.Visualization/unpack-reference-foundation.ps1 +0 -129
  110. package/assets/docs/UI.Visualization/unpack-reference-foundation.sh +0 -218
  111. package/assets/docs/VerticalSlice/PACKAGING.md +0 -185
  112. package/assets/docs/VerticalSlice/VerticalSlice.Reference.pack.txt +0 -19318
  113. package/assets/docs/VerticalSlice/VerticalSlice.pack.txt +0 -2833
  114. package/assets/docs/VerticalSlice/pack-foundation.ps1 +0 -145
  115. package/assets/docs/VerticalSlice/pack-foundation.sh +0 -196
  116. package/assets/docs/VerticalSlice/pack-reference-foundation.ps1 +0 -157
  117. package/assets/docs/VerticalSlice/pack-reference-foundation.sh +0 -209
  118. package/assets/docs/VerticalSlice/unpack-foundation.ps1 +0 -126
  119. package/assets/docs/VerticalSlice/unpack-foundation.sh +0 -217
  120. package/assets/docs/VerticalSlice/unpack-reference-foundation.ps1 +0 -129
  121. package/assets/docs/VerticalSlice/unpack-reference-foundation.sh +0 -218
  122. package/assets/docs/architecture/clean-architecture.md +0 -71
  123. package/assets/docs/architecture/cqrs.md +0 -141
  124. package/assets/docs/architecture/eventing.md +0 -83
  125. package/assets/docs/architecture/folder-structure.md +0 -61
  126. package/assets/docs/architecture/modular-monolith.md +0 -47
  127. package/assets/docs/architecture/persistence.md +0 -269
  128. package/assets/docs/architecture/testing.md +0 -55
  129. package/assets/docs/architecture/vertical-slices.md +0 -201
  130. package/assets/docs/command.txt +0 -295
  131. package/assets/docs/components/Email/README.md +0 -119
  132. package/assets/docs/components/Email/ReferenceEndpoints/SendEmailEndpoint.cs +0 -84
  133. package/assets/docs/components/Email/integration.md +0 -300
  134. package/assets/docs/components/Jobs/README.md +0 -113
  135. package/assets/docs/components/Jobs/integration.md +0 -259
  136. package/assets/docs/components/QrGenerator/README.md +0 -85
  137. package/assets/docs/components/QrGenerator/ReferenceEndpoints/GenerateQrEndpoint.cs +0 -57
  138. package/assets/docs/components/QrGenerator/integration.md +0 -230
  139. package/assets/docs/components/README.md +0 -74
  140. package/assets/docs/domain/domain-driven-design.md +0 -212
  141. package/assets/docs/domainspecs/UIVisualization/chart-bubble.md +0 -70
  142. package/assets/docs/domainspecs/UIVisualization/chart-dimred.md +0 -58
  143. package/assets/docs/domainspecs/UIVisualization/chart-heatmap.md +0 -62
  144. package/assets/docs/domainspecs/UIVisualization/chart-network.md +0 -69
  145. package/assets/docs/domainspecs/UIVisualization/chart-parallel.md +0 -75
  146. package/assets/docs/domainspecs/UIVisualization/chart-scurve.md +0 -66
  147. package/assets/docs/domainspecs/UIVisualization/chart-survival.md +0 -69
  148. package/assets/docs/domainspecs/UIVisualization/chart-trellis.md +0 -68
  149. package/assets/docs/domainspecs/UIVisualization/chart-violin.md +0 -61
  150. package/assets/docs/domainspecs/UIVisualization/chart-volcano.md +0 -63
  151. package/assets/docs/domainspecs/UIVisualization/charting-standards.domain.md +0 -80
  152. package/assets/docs/domainspecs/UIVisualization/clean-architecture.domain.md +0 -87
  153. package/assets/docs/domainspecs/UIVisualization/coding-standards.domain.md +0 -47
  154. package/assets/docs/domainspecs/UIVisualization/comandrulemap.md +0 -130
  155. package/assets/docs/domainspecs/UIVisualization/component-contracts.domain.md +0 -67
  156. package/assets/docs/domainspecs/UIVisualization/data-source.domain.md +0 -68
  157. package/assets/docs/domainspecs/UIVisualization/domain-requirements.md +0 -110
  158. package/assets/docs/domainspecs/UIVisualization/folder-structure.domain.md +0 -55
  159. package/assets/docs/domainspecs/UIVisualization/state-management.domain.md +0 -67
  160. package/assets/docs/domainspecs/UIVisualization/testing.domain.md +0 -52
  161. package/assets/docs/domainspecs/UIVisualization/ui-viz-terms.md +0 -39
  162. package/assets/docs/domainspecs/healthcare/ai-rules.domain.md +0 -34
  163. package/assets/docs/domainspecs/healthcare/api-versioning.domain.md +0 -17
  164. package/assets/docs/domainspecs/healthcare/auditing.domain.md +0 -29
  165. package/assets/docs/domainspecs/healthcare/authorization.domain.md +0 -26
  166. package/assets/docs/domainspecs/healthcare/clinical-terms.md +0 -20
  167. package/assets/docs/domainspecs/healthcare/coding-standards.domain.md +0 -26
  168. package/assets/docs/domainspecs/healthcare/comandrulemap.md +0 -166
  169. package/assets/docs/domainspecs/healthcare/consent.md +0 -19
  170. package/assets/docs/domainspecs/healthcare/cqrs.domain.md +0 -12
  171. package/assets/docs/domainspecs/healthcare/data-classification.domain.md +0 -28
  172. package/assets/docs/domainspecs/healthcare/dependency-policy.domain.md +0 -11
  173. package/assets/docs/domainspecs/healthcare/dicom.md +0 -15
  174. package/assets/docs/domainspecs/healthcare/domain-driven-design.domain.md +0 -28
  175. package/assets/docs/domainspecs/healthcare/domain-requirements.md +0 -55
  176. package/assets/docs/domainspecs/healthcare/eventing.domain.md +0 -18
  177. package/assets/docs/domainspecs/healthcare/fhir.md +0 -36
  178. package/assets/docs/domainspecs/healthcare/folder-structure.domain.md +0 -23
  179. package/assets/docs/domainspecs/healthcare/hipaa.md +0 -34
  180. package/assets/docs/domainspecs/healthcare/hl7.md +0 -15
  181. package/assets/docs/domainspecs/healthcare/integration-terms.md +0 -21
  182. package/assets/docs/domainspecs/healthcare/persistence.domain.md +0 -20
  183. package/assets/docs/domainspecs/healthcare/terminology.md +0 -30
  184. package/assets/docs/domainspecs/healthcare/testing.domain.md +0 -15
  185. package/assets/docs/domainspecs/healthcare/vertical-slices.domain.md +0 -18
  186. package/assets/docs/domainspecs/healthcare/zero-trust.domain.md +0 -12
  187. package/assets/docs/domainspecs/pharma/ai-rules.domain.md +0 -32
  188. package/assets/docs/domainspecs/pharma/api-versioning.domain.md +0 -20
  189. package/assets/docs/domainspecs/pharma/atc.md +0 -22
  190. package/assets/docs/domainspecs/pharma/auditing.domain.md +0 -26
  191. package/assets/docs/domainspecs/pharma/authorization.domain.md +0 -25
  192. package/assets/docs/domainspecs/pharma/coding-standards.domain.md +0 -28
  193. package/assets/docs/domainspecs/pharma/comandrulemap.md +0 -186
  194. package/assets/docs/domainspecs/pharma/cqrs.domain.md +0 -16
  195. package/assets/docs/domainspecs/pharma/data-classification.domain.md +0 -24
  196. package/assets/docs/domainspecs/pharma/data-provenance.md +0 -21
  197. package/assets/docs/domainspecs/pharma/dependency-policy.domain.md +0 -11
  198. package/assets/docs/domainspecs/pharma/domain-driven-design.domain.md +0 -36
  199. package/assets/docs/domainspecs/pharma/domain-requirements.md +0 -99
  200. package/assets/docs/domainspecs/pharma/eventing.domain.md +0 -18
  201. package/assets/docs/domainspecs/pharma/fhir.md +0 -31
  202. package/assets/docs/domainspecs/pharma/folder-structure.domain.md +0 -24
  203. package/assets/docs/domainspecs/pharma/hl7.md +0 -17
  204. package/assets/docs/domainspecs/pharma/idmp.md +0 -26
  205. package/assets/docs/domainspecs/pharma/integration-terms.md +0 -21
  206. package/assets/docs/domainspecs/pharma/ndc.md +0 -28
  207. package/assets/docs/domainspecs/pharma/persistence.domain.md +0 -23
  208. package/assets/docs/domainspecs/pharma/pharma-terms.md +0 -27
  209. package/assets/docs/domainspecs/pharma/product-lifecycle.domain.md +0 -30
  210. package/assets/docs/domainspecs/pharma/regulatory-compliance.md +0 -19
  211. package/assets/docs/domainspecs/pharma/terminology.md +0 -32
  212. package/assets/docs/domainspecs/pharma/testing.domain.md +0 -19
  213. package/assets/docs/domainspecs/pharma/vertical-slices.domain.md +0 -17
  214. package/assets/docs/domainspecs/pharma/zero-trust.domain.md +0 -12
  215. package/assets/docs/glossary/ai-rules.md +0 -59
  216. package/assets/docs/governance/api-versioning.md +0 -99
  217. package/assets/docs/governance/coding-standards.md +0 -87
  218. package/assets/docs/governance/dependency-policy.md +0 -40
  219. package/assets/docs/interop/ihe-conformance.md +0 -31
  220. package/assets/docs/security/auditing.md +0 -117
  221. package/assets/docs/security/authorization-matrix.md +0 -14
  222. package/assets/docs/security/authorization.md +0 -87
  223. package/assets/docs/security/data-classification.md +0 -38
  224. package/assets/docs/security/zero-trust.md +0 -76
  225. package/assets/docs/technology-constitution.md +0 -172
@@ -1,205 +0,0 @@
1
- #!/usr/bin/env bash
2
- #
3
- # pack-reference-foundation.sh — bash/macOS port of pack-reference-foundation.ps1
4
- #
5
- # SYNOPSIS
6
- # Pack a verified UI feature reference template into a single AW-Spec text pack file.
7
- #
8
- # DESCRIPTION
9
- # Walks --source-dir (a templates/features/<Name>.SimpleSample folder for UI features),
10
- # excludes build/IDE artifacts, JS output, template meta-files, and secret-bearing files,
11
- # and writes every remaining file into one pack file using <<<FILE>>> / <<<ENDFILE>>>
12
- # markers. Format-compatible with unpack-reference-foundation.
13
- #
14
- # EXAMPLE
15
- # ./pack-reference-foundation.sh \
16
- # --source-dir ../../../../templates/features/UIVisualization.SimpleSample \
17
- # --out-file ./UI.Visualization.Reference.pack.txt \
18
- # --sentinel UI.Visualization \
19
- # --foundation UI.Visualization.Reference
20
- #
21
- set -euo pipefail
22
-
23
- # ------------------------------------------------------------------ defaults ---
24
- SENTINEL='AppWeaver.UI.Visualization'
25
- FOUNDATION='AppWeaver.UI.Visualization.Reference'
26
- SOURCE_DIR=''
27
- OUT_FILE=''
28
- ALLOW_SECRETS=0
29
-
30
- usage() {
31
- cat >&2 <<'EOF'
32
- Usage: pack-reference-foundation.sh --source-dir <dir> [--out-file <file>]
33
- [--sentinel <name>] [--foundation <name>]
34
- [--allow-secrets]
35
-
36
- -s, --source-dir <dir> templates/features/<Name>.SimpleSample folder (required)
37
- -o, --out-file <file> Output pack file (default: ./<foundation>.pack.txt)
38
- --sentinel <name> Sentinel app name (default: UI.Visualization)
39
- --foundation <name> Foundation name (default: UI.Visualization.Reference)
40
- --allow-secrets Pack even if credential markers are detected
41
- -h, --help Show this help
42
-
43
- Positional fallback: pack-reference-foundation.sh <source-dir> [out-file]
44
- EOF
45
- }
46
-
47
- # -------------------------------------------------------------- arg parsing ---
48
- while [ $# -gt 0 ]; do
49
- case "$1" in
50
- -s|--source-dir) SOURCE_DIR="${2:?--source-dir needs a value}"; shift 2 ;;
51
- -o|--out-file) OUT_FILE="${2:?--out-file needs a value}"; shift 2 ;;
52
- --sentinel) SENTINEL="${2:?--sentinel needs a value}"; shift 2 ;;
53
- --foundation) FOUNDATION="${2:?--foundation needs a value}"; shift 2 ;;
54
- --allow-secrets) ALLOW_SECRETS=1; shift ;;
55
- -h|--help) usage; exit 0 ;;
56
- --) shift; break ;;
57
- -*) echo "Error: unknown option: $1" >&2; usage; exit 2 ;;
58
- *)
59
- if [ -z "$SOURCE_DIR" ]; then SOURCE_DIR="$1"
60
- elif [ -z "$OUT_FILE" ]; then OUT_FILE="$1"
61
- else echo "Error: unexpected argument: $1" >&2; usage; exit 2
62
- fi
63
- shift ;;
64
- esac
65
- done
66
-
67
- [ -n "$SOURCE_DIR" ] || { echo "Error: --source-dir is required." >&2; usage; exit 2; }
68
- [ -d "$SOURCE_DIR" ] || { echo "Error: SourceDir is not a folder: $SOURCE_DIR" >&2; exit 1; }
69
-
70
- SRC="$(cd "$SOURCE_DIR" && pwd -P)"
71
- [ -n "$OUT_FILE" ] || OUT_FILE="$(pwd)/$FOUNDATION.pack.txt"
72
-
73
- # -------------------------------------------------------------- exclusions ---
74
- EXCLUDE_DIRS=(
75
- bin obj .vs .git .idea .vscode TestResults
76
- node_modules packages App_Data artifacts
77
- .next .turbo dist out coverage .cache logs
78
- )
79
-
80
- EXCLUDE_FILES=(
81
- '*.user' '*.suo' '*.DotSettings.user' '*.db' '*.db-shm' '*.db-wal' '*.sqlite' '*.log'
82
- '.env' '*.env.*' '.env.*' '*.pfx' '*.pem' '*.key' '*.snk' 'id_rsa' 'id_rsa.pub' 'secrets.json'
83
- '.DS_Store'
84
- '*.my-ref.*'
85
- '*TemplateConfig.config'
86
- '*.tsbuildinfo'
87
- 'next-env.d.ts'
88
- )
89
-
90
- SECRET_NAMES=('NuGet ClearTextPassword' 'Private key block' 'AWS access key id' 'Azure DevOps PAT-ish')
91
- SECRET_RX=(
92
- 'ClearTextPassword'
93
- 'BEGIN (RSA |OPENSSH |EC |DSA )?PRIVATE KEY'
94
- 'AKIA[0-9A-Z]{16}'
95
- '[A-Za-z0-9]{52}AZDO[A-Za-z0-9]'
96
- )
97
-
98
- is_excluded() {
99
- local rel="$1" seg leaf g
100
- local -a segs
101
- IFS='/' read -ra segs <<< "$rel"
102
- for seg in "${segs[@]}"; do
103
- for g in "${EXCLUDE_DIRS[@]}"; do
104
- [ "$seg" = "$g" ] && return 0
105
- done
106
- done
107
- leaf="${rel##*/}"
108
- for g in "${EXCLUDE_FILES[@]}"; do
109
- # shellcheck disable=SC2254
110
- case "$leaf" in $g) return 0 ;; esac
111
- done
112
- return 1
113
- }
114
-
115
- is_binary() {
116
- local f="$1" n1 n2
117
- n1="$(head -c 8000 "$f" | wc -c | tr -d '[:space:]')"
118
- n2="$(head -c 8000 "$f" | LC_ALL=C tr -d '\000' | wc -c | tr -d '[:space:]')"
119
- [ "$n1" != "$n2" ]
120
- }
121
-
122
- # ----------------------------------------------------------- collect + sort ---
123
- picked=()
124
- while IFS= read -r full; do
125
- rel="${full#"$SRC"/}"
126
- is_excluded "$rel" && continue
127
- picked+=("$rel")
128
- done < <(find "$SRC" -type f | LC_ALL=C sort)
129
-
130
- [ "${#picked[@]}" -gt 0 ] || { echo "Error: No files to pack under: $SRC" >&2; exit 1; }
131
-
132
- # ----------------------------------------------------------- secret scan -----
133
- findings=()
134
- for rel in "${picked[@]}"; do
135
- f="$SRC/$rel"
136
- for i in "${!SECRET_RX[@]}"; do
137
- if LC_ALL=C grep -aEq -- "${SECRET_RX[$i]}" "$f" 2>/dev/null; then
138
- findings+=(" $rel -> ${SECRET_NAMES[$i]}")
139
- fi
140
- done
141
- done
142
- if [ "${#findings[@]}" -gt 0 ]; then
143
- if [ "$ALLOW_SECRETS" -eq 1 ]; then
144
- echo "WARNING: Potential secret(s) detected — packing anyway (--allow-secrets):" >&2
145
- printf '%s\n' "${findings[@]}" >&2
146
- else
147
- echo "Error: Potential secret(s) detected — refusing to pack:" >&2
148
- printf '%s\n' "${findings[@]}" >&2
149
- exit 1
150
- fi
151
- fi
152
-
153
- # ----------------------------------------------------------- sentinel check --
154
- hits=0
155
- for rel in "${picked[@]}"; do
156
- if LC_ALL=C grep -aFq -- "$SENTINEL" "$SRC/$rel" 2>/dev/null; then
157
- hits=$((hits + 1))
158
- fi
159
- done
160
- if [ "$hits" -eq 0 ]; then
161
- echo "WARNING: Sentinel '$SENTINEL' not found in any file. Did you author the sample under that exact name?" >&2
162
- else
163
- echo "Sentinel '$SENTINEL' found in $hits file(s)."
164
- fi
165
-
166
- # ----------------------------------------------------------- write the pack --
167
- outdir="$(dirname "$OUT_FILE")"
168
- [ -d "$outdir" ] || mkdir -p "$outdir"
169
-
170
- {
171
- printf '%s\n' '# AW-SPEC REFERENCE PACK'
172
- printf '# foundation: %s\n' "$FOUNDATION"
173
- printf '# sentinel: %s\n' "$SENTINEL"
174
- printf '# generated: %s\n' "$(date -u +%Y-%m-%dT%H:%M:%S.0000000Z)"
175
- printf '# files: %s\n' "${#picked[@]}"
176
- printf '%s\n' '# format: aw-spec-pack/v1'
177
- printf '%s\n' '# --- replacement contract (ordinal, case-sensitive, longest-first) ---'
178
- printf '%s\n' '# <Sentinel> -> <AppName> (dotted: package.json name as dotted)'
179
- printf '%s\n' '# <Sentinel _-form> -> <AppName _-form> (underscored: identifiers)'
180
- printf '%s\n' '# <sentinel --form> -> <appname --form> (lower-hyphen: npm package name, docker image)'
181
- printf '%s\n' '# <sentinel .-form> -> <appname lower-dot> (lower-dot: lowercased identifiers)'
182
- printf '%s\n' '# Applied to file CONTENTS and file/dir PATHS. Never touch other AppWeaver.* tokens.'
183
- printf '%s\n' '# ============================================================'
184
- printf '\n'
185
- } > "$OUT_FILE"
186
-
187
- for rel in "${picked[@]}"; do
188
- f="$SRC/$rel"
189
- if is_binary "$f"; then
190
- {
191
- printf '<<<FILE path="%s" encoding="base64">>>\n' "$rel"
192
- base64 < "$f" | tr -d '\n'
193
- printf '\n'
194
- printf '%s\n' '<<<ENDFILE>>>'
195
- } >> "$OUT_FILE"
196
- else
197
- {
198
- printf '<<<FILE path="%s">>>\n' "$rel"
199
- awk '{ sub(/\r$/, ""); print }' "$f"
200
- printf '%s\n' '<<<ENDFILE>>>'
201
- } >> "$OUT_FILE"
202
- fi
203
- done
204
-
205
- echo "Packed ${#picked[@]} file(s) -> $OUT_FILE"
@@ -1,126 +0,0 @@
1
- #requires -Version 5.1
2
- <#
3
- .SYNOPSIS
4
- Unpack an AW-Spec foundation pack file into a target application, renaming the
5
- sentinel app name to the caller's app name.
6
-
7
- .DESCRIPTION
8
- Reads -PackFile, takes the sentinel from its header (override with -Sentinel),
9
- derives four case forms of the target app name, and writes every file block to
10
- -OutDir with the sentinel rewritten in both file CONTENTS and file/dir PATHS.
11
- Text blocks are rewritten and written as UTF-8; base64 blocks are decoded as-is.
12
- Refuses to overwrite existing files unless -Force.
13
-
14
- .EXAMPLE
15
- ./unpack-foundation.ps1 -PackFile ./UI.Visualization.pack.txt -TargetAppName MyApp -OutDir ../../
16
- #>
17
- [CmdletBinding()]
18
- param(
19
- [Parameter(Mandatory)] [string] $PackFile,
20
- [Parameter(Mandatory)] [string] $TargetAppName,
21
- [string] $OutDir = '.',
22
- [string] $Sentinel,
23
- [switch] $Force,
24
- [switch] $DryRun
25
- )
26
-
27
- $ErrorActionPreference = 'Stop'
28
-
29
- $pack = (Resolve-Path -LiteralPath $PackFile).Path
30
- $lines = ([System.IO.File]::ReadAllText($pack)) -split "`r?`n"
31
-
32
- # --- sentinel from header unless overridden ---
33
- if (-not $Sentinel) {
34
- foreach ($l in $lines) {
35
- if ($l -match '^#\s*sentinel:\s*(.+?)\s*$') { $Sentinel = $Matches[1]; break }
36
- }
37
- }
38
- if (-not $Sentinel) { throw "Sentinel not found in pack header; supply it with -Sentinel." }
39
-
40
- # --- derive case forms ---
41
- function Conv-Underscore ([string] $s) { $s -replace '\.','_' }
42
- function Conv-LowerHyphen ([string] $s) { ($s.ToLowerInvariant()) -replace '\.','-' }
43
- function Conv-LowerDot ([string] $s) { $s.ToLowerInvariant() }
44
-
45
- # NOTE: do NOT use a hashtable here — PowerShell hashtable keys are case-INSENSITIVE,
46
- # which would collapse the dotted ("AppWeaver.Foundation") and lower-dot
47
- # ("appweaver.foundation") forms into one entry and drop the namespace rename.
48
- $forms = @(
49
- @{ From = $Sentinel; To = $TargetAppName }
50
- @{ From = (Conv-Underscore $Sentinel); To = (Conv-Underscore $TargetAppName) }
51
- @{ From = (Conv-LowerHyphen $Sentinel); To = (Conv-LowerHyphen $TargetAppName) }
52
- @{ From = (Conv-LowerDot $Sentinel); To = (Conv-LowerDot $TargetAppName) }
53
- )
54
- $replacements = @()
55
- $seen = New-Object 'System.Collections.Generic.HashSet[string]' ([System.StringComparer]::Ordinal)
56
- foreach ($pair in $forms) {
57
- $from = [string]$pair.From
58
- $to = [string]$pair.To
59
- if ([string]::IsNullOrEmpty($from)) { continue }
60
- if ($from -ceq $to) { continue } # -ceq: case-sensitive no-op check
61
- if (-not $seen.Add($from)) { continue } # ordinal dedupe of identical From tokens
62
- $replacements += [pscustomobject]@{ From = $from; To = $to }
63
- }
64
- # longest token first so overlaps resolve correctly
65
- $replacements = @($replacements | Sort-Object { $_.From.Length } -Descending)
66
-
67
- function Apply-Repl([string] $text) {
68
- foreach ($r in $replacements) { $text = $text.Replace($r.From, $r.To) }
69
- return $text
70
- }
71
-
72
- # --- output root ---
73
- if (-not (Test-Path -LiteralPath $OutDir)) { New-Item -ItemType Directory -Force -Path $OutDir | Out-Null }
74
- $outRoot = (Resolve-Path -LiteralPath $OutDir).Path
75
- $sep = [System.IO.Path]::DirectorySeparatorChar
76
-
77
- # --- parse file blocks ---
78
- $files = @()
79
- $i = 0
80
- while ($i -lt $lines.Count) {
81
- if ($lines[$i] -match '^<<<FILE path="(.+?)"(?:\s+encoding="(\w+)")?>>>\s*$') {
82
- $rel = $Matches[1]; $enc = $Matches[2]
83
- $i++
84
- $buf = New-Object System.Collections.Generic.List[string]
85
- while ($i -lt $lines.Count -and $lines[$i] -ne '<<<ENDFILE>>>') {
86
- $buf.Add($lines[$i]); $i++
87
- }
88
- $files += [pscustomobject]@{ Rel = $rel; Enc = $enc; Content = ($buf -join "`n") }
89
- }
90
- $i++
91
- }
92
- if ($files.Count -eq 0) { throw "No <<<FILE>>> blocks found in pack: $pack" }
93
-
94
- function Resolve-Dest([string] $rel) {
95
- $renamed = (Apply-Repl $rel).Replace('/', $sep)
96
- return (Join-Path $outRoot $renamed)
97
- }
98
-
99
- # --- conflict guard ---
100
- $conflicts = foreach ($f in $files) { $d = Resolve-Dest $f.Rel; if (Test-Path -LiteralPath $d) { $d } }
101
- if ($conflicts -and -not $Force) {
102
- throw ("Refusing to overwrite existing files (re-run with -Force):`n " + ($conflicts -join "`n "))
103
- }
104
-
105
- # --- write ---
106
- $written = 0
107
- foreach ($f in $files) {
108
- $dest = Resolve-Dest $f.Rel
109
- $destDir = Split-Path -Parent $dest
110
- if ($DryRun) { Write-Host "WOULD WRITE $($f.Rel) -> $dest"; continue }
111
- if ($destDir -and -not (Test-Path -LiteralPath $destDir)) {
112
- New-Item -ItemType Directory -Force -Path $destDir | Out-Null
113
- }
114
- if ($f.Enc -eq 'base64') {
115
- [System.IO.File]::WriteAllBytes($dest, [Convert]::FromBase64String(($f.Content -replace '\s','')))
116
- } else {
117
- [System.IO.File]::WriteAllText($dest, (Apply-Repl $f.Content), [System.Text.UTF8Encoding]::new($false))
118
- }
119
- $written++
120
- }
121
-
122
- if ($DryRun) {
123
- Write-Host "DryRun: $($files.Count) file(s) would be written to $outRoot (sentinel '$Sentinel' -> '$TargetAppName')."
124
- } else {
125
- Write-Host "Unpacked $written file(s) to $outRoot (sentinel '$Sentinel' -> '$TargetAppName')."
126
- }
@@ -1,217 +0,0 @@
1
- #!/usr/bin/env bash
2
- #
3
- # unpack-foundation.sh — bash/macOS+Unix port of unpack-foundation.ps1
4
- #
5
- # SYNOPSIS
6
- # Unpack an AW-Spec foundation pack file into a target application, renaming the
7
- # sentinel app name to the caller's app name.
8
- #
9
- # DESCRIPTION
10
- # Reads --pack-file, takes the sentinel from its header (override with --sentinel),
11
- # derives four case forms of the target app name, and writes every file block to
12
- # --out-dir with the sentinel rewritten in both file CONTENTS and file/dir PATHS.
13
- # Text blocks are rewritten and written as UTF-8; base64 blocks are decoded as-is.
14
- # Refuses to overwrite existing files unless --force. Reads packs produced by either
15
- # pack-foundation.sh or pack-foundation.ps1.
16
- #
17
- # EXAMPLE
18
- # ./unpack-foundation.sh --pack-file ./UI.Visualization.pack.txt --target-app-name MyApp --out-dir ../../
19
- #
20
- set -euo pipefail
21
-
22
- # ------------------------------------------------------------------ defaults ---
23
- PACK_FILE=''
24
- TARGET_APP_NAME=''
25
- OUT_DIR='.'
26
- SENTINEL=''
27
- FORCE=0
28
- DRYRUN=0
29
-
30
- usage() {
31
- cat >&2 <<'EOF'
32
- Usage: unpack-foundation.sh --pack-file <file> --target-app-name <name>
33
- [--out-dir <dir>] [--sentinel <name>] [--force] [--dry-run]
34
-
35
- -p, --pack-file <file> Pack file to unpack (required)
36
- -t, --target-app-name <name> New app name to rename the sentinel into (required)
37
- -o, --out-dir <dir> Output root (default: . / repo root by skill)
38
- --sentinel <name> Override the sentinel from the pack header
39
- --force Overwrite files that already exist
40
- --dry-run List what would be written, write nothing
41
- -h, --help Show this help
42
-
43
- Positional fallback: unpack-foundation.sh <pack-file> <target-app-name> [out-dir]
44
- EOF
45
- }
46
-
47
- # -------------------------------------------------------------- arg parsing ---
48
- while [ $# -gt 0 ]; do
49
- case "$1" in
50
- -p|--pack-file) PACK_FILE="${2:?--pack-file needs a value}"; shift 2 ;;
51
- -t|--target-app-name) TARGET_APP_NAME="${2:?--target-app-name needs a value}"; shift 2 ;;
52
- -o|--out-dir) OUT_DIR="${2:?--out-dir needs a value}"; shift 2 ;;
53
- --sentinel) SENTINEL="${2:?--sentinel needs a value}"; shift 2 ;;
54
- --force) FORCE=1; shift ;;
55
- --dry-run) DRYRUN=1; shift ;;
56
- -h|--help) usage; exit 0 ;;
57
- --) shift; break ;;
58
- -*) echo "Error: unknown option: $1" >&2; usage; exit 2 ;;
59
- *)
60
- if [ -z "$PACK_FILE" ]; then PACK_FILE="$1"
61
- elif [ -z "$TARGET_APP_NAME" ]; then TARGET_APP_NAME="$1"
62
- else OUT_DIR="$1"
63
- fi
64
- shift ;;
65
- esac
66
- done
67
-
68
- [ -n "$PACK_FILE" ] || { echo "Error: --pack-file is required." >&2; usage; exit 2; }
69
- [ -n "$TARGET_APP_NAME" ] || { echo "Error: --target-app-name is required." >&2; usage; exit 2; }
70
- [ -f "$PACK_FILE" ] || { echo "Error: pack file not found: $PACK_FILE" >&2; exit 1; }
71
-
72
- # Keep replacement tokens safe for bash literal substitution / path joins.
73
- case "$TARGET_APP_NAME" in
74
- *[!A-Za-z0-9._-]*)
75
- echo "Error: --target-app-name may contain only letters, digits, '.', '_' or '-': $TARGET_APP_NAME" >&2
76
- exit 2 ;;
77
- esac
78
-
79
- # ------------------------------------------------ sentinel from header --------
80
- if [ -z "$SENTINEL" ]; then
81
- SENTINEL="$(LC_ALL=C sed -n 's/^#[[:space:]]*sentinel:[[:space:]]*\(.*[^[:space:]]\)[[:space:]]*$/\1/p' "$PACK_FILE" | head -n1)"
82
- fi
83
- [ -n "$SENTINEL" ] || { echo "Error: Sentinel not found in pack header; supply it with --sentinel." >&2; exit 1; }
84
-
85
- # ------------------------------------------------ derive case forms -----------
86
- to_lower() { printf '%s' "$1" | LC_ALL=C tr '[:upper:]' '[:lower:]'; }
87
-
88
- S_DOT="$SENTINEL"; T_DOT="$TARGET_APP_NAME" # dotted
89
- S_UND="${SENTINEL//./_}"; T_UND="${TARGET_APP_NAME//./_}" # underscored
90
- s_low="$(to_lower "$SENTINEL")"; t_low="$(to_lower "$TARGET_APP_NAME")"
91
- S_HYP="${s_low//./-}"; T_HYP="${t_low//./-}" # lower-hyphen
92
- S_LDOT="$s_low"; T_LDOT="$t_low" # lower-dot
93
-
94
- # Build replacement list: dedupe by From (ordinal), drop no-ops, sort longest-first.
95
- FROM=(); TO=()
96
- add_form() {
97
- local from="$1" to="$2" e
98
- [ -n "$from" ] || return 0
99
- [ "$from" = "$to" ] && return 0
100
- if [ "${#FROM[@]}" -gt 0 ]; then
101
- for e in "${FROM[@]}"; do [ "$e" = "$from" ] && return 0; done
102
- fi
103
- FROM+=("$from"); TO+=("$to")
104
- }
105
- add_form "$S_DOT" "$T_DOT"
106
- add_form "$S_UND" "$T_UND"
107
- add_form "$S_HYP" "$T_HYP"
108
- add_form "$S_LDOT" "$T_LDOT"
109
-
110
- # Order indices by FROM length descending (stable for equal lengths).
111
- ORDER=()
112
- {
113
- local_n="${#FROM[@]}"
114
- used=(); for ((k = 0; k < local_n; k++)); do used[$k]=0; done
115
- for ((pass = 0; pass < local_n; pass++)); do
116
- best=-1; bestlen=-1
117
- for ((j = 0; j < local_n; j++)); do
118
- if [ "${used[$j]}" -eq 0 ] && [ "${#FROM[$j]}" -gt "$bestlen" ]; then
119
- bestlen="${#FROM[$j]}"; best="$j"
120
- fi
121
- done
122
- used[$best]=1; ORDER+=("$best")
123
- done
124
- }
125
-
126
- REPL_OUT=''
127
- apply_repl() { # literal, ordinal, longest-first; result in $REPL_OUT (no subshell trim)
128
- local text="$1" idx from to
129
- if [ "${#ORDER[@]}" -gt 0 ]; then # empty when target == sentinel (no-op rename)
130
- for idx in "${ORDER[@]}"; do
131
- from="${FROM[$idx]}"; to="${TO[$idx]}"
132
- text="${text//"$from"/$to}" # quoted pattern => literal (non-glob) match
133
- done
134
- fi
135
- REPL_OUT="$text"
136
- }
137
-
138
- # ------------------------------------------------ output root ----------------
139
- [ -d "$OUT_DIR" ] || mkdir -p "$OUT_DIR"
140
- OUT_ROOT="$(cd "$OUT_DIR" && pwd -P)"
141
-
142
- # ------------------------------------------------ base64 decoder (portable) --
143
- B64D=()
144
- if printf 'aGk=' | base64 -d >/dev/null 2>&1; then B64D=(base64 -d)
145
- elif printf 'aGk=' | base64 -D >/dev/null 2>&1; then B64D=(base64 -D)
146
- elif printf 'aGk=' | base64 --decode >/dev/null 2>&1; then B64D=(base64 --decode)
147
- else B64D=(openssl base64 -d -A)
148
- fi
149
-
150
- # ------------------------------------------------ parse file blocks ----------
151
- rels=(); encs=(); contents=()
152
- in_block=0; cur_rel=''; cur_enc=''; cur_content=''; first_line=1
153
- file_re='^<<<FILE path="([^"]+)"( encoding="([^"]+)")?>>>[[:space:]]*$'
154
-
155
- while IFS= read -r line || [ -n "$line" ]; do
156
- line="${line%$'\r'}" # tolerate CRLF packs (e.g. git autocrlf on Windows checkout)
157
- if [ "$in_block" -eq 0 ]; then
158
- if [[ "$line" =~ $file_re ]]; then
159
- cur_rel="${BASH_REMATCH[1]}"
160
- cur_enc="${BASH_REMATCH[3]:-}"
161
- in_block=1; first_line=1; cur_content=''
162
- fi
163
- else
164
- if [ "$line" = '<<<ENDFILE>>>' ]; then
165
- rels+=("$cur_rel"); encs+=("$cur_enc"); contents+=("$cur_content")
166
- in_block=0
167
- elif [ "$first_line" -eq 1 ]; then
168
- cur_content="$line"; first_line=0
169
- else
170
- cur_content="$cur_content"$'\n'"$line"
171
- fi
172
- fi
173
- done < "$PACK_FILE"
174
-
175
- [ "${#rels[@]}" -gt 0 ] || { echo "Error: No <<<FILE>>> blocks found in pack: $PACK_FILE" >&2; exit 1; }
176
-
177
- # ------------------------------------------------ resolve destinations -------
178
- dests=()
179
- for ((i = 0; i < ${#rels[@]}; i++)); do
180
- apply_repl "${rels[$i]}"
181
- dests+=("$OUT_ROOT/$REPL_OUT")
182
- done
183
-
184
- # ------------------------------------------------ conflict guard -------------
185
- if [ "$FORCE" -eq 0 ] && [ "$DRYRUN" -eq 0 ]; then
186
- conflicts=()
187
- for d in "${dests[@]}"; do [ -e "$d" ] && conflicts+=("$d"); done
188
- if [ "${#conflicts[@]}" -gt 0 ]; then
189
- echo "Error: Refusing to overwrite existing files (re-run with --force):" >&2
190
- printf ' %s\n' "${conflicts[@]}" >&2
191
- exit 1
192
- fi
193
- fi
194
-
195
- # ------------------------------------------------ write ----------------------
196
- written=0
197
- for ((i = 0; i < ${#rels[@]}; i++)); do
198
- rel="${rels[$i]}"; enc="${encs[$i]}"; dest="${dests[$i]}"
199
- if [ "$DRYRUN" -eq 1 ]; then
200
- echo "WOULD WRITE $rel -> $dest"
201
- continue
202
- fi
203
- mkdir -p "$(dirname "$dest")"
204
- if [ "$enc" = 'base64' ]; then
205
- printf '%s' "${contents[$i]}" | tr -d '[:space:]' | "${B64D[@]}" > "$dest"
206
- else
207
- apply_repl "${contents[$i]}"
208
- printf '%s' "$REPL_OUT" > "$dest"
209
- fi
210
- written=$((written + 1))
211
- done
212
-
213
- if [ "$DRYRUN" -eq 1 ]; then
214
- echo "DryRun: ${#rels[@]} file(s) would be written to $OUT_ROOT (sentinel '$SENTINEL' -> '$TARGET_APP_NAME')."
215
- else
216
- echo "Unpacked $written file(s) to $OUT_ROOT (sentinel '$SENTINEL' -> '$TARGET_APP_NAME')."
217
- fi
@@ -1,129 +0,0 @@
1
- #requires -Version 5.1
2
- <#
3
- .SYNOPSIS
4
- Unpack an AW-Spec reference pack file into a target project, renaming the
5
- sentinel app name to the caller's app name.
6
-
7
- .DESCRIPTION
8
- Reads -PackFile (produced by pack-reference-foundation.ps1), takes the sentinel from
9
- its header (override with -Sentinel), derives four case forms of the target app name,
10
- and writes every file block to -OutDir with the sentinel rewritten in both file
11
- CONTENTS and file/dir PATHS. Text blocks are rewritten and written as UTF-8;
12
- base64 blocks are decoded as-is. Refuses to overwrite existing files unless -Force.
13
-
14
- .EXAMPLE
15
- ./unpack-reference-foundation.ps1 `
16
- -PackFile ./UI.Visualization.Reference.pack.txt `
17
- -TargetAppName MyApp `
18
- -OutDir ../../
19
- #>
20
- [CmdletBinding()]
21
- param(
22
- [Parameter(Mandatory)] [string] $PackFile,
23
- [Parameter(Mandatory)] [string] $TargetAppName,
24
- [string] $OutDir = '.',
25
- [string] $Sentinel,
26
- [switch] $Force,
27
- [switch] $DryRun
28
- )
29
-
30
- $ErrorActionPreference = 'Stop'
31
-
32
- $pack = (Resolve-Path -LiteralPath $PackFile).Path
33
- $lines = ([System.IO.File]::ReadAllText($pack)) -split "`r?`n"
34
-
35
- # --- sentinel from header unless overridden ---
36
- if (-not $Sentinel) {
37
- foreach ($l in $lines) {
38
- if ($l -match '^#\s*sentinel:\s*(.+?)\s*$') { $Sentinel = $Matches[1]; break }
39
- }
40
- }
41
- if (-not $Sentinel) { throw "Sentinel not found in pack header; supply it with -Sentinel." }
42
-
43
- # --- derive case forms ---
44
- function Conv-Underscore ([string] $s) { $s -replace '\.','_' }
45
- function Conv-LowerHyphen ([string] $s) { ($s.ToLowerInvariant()) -replace '\.','-' }
46
- function Conv-LowerDot ([string] $s) { $s.ToLowerInvariant() }
47
-
48
- # NOTE: do NOT use a hashtable here — PowerShell hashtable keys are case-INSENSITIVE,
49
- # which would collapse the dotted ("AppWeaver.VerticalSlice") and lower-dot
50
- # ("appweaver.verticalslice") forms into one entry and drop the namespace rename.
51
- $forms = @(
52
- @{ From = $Sentinel; To = $TargetAppName }
53
- @{ From = (Conv-Underscore $Sentinel); To = (Conv-Underscore $TargetAppName) }
54
- @{ From = (Conv-LowerHyphen $Sentinel); To = (Conv-LowerHyphen $TargetAppName) }
55
- @{ From = (Conv-LowerDot $Sentinel); To = (Conv-LowerDot $TargetAppName) }
56
- )
57
- $replacements = @()
58
- $seen = New-Object 'System.Collections.Generic.HashSet[string]' ([System.StringComparer]::Ordinal)
59
- foreach ($pair in $forms) {
60
- $from = [string]$pair.From
61
- $to = [string]$pair.To
62
- if ([string]::IsNullOrEmpty($from)) { continue }
63
- if ($from -ceq $to) { continue }
64
- if (-not $seen.Add($from)) { continue }
65
- $replacements += [pscustomobject]@{ From = $from; To = $to }
66
- }
67
- # longest token first so overlaps resolve correctly
68
- $replacements = @($replacements | Sort-Object { $_.From.Length } -Descending)
69
-
70
- function Apply-Repl([string] $text) {
71
- foreach ($r in $replacements) { $text = $text.Replace($r.From, $r.To) }
72
- return $text
73
- }
74
-
75
- # --- output root ---
76
- if (-not (Test-Path -LiteralPath $OutDir)) { New-Item -ItemType Directory -Force -Path $OutDir | Out-Null }
77
- $outRoot = (Resolve-Path -LiteralPath $OutDir).Path
78
- $sep = [System.IO.Path]::DirectorySeparatorChar
79
-
80
- # --- parse file blocks ---
81
- $files = @()
82
- $i = 0
83
- while ($i -lt $lines.Count) {
84
- if ($lines[$i] -match '^<<<FILE path="(.+?)"(?:\s+encoding="(\w+)")?>>>\s*$') {
85
- $rel = $Matches[1]; $enc = $Matches[2]
86
- $i++
87
- $buf = New-Object System.Collections.Generic.List[string]
88
- while ($i -lt $lines.Count -and $lines[$i] -ne '<<<ENDFILE>>>') {
89
- $buf.Add($lines[$i]); $i++
90
- }
91
- $files += [pscustomobject]@{ Rel = $rel; Enc = $enc; Content = ($buf -join "`n") }
92
- }
93
- $i++
94
- }
95
- if ($files.Count -eq 0) { throw "No <<<FILE>>> blocks found in pack: $pack" }
96
-
97
- function Resolve-Dest([string] $rel) {
98
- $renamed = (Apply-Repl $rel).Replace('/', $sep)
99
- return (Join-Path $outRoot $renamed)
100
- }
101
-
102
- # --- conflict guard ---
103
- $conflicts = foreach ($f in $files) { $d = Resolve-Dest $f.Rel; if (Test-Path -LiteralPath $d) { $d } }
104
- if ($conflicts -and -not $Force) {
105
- throw ("Refusing to overwrite existing files (re-run with -Force):`n " + ($conflicts -join "`n "))
106
- }
107
-
108
- # --- write ---
109
- $written = 0
110
- foreach ($f in $files) {
111
- $dest = Resolve-Dest $f.Rel
112
- $destDir = Split-Path -Parent $dest
113
- if ($DryRun) { Write-Host "WOULD WRITE $($f.Rel) -> $dest"; continue }
114
- if ($destDir -and -not (Test-Path -LiteralPath $destDir)) {
115
- New-Item -ItemType Directory -Force -Path $destDir | Out-Null
116
- }
117
- if ($f.Enc -eq 'base64') {
118
- [System.IO.File]::WriteAllBytes($dest, [Convert]::FromBase64String(($f.Content -replace '\s','')))
119
- } else {
120
- [System.IO.File]::WriteAllText($dest, (Apply-Repl $f.Content), [System.Text.UTF8Encoding]::new($false))
121
- }
122
- $written++
123
- }
124
-
125
- if ($DryRun) {
126
- Write-Host "DryRun: $($files.Count) file(s) would be written to $outRoot (sentinel '$Sentinel' -> '$TargetAppName')."
127
- } else {
128
- Write-Host "Unpacked $written file(s) to $outRoot (sentinel '$Sentinel' -> '$TargetAppName')."
129
- }