wile 0.4.17 → 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 +2 -1
- package/dist/agent/.env.example +19 -1
- package/dist/agent/Dockerfile +4 -0
- package/dist/agent/README.md +4 -1
- package/dist/agent/entrypoint.sh +61 -33
- package/dist/agent/scripts/claude-stream.js +4 -0
- package/dist/agent/scripts/mock-claude.sh +49 -0
- package/dist/agent/scripts/opencode-stream.js +49 -0
- package/dist/agent/scripts/prompt-preflight.md +56 -0
- package/dist/agent/scripts/prompt.md +8 -2
- package/dist/agent/scripts/test-additional-instructions.sh +1 -1
- 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 +76 -19
- package/dist/cli.js +140 -54
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -19,13 +19,14 @@ 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
|
|
|
26
26
|
Set `WILE_REPO_SOURCE=local` in `.wile/secrets/.env` to run against the current directory without GitHub.
|
|
27
27
|
When `WILE_REPO_SOURCE=local`, GitHub credentials are optional.
|
|
28
28
|
Set `WILE_MAX_ITERATIONS` in `.wile/secrets/.env` to change the default loop limit (default: 25).
|
|
29
|
+
Set `CODING_AGENT=OC` to use OpenCode (OpenRouter), otherwise `CODING_AGENT=CC` uses Claude Code.
|
|
29
30
|
|
|
30
31
|
## Run Wile
|
|
31
32
|
|
package/dist/agent/.env.example
CHANGED
|
@@ -2,7 +2,16 @@
|
|
|
2
2
|
# Copy this file to .env and fill in your values
|
|
3
3
|
|
|
4
4
|
# =============================================================================
|
|
5
|
-
# REQUIRED -
|
|
5
|
+
# REQUIRED - Coding Agent Selection
|
|
6
|
+
# =============================================================================
|
|
7
|
+
|
|
8
|
+
# Choose which coding agent to run:
|
|
9
|
+
# - CC = Claude Code (default)
|
|
10
|
+
# - OC = OpenCode (OpenRouter)
|
|
11
|
+
CODING_AGENT=CC
|
|
12
|
+
|
|
13
|
+
# =============================================================================
|
|
14
|
+
# REQUIRED - Claude Code Authentication (CC only, choose ONE)
|
|
6
15
|
# =============================================================================
|
|
7
16
|
|
|
8
17
|
# OPTION 1: OAuth Token (RECOMMENDED - uses your Pro/Max subscription)
|
|
@@ -15,6 +24,15 @@ CC_CLAUDE_CODE_OAUTH_TOKEN=sk-ant-oat01-xxxxx
|
|
|
15
24
|
# Only use this if you don't have a Pro/Max subscription
|
|
16
25
|
# CC_ANTHROPIC_API_KEY=sk-ant-xxxxx
|
|
17
26
|
|
|
27
|
+
# =============================================================================
|
|
28
|
+
# REQUIRED - OpenCode Authentication (OC only)
|
|
29
|
+
# =============================================================================
|
|
30
|
+
|
|
31
|
+
# OpenRouter API key (used with OpenCode)
|
|
32
|
+
# OC_OPENROUTER_API_KEY=sk-or-xxxxx
|
|
33
|
+
# OpenRouter model id (Wile maps `glm-4.7` to `openrouter/z-ai/glm-4.7`)
|
|
34
|
+
# OC_MODEL=glm-4.7
|
|
35
|
+
|
|
18
36
|
# =============================================================================
|
|
19
37
|
# GitHub Authentication (required when WILE_REPO_SOURCE=github)
|
|
20
38
|
# =============================================================================
|
package/dist/agent/Dockerfile
CHANGED
|
@@ -48,6 +48,10 @@ ENV NODE_OPTIONS="--max-old-space-size=4096"
|
|
|
48
48
|
# https://www.npmjs.com/package/@anthropic-ai/claude-code
|
|
49
49
|
RUN npm install -g @anthropic-ai/claude-code
|
|
50
50
|
|
|
51
|
+
# Install OpenCode CLI
|
|
52
|
+
# https://www.npmjs.com/package/opencode-ai
|
|
53
|
+
RUN npm install -g opencode-ai@latest
|
|
54
|
+
|
|
51
55
|
# CC_ANTHROPIC_API_KEY is passed at runtime via environment variable (mapped to ANTHROPIC_API_KEY in entrypoint)
|
|
52
56
|
# Usage: claude --dangerously-skip-permissions
|
|
53
57
|
|
package/dist/agent/README.md
CHANGED
|
@@ -110,8 +110,11 @@ For UI work, tell the agent how to verify:
|
|
|
110
110
|
|
|
111
111
|
| Variable | Required | Description |
|
|
112
112
|
|----------|----------|-------------|
|
|
113
|
+
| `CODING_AGENT` | No | `CC` (Claude Code, default) or `OC` (OpenCode via OpenRouter) |
|
|
113
114
|
| `CC_CLAUDE_CODE_OAUTH_TOKEN` | Yes* | OAuth token from `claude setup-token` (uses Pro/Max subscription) |
|
|
114
115
|
| `CC_ANTHROPIC_API_KEY` | Yes* | API key (uses API credits - alternative to OAuth) |
|
|
116
|
+
| `OC_OPENROUTER_API_KEY` | Yes (OC) | OpenRouter API key for OpenCode |
|
|
117
|
+
| `OC_MODEL` | Yes (OC) | OpenRouter model id (set `glm-4.7` to target `openrouter/z-ai/glm-4.7`) |
|
|
115
118
|
| `WILE_REPO_SOURCE` | No | `github` (default) or `local` |
|
|
116
119
|
| `GITHUB_TOKEN` | Yes (github) | GitHub PAT with repo access |
|
|
117
120
|
| `GITHUB_REPO_URL` | Yes (github) | HTTPS URL to repository |
|
|
@@ -119,7 +122,7 @@ For UI work, tell the agent how to verify:
|
|
|
119
122
|
| `MAX_ITERATIONS` | No | Max loops (default: 25) |
|
|
120
123
|
| `CC_CLAUDE_MODEL` | No | Claude model alias/name (default: sonnet) |
|
|
121
124
|
|
|
122
|
-
*Either `CC_CLAUDE_CODE_OAUTH_TOKEN` or `CC_ANTHROPIC_API_KEY` is required
|
|
125
|
+
*Either `CC_CLAUDE_CODE_OAUTH_TOKEN` or `CC_ANTHROPIC_API_KEY` is required when `CODING_AGENT=CC`.
|
|
123
126
|
|
|
124
127
|
## Output Files
|
|
125
128
|
|
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);
|
|
@@ -67,10 +71,12 @@ NODE
|
|
|
67
71
|
exit 0
|
|
68
72
|
fi
|
|
69
73
|
|
|
74
|
+
CODING_AGENT="${CODING_AGENT:-CC}"
|
|
70
75
|
REPO_SOURCE="${WILE_REPO_SOURCE:-github}"
|
|
71
76
|
LOCAL_REPO_PATH="${WILE_LOCAL_REPO_PATH:-/home/wile/workspace/repo}"
|
|
72
77
|
ADDITIONAL_INSTRUCTIONS_PATH="${WILE_ADDITIONAL_INSTRUCTIONS:-}"
|
|
73
78
|
|
|
79
|
+
echo " Agent: $CODING_AGENT"
|
|
74
80
|
if [ "$REPO_SOURCE" = "local" ]; then
|
|
75
81
|
if [ ! -d "$LOCAL_REPO_PATH" ]; then
|
|
76
82
|
echo "ERROR: WILE_LOCAL_REPO_PATH does not exist: $LOCAL_REPO_PATH"
|
|
@@ -83,53 +89,74 @@ else
|
|
|
83
89
|
: "${GITHUB_TOKEN:?GITHUB_TOKEN is required}"
|
|
84
90
|
fi
|
|
85
91
|
|
|
86
|
-
# Authentication
|
|
87
|
-
if [
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
92
|
+
# Authentication for selected coding agent
|
|
93
|
+
if [ "$CODING_AGENT" = "OC" ]; then
|
|
94
|
+
if [ -z "$OC_OPENROUTER_API_KEY" ]; then
|
|
95
|
+
echo "ERROR: OC_OPENROUTER_API_KEY is required for OpenCode"
|
|
96
|
+
exit 1
|
|
97
|
+
fi
|
|
98
|
+
if [ -z "$OC_MODEL" ]; then
|
|
99
|
+
echo "ERROR: OC_MODEL is required for OpenCode"
|
|
100
|
+
exit 1
|
|
101
|
+
fi
|
|
102
|
+
else
|
|
103
|
+
if [ -z "$CC_CLAUDE_CODE_OAUTH_TOKEN" ] && [ -z "$CC_ANTHROPIC_API_KEY" ]; then
|
|
104
|
+
echo "ERROR: Either CC_CLAUDE_CODE_OAUTH_TOKEN or CC_ANTHROPIC_API_KEY is required"
|
|
105
|
+
echo ""
|
|
106
|
+
echo " CC_CLAUDE_CODE_OAUTH_TOKEN - Uses your Pro/Max subscription (recommended)"
|
|
107
|
+
echo " CC_ANTHROPIC_API_KEY - Uses API credits (pay per token)"
|
|
108
|
+
echo ""
|
|
109
|
+
echo "Run 'claude setup-token' on your local machine to get an OAuth token."
|
|
110
|
+
exit 1
|
|
111
|
+
fi
|
|
95
112
|
fi
|
|
96
113
|
|
|
97
114
|
MAX_ITERATIONS=${MAX_ITERATIONS:-25}
|
|
98
115
|
SCRIPT_DIR="/home/wile/scripts"
|
|
99
116
|
WORKSPACE="/home/wile/workspace"
|
|
100
117
|
|
|
101
|
-
if [ "${WILE_MOCK_CLAUDE:-}" = "true" ]; then
|
|
118
|
+
if [ "${WILE_MOCK_CLAUDE:-}" = "true" ] && [ "$CODING_AGENT" = "CC" ]; then
|
|
102
119
|
echo " Claude: Mocked"
|
|
103
120
|
MOCK_BIN="/home/wile/mock-bin"
|
|
104
121
|
mkdir -p "$MOCK_BIN"
|
|
105
|
-
|
|
106
|
-
#!/bin/sh
|
|
107
|
-
cat <<'JSON'
|
|
108
|
-
{"type":"assistant","message":{"content":[{"type":"text","text":"ANSWER: 2\n<promise>COMPLETE</promise>\n"}]}}
|
|
109
|
-
JSON
|
|
110
|
-
MOCK
|
|
122
|
+
cp "$SCRIPT_DIR/mock-claude.sh" "$MOCK_BIN/claude"
|
|
111
123
|
chmod +x "$MOCK_BIN/claude"
|
|
112
124
|
export PATH="$MOCK_BIN:$PATH"
|
|
113
125
|
fi
|
|
114
126
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
127
|
+
if [ "$CODING_AGENT" = "OC" ]; then
|
|
128
|
+
echo " Auth: OpenRouter (OpenCode)"
|
|
129
|
+
OPENCODE_DATA_DIR="${XDG_DATA_HOME:-$HOME/.local/share}/opencode"
|
|
130
|
+
mkdir -p "$OPENCODE_DATA_DIR"
|
|
131
|
+
cat > "$OPENCODE_DATA_DIR/auth.json" << OPENCODEAUTH
|
|
132
|
+
{
|
|
133
|
+
"openrouter": {
|
|
134
|
+
"type": "api",
|
|
135
|
+
"key": "$OC_OPENROUTER_API_KEY"
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
OPENCODEAUTH
|
|
139
|
+
chmod 600 "$OPENCODE_DATA_DIR/auth.json"
|
|
140
|
+
export OPENROUTER_API_KEY="$OC_OPENROUTER_API_KEY"
|
|
141
|
+
else
|
|
142
|
+
# Set up Claude Code authentication
|
|
143
|
+
if [ -n "$CC_CLAUDE_CODE_OAUTH_TOKEN" ]; then
|
|
144
|
+
echo " Auth: OAuth (Pro/Max subscription)"
|
|
118
145
|
|
|
119
|
-
|
|
120
|
-
|
|
146
|
+
# Create required directories
|
|
147
|
+
mkdir -p ~/.claude ~/.config/claude
|
|
121
148
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
149
|
+
# Create ~/.claude.json (THE CRITICAL FILE!)
|
|
150
|
+
# Without this, Claude Code thinks it's a fresh install and breaks
|
|
151
|
+
cat > ~/.claude.json << 'CLAUDEJSON'
|
|
125
152
|
{
|
|
126
153
|
"hasCompletedOnboarding": true,
|
|
127
154
|
"theme": "dark"
|
|
128
155
|
}
|
|
129
156
|
CLAUDEJSON
|
|
130
157
|
|
|
131
|
-
|
|
132
|
-
|
|
158
|
+
# Create credentials file with the OAuth token
|
|
159
|
+
cat > ~/.claude/.credentials.json << CREDSJSON
|
|
133
160
|
{
|
|
134
161
|
"claudeAiOauth": {
|
|
135
162
|
"accessToken": "$CC_CLAUDE_CODE_OAUTH_TOKEN",
|
|
@@ -140,14 +167,15 @@ CLAUDEJSON
|
|
|
140
167
|
}
|
|
141
168
|
CREDSJSON
|
|
142
169
|
|
|
143
|
-
|
|
144
|
-
|
|
170
|
+
# Copy to alternate location too
|
|
171
|
+
cp ~/.claude/.credentials.json ~/.config/claude/.credentials.json
|
|
145
172
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
else
|
|
149
|
-
|
|
150
|
-
|
|
173
|
+
# Ensure ANTHROPIC_API_KEY is not set (it overrides OAuth)
|
|
174
|
+
unset ANTHROPIC_API_KEY
|
|
175
|
+
else
|
|
176
|
+
echo " Auth: API Key (credits)"
|
|
177
|
+
export ANTHROPIC_API_KEY="$CC_ANTHROPIC_API_KEY"
|
|
178
|
+
fi
|
|
151
179
|
fi
|
|
152
180
|
|
|
153
181
|
if [ "$REPO_SOURCE" = "local" ]; then
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
set -e
|
|
3
|
+
|
|
4
|
+
COUNT_FILE="/tmp/wile-claude-mock-count"
|
|
5
|
+
if [ ! -f "$COUNT_FILE" ]; then
|
|
6
|
+
echo "0" > "$COUNT_FILE"
|
|
7
|
+
fi
|
|
8
|
+
|
|
9
|
+
COUNT=$(cat "$COUNT_FILE")
|
|
10
|
+
NEXT_COUNT=$((COUNT + 1))
|
|
11
|
+
echo "$NEXT_COUNT" > "$COUNT_FILE"
|
|
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
|
+
|
|
41
|
+
if [ "$COUNT" -eq 0 ]; then
|
|
42
|
+
cat <<'JSON'
|
|
43
|
+
{"type":"assistant","message":{"content":[{"type":"text","text":"ANSWER: 2\n"}]}}
|
|
44
|
+
JSON
|
|
45
|
+
else
|
|
46
|
+
cat <<'JSON'
|
|
47
|
+
{"type":"assistant","message":{"content":[{"type":"text","text":"<promise>COMPLETE</promise>\n"}]}}
|
|
48
|
+
JSON
|
|
49
|
+
fi
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
const readline = require("node:readline");
|
|
3
|
+
|
|
4
|
+
const rl = readline.createInterface({
|
|
5
|
+
input: process.stdin,
|
|
6
|
+
crlfDelay: Infinity
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
const writeLine = (value) => {
|
|
10
|
+
process.stdout.write(`${value}\n`);
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
const formatToolLine = (tool, title, input) => {
|
|
14
|
+
if (title) return `[tool] ${tool}: ${title}`;
|
|
15
|
+
if (input && Object.keys(input).length > 0) {
|
|
16
|
+
return `[tool] ${tool}: ${JSON.stringify(input)}`;
|
|
17
|
+
}
|
|
18
|
+
return `[tool] ${tool}`;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
rl.on("line", (line) => {
|
|
22
|
+
if (!line.trim()) return;
|
|
23
|
+
let payload;
|
|
24
|
+
try {
|
|
25
|
+
payload = JSON.parse(line);
|
|
26
|
+
} catch {
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (payload.type === "text" && payload.part?.text) {
|
|
31
|
+
process.stdout.write(payload.part.text);
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (payload.type === "tool_use" && payload.part) {
|
|
36
|
+
const tool = payload.part.tool ?? "tool";
|
|
37
|
+
const title = payload.part.state?.title ?? "";
|
|
38
|
+
const input = payload.part.state?.input ?? {};
|
|
39
|
+
writeLine(formatToolLine(tool, title, input));
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (payload.type === "error" && payload.error) {
|
|
44
|
+
const name = payload.error?.name ?? "error";
|
|
45
|
+
const message = payload.error?.data?.message ?? payload.error?.message ?? "";
|
|
46
|
+
writeLine(`[error] ${name}${message ? `: ${message}` : ""}`);
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
});
|
|
@@ -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
|
|
@@ -87,6 +90,7 @@ After completing steps 1-8, check if ALL stories in `.wile/prd.json` have `passe
|
|
|
87
90
|
```
|
|
88
91
|
<promise>COMPLETE</promise>
|
|
89
92
|
```
|
|
93
|
+
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.
|
|
90
94
|
|
|
91
95
|
**If there are still stories with `passes: false`**, end your response normally. The loop will call you again for the next story.
|
|
92
96
|
|
|
@@ -103,6 +107,8 @@ After completing steps 1-8, check if ALL stories in `.wile/prd.json` have `passe
|
|
|
103
107
|
9. **Integration tests must validate real system behavior, not just the harness**
|
|
104
108
|
10. **If you discover reusable, module-specific guidance, add it to the nearest AGENTS.md**
|
|
105
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`.
|
|
106
112
|
|
|
107
113
|
## Common Patterns
|
|
108
114
|
|
|
@@ -47,7 +47,7 @@ EOF
|
|
|
47
47
|
cat > "$BIN_DIR/claude" <<'EOF'
|
|
48
48
|
#!/bin/sh
|
|
49
49
|
cat > "$CLAUDE_CAPTURE"
|
|
50
|
-
printf '%s\n' '{"type":"assistant","message":{"content":[{"type":"text","text":"<promise>COMPLETE</promise
|
|
50
|
+
printf '%s\n' '{"type":"assistant","message":{"content":[{"type":"text","text":"<promise>COMPLETE</promise>\n"}]}}'
|
|
51
51
|
EOF
|
|
52
52
|
chmod +x "$BIN_DIR/claude"
|
|
53
53
|
|
|
@@ -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 "══════════════════════════════════════════════════════"
|
|
@@ -7,17 +7,32 @@
|
|
|
7
7
|
set -e
|
|
8
8
|
|
|
9
9
|
MAX_ITERATIONS=${1:-25}
|
|
10
|
+
CODING_AGENT=${CODING_AGENT:-CC}
|
|
10
11
|
CLAUDE_MODEL=${CC_CLAUDE_MODEL:-sonnet}
|
|
12
|
+
OC_MODEL=${OC_MODEL:-glm-4.7}
|
|
13
|
+
if [[ "$OC_MODEL" != */* ]]; then
|
|
14
|
+
OC_MODEL="z-ai/$OC_MODEL"
|
|
15
|
+
fi
|
|
11
16
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
12
17
|
PROMPT_FILE="$SCRIPT_DIR/prompt.md"
|
|
18
|
+
PREFLIGHT_PROMPT_FILE="$SCRIPT_DIR/prompt-preflight.md"
|
|
13
19
|
SETUP_PROMPT_FILE="$SCRIPT_DIR/prompt-setup.md"
|
|
14
20
|
ADDITIONAL_PROMPT_FILE="${WILE_ADDITIONAL_INSTRUCTIONS:-}"
|
|
21
|
+
TEE_TARGET="${WILE_TEE_TARGET:-/dev/stderr}"
|
|
22
|
+
if ! ( : > "$TEE_TARGET" ) 2>/dev/null; then
|
|
23
|
+
TEE_TARGET="/dev/null"
|
|
24
|
+
fi
|
|
15
25
|
|
|
16
26
|
echo "══════════════════════════════════════════════════════"
|
|
17
27
|
echo " 🌵 WILE - Autonomous Coding Agent"
|
|
18
28
|
echo "══════════════════════════════════════════════════════"
|
|
29
|
+
echo " Agent: $CODING_AGENT"
|
|
19
30
|
echo " Max iterations: $MAX_ITERATIONS"
|
|
20
|
-
|
|
31
|
+
if [ "$CODING_AGENT" = "OC" ]; then
|
|
32
|
+
echo " Model: $OC_MODEL"
|
|
33
|
+
else
|
|
34
|
+
echo " Model: $CLAUDE_MODEL"
|
|
35
|
+
fi
|
|
21
36
|
echo " Prompt file: $PROMPT_FILE"
|
|
22
37
|
echo "══════════════════════════════════════════════════════"
|
|
23
38
|
echo ""
|
|
@@ -39,22 +54,62 @@ if [ -n "$ADDITIONAL_PROMPT_FILE" ] && [ -f "$ADDITIONAL_PROMPT_FILE" ]; then
|
|
|
39
54
|
fi
|
|
40
55
|
fi
|
|
41
56
|
|
|
57
|
+
run_claude() {
|
|
58
|
+
local prompt_path="$1"
|
|
59
|
+
cat "$prompt_path" \
|
|
60
|
+
| claude --model "$CLAUDE_MODEL" --print --output-format stream-json --verbose --dangerously-skip-permissions \
|
|
61
|
+
| node "$SCRIPT_DIR/claude-stream.js"
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
run_opencode() {
|
|
65
|
+
local prompt_path="$1"
|
|
66
|
+
cat "$prompt_path" \
|
|
67
|
+
| opencode run --format json --model "openrouter/$OC_MODEL" \
|
|
68
|
+
| node "$SCRIPT_DIR/opencode-stream.js"
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
run_agent() {
|
|
72
|
+
local prompt_path="$1"
|
|
73
|
+
if [ "$CODING_AGENT" = "OC" ]; then
|
|
74
|
+
run_opencode "$prompt_path"
|
|
75
|
+
else
|
|
76
|
+
run_claude "$prompt_path"
|
|
77
|
+
fi
|
|
78
|
+
}
|
|
79
|
+
|
|
42
80
|
# ════════════════════════════════════════════════════════════
|
|
43
|
-
# ITERATION 0: Setup
|
|
81
|
+
# ITERATION 0: Preflight / Setup
|
|
44
82
|
# ════════════════════════════════════════════════════════════
|
|
45
83
|
echo ""
|
|
46
84
|
echo "══════════════════════════════════════════════════════"
|
|
47
|
-
echo " Iteration 0 -
|
|
85
|
+
echo " Iteration 0 - Preflight"
|
|
48
86
|
echo "══════════════════════════════════════════════════════"
|
|
49
87
|
echo ""
|
|
50
88
|
|
|
51
|
-
if [ -f "$
|
|
52
|
-
OUTPUT=$(
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
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
|
|
112
|
+
OUTPUT=$(run_agent "$SETUP_PROMPT_FILE" | tee "$TEE_TARGET") || true
|
|
58
113
|
|
|
59
114
|
# Check if setup failed critically
|
|
60
115
|
if echo "$OUTPUT" | grep -q "<promise>SETUP_FAILED</promise>"; then
|
|
@@ -85,20 +140,22 @@ for i in $(seq 1 $MAX_ITERATIONS); do
|
|
|
85
140
|
# Pipe prompt to Claude Code
|
|
86
141
|
# --dangerously-skip-permissions allows autonomous operation
|
|
87
142
|
# Capture output while also displaying it (tee to stderr)
|
|
88
|
-
OUTPUT=$(
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
143
|
+
OUTPUT=$(run_agent "$PROMPT_FILE" | tee "$TEE_TARGET") || true
|
|
144
|
+
|
|
145
|
+
# Check for completion signal (tag must be on its own line; reject backticks/code fences)
|
|
146
|
+
CLEAN_OUTPUT=$(printf '%s' "$OUTPUT" | tr -d '\r' | sed -e 's/[[:space:]]*$//')
|
|
147
|
+
if printf '%s\n' "$CLEAN_OUTPUT" | grep -q -E '^[[:space:]]*<promise>COMPLETE</promise>[[:space:]]*$'; then
|
|
148
|
+
if printf '%s' "$CLEAN_OUTPUT" | grep -F '```' >/dev/null 2>&1; then
|
|
149
|
+
:
|
|
150
|
+
elif printf '%s' "$CLEAN_OUTPUT" | grep -F '`<promise>COMPLETE</promise>`' >/dev/null 2>&1; then
|
|
151
|
+
:
|
|
152
|
+
else
|
|
97
153
|
echo ""
|
|
98
154
|
echo "══════════════════════════════════════════════════════"
|
|
99
155
|
echo " ✅ ALL TASKS COMPLETE"
|
|
100
156
|
echo "══════════════════════════════════════════════════════"
|
|
101
157
|
exit 0
|
|
158
|
+
fi
|
|
102
159
|
fi
|
|
103
160
|
|
|
104
161
|
echo ""
|
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);
|
|
@@ -7544,6 +7544,7 @@ var prdExample = {
|
|
|
7544
7544
|
var tips = {
|
|
7545
7545
|
oauth: "Tip: run 'claude setup-token' on your machine to generate an OAuth token (uses Pro/Max subscription).",
|
|
7546
7546
|
apiKey: "Tip: create an Anthropic API key in the console (uses API credits).",
|
|
7547
|
+
openrouter: "Tip: create an OpenRouter API key for OpenCode (used for z-ai/glm-4.7).",
|
|
7547
7548
|
github: "Tip: use a GitHub Personal Access Token (fine-grained recommended). Create at https://github.com/settings/tokens?type=beta with Contents (read/write) and Metadata (read)."
|
|
7548
7549
|
};
|
|
7549
7550
|
var readEnvFile = async (path) => {
|
|
@@ -7554,7 +7555,7 @@ var readEnvFile = async (path) => {
|
|
|
7554
7555
|
return import_dotenv.default.parse(contents);
|
|
7555
7556
|
};
|
|
7556
7557
|
var ensureGitignore = async (path) => {
|
|
7557
|
-
const entries = ["secrets/", "screenshots/", "logs/"];
|
|
7558
|
+
const entries = ["secrets/", "screenshots/", "logs/", ".env.project"];
|
|
7558
7559
|
if (!existsSync(path)) {
|
|
7559
7560
|
await writeFile(path, entries.join(`
|
|
7560
7561
|
`) + `
|
|
@@ -7616,53 +7617,82 @@ var runConfig = async () => {
|
|
|
7616
7617
|
const wileDir = join(cwd, ".wile");
|
|
7617
7618
|
const secretsDir = join(wileDir, "secrets");
|
|
7618
7619
|
const envPath = join(secretsDir, ".env");
|
|
7619
|
-
const envProjectPath = join(
|
|
7620
|
+
const envProjectPath = join(wileDir, ".env.project");
|
|
7620
7621
|
const gitignorePath = join(wileDir, ".gitignore");
|
|
7621
7622
|
const prdPath = join(wileDir, "prd.json");
|
|
7622
7623
|
const prdExamplePath = join(wileDir, "prd.json.example");
|
|
7623
7624
|
const additionalInstructionsPath = join(wileDir, "additional-instructions.md");
|
|
7625
|
+
const preflightPath = join(wileDir, "preflight.md");
|
|
7624
7626
|
const agentsPath = join(wileDir, "AGENTS.md");
|
|
7625
7627
|
await mkdir(secretsDir, { recursive: true });
|
|
7626
7628
|
const existingEnv = await readEnvFile(envPath);
|
|
7627
|
-
await prompt({
|
|
7629
|
+
const codingAgentResponse = await prompt({
|
|
7628
7630
|
type: "select",
|
|
7629
7631
|
name: "codingAgent",
|
|
7630
7632
|
message: "Select coding agent",
|
|
7631
|
-
choices: [{ title: "Claude Code (CC)", value: "CC" }],
|
|
7632
|
-
initial: 0
|
|
7633
|
-
});
|
|
7634
|
-
const authDefault = existingEnv.CC_CLAUDE_CODE_OAUTH_TOKEN ? "oauth" : existingEnv.CC_ANTHROPIC_API_KEY ? "apiKey" : "oauth";
|
|
7635
|
-
const authResponse = await prompt({
|
|
7636
|
-
type: "select",
|
|
7637
|
-
name: "authMethod",
|
|
7638
|
-
message: "Claude Code authentication",
|
|
7639
7633
|
choices: [
|
|
7640
|
-
{ title: "
|
|
7641
|
-
{ title: "
|
|
7634
|
+
{ title: "Claude Code (CC)", value: "CC" },
|
|
7635
|
+
{ title: "OpenCode (OC)", value: "OC" }
|
|
7642
7636
|
],
|
|
7643
|
-
initial:
|
|
7644
|
-
});
|
|
7645
|
-
const authMethod = authResponse.authMethod;
|
|
7646
|
-
console.log("");
|
|
7647
|
-
console.log(authMethod === "oauth" ? tips.oauth : tips.apiKey);
|
|
7648
|
-
console.log("");
|
|
7649
|
-
const authValueResponse = await prompt({
|
|
7650
|
-
type: "password",
|
|
7651
|
-
name: "authValue",
|
|
7652
|
-
message: authMethod === "oauth" ? "Claude Code OAuth token (press enter to keep existing)" : "Anthropic API key (press enter to keep existing)",
|
|
7653
|
-
initial: authMethod === "oauth" ? existingEnv.CC_CLAUDE_CODE_OAUTH_TOKEN ?? "" : existingEnv.CC_ANTHROPIC_API_KEY ?? ""
|
|
7654
|
-
});
|
|
7655
|
-
const defaultModelResponse = await prompt({
|
|
7656
|
-
type: "select",
|
|
7657
|
-
name: "model",
|
|
7658
|
-
message: "Default Claude model",
|
|
7659
|
-
choices: [
|
|
7660
|
-
{ title: "sonnet", value: "sonnet" },
|
|
7661
|
-
{ title: "opus", value: "opus" },
|
|
7662
|
-
{ title: "haiku", value: "haiku" }
|
|
7663
|
-
],
|
|
7664
|
-
initial: existingEnv.CC_CLAUDE_MODEL === "opus" ? 1 : existingEnv.CC_CLAUDE_MODEL === "haiku" ? 2 : 0
|
|
7637
|
+
initial: existingEnv.CODING_AGENT === "OC" ? 1 : 0
|
|
7665
7638
|
});
|
|
7639
|
+
const codingAgent = codingAgentResponse.codingAgent;
|
|
7640
|
+
let authMethod = null;
|
|
7641
|
+
let authValueResponse = {};
|
|
7642
|
+
let defaultModelResponse = {};
|
|
7643
|
+
let ocKeyResponse = {};
|
|
7644
|
+
let ocModelResponse = {};
|
|
7645
|
+
if (codingAgent === "CC") {
|
|
7646
|
+
const authDefault = existingEnv.CC_CLAUDE_CODE_OAUTH_TOKEN ? "oauth" : existingEnv.CC_ANTHROPIC_API_KEY ? "apiKey" : "oauth";
|
|
7647
|
+
const authResponse = await prompt({
|
|
7648
|
+
type: "select",
|
|
7649
|
+
name: "authMethod",
|
|
7650
|
+
message: "Claude Code authentication",
|
|
7651
|
+
choices: [
|
|
7652
|
+
{ title: "OAuth token (Pro/Max subscription)", value: "oauth" },
|
|
7653
|
+
{ title: "API key (Anthropic credits)", value: "apiKey" }
|
|
7654
|
+
],
|
|
7655
|
+
initial: authDefault === "apiKey" ? 1 : 0
|
|
7656
|
+
});
|
|
7657
|
+
authMethod = authResponse.authMethod;
|
|
7658
|
+
console.log("");
|
|
7659
|
+
console.log(authMethod === "oauth" ? tips.oauth : tips.apiKey);
|
|
7660
|
+
console.log("");
|
|
7661
|
+
authValueResponse = await prompt({
|
|
7662
|
+
type: "password",
|
|
7663
|
+
name: "authValue",
|
|
7664
|
+
message: authMethod === "oauth" ? "Claude Code OAuth token (press enter to keep existing)" : "Anthropic API key (press enter to keep existing)",
|
|
7665
|
+
initial: authMethod === "oauth" ? existingEnv.CC_CLAUDE_CODE_OAUTH_TOKEN ?? "" : existingEnv.CC_ANTHROPIC_API_KEY ?? ""
|
|
7666
|
+
});
|
|
7667
|
+
defaultModelResponse = await prompt({
|
|
7668
|
+
type: "select",
|
|
7669
|
+
name: "model",
|
|
7670
|
+
message: "Default Claude model",
|
|
7671
|
+
choices: [
|
|
7672
|
+
{ title: "sonnet", value: "sonnet" },
|
|
7673
|
+
{ title: "opus", value: "opus" },
|
|
7674
|
+
{ title: "haiku", value: "haiku" }
|
|
7675
|
+
],
|
|
7676
|
+
initial: existingEnv.CC_CLAUDE_MODEL === "opus" ? 1 : existingEnv.CC_CLAUDE_MODEL === "haiku" ? 2 : 0
|
|
7677
|
+
});
|
|
7678
|
+
} else {
|
|
7679
|
+
console.log("");
|
|
7680
|
+
console.log(tips.openrouter);
|
|
7681
|
+
console.log("");
|
|
7682
|
+
ocKeyResponse = await prompt({
|
|
7683
|
+
type: "password",
|
|
7684
|
+
name: "ocKey",
|
|
7685
|
+
message: "OpenRouter API key (press enter to keep existing)",
|
|
7686
|
+
initial: existingEnv.OC_OPENROUTER_API_KEY ?? ""
|
|
7687
|
+
});
|
|
7688
|
+
ocModelResponse = await prompt({
|
|
7689
|
+
type: "select",
|
|
7690
|
+
name: "ocModel",
|
|
7691
|
+
message: "OpenCode model (OpenRouter)",
|
|
7692
|
+
choices: [{ title: "glm-4.7", value: "glm-4.7" }],
|
|
7693
|
+
initial: existingEnv.OC_MODEL === "glm-4.7" ? 0 : 0
|
|
7694
|
+
});
|
|
7695
|
+
}
|
|
7666
7696
|
const repoSourceResponse = await prompt({
|
|
7667
7697
|
type: "select",
|
|
7668
7698
|
name: "repoSource",
|
|
@@ -7691,6 +7721,12 @@ var runConfig = async () => {
|
|
|
7691
7721
|
message: "GitHub repo URL",
|
|
7692
7722
|
initial: existingEnv.GITHUB_REPO_URL ?? ""
|
|
7693
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
|
+
});
|
|
7694
7730
|
const branchResponse = await prompt({
|
|
7695
7731
|
type: "text",
|
|
7696
7732
|
name: "branchName",
|
|
@@ -7706,30 +7742,43 @@ var runConfig = async () => {
|
|
|
7706
7742
|
const fallbackIterations = existingEnv.WILE_MAX_ITERATIONS ? Number(existingEnv.WILE_MAX_ITERATIONS) : 25;
|
|
7707
7743
|
const maxIterations = Number.isFinite(iterationsResponse.maxIterations) && iterationsResponse.maxIterations > 0 ? iterationsResponse.maxIterations : fallbackIterations;
|
|
7708
7744
|
const authFallback = authMethod === "oauth" ? existingEnv.CC_CLAUDE_CODE_OAUTH_TOKEN : existingEnv.CC_ANTHROPIC_API_KEY;
|
|
7709
|
-
const authValue = coalesceValue(authValueResponse.authValue, authFallback);
|
|
7745
|
+
const authValue = codingAgent === "CC" ? coalesceValue(authValueResponse.authValue, authFallback) : undefined;
|
|
7746
|
+
const ocKey = codingAgent === "OC" ? coalesceValue(ocKeyResponse.ocKey, existingEnv.OC_OPENROUTER_API_KEY) : undefined;
|
|
7747
|
+
const ocModel = codingAgent === "OC" ? coalesceValue(ocModelResponse.ocModel, existingEnv.OC_MODEL ?? "glm-4.7") : undefined;
|
|
7710
7748
|
const githubToken = repoSource === "github" ? coalesceValue(githubTokenResponse.githubToken, existingEnv.GITHUB_TOKEN) : existingEnv.GITHUB_TOKEN;
|
|
7711
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";
|
|
7712
7751
|
const branchName = coalesceValue(branchResponse.branchName, existingEnv.BRANCH_NAME ?? "main");
|
|
7713
7752
|
const envLines = [
|
|
7714
|
-
|
|
7753
|
+
`CODING_AGENT=${codingAgent}`,
|
|
7715
7754
|
`WILE_REPO_SOURCE=${repoSource}`,
|
|
7755
|
+
`WILE_ENV_PROJECT_PATH=${envProjectPathValue}`,
|
|
7716
7756
|
`GITHUB_TOKEN=${githubToken ?? ""}`,
|
|
7717
7757
|
`GITHUB_REPO_URL=${repoUrl ?? ""}`,
|
|
7718
7758
|
`BRANCH_NAME=${branchName ?? "main"}`,
|
|
7719
|
-
`CC_CLAUDE_MODEL=${defaultModelResponse.model}`,
|
|
7720
7759
|
`WILE_MAX_ITERATIONS=${maxIterations}`
|
|
7721
7760
|
];
|
|
7722
|
-
if (
|
|
7723
|
-
envLines.push(`
|
|
7761
|
+
if (codingAgent === "CC") {
|
|
7762
|
+
envLines.push(`CC_CLAUDE_MODEL=${defaultModelResponse.model}`);
|
|
7763
|
+
if (authMethod === "oauth") {
|
|
7764
|
+
envLines.push(`CC_CLAUDE_CODE_OAUTH_TOKEN=${authValue ?? ""}`);
|
|
7765
|
+
} else {
|
|
7766
|
+
envLines.push(`CC_ANTHROPIC_API_KEY=${authValue ?? ""}`);
|
|
7767
|
+
}
|
|
7724
7768
|
} else {
|
|
7725
|
-
envLines.push(`
|
|
7769
|
+
envLines.push(`OC_MODEL=${ocModel ?? "glm-4.7"}`);
|
|
7770
|
+
envLines.push(`OC_OPENROUTER_API_KEY=${ocKey ?? ""}`);
|
|
7726
7771
|
}
|
|
7727
7772
|
await writeFile(envPath, envLines.join(`
|
|
7728
7773
|
`) + `
|
|
7729
7774
|
`);
|
|
7730
7775
|
await ensureGitignore(gitignorePath);
|
|
7731
|
-
|
|
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
|
|
7732
7780
|
`);
|
|
7781
|
+
}
|
|
7733
7782
|
if (!existsSync(prdPath)) {
|
|
7734
7783
|
const prdContents = JSON.stringify({ userStories: [] }, null, 2);
|
|
7735
7784
|
await writeFile(prdPath, prdContents + `
|
|
@@ -7738,11 +7787,18 @@ var runConfig = async () => {
|
|
|
7738
7787
|
await writeIfMissing(prdExamplePath, JSON.stringify(prdExample, null, 2) + `
|
|
7739
7788
|
`);
|
|
7740
7789
|
const hadAdditionalInstructions = existsSync(additionalInstructionsPath);
|
|
7790
|
+
const hadPreflight = existsSync(preflightPath);
|
|
7741
7791
|
await writeIfMissing(additionalInstructionsPath, `<!--
|
|
7742
7792
|
Use bullet points for additional instructions, e.g.
|
|
7743
7793
|
- You may run \`supabase db reset --db-url "$SUPABASE_DB_URL"\` when needed.
|
|
7744
7794
|
- Do not ask for permission before running it.
|
|
7745
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
|
+
-->
|
|
7746
7802
|
`);
|
|
7747
7803
|
await writeIfMissing(agentsPath, [
|
|
7748
7804
|
"# PRD authoring guidance for Wile",
|
|
@@ -7767,7 +7823,7 @@ Use bullet points for additional instructions, e.g.
|
|
|
7767
7823
|
"",
|
|
7768
7824
|
"Environment notes:",
|
|
7769
7825
|
"- Playwright (Chromium) is available in the agent container for UI checks.",
|
|
7770
|
-
"- 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).",
|
|
7771
7827
|
"- Optional extra guidance can be added in `.wile/additional-instructions.md`.",
|
|
7772
7828
|
"- The container has outbound internet access by default.",
|
|
7773
7829
|
""
|
|
@@ -7775,22 +7831,25 @@ Use bullet points for additional instructions, e.g.
|
|
|
7775
7831
|
`));
|
|
7776
7832
|
console.log(`
|
|
7777
7833
|
Wile config complete.`);
|
|
7778
|
-
console.log("Add project env vars to .wile
|
|
7834
|
+
console.log("Add project env vars to .wile/.env.project when needed.");
|
|
7779
7835
|
if (!hadAdditionalInstructions) {
|
|
7780
7836
|
console.log("Created .wile/additional-instructions.md for extra agent guidance (optional).");
|
|
7781
7837
|
}
|
|
7838
|
+
if (!hadPreflight) {
|
|
7839
|
+
console.log("Created .wile/preflight.md for preflight checks (optional).");
|
|
7840
|
+
}
|
|
7782
7841
|
};
|
|
7783
7842
|
|
|
7784
7843
|
// src/commands/run.ts
|
|
7785
7844
|
import { existsSync as existsSync3, readFileSync as readFileSync2, mkdirSync, createWriteStream, writeFileSync } from "node:fs";
|
|
7786
7845
|
import { spawn, spawnSync } from "node:child_process";
|
|
7787
|
-
import { resolve, join as join3, dirname } from "node:path";
|
|
7846
|
+
import { resolve as resolve2, join as join3, dirname } from "node:path";
|
|
7788
7847
|
import { fileURLToPath } from "node:url";
|
|
7789
7848
|
|
|
7790
7849
|
// src/lib/config.ts
|
|
7791
7850
|
var import_dotenv2 = __toESM(require_main(), 1);
|
|
7792
7851
|
import { existsSync as existsSync2, readFileSync } from "node:fs";
|
|
7793
|
-
import { join as join2 } from "node:path";
|
|
7852
|
+
import { join as join2, resolve, isAbsolute } from "node:path";
|
|
7794
7853
|
var getWilePaths = (cwd = process.cwd()) => {
|
|
7795
7854
|
const wileDir = join2(cwd, ".wile");
|
|
7796
7855
|
const secretsDir = join2(wileDir, "secrets");
|
|
@@ -7798,11 +7857,25 @@ var getWilePaths = (cwd = process.cwd()) => {
|
|
|
7798
7857
|
wileDir,
|
|
7799
7858
|
secretsDir,
|
|
7800
7859
|
envPath: join2(secretsDir, ".env"),
|
|
7801
|
-
envProjectPath: join2(
|
|
7860
|
+
envProjectPath: join2(wileDir, ".env.project"),
|
|
7802
7861
|
gitignorePath: join2(wileDir, ".gitignore"),
|
|
7803
7862
|
prdPath: join2(wileDir, "prd.json")
|
|
7804
7863
|
};
|
|
7805
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
|
+
};
|
|
7806
7879
|
var parseEnvFile = (path) => {
|
|
7807
7880
|
if (!existsSync2(path)) {
|
|
7808
7881
|
return {};
|
|
@@ -7822,19 +7895,29 @@ var readWileConfig = (options = {}) => {
|
|
|
7822
7895
|
ensureRequired(existsSync2(paths.envPath), "Missing .wile/secrets/.env. Run 'bunx wile config' first.");
|
|
7823
7896
|
}
|
|
7824
7897
|
const env = parseEnvFile(paths.envPath);
|
|
7825
|
-
const
|
|
7898
|
+
const envProjectPath = resolveEnvProjectPath(options.cwd ?? process.cwd(), env.WILE_ENV_PROJECT_PATH);
|
|
7899
|
+
const envProject = parseEnvFile(envProjectPath);
|
|
7826
7900
|
const repoSource = env.WILE_REPO_SOURCE || "github";
|
|
7827
7901
|
if (validate) {
|
|
7828
|
-
ensureRequired(env.CODING_AGENT === "CC", "CODING_AGENT must be set to CC in .wile/secrets/.env. Run 'bunx wile config'.");
|
|
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'.");
|
|
7829
7903
|
if (repoSource === "github") {
|
|
7830
7904
|
ensureRequired(Boolean(env.GITHUB_TOKEN), "GITHUB_TOKEN is required in .wile/secrets/.env. Run 'bunx wile config'.");
|
|
7831
7905
|
ensureRequired(Boolean(env.GITHUB_REPO_URL), "GITHUB_REPO_URL is required in .wile/secrets/.env. Run 'bunx wile config'.");
|
|
7832
7906
|
ensureRequired(Boolean(env.BRANCH_NAME), "BRANCH_NAME is required in .wile/secrets/.env. Run 'bunx wile config'.");
|
|
7833
7907
|
}
|
|
7834
|
-
|
|
7908
|
+
if (env.CODING_AGENT === "CC") {
|
|
7909
|
+
ensureRequired(Boolean(env.CC_CLAUDE_CODE_OAUTH_TOKEN || env.CC_ANTHROPIC_API_KEY), "Either CC_CLAUDE_CODE_OAUTH_TOKEN or CC_ANTHROPIC_API_KEY is required in .wile/secrets/.env.");
|
|
7910
|
+
}
|
|
7911
|
+
if (env.CODING_AGENT === "OC") {
|
|
7912
|
+
ensureRequired(Boolean(env.OC_OPENROUTER_API_KEY), "OC_OPENROUTER_API_KEY is required in .wile/secrets/.env for OpenCode.");
|
|
7913
|
+
ensureRequired(Boolean(env.OC_MODEL), "OC_MODEL is required in .wile/secrets/.env for OpenCode.");
|
|
7914
|
+
}
|
|
7835
7915
|
}
|
|
7836
7916
|
return {
|
|
7837
|
-
paths
|
|
7917
|
+
paths: {
|
|
7918
|
+
...paths,
|
|
7919
|
+
envProjectPath
|
|
7920
|
+
},
|
|
7838
7921
|
config: {
|
|
7839
7922
|
codingAgent: env.CODING_AGENT ?? "CC",
|
|
7840
7923
|
githubToken: env.GITHUB_TOKEN ?? "",
|
|
@@ -7845,6 +7928,8 @@ var readWileConfig = (options = {}) => {
|
|
|
7845
7928
|
maxIterations: env.WILE_MAX_ITERATIONS,
|
|
7846
7929
|
ccClaudeCodeOauthToken: env.CC_CLAUDE_CODE_OAUTH_TOKEN,
|
|
7847
7930
|
ccAnthropicApiKey: env.CC_ANTHROPIC_API_KEY,
|
|
7931
|
+
ocOpenrouterApiKey: env.OC_OPENROUTER_API_KEY,
|
|
7932
|
+
ocModel: env.OC_MODEL,
|
|
7848
7933
|
envProject
|
|
7849
7934
|
}
|
|
7850
7935
|
};
|
|
@@ -7924,7 +8009,7 @@ var resolveAgentDir = () => {
|
|
|
7924
8009
|
if (existsSync3(bundledAgentDir)) {
|
|
7925
8010
|
return bundledAgentDir;
|
|
7926
8011
|
}
|
|
7927
|
-
const cliRoot =
|
|
8012
|
+
const cliRoot = resolve2(here, "..", "..", "..");
|
|
7928
8013
|
const agentDir = join3(cliRoot, "agent");
|
|
7929
8014
|
if (!existsSync3(agentDir)) {
|
|
7930
8015
|
throw new Error("Unable to locate packages/agent. Run from the monorepo.");
|
|
@@ -8009,6 +8094,7 @@ var runWile = async (options) => {
|
|
|
8009
8094
|
console.log(`- cwd: ${cwd}`);
|
|
8010
8095
|
console.log(`- INIT_CWD: ${initCwd}`);
|
|
8011
8096
|
console.log(`- WILE_AGENT_DIR: ${process.env.WILE_AGENT_DIR ?? "(unset)"}`);
|
|
8097
|
+
console.log(`- codingAgent: ${config.codingAgent}`);
|
|
8012
8098
|
console.log(`- repoSource: ${config.repoSource}`);
|
|
8013
8099
|
console.log(`- githubRepoUrl: ${config.githubRepoUrl || "(empty)"}`);
|
|
8014
8100
|
console.log(`- branchName: ${config.branchName || "(empty)"}`);
|
|
@@ -8054,7 +8140,7 @@ var runWile = async (options) => {
|
|
|
8054
8140
|
};
|
|
8055
8141
|
|
|
8056
8142
|
// src/cli.ts
|
|
8057
|
-
var packageJsonPath =
|
|
8143
|
+
var packageJsonPath = resolve3(new URL("../package.json", import.meta.url).pathname);
|
|
8058
8144
|
var packageJson = JSON.parse(readFileSync3(packageJsonPath, "utf8"));
|
|
8059
8145
|
var program2 = new Command;
|
|
8060
8146
|
program2.name("wile").description("Autonomous AI coding agent that ships features while you sleep").version(packageJson.version);
|