wile 0.4.18 → 0.4.19
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/README.md +1 -1
- package/dist/agent/entrypoint.sh +4 -0
- package/dist/agent/scripts/mock-claude.sh +28 -0
- package/dist/agent/scripts/prompt-preflight.md +56 -0
- package/dist/agent/scripts/prompt.md +7 -2
- package/dist/agent/scripts/test-env-project-docker.sh +52 -0
- package/dist/agent/scripts/test-preflight-docker.sh +134 -0
- package/dist/agent/scripts/wile-preflight.sh +81 -0
- package/dist/agent/scripts/wile.sh +26 -3
- package/dist/cli.js +54 -13
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -19,7 +19,7 @@ bunx wile config
|
|
|
19
19
|
This creates:
|
|
20
20
|
|
|
21
21
|
- `.wile/secrets/.env` for required credentials
|
|
22
|
-
- `.wile
|
|
22
|
+
- `.wile/.env.project` for env vars forwarded into the container (or set `WILE_ENV_PROJECT_PATH`)
|
|
23
23
|
- `.wile/.gitignore` to ignore `secrets/`, `screenshots/`, and `logs/`
|
|
24
24
|
- `.wile/prd.json` (empty) and `.wile/prd.json.example`
|
|
25
25
|
|
package/dist/agent/entrypoint.sh
CHANGED
|
@@ -38,6 +38,10 @@ const prd = JSON.parse(fs.readFileSync(prdPath, 'utf8'));
|
|
|
38
38
|
const stories = Array.isArray(prd.userStories) ? prd.userStories : [];
|
|
39
39
|
const pending = stories.filter((story) => story.passes === false);
|
|
40
40
|
|
|
41
|
+
if (process.env.TEST_FORWARD) {
|
|
42
|
+
console.log(`Forwarded env: ${process.env.TEST_FORWARD}`);
|
|
43
|
+
}
|
|
44
|
+
|
|
41
45
|
if (pending.length === 0) {
|
|
42
46
|
console.log('No pending stories to complete in test mode.');
|
|
43
47
|
process.exit(0);
|
|
@@ -10,6 +10,34 @@ COUNT=$(cat "$COUNT_FILE")
|
|
|
10
10
|
NEXT_COUNT=$((COUNT + 1))
|
|
11
11
|
echo "$NEXT_COUNT" > "$COUNT_FILE"
|
|
12
12
|
|
|
13
|
+
if [ "${WILE_MOCK_MODE:-}" = "preflight_fail" ]; then
|
|
14
|
+
PROGRESS_PATH=".wile/progress.txt"
|
|
15
|
+
if [ -f "$PROGRESS_PATH" ]; then
|
|
16
|
+
:
|
|
17
|
+
else
|
|
18
|
+
printf '%s\n' "# Wile Progress Log" "" "## Codebase Patterns" "" "---" > "$PROGRESS_PATH"
|
|
19
|
+
fi
|
|
20
|
+
|
|
21
|
+
DATE=$(date +%Y-%m-%d)
|
|
22
|
+
cat >> "$PROGRESS_PATH" <<EOF
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## ${DATE} - PREFLIGHT FAILED
|
|
27
|
+
|
|
28
|
+
**Checks run:**
|
|
29
|
+
- Mocked preflight check
|
|
30
|
+
|
|
31
|
+
**Failures:**
|
|
32
|
+
- Mocked preflight failure (WILE_MOCK_MODE=preflight_fail)
|
|
33
|
+
EOF
|
|
34
|
+
|
|
35
|
+
cat <<'JSON'
|
|
36
|
+
{"type":"assistant","message":{"content":[{"type":"text","text":"<promise>PREFLIGHT_FAILED</promise>\n"}]}}
|
|
37
|
+
JSON
|
|
38
|
+
exit 0
|
|
39
|
+
fi
|
|
40
|
+
|
|
13
41
|
if [ "$COUNT" -eq 0 ]; then
|
|
14
42
|
cat <<'JSON'
|
|
15
43
|
{"type":"assistant","message":{"content":[{"type":"text","text":"ANSWER: 2\n"}]}}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# Wile Preflight (Iteration 0)
|
|
2
|
+
|
|
3
|
+
You are running the preflight phase for a Wile autonomous coding session.
|
|
4
|
+
|
|
5
|
+
## Tasks
|
|
6
|
+
|
|
7
|
+
1. Verify `.wile/prd.json` exists and is valid JSON:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
cat .wile/prd.json
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
2. If `.wile/preflight.md` does **not** exist, do nothing else. Do not modify files and do not print extra output.
|
|
14
|
+
|
|
15
|
+
3. If `.wile/preflight.md` exists, read it and follow the checks exactly, in order. Run any commands listed in code blocks. If it describes a check without a command, perform the check and note the result.
|
|
16
|
+
|
|
17
|
+
4. If **any** check fails or cannot be completed:
|
|
18
|
+
- Append a new entry to `.wile/progress.txt` describing what failed and why, using this format:
|
|
19
|
+
|
|
20
|
+
```markdown
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## [DATE] - PREFLIGHT FAILED
|
|
24
|
+
|
|
25
|
+
**Checks run:**
|
|
26
|
+
- ...
|
|
27
|
+
|
|
28
|
+
**Failures:**
|
|
29
|
+
- ...
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
- If GitHub is configured (`WILE_REPO_SOURCE=github` or `GITHUB_REPO_URL` is set), commit and push the progress update:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
git add .wile/progress.txt
|
|
36
|
+
git commit -m "chore: preflight failed"
|
|
37
|
+
git push
|
|
38
|
+
```
|
|
39
|
+
- Respond with exactly:
|
|
40
|
+
|
|
41
|
+
```
|
|
42
|
+
<promise>PREFLIGHT_FAILED</promise>
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
The entire response must be exactly that single line. No other text before or after. No extra lines. No markdown. No backticks. No code blocks.
|
|
46
|
+
|
|
47
|
+
5. If all checks pass, respond with exactly:
|
|
48
|
+
```
|
|
49
|
+
<promise>COMPLETE</promise>
|
|
50
|
+
```
|
|
51
|
+
The entire response must be exactly that single line. No other text before or after. No extra lines. No markdown. No backticks. No code blocks.
|
|
52
|
+
|
|
53
|
+
## Notes
|
|
54
|
+
|
|
55
|
+
- Preflight may have side effects if the checks require them.
|
|
56
|
+
- Do not change any files unless a failure must be recorded in `.wile/progress.txt`.
|
|
@@ -35,8 +35,8 @@ Pick the highest priority story where `passes: false` and implement it completel
|
|
|
35
35
|
Run the project's tests and type checking:
|
|
36
36
|
```bash
|
|
37
37
|
# Try common commands (adapt to the project)
|
|
38
|
-
npm run typecheck || npm run tsc || npx tsc --noEmit
|
|
39
|
-
npm test || npm run test
|
|
38
|
+
npm run typecheck || npm run tsc || npx tsc --noEmit
|
|
39
|
+
npm test || npm run test
|
|
40
40
|
```
|
|
41
41
|
|
|
42
42
|
If tests or typecheck fail, fix the issues before proceeding.
|
|
@@ -58,6 +58,9 @@ Set `passes: true` for the completed story:
|
|
|
58
58
|
**Implemented:**
|
|
59
59
|
- What was done
|
|
60
60
|
|
|
61
|
+
**Verification:**
|
|
62
|
+
- Command(s) run and pass/fail status
|
|
63
|
+
|
|
61
64
|
**Files changed:**
|
|
62
65
|
- file1.ts
|
|
63
66
|
- file2.ts
|
|
@@ -104,6 +107,8 @@ The entire response must be exactly that single line. No other text before or af
|
|
|
104
107
|
9. **Integration tests must validate real system behavior, not just the harness**
|
|
105
108
|
10. **If you discover reusable, module-specific guidance, add it to the nearest AGENTS.md**
|
|
106
109
|
Note: Never update .wile/AGENTS.md.
|
|
110
|
+
11. **Definition of done** - Do not set `passes: true` unless each acceptance criterion has a concrete verification and all verifications passed. If any verification fails or can’t run, leave `passes: false` and explain why in `.wile/progress.txt`.
|
|
111
|
+
12. **No verification section means no pass** - If the progress entry lacks a **Verification** section, do not mark `passes: true`.
|
|
107
112
|
|
|
108
113
|
## Common Patterns
|
|
109
114
|
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
ROOT_DIR=$(cd "$(dirname "$0")/../../.." && pwd)
|
|
5
|
+
AGENT_DIR="$ROOT_DIR/packages/agent"
|
|
6
|
+
|
|
7
|
+
docker build -t wile-agent:local "$AGENT_DIR" >/dev/null
|
|
8
|
+
|
|
9
|
+
TMP_DIR=$(mktemp -d /tmp/wile-env-project-XXXXXX)
|
|
10
|
+
cleanup() {
|
|
11
|
+
rm -rf "$TMP_DIR"
|
|
12
|
+
}
|
|
13
|
+
trap cleanup EXIT INT TERM
|
|
14
|
+
|
|
15
|
+
mkdir -p "$TMP_DIR/.wile/secrets"
|
|
16
|
+
cat > "$TMP_DIR/.wile/prd.json" <<'JSON'
|
|
17
|
+
{
|
|
18
|
+
"userStories": [
|
|
19
|
+
{
|
|
20
|
+
"id": "US-TEST-ENV-001",
|
|
21
|
+
"title": "Env project forward test",
|
|
22
|
+
"acceptanceCriteria": ["n/a"],
|
|
23
|
+
"priority": 1,
|
|
24
|
+
"passes": false
|
|
25
|
+
}
|
|
26
|
+
]
|
|
27
|
+
}
|
|
28
|
+
JSON
|
|
29
|
+
|
|
30
|
+
printf "secrets/\nscreenshots/\nlogs/\n" > "$TMP_DIR/.wile/.gitignore"
|
|
31
|
+
|
|
32
|
+
printf "TEST_FORWARD=ok\n" > "$TMP_DIR/.env.custom"
|
|
33
|
+
|
|
34
|
+
cat > "$TMP_DIR/.wile/secrets/.env" <<'ENV'
|
|
35
|
+
CODING_AGENT=CC
|
|
36
|
+
WILE_ENV_PROJECT_PATH=.env.custom
|
|
37
|
+
ENV
|
|
38
|
+
|
|
39
|
+
export WILE_AGENT_DIR="$AGENT_DIR"
|
|
40
|
+
|
|
41
|
+
cd "$TMP_DIR"
|
|
42
|
+
node "$ROOT_DIR/packages/cli/dist/cli.js" run --test --max-iterations 1 >/dev/null 2>&1
|
|
43
|
+
|
|
44
|
+
LOG_FILE=$(ls "$TMP_DIR/.wile/logs"/run-*.log | head -n 1)
|
|
45
|
+
if [ -z "$LOG_FILE" ]; then
|
|
46
|
+
echo "error: expected run log file" >&2
|
|
47
|
+
exit 1
|
|
48
|
+
fi
|
|
49
|
+
|
|
50
|
+
grep -q "Forwarded env: ok" "$LOG_FILE"
|
|
51
|
+
|
|
52
|
+
echo "test-env-project-docker: ok"
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
ROOT_DIR=$(cd "$(dirname "$0")/../../.." && pwd)
|
|
5
|
+
AGENT_DIR="$ROOT_DIR/packages/agent"
|
|
6
|
+
|
|
7
|
+
docker build -t wile-agent:local "$AGENT_DIR" >/dev/null
|
|
8
|
+
|
|
9
|
+
run_failure_case() {
|
|
10
|
+
TMP_DIR=$(mktemp -d /tmp/wile-preflight-fail-XXXXXX)
|
|
11
|
+
cleanup() {
|
|
12
|
+
rm -rf "$TMP_DIR"
|
|
13
|
+
}
|
|
14
|
+
trap cleanup EXIT INT TERM
|
|
15
|
+
|
|
16
|
+
mkdir -p "$TMP_DIR/.wile"
|
|
17
|
+
cat > "$TMP_DIR/.wile/prd.json" <<'JSON'
|
|
18
|
+
{
|
|
19
|
+
"userStories": [
|
|
20
|
+
{
|
|
21
|
+
"id": "US-TEST-001",
|
|
22
|
+
"title": "Preflight fail test",
|
|
23
|
+
"acceptanceCriteria": ["n/a"],
|
|
24
|
+
"priority": 1,
|
|
25
|
+
"passes": false
|
|
26
|
+
}
|
|
27
|
+
]
|
|
28
|
+
}
|
|
29
|
+
JSON
|
|
30
|
+
|
|
31
|
+
cat > "$TMP_DIR/.wile/progress.txt" <<'TXT'
|
|
32
|
+
# Wile Progress Log
|
|
33
|
+
|
|
34
|
+
## Codebase Patterns
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
TXT
|
|
38
|
+
|
|
39
|
+
cat > "$TMP_DIR/.wile/preflight.md" <<'MD'
|
|
40
|
+
<!--
|
|
41
|
+
Use bullet points for preflight checks, e.g.
|
|
42
|
+
- Confirm SUPABASE_DB_URL is set.
|
|
43
|
+
- Run `supabase db reset --db-url "$SUPABASE_DB_URL"`.
|
|
44
|
+
-->
|
|
45
|
+
MD
|
|
46
|
+
|
|
47
|
+
OUTPUT_FILE="$TMP_DIR/output.txt"
|
|
48
|
+
|
|
49
|
+
set +e
|
|
50
|
+
docker run --rm \
|
|
51
|
+
-e CODING_AGENT=CC \
|
|
52
|
+
-e CC_ANTHROPIC_API_KEY=dummy-key \
|
|
53
|
+
-e WILE_REPO_SOURCE=local \
|
|
54
|
+
-e WILE_LOCAL_REPO_PATH=/home/wile/workspace/repo \
|
|
55
|
+
-e MAX_ITERATIONS=1 \
|
|
56
|
+
-e WILE_MOCK_CLAUDE=true \
|
|
57
|
+
-e WILE_MOCK_MODE=preflight_fail \
|
|
58
|
+
-v "$TMP_DIR:/home/wile/workspace/repo" \
|
|
59
|
+
wile-agent:local > "$OUTPUT_FILE" 2>&1
|
|
60
|
+
EXIT_CODE=$?
|
|
61
|
+
set -e
|
|
62
|
+
|
|
63
|
+
if [ "$EXIT_CODE" -eq 0 ]; then
|
|
64
|
+
echo "error: expected non-zero exit code for preflight failure" >&2
|
|
65
|
+
exit 1
|
|
66
|
+
fi
|
|
67
|
+
|
|
68
|
+
grep -q "PREFLIGHT FAILED - Cannot continue" "$OUTPUT_FILE"
|
|
69
|
+
grep -q "PREFLIGHT FAILED" "$TMP_DIR/.wile/progress.txt"
|
|
70
|
+
|
|
71
|
+
rm -rf "$TMP_DIR"
|
|
72
|
+
trap - EXIT INT TERM
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
run_success_case() {
|
|
76
|
+
TMP_DIR=$(mktemp -d /tmp/wile-preflight-success-XXXXXX)
|
|
77
|
+
cleanup() {
|
|
78
|
+
rm -rf "$TMP_DIR"
|
|
79
|
+
}
|
|
80
|
+
trap cleanup EXIT INT TERM
|
|
81
|
+
|
|
82
|
+
mkdir -p "$TMP_DIR/.wile"
|
|
83
|
+
cat > "$TMP_DIR/.wile/prd.json" <<'JSON'
|
|
84
|
+
{
|
|
85
|
+
"userStories": [
|
|
86
|
+
{
|
|
87
|
+
"id": "US-TEST-002",
|
|
88
|
+
"title": "Preflight success test",
|
|
89
|
+
"acceptanceCriteria": ["n/a"],
|
|
90
|
+
"priority": 1,
|
|
91
|
+
"passes": false
|
|
92
|
+
}
|
|
93
|
+
]
|
|
94
|
+
}
|
|
95
|
+
JSON
|
|
96
|
+
|
|
97
|
+
cat > "$TMP_DIR/.wile/preflight.md" <<'MD'
|
|
98
|
+
<!--
|
|
99
|
+
Use bullet points for preflight checks, e.g.
|
|
100
|
+
- Confirm SUPABASE_DB_URL is set.
|
|
101
|
+
- Run `supabase db reset --db-url "$SUPABASE_DB_URL"`.
|
|
102
|
+
-->
|
|
103
|
+
MD
|
|
104
|
+
|
|
105
|
+
OUTPUT_FILE="$TMP_DIR/output.txt"
|
|
106
|
+
|
|
107
|
+
set +e
|
|
108
|
+
docker run --rm \
|
|
109
|
+
-e CODING_AGENT=CC \
|
|
110
|
+
-e CC_ANTHROPIC_API_KEY=dummy-key \
|
|
111
|
+
-e WILE_REPO_SOURCE=local \
|
|
112
|
+
-e WILE_LOCAL_REPO_PATH=/home/wile/workspace/repo \
|
|
113
|
+
-e MAX_ITERATIONS=1 \
|
|
114
|
+
-e WILE_MOCK_CLAUDE=true \
|
|
115
|
+
-v "$TMP_DIR:/home/wile/workspace/repo" \
|
|
116
|
+
wile-agent:local > "$OUTPUT_FILE" 2>&1
|
|
117
|
+
EXIT_CODE=$?
|
|
118
|
+
set -e
|
|
119
|
+
|
|
120
|
+
if [ "$EXIT_CODE" -ne 0 ]; then
|
|
121
|
+
echo "error: expected zero exit code for preflight success" >&2
|
|
122
|
+
exit 1
|
|
123
|
+
fi
|
|
124
|
+
|
|
125
|
+
grep -q "Preflight complete. Starting main loop..." "$OUTPUT_FILE"
|
|
126
|
+
|
|
127
|
+
rm -rf "$TMP_DIR"
|
|
128
|
+
trap - EXIT INT TERM
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
run_failure_case
|
|
132
|
+
run_success_case
|
|
133
|
+
|
|
134
|
+
echo "test-preflight-docker: ok"
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
#
|
|
3
|
+
# Wile - Preflight check (single run)
|
|
4
|
+
#
|
|
5
|
+
|
|
6
|
+
set -e
|
|
7
|
+
|
|
8
|
+
CODING_AGENT=${CODING_AGENT:-CC}
|
|
9
|
+
CLAUDE_MODEL=${CC_CLAUDE_MODEL:-sonnet}
|
|
10
|
+
OC_MODEL=${OC_MODEL:-glm-4.7}
|
|
11
|
+
if [[ "$OC_MODEL" != */* ]]; then
|
|
12
|
+
OC_MODEL="z-ai/$OC_MODEL"
|
|
13
|
+
fi
|
|
14
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
15
|
+
PREFLIGHT_PROMPT_FILE="$SCRIPT_DIR/prompt-preflight.md"
|
|
16
|
+
TEE_TARGET="${WILE_TEE_TARGET:-/dev/stderr}"
|
|
17
|
+
if ! ( : > "$TEE_TARGET" ) 2>/dev/null; then
|
|
18
|
+
TEE_TARGET="/dev/null"
|
|
19
|
+
fi
|
|
20
|
+
|
|
21
|
+
echo "══════════════════════════════════════════════════════"
|
|
22
|
+
echo " 🌵 WILE - Preflight"
|
|
23
|
+
echo "══════════════════════════════════════════════════════"
|
|
24
|
+
echo " Agent: $CODING_AGENT"
|
|
25
|
+
if [ "$CODING_AGENT" = "OC" ]; then
|
|
26
|
+
echo " Model: $OC_MODEL"
|
|
27
|
+
else
|
|
28
|
+
echo " Model: $CLAUDE_MODEL"
|
|
29
|
+
fi
|
|
30
|
+
echo " Prompt file: $PREFLIGHT_PROMPT_FILE"
|
|
31
|
+
echo "══════════════════════════════════════════════════════"
|
|
32
|
+
echo ""
|
|
33
|
+
|
|
34
|
+
if [ ! -f "$PREFLIGHT_PROMPT_FILE" ]; then
|
|
35
|
+
echo "ERROR: Preflight prompt file not found: $PREFLIGHT_PROMPT_FILE"
|
|
36
|
+
exit 1
|
|
37
|
+
fi
|
|
38
|
+
|
|
39
|
+
run_claude() {
|
|
40
|
+
local prompt_path="$1"
|
|
41
|
+
cat "$prompt_path" \
|
|
42
|
+
| claude --model "$CLAUDE_MODEL" --print --output-format stream-json --verbose --dangerously-skip-permissions \
|
|
43
|
+
| node "$SCRIPT_DIR/claude-stream.js"
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
run_opencode() {
|
|
47
|
+
local prompt_path="$1"
|
|
48
|
+
cat "$prompt_path" \
|
|
49
|
+
| opencode run --format json --model "openrouter/$OC_MODEL" \
|
|
50
|
+
| node "$SCRIPT_DIR/opencode-stream.js"
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
run_agent() {
|
|
54
|
+
local prompt_path="$1"
|
|
55
|
+
if [ "$CODING_AGENT" = "OC" ]; then
|
|
56
|
+
run_opencode "$prompt_path"
|
|
57
|
+
else
|
|
58
|
+
run_claude "$prompt_path"
|
|
59
|
+
fi
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
OUTPUT=$(run_agent "$PREFLIGHT_PROMPT_FILE" | tee "$TEE_TARGET") || true
|
|
63
|
+
CLEAN_OUTPUT=$(printf '%s' "$OUTPUT" | tr -d '\r' | sed -e 's/[[:space:]]*$//')
|
|
64
|
+
if printf '%s\n' "$CLEAN_OUTPUT" | grep -q -E '^[[:space:]]*<promise>PREFLIGHT_FAILED</promise>[[:space:]]*$'; then
|
|
65
|
+
if printf '%s' "$CLEAN_OUTPUT" | grep -F '```' >/dev/null 2>&1; then
|
|
66
|
+
:
|
|
67
|
+
elif printf '%s' "$CLEAN_OUTPUT" | grep -F '`<promise>PREFLIGHT_FAILED</promise>`' >/dev/null 2>&1; then
|
|
68
|
+
:
|
|
69
|
+
else
|
|
70
|
+
echo ""
|
|
71
|
+
echo "══════════════════════════════════════════════════════"
|
|
72
|
+
echo " ❌ PREFLIGHT FAILED"
|
|
73
|
+
echo "══════════════════════════════════════════════════════"
|
|
74
|
+
exit 2
|
|
75
|
+
fi
|
|
76
|
+
fi
|
|
77
|
+
|
|
78
|
+
echo ""
|
|
79
|
+
echo "══════════════════════════════════════════════════════"
|
|
80
|
+
echo " ✅ PREFLIGHT COMPLETE"
|
|
81
|
+
echo "══════════════════════════════════════════════════════"
|
|
@@ -15,6 +15,7 @@ if [[ "$OC_MODEL" != */* ]]; then
|
|
|
15
15
|
fi
|
|
16
16
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
17
17
|
PROMPT_FILE="$SCRIPT_DIR/prompt.md"
|
|
18
|
+
PREFLIGHT_PROMPT_FILE="$SCRIPT_DIR/prompt-preflight.md"
|
|
18
19
|
SETUP_PROMPT_FILE="$SCRIPT_DIR/prompt-setup.md"
|
|
19
20
|
ADDITIONAL_PROMPT_FILE="${WILE_ADDITIONAL_INSTRUCTIONS:-}"
|
|
20
21
|
TEE_TARGET="${WILE_TEE_TARGET:-/dev/stderr}"
|
|
@@ -77,15 +78,37 @@ run_agent() {
|
|
|
77
78
|
}
|
|
78
79
|
|
|
79
80
|
# ════════════════════════════════════════════════════════════
|
|
80
|
-
# ITERATION 0: Setup
|
|
81
|
+
# ITERATION 0: Preflight / Setup
|
|
81
82
|
# ════════════════════════════════════════════════════════════
|
|
82
83
|
echo ""
|
|
83
84
|
echo "══════════════════════════════════════════════════════"
|
|
84
|
-
echo " Iteration 0 -
|
|
85
|
+
echo " Iteration 0 - Preflight"
|
|
85
86
|
echo "══════════════════════════════════════════════════════"
|
|
86
87
|
echo ""
|
|
87
88
|
|
|
88
|
-
if [ -f "$
|
|
89
|
+
if [ -f "$PREFLIGHT_PROMPT_FILE" ]; then
|
|
90
|
+
OUTPUT=$(run_agent "$PREFLIGHT_PROMPT_FILE" | tee "$TEE_TARGET") || true
|
|
91
|
+
|
|
92
|
+
# Check if preflight failed critically (tag must be on its own line; reject backticks/code fences)
|
|
93
|
+
CLEAN_OUTPUT=$(printf '%s' "$OUTPUT" | tr -d '\r' | sed -e 's/[[:space:]]*$//')
|
|
94
|
+
if printf '%s\n' "$CLEAN_OUTPUT" | grep -q -E '^[[:space:]]*<promise>PREFLIGHT_FAILED</promise>[[:space:]]*$'; then
|
|
95
|
+
if printf '%s' "$CLEAN_OUTPUT" | grep -F '```' >/dev/null 2>&1; then
|
|
96
|
+
:
|
|
97
|
+
elif printf '%s' "$CLEAN_OUTPUT" | grep -F '`<promise>PREFLIGHT_FAILED</promise>`' >/dev/null 2>&1; then
|
|
98
|
+
:
|
|
99
|
+
else
|
|
100
|
+
echo ""
|
|
101
|
+
echo "══════════════════════════════════════════════════════"
|
|
102
|
+
echo " ❌ PREFLIGHT FAILED - Cannot continue"
|
|
103
|
+
echo "══════════════════════════════════════════════════════"
|
|
104
|
+
exit 2
|
|
105
|
+
fi
|
|
106
|
+
fi
|
|
107
|
+
|
|
108
|
+
echo ""
|
|
109
|
+
echo "Preflight complete. Starting main loop..."
|
|
110
|
+
sleep 2
|
|
111
|
+
elif [ -f "$SETUP_PROMPT_FILE" ]; then
|
|
89
112
|
OUTPUT=$(run_agent "$SETUP_PROMPT_FILE" | tee "$TEE_TARGET") || true
|
|
90
113
|
|
|
91
114
|
# Check if setup failed critically
|
package/dist/cli.js
CHANGED
|
@@ -7442,7 +7442,7 @@ var {
|
|
|
7442
7442
|
|
|
7443
7443
|
// src/cli.ts
|
|
7444
7444
|
import { readFileSync as readFileSync3 } from "node:fs";
|
|
7445
|
-
import { resolve as
|
|
7445
|
+
import { resolve as resolve3 } from "node:path";
|
|
7446
7446
|
|
|
7447
7447
|
// src/commands/config.ts
|
|
7448
7448
|
var import_prompts = __toESM(require_prompts3(), 1);
|
|
@@ -7555,7 +7555,7 @@ var readEnvFile = async (path) => {
|
|
|
7555
7555
|
return import_dotenv.default.parse(contents);
|
|
7556
7556
|
};
|
|
7557
7557
|
var ensureGitignore = async (path) => {
|
|
7558
|
-
const entries = ["secrets/", "screenshots/", "logs/"];
|
|
7558
|
+
const entries = ["secrets/", "screenshots/", "logs/", ".env.project"];
|
|
7559
7559
|
if (!existsSync(path)) {
|
|
7560
7560
|
await writeFile(path, entries.join(`
|
|
7561
7561
|
`) + `
|
|
@@ -7617,11 +7617,12 @@ var runConfig = async () => {
|
|
|
7617
7617
|
const wileDir = join(cwd, ".wile");
|
|
7618
7618
|
const secretsDir = join(wileDir, "secrets");
|
|
7619
7619
|
const envPath = join(secretsDir, ".env");
|
|
7620
|
-
const envProjectPath = join(
|
|
7620
|
+
const envProjectPath = join(wileDir, ".env.project");
|
|
7621
7621
|
const gitignorePath = join(wileDir, ".gitignore");
|
|
7622
7622
|
const prdPath = join(wileDir, "prd.json");
|
|
7623
7623
|
const prdExamplePath = join(wileDir, "prd.json.example");
|
|
7624
7624
|
const additionalInstructionsPath = join(wileDir, "additional-instructions.md");
|
|
7625
|
+
const preflightPath = join(wileDir, "preflight.md");
|
|
7625
7626
|
const agentsPath = join(wileDir, "AGENTS.md");
|
|
7626
7627
|
await mkdir(secretsDir, { recursive: true });
|
|
7627
7628
|
const existingEnv = await readEnvFile(envPath);
|
|
@@ -7720,6 +7721,12 @@ var runConfig = async () => {
|
|
|
7720
7721
|
message: "GitHub repo URL",
|
|
7721
7722
|
initial: existingEnv.GITHUB_REPO_URL ?? ""
|
|
7722
7723
|
}) : { repoUrl: undefined };
|
|
7724
|
+
const envProjectPathResponse = await prompt({
|
|
7725
|
+
type: "text",
|
|
7726
|
+
name: "envProjectPath",
|
|
7727
|
+
message: "Project env file path to forward into the container",
|
|
7728
|
+
initial: existingEnv.WILE_ENV_PROJECT_PATH ?? ".wile/.env.project"
|
|
7729
|
+
});
|
|
7723
7730
|
const branchResponse = await prompt({
|
|
7724
7731
|
type: "text",
|
|
7725
7732
|
name: "branchName",
|
|
@@ -7740,10 +7747,12 @@ var runConfig = async () => {
|
|
|
7740
7747
|
const ocModel = codingAgent === "OC" ? coalesceValue(ocModelResponse.ocModel, existingEnv.OC_MODEL ?? "glm-4.7") : undefined;
|
|
7741
7748
|
const githubToken = repoSource === "github" ? coalesceValue(githubTokenResponse.githubToken, existingEnv.GITHUB_TOKEN) : existingEnv.GITHUB_TOKEN;
|
|
7742
7749
|
const repoUrl = repoSource === "github" ? coalesceValue(repoResponse.repoUrl, existingEnv.GITHUB_REPO_URL) : existingEnv.GITHUB_REPO_URL;
|
|
7750
|
+
const envProjectPathValue = coalesceValue(envProjectPathResponse.envProjectPath, existingEnv.WILE_ENV_PROJECT_PATH ?? ".wile/.env.project") ?? ".wile/.env.project";
|
|
7743
7751
|
const branchName = coalesceValue(branchResponse.branchName, existingEnv.BRANCH_NAME ?? "main");
|
|
7744
7752
|
const envLines = [
|
|
7745
7753
|
`CODING_AGENT=${codingAgent}`,
|
|
7746
7754
|
`WILE_REPO_SOURCE=${repoSource}`,
|
|
7755
|
+
`WILE_ENV_PROJECT_PATH=${envProjectPathValue}`,
|
|
7747
7756
|
`GITHUB_TOKEN=${githubToken ?? ""}`,
|
|
7748
7757
|
`GITHUB_REPO_URL=${repoUrl ?? ""}`,
|
|
7749
7758
|
`BRANCH_NAME=${branchName ?? "main"}`,
|
|
@@ -7764,8 +7773,12 @@ var runConfig = async () => {
|
|
|
7764
7773
|
`) + `
|
|
7765
7774
|
`);
|
|
7766
7775
|
await ensureGitignore(gitignorePath);
|
|
7767
|
-
|
|
7776
|
+
const envProjectTarget = envProjectPathValue === ".wile/.env.project" ? envProjectPath : envProjectPathValue;
|
|
7777
|
+
const envProjectResolved = envProjectTarget.startsWith("/") ? envProjectTarget : join(cwd, envProjectTarget);
|
|
7778
|
+
if (envProjectResolved.startsWith(wileDir)) {
|
|
7779
|
+
await writeIfMissing(envProjectResolved, `# Add env vars here to forward into the container
|
|
7768
7780
|
`);
|
|
7781
|
+
}
|
|
7769
7782
|
if (!existsSync(prdPath)) {
|
|
7770
7783
|
const prdContents = JSON.stringify({ userStories: [] }, null, 2);
|
|
7771
7784
|
await writeFile(prdPath, prdContents + `
|
|
@@ -7774,11 +7787,18 @@ var runConfig = async () => {
|
|
|
7774
7787
|
await writeIfMissing(prdExamplePath, JSON.stringify(prdExample, null, 2) + `
|
|
7775
7788
|
`);
|
|
7776
7789
|
const hadAdditionalInstructions = existsSync(additionalInstructionsPath);
|
|
7790
|
+
const hadPreflight = existsSync(preflightPath);
|
|
7777
7791
|
await writeIfMissing(additionalInstructionsPath, `<!--
|
|
7778
7792
|
Use bullet points for additional instructions, e.g.
|
|
7779
7793
|
- You may run \`supabase db reset --db-url "$SUPABASE_DB_URL"\` when needed.
|
|
7780
7794
|
- Do not ask for permission before running it.
|
|
7781
7795
|
-->
|
|
7796
|
+
`);
|
|
7797
|
+
await writeIfMissing(preflightPath, `<!--
|
|
7798
|
+
Use bullet points for preflight checks, e.g.
|
|
7799
|
+
- Confirm SUPABASE_DB_URL is set.
|
|
7800
|
+
- Run \`supabase db reset --db-url "$SUPABASE_DB_URL"\`.
|
|
7801
|
+
-->
|
|
7782
7802
|
`);
|
|
7783
7803
|
await writeIfMissing(agentsPath, [
|
|
7784
7804
|
"# PRD authoring guidance for Wile",
|
|
@@ -7803,7 +7823,7 @@ Use bullet points for additional instructions, e.g.
|
|
|
7803
7823
|
"",
|
|
7804
7824
|
"Environment notes:",
|
|
7805
7825
|
"- Playwright (Chromium) is available in the agent container for UI checks.",
|
|
7806
|
-
"- Project env vars can be passed via `.wile
|
|
7826
|
+
"- Project env vars can be passed via `.wile/.env.project` (or override with WILE_ENV_PROJECT_PATH).",
|
|
7807
7827
|
"- Optional extra guidance can be added in `.wile/additional-instructions.md`.",
|
|
7808
7828
|
"- The container has outbound internet access by default.",
|
|
7809
7829
|
""
|
|
@@ -7811,22 +7831,25 @@ Use bullet points for additional instructions, e.g.
|
|
|
7811
7831
|
`));
|
|
7812
7832
|
console.log(`
|
|
7813
7833
|
Wile config complete.`);
|
|
7814
|
-
console.log("Add project env vars to .wile
|
|
7834
|
+
console.log("Add project env vars to .wile/.env.project when needed.");
|
|
7815
7835
|
if (!hadAdditionalInstructions) {
|
|
7816
7836
|
console.log("Created .wile/additional-instructions.md for extra agent guidance (optional).");
|
|
7817
7837
|
}
|
|
7838
|
+
if (!hadPreflight) {
|
|
7839
|
+
console.log("Created .wile/preflight.md for preflight checks (optional).");
|
|
7840
|
+
}
|
|
7818
7841
|
};
|
|
7819
7842
|
|
|
7820
7843
|
// src/commands/run.ts
|
|
7821
7844
|
import { existsSync as existsSync3, readFileSync as readFileSync2, mkdirSync, createWriteStream, writeFileSync } from "node:fs";
|
|
7822
7845
|
import { spawn, spawnSync } from "node:child_process";
|
|
7823
|
-
import { resolve, join as join3, dirname } from "node:path";
|
|
7846
|
+
import { resolve as resolve2, join as join3, dirname } from "node:path";
|
|
7824
7847
|
import { fileURLToPath } from "node:url";
|
|
7825
7848
|
|
|
7826
7849
|
// src/lib/config.ts
|
|
7827
7850
|
var import_dotenv2 = __toESM(require_main(), 1);
|
|
7828
7851
|
import { existsSync as existsSync2, readFileSync } from "node:fs";
|
|
7829
|
-
import { join as join2 } from "node:path";
|
|
7852
|
+
import { join as join2, resolve, isAbsolute } from "node:path";
|
|
7830
7853
|
var getWilePaths = (cwd = process.cwd()) => {
|
|
7831
7854
|
const wileDir = join2(cwd, ".wile");
|
|
7832
7855
|
const secretsDir = join2(wileDir, "secrets");
|
|
@@ -7834,11 +7857,25 @@ var getWilePaths = (cwd = process.cwd()) => {
|
|
|
7834
7857
|
wileDir,
|
|
7835
7858
|
secretsDir,
|
|
7836
7859
|
envPath: join2(secretsDir, ".env"),
|
|
7837
|
-
envProjectPath: join2(
|
|
7860
|
+
envProjectPath: join2(wileDir, ".env.project"),
|
|
7838
7861
|
gitignorePath: join2(wileDir, ".gitignore"),
|
|
7839
7862
|
prdPath: join2(wileDir, "prd.json")
|
|
7840
7863
|
};
|
|
7841
7864
|
};
|
|
7865
|
+
var resolveEnvProjectPath = (cwd, configured) => {
|
|
7866
|
+
const defaultPath = join2(cwd, ".wile", ".env.project");
|
|
7867
|
+
const legacyPath = join2(cwd, ".wile", "secrets", ".env.project");
|
|
7868
|
+
if (configured && configured.trim().length > 0) {
|
|
7869
|
+
return isAbsolute(configured) ? configured : resolve(cwd, configured);
|
|
7870
|
+
}
|
|
7871
|
+
if (existsSync2(defaultPath)) {
|
|
7872
|
+
return defaultPath;
|
|
7873
|
+
}
|
|
7874
|
+
if (existsSync2(legacyPath)) {
|
|
7875
|
+
return legacyPath;
|
|
7876
|
+
}
|
|
7877
|
+
return defaultPath;
|
|
7878
|
+
};
|
|
7842
7879
|
var parseEnvFile = (path) => {
|
|
7843
7880
|
if (!existsSync2(path)) {
|
|
7844
7881
|
return {};
|
|
@@ -7858,7 +7895,8 @@ var readWileConfig = (options = {}) => {
|
|
|
7858
7895
|
ensureRequired(existsSync2(paths.envPath), "Missing .wile/secrets/.env. Run 'bunx wile config' first.");
|
|
7859
7896
|
}
|
|
7860
7897
|
const env = parseEnvFile(paths.envPath);
|
|
7861
|
-
const
|
|
7898
|
+
const envProjectPath = resolveEnvProjectPath(options.cwd ?? process.cwd(), env.WILE_ENV_PROJECT_PATH);
|
|
7899
|
+
const envProject = parseEnvFile(envProjectPath);
|
|
7862
7900
|
const repoSource = env.WILE_REPO_SOURCE || "github";
|
|
7863
7901
|
if (validate) {
|
|
7864
7902
|
ensureRequired(env.CODING_AGENT === "CC" || env.CODING_AGENT === "OC", "CODING_AGENT must be set to CC or OC in .wile/secrets/.env. Run 'bunx wile config'.");
|
|
@@ -7876,7 +7914,10 @@ var readWileConfig = (options = {}) => {
|
|
|
7876
7914
|
}
|
|
7877
7915
|
}
|
|
7878
7916
|
return {
|
|
7879
|
-
paths
|
|
7917
|
+
paths: {
|
|
7918
|
+
...paths,
|
|
7919
|
+
envProjectPath
|
|
7920
|
+
},
|
|
7880
7921
|
config: {
|
|
7881
7922
|
codingAgent: env.CODING_AGENT ?? "CC",
|
|
7882
7923
|
githubToken: env.GITHUB_TOKEN ?? "",
|
|
@@ -7968,7 +8009,7 @@ var resolveAgentDir = () => {
|
|
|
7968
8009
|
if (existsSync3(bundledAgentDir)) {
|
|
7969
8010
|
return bundledAgentDir;
|
|
7970
8011
|
}
|
|
7971
|
-
const cliRoot =
|
|
8012
|
+
const cliRoot = resolve2(here, "..", "..", "..");
|
|
7972
8013
|
const agentDir = join3(cliRoot, "agent");
|
|
7973
8014
|
if (!existsSync3(agentDir)) {
|
|
7974
8015
|
throw new Error("Unable to locate packages/agent. Run from the monorepo.");
|
|
@@ -8099,7 +8140,7 @@ var runWile = async (options) => {
|
|
|
8099
8140
|
};
|
|
8100
8141
|
|
|
8101
8142
|
// src/cli.ts
|
|
8102
|
-
var packageJsonPath =
|
|
8143
|
+
var packageJsonPath = resolve3(new URL("../package.json", import.meta.url).pathname);
|
|
8103
8144
|
var packageJson = JSON.parse(readFileSync3(packageJsonPath, "utf8"));
|
|
8104
8145
|
var program2 = new Command;
|
|
8105
8146
|
program2.name("wile").description("Autonomous AI coding agent that ships features while you sleep").version(packageJson.version);
|