@ai-hero/sandcastle 0.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 (133) hide show
  1. package/README.md +284 -0
  2. package/dist/AgentProvider.d.ts +8 -0
  3. package/dist/AgentProvider.d.ts.map +1 -0
  4. package/dist/AgentProvider.js +60 -0
  5. package/dist/AgentProvider.js.map +1 -0
  6. package/dist/Config.d.ts +35 -0
  7. package/dist/Config.d.ts.map +1 -0
  8. package/dist/Config.js +56 -0
  9. package/dist/Config.js.map +1 -0
  10. package/dist/CopyToSandbox.d.ts +8 -0
  11. package/dist/CopyToSandbox.d.ts.map +1 -0
  12. package/dist/CopyToSandbox.js +32 -0
  13. package/dist/CopyToSandbox.js.map +1 -0
  14. package/dist/Display.d.ts +52 -0
  15. package/dist/Display.d.ts.map +1 -0
  16. package/dist/Display.js +132 -0
  17. package/dist/Display.js.map +1 -0
  18. package/dist/DockerLifecycle.d.ts +37 -0
  19. package/dist/DockerLifecycle.d.ts.map +1 -0
  20. package/dist/DockerLifecycle.js +109 -0
  21. package/dist/DockerLifecycle.js.map +1 -0
  22. package/dist/DockerSandbox.d.ts +6 -0
  23. package/dist/DockerSandbox.d.ts.map +1 -0
  24. package/dist/DockerSandbox.js +122 -0
  25. package/dist/DockerSandbox.js.map +1 -0
  26. package/dist/EnvResolver.d.ts +11 -0
  27. package/dist/EnvResolver.d.ts.map +1 -0
  28. package/dist/EnvResolver.js +43 -0
  29. package/dist/EnvResolver.js.map +1 -0
  30. package/dist/ErrorHandler.d.ts +15 -0
  31. package/dist/ErrorHandler.d.ts.map +1 -0
  32. package/dist/ErrorHandler.js +58 -0
  33. package/dist/ErrorHandler.js.map +1 -0
  34. package/dist/FilesystemSandbox.d.ts +6 -0
  35. package/dist/FilesystemSandbox.d.ts.map +1 -0
  36. package/dist/FilesystemSandbox.js +83 -0
  37. package/dist/FilesystemSandbox.js.map +1 -0
  38. package/dist/InitService.d.ts +11 -0
  39. package/dist/InitService.d.ts.map +1 -0
  40. package/dist/InitService.js +111 -0
  41. package/dist/InitService.js.map +1 -0
  42. package/dist/Orchestrator.d.ts +49 -0
  43. package/dist/Orchestrator.d.ts.map +1 -0
  44. package/dist/Orchestrator.js +155 -0
  45. package/dist/Orchestrator.js.map +1 -0
  46. package/dist/PromptArgumentSubstitution.d.ts +6 -0
  47. package/dist/PromptArgumentSubstitution.d.ts.map +1 -0
  48. package/dist/PromptArgumentSubstitution.js +33 -0
  49. package/dist/PromptArgumentSubstitution.js.map +1 -0
  50. package/dist/PromptPreprocessor.d.ts +7 -0
  51. package/dist/PromptPreprocessor.d.ts.map +1 -0
  52. package/dist/PromptPreprocessor.js +34 -0
  53. package/dist/PromptPreprocessor.js.map +1 -0
  54. package/dist/PromptResolver.d.ts +9 -0
  55. package/dist/PromptResolver.d.ts.map +1 -0
  56. package/dist/PromptResolver.js +26 -0
  57. package/dist/PromptResolver.js.map +1 -0
  58. package/dist/RecoveryMessage.d.ts +15 -0
  59. package/dist/RecoveryMessage.d.ts.map +1 -0
  60. package/dist/RecoveryMessage.js +81 -0
  61. package/dist/RecoveryMessage.js.map +1 -0
  62. package/dist/Sandbox.d.ts +23 -0
  63. package/dist/Sandbox.d.ts.map +1 -0
  64. package/dist/Sandbox.js +5 -0
  65. package/dist/Sandbox.js.map +1 -0
  66. package/dist/SandboxFactory.d.ts +56 -0
  67. package/dist/SandboxFactory.d.ts.map +1 -0
  68. package/dist/SandboxFactory.js +219 -0
  69. package/dist/SandboxFactory.js.map +1 -0
  70. package/dist/SandboxLifecycle.d.ts +32 -0
  71. package/dist/SandboxLifecycle.d.ts.map +1 -0
  72. package/dist/SandboxLifecycle.js +152 -0
  73. package/dist/SandboxLifecycle.js.map +1 -0
  74. package/dist/SyncService.d.ts +20 -0
  75. package/dist/SyncService.d.ts.map +1 -0
  76. package/dist/SyncService.js +504 -0
  77. package/dist/SyncService.js.map +1 -0
  78. package/dist/TokenResolver.d.ts +6 -0
  79. package/dist/TokenResolver.d.ts.map +1 -0
  80. package/dist/TokenResolver.js +43 -0
  81. package/dist/TokenResolver.js.map +1 -0
  82. package/dist/WorktreeManager.d.ts +42 -0
  83. package/dist/WorktreeManager.d.ts.map +1 -0
  84. package/dist/WorktreeManager.js +170 -0
  85. package/dist/WorktreeManager.js.map +1 -0
  86. package/dist/cli.d.ts +22 -0
  87. package/dist/cli.d.ts.map +1 -0
  88. package/dist/cli.js +217 -0
  89. package/dist/cli.js.map +1 -0
  90. package/dist/errors.d.ts +95 -0
  91. package/dist/errors.d.ts.map +1 -0
  92. package/dist/errors.js +35 -0
  93. package/dist/errors.js.map +1 -0
  94. package/dist/index.d.ts +4 -0
  95. package/dist/index.d.ts.map +1 -0
  96. package/dist/index.js +2 -0
  97. package/dist/index.js.map +1 -0
  98. package/dist/main.d.ts +3 -0
  99. package/dist/main.d.ts.map +1 -0
  100. package/dist/main.js +16 -0
  101. package/dist/main.js.map +1 -0
  102. package/dist/run.d.ts +91 -0
  103. package/dist/run.d.ts.map +1 -0
  104. package/dist/run.js +155 -0
  105. package/dist/run.js.map +1 -0
  106. package/dist/templates/blank/main.ts +9 -0
  107. package/dist/templates/blank/prompt.md +12 -0
  108. package/dist/templates/blank/template.json +4 -0
  109. package/dist/templates/parallel-planner/implement-prompt.md +62 -0
  110. package/dist/templates/parallel-planner/main.ts +200 -0
  111. package/dist/templates/parallel-planner/merge-prompt.md +22 -0
  112. package/dist/templates/parallel-planner/plan-prompt.md +33 -0
  113. package/dist/templates/parallel-planner/template.json +4 -0
  114. package/dist/templates/sequential-reviewer/implement-prompt.md +62 -0
  115. package/dist/templates/sequential-reviewer/main.ts +102 -0
  116. package/dist/templates/sequential-reviewer/review-prompt.md +43 -0
  117. package/dist/templates/sequential-reviewer/template.json +4 -0
  118. package/dist/templates/simple-loop/main.ts +37 -0
  119. package/dist/templates/simple-loop/prompt.md +51 -0
  120. package/dist/templates/simple-loop/template.json +4 -0
  121. package/dist/templates.d.ts +2 -0
  122. package/dist/templates.d.ts.map +1 -0
  123. package/dist/templates.js +26 -0
  124. package/dist/templates.js.map +1 -0
  125. package/dist/terminalCleanup.d.ts +30 -0
  126. package/dist/terminalCleanup.d.ts.map +1 -0
  127. package/dist/terminalCleanup.js +37 -0
  128. package/dist/terminalCleanup.js.map +1 -0
  129. package/dist/testSandbox.d.ts +8 -0
  130. package/dist/testSandbox.d.ts.map +1 -0
  131. package/dist/testSandbox.js +101 -0
  132. package/dist/testSandbox.js.map +1 -0
  133. package/package.json +62 -0
@@ -0,0 +1,81 @@
1
+ /**
2
+ * Build copy-pastable recovery commands for a failed sync-out.
3
+ * Pure function: takes failure state, returns formatted terminal output.
4
+ */
5
+ export const buildRecoveryMessage = (input) => {
6
+ const { patchDir, failedStep, hasCommits, hasDiff, hasUntracked, branch } = input;
7
+ // When --branch is set, commands run inside .sandcastle/worktree,
8
+ // so patch paths need ../../ prefix to reach repo root
9
+ const cmdPatchDir = branch ? `../../${patchDir}` : patchDir;
10
+ // Determine the step number for the failed step
11
+ const steps = [];
12
+ if (hasCommits)
13
+ steps.push({ key: "commits", label: "committed changes", has: true });
14
+ if (hasDiff)
15
+ steps.push({ key: "diff", label: "uncommitted changes", has: true });
16
+ if (hasUntracked)
17
+ steps.push({ key: "untracked", label: "untracked files", has: true });
18
+ const failedIndex = steps.findIndex((s) => s.key === failedStep);
19
+ const failedStepInfo = steps[failedIndex];
20
+ const stepNumber = failedIndex + 1;
21
+ const lines = [];
22
+ lines.push(`Patch application failed at step ${stepNumber} (${failedStepInfo.label}).`);
23
+ lines.push("");
24
+ // Add worktree setup preamble for --branch
25
+ if (branch) {
26
+ lines.push("Set up worktree, then resolve:");
27
+ lines.push(formatCommandBlock([
28
+ `git worktree add .sandcastle/worktree ${branch}`,
29
+ `cd .sandcastle/worktree`,
30
+ ]));
31
+ lines.push("");
32
+ }
33
+ if (failedStep === "commits") {
34
+ // git am failure — lean on git's built-in workflow
35
+ lines.push("Resolve conflicts, then continue with:");
36
+ lines.push(` git am --continue`);
37
+ // Remaining steps after git am resolves
38
+ const remaining = buildRemainingCommands(cmdPatchDir, steps.slice(failedIndex + 1));
39
+ if (remaining.length > 0) {
40
+ lines.push("");
41
+ lines.push("After all commits are applied, run the remaining steps:");
42
+ lines.push(formatCommandBlock(remaining));
43
+ }
44
+ }
45
+ else {
46
+ // diff or untracked failure — print remaining commands from failed step onward
47
+ const remaining = buildRemainingCommands(cmdPatchDir, steps.slice(failedIndex));
48
+ if (remaining.length > 0) {
49
+ lines.push("Run the remaining steps:");
50
+ lines.push(formatCommandBlock(remaining));
51
+ }
52
+ }
53
+ return lines.join("\n");
54
+ };
55
+ const buildRemainingCommands = (patchDir, steps) => {
56
+ const commands = [];
57
+ for (const step of steps) {
58
+ if (!step.has)
59
+ continue;
60
+ if (step.key === "commits") {
61
+ commands.push(`git am --3way ${patchDir}/*.patch`);
62
+ }
63
+ else if (step.key === "diff") {
64
+ commands.push(`git apply ${patchDir}/changes.patch`);
65
+ }
66
+ else if (step.key === "untracked") {
67
+ commands.push(`cp -r ${patchDir}/untracked/* .`);
68
+ }
69
+ }
70
+ return commands;
71
+ };
72
+ const formatCommandBlock = (commands) => {
73
+ if (commands.length === 1) {
74
+ return ` ${commands[0]}`;
75
+ }
76
+ // Join with && \ continuation
77
+ return commands
78
+ .map((cmd, i) => (i < commands.length - 1 ? ` ${cmd} && \\` : ` ${cmd}`))
79
+ .join("\n");
80
+ };
81
+ //# sourceMappingURL=RecoveryMessage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RecoveryMessage.js","sourceRoot":"","sources":["../src/RecoveryMessage.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ import { Context, Effect } from "effect";
2
+ import type { CopyError, ExecError } from "./errors.js";
3
+ export { type SandboxError } from "./errors.js";
4
+ export { ExecError, ExecHostError, CopyError, DockerError, SyncError, PromptError, AgentError, ConfigDirError, InitError, } from "./errors.js";
5
+ export interface ExecResult {
6
+ readonly stdout: string;
7
+ readonly stderr: string;
8
+ readonly exitCode: number;
9
+ }
10
+ export interface SandboxService {
11
+ readonly exec: (command: string, options?: {
12
+ cwd?: string;
13
+ }) => Effect.Effect<ExecResult, ExecError>;
14
+ readonly execStreaming: (command: string, onStdoutLine: (line: string) => void, options?: {
15
+ cwd?: string;
16
+ }) => Effect.Effect<ExecResult, ExecError>;
17
+ readonly copyIn: (hostPath: string, sandboxPath: string) => Effect.Effect<void, CopyError>;
18
+ readonly copyOut: (sandboxPath: string, hostPath: string) => Effect.Effect<void, CopyError>;
19
+ }
20
+ declare const Sandbox_base: Context.TagClass<Sandbox, "Sandbox", SandboxService>;
21
+ export declare class Sandbox extends Sandbox_base {
22
+ }
23
+ //# sourceMappingURL=Sandbox.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Sandbox.d.ts","sourceRoot":"","sources":["../src/Sandbox.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AACzC,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAExD,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EACL,SAAS,EACT,aAAa,EACb,SAAS,EACT,WAAW,EACX,SAAS,EACT,WAAW,EACX,UAAU,EACV,cAAc,EACd,SAAS,GACV,MAAM,aAAa,CAAC;AAErB,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,IAAI,EAAE,CACb,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE;QAAE,GAAG,CAAC,EAAE,MAAM,CAAA;KAAE,KACvB,MAAM,CAAC,MAAM,CAAC,UAAU,EAAE,SAAS,CAAC,CAAC;IAE1C,QAAQ,CAAC,aAAa,EAAE,CACtB,OAAO,EAAE,MAAM,EACf,YAAY,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,EACpC,OAAO,CAAC,EAAE;QAAE,GAAG,CAAC,EAAE,MAAM,CAAA;KAAE,KACvB,MAAM,CAAC,MAAM,CAAC,UAAU,EAAE,SAAS,CAAC,CAAC;IAE1C,QAAQ,CAAC,MAAM,EAAE,CACf,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,MAAM,KAChB,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;IAEpC,QAAQ,CAAC,OAAO,EAAE,CAChB,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,KACb,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;CACrC;;AAED,qBAAa,OAAQ,SAAQ,YAG1B;CAAG"}
@@ -0,0 +1,5 @@
1
+ import { Context } from "effect";
2
+ export { ExecError, ExecHostError, CopyError, DockerError, SyncError, PromptError, AgentError, ConfigDirError, InitError, } from "./errors.js";
3
+ export class Sandbox extends Context.Tag("Sandbox")() {
4
+ }
5
+ //# sourceMappingURL=Sandbox.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Sandbox.js","sourceRoot":"","sources":["../src/Sandbox.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAU,MAAM,QAAQ,CAAC;AAIzC,OAAO,EACL,SAAS,EACT,aAAa,EACb,SAAS,EACT,WAAW,EACX,SAAS,EACT,WAAW,EACX,UAAU,EACV,cAAc,EACd,SAAS,GACV,MAAM,aAAa,CAAC;AA+BrB,MAAM,OAAO,OAAQ,SAAQ,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,EAGhD;CAAG"}
@@ -0,0 +1,56 @@
1
+ import { Context, Effect, Layer } from "effect";
2
+ import { FileSystem } from "@effect/platform";
3
+ import { CopyError, ExecError, type DockerError, type WorktreeError } from "./errors.js";
4
+ import { Display } from "./Display.js";
5
+ export interface ExecResult {
6
+ readonly stdout: string;
7
+ readonly stderr: string;
8
+ readonly exitCode: number;
9
+ }
10
+ export interface SandboxService {
11
+ readonly exec: (command: string, options?: {
12
+ cwd?: string;
13
+ }) => Effect.Effect<ExecResult, ExecError>;
14
+ readonly execStreaming: (command: string, onStdoutLine: (line: string) => void, options?: {
15
+ cwd?: string;
16
+ }) => Effect.Effect<ExecResult, ExecError>;
17
+ readonly copyIn: (hostPath: string, sandboxPath: string) => Effect.Effect<void, CopyError>;
18
+ readonly copyOut: (sandboxPath: string, hostPath: string) => Effect.Effect<void, CopyError>;
19
+ }
20
+ declare const Sandbox_base: Context.TagClass<Sandbox, "Sandbox", SandboxService>;
21
+ export declare class Sandbox extends Sandbox_base {
22
+ }
23
+ /** The mount point inside the container where the project worktree is bound. */
24
+ export declare const SANDBOX_WORKSPACE_DIR = "/home/agent/workspace";
25
+ export interface SandboxInfo {
26
+ /** Host-side path to the worktree directory (worktree mode only). */
27
+ readonly hostWorktreePath?: string;
28
+ }
29
+ declare const SandboxFactory_base: Context.TagClass<SandboxFactory, "SandboxFactory", {
30
+ readonly withSandbox: <A, E, R>(makeEffect: (info: SandboxInfo) => Effect.Effect<A, E, R | Sandbox>) => Effect.Effect<A, E | DockerError | WorktreeError, Exclude<R, Sandbox>>;
31
+ }>;
32
+ export declare class SandboxFactory extends SandboxFactory_base {
33
+ }
34
+ declare const WorktreeSandboxConfig_base: Context.TagClass<WorktreeSandboxConfig, "WorktreeSandboxConfig", {
35
+ readonly imageName: string;
36
+ readonly env: Record<string, string>;
37
+ readonly hostRepoDir: string;
38
+ /** When specified, the worktree checks out this branch. Otherwise a temp branch is created. */
39
+ readonly branch?: string | undefined;
40
+ /** Paths relative to the host repo root to copy into the worktree before container start. */
41
+ readonly copyToSandbox?: string[] | undefined;
42
+ /** When specified, the agent name is included in the auto-generated branch and worktree names. */
43
+ readonly agentName?: string | undefined;
44
+ }>;
45
+ export declare class WorktreeSandboxConfig extends WorktreeSandboxConfig_base {
46
+ }
47
+ /**
48
+ * Worktree sandbox mode: creates a git worktree and bind-mounts it into the
49
+ * container at SANDBOX_WORKSPACE_DIR. The host's .git directory is also bind-mounted at
50
+ * its original host path so the worktree's .git file pointer resolves correctly.
51
+ */
52
+ export declare const WorktreeDockerSandboxFactory: {
53
+ layer: Layer.Layer<SandboxFactory, never, Display | FileSystem.FileSystem | WorktreeSandboxConfig>;
54
+ };
55
+ export {};
56
+ //# sourceMappingURL=SandboxFactory.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SandboxFactory.d.ts","sourceRoot":"","sources":["../src/SandboxFactory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAW9C,OAAO,EACL,SAAS,EACT,SAAS,EACT,KAAK,WAAW,EAChB,KAAK,aAAa,EACnB,MAAM,aAAa,CAAC;AAGrB,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAEvC,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,IAAI,EAAE,CACb,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE;QAAE,GAAG,CAAC,EAAE,MAAM,CAAA;KAAE,KACvB,MAAM,CAAC,MAAM,CAAC,UAAU,EAAE,SAAS,CAAC,CAAC;IAE1C,QAAQ,CAAC,aAAa,EAAE,CACtB,OAAO,EAAE,MAAM,EACf,YAAY,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,EACpC,OAAO,CAAC,EAAE;QAAE,GAAG,CAAC,EAAE,MAAM,CAAA;KAAE,KACvB,MAAM,CAAC,MAAM,CAAC,UAAU,EAAE,SAAS,CAAC,CAAC;IAE1C,QAAQ,CAAC,MAAM,EAAE,CACf,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,MAAM,KAChB,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;IAEpC,QAAQ,CAAC,OAAO,EAAE,CAChB,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,KACb,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;CACrC;;AAED,qBAAa,OAAQ,SAAQ,YAG1B;CAAG;AAgLN,gFAAgF;AAChF,eAAO,MAAM,qBAAqB,0BAA0B,CAAC;AAE7D,MAAM,WAAW,WAAW;IAC1B,qEAAqE;IACrE,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;CACpC;;2BAK0B,CAAC,EAAE,CAAC,EAAE,CAAC;;AAHlC,qBAAa,cAAe,SAAQ,mBAOjC;CAAG;;;;;IAoBF,+FAA+F;;IAE/F,6FAA6F;;IAE7F,kGAAkG;;;AAVtG,qBAAa,qBAAsB,SAAQ,0BAaxC;CAAG;AAoBN;;;;GAIG;AACH,eAAO,MAAM,4BAA4B;;CA4HxC,CAAC"}
@@ -0,0 +1,219 @@
1
+ import { Context, Effect, Layer } from "effect";
2
+ import { FileSystem } from "@effect/platform";
3
+ import { NodeFileSystem } from "@effect/platform-node";
4
+ import { randomUUID } from "node:crypto";
5
+ import { execFile, execFileSync, spawn } from "node:child_process";
6
+ import { dirname, join } from "node:path";
7
+ import { createInterface } from "node:readline";
8
+ import { startContainer, removeContainer, chownInContainer, } from "./DockerLifecycle.js";
9
+ import { CopyError, ExecError, } from "./errors.js";
10
+ import * as WorktreeManager from "./WorktreeManager.js";
11
+ import { copyToSandbox } from "./CopyToSandbox.js";
12
+ import { Display } from "./Display.js";
13
+ export class Sandbox extends Context.Tag("Sandbox")() {
14
+ }
15
+ const makeDockerSandbox = (containerName) => Effect.gen(function* () {
16
+ const fs = yield* FileSystem.FileSystem;
17
+ return {
18
+ exec: (command, options) => Effect.async((resume) => {
19
+ const args = ["exec"];
20
+ if (options?.cwd) {
21
+ args.push("-w", options.cwd);
22
+ }
23
+ args.push(containerName, "sh", "-c", command);
24
+ execFile("docker", args, { maxBuffer: 10 * 1024 * 1024 }, (error, stdout, stderr) => {
25
+ if (error && error.code === undefined) {
26
+ resume(Effect.fail(new ExecError({
27
+ command,
28
+ message: `docker exec failed: ${error.message}`,
29
+ })));
30
+ }
31
+ else {
32
+ resume(Effect.succeed({
33
+ stdout: stdout.toString(),
34
+ stderr: stderr.toString(),
35
+ exitCode: typeof error?.code === "number"
36
+ ? error.code
37
+ : 0,
38
+ }));
39
+ }
40
+ });
41
+ }),
42
+ execStreaming: (command, onStdoutLine, options) => Effect.async((resume) => {
43
+ const args = ["exec"];
44
+ if (options?.cwd) {
45
+ args.push("-w", options.cwd);
46
+ }
47
+ args.push(containerName, "sh", "-c", command);
48
+ const proc = spawn("docker", args, {
49
+ stdio: ["ignore", "pipe", "pipe"],
50
+ });
51
+ const stdoutChunks = [];
52
+ const stderrChunks = [];
53
+ const rl = createInterface({ input: proc.stdout });
54
+ rl.on("line", (line) => {
55
+ stdoutChunks.push(line);
56
+ onStdoutLine(line);
57
+ });
58
+ proc.stderr.on("data", (chunk) => {
59
+ stderrChunks.push(chunk.toString());
60
+ });
61
+ proc.on("error", (error) => {
62
+ resume(Effect.fail(new ExecError({
63
+ command,
64
+ message: `docker exec streaming failed: ${error.message}`,
65
+ })));
66
+ });
67
+ proc.on("close", (code) => {
68
+ resume(Effect.succeed({
69
+ stdout: stdoutChunks.join("\n"),
70
+ stderr: stderrChunks.join(""),
71
+ exitCode: code ?? 0,
72
+ }));
73
+ });
74
+ }),
75
+ copyIn: (hostPath, sandboxPath) => Effect.gen(function* () {
76
+ const parentDir = dirname(sandboxPath);
77
+ yield* Effect.async((resume) => {
78
+ execFile("docker", ["exec", containerName, "mkdir", "-p", parentDir], (error) => {
79
+ if (error) {
80
+ resume(Effect.fail(new CopyError({
81
+ message: `Failed to create dir ${parentDir}: ${error.message}`,
82
+ })));
83
+ }
84
+ else {
85
+ resume(Effect.succeed(undefined));
86
+ }
87
+ });
88
+ });
89
+ yield* Effect.async((resume) => {
90
+ execFile("docker", ["cp", hostPath, `${containerName}:${sandboxPath}`], (error) => {
91
+ if (error) {
92
+ resume(Effect.fail(new CopyError({
93
+ message: `Failed to copy ${hostPath} -> ${containerName}:${sandboxPath}: ${error.message}`,
94
+ })));
95
+ }
96
+ else {
97
+ resume(Effect.succeed(undefined));
98
+ }
99
+ });
100
+ });
101
+ }),
102
+ copyOut: (sandboxPath, hostPath) => Effect.gen(function* () {
103
+ yield* fs.makeDirectory(dirname(hostPath), { recursive: true }).pipe(Effect.mapError((error) => new CopyError({
104
+ message: `Failed to create host dir ${dirname(hostPath)}: ${error}`,
105
+ })));
106
+ yield* Effect.async((resume) => {
107
+ execFile("docker", ["cp", `${containerName}:${sandboxPath}`, hostPath], (error) => {
108
+ if (error) {
109
+ resume(Effect.fail(new CopyError({
110
+ message: `Failed to copy ${containerName}:${sandboxPath} -> ${hostPath}: ${error.message}`,
111
+ })));
112
+ }
113
+ else {
114
+ resume(Effect.succeed(undefined));
115
+ }
116
+ });
117
+ });
118
+ }),
119
+ };
120
+ });
121
+ const makeDockerSandboxLayer = (containerName) => Layer.effect(Sandbox, makeDockerSandbox(containerName)).pipe(Layer.provide(NodeFileSystem.layer));
122
+ /** The mount point inside the container where the project worktree is bound. */
123
+ export const SANDBOX_WORKSPACE_DIR = "/home/agent/workspace";
124
+ export class SandboxFactory extends Context.Tag("SandboxFactory")() {
125
+ }
126
+ /**
127
+ * Synchronously force-remove a Docker container.
128
+ * Used in process exit handlers where async operations are not possible.
129
+ */
130
+ const forceRemoveContainerSync = (containerName) => {
131
+ try {
132
+ execFileSync("docker", ["rm", "-f", containerName], { stdio: "ignore" });
133
+ }
134
+ catch {
135
+ // Best-effort — container may already be gone
136
+ }
137
+ };
138
+ export class WorktreeSandboxConfig extends Context.Tag("WorktreeSandboxConfig")() {
139
+ }
140
+ /**
141
+ * Synchronously force-remove a git worktree.
142
+ * Used in process exit handlers where async operations are not possible.
143
+ */
144
+ const forceRemoveWorktreeSync = (worktreePath, repoDir) => {
145
+ try {
146
+ execFileSync("git", ["worktree", "remove", "--force", worktreePath], {
147
+ stdio: "ignore",
148
+ cwd: repoDir,
149
+ });
150
+ }
151
+ catch {
152
+ // Best-effort — worktree may already be gone
153
+ }
154
+ };
155
+ /**
156
+ * Worktree sandbox mode: creates a git worktree and bind-mounts it into the
157
+ * container at SANDBOX_WORKSPACE_DIR. The host's .git directory is also bind-mounted at
158
+ * its original host path so the worktree's .git file pointer resolves correctly.
159
+ */
160
+ export const WorktreeDockerSandboxFactory = {
161
+ layer: Layer.effect(SandboxFactory, Effect.gen(function* () {
162
+ const { imageName, env, hostRepoDir, branch, copyToSandbox: copyPaths, agentName, } = yield* WorktreeSandboxConfig;
163
+ const fileSystem = yield* FileSystem.FileSystem;
164
+ const display = yield* Display;
165
+ return {
166
+ withSandbox: (makeEffect) => {
167
+ const containerName = `sandcastle-${randomUUID()}`;
168
+ return Effect.acquireUseRelease(
169
+ // Acquire: prune stale worktrees (best-effort), create worktree, then start container
170
+ WorktreeManager.pruneStale(hostRepoDir)
171
+ .pipe(Effect.catchAll((e) => Effect.sync(() => {
172
+ console.error("[sandcastle] Warning: failed to prune stale worktrees:", e.message);
173
+ })))
174
+ .pipe(Effect.andThen(branch
175
+ ? WorktreeManager.create(hostRepoDir, { branch })
176
+ : WorktreeManager.create(hostRepoDir, { agentName })))
177
+ .pipe(Effect.provideService(FileSystem.FileSystem, fileSystem))
178
+ .pipe(Effect.flatMap((worktreeInfo) => (copyPaths && copyPaths.length > 0
179
+ ? display.spinner("Copying to sandbox", copyToSandbox(copyPaths, hostRepoDir, worktreeInfo.path))
180
+ : Effect.succeed(undefined)).pipe(Effect.map(() => worktreeInfo))))
181
+ .pipe(Effect.flatMap((worktreeInfo) => {
182
+ const gitDir = join(hostRepoDir, ".git");
183
+ const volumeMounts = [
184
+ `${worktreeInfo.path}:${SANDBOX_WORKSPACE_DIR}`,
185
+ `${gitDir}:${gitDir}`,
186
+ ];
187
+ const cleanup = () => {
188
+ forceRemoveContainerSync(containerName);
189
+ forceRemoveWorktreeSync(worktreeInfo.path, hostRepoDir);
190
+ };
191
+ const onSignal = () => {
192
+ cleanup();
193
+ process.exit(1);
194
+ };
195
+ const hostUid = process.getuid?.() ?? 1000;
196
+ const hostGid = process.getgid?.() ?? 1000;
197
+ return startContainer(containerName, imageName, env, {
198
+ volumeMounts,
199
+ workdir: SANDBOX_WORKSPACE_DIR,
200
+ user: `${hostUid}:${hostGid}`,
201
+ }).pipe(Effect.andThen(chownInContainer(containerName, `${hostUid}:${hostGid}`, "/home/agent")), Effect.tap(() => Effect.sync(() => {
202
+ process.on("exit", cleanup);
203
+ process.on("SIGINT", onSignal);
204
+ process.on("SIGTERM", onSignal);
205
+ })), Effect.map(() => ({ worktreeInfo, cleanup, onSignal })));
206
+ })),
207
+ // Use
208
+ ({ worktreeInfo }) => makeEffect({ hostWorktreePath: worktreeInfo.path }).pipe(Effect.provide(makeDockerSandboxLayer(containerName))),
209
+ // Release: remove container, then remove worktree
210
+ ({ worktreeInfo, cleanup, onSignal }) => Effect.sync(() => {
211
+ process.removeListener("exit", cleanup);
212
+ process.removeListener("SIGINT", onSignal);
213
+ process.removeListener("SIGTERM", onSignal);
214
+ }).pipe(Effect.andThen(removeContainer(containerName)), Effect.andThen(WorktreeManager.remove(worktreeInfo.path)), Effect.orDie));
215
+ },
216
+ };
217
+ })),
218
+ };
219
+ //# sourceMappingURL=SandboxFactory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SandboxFactory.js","sourceRoot":"","sources":["../src/SandboxFactory.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ import { Effect } from "effect";
2
+ import { Display } from "./Display.js";
3
+ import { type SandboxError } from "./errors.js";
4
+ import { Sandbox, type SandboxService } from "./SandboxFactory.js";
5
+ export type SandboxHooks = {
6
+ readonly onSandboxReady?: ReadonlyArray<{
7
+ readonly command: string;
8
+ }>;
9
+ };
10
+ export interface SandboxLifecycleOptions {
11
+ readonly hostRepoDir: string;
12
+ readonly sandboxRepoDir: string;
13
+ readonly hooks?: SandboxHooks;
14
+ readonly branch?: string;
15
+ /** Host-side path to the worktree directory. Required when sandboxRepoDir
16
+ * is a container path that doesn't exist on the host (e.g. /home/agent/workspace). */
17
+ readonly hostWorktreePath?: string;
18
+ }
19
+ export interface SandboxContext {
20
+ readonly sandbox: SandboxService;
21
+ readonly sandboxRepoDir: string;
22
+ readonly baseHead: string;
23
+ }
24
+ export interface SandboxLifecycleResult<A> {
25
+ readonly result: A;
26
+ readonly branch: string;
27
+ readonly commits: {
28
+ sha: string;
29
+ }[];
30
+ }
31
+ export declare const withSandboxLifecycle: <A>(options: SandboxLifecycleOptions, work: (ctx: SandboxContext) => Effect.Effect<A, SandboxError, Display | Sandbox>) => Effect.Effect<SandboxLifecycleResult<A>, SandboxError, Display | Sandbox>;
32
+ //# sourceMappingURL=SandboxLifecycle.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SandboxLifecycle.d.ts","sourceRoot":"","sources":["../src/SandboxLifecycle.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAwB,KAAK,YAAY,EAAE,MAAM,aAAa,CAAC;AACtE,OAAO,EACL,OAAO,EAEP,KAAK,cAAc,EACpB,MAAM,qBAAqB,CAAC;AAoB7B,MAAM,MAAM,YAAY,GAAG;IACzB,QAAQ,CAAC,cAAc,CAAC,EAAE,aAAa,CAAC;QAAE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACvE,CAAC;AAEF,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,KAAK,CAAC,EAAE,YAAY,CAAC;IAC9B,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB;2FACuF;IACvF,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;CACpC;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,OAAO,EAAE,cAAc,CAAC;IACjC,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,sBAAsB,CAAC,CAAC;IACvC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;IACnB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,OAAO,EAAE;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CACrC;AAED,eAAO,MAAM,oBAAoB,GAAI,CAAC,kMA6LlC,CAAC"}
@@ -0,0 +1,152 @@
1
+ import { exec } from "node:child_process";
2
+ import { promisify } from "node:util";
3
+ import { Effect } from "effect";
4
+ import { Display } from "./Display.js";
5
+ import { ExecError, SyncError } from "./errors.js";
6
+ import { Sandbox, } from "./SandboxFactory.js";
7
+ const execOk = (sandbox, command, options) => Effect.flatMap(sandbox.exec(command, options), (result) => result.exitCode !== 0
8
+ ? Effect.fail(new ExecError({
9
+ command,
10
+ message: `Command failed (exit ${result.exitCode}): ${command}\n${result.stderr}`,
11
+ }))
12
+ : Effect.succeed(result));
13
+ const execAsync = promisify(exec);
14
+ export const withSandboxLifecycle = (options, work) => Effect.gen(function* () {
15
+ const sandbox = yield* Sandbox;
16
+ const display = yield* Display;
17
+ const { hostRepoDir, sandboxRepoDir, hooks, branch, hostWorktreePath } = options;
18
+ // Without an explicit branch, record host's current branch for cherry-pick
19
+ const hostCurrentBranch = !branch
20
+ ? yield* Effect.promise(async () => {
21
+ const { stdout } = await execAsync("git rev-parse --abbrev-ref HEAD", { cwd: hostRepoDir });
22
+ return stdout.trim();
23
+ })
24
+ : null;
25
+ // Read host git identity before entering the sandbox
26
+ const [hostGitName, hostGitEmail] = yield* Effect.promise(async () => {
27
+ const [nameResult, emailResult] = await Promise.all([
28
+ execAsync("git config user.name", { cwd: hostRepoDir })
29
+ .then((r) => r.stdout.trim())
30
+ .catch(() => ""),
31
+ execAsync("git config user.email", { cwd: hostRepoDir })
32
+ .then((r) => r.stdout.trim())
33
+ .catch(() => ""),
34
+ ]);
35
+ return [nameResult, emailResult];
36
+ });
37
+ // Setup: onSandboxReady hooks
38
+ let resolvedBranch = "";
39
+ yield* display.taskLog("Setting up sandbox", (message) => Effect.gen(function* () {
40
+ // The bind-mounted worktree may be owned by a different UID (host user
41
+ // vs container user). Mark it safe so git doesn't reject it with
42
+ // "dubious ownership".
43
+ yield* execOk(sandbox, `git config --global --add safe.directory "${sandboxRepoDir}"`);
44
+ // Propagate host git identity into the sandbox so commits are attributed
45
+ // to the actual developer without requiring manual setup.
46
+ if (hostGitName) {
47
+ yield* execOk(sandbox, `git config --global user.name "${hostGitName.replace(/"/g, '\\"')}"`);
48
+ }
49
+ if (hostGitEmail) {
50
+ yield* execOk(sandbox, `git config --global user.email "${hostGitEmail.replace(/"/g, '\\"')}"`);
51
+ }
52
+ // Repo is bind-mounted — discover branch directly
53
+ resolvedBranch = (yield* execOk(sandbox, "git rev-parse --abbrev-ref HEAD", { cwd: sandboxRepoDir })).stdout.trim();
54
+ if (hooks?.onSandboxReady?.length) {
55
+ for (const hook of hooks.onSandboxReady) {
56
+ message(hook.command);
57
+ yield* execOk(sandbox, hook.command, { cwd: sandboxRepoDir });
58
+ }
59
+ }
60
+ }));
61
+ const targetBranch = branch ?? resolvedBranch;
62
+ // Record base HEAD
63
+ const baseHead = (yield* execOk(sandbox, "git rev-parse HEAD", {
64
+ cwd: sandboxRepoDir,
65
+ })).stdout.trim();
66
+ // Run the caller's work
67
+ const result = yield* work({ sandbox, sandboxRepoDir, baseHead });
68
+ // Collect commits and handle cherry-pick for temp branches
69
+ let commits;
70
+ let finalBranch;
71
+ // For host-side git operations in worktree mode, use hostWorktreePath
72
+ // (the real path on the host) instead of sandboxRepoDir (which may be a container path
73
+ // like /home/agent/workspace that doesn't exist on the host).
74
+ const hostSideWorktreePath = hostWorktreePath ?? sandboxRepoDir;
75
+ if (hostCurrentBranch !== null) {
76
+ // Temp branch mode: fast-forward host branch to temp branch, then delete temp branch.
77
+ // We use fast-forward instead of cherry-pick because cherry-pick breaks when the
78
+ // temp branch contains merge commits (e.g. a merge agent merging multiple parallel
79
+ // branches). The temp branch is always a direct descendant of hostCurrentBranch,
80
+ // so fast-forward is always valid.
81
+ // Check if there are any new commits on the temp branch
82
+ const hasNewCommits = yield* Effect.promise(async () => {
83
+ try {
84
+ const { stdout } = await execAsync(`git rev-list "${baseHead}..HEAD" --count`, { cwd: hostSideWorktreePath });
85
+ return parseInt(stdout.trim(), 10) > 0;
86
+ }
87
+ catch {
88
+ return false;
89
+ }
90
+ });
91
+ // Detach the worktree from the temp branch so the branch can be deleted
92
+ yield* execOk(sandbox, "git checkout --detach", { cwd: sandboxRepoDir });
93
+ if (hasNewCommits) {
94
+ // Fast-forward host's current branch to the temp branch
95
+ yield* Effect.tryPromise({
96
+ try: async () => {
97
+ try {
98
+ await execAsync(`git merge --ff-only "${resolvedBranch}"`, {
99
+ cwd: hostRepoDir,
100
+ });
101
+ }
102
+ catch {
103
+ throw new Error(`Fast-forward merge of '${resolvedBranch}' onto '${hostCurrentBranch}' failed. ` +
104
+ `The temporary branch '${resolvedBranch}' has been preserved. ` +
105
+ `To retry: git merge --ff-only ${resolvedBranch}, ` +
106
+ `then clean up: git branch -D ${resolvedBranch}`);
107
+ }
108
+ },
109
+ catch: (e) => new SyncError({
110
+ message: String(e instanceof Error ? e.message : e),
111
+ }),
112
+ });
113
+ }
114
+ // Delete the temp branch (now merged into host branch)
115
+ yield* Effect.promise(() => execAsync(`git branch -D "${resolvedBranch}"`, {
116
+ cwd: hostRepoDir,
117
+ }).catch(() => { }));
118
+ // Collect the commits now on the host branch
119
+ commits = yield* Effect.promise(async () => {
120
+ try {
121
+ const { stdout } = await execAsync(`git rev-list "${baseHead}..HEAD" --reverse`, { cwd: hostRepoDir });
122
+ const lines = stdout.trim();
123
+ if (!lines)
124
+ return [];
125
+ return lines.split("\n").map((sha) => ({ sha }));
126
+ }
127
+ catch {
128
+ return [];
129
+ }
130
+ });
131
+ finalBranch = hostCurrentBranch;
132
+ }
133
+ else {
134
+ // Explicit branch: commits stay on that branch
135
+ commits = yield* Effect.promise(async () => {
136
+ try {
137
+ const { stdout } = await execAsync(`git rev-list "${baseHead}..refs/heads/${targetBranch}" --reverse`, { cwd: hostRepoDir });
138
+ const lines = stdout.trim();
139
+ if (!lines)
140
+ return [];
141
+ return lines.split("\n").map((sha) => ({ sha }));
142
+ }
143
+ catch {
144
+ // Branch doesn't exist on host (no commits were produced)
145
+ return [];
146
+ }
147
+ });
148
+ finalBranch = targetBranch;
149
+ }
150
+ return { result, branch: finalBranch, commits };
151
+ });
152
+ //# sourceMappingURL=SandboxLifecycle.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SandboxLifecycle.js","sourceRoot":"","sources":["../src/SandboxLifecycle.ts"],"names":[],"mappings":"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"}