wile 0.8.0 → 1.0.1

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.
Files changed (31) hide show
  1. package/dist/agent/Dockerfile +1 -1
  2. package/dist/agent/README.md +20 -20
  3. package/dist/agent/entrypoint.sh +33 -21
  4. package/dist/agent/scripts/claude-stream.ts +159 -0
  5. package/dist/agent/scripts/codex-stream.ts +167 -0
  6. package/dist/agent/scripts/gemini-stream.ts +97 -0
  7. package/dist/agent/scripts/mock-claude.sh +48 -21
  8. package/dist/agent/scripts/mock-codex.sh +48 -21
  9. package/dist/agent/scripts/mock-gemini.sh +48 -21
  10. package/dist/agent/scripts/opencode-stream.ts +93 -0
  11. package/dist/agent/scripts/prompt-compact.md +36 -34
  12. package/dist/agent/scripts/prompt-preflight.md +0 -7
  13. package/dist/agent/scripts/prompt.md +26 -24
  14. package/dist/agent/scripts/test-additional-instructions.sh +4 -2
  15. package/dist/agent/scripts/test-env-project-docker.sh +5 -4
  16. package/dist/agent/scripts/test-iteration-limit.sh +4 -2
  17. package/dist/agent/scripts/test-prd-validation-docker.sh +151 -0
  18. package/dist/agent/scripts/test-preflight-claude-docker.sh +5 -4
  19. package/dist/agent/scripts/test-preflight-docker.sh +16 -13
  20. package/dist/agent/scripts/validate-compact.ts +134 -0
  21. package/dist/agent/scripts/validate-prd.ts +280 -0
  22. package/dist/agent/scripts/wile-compact.sh +6 -6
  23. package/dist/agent/scripts/wile-preflight.sh +4 -4
  24. package/dist/agent/scripts/wile.sh +4 -4
  25. package/dist/cli.js +236 -58
  26. package/package.json +10 -1
  27. package/dist/agent/scripts/claude-stream.js +0 -88
  28. package/dist/agent/scripts/codex-stream.js +0 -125
  29. package/dist/agent/scripts/gemini-stream.js +0 -63
  30. package/dist/agent/scripts/opencode-stream.js +0 -52
  31. package/dist/agent/scripts/validate-compact.js +0 -135
@@ -8,26 +8,53 @@ const fs = require("fs");
8
8
  const prdPath = ".wile/prd.json";
9
9
  const progressPath = ".wile/progress.txt";
10
10
  const prd = JSON.parse(fs.readFileSync(prdPath, "utf8"));
11
- const stories = Array.isArray(prd.userStories) ? prd.userStories : [];
12
- const firstStory = stories[0] || {};
13
- const lastStory = stories[stories.length - 1] || {};
14
- const priority = typeof firstStory.priority === "number" ? firstStory.priority : 1;
15
- const taskIds = `From ${firstStory.id || "TASK-001"} to ${lastStory.id || "TASK-001"}`;
16
-
17
- const compactStory = {
18
- id: "GROUP-001",
19
- title: "summary of everything done here",
20
- tasks: [
21
- "High level of what was accomplished here",
22
- "Should NOT have all tasks in here, should be very summarized"
23
- ],
24
- taskIds,
25
- priority,
26
- passes: true,
27
- notes: "Don't repeat task ids when starting the next one."
28
- };
29
-
30
- fs.writeFileSync(prdPath, JSON.stringify({ userStories: [compactStory] }, null, 2) + "\n");
11
+ const stories = Array.isArray(prd.stories) ? prd.stories : [];
12
+ const pendingStories = stories.filter((story) => story.status === "pending");
13
+ const doneStories = stories.filter((story) => story.status === "done");
14
+ const requiredDoneIds = new Set();
15
+ for (const story of pendingStories) {
16
+ const deps = Array.isArray(story.dependsOn) ? story.dependsOn : [];
17
+ for (const depId of deps) {
18
+ requiredDoneIds.add(depId);
19
+ }
20
+ }
21
+ const retainedDoneStories = doneStories.filter((story) => requiredDoneIds.has(story.id));
22
+ const compactableDoneStories = doneStories.filter((story) => !requiredDoneIds.has(story.id));
23
+ const reservedIds = new Set(stories.map((story) => story.id));
24
+ for (const story of stories) {
25
+ const priorCompacted = Array.isArray(story.compactedFrom) ? story.compactedFrom : [];
26
+ for (const compactedId of priorCompacted) {
27
+ reservedIds.add(compactedId);
28
+ }
29
+ }
30
+ const summaryId = Math.max(0, ...reservedIds) + 1;
31
+
32
+ const nextStories = [...pendingStories, ...retainedDoneStories];
33
+ if (compactableDoneStories.length > 0) {
34
+ const compactedFrom = [
35
+ ...new Set(
36
+ compactableDoneStories.flatMap((story) => {
37
+ const priorCompacted = Array.isArray(story.compactedFrom) ? story.compactedFrom : [];
38
+ return [story.id, ...priorCompacted];
39
+ })
40
+ )
41
+ ].sort((a, b) => a - b);
42
+
43
+ nextStories.push({
44
+ id: summaryId,
45
+ title: "[COMPACT] Completed stories summary",
46
+ description: "Compacted completed stories into a high-level summary entry.",
47
+ acceptanceCriteria: [
48
+ "Historical summary for compacted completed work.",
49
+ "Pending stories were preserved unchanged."
50
+ ],
51
+ dependsOn: [],
52
+ compactedFrom,
53
+ status: "done"
54
+ });
55
+ }
56
+
57
+ fs.writeFileSync(prdPath, JSON.stringify({ stories: nextStories }, null, 2) + "\n");
31
58
 
32
59
  const progressLines = [
33
60
  "# Wile Progress Log",
@@ -46,7 +73,7 @@ fs.writeFileSync(progressPath, progressLines.join("\n"));
46
73
  NODE
47
74
 
48
75
  cat <<'JSON'
49
- {"type":"assistant","message":{"content":[{"type":"text","text":"{\"id\":\"GROUP-001\",\"title\":\"summary of everything done here\",\"tasks\":[\"High level of what was accomplished here\",\"Should NOT have all tasks in here, should be very summarized\"],\"taskIds\":\"From TASK-001 to TASK-029\",\"priority\":1,\"passes\":true,\"notes\":\"Don't repeat task ids when starting the next one.\"}\n"}]}}
76
+ {"type":"assistant","message":{"content":[{"type":"text","text":"{\"summaryStoryId\":999,\"summaryTitle\":\"[COMPACT] Completed stories summary\"}\n"}]}}
50
77
  JSON
51
78
  exit 0
52
79
  fi
@@ -8,26 +8,53 @@ const fs = require("fs");
8
8
  const prdPath = ".wile/prd.json";
9
9
  const progressPath = ".wile/progress.txt";
10
10
  const prd = JSON.parse(fs.readFileSync(prdPath, "utf8"));
11
- const stories = Array.isArray(prd.userStories) ? prd.userStories : [];
12
- const firstStory = stories[0] || {};
13
- const lastStory = stories[stories.length - 1] || {};
14
- const priority = typeof firstStory.priority === "number" ? firstStory.priority : 1;
15
- const taskIds = `From ${firstStory.id || "TASK-001"} to ${lastStory.id || "TASK-001"}`;
16
-
17
- const compactStory = {
18
- id: "GROUP-001",
19
- title: "summary of everything done here",
20
- tasks: [
21
- "High level of what was accomplished here",
22
- "Should NOT have all tasks in here, should be very summarized"
23
- ],
24
- taskIds,
25
- priority,
26
- passes: true,
27
- notes: "Don't repeat task ids when starting the next one."
28
- };
29
-
30
- fs.writeFileSync(prdPath, JSON.stringify({ userStories: [compactStory] }, null, 2) + "\n");
11
+ const stories = Array.isArray(prd.stories) ? prd.stories : [];
12
+ const pendingStories = stories.filter((story) => story.status === "pending");
13
+ const doneStories = stories.filter((story) => story.status === "done");
14
+ const requiredDoneIds = new Set();
15
+ for (const story of pendingStories) {
16
+ const deps = Array.isArray(story.dependsOn) ? story.dependsOn : [];
17
+ for (const depId of deps) {
18
+ requiredDoneIds.add(depId);
19
+ }
20
+ }
21
+ const retainedDoneStories = doneStories.filter((story) => requiredDoneIds.has(story.id));
22
+ const compactableDoneStories = doneStories.filter((story) => !requiredDoneIds.has(story.id));
23
+ const reservedIds = new Set(stories.map((story) => story.id));
24
+ for (const story of stories) {
25
+ const priorCompacted = Array.isArray(story.compactedFrom) ? story.compactedFrom : [];
26
+ for (const compactedId of priorCompacted) {
27
+ reservedIds.add(compactedId);
28
+ }
29
+ }
30
+ const summaryId = Math.max(0, ...reservedIds) + 1;
31
+
32
+ const nextStories = [...pendingStories, ...retainedDoneStories];
33
+ if (compactableDoneStories.length > 0) {
34
+ const compactedFrom = [
35
+ ...new Set(
36
+ compactableDoneStories.flatMap((story) => {
37
+ const priorCompacted = Array.isArray(story.compactedFrom) ? story.compactedFrom : [];
38
+ return [story.id, ...priorCompacted];
39
+ })
40
+ )
41
+ ].sort((a, b) => a - b);
42
+
43
+ nextStories.push({
44
+ id: summaryId,
45
+ title: "[COMPACT] Completed stories summary",
46
+ description: "Compacted completed stories into a high-level summary entry.",
47
+ acceptanceCriteria: [
48
+ "Historical summary for compacted completed work.",
49
+ "Pending stories were preserved unchanged."
50
+ ],
51
+ dependsOn: [],
52
+ compactedFrom,
53
+ status: "done"
54
+ });
55
+ }
56
+
57
+ fs.writeFileSync(prdPath, JSON.stringify({ stories: nextStories }, null, 2) + "\n");
31
58
 
32
59
  const progressLines = [
33
60
  "# Wile Progress Log",
@@ -46,7 +73,7 @@ fs.writeFileSync(progressPath, progressLines.join("\n"));
46
73
  NODE
47
74
 
48
75
  cat <<'JSON'
49
- {"type":"item.completed","item":{"id":"item_1","type":"agent_message","text":"{\"id\":\"GROUP-001\",\"title\":\"summary of everything done here\",\"tasks\":[\"High level of what was accomplished here\",\"Should NOT have all tasks in here, should be very summarized\"],\"taskIds\":\"From TASK-001 to TASK-029\",\"priority\":1,\"passes\":true,\"notes\":\"Don't repeat task ids when starting the next one.\"}\n"}}
76
+ {"type":"item.completed","item":{"id":"item_1","type":"agent_message","text":"{\"summaryStoryId\":999,\"summaryTitle\":\"[COMPACT] Completed stories summary\"}\n"}}
50
77
  JSON
51
78
  exit 0
52
79
  fi
@@ -8,26 +8,53 @@ const fs = require("fs");
8
8
  const prdPath = ".wile/prd.json";
9
9
  const progressPath = ".wile/progress.txt";
10
10
  const prd = JSON.parse(fs.readFileSync(prdPath, "utf8"));
11
- const stories = Array.isArray(prd.userStories) ? prd.userStories : [];
12
- const firstStory = stories[0] || {};
13
- const lastStory = stories[stories.length - 1] || {};
14
- const priority = typeof firstStory.priority === "number" ? firstStory.priority : 1;
15
- const taskIds = `From ${firstStory.id || "TASK-001"} to ${lastStory.id || "TASK-001"}`;
16
-
17
- const compactStory = {
18
- id: "GROUP-001",
19
- title: "summary of everything done here",
20
- tasks: [
21
- "High level of what was accomplished here",
22
- "Should NOT have all tasks in here, should be very summarized"
23
- ],
24
- taskIds,
25
- priority,
26
- passes: true,
27
- notes: "Don't repeat task ids when starting the next one."
28
- };
29
-
30
- fs.writeFileSync(prdPath, JSON.stringify({ userStories: [compactStory] }, null, 2) + "\n");
11
+ const stories = Array.isArray(prd.stories) ? prd.stories : [];
12
+ const pendingStories = stories.filter((story) => story.status === "pending");
13
+ const doneStories = stories.filter((story) => story.status === "done");
14
+ const requiredDoneIds = new Set();
15
+ for (const story of pendingStories) {
16
+ const deps = Array.isArray(story.dependsOn) ? story.dependsOn : [];
17
+ for (const depId of deps) {
18
+ requiredDoneIds.add(depId);
19
+ }
20
+ }
21
+ const retainedDoneStories = doneStories.filter((story) => requiredDoneIds.has(story.id));
22
+ const compactableDoneStories = doneStories.filter((story) => !requiredDoneIds.has(story.id));
23
+ const reservedIds = new Set(stories.map((story) => story.id));
24
+ for (const story of stories) {
25
+ const priorCompacted = Array.isArray(story.compactedFrom) ? story.compactedFrom : [];
26
+ for (const compactedId of priorCompacted) {
27
+ reservedIds.add(compactedId);
28
+ }
29
+ }
30
+ const summaryId = Math.max(0, ...reservedIds) + 1;
31
+
32
+ const nextStories = [...pendingStories, ...retainedDoneStories];
33
+ if (compactableDoneStories.length > 0) {
34
+ const compactedFrom = [
35
+ ...new Set(
36
+ compactableDoneStories.flatMap((story) => {
37
+ const priorCompacted = Array.isArray(story.compactedFrom) ? story.compactedFrom : [];
38
+ return [story.id, ...priorCompacted];
39
+ })
40
+ )
41
+ ].sort((a, b) => a - b);
42
+
43
+ nextStories.push({
44
+ id: summaryId,
45
+ title: "[COMPACT] Completed stories summary",
46
+ description: "Compacted completed stories into a high-level summary entry.",
47
+ acceptanceCriteria: [
48
+ "Historical summary for compacted completed work.",
49
+ "Pending stories were preserved unchanged."
50
+ ],
51
+ dependsOn: [],
52
+ compactedFrom,
53
+ status: "done"
54
+ });
55
+ }
56
+
57
+ fs.writeFileSync(prdPath, JSON.stringify({ stories: nextStories }, null, 2) + "\n");
31
58
 
32
59
  const progressLines = [
33
60
  "# Wile Progress Log",
@@ -46,7 +73,7 @@ fs.writeFileSync(progressPath, progressLines.join("\n"));
46
73
  NODE
47
74
 
48
75
  cat <<'JSON'
49
- {"type":"message","role":"assistant","content":"{\"id\":\"GROUP-001\",\"title\":\"summary of everything done here\",\"tasks\":[\"High level of what was accomplished here\",\"Should NOT have all tasks in here, should be very summarized\"],\"taskIds\":\"From TASK-001 to TASK-029\",\"priority\":1,\"passes\":true,\"notes\":\"Don't repeat task ids when starting the next one.\"}\n"}
76
+ {"type":"message","role":"assistant","content":"{\"summaryStoryId\":999,\"summaryTitle\":\"[COMPACT] Completed stories summary\"}\n"}
50
77
  JSON
51
78
  exit 0
52
79
  fi
@@ -0,0 +1,93 @@
1
+ #!/usr/bin/env bun
2
+ import { createInterface } from "node:readline";
3
+
4
+ type JsonObject = Record<string, unknown>;
5
+
6
+ const isObject = (value: unknown): value is JsonObject =>
7
+ typeof value === "object" && value !== null;
8
+
9
+ const getString = (obj: JsonObject, key: string): string | undefined => {
10
+ const value = obj[key];
11
+ return typeof value === "string" ? value : undefined;
12
+ };
13
+
14
+ const getObject = (obj: JsonObject, key: string): JsonObject | undefined => {
15
+ const value = obj[key];
16
+ return isObject(value) ? value : undefined;
17
+ };
18
+
19
+ const writeLine = (value: string): void => {
20
+ process.stdout.write(`${value}\n`);
21
+ };
22
+
23
+ const formatToolLine = (tool: string, title: string, input: JsonObject): string => {
24
+ if (title) {
25
+ return `[tool] ${tool}: ${title}`;
26
+ }
27
+ if (Object.keys(input).length > 0) {
28
+ return `[tool] ${tool}: ${JSON.stringify(input)}`;
29
+ }
30
+ return `[tool] ${tool}`;
31
+ };
32
+
33
+ const rl = createInterface({
34
+ input: process.stdin,
35
+ crlfDelay: Infinity
36
+ });
37
+
38
+ rl.on("line", (line: string) => {
39
+ if (!line.trim()) {
40
+ return;
41
+ }
42
+
43
+ let parsed: unknown;
44
+ try {
45
+ parsed = JSON.parse(line);
46
+ } catch {
47
+ return;
48
+ }
49
+
50
+ if (!isObject(parsed)) {
51
+ return;
52
+ }
53
+
54
+ const payloadType = getString(parsed, "type");
55
+
56
+ if (payloadType === "text") {
57
+ const part = getObject(parsed, "part");
58
+ const text = part ? getString(part, "text") : undefined;
59
+ if (text) {
60
+ process.stdout.write(text);
61
+ if (!text.endsWith("\n")) {
62
+ process.stdout.write("\n");
63
+ }
64
+ }
65
+ return;
66
+ }
67
+
68
+ if (payloadType === "tool_use") {
69
+ const part = getObject(parsed, "part");
70
+ if (!part) {
71
+ return;
72
+ }
73
+
74
+ const tool = getString(part, "tool") ?? "tool";
75
+ const state = getObject(part, "state");
76
+ const title = state ? getString(state, "title") ?? "" : "";
77
+ const input = state ? getObject(state, "input") ?? {} : {};
78
+ writeLine(formatToolLine(tool, title, input));
79
+ return;
80
+ }
81
+
82
+ if (payloadType === "error") {
83
+ const error = getObject(parsed, "error");
84
+ if (!error) {
85
+ return;
86
+ }
87
+ const name = getString(error, "name") ?? "error";
88
+ const data = getObject(error, "data");
89
+ const message =
90
+ (data ? getString(data, "message") : undefined) ?? getString(error, "message") ?? "";
91
+ writeLine(`[error] ${name}${message ? `: ${message}` : ""}`);
92
+ }
93
+ });
@@ -1,44 +1,46 @@
1
1
  You are running a one-shot compaction task.
2
2
 
3
- Goal: compact both `.wile/prd.json` and `.wile/progress.txt` while preserving important information.
3
+ Goal: compact both `.wile/prd.json` and `.wile/progress.txt` while preserving correctness.
4
+
5
+ Rules:
6
+ - Final `.wile/prd.json` must stay valid under the current schema (`stories`, numeric `id`, `dependsOn`, `status`).
7
+ - Never reuse a compacted story ID. Any ID listed in any `compactedFrom` is permanently reserved.
8
+ - Keep every pending story exactly as-is.
9
+ - Do not create missing dependencies.
4
10
 
5
11
  Steps:
6
12
  1. Read `.wile/prd.json` and `.wile/progress.txt`.
7
- 2. Update `.wile/prd.json` to:
8
- - Keep every story where `passes` is `false` exactly as-is.
9
- - Preserve any existing grouped stories (ids starting with `GROUP-`) exactly as-is.
10
- - Replace all remaining stories where `passes` is `true` with a single grouped story.
11
- - The final structure must be: `{ "userStories": [ ...existing-group-stories, { ...GROUP-001... }, ...all-passes-false-stories ] }`.
12
- - The grouped story must use `id: "GROUP-001"`.
13
- - `title`: a concise summary of everything done.
14
- - `tasks`: 2-4 short bullet items derived from the summary tasks.
15
- - `taskIds`: a single string in the form `From TASK-001 to TASK-029` using the first and last task IDs you find.
16
- - `priority`: copy the priority from the first story in the original file.
17
- - `passes`: `true` (hardcoded).
18
- - `notes`: `Don't repeat task ids when starting the next one.` (exact text).
19
- 3. Update `.wile/progress.txt`:
20
- - Keep the header `# Wile Progress Log` and `## Codebase Patterns`.
21
- - The first line must be exactly `# Wile Progress Log`.
22
- - Add bullet points at the top under `## Codebase Patterns` for any important learnings that would help future agents.
23
- - Replace the rest of the log with a short, high-level summary in a few paragraphs.
24
- - Do not lose important info, but avoid detailed step-by-step logs.
25
- - Ignore preflight failures in the history.
26
- 4. When committing changes, only `.wile/prd.json` and `.wile/progress.txt` should be committed. Any other changes must be discarded.
13
+ 2. Compute:
14
+ - `pendingStories`: all stories where `status` is `"pending"`
15
+ - `doneStories`: all stories where `status` is `"done"`
16
+ - `requiredDoneIds`: every done-story id referenced by any pending story `dependsOn`
17
+ 3. Build a compacted `stories` array:
18
+ - Keep all `pendingStories` exactly as-is.
19
+ - Keep all done stories whose id is in `requiredDoneIds` exactly as-is.
20
+ - For remaining done stories, replace them with one summary done story:
21
+ - `id`: next available integer id greater than every story `id` and every value in every `compactedFrom` array
22
+ - `title`: `[COMPACT] Completed stories summary`
23
+ - `description`: concise summary of shipped work
24
+ - `acceptanceCriteria`: a short list (1-3 bullets) describing what was completed
25
+ - `dependsOn`: []
26
+ - `compactedFrom`: sorted unique list of all compacted story IDs
27
+ - Include each replaced done story `id`
28
+ - If a replaced story already has `compactedFrom`, include those IDs too (preserve tombstones transitively)
29
+ - `status`: `"done"`
30
+ - Preserve stable ordering as much as possible: keep retained stories in original order and append the summary story at the end.
31
+ 4. Update `.wile/progress.txt`:
32
+ - Keep header `# Wile Progress Log` and `## Codebase Patterns`.
33
+ - Add useful high-level bullets under `## Codebase Patterns`.
34
+ - Replace verbose history with a concise high-level summary.
35
+ - Ignore preflight-failure noise.
36
+ 5. When committing changes, only `.wile/prd.json` and `.wile/progress.txt` should be committed.
27
37
 
28
38
  Response format:
29
- - Your response must end with a single-line JSON object and nothing after it (no trailing text).
30
- - The final non-empty line of output must be valid JSON exactly matching this shape:
39
+ - Your response must end with a single-line JSON object and nothing after it.
40
+ - The final non-empty line must be valid JSON with this shape:
31
41
  {
32
- "id": "GROUP-001",
33
- "title": "summary of everything done here",
34
- "tasks": [
35
- "High level of what was accomplished here",
36
- "Should NOT have all tasks in here, should be very summarized"
37
- ],
38
- "taskIds": "From TASK-001 to TASK-029",
39
- "priority": 1,
40
- "passes": true,
41
- "notes": "Don't repeat task ids when starting the next one."
42
+ "summaryStoryId": 123,
43
+ "summaryTitle": "[COMPACT] Completed stories summary"
42
44
  }
43
- - Do not wrap the JSON in code fences.
45
+ - Do not wrap JSON in code fences.
44
46
  - Ensure nothing appears after the JSON line.
@@ -39,13 +39,6 @@ cat .wile/prd.json
39
39
  - Under **Checks run**, include the exact command(s) you executed (verbatim).
40
40
  - Under **Failures**, include the specific missing file names or failing commands.
41
41
 
42
- - If GitHub is configured (`WILE_REPO_SOURCE=github` or `GITHUB_REPO_URL` is set), commit and push the progress update:
43
-
44
- ```bash
45
- git add .wile/progress.txt
46
- git commit -m "chore: preflight failed"
47
- git push
48
- ```
49
42
  - Respond with exactly:
50
43
 
51
44
  ```
@@ -1,6 +1,6 @@
1
1
  # Wile Agent Instructions
2
2
 
3
- You are an autonomous coding agent running in a loop. Each iteration, you complete ONE user story from the backlog, then exit. The loop will call you again for the next story.
3
+ You are an autonomous coding agent running in a loop. Each iteration, you complete ONE story from the backlog, then exit. The loop will call you again for the next story.
4
4
 
5
5
  ## Your Task (Execute in Order)
6
6
 
@@ -8,7 +8,11 @@ You are an autonomous coding agent running in a loop. Each iteration, you comple
8
8
  ```bash
9
9
  cat .wile/prd.json
10
10
  ```
11
- Parse the `userStories` array. Find the highest priority story where `passes: false`.
11
+ Parse the `stories` array. Pick the first story (array order) where:
12
+ - `status` is `"pending"`
13
+ - every ID in `dependsOn` points to a story whose `status` is `"done"`
14
+
15
+ If no pending stories remain, respond with `<promise>ALL_STORIES_COMPLETED</promise>`.
12
16
 
13
17
  ### 2. Read Progress Log
14
18
  ```bash
@@ -24,7 +28,7 @@ git status
24
28
  Ensure you're on the correct branch specified by the `BRANCH_NAME` environment variable.
25
29
 
26
30
  ### 4. Implement the Story
27
- Pick the highest priority story where `passes: false` and implement it completely.
31
+ Implement the selected runnable pending story completely.
28
32
 
29
33
  - Read and understand all acceptance criteria
30
34
  - Implement the feature/fix
@@ -41,10 +45,10 @@ npm test || npm run test
41
45
 
42
46
  If tests or typecheck fail, fix the issues before proceeding.
43
47
 
44
- ### 6. Update prd.json
45
- Set `passes: true` for the completed story:
48
+ ### 6. Update .wile/prd.json
49
+ Set `status: "done"` for the completed story:
46
50
  ```bash
47
- # Edit .wile/prd.json to mark the story as complete
51
+ # Edit .wile/prd.json to mark the story as done
48
52
  ```
49
53
 
50
54
  ### 7. Log Your Progress
@@ -73,42 +77,40 @@ Set `passes: true` for the completed story:
73
77
 
74
78
  If you discovered important patterns, also add them to the **Codebase Patterns** section at the TOP of progress.txt.
75
79
 
76
- ### 8. Commit and Push
80
+ ### 8. Commit
77
81
  ```bash
78
82
  git add -A
79
83
  git commit -m "feat: [STORY-ID] - [Story Title]"
80
- git push
81
84
  ```
82
85
 
83
86
  Use the exact story ID and title from `.wile/prd.json`.
84
87
 
85
88
  ## Stop Condition
86
89
 
87
- After completing steps 1-8, check if ALL stories in `.wile/prd.json` have `passes: true`.
90
+ After completing steps 1-8, check if ALL stories in `.wile/prd.json` have `status: "done"`.
88
91
 
89
- **If ALL stories pass**, respond with exactly:
92
+ **If ALL stories are done**, respond with exactly:
90
93
  ```
91
94
  <promise>ALL_STORIES_COMPLETED</promise>
92
95
  ```
93
96
  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.
94
97
 
95
- **If there are still stories with `passes: false`**, end your response normally. The loop will call you again for the next story.
98
+ **If there are still stories with `status: "pending"`**, end your response normally. The loop will call you again for the next story.
96
99
 
97
100
  ## Important Rules
98
101
 
99
102
  1. **ONE story per iteration** - Do not implement multiple stories
100
- 2. **Always push** - Push after every commit so progress is visible
101
- 3. **One commit per feature** - Include the implementation, prd.json update, and progress log in a single commit
102
- 4. **Fix related files** - If typecheck requires changes in other files, make them (this is not scope creep)
103
- 5. **Be idempotent** - Use `IF NOT EXISTS` for migrations, check before creating files
104
- 6. **No interactive prompts** - Use `echo -e "\n\n\n" |` if a command might prompt
105
- 7. **NEVER commit node_modules, dist, or build artifacts** - .gitignore should already be set up at the start of the run
106
- 8. **Use acceptance criteria as verification steps** - Run commands to confirm outputs or write tests that fail if the feature is removed
107
- 9. **Integration tests must validate real system behavior, not just the harness**
108
- 10. **If you discover reusable, module-specific guidance, add it to the nearest AGENTS.md**
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`.
103
+ 2. **One commit per feature** - Include the implementation, .wile/prd.json update, and progress log in a single commit
104
+ 3. **Fix related files** - If typecheck requires changes in other files, make them (this is not scope creep)
105
+ 4. **Be idempotent** - Use `IF NOT EXISTS` for migrations, check before creating files
106
+ 5. **No interactive prompts** - Use `echo -e "\n\n\n" |` if a command might prompt
107
+ 6. **NEVER commit node_modules, dist, or build artifacts** - .gitignore should already be set up at the start of the run
108
+ 7. **Use acceptance criteria as verification steps** - Run commands to confirm outputs or write tests that fail if the feature is removed
109
+ 8. **Integration tests must validate real system behavior, not just the harness**
110
+ 9. **If you discover reusable, module-specific guidance, add it to the nearest AGENTS.md**
111
+ Note: Never update .wile/AGENTS.md.
112
+ 10. **Definition of done** - Set `status: "done"` only when every acceptance criterion has concrete verification and all verifications passed.
113
+ 11. **No verification section means not done** - If the progress entry lacks a **Verification** section, do not mark the story as done.
112
114
 
113
115
  ## Common Patterns
114
116
 
@@ -158,7 +160,7 @@ const { chromium } = require('playwright');
158
160
  const page = await browser.newPage();
159
161
  await page.goto('http://localhost:3000/login');
160
162
  await page.waitForLoadState('networkidle');
161
- const element = await page.\$('form#login');
163
+ const element = await page.$('form#login');
162
164
  console.log(element ? 'FOUND: form#login' : 'NOT FOUND: form#login');
163
165
  await browser.close();
164
166
  })();
@@ -16,8 +16,9 @@ run_case() {
16
16
  BIN_DIR="$TMP_DIR/bin"
17
17
  mkdir -p "$SCRIPT_DIR" "$BIN_DIR"
18
18
 
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"
19
+ REPO_SCRIPTS="$(cd "$(dirname "$0")" && pwd)"
20
+ cp "$REPO_SCRIPTS/wile.sh" "$SCRIPT_DIR/wile.sh"
21
+ cp "$REPO_SCRIPTS/claude-stream.ts" "$SCRIPT_DIR/claude-stream.ts"
21
22
  chmod +x "$SCRIPT_DIR/wile.sh"
22
23
 
23
24
  echo "BASE PROMPT" > "$SCRIPT_DIR/prompt.md"
@@ -52,6 +53,7 @@ EOF
52
53
  chmod +x "$BIN_DIR/claude"
53
54
 
54
55
  PATH="$BIN_DIR:$PATH" \
56
+ CODING_AGENT="CC" \
55
57
  CLAUDE_CAPTURE="$CAPTURE" \
56
58
  WILE_ADDITIONAL_INSTRUCTIONS="$ADDITIONAL" \
57
59
  CC_CLAUDE_MODEL="sonnet" \
@@ -15,13 +15,14 @@ trap cleanup EXIT INT TERM
15
15
  mkdir -p "$TMP_DIR/.wile/secrets"
16
16
  cat > "$TMP_DIR/.wile/prd.json" <<'JSON'
17
17
  {
18
- "userStories": [
18
+ "stories": [
19
19
  {
20
- "id": "US-TEST-ENV-001",
20
+ "id": 1,
21
21
  "title": "Env project forward test",
22
+ "description": "Forward custom env file into container",
22
23
  "acceptanceCriteria": ["n/a"],
23
- "priority": 1,
24
- "passes": false
24
+ "dependsOn": [],
25
+ "status": "pending"
25
26
  }
26
27
  ]
27
28
  }
@@ -11,8 +11,9 @@ SCRIPT_DIR="$TMP_DIR/agent"
11
11
  BIN_DIR="$TMP_DIR/bin"
12
12
  mkdir -p "$SCRIPT_DIR" "$BIN_DIR"
13
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"
14
+ REPO_SCRIPTS="$(cd "$(dirname "$0")" && pwd)"
15
+ cp "$REPO_SCRIPTS/wile.sh" "$SCRIPT_DIR/wile.sh"
16
+ cp "$REPO_SCRIPTS/claude-stream.ts" "$SCRIPT_DIR/claude-stream.ts"
16
17
  chmod +x "$SCRIPT_DIR/wile.sh"
17
18
 
18
19
  echo "BASE PROMPT" > "$SCRIPT_DIR/prompt.md"
@@ -27,6 +28,7 @@ chmod +x "$BIN_DIR/claude"
27
28
 
28
29
  set +e
29
30
  PATH="$BIN_DIR:$PATH" \
31
+ CODING_AGENT="CC" \
30
32
  CC_CLAUDE_MODEL="sonnet" \
31
33
  "$SCRIPT_DIR/wile.sh" 3 > "$OUTPUT_FILE" 2>&1
32
34
  EXIT_CODE=$?