@ai-hero/sandcastle 0.5.8 → 0.5.10

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 (55) hide show
  1. package/README.md +45 -3
  2. package/dist/AgentProvider.d.ts +2 -0
  3. package/dist/AgentProvider.d.ts.map +1 -1
  4. package/dist/AgentProvider.js +4 -1
  5. package/dist/AgentProvider.js.map +1 -1
  6. package/dist/DockerLifecycle.d.ts +16 -1
  7. package/dist/DockerLifecycle.d.ts.map +1 -1
  8. package/dist/DockerLifecycle.js +12 -2
  9. package/dist/DockerLifecycle.js.map +1 -1
  10. package/dist/EnvResolver.d.ts.map +1 -1
  11. package/dist/EnvResolver.js +18 -3
  12. package/dist/EnvResolver.js.map +1 -1
  13. package/dist/InitService.d.ts.map +1 -1
  14. package/dist/InitService.js +37 -21
  15. package/dist/InitService.js.map +1 -1
  16. package/dist/Output.d.ts +80 -0
  17. package/dist/Output.d.ts.map +1 -0
  18. package/dist/Output.js +68 -0
  19. package/dist/Output.js.map +1 -0
  20. package/dist/cli.d.ts.map +1 -1
  21. package/dist/cli.js +16 -1
  22. package/dist/cli.js.map +1 -1
  23. package/dist/createSandbox.d.ts.map +1 -1
  24. package/dist/createSandbox.js +13 -2
  25. package/dist/createSandbox.js.map +1 -1
  26. package/dist/extractStructuredOutput.d.ts +21 -0
  27. package/dist/extractStructuredOutput.d.ts.map +1 -0
  28. package/dist/extractStructuredOutput.js +97 -0
  29. package/dist/extractStructuredOutput.js.map +1 -0
  30. package/dist/index.d.ts +2 -0
  31. package/dist/index.d.ts.map +1 -1
  32. package/dist/index.js +1 -0
  33. package/dist/index.js.map +1 -1
  34. package/dist/mountUtils.d.ts +42 -0
  35. package/dist/mountUtils.d.ts.map +1 -1
  36. package/dist/mountUtils.js +58 -2
  37. package/dist/mountUtils.js.map +1 -1
  38. package/dist/run.d.ts +30 -1
  39. package/dist/run.d.ts.map +1 -1
  40. package/dist/run.js +27 -3
  41. package/dist/run.js.map +1 -1
  42. package/dist/sandboxes/docker.d.ts +22 -0
  43. package/dist/sandboxes/docker.d.ts.map +1 -1
  44. package/dist/sandboxes/docker.js +71 -9
  45. package/dist/sandboxes/docker.js.map +1 -1
  46. package/dist/sandboxes/podman.d.ts +2 -1
  47. package/dist/sandboxes/podman.d.ts.map +1 -1
  48. package/dist/sandboxes/podman.js +28 -8
  49. package/dist/sandboxes/podman.js.map +1 -1
  50. package/dist/templates/sequential-reviewer/implement-prompt.md +1 -1
  51. package/dist/templates/sequential-reviewer/main.mts +54 -49
  52. package/dist/templates/simple-loop/main.mts +1 -1
  53. package/dist/templates/simple-loop/prompt.md +1 -1
  54. package/dist/templates/simple-loop/template.json +1 -1
  55. package/package.json +1 -1
@@ -1,12 +1,15 @@
1
1
  // Sequential Reviewer — implement-then-review loop
2
2
  //
3
3
  // This template drives a two-phase workflow per issue:
4
- // Phase 1 (Implement): A sonnet agent picks an open GitHub issue, works on it
4
+ // Phase 1 (Implement): A sonnet agent picks an open issue, works on it
5
5
  // on a dedicated branch, commits the changes, and signals
6
6
  // completion.
7
7
  // Phase 2 (Review): A second sonnet agent reviews the branch diff and either
8
8
  // approves it or makes corrections directly on the branch.
9
9
  //
10
+ // Both phases share a single sandbox created via createSandbox(), so the
11
+ // implementer and reviewer work on the same explicit branch.
12
+ //
10
13
  // The outer loop repeats up to MAX_ITERATIONS times, processing one issue per
11
14
  // iteration. This is a middle-complexity option between the simple-loop (no review
12
15
  // gate) and the parallel-planner (concurrent execution with a planning phase).
@@ -45,62 +48,64 @@ const copyToWorktree = ["node_modules"];
45
48
  for (let iteration = 1; iteration <= MAX_ITERATIONS; iteration++) {
46
49
  console.log(`\n=== Iteration ${iteration}/${MAX_ITERATIONS} ===\n`);
47
50
 
48
- // -------------------------------------------------------------------------
49
- // Phase 1: Implement
50
- //
51
- // A sonnet agent picks the next open GitHub issue, creates a branch, writes
52
- // the implementation (using RGR: Red Green Repeat Refactor), and
53
- // commits the result.
54
- //
55
- // The agent signals completion via <promise>COMPLETE</promise> when done.
56
- // The result contains the branch name the agent worked on.
57
- // -------------------------------------------------------------------------
58
- const implement = await sandcastle.run({
51
+ // Generate a unique branch name for this iteration.
52
+ const branch = `sandcastle/sequential-reviewer/${Date.now()}`;
53
+
54
+ // Create a single sandbox that both the implementer and reviewer share.
55
+ // This gives both agents a real, named branch that persists across phases.
56
+ const sandbox = await sandcastle.createSandbox({
57
+ branch,
58
+ sandbox: docker(),
59
59
  hooks,
60
60
  copyToWorktree,
61
- sandbox: docker(),
62
- branchStrategy: { type: "merge-to-head" },
63
- name: "implementer",
64
- maxIterations: 100,
65
- agent: sandcastle.claudeCode("claude-sonnet-4-6"),
66
- promptFile: "./.sandcastle/implement-prompt.md",
67
61
  });
68
62
 
69
- // Extract the branch the agent worked on so the reviewer can target it.
70
- const branch = implement.branch;
63
+ try {
64
+ // -----------------------------------------------------------------------
65
+ // Phase 1: Implement
66
+ //
67
+ // A sonnet agent picks the next open issue, writes the
68
+ // implementation (using RGR: Red → Green → Repeat → Refactor), and
69
+ // commits the result.
70
+ //
71
+ // The agent signals completion via <promise>COMPLETE</promise> when done.
72
+ // -----------------------------------------------------------------------
73
+ const implement = await sandbox.run({
74
+ name: "implementer",
75
+ maxIterations: 100,
76
+ agent: sandcastle.claudeCode("claude-sonnet-4-6"),
77
+ promptFile: "./.sandcastle/implement-prompt.md",
78
+ });
71
79
 
72
- if (!implement.commits.length) {
73
- console.log("Implementation agent made no commits. Skipping review.");
74
- continue;
75
- }
80
+ if (!implement.commits.length) {
81
+ console.log("Implementation agent made no commits. Skipping review.");
82
+ continue;
83
+ }
76
84
 
77
- console.log(`\nImplementation complete on branch: ${branch}`);
78
- console.log(`Commits: ${implement.commits.length}`);
85
+ console.log(`\nImplementation complete on branch: ${branch}`);
86
+ console.log(`Commits: ${implement.commits.length}`);
79
87
 
80
- // -------------------------------------------------------------------------
81
- // Phase 2: Review
82
- //
83
- // A second sonnet agent reviews the diff of the branch produced by Phase 1.
84
- // It uses the {{BRANCH}} prompt argument to inspect the right branch, and
85
- // either approves or makes corrections directly on the branch.
86
- // -------------------------------------------------------------------------
87
- await sandcastle.run({
88
- hooks,
89
- copyToWorktree,
90
- sandbox: docker(),
91
- branchStrategy: { type: "branch", branch },
92
- name: "reviewer",
93
- maxIterations: 1,
94
- agent: sandcastle.claudeCode("claude-sonnet-4-6"),
95
- promptFile: "./.sandcastle/review-prompt.md",
96
- // Prompt arguments substitute {{BRANCH}} in review-prompt.md before the
97
- // agent sees the prompt.
98
- promptArgs: {
99
- BRANCH: branch,
100
- },
101
- });
88
+ // -----------------------------------------------------------------------
89
+ // Phase 2: Review
90
+ //
91
+ // A second sonnet agent reviews the diff of the branch produced by
92
+ // Phase 1. It uses the {{BRANCH}} prompt argument to inspect the right
93
+ // branch, and either approves or makes corrections directly on the branch.
94
+ // -----------------------------------------------------------------------
95
+ await sandbox.run({
96
+ name: "reviewer",
97
+ maxIterations: 1,
98
+ agent: sandcastle.claudeCode("claude-sonnet-4-6"),
99
+ promptFile: "./.sandcastle/review-prompt.md",
100
+ promptArgs: {
101
+ BRANCH: branch,
102
+ },
103
+ });
102
104
 
103
- console.log("\nReview complete.");
105
+ console.log("\nReview complete.");
106
+ } finally {
107
+ await sandbox.close();
108
+ }
104
109
  }
105
110
 
106
111
  console.log("\nAll done.");
@@ -1,7 +1,7 @@
1
1
  import { run, claudeCode } from "@ai-hero/sandcastle";
2
2
  import { docker } from "@ai-hero/sandcastle/sandboxes/docker";
3
3
 
4
- // Simple loop: an agent that picks open GitHub issues one by one and closes them.
4
+ // Simple loop: an agent that picks open issues one by one and closes them.
5
5
  // Run this with: npx tsx .sandcastle/main.mts
6
6
  // Or add to package.json scripts: "sandcastle": "npx tsx .sandcastle/main.mts"
7
7
 
@@ -10,7 +10,7 @@
10
10
 
11
11
  # Task
12
12
 
13
- You are RALPH — an autonomous coding agent working through GitHub issues one at a time.
13
+ You are RALPH — an autonomous coding agent working through issues one at a time.
14
14
 
15
15
  ## Priority order
16
16
 
@@ -1,4 +1,4 @@
1
1
  {
2
2
  "name": "simple-loop",
3
- "description": "Picks GitHub issues one by one and closes them"
3
+ "description": "Picks issues one by one and closes them"
4
4
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-hero/sandcastle",
3
- "version": "0.5.8",
3
+ "version": "0.5.10",
4
4
  "description": "CLI for orchestrating AI agents in isolated sandbox environments",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",