wile 0.4.16 → 0.4.18
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 -0
- 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 +59 -34
- package/dist/agent/scripts/claude-stream.js +85 -0
- package/dist/agent/scripts/mock-claude.sh +21 -0
- package/dist/agent/scripts/opencode-stream.js +49 -0
- package/dist/agent/scripts/prompt.md +1 -0
- package/dist/agent/scripts/test-additional-instructions.sh +3 -2
- package/dist/agent/scripts/test-iteration-limit.sh +44 -0
- package/dist/agent/scripts/wile.sh +50 -6
- package/dist/cli.js +99 -42
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -25,6 +25,8 @@ This creates:
|
|
|
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
|
+
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.
|
|
28
30
|
|
|
29
31
|
## Run Wile
|
|
30
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
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
set -e
|
|
8
8
|
|
|
9
9
|
echo "══════════════════════════════════════════════════════"
|
|
10
|
-
echo "
|
|
10
|
+
echo " 🌵 WILE - Container Startup"
|
|
11
11
|
echo "══════════════════════════════════════════════════════"
|
|
12
12
|
|
|
13
13
|
if [ "${WILE_TEST:-}" = "true" ]; then
|
|
@@ -67,10 +67,12 @@ NODE
|
|
|
67
67
|
exit 0
|
|
68
68
|
fi
|
|
69
69
|
|
|
70
|
+
CODING_AGENT="${CODING_AGENT:-CC}"
|
|
70
71
|
REPO_SOURCE="${WILE_REPO_SOURCE:-github}"
|
|
71
72
|
LOCAL_REPO_PATH="${WILE_LOCAL_REPO_PATH:-/home/wile/workspace/repo}"
|
|
72
73
|
ADDITIONAL_INSTRUCTIONS_PATH="${WILE_ADDITIONAL_INSTRUCTIONS:-}"
|
|
73
74
|
|
|
75
|
+
echo " Agent: $CODING_AGENT"
|
|
74
76
|
if [ "$REPO_SOURCE" = "local" ]; then
|
|
75
77
|
if [ ! -d "$LOCAL_REPO_PATH" ]; then
|
|
76
78
|
echo "ERROR: WILE_LOCAL_REPO_PATH does not exist: $LOCAL_REPO_PATH"
|
|
@@ -83,52 +85,74 @@ else
|
|
|
83
85
|
: "${GITHUB_TOKEN:?GITHUB_TOKEN is required}"
|
|
84
86
|
fi
|
|
85
87
|
|
|
86
|
-
# Authentication
|
|
87
|
-
if [
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
88
|
+
# Authentication for selected coding agent
|
|
89
|
+
if [ "$CODING_AGENT" = "OC" ]; then
|
|
90
|
+
if [ -z "$OC_OPENROUTER_API_KEY" ]; then
|
|
91
|
+
echo "ERROR: OC_OPENROUTER_API_KEY is required for OpenCode"
|
|
92
|
+
exit 1
|
|
93
|
+
fi
|
|
94
|
+
if [ -z "$OC_MODEL" ]; then
|
|
95
|
+
echo "ERROR: OC_MODEL is required for OpenCode"
|
|
96
|
+
exit 1
|
|
97
|
+
fi
|
|
98
|
+
else
|
|
99
|
+
if [ -z "$CC_CLAUDE_CODE_OAUTH_TOKEN" ] && [ -z "$CC_ANTHROPIC_API_KEY" ]; then
|
|
100
|
+
echo "ERROR: Either CC_CLAUDE_CODE_OAUTH_TOKEN or CC_ANTHROPIC_API_KEY is required"
|
|
101
|
+
echo ""
|
|
102
|
+
echo " CC_CLAUDE_CODE_OAUTH_TOKEN - Uses your Pro/Max subscription (recommended)"
|
|
103
|
+
echo " CC_ANTHROPIC_API_KEY - Uses API credits (pay per token)"
|
|
104
|
+
echo ""
|
|
105
|
+
echo "Run 'claude setup-token' on your local machine to get an OAuth token."
|
|
106
|
+
exit 1
|
|
107
|
+
fi
|
|
95
108
|
fi
|
|
96
109
|
|
|
97
110
|
MAX_ITERATIONS=${MAX_ITERATIONS:-25}
|
|
98
111
|
SCRIPT_DIR="/home/wile/scripts"
|
|
99
112
|
WORKSPACE="/home/wile/workspace"
|
|
100
113
|
|
|
101
|
-
if [ "${WILE_MOCK_CLAUDE:-}" = "true" ]; then
|
|
114
|
+
if [ "${WILE_MOCK_CLAUDE:-}" = "true" ] && [ "$CODING_AGENT" = "CC" ]; then
|
|
102
115
|
echo " Claude: Mocked"
|
|
103
116
|
MOCK_BIN="/home/wile/mock-bin"
|
|
104
117
|
mkdir -p "$MOCK_BIN"
|
|
105
|
-
|
|
106
|
-
#!/bin/sh
|
|
107
|
-
echo "ANSWER: 2"
|
|
108
|
-
echo "<promise>COMPLETE</promise>"
|
|
109
|
-
MOCK
|
|
118
|
+
cp "$SCRIPT_DIR/mock-claude.sh" "$MOCK_BIN/claude"
|
|
110
119
|
chmod +x "$MOCK_BIN/claude"
|
|
111
120
|
export PATH="$MOCK_BIN:$PATH"
|
|
112
121
|
fi
|
|
113
122
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
123
|
+
if [ "$CODING_AGENT" = "OC" ]; then
|
|
124
|
+
echo " Auth: OpenRouter (OpenCode)"
|
|
125
|
+
OPENCODE_DATA_DIR="${XDG_DATA_HOME:-$HOME/.local/share}/opencode"
|
|
126
|
+
mkdir -p "$OPENCODE_DATA_DIR"
|
|
127
|
+
cat > "$OPENCODE_DATA_DIR/auth.json" << OPENCODEAUTH
|
|
128
|
+
{
|
|
129
|
+
"openrouter": {
|
|
130
|
+
"type": "api",
|
|
131
|
+
"key": "$OC_OPENROUTER_API_KEY"
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
OPENCODEAUTH
|
|
135
|
+
chmod 600 "$OPENCODE_DATA_DIR/auth.json"
|
|
136
|
+
export OPENROUTER_API_KEY="$OC_OPENROUTER_API_KEY"
|
|
137
|
+
else
|
|
138
|
+
# Set up Claude Code authentication
|
|
139
|
+
if [ -n "$CC_CLAUDE_CODE_OAUTH_TOKEN" ]; then
|
|
140
|
+
echo " Auth: OAuth (Pro/Max subscription)"
|
|
117
141
|
|
|
118
|
-
|
|
119
|
-
|
|
142
|
+
# Create required directories
|
|
143
|
+
mkdir -p ~/.claude ~/.config/claude
|
|
120
144
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
145
|
+
# Create ~/.claude.json (THE CRITICAL FILE!)
|
|
146
|
+
# Without this, Claude Code thinks it's a fresh install and breaks
|
|
147
|
+
cat > ~/.claude.json << 'CLAUDEJSON'
|
|
124
148
|
{
|
|
125
149
|
"hasCompletedOnboarding": true,
|
|
126
150
|
"theme": "dark"
|
|
127
151
|
}
|
|
128
152
|
CLAUDEJSON
|
|
129
153
|
|
|
130
|
-
|
|
131
|
-
|
|
154
|
+
# Create credentials file with the OAuth token
|
|
155
|
+
cat > ~/.claude/.credentials.json << CREDSJSON
|
|
132
156
|
{
|
|
133
157
|
"claudeAiOauth": {
|
|
134
158
|
"accessToken": "$CC_CLAUDE_CODE_OAUTH_TOKEN",
|
|
@@ -139,14 +163,15 @@ CLAUDEJSON
|
|
|
139
163
|
}
|
|
140
164
|
CREDSJSON
|
|
141
165
|
|
|
142
|
-
|
|
143
|
-
|
|
166
|
+
# Copy to alternate location too
|
|
167
|
+
cp ~/.claude/.credentials.json ~/.config/claude/.credentials.json
|
|
144
168
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
else
|
|
148
|
-
|
|
149
|
-
|
|
169
|
+
# Ensure ANTHROPIC_API_KEY is not set (it overrides OAuth)
|
|
170
|
+
unset ANTHROPIC_API_KEY
|
|
171
|
+
else
|
|
172
|
+
echo " Auth: API Key (credits)"
|
|
173
|
+
export ANTHROPIC_API_KEY="$CC_ANTHROPIC_API_KEY"
|
|
174
|
+
fi
|
|
150
175
|
fi
|
|
151
176
|
|
|
152
177
|
if [ "$REPO_SOURCE" = "local" ]; then
|
|
@@ -161,7 +186,7 @@ echo ""
|
|
|
161
186
|
|
|
162
187
|
# Configure git
|
|
163
188
|
echo "Configuring git..."
|
|
164
|
-
git config --global user.name "
|
|
189
|
+
git config --global user.name "wile"
|
|
165
190
|
git config --global user.email "wile@bot.local"
|
|
166
191
|
git config --global credential.helper store
|
|
167
192
|
|
|
@@ -0,0 +1,85 @@
|
|
|
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 extractText = (content) => {
|
|
14
|
+
if (!Array.isArray(content)) return;
|
|
15
|
+
for (const chunk of content) {
|
|
16
|
+
if (!chunk || typeof chunk !== "object") continue;
|
|
17
|
+
if (chunk.type === "text" && typeof chunk.text === "string") {
|
|
18
|
+
process.stdout.write(chunk.text);
|
|
19
|
+
continue;
|
|
20
|
+
}
|
|
21
|
+
if (chunk.type === "thinking" && typeof chunk.thinking === "string") {
|
|
22
|
+
writeLine(`[thinking] ${chunk.thinking}`);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const extractToolUse = (content) => {
|
|
28
|
+
if (!Array.isArray(content)) return;
|
|
29
|
+
for (const chunk of content) {
|
|
30
|
+
if (!chunk || typeof chunk !== "object") continue;
|
|
31
|
+
if (chunk.type === "tool_use") {
|
|
32
|
+
const toolName = chunk.name ?? "tool";
|
|
33
|
+
const description = chunk.input?.description ?? "";
|
|
34
|
+
const command = chunk.input?.command ?? "";
|
|
35
|
+
if (description && command) {
|
|
36
|
+
writeLine(`[tool] ${toolName}: ${description} (${command})`);
|
|
37
|
+
} else if (command) {
|
|
38
|
+
writeLine(`[tool] ${toolName}: ${command}`);
|
|
39
|
+
} else if (description) {
|
|
40
|
+
writeLine(`[tool] ${toolName}: ${description}`);
|
|
41
|
+
} else {
|
|
42
|
+
writeLine(`[tool] ${toolName}`);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
rl.on("line", (line) => {
|
|
49
|
+
if (!line.trim()) return;
|
|
50
|
+
if (process.env.WILE_STREAM_JSON === "true") {
|
|
51
|
+
writeLine(line);
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
let payload;
|
|
55
|
+
try {
|
|
56
|
+
payload = JSON.parse(line);
|
|
57
|
+
} catch {
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (payload.type === "system" && payload.subtype === "init") {
|
|
62
|
+
const model = payload.model ?? "unknown";
|
|
63
|
+
writeLine(`[system] model: ${model}`);
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (payload.type === "assistant" && payload.message) {
|
|
68
|
+
extractToolUse(payload.message.content);
|
|
69
|
+
extractText(payload.message.content);
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (payload.type === "user" && payload.message?.content) {
|
|
74
|
+
for (const chunk of payload.message.content) {
|
|
75
|
+
if (chunk?.type === "tool_result") {
|
|
76
|
+
writeLine(`[tool-result] ${chunk.tool_use_id ?? "unknown"} ${chunk.is_error ? "error" : "ok"}`);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (payload.type === "result" && payload.result) {
|
|
83
|
+
writeLine(payload.result);
|
|
84
|
+
}
|
|
85
|
+
});
|
|
@@ -0,0 +1,21 @@
|
|
|
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 [ "$COUNT" -eq 0 ]; then
|
|
14
|
+
cat <<'JSON'
|
|
15
|
+
{"type":"assistant","message":{"content":[{"type":"text","text":"ANSWER: 2\n"}]}}
|
|
16
|
+
JSON
|
|
17
|
+
else
|
|
18
|
+
cat <<'JSON'
|
|
19
|
+
{"type":"assistant","message":{"content":[{"type":"text","text":"<promise>COMPLETE</promise>\n"}]}}
|
|
20
|
+
JSON
|
|
21
|
+
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
|
+
});
|
|
@@ -87,6 +87,7 @@ After completing steps 1-8, check if ALL stories in `.wile/prd.json` have `passe
|
|
|
87
87
|
```
|
|
88
88
|
<promise>COMPLETE</promise>
|
|
89
89
|
```
|
|
90
|
+
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
91
|
|
|
91
92
|
**If there are still stories with `passes: false`**, end your response normally. The loop will call you again for the next story.
|
|
92
93
|
|
|
@@ -17,6 +17,7 @@ run_case() {
|
|
|
17
17
|
mkdir -p "$SCRIPT_DIR" "$BIN_DIR"
|
|
18
18
|
|
|
19
19
|
cp /Users/thiagoduarte/Projects/personal/wile/packages/agent/scripts/wile.sh "$SCRIPT_DIR/wile.sh"
|
|
20
|
+
cp /Users/thiagoduarte/Projects/personal/wile/packages/agent/scripts/claude-stream.js "$SCRIPT_DIR/claude-stream.js"
|
|
20
21
|
chmod +x "$SCRIPT_DIR/wile.sh"
|
|
21
22
|
|
|
22
23
|
echo "BASE PROMPT" > "$SCRIPT_DIR/prompt.md"
|
|
@@ -43,10 +44,10 @@ EOF
|
|
|
43
44
|
|
|
44
45
|
CAPTURE="$TMP_DIR/capture.txt"
|
|
45
46
|
|
|
46
|
-
|
|
47
|
+
cat > "$BIN_DIR/claude" <<'EOF'
|
|
47
48
|
#!/bin/sh
|
|
48
49
|
cat > "$CLAUDE_CAPTURE"
|
|
49
|
-
|
|
50
|
+
printf '%s\n' '{"type":"assistant","message":{"content":[{"type":"text","text":"<promise>COMPLETE</promise>\n"}]}}'
|
|
50
51
|
EOF
|
|
51
52
|
chmod +x "$BIN_DIR/claude"
|
|
52
53
|
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
TMP_DIR=$(mktemp -d /tmp/wile-iteration-limit-XXXXXX)
|
|
5
|
+
cleanup() {
|
|
6
|
+
rm -rf "$TMP_DIR"
|
|
7
|
+
}
|
|
8
|
+
trap cleanup EXIT INT TERM
|
|
9
|
+
|
|
10
|
+
SCRIPT_DIR="$TMP_DIR/agent"
|
|
11
|
+
BIN_DIR="$TMP_DIR/bin"
|
|
12
|
+
mkdir -p "$SCRIPT_DIR" "$BIN_DIR"
|
|
13
|
+
|
|
14
|
+
cp /Users/thiagoduarte/Projects/personal/wile/packages/agent/scripts/wile.sh "$SCRIPT_DIR/wile.sh"
|
|
15
|
+
cp /Users/thiagoduarte/Projects/personal/wile/packages/agent/scripts/claude-stream.js "$SCRIPT_DIR/claude-stream.js"
|
|
16
|
+
chmod +x "$SCRIPT_DIR/wile.sh"
|
|
17
|
+
|
|
18
|
+
echo "BASE PROMPT" > "$SCRIPT_DIR/prompt.md"
|
|
19
|
+
|
|
20
|
+
OUTPUT_FILE="$TMP_DIR/output.txt"
|
|
21
|
+
|
|
22
|
+
cat > "$BIN_DIR/claude" <<'EOF'
|
|
23
|
+
#!/bin/sh
|
|
24
|
+
printf '%s\n' '{"type":"assistant","message":{"content":[{"type":"text","text":"working...\n"}]}}'
|
|
25
|
+
EOF
|
|
26
|
+
chmod +x "$BIN_DIR/claude"
|
|
27
|
+
|
|
28
|
+
set +e
|
|
29
|
+
PATH="$BIN_DIR:$PATH" \
|
|
30
|
+
CC_CLAUDE_MODEL="sonnet" \
|
|
31
|
+
"$SCRIPT_DIR/wile.sh" 3 > "$OUTPUT_FILE" 2>&1
|
|
32
|
+
EXIT_CODE=$?
|
|
33
|
+
set -e
|
|
34
|
+
|
|
35
|
+
if [ "$EXIT_CODE" -eq 0 ]; then
|
|
36
|
+
echo "error: expected non-zero exit when max iterations reached" >&2
|
|
37
|
+
exit 1
|
|
38
|
+
fi
|
|
39
|
+
|
|
40
|
+
grep -q "MAX ITERATIONS REACHED (3)" "$OUTPUT_FILE"
|
|
41
|
+
grep -q "Iteration 1 of 3" "$OUTPUT_FILE"
|
|
42
|
+
grep -q "Iteration 3 of 3" "$OUTPUT_FILE"
|
|
43
|
+
|
|
44
|
+
echo "test-iteration-limit: ok"
|
|
@@ -7,17 +7,31 @@
|
|
|
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"
|
|
13
18
|
SETUP_PROMPT_FILE="$SCRIPT_DIR/prompt-setup.md"
|
|
14
19
|
ADDITIONAL_PROMPT_FILE="${WILE_ADDITIONAL_INSTRUCTIONS:-}"
|
|
20
|
+
TEE_TARGET="${WILE_TEE_TARGET:-/dev/stderr}"
|
|
21
|
+
if ! ( : > "$TEE_TARGET" ) 2>/dev/null; then
|
|
22
|
+
TEE_TARGET="/dev/null"
|
|
23
|
+
fi
|
|
15
24
|
|
|
16
25
|
echo "══════════════════════════════════════════════════════"
|
|
17
|
-
echo "
|
|
26
|
+
echo " 🌵 WILE - Autonomous Coding Agent"
|
|
18
27
|
echo "══════════════════════════════════════════════════════"
|
|
28
|
+
echo " Agent: $CODING_AGENT"
|
|
19
29
|
echo " Max iterations: $MAX_ITERATIONS"
|
|
20
|
-
|
|
30
|
+
if [ "$CODING_AGENT" = "OC" ]; then
|
|
31
|
+
echo " Model: $OC_MODEL"
|
|
32
|
+
else
|
|
33
|
+
echo " Model: $CLAUDE_MODEL"
|
|
34
|
+
fi
|
|
21
35
|
echo " Prompt file: $PROMPT_FILE"
|
|
22
36
|
echo "══════════════════════════════════════════════════════"
|
|
23
37
|
echo ""
|
|
@@ -39,6 +53,29 @@ if [ -n "$ADDITIONAL_PROMPT_FILE" ] && [ -f "$ADDITIONAL_PROMPT_FILE" ]; then
|
|
|
39
53
|
fi
|
|
40
54
|
fi
|
|
41
55
|
|
|
56
|
+
run_claude() {
|
|
57
|
+
local prompt_path="$1"
|
|
58
|
+
cat "$prompt_path" \
|
|
59
|
+
| claude --model "$CLAUDE_MODEL" --print --output-format stream-json --verbose --dangerously-skip-permissions \
|
|
60
|
+
| node "$SCRIPT_DIR/claude-stream.js"
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
run_opencode() {
|
|
64
|
+
local prompt_path="$1"
|
|
65
|
+
cat "$prompt_path" \
|
|
66
|
+
| opencode run --format json --model "openrouter/$OC_MODEL" \
|
|
67
|
+
| node "$SCRIPT_DIR/opencode-stream.js"
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
run_agent() {
|
|
71
|
+
local prompt_path="$1"
|
|
72
|
+
if [ "$CODING_AGENT" = "OC" ]; then
|
|
73
|
+
run_opencode "$prompt_path"
|
|
74
|
+
else
|
|
75
|
+
run_claude "$prompt_path"
|
|
76
|
+
fi
|
|
77
|
+
}
|
|
78
|
+
|
|
42
79
|
# ════════════════════════════════════════════════════════════
|
|
43
80
|
# ITERATION 0: Setup
|
|
44
81
|
# ════════════════════════════════════════════════════════════
|
|
@@ -49,7 +86,7 @@ echo "════════════════════════
|
|
|
49
86
|
echo ""
|
|
50
87
|
|
|
51
88
|
if [ -f "$SETUP_PROMPT_FILE" ]; then
|
|
52
|
-
OUTPUT=$(
|
|
89
|
+
OUTPUT=$(run_agent "$SETUP_PROMPT_FILE" | tee "$TEE_TARGET") || true
|
|
53
90
|
|
|
54
91
|
# Check if setup failed critically
|
|
55
92
|
if echo "$OUTPUT" | grep -q "<promise>SETUP_FAILED</promise>"; then
|
|
@@ -80,15 +117,22 @@ for i in $(seq 1 $MAX_ITERATIONS); do
|
|
|
80
117
|
# Pipe prompt to Claude Code
|
|
81
118
|
# --dangerously-skip-permissions allows autonomous operation
|
|
82
119
|
# Capture output while also displaying it (tee to stderr)
|
|
83
|
-
OUTPUT=$(
|
|
120
|
+
OUTPUT=$(run_agent "$PROMPT_FILE" | tee "$TEE_TARGET") || true
|
|
84
121
|
|
|
85
|
-
# Check for completion signal
|
|
86
|
-
|
|
122
|
+
# Check for completion signal (tag must be on its own line; reject backticks/code fences)
|
|
123
|
+
CLEAN_OUTPUT=$(printf '%s' "$OUTPUT" | tr -d '\r' | sed -e 's/[[:space:]]*$//')
|
|
124
|
+
if printf '%s\n' "$CLEAN_OUTPUT" | grep -q -E '^[[:space:]]*<promise>COMPLETE</promise>[[:space:]]*$'; then
|
|
125
|
+
if printf '%s' "$CLEAN_OUTPUT" | grep -F '```' >/dev/null 2>&1; then
|
|
126
|
+
:
|
|
127
|
+
elif printf '%s' "$CLEAN_OUTPUT" | grep -F '`<promise>COMPLETE</promise>`' >/dev/null 2>&1; then
|
|
128
|
+
:
|
|
129
|
+
else
|
|
87
130
|
echo ""
|
|
88
131
|
echo "══════════════════════════════════════════════════════"
|
|
89
132
|
echo " ✅ ALL TASKS COMPLETE"
|
|
90
133
|
echo "══════════════════════════════════════════════════════"
|
|
91
134
|
exit 0
|
|
135
|
+
fi
|
|
92
136
|
fi
|
|
93
137
|
|
|
94
138
|
echo ""
|
package/dist/cli.js
CHANGED
|
@@ -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) => {
|
|
@@ -7624,44 +7625,73 @@ var runConfig = async () => {
|
|
|
7624
7625
|
const agentsPath = join(wileDir, "AGENTS.md");
|
|
7625
7626
|
await mkdir(secretsDir, { recursive: true });
|
|
7626
7627
|
const existingEnv = await readEnvFile(envPath);
|
|
7627
|
-
await prompt({
|
|
7628
|
+
const codingAgentResponse = await prompt({
|
|
7628
7629
|
type: "select",
|
|
7629
7630
|
name: "codingAgent",
|
|
7630
7631
|
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
7632
|
choices: [
|
|
7640
|
-
{ title: "
|
|
7641
|
-
{ title: "
|
|
7633
|
+
{ title: "Claude Code (CC)", value: "CC" },
|
|
7634
|
+
{ title: "OpenCode (OC)", value: "OC" }
|
|
7642
7635
|
],
|
|
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
|
-
],
|
|
7663
|
-
initial: existingEnv.CC_CLAUDE_MODEL === "opus" ? 1 : 0
|
|
7636
|
+
initial: existingEnv.CODING_AGENT === "OC" ? 1 : 0
|
|
7664
7637
|
});
|
|
7638
|
+
const codingAgent = codingAgentResponse.codingAgent;
|
|
7639
|
+
let authMethod = null;
|
|
7640
|
+
let authValueResponse = {};
|
|
7641
|
+
let defaultModelResponse = {};
|
|
7642
|
+
let ocKeyResponse = {};
|
|
7643
|
+
let ocModelResponse = {};
|
|
7644
|
+
if (codingAgent === "CC") {
|
|
7645
|
+
const authDefault = existingEnv.CC_CLAUDE_CODE_OAUTH_TOKEN ? "oauth" : existingEnv.CC_ANTHROPIC_API_KEY ? "apiKey" : "oauth";
|
|
7646
|
+
const authResponse = await prompt({
|
|
7647
|
+
type: "select",
|
|
7648
|
+
name: "authMethod",
|
|
7649
|
+
message: "Claude Code authentication",
|
|
7650
|
+
choices: [
|
|
7651
|
+
{ title: "OAuth token (Pro/Max subscription)", value: "oauth" },
|
|
7652
|
+
{ title: "API key (Anthropic credits)", value: "apiKey" }
|
|
7653
|
+
],
|
|
7654
|
+
initial: authDefault === "apiKey" ? 1 : 0
|
|
7655
|
+
});
|
|
7656
|
+
authMethod = authResponse.authMethod;
|
|
7657
|
+
console.log("");
|
|
7658
|
+
console.log(authMethod === "oauth" ? tips.oauth : tips.apiKey);
|
|
7659
|
+
console.log("");
|
|
7660
|
+
authValueResponse = await prompt({
|
|
7661
|
+
type: "password",
|
|
7662
|
+
name: "authValue",
|
|
7663
|
+
message: authMethod === "oauth" ? "Claude Code OAuth token (press enter to keep existing)" : "Anthropic API key (press enter to keep existing)",
|
|
7664
|
+
initial: authMethod === "oauth" ? existingEnv.CC_CLAUDE_CODE_OAUTH_TOKEN ?? "" : existingEnv.CC_ANTHROPIC_API_KEY ?? ""
|
|
7665
|
+
});
|
|
7666
|
+
defaultModelResponse = await prompt({
|
|
7667
|
+
type: "select",
|
|
7668
|
+
name: "model",
|
|
7669
|
+
message: "Default Claude model",
|
|
7670
|
+
choices: [
|
|
7671
|
+
{ title: "sonnet", value: "sonnet" },
|
|
7672
|
+
{ title: "opus", value: "opus" },
|
|
7673
|
+
{ title: "haiku", value: "haiku" }
|
|
7674
|
+
],
|
|
7675
|
+
initial: existingEnv.CC_CLAUDE_MODEL === "opus" ? 1 : existingEnv.CC_CLAUDE_MODEL === "haiku" ? 2 : 0
|
|
7676
|
+
});
|
|
7677
|
+
} else {
|
|
7678
|
+
console.log("");
|
|
7679
|
+
console.log(tips.openrouter);
|
|
7680
|
+
console.log("");
|
|
7681
|
+
ocKeyResponse = await prompt({
|
|
7682
|
+
type: "password",
|
|
7683
|
+
name: "ocKey",
|
|
7684
|
+
message: "OpenRouter API key (press enter to keep existing)",
|
|
7685
|
+
initial: existingEnv.OC_OPENROUTER_API_KEY ?? ""
|
|
7686
|
+
});
|
|
7687
|
+
ocModelResponse = await prompt({
|
|
7688
|
+
type: "select",
|
|
7689
|
+
name: "ocModel",
|
|
7690
|
+
message: "OpenCode model (OpenRouter)",
|
|
7691
|
+
choices: [{ title: "glm-4.7", value: "glm-4.7" }],
|
|
7692
|
+
initial: existingEnv.OC_MODEL === "glm-4.7" ? 0 : 0
|
|
7693
|
+
});
|
|
7694
|
+
}
|
|
7665
7695
|
const repoSourceResponse = await prompt({
|
|
7666
7696
|
type: "select",
|
|
7667
7697
|
name: "repoSource",
|
|
@@ -7696,23 +7726,39 @@ var runConfig = async () => {
|
|
|
7696
7726
|
message: "Default branch name",
|
|
7697
7727
|
initial: existingEnv.BRANCH_NAME ?? "main"
|
|
7698
7728
|
});
|
|
7729
|
+
const iterationsResponse = await prompt({
|
|
7730
|
+
type: "number",
|
|
7731
|
+
name: "maxIterations",
|
|
7732
|
+
message: "Default max iterations",
|
|
7733
|
+
initial: existingEnv.WILE_MAX_ITERATIONS ? Number(existingEnv.WILE_MAX_ITERATIONS) : 25
|
|
7734
|
+
});
|
|
7735
|
+
const fallbackIterations = existingEnv.WILE_MAX_ITERATIONS ? Number(existingEnv.WILE_MAX_ITERATIONS) : 25;
|
|
7736
|
+
const maxIterations = Number.isFinite(iterationsResponse.maxIterations) && iterationsResponse.maxIterations > 0 ? iterationsResponse.maxIterations : fallbackIterations;
|
|
7699
7737
|
const authFallback = authMethod === "oauth" ? existingEnv.CC_CLAUDE_CODE_OAUTH_TOKEN : existingEnv.CC_ANTHROPIC_API_KEY;
|
|
7700
|
-
const authValue = coalesceValue(authValueResponse.authValue, authFallback);
|
|
7738
|
+
const authValue = codingAgent === "CC" ? coalesceValue(authValueResponse.authValue, authFallback) : undefined;
|
|
7739
|
+
const ocKey = codingAgent === "OC" ? coalesceValue(ocKeyResponse.ocKey, existingEnv.OC_OPENROUTER_API_KEY) : undefined;
|
|
7740
|
+
const ocModel = codingAgent === "OC" ? coalesceValue(ocModelResponse.ocModel, existingEnv.OC_MODEL ?? "glm-4.7") : undefined;
|
|
7701
7741
|
const githubToken = repoSource === "github" ? coalesceValue(githubTokenResponse.githubToken, existingEnv.GITHUB_TOKEN) : existingEnv.GITHUB_TOKEN;
|
|
7702
7742
|
const repoUrl = repoSource === "github" ? coalesceValue(repoResponse.repoUrl, existingEnv.GITHUB_REPO_URL) : existingEnv.GITHUB_REPO_URL;
|
|
7703
7743
|
const branchName = coalesceValue(branchResponse.branchName, existingEnv.BRANCH_NAME ?? "main");
|
|
7704
7744
|
const envLines = [
|
|
7705
|
-
|
|
7745
|
+
`CODING_AGENT=${codingAgent}`,
|
|
7706
7746
|
`WILE_REPO_SOURCE=${repoSource}`,
|
|
7707
7747
|
`GITHUB_TOKEN=${githubToken ?? ""}`,
|
|
7708
7748
|
`GITHUB_REPO_URL=${repoUrl ?? ""}`,
|
|
7709
7749
|
`BRANCH_NAME=${branchName ?? "main"}`,
|
|
7710
|
-
`
|
|
7750
|
+
`WILE_MAX_ITERATIONS=${maxIterations}`
|
|
7711
7751
|
];
|
|
7712
|
-
if (
|
|
7713
|
-
envLines.push(`
|
|
7752
|
+
if (codingAgent === "CC") {
|
|
7753
|
+
envLines.push(`CC_CLAUDE_MODEL=${defaultModelResponse.model}`);
|
|
7754
|
+
if (authMethod === "oauth") {
|
|
7755
|
+
envLines.push(`CC_CLAUDE_CODE_OAUTH_TOKEN=${authValue ?? ""}`);
|
|
7756
|
+
} else {
|
|
7757
|
+
envLines.push(`CC_ANTHROPIC_API_KEY=${authValue ?? ""}`);
|
|
7758
|
+
}
|
|
7714
7759
|
} else {
|
|
7715
|
-
envLines.push(`
|
|
7760
|
+
envLines.push(`OC_MODEL=${ocModel ?? "glm-4.7"}`);
|
|
7761
|
+
envLines.push(`OC_OPENROUTER_API_KEY=${ocKey ?? ""}`);
|
|
7716
7762
|
}
|
|
7717
7763
|
await writeFile(envPath, envLines.join(`
|
|
7718
7764
|
`) + `
|
|
@@ -7815,13 +7861,19 @@ var readWileConfig = (options = {}) => {
|
|
|
7815
7861
|
const envProject = parseEnvFile(paths.envProjectPath);
|
|
7816
7862
|
const repoSource = env.WILE_REPO_SOURCE || "github";
|
|
7817
7863
|
if (validate) {
|
|
7818
|
-
ensureRequired(env.CODING_AGENT === "CC", "CODING_AGENT must be set to CC in .wile/secrets/.env. Run 'bunx wile config'.");
|
|
7864
|
+
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'.");
|
|
7819
7865
|
if (repoSource === "github") {
|
|
7820
7866
|
ensureRequired(Boolean(env.GITHUB_TOKEN), "GITHUB_TOKEN is required in .wile/secrets/.env. Run 'bunx wile config'.");
|
|
7821
7867
|
ensureRequired(Boolean(env.GITHUB_REPO_URL), "GITHUB_REPO_URL is required in .wile/secrets/.env. Run 'bunx wile config'.");
|
|
7822
7868
|
ensureRequired(Boolean(env.BRANCH_NAME), "BRANCH_NAME is required in .wile/secrets/.env. Run 'bunx wile config'.");
|
|
7823
7869
|
}
|
|
7824
|
-
|
|
7870
|
+
if (env.CODING_AGENT === "CC") {
|
|
7871
|
+
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.");
|
|
7872
|
+
}
|
|
7873
|
+
if (env.CODING_AGENT === "OC") {
|
|
7874
|
+
ensureRequired(Boolean(env.OC_OPENROUTER_API_KEY), "OC_OPENROUTER_API_KEY is required in .wile/secrets/.env for OpenCode.");
|
|
7875
|
+
ensureRequired(Boolean(env.OC_MODEL), "OC_MODEL is required in .wile/secrets/.env for OpenCode.");
|
|
7876
|
+
}
|
|
7825
7877
|
}
|
|
7826
7878
|
return {
|
|
7827
7879
|
paths,
|
|
@@ -7832,8 +7884,11 @@ var readWileConfig = (options = {}) => {
|
|
|
7832
7884
|
branchName: env.BRANCH_NAME ?? "",
|
|
7833
7885
|
repoSource,
|
|
7834
7886
|
ccClaudeModel: env.CC_CLAUDE_MODEL,
|
|
7887
|
+
maxIterations: env.WILE_MAX_ITERATIONS,
|
|
7835
7888
|
ccClaudeCodeOauthToken: env.CC_CLAUDE_CODE_OAUTH_TOKEN,
|
|
7836
7889
|
ccAnthropicApiKey: env.CC_ANTHROPIC_API_KEY,
|
|
7890
|
+
ocOpenrouterApiKey: env.OC_OPENROUTER_API_KEY,
|
|
7891
|
+
ocModel: env.OC_MODEL,
|
|
7837
7892
|
envProject
|
|
7838
7893
|
}
|
|
7839
7894
|
};
|
|
@@ -7998,6 +8053,7 @@ var runWile = async (options) => {
|
|
|
7998
8053
|
console.log(`- cwd: ${cwd}`);
|
|
7999
8054
|
console.log(`- INIT_CWD: ${initCwd}`);
|
|
8000
8055
|
console.log(`- WILE_AGENT_DIR: ${process.env.WILE_AGENT_DIR ?? "(unset)"}`);
|
|
8056
|
+
console.log(`- codingAgent: ${config.codingAgent}`);
|
|
8001
8057
|
console.log(`- repoSource: ${config.repoSource}`);
|
|
8002
8058
|
console.log(`- githubRepoUrl: ${config.githubRepoUrl || "(empty)"}`);
|
|
8003
8059
|
console.log(`- branchName: ${config.branchName || "(empty)"}`);
|
|
@@ -8018,8 +8074,9 @@ var runWile = async (options) => {
|
|
|
8018
8074
|
return;
|
|
8019
8075
|
}
|
|
8020
8076
|
const agentDir = resolveAgentDir();
|
|
8077
|
+
const resolvedIterations = options.maxIterations || config.maxIterations || "25";
|
|
8021
8078
|
buildAgentImage(agentDir);
|
|
8022
|
-
const dockerArgs = buildDockerArgs(options, config, paths, cwd);
|
|
8079
|
+
const dockerArgs = buildDockerArgs({ ...options, maxIterations: resolvedIterations }, config, paths, cwd);
|
|
8023
8080
|
const logsDir = join3(paths.wileDir, "logs");
|
|
8024
8081
|
mkdirSync(logsDir, { recursive: true });
|
|
8025
8082
|
const logPath = join3(logsDir, `run-${getTimestamp()}.log`);
|
|
@@ -8049,7 +8106,7 @@ program2.name("wile").description("Autonomous AI coding agent that ships feature
|
|
|
8049
8106
|
program2.command("config").description("Configure the current project for Wile").action(async () => {
|
|
8050
8107
|
await runConfig();
|
|
8051
8108
|
});
|
|
8052
|
-
program2.command("run").description("Run Wile on a repository").option("--repo <repo>", "Repository URL or local path").option("--max-iterations <count>", "Maximum iterations"
|
|
8109
|
+
program2.command("run").description("Run Wile on a repository").option("--repo <repo>", "Repository URL or local path").option("--max-iterations <count>", "Maximum iterations").option("--test", "Run in test mode").option("--debug", "Print debug info before running").action(async (options) => {
|
|
8053
8110
|
await runWile(options);
|
|
8054
8111
|
});
|
|
8055
8112
|
program2.parse(process.argv);
|