@hybridlabor-api/aos 4.8.0 → 4.9.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 (166) hide show
  1. package/.agents/agents.md +1 -1
  2. package/.agents/nodes.json +1 -1
  3. package/.agents/vendor-manifest.json +23 -1
  4. package/.claude/agents/godmode-media-eventtech.md +1 -1
  5. package/.claude/hooks/conventional-commits.mjs +125 -0
  6. package/.claude/hooks/env-file-protection.mjs +105 -0
  7. package/.claude/hooks/go-gate.mjs +101 -81
  8. package/.claude/settings.json +13 -0
  9. package/.opencode/agents/godmode-media-eventtech.md +1 -1
  10. package/.opencode/plugins/bdb-aos.js +31 -4
  11. package/README.de.md +1 -1
  12. package/README.md +1 -1
  13. package/README.pt.md +1 -1
  14. package/THIRD_PARTY_NOTICES.md +88 -0
  15. package/docs/skills_table.md +1 -1
  16. package/installer.js +174 -46
  17. package/package.json +6 -2
  18. package/packages/aos-cli/README.md +80 -0
  19. package/packages/aos-cli/bin/aos-cli.mjs +134 -0
  20. package/packages/aos-cli/core-skills.json +12 -0
  21. package/packages/aos-cli/extensions/aos.ts +321 -0
  22. package/packages/aos-cli/package-lock.json +1923 -0
  23. package/packages/aos-cli/package.json +29 -0
  24. package/packages/aos-cli/scripts/check-theme.mjs +63 -0
  25. package/packages/aos-cli/themes/aos.json +97 -0
  26. package/scripts/build-plugin-manifest.mjs +131 -0
  27. package/scripts/validate-skills.mjs +81 -6
  28. package/skills/basic/ao-orchestrator/SKILL.md +116 -0
  29. package/skills/global_config/agenttrail/SKILL.md +6 -1
  30. package/skills/global_config/ask-tim/SKILL.md +4 -4
  31. package/skills/global_config/bash-script-generator/SKILL.md +201 -0
  32. package/skills/global_config/bash-script-generator/assets/templates/standard-template.sh +96 -0
  33. package/skills/global_config/bash-script-generator/docs/bash-scripting-guide.md +729 -0
  34. package/skills/global_config/bash-script-generator/docs/generation-best-practices.md +193 -0
  35. package/skills/global_config/bash-script-generator/docs/script-patterns.md +566 -0
  36. package/skills/global_config/bash-script-generator/docs/text-processing-guide.md +437 -0
  37. package/skills/global_config/bash-script-generator/examples/log-analyzer.sh +92 -0
  38. package/skills/global_config/bash-script-generator/scripts/generate_script_template.sh +123 -0
  39. package/skills/global_config/bash-script-generator/scripts/run_ci_checks.sh +172 -0
  40. package/skills/global_config/bash-script-generator/scripts/test_generator.sh +413 -0
  41. package/skills/global_config/bash-script-validator/SKILL.md +249 -0
  42. package/skills/global_config/bash-script-validator/docs/awk-reference.md +449 -0
  43. package/skills/global_config/bash-script-validator/docs/bash-reference.md +468 -0
  44. package/skills/global_config/bash-script-validator/docs/common-mistakes.md +623 -0
  45. package/skills/global_config/bash-script-validator/docs/grep-reference.md +395 -0
  46. package/skills/global_config/bash-script-validator/docs/regex-reference.md +391 -0
  47. package/skills/global_config/bash-script-validator/docs/sed-reference.md +454 -0
  48. package/skills/global_config/bash-script-validator/docs/shell-reference.md +463 -0
  49. package/skills/global_config/bash-script-validator/docs/shellcheck-reference.md +399 -0
  50. package/skills/global_config/bash-script-validator/examples/bad-bash.sh +55 -0
  51. package/skills/global_config/bash-script-validator/examples/bad-shell.sh +54 -0
  52. package/skills/global_config/bash-script-validator/examples/good-bash.sh +71 -0
  53. package/skills/global_config/bash-script-validator/examples/good-shell.sh +69 -0
  54. package/skills/global_config/bash-script-validator/scripts/run_ci_checks.sh +23 -0
  55. package/skills/global_config/bash-script-validator/scripts/shellcheck_wrapper.sh +174 -0
  56. package/skills/global_config/bash-script-validator/scripts/test_validate.sh +446 -0
  57. package/skills/global_config/bash-script-validator/scripts/validate.sh +512 -0
  58. package/skills/global_config/ci-pipeline/SKILL.md +135 -0
  59. package/skills/global_config/dispatching-parallel-agents/SKILL.md +170 -0
  60. package/skills/global_config/dockerfile-generator/SKILL.md +1038 -0
  61. package/skills/global_config/dockerfile-generator/examples/example.dockerignore +95 -0
  62. package/skills/global_config/dockerfile-generator/examples/golang-distroless.Dockerfile +34 -0
  63. package/skills/global_config/dockerfile-generator/examples/java-springboot.Dockerfile +45 -0
  64. package/skills/global_config/dockerfile-generator/examples/nextjs-production.Dockerfile +49 -0
  65. package/skills/global_config/dockerfile-generator/examples/nodejs-multistage.Dockerfile +55 -0
  66. package/skills/global_config/dockerfile-generator/examples/python-fastapi.Dockerfile +48 -0
  67. package/skills/global_config/dockerfile-generator/references/language_specific_guides.md +510 -0
  68. package/skills/global_config/dockerfile-generator/references/multistage_builds.md +570 -0
  69. package/skills/global_config/dockerfile-generator/references/optimization_patterns.md +492 -0
  70. package/skills/global_config/dockerfile-generator/references/security_best_practices.md +375 -0
  71. package/skills/global_config/dockerfile-generator/scripts/generate_dockerignore.sh +199 -0
  72. package/skills/global_config/dockerfile-generator/scripts/generate_golang.sh +172 -0
  73. package/skills/global_config/dockerfile-generator/scripts/generate_java.sh +185 -0
  74. package/skills/global_config/dockerfile-generator/scripts/generate_nodejs.sh +279 -0
  75. package/skills/global_config/dockerfile-generator/scripts/generate_python.sh +218 -0
  76. package/skills/global_config/dockerfile-generator/scripts/test_generator.sh +210 -0
  77. package/skills/global_config/dockerfile-validator/SKILL.md +300 -0
  78. package/skills/global_config/dockerfile-validator/examples/.dockerignore.example +34 -0
  79. package/skills/global_config/dockerfile-validator/examples/bad-example.Dockerfile +37 -0
  80. package/skills/global_config/dockerfile-validator/examples/golang-distroless.Dockerfile +50 -0
  81. package/skills/global_config/dockerfile-validator/examples/good-example.Dockerfile +52 -0
  82. package/skills/global_config/dockerfile-validator/examples/python-optimized.Dockerfile +53 -0
  83. package/skills/global_config/dockerfile-validator/examples/security-issues.Dockerfile +42 -0
  84. package/skills/global_config/dockerfile-validator/references/docker_best_practices.md +348 -0
  85. package/skills/global_config/dockerfile-validator/references/optimization_guide.md +473 -0
  86. package/skills/global_config/dockerfile-validator/references/security_checklist.md +208 -0
  87. package/skills/global_config/dockerfile-validator/scripts/dockerfile-validate.sh +699 -0
  88. package/skills/global_config/dockerfile-validator/scripts/test_validate.sh +35 -0
  89. package/skills/global_config/dockerfile-validator/tests/fixtures/copy-before-yarn-lock-read.Dockerfile +6 -0
  90. package/skills/global_config/dockerfile-validator/tests/fixtures/copy-before-yarn.Dockerfile +6 -0
  91. package/skills/global_config/dockerfile-validator/tests/fixtures/from-platform-nonroot.Dockerfile +7 -0
  92. package/skills/global_config/dockerfile-validator/tests/test_regression.sh +164 -0
  93. package/skills/global_config/finishing-a-development-branch/SKILL.md +228 -0
  94. package/skills/global_config/github-actions-generator/SKILL.md +353 -0
  95. package/skills/global_config/github-actions-generator/assets/templates/action/composite/action.yml +82 -0
  96. package/skills/global_config/github-actions-generator/assets/templates/action/docker/Dockerfile +25 -0
  97. package/skills/global_config/github-actions-generator/assets/templates/action/docker/action.yml +42 -0
  98. package/skills/global_config/github-actions-generator/assets/templates/action/docker/entrypoint.sh +27 -0
  99. package/skills/global_config/github-actions-generator/assets/templates/action/javascript/action.yml +33 -0
  100. package/skills/global_config/github-actions-generator/assets/templates/action/javascript/index.js +50 -0
  101. package/skills/global_config/github-actions-generator/assets/templates/action/javascript/package.json +27 -0
  102. package/skills/global_config/github-actions-generator/assets/templates/workflow/basic_workflow.yml +242 -0
  103. package/skills/global_config/github-actions-generator/assets/templates/workflow/reusable_workflow.yml +106 -0
  104. package/skills/global_config/github-actions-generator/examples/README.md +147 -0
  105. package/skills/global_config/github-actions-generator/examples/actions/setup-node-cached/action.yml +93 -0
  106. package/skills/global_config/github-actions-generator/examples/caching/docker-buildkit.yml +256 -0
  107. package/skills/global_config/github-actions-generator/examples/security/dependency-review.yml +62 -0
  108. package/skills/global_config/github-actions-generator/examples/security/sbom-attestation.yml +119 -0
  109. package/skills/global_config/github-actions-generator/examples/triggers/chatops-commands.yml +475 -0
  110. package/skills/global_config/github-actions-generator/examples/triggers/repository-dispatch.yml +418 -0
  111. package/skills/global_config/github-actions-generator/examples/triggers/workflow-orchestration.yml +404 -0
  112. package/skills/global_config/github-actions-generator/examples/workflows/docker-build-push.yml +68 -0
  113. package/skills/global_config/github-actions-generator/examples/workflows/go-ci.yml +161 -0
  114. package/skills/global_config/github-actions-generator/examples/workflows/monorepo-ci.yml +340 -0
  115. package/skills/global_config/github-actions-generator/examples/workflows/multi-environment-deploy.yml +406 -0
  116. package/skills/global_config/github-actions-generator/examples/workflows/nodejs-ci.yml +122 -0
  117. package/skills/global_config/github-actions-generator/examples/workflows/python-ci.yml +157 -0
  118. package/skills/global_config/github-actions-generator/examples/workflows/scheduled-tasks.yml +376 -0
  119. package/skills/global_config/github-actions-generator/references/advanced-triggers.md +917 -0
  120. package/skills/global_config/github-actions-generator/references/best-practices.md +755 -0
  121. package/skills/global_config/github-actions-generator/references/common-actions.md +715 -0
  122. package/skills/global_config/github-actions-generator/references/custom-actions.md +320 -0
  123. package/skills/global_config/github-actions-generator/references/expressions-and-contexts.md +688 -0
  124. package/skills/global_config/github-actions-generator/references/modern-features.md +421 -0
  125. package/skills/global_config/github-actions-generator/scripts/test_generator.sh +344 -0
  126. package/skills/global_config/github-actions-templates/SKILL.md +7 -0
  127. package/skills/global_config/github-actions-validator/SKILL.md +576 -0
  128. package/skills/global_config/github-actions-validator/examples/README.md +88 -0
  129. package/skills/global_config/github-actions-validator/examples/outdated-versions.yml +76 -0
  130. package/skills/global_config/github-actions-validator/examples/valid-ci.yml +79 -0
  131. package/skills/global_config/github-actions-validator/examples/with-errors.yml +47 -0
  132. package/skills/global_config/github-actions-validator/references/act_usage.md +233 -0
  133. package/skills/global_config/github-actions-validator/references/action_versions.md +122 -0
  134. package/skills/global_config/github-actions-validator/references/actionlint_usage.md +343 -0
  135. package/skills/global_config/github-actions-validator/references/common_errors.md +512 -0
  136. package/skills/global_config/github-actions-validator/references/modern_features.md +384 -0
  137. package/skills/global_config/github-actions-validator/references/runners.md +317 -0
  138. package/skills/global_config/github-actions-validator/scripts/install_tools.sh +113 -0
  139. package/skills/global_config/github-actions-validator/scripts/validate_workflow.sh +910 -0
  140. package/skills/global_config/github-actions-validator/tests/test_validate_workflow.sh +237 -0
  141. package/skills/global_config/makefile-generator/SKILL.md +614 -0
  142. package/skills/global_config/makefile-generator/assets/templates/.gitkeep +1 -0
  143. package/skills/global_config/makefile-generator/docs/makefile-structure.md +530 -0
  144. package/skills/global_config/makefile-generator/docs/optimization-guide.md +784 -0
  145. package/skills/global_config/makefile-generator/docs/patterns-guide.md +642 -0
  146. package/skills/global_config/makefile-generator/docs/security-guide.md +361 -0
  147. package/skills/global_config/makefile-generator/docs/targets-guide.md +642 -0
  148. package/skills/global_config/makefile-generator/docs/variables-guide.md +596 -0
  149. package/skills/global_config/makefile-generator/scripts/add_standard_targets.sh +539 -0
  150. package/skills/global_config/makefile-generator/scripts/generate_makefile_template.sh +690 -0
  151. package/skills/global_config/makefile-generator/test/test_helper_scripts.sh +190 -0
  152. package/skills/global_config/makefile-validator/SKILL.md +244 -0
  153. package/skills/global_config/makefile-validator/docs/bake-tool.md +1000 -0
  154. package/skills/global_config/makefile-validator/docs/best-practices.md +858 -0
  155. package/skills/global_config/makefile-validator/docs/common-mistakes.md +944 -0
  156. package/skills/global_config/makefile-validator/examples/bad-makefile.mk +77 -0
  157. package/skills/global_config/makefile-validator/examples/good-makefile.mk +103 -0
  158. package/skills/global_config/makefile-validator/scripts/test_validate.sh +382 -0
  159. package/skills/global_config/makefile-validator/scripts/validate_makefile.sh +712 -0
  160. package/skills/global_config/{MCP_Manage → mcp-manage}/SKILL.md +3 -3
  161. package/skills/global_config/requesting-code-review/SKILL.md +98 -0
  162. package/skills/global_config/requesting-code-review/code-reviewer.md +198 -0
  163. package/skills/global_config/using-git-worktrees/SKILL.md +170 -0
  164. package/skills/global_config/verification-before-completion/SKILL.md +123 -0
  165. package/skills/global_config/writing-plans/SKILL.md +126 -46
  166. package/skills/global_config/writing-plans-legacy/SKILL.md +139 -0
@@ -0,0 +1,218 @@
1
+ #!/usr/bin/env bash
2
+ # Generate a production-ready Python Dockerfile with multi-stage build
3
+
4
+ set -euo pipefail
5
+
6
+ # Default values
7
+ PYTHON_VERSION="${PYTHON_VERSION:-3.12}"
8
+ PORT="${PORT:-8000}"
9
+ OUTPUT_FILE="${OUTPUT_FILE:-Dockerfile}"
10
+ LEGACY_ENTRY="${APP_ENTRY:-app.py}"
11
+ LEGACY_ENTRY_SET="false"
12
+ ENTRY_CMD="${ENTRY_CMD:-}"
13
+ ENTRY_ARGS=()
14
+
15
+ # Usage
16
+ usage() {
17
+ cat <<EOF
18
+ Usage: $0 [OPTIONS]
19
+
20
+ Generate a production-ready Python Dockerfile with multi-stage build.
21
+
22
+ OPTIONS:
23
+ -v, --version VERSION Python version (default: 3.12)
24
+ -p, --port PORT Port to expose (default: 8000)
25
+ -o, --output FILE Output file (default: Dockerfile)
26
+ -e, --entry COMMAND Legacy entry syntax (simple whitespace split only)
27
+ --entry-cmd COMMAND Preferred command binary/executable
28
+ --entry-arg ARG Preferred command argument (repeatable; preserves spaces)
29
+ -h, --help Show this help message
30
+
31
+ EXAMPLES:
32
+ # Basic Python app
33
+ $0
34
+
35
+ # FastAPI app
36
+ $0 --version 3.12 --port 8000
37
+
38
+ # Django app
39
+ $0 --port 8080 --entry "python manage.py runserver 0.0.0.0:8080"
40
+
41
+ # Preferred structured entrypoint (preserves quoted args exactly)
42
+ $0 --entry-cmd python --entry-arg -m --entry-arg uvicorn --entry-arg main:app --entry-arg --log-config --entry-arg "configs/logging prod.yaml"
43
+
44
+ EOF
45
+ exit 0
46
+ }
47
+
48
+ # Parse arguments
49
+ while [[ $# -gt 0 ]]; do
50
+ case $1 in
51
+ -v|--version)
52
+ PYTHON_VERSION="$2"
53
+ shift 2
54
+ ;;
55
+ -p|--port)
56
+ PORT="$2"
57
+ shift 2
58
+ ;;
59
+ -o|--output)
60
+ OUTPUT_FILE="$2"
61
+ shift 2
62
+ ;;
63
+ -e|--entry)
64
+ LEGACY_ENTRY="$2"
65
+ LEGACY_ENTRY_SET="true"
66
+ shift 2
67
+ ;;
68
+ --entry-cmd)
69
+ ENTRY_CMD="$2"
70
+ shift 2
71
+ ;;
72
+ --entry-arg)
73
+ ENTRY_ARGS+=("$2")
74
+ shift 2
75
+ ;;
76
+ -h|--help)
77
+ usage
78
+ ;;
79
+ *)
80
+ echo "Unknown option: $1"
81
+ usage
82
+ ;;
83
+ esac
84
+ done
85
+
86
+ # Escape values that are inserted into JSON-form CMD arrays.
87
+ escape_json_string() {
88
+ local input="$1"
89
+ input="${input//\\/\\\\}"
90
+ input="${input//\"/\\\"}"
91
+ printf '%s' "$input"
92
+ }
93
+
94
+ # Escape values that are inserted into sed replacement strings.
95
+ escape_sed_replacement() {
96
+ local input="$1"
97
+ input="${input//\\/\\\\}"
98
+ input="${input//&/\\&}"
99
+ input="${input//|/\\|}"
100
+ printf '%s' "$input"
101
+ }
102
+
103
+ # Validate mutually exclusive entrypoint interfaces.
104
+ if [[ -n "$ENTRY_CMD" && "$LEGACY_ENTRY_SET" == "true" ]]; then
105
+ echo "ERROR: use either --entry or --entry-cmd/--entry-arg, not both." >&2
106
+ exit 1
107
+ fi
108
+
109
+ if [[ -z "$ENTRY_CMD" && ${#ENTRY_ARGS[@]} -gt 0 ]]; then
110
+ echo "ERROR: --entry-arg requires --entry-cmd." >&2
111
+ exit 1
112
+ fi
113
+
114
+ # Build CMD instruction.
115
+ # Preferred mode:
116
+ # --entry-cmd <cmd> --entry-arg <arg> --entry-arg <arg>
117
+ # Legacy mode:
118
+ # --entry "<simple whitespace-delimited command>"
119
+ # Quoted legacy entries are rejected because they cannot be parsed safely.
120
+ if [[ -n "$ENTRY_CMD" ]]; then
121
+ CMD_PARTS=("$ENTRY_CMD" "${ENTRY_ARGS[@]}")
122
+ else
123
+ if [[ "$LEGACY_ENTRY" == *"\""* || "$LEGACY_ENTRY" == *"'"* ]]; then
124
+ echo "ERROR: quoted --entry values are not supported. Use --entry-cmd/--entry-arg." >&2
125
+ exit 1
126
+ fi
127
+
128
+ if [[ "$LEGACY_ENTRY" =~ [[:space:]] ]]; then
129
+ read -r -a CMD_PARTS <<< "$LEGACY_ENTRY"
130
+ else
131
+ CMD_PARTS=("python" "$LEGACY_ENTRY")
132
+ fi
133
+ fi
134
+
135
+ if [[ -z "${CMD_PARTS[0]:-}" ]]; then
136
+ echo "ERROR: entry command cannot be empty." >&2
137
+ exit 1
138
+ fi
139
+
140
+ _json_parts=()
141
+ for _token in "${CMD_PARTS[@]}"; do
142
+ _json_parts+=("\"$(escape_json_string "$_token")\"")
143
+ done
144
+ CMD_INSTRUCTION="CMD [$(IFS=', '; echo "${_json_parts[*]}")]"
145
+ CMD_INSTRUCTION_SED="$(escape_sed_replacement "$CMD_INSTRUCTION")"
146
+
147
+ # Generate Dockerfile
148
+ cat > "$OUTPUT_FILE" <<'EOF'
149
+ # syntax=docker/dockerfile:1
150
+
151
+ # Build stage
152
+ FROM python:PYTHON_VERSION-slim AS builder
153
+ WORKDIR /app
154
+
155
+ # Install build dependencies
156
+ # hadolint ignore=DL3008
157
+ RUN apt-get update && apt-get install -y --no-install-recommends \
158
+ gcc \
159
+ && rm -rf /var/lib/apt/lists/*
160
+
161
+ # Copy dependency files
162
+ COPY requirements.txt .
163
+
164
+ # Install Python dependencies
165
+ RUN pip install --no-cache-dir --user -r requirements.txt
166
+
167
+ # Production stage
168
+ FROM python:PYTHON_VERSION-slim AS production
169
+ WORKDIR /app
170
+
171
+ # Create non-root user
172
+ RUN useradd -m -u 1001 app
173
+
174
+ # Copy dependencies from builder
175
+ COPY --from=builder /root/.local /home/app/.local
176
+
177
+ # Copy application code
178
+ COPY --chown=app:app . .
179
+
180
+ # Update PATH and set Python production env vars
181
+ ENV PATH=/home/app/.local/bin:$PATH \
182
+ PYTHONUNBUFFERED=1 \
183
+ PYTHONDONTWRITEBYTECODE=1
184
+
185
+ # Switch to non-root user
186
+ USER app
187
+
188
+ # Expose port
189
+ EXPOSE PORT_NUMBER
190
+
191
+ # Health check
192
+ HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
193
+ CMD python -c "import urllib.request; urllib.request.urlopen('http://localhost:PORT_NUMBER/health').read()" || exit 1
194
+
195
+ # Start application
196
+ CMD_INSTRUCTION_PLACEHOLDER
197
+ EOF
198
+
199
+ # Replace placeholders
200
+ sed -i.bak "s/PYTHON_VERSION/$PYTHON_VERSION/g" "$OUTPUT_FILE"
201
+ sed -i.bak "s/PORT_NUMBER/$PORT/g" "$OUTPUT_FILE"
202
+ sed -i.bak "s|CMD_INSTRUCTION_PLACEHOLDER|$CMD_INSTRUCTION_SED|g" "$OUTPUT_FILE"
203
+
204
+ # Clean up backup files
205
+ rm -f "${OUTPUT_FILE}.bak"
206
+
207
+ echo "✓ Generated Python Dockerfile: $OUTPUT_FILE"
208
+ echo " Python version: $PYTHON_VERSION"
209
+ echo " Port: $PORT"
210
+ if [[ -n "$ENTRY_CMD" ]]; then
211
+ ENTRY_DISPLAY="$ENTRY_CMD"
212
+ for _arg in "${ENTRY_ARGS[@]}"; do
213
+ ENTRY_DISPLAY+=" $(printf '%q' "$_arg")"
214
+ done
215
+ else
216
+ ENTRY_DISPLAY="$LEGACY_ENTRY"
217
+ fi
218
+ echo " Entry point: $ENTRY_DISPLAY"
@@ -0,0 +1,210 @@
1
+ #!/usr/bin/env bash
2
+ #
3
+ # Regression tests for dockerfile-generator scripts and examples.
4
+ #
5
+ # Covers:
6
+ # 1. Node/Python structured entrypoint args (--entry-cmd/--entry-arg)
7
+ # 2. Legacy --entry behavior and quote rejection
8
+ # 3. Node multistage example dependency/build flow consistency
9
+ #
10
+ # Exit 0 when all assertions pass; non-zero otherwise.
11
+ #
12
+
13
+ set -euo pipefail
14
+
15
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
16
+ readonly SCRIPT_DIR
17
+ readonly SKILL_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
18
+ readonly NODE_GENERATOR="$SCRIPT_DIR/generate_nodejs.sh"
19
+ readonly PYTHON_GENERATOR="$SCRIPT_DIR/generate_python.sh"
20
+ readonly NODE_EXAMPLE="$SKILL_DIR/examples/nodejs-multistage.Dockerfile"
21
+
22
+ PASS=0
23
+ FAIL=0
24
+ OUTPUT=""
25
+ EXIT_CODE=0
26
+
27
+ pass() { echo " PASS: $1"; PASS=$((PASS + 1)); }
28
+ fail() { echo " FAIL: $1"; FAIL=$((FAIL + 1)); }
29
+
30
+ run_capture() {
31
+ EXIT_CODE=0
32
+ OUTPUT=$("$@" 2>&1) || EXIT_CODE=$?
33
+ }
34
+
35
+ assert_exit() {
36
+ local label="$1"
37
+ local expected="$2"
38
+ if [[ "$EXIT_CODE" -eq "$expected" ]]; then
39
+ pass "$label (exit $EXIT_CODE)"
40
+ else
41
+ fail "$label — expected exit $expected, got $EXIT_CODE"
42
+ echo "$OUTPUT" | sed 's/^/ /'
43
+ fi
44
+ }
45
+
46
+ assert_output_contains() {
47
+ local label="$1"
48
+ local pattern="$2"
49
+ if echo "$OUTPUT" | grep -qE -- "$pattern"; then
50
+ pass "$label"
51
+ else
52
+ fail "$label — pattern not found: $pattern"
53
+ echo "$OUTPUT" | sed 's/^/ /'
54
+ fi
55
+ }
56
+
57
+ assert_file_contains() {
58
+ local label="$1"
59
+ local file="$2"
60
+ local pattern="$3"
61
+ if grep -qE -- "$pattern" "$file"; then
62
+ pass "$label"
63
+ else
64
+ fail "$label — pattern '$pattern' not found in $file"
65
+ sed 's/^/ /' "$file"
66
+ fi
67
+ }
68
+
69
+ assert_file_not_contains() {
70
+ local label="$1"
71
+ local file="$2"
72
+ local pattern="$3"
73
+ if grep -qE -- "$pattern" "$file"; then
74
+ fail "$label — unexpected pattern '$pattern' found in $file"
75
+ grep -nE -- "$pattern" "$file" | sed 's/^/ /'
76
+ else
77
+ pass "$label"
78
+ fi
79
+ }
80
+
81
+ TMP_DIR="$(mktemp -d)"
82
+ trap 'rm -rf "$TMP_DIR"' EXIT
83
+
84
+ echo "Running dockerfile-generator regression tests..."
85
+
86
+ echo ""
87
+ echo "[shell syntax checks]"
88
+ if bash -n "$NODE_GENERATOR"; then
89
+ pass "node generator passes bash -n"
90
+ else
91
+ fail "node generator has syntax errors"
92
+ fi
93
+
94
+ if bash -n "$PYTHON_GENERATOR"; then
95
+ pass "python generator passes bash -n"
96
+ else
97
+ fail "python generator has syntax errors"
98
+ fi
99
+
100
+ echo ""
101
+ echo "[node generator]"
102
+ NODE_STRUCTURED_OUT="$TMP_DIR/node-structured.Dockerfile"
103
+ run_capture \
104
+ bash "$NODE_GENERATOR" \
105
+ --output "$NODE_STRUCTURED_OUT" \
106
+ --entry-cmd node \
107
+ --entry-arg server.js \
108
+ --entry-arg --message \
109
+ --entry-arg "hello world"
110
+ assert_exit "structured node entry generation succeeds" 0
111
+ assert_file_contains \
112
+ "structured node entry preserves spaced arg" \
113
+ "$NODE_STRUCTURED_OUT" \
114
+ 'CMD \["node","server\.js","--message","hello world"\]'
115
+
116
+ NODE_LEGACY_OUT="$TMP_DIR/node-legacy.Dockerfile"
117
+ run_capture \
118
+ bash "$NODE_GENERATOR" \
119
+ --output "$NODE_LEGACY_OUT" \
120
+ --entry "npm start"
121
+ assert_exit "legacy node entry generation succeeds" 0
122
+ assert_file_contains \
123
+ "legacy node entry still tokenizes simple commands" \
124
+ "$NODE_LEGACY_OUT" \
125
+ 'CMD \["npm","start"\]'
126
+
127
+ run_capture \
128
+ bash "$NODE_GENERATOR" \
129
+ --output "$TMP_DIR/node-legacy-quoted.Dockerfile" \
130
+ --entry "node server.js --message \"hello world\""
131
+ assert_exit "legacy quoted node entry is rejected" 1
132
+ assert_output_contains \
133
+ "legacy quoted node rejection message is clear" \
134
+ 'ERROR: quoted --entry values are not supported\. Use --entry-cmd/--entry-arg\.'
135
+
136
+ run_capture \
137
+ bash "$NODE_GENERATOR" \
138
+ --output "$TMP_DIR/node-invalid-args.Dockerfile" \
139
+ --entry-arg server.js
140
+ assert_exit "--entry-arg without --entry-cmd fails for node" 1
141
+ assert_output_contains \
142
+ "node --entry-arg validation message is clear" \
143
+ 'ERROR: --entry-arg requires --entry-cmd\.'
144
+
145
+ echo ""
146
+ echo "[python generator]"
147
+ PY_STRUCTURED_OUT="$TMP_DIR/python-structured.Dockerfile"
148
+ run_capture \
149
+ bash "$PYTHON_GENERATOR" \
150
+ --output "$PY_STRUCTURED_OUT" \
151
+ --entry-cmd python \
152
+ --entry-arg -m \
153
+ --entry-arg uvicorn \
154
+ --entry-arg main:app \
155
+ --entry-arg --log-config \
156
+ --entry-arg "configs/logging prod.yaml"
157
+ assert_exit "structured python entry generation succeeds" 0
158
+ assert_file_contains \
159
+ "structured python entry preserves spaced arg" \
160
+ "$PY_STRUCTURED_OUT" \
161
+ 'CMD \["python","-m","uvicorn","main:app","--log-config","configs/logging prod\.yaml"\]'
162
+
163
+ PY_LEGACY_OUT="$TMP_DIR/python-legacy.Dockerfile"
164
+ run_capture \
165
+ bash "$PYTHON_GENERATOR" \
166
+ --output "$PY_LEGACY_OUT" \
167
+ --entry "python app.py"
168
+ assert_exit "legacy python entry generation succeeds" 0
169
+ assert_file_contains \
170
+ "legacy python entry still tokenizes simple commands" \
171
+ "$PY_LEGACY_OUT" \
172
+ 'CMD \["python","app\.py"\]'
173
+
174
+ run_capture \
175
+ bash "$PYTHON_GENERATOR" \
176
+ --output "$TMP_DIR/python-legacy-quoted.Dockerfile" \
177
+ --entry "python app.py --message \"hello world\""
178
+ assert_exit "legacy quoted python entry is rejected" 1
179
+ assert_output_contains \
180
+ "legacy quoted python rejection message is clear" \
181
+ 'ERROR: quoted --entry values are not supported\. Use --entry-cmd/--entry-arg\.'
182
+
183
+ echo ""
184
+ echo "[node example]"
185
+ assert_file_contains \
186
+ "node example installs full deps before build" \
187
+ "$NODE_EXAMPLE" \
188
+ 'RUN npm ci &&'
189
+ assert_file_contains \
190
+ "node example prunes dev dependencies after build" \
191
+ "$NODE_EXAMPLE" \
192
+ 'npm prune --omit=dev'
193
+ assert_file_not_contains \
194
+ "node example avoids mixed only=production build flow" \
195
+ "$NODE_EXAMPLE" \
196
+ 'npm ci --only=production'
197
+ assert_file_contains \
198
+ "node example runs compiled output" \
199
+ "$NODE_EXAMPLE" \
200
+ 'CMD \["node", "dist/index\.js"\]'
201
+
202
+ echo ""
203
+ echo "Passed: $PASS"
204
+ echo "Failed: $FAIL"
205
+
206
+ if [[ "$FAIL" -gt 0 ]]; then
207
+ exit 1
208
+ fi
209
+
210
+ echo "All dockerfile-generator regression tests passed."