wile 0.4.16 → 0.4.17
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/entrypoint.sh +5 -4
- package/dist/agent/scripts/claude-stream.js +81 -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 +13 -3
- package/dist/cli.js +17 -5
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -25,6 +25,7 @@ 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).
|
|
28
29
|
|
|
29
30
|
## Run Wile
|
|
30
31
|
|
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
|
|
@@ -104,8 +104,9 @@ if [ "${WILE_MOCK_CLAUDE:-}" = "true" ]; then
|
|
|
104
104
|
mkdir -p "$MOCK_BIN"
|
|
105
105
|
cat > "$MOCK_BIN/claude" << 'MOCK'
|
|
106
106
|
#!/bin/sh
|
|
107
|
-
|
|
108
|
-
|
|
107
|
+
cat <<'JSON'
|
|
108
|
+
{"type":"assistant","message":{"content":[{"type":"text","text":"ANSWER: 2\n<promise>COMPLETE</promise>\n"}]}}
|
|
109
|
+
JSON
|
|
109
110
|
MOCK
|
|
110
111
|
chmod +x "$MOCK_BIN/claude"
|
|
111
112
|
export PATH="$MOCK_BIN:$PATH"
|
|
@@ -161,7 +162,7 @@ echo ""
|
|
|
161
162
|
|
|
162
163
|
# Configure git
|
|
163
164
|
echo "Configuring git..."
|
|
164
|
-
git config --global user.name "
|
|
165
|
+
git config --global user.name "wile"
|
|
165
166
|
git config --global user.email "wile@bot.local"
|
|
166
167
|
git config --global credential.helper store
|
|
167
168
|
|
|
@@ -0,0 +1,81 @@
|
|
|
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
|
+
let payload;
|
|
51
|
+
try {
|
|
52
|
+
payload = JSON.parse(line);
|
|
53
|
+
} catch {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (payload.type === "system" && payload.subtype === "init") {
|
|
58
|
+
const model = payload.model ?? "unknown";
|
|
59
|
+
writeLine(`[system] model: ${model}`);
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (payload.type === "assistant" && payload.message) {
|
|
64
|
+
extractToolUse(payload.message.content);
|
|
65
|
+
extractText(payload.message.content);
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (payload.type === "user" && payload.message?.content) {
|
|
70
|
+
for (const chunk of payload.message.content) {
|
|
71
|
+
if (chunk?.type === "tool_result") {
|
|
72
|
+
writeLine(`[tool-result] ${chunk.tool_use_id ?? "unknown"} ${chunk.is_error ? "error" : "ok"}`);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (payload.type === "result" && payload.result) {
|
|
79
|
+
writeLine(payload.result);
|
|
80
|
+
}
|
|
81
|
+
});
|
|
@@ -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"
|
|
@@ -14,7 +14,7 @@ SETUP_PROMPT_FILE="$SCRIPT_DIR/prompt-setup.md"
|
|
|
14
14
|
ADDITIONAL_PROMPT_FILE="${WILE_ADDITIONAL_INSTRUCTIONS:-}"
|
|
15
15
|
|
|
16
16
|
echo "══════════════════════════════════════════════════════"
|
|
17
|
-
echo "
|
|
17
|
+
echo " 🌵 WILE - Autonomous Coding Agent"
|
|
18
18
|
echo "══════════════════════════════════════════════════════"
|
|
19
19
|
echo " Max iterations: $MAX_ITERATIONS"
|
|
20
20
|
echo " Model: $CLAUDE_MODEL"
|
|
@@ -49,7 +49,12 @@ echo "════════════════════════
|
|
|
49
49
|
echo ""
|
|
50
50
|
|
|
51
51
|
if [ -f "$SETUP_PROMPT_FILE" ]; then
|
|
52
|
-
OUTPUT=$(
|
|
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
|
|
53
58
|
|
|
54
59
|
# Check if setup failed critically
|
|
55
60
|
if echo "$OUTPUT" | grep -q "<promise>SETUP_FAILED</promise>"; then
|
|
@@ -80,7 +85,12 @@ for i in $(seq 1 $MAX_ITERATIONS); do
|
|
|
80
85
|
# Pipe prompt to Claude Code
|
|
81
86
|
# --dangerously-skip-permissions allows autonomous operation
|
|
82
87
|
# Capture output while also displaying it (tee to stderr)
|
|
83
|
-
OUTPUT=$(
|
|
88
|
+
OUTPUT=$(
|
|
89
|
+
cat "$PROMPT_FILE" \
|
|
90
|
+
| claude --model "$CLAUDE_MODEL" --print --output-format stream-json --verbose --dangerously-skip-permissions \
|
|
91
|
+
| node "$SCRIPT_DIR/claude-stream.js" \
|
|
92
|
+
| tee /dev/stderr
|
|
93
|
+
) || true
|
|
84
94
|
|
|
85
95
|
# Check for completion signal
|
|
86
96
|
if echo "$OUTPUT" | grep -q "<promise>COMPLETE</promise>"; then
|
package/dist/cli.js
CHANGED
|
@@ -7658,9 +7658,10 @@ var runConfig = async () => {
|
|
|
7658
7658
|
message: "Default Claude model",
|
|
7659
7659
|
choices: [
|
|
7660
7660
|
{ title: "sonnet", value: "sonnet" },
|
|
7661
|
-
{ title: "opus", value: "opus" }
|
|
7661
|
+
{ title: "opus", value: "opus" },
|
|
7662
|
+
{ title: "haiku", value: "haiku" }
|
|
7662
7663
|
],
|
|
7663
|
-
initial: existingEnv.CC_CLAUDE_MODEL === "opus" ? 1 : 0
|
|
7664
|
+
initial: existingEnv.CC_CLAUDE_MODEL === "opus" ? 1 : existingEnv.CC_CLAUDE_MODEL === "haiku" ? 2 : 0
|
|
7664
7665
|
});
|
|
7665
7666
|
const repoSourceResponse = await prompt({
|
|
7666
7667
|
type: "select",
|
|
@@ -7696,6 +7697,14 @@ var runConfig = async () => {
|
|
|
7696
7697
|
message: "Default branch name",
|
|
7697
7698
|
initial: existingEnv.BRANCH_NAME ?? "main"
|
|
7698
7699
|
});
|
|
7700
|
+
const iterationsResponse = await prompt({
|
|
7701
|
+
type: "number",
|
|
7702
|
+
name: "maxIterations",
|
|
7703
|
+
message: "Default max iterations",
|
|
7704
|
+
initial: existingEnv.WILE_MAX_ITERATIONS ? Number(existingEnv.WILE_MAX_ITERATIONS) : 25
|
|
7705
|
+
});
|
|
7706
|
+
const fallbackIterations = existingEnv.WILE_MAX_ITERATIONS ? Number(existingEnv.WILE_MAX_ITERATIONS) : 25;
|
|
7707
|
+
const maxIterations = Number.isFinite(iterationsResponse.maxIterations) && iterationsResponse.maxIterations > 0 ? iterationsResponse.maxIterations : fallbackIterations;
|
|
7699
7708
|
const authFallback = authMethod === "oauth" ? existingEnv.CC_CLAUDE_CODE_OAUTH_TOKEN : existingEnv.CC_ANTHROPIC_API_KEY;
|
|
7700
7709
|
const authValue = coalesceValue(authValueResponse.authValue, authFallback);
|
|
7701
7710
|
const githubToken = repoSource === "github" ? coalesceValue(githubTokenResponse.githubToken, existingEnv.GITHUB_TOKEN) : existingEnv.GITHUB_TOKEN;
|
|
@@ -7707,7 +7716,8 @@ var runConfig = async () => {
|
|
|
7707
7716
|
`GITHUB_TOKEN=${githubToken ?? ""}`,
|
|
7708
7717
|
`GITHUB_REPO_URL=${repoUrl ?? ""}`,
|
|
7709
7718
|
`BRANCH_NAME=${branchName ?? "main"}`,
|
|
7710
|
-
`CC_CLAUDE_MODEL=${defaultModelResponse.model}
|
|
7719
|
+
`CC_CLAUDE_MODEL=${defaultModelResponse.model}`,
|
|
7720
|
+
`WILE_MAX_ITERATIONS=${maxIterations}`
|
|
7711
7721
|
];
|
|
7712
7722
|
if (authMethod === "oauth") {
|
|
7713
7723
|
envLines.push(`CC_CLAUDE_CODE_OAUTH_TOKEN=${authValue ?? ""}`);
|
|
@@ -7832,6 +7842,7 @@ var readWileConfig = (options = {}) => {
|
|
|
7832
7842
|
branchName: env.BRANCH_NAME ?? "",
|
|
7833
7843
|
repoSource,
|
|
7834
7844
|
ccClaudeModel: env.CC_CLAUDE_MODEL,
|
|
7845
|
+
maxIterations: env.WILE_MAX_ITERATIONS,
|
|
7835
7846
|
ccClaudeCodeOauthToken: env.CC_CLAUDE_CODE_OAUTH_TOKEN,
|
|
7836
7847
|
ccAnthropicApiKey: env.CC_ANTHROPIC_API_KEY,
|
|
7837
7848
|
envProject
|
|
@@ -8018,8 +8029,9 @@ var runWile = async (options) => {
|
|
|
8018
8029
|
return;
|
|
8019
8030
|
}
|
|
8020
8031
|
const agentDir = resolveAgentDir();
|
|
8032
|
+
const resolvedIterations = options.maxIterations || config.maxIterations || "25";
|
|
8021
8033
|
buildAgentImage(agentDir);
|
|
8022
|
-
const dockerArgs = buildDockerArgs(options, config, paths, cwd);
|
|
8034
|
+
const dockerArgs = buildDockerArgs({ ...options, maxIterations: resolvedIterations }, config, paths, cwd);
|
|
8023
8035
|
const logsDir = join3(paths.wileDir, "logs");
|
|
8024
8036
|
mkdirSync(logsDir, { recursive: true });
|
|
8025
8037
|
const logPath = join3(logsDir, `run-${getTimestamp()}.log`);
|
|
@@ -8049,7 +8061,7 @@ program2.name("wile").description("Autonomous AI coding agent that ships feature
|
|
|
8049
8061
|
program2.command("config").description("Configure the current project for Wile").action(async () => {
|
|
8050
8062
|
await runConfig();
|
|
8051
8063
|
});
|
|
8052
|
-
program2.command("run").description("Run Wile on a repository").option("--repo <repo>", "Repository URL or local path").option("--max-iterations <count>", "Maximum iterations"
|
|
8064
|
+
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
8065
|
await runWile(options);
|
|
8054
8066
|
});
|
|
8055
8067
|
program2.parse(process.argv);
|