wile 0.4.17 → 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 +1 -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 +57 -33
- package/dist/agent/scripts/claude-stream.js +4 -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 +1 -1
- package/dist/agent/scripts/wile.sh +50 -16
- package/dist/cli.js +86 -41
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -26,6 +26,7 @@ This creates:
|
|
|
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
|
@@ -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,53 +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
|
-
cat <<'JSON'
|
|
108
|
-
{"type":"assistant","message":{"content":[{"type":"text","text":"ANSWER: 2\n<promise>COMPLETE</promise>\n"}]}}
|
|
109
|
-
JSON
|
|
110
|
-
MOCK
|
|
118
|
+
cp "$SCRIPT_DIR/mock-claude.sh" "$MOCK_BIN/claude"
|
|
111
119
|
chmod +x "$MOCK_BIN/claude"
|
|
112
120
|
export PATH="$MOCK_BIN:$PATH"
|
|
113
121
|
fi
|
|
114
122
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
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)"
|
|
118
141
|
|
|
119
|
-
|
|
120
|
-
|
|
142
|
+
# Create required directories
|
|
143
|
+
mkdir -p ~/.claude ~/.config/claude
|
|
121
144
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
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'
|
|
125
148
|
{
|
|
126
149
|
"hasCompletedOnboarding": true,
|
|
127
150
|
"theme": "dark"
|
|
128
151
|
}
|
|
129
152
|
CLAUDEJSON
|
|
130
153
|
|
|
131
|
-
|
|
132
|
-
|
|
154
|
+
# Create credentials file with the OAuth token
|
|
155
|
+
cat > ~/.claude/.credentials.json << CREDSJSON
|
|
133
156
|
{
|
|
134
157
|
"claudeAiOauth": {
|
|
135
158
|
"accessToken": "$CC_CLAUDE_CODE_OAUTH_TOKEN",
|
|
@@ -140,14 +163,15 @@ CLAUDEJSON
|
|
|
140
163
|
}
|
|
141
164
|
CREDSJSON
|
|
142
165
|
|
|
143
|
-
|
|
144
|
-
|
|
166
|
+
# Copy to alternate location too
|
|
167
|
+
cp ~/.claude/.credentials.json ~/.config/claude/.credentials.json
|
|
145
168
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
else
|
|
149
|
-
|
|
150
|
-
|
|
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
|
|
151
175
|
fi
|
|
152
176
|
|
|
153
177
|
if [ "$REPO_SOURCE" = "local" ]; then
|
|
@@ -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
|
|
|
@@ -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
|
|
|
@@ -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
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,12 +86,7 @@ echo "════════════════════════
|
|
|
49
86
|
echo ""
|
|
50
87
|
|
|
51
88
|
if [ -f "$SETUP_PROMPT_FILE" ]; then
|
|
52
|
-
OUTPUT=$(
|
|
53
|
-
cat "$SETUP_PROMPT_FILE" \
|
|
54
|
-
| claude --model "$CLAUDE_MODEL" --print --output-format stream-json --verbose --dangerously-skip-permissions \
|
|
55
|
-
| node "$SCRIPT_DIR/claude-stream.js" \
|
|
56
|
-
| tee /dev/stderr
|
|
57
|
-
) || true
|
|
89
|
+
OUTPUT=$(run_agent "$SETUP_PROMPT_FILE" | tee "$TEE_TARGET") || true
|
|
58
90
|
|
|
59
91
|
# Check if setup failed critically
|
|
60
92
|
if echo "$OUTPUT" | grep -q "<promise>SETUP_FAILED</promise>"; then
|
|
@@ -85,20 +117,22 @@ for i in $(seq 1 $MAX_ITERATIONS); do
|
|
|
85
117
|
# Pipe prompt to Claude Code
|
|
86
118
|
# --dangerously-skip-permissions allows autonomous operation
|
|
87
119
|
# Capture output while also displaying it (tee to stderr)
|
|
88
|
-
OUTPUT=$(
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
120
|
+
OUTPUT=$(run_agent "$PROMPT_FILE" | tee "$TEE_TARGET") || true
|
|
121
|
+
|
|
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
|
|
97
130
|
echo ""
|
|
98
131
|
echo "══════════════════════════════════════════════════════"
|
|
99
132
|
echo " ✅ ALL TASKS COMPLETE"
|
|
100
133
|
echo "══════════════════════════════════════════════════════"
|
|
101
134
|
exit 0
|
|
135
|
+
fi
|
|
102
136
|
fi
|
|
103
137
|
|
|
104
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,45 +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
|
-
{ title: "haiku", value: "haiku" }
|
|
7663
|
-
],
|
|
7664
|
-
initial: existingEnv.CC_CLAUDE_MODEL === "opus" ? 1 : existingEnv.CC_CLAUDE_MODEL === "haiku" ? 2 : 0
|
|
7636
|
+
initial: existingEnv.CODING_AGENT === "OC" ? 1 : 0
|
|
7665
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
|
+
}
|
|
7666
7695
|
const repoSourceResponse = await prompt({
|
|
7667
7696
|
type: "select",
|
|
7668
7697
|
name: "repoSource",
|
|
@@ -7706,23 +7735,30 @@ var runConfig = async () => {
|
|
|
7706
7735
|
const fallbackIterations = existingEnv.WILE_MAX_ITERATIONS ? Number(existingEnv.WILE_MAX_ITERATIONS) : 25;
|
|
7707
7736
|
const maxIterations = Number.isFinite(iterationsResponse.maxIterations) && iterationsResponse.maxIterations > 0 ? iterationsResponse.maxIterations : fallbackIterations;
|
|
7708
7737
|
const authFallback = authMethod === "oauth" ? existingEnv.CC_CLAUDE_CODE_OAUTH_TOKEN : existingEnv.CC_ANTHROPIC_API_KEY;
|
|
7709
|
-
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;
|
|
7710
7741
|
const githubToken = repoSource === "github" ? coalesceValue(githubTokenResponse.githubToken, existingEnv.GITHUB_TOKEN) : existingEnv.GITHUB_TOKEN;
|
|
7711
7742
|
const repoUrl = repoSource === "github" ? coalesceValue(repoResponse.repoUrl, existingEnv.GITHUB_REPO_URL) : existingEnv.GITHUB_REPO_URL;
|
|
7712
7743
|
const branchName = coalesceValue(branchResponse.branchName, existingEnv.BRANCH_NAME ?? "main");
|
|
7713
7744
|
const envLines = [
|
|
7714
|
-
|
|
7745
|
+
`CODING_AGENT=${codingAgent}`,
|
|
7715
7746
|
`WILE_REPO_SOURCE=${repoSource}`,
|
|
7716
7747
|
`GITHUB_TOKEN=${githubToken ?? ""}`,
|
|
7717
7748
|
`GITHUB_REPO_URL=${repoUrl ?? ""}`,
|
|
7718
7749
|
`BRANCH_NAME=${branchName ?? "main"}`,
|
|
7719
|
-
`CC_CLAUDE_MODEL=${defaultModelResponse.model}`,
|
|
7720
7750
|
`WILE_MAX_ITERATIONS=${maxIterations}`
|
|
7721
7751
|
];
|
|
7722
|
-
if (
|
|
7723
|
-
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
|
+
}
|
|
7724
7759
|
} else {
|
|
7725
|
-
envLines.push(`
|
|
7760
|
+
envLines.push(`OC_MODEL=${ocModel ?? "glm-4.7"}`);
|
|
7761
|
+
envLines.push(`OC_OPENROUTER_API_KEY=${ocKey ?? ""}`);
|
|
7726
7762
|
}
|
|
7727
7763
|
await writeFile(envPath, envLines.join(`
|
|
7728
7764
|
`) + `
|
|
@@ -7825,13 +7861,19 @@ var readWileConfig = (options = {}) => {
|
|
|
7825
7861
|
const envProject = parseEnvFile(paths.envProjectPath);
|
|
7826
7862
|
const repoSource = env.WILE_REPO_SOURCE || "github";
|
|
7827
7863
|
if (validate) {
|
|
7828
|
-
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'.");
|
|
7829
7865
|
if (repoSource === "github") {
|
|
7830
7866
|
ensureRequired(Boolean(env.GITHUB_TOKEN), "GITHUB_TOKEN is required in .wile/secrets/.env. Run 'bunx wile config'.");
|
|
7831
7867
|
ensureRequired(Boolean(env.GITHUB_REPO_URL), "GITHUB_REPO_URL is required in .wile/secrets/.env. Run 'bunx wile config'.");
|
|
7832
7868
|
ensureRequired(Boolean(env.BRANCH_NAME), "BRANCH_NAME is required in .wile/secrets/.env. Run 'bunx wile config'.");
|
|
7833
7869
|
}
|
|
7834
|
-
|
|
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
|
+
}
|
|
7835
7877
|
}
|
|
7836
7878
|
return {
|
|
7837
7879
|
paths,
|
|
@@ -7845,6 +7887,8 @@ var readWileConfig = (options = {}) => {
|
|
|
7845
7887
|
maxIterations: env.WILE_MAX_ITERATIONS,
|
|
7846
7888
|
ccClaudeCodeOauthToken: env.CC_CLAUDE_CODE_OAUTH_TOKEN,
|
|
7847
7889
|
ccAnthropicApiKey: env.CC_ANTHROPIC_API_KEY,
|
|
7890
|
+
ocOpenrouterApiKey: env.OC_OPENROUTER_API_KEY,
|
|
7891
|
+
ocModel: env.OC_MODEL,
|
|
7848
7892
|
envProject
|
|
7849
7893
|
}
|
|
7850
7894
|
};
|
|
@@ -8009,6 +8053,7 @@ var runWile = async (options) => {
|
|
|
8009
8053
|
console.log(`- cwd: ${cwd}`);
|
|
8010
8054
|
console.log(`- INIT_CWD: ${initCwd}`);
|
|
8011
8055
|
console.log(`- WILE_AGENT_DIR: ${process.env.WILE_AGENT_DIR ?? "(unset)"}`);
|
|
8056
|
+
console.log(`- codingAgent: ${config.codingAgent}`);
|
|
8012
8057
|
console.log(`- repoSource: ${config.repoSource}`);
|
|
8013
8058
|
console.log(`- githubRepoUrl: ${config.githubRepoUrl || "(empty)"}`);
|
|
8014
8059
|
console.log(`- branchName: ${config.branchName || "(empty)"}`);
|