plain-forge 1.0.1
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.
- package/LICENSE +21 -0
- package/README.md +247 -0
- package/bin/cli.mjs +143 -0
- package/forge/docs/.gitkeep +0 -0
- package/forge/rules/definitions.md +57 -0
- package/forge/rules/exported-concepts.md +39 -0
- package/forge/rules/func-specs.md +72 -0
- package/forge/rules/impl-reqs.md +50 -0
- package/forge/rules/import-modules.md +51 -0
- package/forge/rules/required-concepts.md +45 -0
- package/forge/rules/requires-modules.md +59 -0
- package/forge/rules/test-reqs.md +47 -0
- package/forge/skills/add-acceptance-test/SKILL.md +98 -0
- package/forge/skills/add-concept/SKILL.md +67 -0
- package/forge/skills/add-feature/SKILL.md +136 -0
- package/forge/skills/add-functional-spec/SKILL.md +81 -0
- package/forge/skills/add-functional-specs/SKILL.md +115 -0
- package/forge/skills/add-implementation-requirement/SKILL.md +73 -0
- package/forge/skills/add-resource/SKILL.md +108 -0
- package/forge/skills/add-template/SKILL.md +65 -0
- package/forge/skills/add-test-requirement/SKILL.md +68 -0
- package/forge/skills/analyze-2-func-specs/SKILL.md +102 -0
- package/forge/skills/analyze-func-specs/SKILL.md +124 -0
- package/forge/skills/analyze-if-func-spec-too-complex/SKILL.md +152 -0
- package/forge/skills/break-down-func-spec/SKILL.md +156 -0
- package/forge/skills/check-plain-env/SKILL.md +288 -0
- package/forge/skills/consolidate-concepts/SKILL.md +193 -0
- package/forge/skills/create-import-module/SKILL.md +98 -0
- package/forge/skills/create-requires-module/SKILL.md +104 -0
- package/forge/skills/debug-specs/SKILL.md +189 -0
- package/forge/skills/forge-integration/SKILL.md +443 -0
- package/forge/skills/forge-plain/SKILL.md +333 -0
- package/forge/skills/implement-conformance-testing-script/SKILL.md +247 -0
- package/forge/skills/implement-conformance-testing-script/assets/run_conformance_tests_cypress.ps1 +324 -0
- package/forge/skills/implement-conformance-testing-script/assets/run_conformance_tests_golang.ps1 +100 -0
- package/forge/skills/implement-conformance-testing-script/assets/run_conformance_tests_java.sh +102 -0
- package/forge/skills/implement-conformance-testing-script/assets/run_conformance_tests_python.ps1 +92 -0
- package/forge/skills/implement-conformance-testing-script/assets/run_conformance_tests_python.sh +100 -0
- package/forge/skills/implement-prepare-environment-script/SKILL.md +242 -0
- package/forge/skills/implement-prepare-environment-script/assets/prepare_environment_java.sh +42 -0
- package/forge/skills/implement-prepare-environment-script/assets/prepare_environment_python.sh +81 -0
- package/forge/skills/implement-unit-testing-script/SKILL.md +133 -0
- package/forge/skills/implement-unit-testing-script/assets/run_unittests_flutter.ps1 +82 -0
- package/forge/skills/implement-unit-testing-script/assets/run_unittests_golang.ps1 +68 -0
- package/forge/skills/implement-unit-testing-script/assets/run_unittests_java.sh +45 -0
- package/forge/skills/implement-unit-testing-script/assets/run_unittests_python.ps1 +76 -0
- package/forge/skills/implement-unit-testing-script/assets/run_unittests_python.sh +90 -0
- package/forge/skills/implement-unit-testing-script/assets/run_unittests_react.ps1 +83 -0
- package/forge/skills/init-config-file/SKILL.md +261 -0
- package/forge/skills/init-plain-project/SKILL.md +124 -0
- package/forge/skills/load-plain-reference/SKILL.md +646 -0
- package/forge/skills/plain-healthcheck/SKILL.md +132 -0
- package/forge/skills/refactor-module/SKILL.md +197 -0
- package/forge/skills/resolve-spec-conflict/SKILL.md +88 -0
- package/forge/skills/run-codeplain/SKILL.md +540 -0
- package/package.json +42 -0
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
#!/usr/bin/env pwsh
|
|
2
|
+
|
|
3
|
+
$ErrorActionPreference = 'Stop'
|
|
4
|
+
|
|
5
|
+
$UNRECOVERABLE_ERROR_EXIT_CODE = 69
|
|
6
|
+
|
|
7
|
+
# Check if subfolder name is provided
|
|
8
|
+
if (-not $args[0]) {
|
|
9
|
+
Write-Host "Error: No subfolder name provided."
|
|
10
|
+
Write-Host "Usage: $($MyInvocation.MyCommand.Name) <subfolder_name>"
|
|
11
|
+
exit $UNRECOVERABLE_ERROR_EXIT_CODE
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
$BuildFolder = $args[0]
|
|
15
|
+
|
|
16
|
+
$GO_BUILD_SUBFOLDER = "go_$BuildFolder"
|
|
17
|
+
|
|
18
|
+
if ($env:VERBOSE -eq "1") {
|
|
19
|
+
Write-Host "Preparing Go build subfolder: $GO_BUILD_SUBFOLDER"
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
# Check if the go build subfolder exists
|
|
23
|
+
if (Test-Path $GO_BUILD_SUBFOLDER) {
|
|
24
|
+
# Delete all files and folders inside
|
|
25
|
+
Get-ChildItem -Path $GO_BUILD_SUBFOLDER -Force | Remove-Item -Recurse -Force
|
|
26
|
+
|
|
27
|
+
if ($env:VERBOSE -eq "1") {
|
|
28
|
+
Write-Host "Cleanup completed."
|
|
29
|
+
}
|
|
30
|
+
} else {
|
|
31
|
+
if ($env:VERBOSE -eq "1") {
|
|
32
|
+
Write-Host "Subfolder does not exist. Creating it..."
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
New-Item -ItemType Directory -Path $GO_BUILD_SUBFOLDER -Force | Out-Null
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
Copy-Item -Path "$BuildFolder/*" -Destination $GO_BUILD_SUBFOLDER -Recurse -Force
|
|
39
|
+
|
|
40
|
+
# Move to the subfolder
|
|
41
|
+
if (-not (Test-Path $GO_BUILD_SUBFOLDER)) {
|
|
42
|
+
Write-Host "Error: Go build folder '$GO_BUILD_SUBFOLDER' does not exist."
|
|
43
|
+
exit $UNRECOVERABLE_ERROR_EXIT_CODE
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
Push-Location $GO_BUILD_SUBFOLDER
|
|
47
|
+
|
|
48
|
+
try {
|
|
49
|
+
Write-Host "Running go get..."
|
|
50
|
+
# Temporarily allow stderr output without throwing (Go tools write to stderr)
|
|
51
|
+
# ForEach-Object converts ErrorRecord objects (from stderr) to plain strings to avoid verbose error formatting
|
|
52
|
+
$ErrorActionPreference = 'Continue'
|
|
53
|
+
$output = go get 2>&1 | ForEach-Object { if ($_ -is [System.Management.Automation.ErrorRecord]) { $_.Exception.Message } else { $_ } } | Out-String
|
|
54
|
+
$ErrorActionPreference = 'Stop'
|
|
55
|
+
if ($output.Trim()) { Write-Host $output }
|
|
56
|
+
|
|
57
|
+
# Execute all Golang unittests in the subfolder
|
|
58
|
+
Write-Host "Running Golang unittests in $BuildFolder..."
|
|
59
|
+
$ErrorActionPreference = 'Continue'
|
|
60
|
+
$output = go test 2>&1 | ForEach-Object { if ($_ -is [System.Management.Automation.ErrorRecord]) { $_.Exception.Message } else { $_ } } | Out-String
|
|
61
|
+
$exit_code = $LASTEXITCODE
|
|
62
|
+
$ErrorActionPreference = 'Stop'
|
|
63
|
+
|
|
64
|
+
Write-Host $output
|
|
65
|
+
exit $exit_code
|
|
66
|
+
} finally {
|
|
67
|
+
Pop-Location
|
|
68
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
# Check that Java 21 is installed
|
|
4
|
+
if ! /usr/libexec/java_home -v 21 >/dev/null 2>&1; then
|
|
5
|
+
echo "Error: Java 21 is not installed."
|
|
6
|
+
exit 69
|
|
7
|
+
fi
|
|
8
|
+
|
|
9
|
+
export JAVA_HOME=$(/usr/libexec/java_home -v 21)
|
|
10
|
+
java --version
|
|
11
|
+
|
|
12
|
+
# Check if subfolder name is provided
|
|
13
|
+
if [ -z "$1" ]; then
|
|
14
|
+
echo "Error: No subfolder name provided."
|
|
15
|
+
echo "Usage: $0 <subfolder_name>"
|
|
16
|
+
exit 1
|
|
17
|
+
fi
|
|
18
|
+
|
|
19
|
+
# Define the path to the java build subfolder
|
|
20
|
+
WORKING_FOLDER=.tmp/$1
|
|
21
|
+
|
|
22
|
+
# Check if the java subfolder exists
|
|
23
|
+
if [ -d "$WORKING_FOLDER" ]; then
|
|
24
|
+
# delete everything in the subfolder
|
|
25
|
+
rm -rf "$WORKING_FOLDER"/*
|
|
26
|
+
else
|
|
27
|
+
echo "Subfolder '$WORKING_FOLDER' does not exist. Creating it now..."
|
|
28
|
+
mkdir -p "$WORKING_FOLDER"
|
|
29
|
+
fi
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
# copy all folders and files from the build folder to the subfolder
|
|
33
|
+
cp -R $1/* $WORKING_FOLDER
|
|
34
|
+
printf "Copied from $1 to $WORKING_FOLDER...\n"
|
|
35
|
+
# Move to the subfolder
|
|
36
|
+
cd "$WORKING_FOLDER" 2>/dev/null
|
|
37
|
+
printf "Moved to $WORKING_FOLDER...\n"
|
|
38
|
+
if [ $? -ne 0 ]; then
|
|
39
|
+
echo "Error: Subfolder '$1' does not exist."
|
|
40
|
+
exit 2
|
|
41
|
+
fi
|
|
42
|
+
|
|
43
|
+
# Execute all Java unittests in the subfolder
|
|
44
|
+
echo "Running Java unittests in $(pwd)..."
|
|
45
|
+
mvn test
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
#!/usr/bin/env pwsh
|
|
2
|
+
|
|
3
|
+
$ErrorActionPreference = 'Stop'
|
|
4
|
+
|
|
5
|
+
$UNRECOVERABLE_ERROR_EXIT_CODE = 69
|
|
6
|
+
|
|
7
|
+
# Check if subfolder name is provided
|
|
8
|
+
if (-not $args[0]) {
|
|
9
|
+
Write-Host "Error: No subfolder name provided."
|
|
10
|
+
Write-Host "Usage: $($MyInvocation.MyCommand.Name) <subfolder_name>"
|
|
11
|
+
exit $UNRECOVERABLE_ERROR_EXIT_CODE
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
$BuildFolder = $args[0]
|
|
15
|
+
|
|
16
|
+
# Try to find Python interpreter (python3 first, then python)
|
|
17
|
+
if (Get-Command python3 -ErrorAction SilentlyContinue) {
|
|
18
|
+
$PYTHON_CMD = "python3"
|
|
19
|
+
} elseif (Get-Command python -ErrorAction SilentlyContinue) {
|
|
20
|
+
$PYTHON_CMD = "python"
|
|
21
|
+
} else {
|
|
22
|
+
Write-Host "Error: Python interpreter not found. Please install Python."
|
|
23
|
+
exit $UNRECOVERABLE_ERROR_EXIT_CODE
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
$PYTHON_BUILD_SUBFOLDER = "python_$BuildFolder"
|
|
27
|
+
|
|
28
|
+
if ($env:VERBOSE -eq "1") {
|
|
29
|
+
Write-Host "Preparing Python build subfolder: $PYTHON_BUILD_SUBFOLDER"
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
# Check if the Python build subfolder exists
|
|
33
|
+
if (Test-Path $PYTHON_BUILD_SUBFOLDER) {
|
|
34
|
+
# Delete all files and folders inside
|
|
35
|
+
Get-ChildItem -Path $PYTHON_BUILD_SUBFOLDER -Force | Remove-Item -Recurse -Force
|
|
36
|
+
|
|
37
|
+
if ($env:VERBOSE -eq "1") {
|
|
38
|
+
Write-Host "Cleanup completed."
|
|
39
|
+
}
|
|
40
|
+
} else {
|
|
41
|
+
if ($env:VERBOSE -eq "1") {
|
|
42
|
+
Write-Host "Subfolder does not exist. Creating it..."
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
New-Item -ItemType Directory -Path $PYTHON_BUILD_SUBFOLDER -Force | Out-Null
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
Copy-Item -Path "$BuildFolder/*" -Destination $PYTHON_BUILD_SUBFOLDER -Recurse -Force
|
|
49
|
+
|
|
50
|
+
# Move to the subfolder
|
|
51
|
+
if (-not (Test-Path $PYTHON_BUILD_SUBFOLDER)) {
|
|
52
|
+
Write-Host "Error: Python build folder '$PYTHON_BUILD_SUBFOLDER' does not exist."
|
|
53
|
+
exit $UNRECOVERABLE_ERROR_EXIT_CODE
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
Push-Location $PYTHON_BUILD_SUBFOLDER
|
|
57
|
+
|
|
58
|
+
try {
|
|
59
|
+
# Execute all Python unittests in the subfolder
|
|
60
|
+
Write-Host "Running Python unittests in $PYTHON_BUILD_SUBFOLDER..."
|
|
61
|
+
|
|
62
|
+
# Temporarily allow stderr output without throwing (Python unittest writes progress to stderr)
|
|
63
|
+
# ForEach-Object converts ErrorRecord objects (from stderr) to plain strings to avoid verbose error formatting
|
|
64
|
+
$ErrorActionPreference = 'Continue'
|
|
65
|
+
$output = & $PYTHON_CMD -m unittest discover -b 2>&1 | ForEach-Object { if ($_ -is [System.Management.Automation.ErrorRecord]) { $_.Exception.Message } else { $_ } } | Out-String
|
|
66
|
+
$exit_code = $LASTEXITCODE
|
|
67
|
+
$ErrorActionPreference = 'Stop'
|
|
68
|
+
|
|
69
|
+
# Echo the original output
|
|
70
|
+
Write-Host $output
|
|
71
|
+
|
|
72
|
+
# Return the exit code of the unittest command
|
|
73
|
+
exit $exit_code
|
|
74
|
+
} finally {
|
|
75
|
+
Pop-Location
|
|
76
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
UNRECOVERABLE_ERROR_EXIT_CODE=69
|
|
4
|
+
|
|
5
|
+
# Check if subfolder name is provided
|
|
6
|
+
if [ -z "$1" ]; then
|
|
7
|
+
echo "Error: No subfolder name provided."
|
|
8
|
+
echo "Usage: $0 <subfolder_name>"
|
|
9
|
+
exit $UNRECOVERABLE_ERROR_EXIT_CODE
|
|
10
|
+
fi
|
|
11
|
+
|
|
12
|
+
current_dir=$(pwd)
|
|
13
|
+
echo "Current directory: $current_dir"
|
|
14
|
+
echo "Build folder name: $1"
|
|
15
|
+
echo "--------------------------------"
|
|
16
|
+
|
|
17
|
+
PYTHON_BUILD_SUBFOLDER=.tmp/$1
|
|
18
|
+
|
|
19
|
+
if [ "${VERBOSE:-}" -eq 1 ] 2>/dev/null; then
|
|
20
|
+
printf "Preparing Python build subfolder: $PYTHON_BUILD_SUBFOLDER\n"
|
|
21
|
+
fi
|
|
22
|
+
|
|
23
|
+
rm -rf $PYTHON_BUILD_SUBFOLDER
|
|
24
|
+
mkdir -p $PYTHON_BUILD_SUBFOLDER
|
|
25
|
+
|
|
26
|
+
cp -R $1/* $PYTHON_BUILD_SUBFOLDER
|
|
27
|
+
|
|
28
|
+
# Move to the subfolder
|
|
29
|
+
cd "$PYTHON_BUILD_SUBFOLDER" 2>/dev/null
|
|
30
|
+
|
|
31
|
+
if [ $? -ne 0 ]; then
|
|
32
|
+
printf "Error: Python build folder '$PYTHON_BUILD_SUBFOLDER' does not exist.\n"
|
|
33
|
+
exit $UNRECOVERABLE_ERROR_EXIT_CODE
|
|
34
|
+
fi
|
|
35
|
+
|
|
36
|
+
printf "Creating and activating virtual environment...\n"
|
|
37
|
+
|
|
38
|
+
# Time the virtual environment creation and activation
|
|
39
|
+
start_time=$(date +%s.%N)
|
|
40
|
+
|
|
41
|
+
VENV_DIR=".venv"
|
|
42
|
+
|
|
43
|
+
if ! $PYTHON_CMD -m venv "$VENV_DIR"; then
|
|
44
|
+
printf "Error: Failed to create virtual environment in '$VENV_DIR'.\n"
|
|
45
|
+
exit $UNRECOVERABLE_ERROR_EXIT_CODE
|
|
46
|
+
fi
|
|
47
|
+
|
|
48
|
+
# shellcheck disable=SC1091
|
|
49
|
+
source "$VENV_DIR/bin/activate"
|
|
50
|
+
|
|
51
|
+
if [ $? -ne 0 ]; then
|
|
52
|
+
printf "Error: Failed to activate virtual environment at '$VENV_DIR/bin/activate'.\n"
|
|
53
|
+
exit $UNRECOVERABLE_ERROR_EXIT_CODE
|
|
54
|
+
fi
|
|
55
|
+
|
|
56
|
+
# Install requirements if requirements.txt exists
|
|
57
|
+
if [ -f "requirements.txt" ]; then
|
|
58
|
+
pip install --upgrade pip
|
|
59
|
+
pip install -r requirements.txt
|
|
60
|
+
else
|
|
61
|
+
echo "Error: requirements.txt not found. Cannot proceed with setting up requirements."
|
|
62
|
+
fi
|
|
63
|
+
|
|
64
|
+
end_time=$(date +%s.%N)
|
|
65
|
+
|
|
66
|
+
# Calculate and display the time taken
|
|
67
|
+
duration=$(echo "$end_time - $start_time" | bc)
|
|
68
|
+
printf "Requirements setup completed in %.2f seconds\n\n" "$duration"
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
# Execute all Python unittests in the subfolder
|
|
72
|
+
echo "Running Python unittests in $PYTHON_BUILD_SUBFOLDER..."
|
|
73
|
+
|
|
74
|
+
output=$(timeout 120s python -m unittest discover -b -v 2>&1)
|
|
75
|
+
exit_code=$?
|
|
76
|
+
|
|
77
|
+
# Check if the command timed out
|
|
78
|
+
if [ $exit_code -eq 124 ]; then
|
|
79
|
+
printf "\nError: Unittests timed out after 120 seconds.\n"
|
|
80
|
+
exit $exit_code
|
|
81
|
+
fi
|
|
82
|
+
|
|
83
|
+
# Echo the original output
|
|
84
|
+
echo "$output"
|
|
85
|
+
|
|
86
|
+
# Return the exit code of the unittest command
|
|
87
|
+
exit $exit_code
|
|
88
|
+
|
|
89
|
+
# Note: The 'discover' option automatically identifies and runs all unittests in the current directory and subdirectories
|
|
90
|
+
# Ensure that your Python files are named according to the unittest discovery pattern (test*.py by default)
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
#!/usr/bin/env pwsh
|
|
2
|
+
|
|
3
|
+
$ErrorActionPreference = 'Stop'
|
|
4
|
+
|
|
5
|
+
$UNRECOVERABLE_ERROR_EXIT_CODE = 69
|
|
6
|
+
|
|
7
|
+
# ANSI escape code pattern to remove color codes and formatting from output
|
|
8
|
+
$ANSI_ESCAPE_PATTERN = '\x1b\[[0-9;]*[mK]'
|
|
9
|
+
|
|
10
|
+
# Check if subfolder name is provided
|
|
11
|
+
if (-not $args[0]) {
|
|
12
|
+
Write-Host "Error: No subfolder name provided."
|
|
13
|
+
Write-Host "Usage: $($MyInvocation.MyCommand.Name) <subfolder_name>"
|
|
14
|
+
exit $UNRECOVERABLE_ERROR_EXIT_CODE
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
$BuildFolder = $args[0]
|
|
18
|
+
|
|
19
|
+
# Define the path to the subfolder
|
|
20
|
+
$NODE_SUBFOLDER = "node_$BuildFolder"
|
|
21
|
+
|
|
22
|
+
if ($env:VERBOSE -eq "1") {
|
|
23
|
+
Write-Host "Preparing Node subfolder: $NODE_SUBFOLDER"
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
# Check if the node subfolder exists
|
|
27
|
+
if (Test-Path $NODE_SUBFOLDER) {
|
|
28
|
+
# Delete all files and folders except "node_modules", "build", and "package-lock.json"
|
|
29
|
+
Get-ChildItem -Path $NODE_SUBFOLDER -Force |
|
|
30
|
+
Where-Object {
|
|
31
|
+
$_.Name -ne "node_modules" -and
|
|
32
|
+
$_.Name -ne "build" -and
|
|
33
|
+
$_.Name -ne "package-lock.json"
|
|
34
|
+
} | Remove-Item -Recurse -Force
|
|
35
|
+
|
|
36
|
+
if ($env:VERBOSE -eq "1") {
|
|
37
|
+
Write-Host "Cleanup completed, keeping 'node_modules' and 'package-lock.json'."
|
|
38
|
+
}
|
|
39
|
+
} else {
|
|
40
|
+
if ($env:VERBOSE -eq "1") {
|
|
41
|
+
Write-Host "Subfolder does not exist. Creating it..."
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
New-Item -ItemType Directory -Path $NODE_SUBFOLDER -Force | Out-Null
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
Copy-Item -Path "$BuildFolder/*" -Destination $NODE_SUBFOLDER -Recurse -Force
|
|
48
|
+
|
|
49
|
+
# Move to the subfolder
|
|
50
|
+
if (-not (Test-Path $NODE_SUBFOLDER)) {
|
|
51
|
+
Write-Host "Error: Subfolder '$BuildFolder' does not exist."
|
|
52
|
+
exit $UNRECOVERABLE_ERROR_EXIT_CODE
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
Push-Location $NODE_SUBFOLDER
|
|
56
|
+
|
|
57
|
+
try {
|
|
58
|
+
# Install libraries
|
|
59
|
+
npm install
|
|
60
|
+
|
|
61
|
+
# Execute all React unittests in the subfolder
|
|
62
|
+
Write-Host "Running React unittests in $BuildFolder..."
|
|
63
|
+
# Temporarily allow stderr output without throwing (npm/jest may write to stderr)
|
|
64
|
+
# ForEach-Object converts ErrorRecord objects (from stderr) to plain strings to avoid verbose error formatting
|
|
65
|
+
$ErrorActionPreference = 'Continue'
|
|
66
|
+
$output = npm test -- --runInBand --silent --detectOpenHandles 2>&1 | ForEach-Object { if ($_ -is [System.Management.Automation.ErrorRecord]) { $_.Exception.Message } else { $_ } } | Out-String
|
|
67
|
+
$TEST_EXIT_CODE = $LASTEXITCODE
|
|
68
|
+
$ErrorActionPreference = 'Stop'
|
|
69
|
+
|
|
70
|
+
# Strip ANSI escape codes
|
|
71
|
+
$output = $output -replace $ANSI_ESCAPE_PATTERN, ''
|
|
72
|
+
Write-Host $output
|
|
73
|
+
|
|
74
|
+
# Check if tests failed
|
|
75
|
+
if ($TEST_EXIT_CODE -ne 0) {
|
|
76
|
+
Write-Host "Error: Tests failed with exit code $TEST_EXIT_CODE"
|
|
77
|
+
exit $TEST_EXIT_CODE
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
exit $TEST_EXIT_CODE
|
|
81
|
+
} finally {
|
|
82
|
+
Pop-Location
|
|
83
|
+
}
|
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: init-config-file
|
|
3
|
+
description: >-
|
|
4
|
+
Build / finalize the `config.yaml` file(s) that the `codeplain` renderer
|
|
5
|
+
consumes. Pulls together every decision made during Phase 3 of `forge-plain`
|
|
6
|
+
(script paths, template directory, build folders, copy/dest behavior, log
|
|
7
|
+
settings) and emits one canonical `config.yaml` per part of the project.
|
|
8
|
+
Run this at the **end of `forge-plain`** (just before `plain-healthcheck`),
|
|
9
|
+
at the end of `add-feature` whenever the testing surface or template
|
|
10
|
+
directory changed, and any time the user wants to regenerate / consolidate
|
|
11
|
+
a project's `config.yaml`.
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
# Init Config File
|
|
15
|
+
|
|
16
|
+
This skill is the **single authoritative writer** of `config.yaml` for a ***plain project. Anything that ends up in `config.yaml` should go through this skill. The renderer (`codeplain`) reads each key listed below into the same argparse namespace it uses for CLI flags — so a value set in `config.yaml` is exactly equivalent to passing the corresponding `--flag` on the command line.
|
|
17
|
+
|
|
18
|
+
## When to run
|
|
19
|
+
|
|
20
|
+
- **End of `forge-plain` Phase 3 / start of Phase 4** — after every test-script decision is locked in (unit tests, conformance tests, prepare-environment), before delegating to `plain-healthcheck`.
|
|
21
|
+
- **End of `add-feature`** — only when Phase 3 of the feature touched the testing surface (new script generated, script removed, template directory introduced).
|
|
22
|
+
- **End of any single-skill workflow that finalizes a script or template** — e.g. after `implement-unit-testing-script`, `implement-conformance-testing-script`, `implement-prepare-environment-script`, `add-template`, or `create-import-module`.
|
|
23
|
+
- **On demand** — when the user asks "rebuild my config", "what valid keys are there", or you discover the config file is hand-edited / inconsistent.
|
|
24
|
+
|
|
25
|
+
If you only fixed a typo inside a `.plain` file and the testing surface didn't move, you do **not** need to re-run this skill — go straight to `plain-healthcheck`.
|
|
26
|
+
|
|
27
|
+
## What this skill does
|
|
28
|
+
|
|
29
|
+
1. Determines **how many** `config.yaml` files the project needs (one per part — see [Per-part split](#per-part-split)).
|
|
30
|
+
2. For each config, gathers the decided values from the current project state (existing scripts under `test_scripts/`, the template directory, the build/dest folder choices).
|
|
31
|
+
3. Emits a clean, alphabetically-grouped `config.yaml` containing **only** keys that are actually in use, using the canonical key names from the [Valid keys reference](#valid-keys-reference).
|
|
32
|
+
4. Verifies that every `*-script` value points at a file that exists on disk under `test_scripts/` (or wherever the user placed it), using the same lookup rule the renderer uses: absolute path → path relative to the config file's directory → path relative to the renderer's directory.
|
|
33
|
+
5. Hands off to `plain-healthcheck` for the full validation pass.
|
|
34
|
+
|
|
35
|
+
## What this skill does NOT do
|
|
36
|
+
|
|
37
|
+
- It does **not** generate testing scripts. Use `implement-unit-testing-script`, `implement-conformance-testing-script`, or `implement-prepare-environment-script` first; this skill only wires them in.
|
|
38
|
+
- It does **not** decide *whether* the user wants conformance tests, a prepare-environment script, copy-build, etc. Those decisions belong to `forge-plain` Phase 3. This skill only **records** them.
|
|
39
|
+
- It does **not** invent values for keys whose decisions weren't made — it leaves them out (the renderer falls back to its default) rather than guessing.
|
|
40
|
+
- It does **not** write secrets. `api-key` belongs in the `CODEPLAIN_API_KEY` environment variable, never in `config.yaml`.
|
|
41
|
+
|
|
42
|
+
## Valid keys reference
|
|
43
|
+
|
|
44
|
+
The canonical list of keys is derived from the `codeplain` CLI argparse parser. Every key below corresponds to exactly one `--flag` and is read by the renderer through `update_args_with_config`. **No other keys are valid** — the renderer rejects unknown keys with `parser.error(f"Invalid argument: {key}")`.
|
|
45
|
+
|
|
46
|
+
YAML keys use the **dashed** form (e.g. `unittests-script`, not `unittests_script`) to mirror the CLI flag spelling. The only exception that has historically appeared with underscores is `template_dir`; prefer `template-dir` for new configs but accept either when reading an existing file.
|
|
47
|
+
|
|
48
|
+
### Keys you typically include
|
|
49
|
+
|
|
50
|
+
These keys reflect choices made in Phase 3 of `forge-plain` and are the bread and butter of a project's `config.yaml`:
|
|
51
|
+
|
|
52
|
+
| Key | Type | Default | When to include |
|
|
53
|
+
|---|---|---|---|
|
|
54
|
+
| `unittests-script` | path (string) | — | **Required.** Every project gets a unit-test runner. Path resolves relative to the config file's directory (preferred) or the renderer directory. |
|
|
55
|
+
| `conformance-tests-script` | path (string) | — | Include when the user opted into conformance testing in Phase 3. |
|
|
56
|
+
| `prepare-environment-script` | path (string) | — | Include only when both (a) the user opted into a prepare-environment script and (b) `conformance-tests-script` is also set. Setting prepare without conformance is a hard `plain-healthcheck` failure. |
|
|
57
|
+
| `test-script-timeout` | int (seconds) | `120` | Include only when the user explicitly raised/lowered the default. |
|
|
58
|
+
| `template-dir` | path (string) | — | Include whenever the project has an `import` module or a custom template directory (e.g. `template/`). Required for projects with shared templates. |
|
|
59
|
+
| `logging-config-path` | path (string) | `logging_config.yaml` | Points at a **separate** YAML file consumed by Python's `logging.config.dictConfig`. This is the only knob that lets the user actually change log **levels** for the renderer and its dependencies. See [Logging configuration](#logging-configuration) below. Include the key explicitly whenever the project ships a non-default logging config; leave it out only when the user is happy with the renderer's defaults (`INFO` root, `WARNING` for `git`, `ERROR` for `transitions`). |
|
|
60
|
+
| `conformance-tests-folder` | string | `conformance_tests` | Include only when the user picked a non-default folder name. |
|
|
61
|
+
| `build-folder` | string | `plain_modules` | Include only when the user picked a non-default folder name. Must differ from `build-dest`. |
|
|
62
|
+
| `build-dest` | string | `dist` | **Always include with the value `dist`.** This skill pins the copy destination explicitly so every project's `config.yaml` has the same, predictable target folder for the post-render copy. Even though `dist` matches the renderer's default, we still write it out so the choice is visible in the file and protected against future default changes. Must differ from `build-folder`. |
|
|
63
|
+
| `base-folder` | string | — | Include when the user wants build output rooted somewhere other than the project root. |
|
|
64
|
+
|
|
65
|
+
### Keys you occasionally include
|
|
66
|
+
|
|
67
|
+
These are useful but the defaults are almost always fine. Only include them when the user explicitly changed the default during Phase 3:
|
|
68
|
+
|
|
69
|
+
| Key | Type | Default | Notes |
|
|
70
|
+
|---|---|---|---|
|
|
71
|
+
| `copy-build` | bool | `true` | The renderer copies the rendered code to `build-dest` after a successful render. Set to `false` only when the user doesn't want this. |
|
|
72
|
+
| `copy-conformance-tests` | bool | `false` | Requires `conformance-tests-script` to also be set. |
|
|
73
|
+
| `conformance-tests-dest` | string | `dist_conformance_tests` | Target folder for the conformance-test copy. Must differ from `conformance-tests-folder`. |
|
|
74
|
+
| `log-to-file` | bool | `true` | Disable only when the user explicitly does not want a log file. Controls whether logs are mirrored to disk — it does **not** set the log level (that's `logging-config-path`'s job). |
|
|
75
|
+
| `log-file-name` | string | `codeplain.log` | If `log-to-file` is `false`, this key must be left out. Resolved relative to the `.plain` file directory. |
|
|
76
|
+
| `render-machine-graph` | bool | `false` | Include only when the user wants the state-machine graph rendered. |
|
|
77
|
+
| `headless` | bool | `false` | Include only when the project is meant to run in CI / non-interactive mode by default. |
|
|
78
|
+
| `force-render` | bool | `false` | Almost never belongs in `config.yaml`; prefer the CLI flag for one-off forced renders. |
|
|
79
|
+
| `verbose` | bool | `false` | Almost never belongs in `config.yaml`; prefer the CLI flag for one-off verbose runs. |
|
|
80
|
+
| `api` | URL (string) | `https://api.codeplain.ai` | Include only when the user is pointing at a non-default API endpoint. |
|
|
81
|
+
|
|
82
|
+
### Keys you must NEVER include
|
|
83
|
+
|
|
84
|
+
These flags are **per-invocation** or **secret**. Putting them in `config.yaml` is always wrong:
|
|
85
|
+
|
|
86
|
+
| Key | Why it doesn't belong |
|
|
87
|
+
|---|---|
|
|
88
|
+
| `api-key` | Secret. Belongs in the `CODEPLAIN_API_KEY` environment variable. Never in a file the user might commit. |
|
|
89
|
+
| `dry-run` | Per-invocation. `plain-healthcheck` runs the dry-run explicitly; pinning it in the config would make a real render impossible. |
|
|
90
|
+
| `full-plain` | Per-invocation preview. Mutually exclusive with `dry-run`. |
|
|
91
|
+
| `render-range` | Per-invocation. Selects a slice of functionalities to (re)render. |
|
|
92
|
+
| `render-from` | Per-invocation. Mutually exclusive with `render-range`. |
|
|
93
|
+
| `replay-with` | Internal / debugging flag. |
|
|
94
|
+
| `config-name` | Refers to the config file itself — the renderer ignores it when reading the config. |
|
|
95
|
+
| `filename` | The `.plain` file to render is always passed positionally on the CLI. |
|
|
96
|
+
|
|
97
|
+
If the user asks to put any of these in `config.yaml`, refuse and explain why.
|
|
98
|
+
|
|
99
|
+
## Logging configuration
|
|
100
|
+
|
|
101
|
+
Log **levels** are not controlled directly by `config.yaml` — they live in a separate YAML file that the renderer feeds to Python's `logging.config.dictConfig`. The `config.yaml` key `logging-config-path` is the pointer that wires the two together.
|
|
102
|
+
|
|
103
|
+
### How the renderer assembles logging
|
|
104
|
+
|
|
105
|
+
From `setup_logging` in the `codeplain` source:
|
|
106
|
+
|
|
107
|
+
1. The renderer first installs a set of **baseline levels**:
|
|
108
|
+
- root logger → `INFO`
|
|
109
|
+
- `LOGGER_NAME` (the renderer's own logger) → `INFO`
|
|
110
|
+
- `git` → `WARNING`
|
|
111
|
+
- `transitions` → `ERROR`
|
|
112
|
+
- `transitions.extensions.diagrams` → `ERROR`
|
|
113
|
+
2. **If** `args.logging_config_path` resolves to an existing file on disk, the renderer loads that YAML and calls `logging.config.dictConfig(...)` on it. This overlays anything from step 1 — the user can raise, lower, or add levels for any logger they care about, add handlers, change formatters, etc.
|
|
114
|
+
3. The renderer then attaches its own handlers (TUI handler unless `headless`, file handler if `log-to-file`, crash buffer otherwise). Whatever **level** the root logger ended up at after step 2 is the level those handlers respect.
|
|
115
|
+
|
|
116
|
+
In other words: `logging-config-path` is the **only** knob that changes the levels. `log-to-file` and `log-file-name` only control *whether and where* logs are written — not *what* gets written.
|
|
117
|
+
|
|
118
|
+
### Default behavior
|
|
119
|
+
|
|
120
|
+
- The CLI default value for `logging-config-path` is `logging_config.yaml`. If a file by that exact name exists in the current working directory, it will be loaded automatically — even without `logging-config-path` being set in `config.yaml`.
|
|
121
|
+
- If the file does not exist, the renderer silently keeps the baseline levels from step 1 above (no warning).
|
|
122
|
+
- If the file exists but fails to parse / apply, the renderer warns (`Failed to load logging configuration from …`) and falls back to the baseline.
|
|
123
|
+
|
|
124
|
+
This means **the mere presence of a `logging_config.yaml` file is itself a config decision.** When you assemble a project's `config.yaml`, you have three cases:
|
|
125
|
+
|
|
126
|
+
| Situation | What to do |
|
|
127
|
+
|---|---|
|
|
128
|
+
| The user is happy with the baseline levels and the project has no `logging_config.yaml` on disk. | Leave `logging-config-path` out of `config.yaml`. |
|
|
129
|
+
| The user wants custom levels and is fine with the file being named `logging_config.yaml` next to the `.plain` file. | Create that file (see [Recommended logging config](#recommended-logging-config) below). Leaving `logging-config-path` out of `config.yaml` is fine — the default points at it already — but explicitly setting `logging-config-path: logging_config.yaml` is also acceptable and makes the dependency visible to anyone reading the config. |
|
|
130
|
+
| The user wants the logging config file to live somewhere non-default (different filename or directory). | Create the file at the chosen path and set `logging-config-path: <that path>` in `config.yaml`. |
|
|
131
|
+
|
|
132
|
+
When in doubt, ask the user: "Do you want to change the default log levels (INFO for the renderer, WARNING for git, ERROR for transitions), or stick with the defaults?" Only generate / pin the file when they say yes.
|
|
133
|
+
|
|
134
|
+
### Recommended logging config
|
|
135
|
+
|
|
136
|
+
When the user does want custom levels, write a minimal `dictConfig`-style YAML file. Example with two common knobs (verbose renderer logs, plus suppression of a chatty third-party logger):
|
|
137
|
+
|
|
138
|
+
```/dev/null/logging_config.yaml.example#L1-15
|
|
139
|
+
version: 1
|
|
140
|
+
disable_existing_loggers: false
|
|
141
|
+
formatters:
|
|
142
|
+
default:
|
|
143
|
+
format: "%(levelname)s:%(name)s:%(message)s"
|
|
144
|
+
handlers:
|
|
145
|
+
console:
|
|
146
|
+
class: logging.StreamHandler
|
|
147
|
+
formatter: default
|
|
148
|
+
level: DEBUG
|
|
149
|
+
loggers:
|
|
150
|
+
codeplain:
|
|
151
|
+
level: DEBUG
|
|
152
|
+
urllib3:
|
|
153
|
+
level: WARNING
|
|
154
|
+
root:
|
|
155
|
+
level: INFO
|
|
156
|
+
handlers: [console]
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
Guidelines for what to put in this file:
|
|
160
|
+
|
|
161
|
+
- Always set `version: 1` — `dictConfig` requires it.
|
|
162
|
+
- Set `disable_existing_loggers: false` unless the user explicitly wants to silence loggers that were created before `dictConfig` ran. The renderer creates several before it loads this file, and disabling them by default leads to confusing dead silence.
|
|
163
|
+
- Only override levels the user actually asked about. Don't preemptively add every logger the codebase touches — that creates ongoing maintenance for no benefit.
|
|
164
|
+
- Don't put the `LoggingHandler` / `CrashLogHandler` / `FileHandler` here — the renderer attaches those itself after `dictConfig` runs. Adding them here will cause duplicate log lines.
|
|
165
|
+
- This file is **not** validated by `plain-healthcheck`. If you change it, ask the user to confirm by reading it back to them.
|
|
166
|
+
|
|
167
|
+
## Per-part split
|
|
168
|
+
|
|
169
|
+
The rule, which mirrors what `forge-plain` Phase 3 already establishes, is **one `config.yaml` per part of the system that has its own testing scripts**:
|
|
170
|
+
|
|
171
|
+
- **Single-stack project** (e.g. one Python service) → one `config.yaml` at the project root.
|
|
172
|
+
- **Multi-part project** (e.g. Python backend + React frontend) → one `config.yaml` per part, placed next to the part's top module (e.g. `backend/config.yaml`, `frontend/config.yaml`). Each config references only its own scripts; **never mix stacks in a single config**.
|
|
173
|
+
- A part's split should follow the module boundaries from Phase 1 / Phase 2: if a module has its own language, framework, and test scripts, it gets its own `config.yaml` next to that module.
|
|
174
|
+
|
|
175
|
+
Before emitting anything, state the planned split to the user (e.g. "I'll emit `backend/config.yaml` and `frontend/config.yaml`") if there is more than one part.
|
|
176
|
+
|
|
177
|
+
## Workflow
|
|
178
|
+
|
|
179
|
+
### Step 1 — Inventory
|
|
180
|
+
|
|
181
|
+
1. List every `.plain` file in the repo and identify the top modules (modules not `requires`-ed by anything else) — same procedure as `plain-healthcheck` Step 1.
|
|
182
|
+
2. For each top module, determine which part it belongs to (single-stack → one part; multi-part → one part per top module).
|
|
183
|
+
3. List every script under `test_scripts/` and group them by part (e.g. `*_python.sh` belongs to the backend part, `*_js.sh` belongs to the frontend part).
|
|
184
|
+
4. Identify the template directory (typically `template/`) and any custom resource directories (typically `resources/`).
|
|
185
|
+
5. Read any **existing** `config.yaml` in each part's directory — preserve any user-set fields not listed in [Valid keys reference](#valid-keys-reference) only with the user's explicit approval, and warn that unknown keys will be rejected by the renderer.
|
|
186
|
+
|
|
187
|
+
### Step 2 — Assemble per-part values
|
|
188
|
+
|
|
189
|
+
For each part:
|
|
190
|
+
|
|
191
|
+
1. Start from an empty key set.
|
|
192
|
+
2. Add `unittests-script: test_scripts/run_unittests_<lang>.<sh|ps1>` — required. If the script doesn't exist yet, stop and tell the caller to run `implement-unit-testing-script` first.
|
|
193
|
+
3. If the part has a conformance script on disk → add `conformance-tests-script: …`.
|
|
194
|
+
4. If the part has a prepare-environment script on disk → first verify `conformance-tests-script` is also being added; if not, stop and surface this to the user (offer to either generate the missing conformance script via `implement-conformance-testing-script` or drop the prepare-environment script).
|
|
195
|
+
5. If the project has shared templates → add `template-dir: template` (or whatever path the user used).
|
|
196
|
+
6. **Always add `build-dest: dist`.** This skill pins the copy destination on every config it writes, regardless of what Phase 3 said about it. If Phase 3 explicitly asked for a different `build-dest`, stop and surface the conflict to the user — do not silently honor the override.
|
|
197
|
+
7. For every other key in [Valid keys reference](#valid-keys-reference), include it **only** if Phase 3 produced a non-default decision for that key.
|
|
198
|
+
8. Cross-validate the assembled key set:
|
|
199
|
+
- `build-dest` is set to `dist`.
|
|
200
|
+
- `build-folder` ≠ `build-dest` (in particular, `build-folder` is never `dist`).
|
|
201
|
+
- `conformance-tests-folder` ≠ `conformance-tests-dest`.
|
|
202
|
+
- `copy-conformance-tests: true` requires `conformance-tests-script`.
|
|
203
|
+
- `log-file-name` is set ⇒ `log-to-file` is not `false`.
|
|
204
|
+
- All `*-script` paths resolve on disk (absolute → relative to config dir → relative to renderer dir).
|
|
205
|
+
- No script path crosses stacks (e.g. `backend/config.yaml` must not reference `run_unittests_js.sh`).
|
|
206
|
+
|
|
207
|
+
### Step 3 — Emit `config.yaml`
|
|
208
|
+
|
|
209
|
+
For each part, write a clean YAML file:
|
|
210
|
+
|
|
211
|
+
- One key per line, in the order they appear in [Valid keys reference](#valid-keys-reference) (script paths first, then template/build folders, then copy/log settings).
|
|
212
|
+
- Use dashed key names. Quote string values only when YAML requires it.
|
|
213
|
+
- No comments inside the file — keep it machine-parseable. If the user needs a comment, put it in the surrounding spec or README.
|
|
214
|
+
- Idempotent: re-running this skill on an unchanged project produces a byte-for-byte identical file.
|
|
215
|
+
|
|
216
|
+
Example for a single-stack Python project with conformance testing and a prepare-environment script:
|
|
217
|
+
|
|
218
|
+
```/dev/null/config.yaml.example#L1-5
|
|
219
|
+
unittests-script: test_scripts/run_unittests_python.sh
|
|
220
|
+
conformance-tests-script: test_scripts/run_conformance_tests_python.sh
|
|
221
|
+
prepare-environment-script: test_scripts/prepare_environment_python.sh
|
|
222
|
+
template-dir: template
|
|
223
|
+
build-dest: dist
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
Example for a multi-part project (`backend/config.yaml`):
|
|
227
|
+
|
|
228
|
+
```/dev/null/config.yaml.example#L1-4
|
|
229
|
+
unittests-script: test_scripts/run_unittests_python.sh
|
|
230
|
+
conformance-tests-script: test_scripts/run_conformance_tests_python.sh
|
|
231
|
+
template-dir: ../template
|
|
232
|
+
build-dest: dist
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
### Step 4 — Hand off
|
|
236
|
+
|
|
237
|
+
Tell the caller exactly which file(s) were written and invoke `plain-healthcheck` to validate the project end-to-end. Do **not** declare success on your own — `plain-healthcheck` is the source of truth for "is this project ready to render?".
|
|
238
|
+
|
|
239
|
+
## Anti-patterns
|
|
240
|
+
|
|
241
|
+
- **Inventing values for keys the user never decided on.** Leave them out and let the renderer use its default.
|
|
242
|
+
- **Mixing stacks in one config.** `backend/config.yaml` referencing a JS script is always a bug — split into per-part configs instead.
|
|
243
|
+
- **Putting `api-key`, `dry-run`, `full-plain`, `render-range`, `render-from`, `replay-with`, `config-name`, or `filename` in `config.yaml`.** All of these are per-invocation or secret; the renderer treats them as command-line concerns.
|
|
244
|
+
- **Emitting `prepare-environment-script` without `conformance-tests-script`.** A prepare-environment script only makes sense in service of conformance tests; without one, `plain-healthcheck` will fail.
|
|
245
|
+
- **Hand-merging into an existing config.yaml without re-running this skill.** If the user edited the config manually, re-run the skill to re-derive a clean canonical version (after confirming any custom fields with the user).
|
|
246
|
+
- **Reading the renderer's API key from a project file.** Always rely on `CODEPLAIN_API_KEY`.
|
|
247
|
+
|
|
248
|
+
## Validation Checklist
|
|
249
|
+
|
|
250
|
+
- [ ] One `config.yaml` exists per part of the system (single-stack → root; multi-part → per part).
|
|
251
|
+
- [ ] Every `config.yaml` has at minimum `unittests-script`.
|
|
252
|
+
- [ ] Every `*-script` value points at a file that exists on disk.
|
|
253
|
+
- [ ] No `config.yaml` declares `prepare-environment-script` without also declaring `conformance-tests-script`.
|
|
254
|
+
- [ ] No `config.yaml` mixes stacks (every script in it targets the same language).
|
|
255
|
+
- [ ] `build-dest` is set to `dist` in every emitted `config.yaml`.
|
|
256
|
+
- [ ] `build-folder` ≠ `build-dest`; `conformance-tests-folder` ≠ `conformance-tests-dest`.
|
|
257
|
+
- [ ] `copy-conformance-tests: true` only when `conformance-tests-script` is set.
|
|
258
|
+
- [ ] `log-file-name` only when `log-to-file` is not `false`.
|
|
259
|
+
- [ ] No forbidden keys (`api-key`, `dry-run`, `full-plain`, `render-range`, `render-from`, `replay-with`, `config-name`, `filename`).
|
|
260
|
+
- [ ] `template-dir` set whenever the project has shared templates or import modules.
|
|
261
|
+
- [ ] `plain-healthcheck` returned `PASS` after the config(s) were written.
|