@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.
- package/README.md +284 -0
- package/dist/AgentProvider.d.ts +8 -0
- package/dist/AgentProvider.d.ts.map +1 -0
- package/dist/AgentProvider.js +60 -0
- package/dist/AgentProvider.js.map +1 -0
- package/dist/Config.d.ts +35 -0
- package/dist/Config.d.ts.map +1 -0
- package/dist/Config.js +56 -0
- package/dist/Config.js.map +1 -0
- package/dist/CopyToSandbox.d.ts +8 -0
- package/dist/CopyToSandbox.d.ts.map +1 -0
- package/dist/CopyToSandbox.js +32 -0
- package/dist/CopyToSandbox.js.map +1 -0
- package/dist/Display.d.ts +52 -0
- package/dist/Display.d.ts.map +1 -0
- package/dist/Display.js +132 -0
- package/dist/Display.js.map +1 -0
- package/dist/DockerLifecycle.d.ts +37 -0
- package/dist/DockerLifecycle.d.ts.map +1 -0
- package/dist/DockerLifecycle.js +109 -0
- package/dist/DockerLifecycle.js.map +1 -0
- package/dist/DockerSandbox.d.ts +6 -0
- package/dist/DockerSandbox.d.ts.map +1 -0
- package/dist/DockerSandbox.js +122 -0
- package/dist/DockerSandbox.js.map +1 -0
- package/dist/EnvResolver.d.ts +11 -0
- package/dist/EnvResolver.d.ts.map +1 -0
- package/dist/EnvResolver.js +43 -0
- package/dist/EnvResolver.js.map +1 -0
- package/dist/ErrorHandler.d.ts +15 -0
- package/dist/ErrorHandler.d.ts.map +1 -0
- package/dist/ErrorHandler.js +58 -0
- package/dist/ErrorHandler.js.map +1 -0
- package/dist/FilesystemSandbox.d.ts +6 -0
- package/dist/FilesystemSandbox.d.ts.map +1 -0
- package/dist/FilesystemSandbox.js +83 -0
- package/dist/FilesystemSandbox.js.map +1 -0
- package/dist/InitService.d.ts +11 -0
- package/dist/InitService.d.ts.map +1 -0
- package/dist/InitService.js +111 -0
- package/dist/InitService.js.map +1 -0
- package/dist/Orchestrator.d.ts +49 -0
- package/dist/Orchestrator.d.ts.map +1 -0
- package/dist/Orchestrator.js +155 -0
- package/dist/Orchestrator.js.map +1 -0
- package/dist/PromptArgumentSubstitution.d.ts +6 -0
- package/dist/PromptArgumentSubstitution.d.ts.map +1 -0
- package/dist/PromptArgumentSubstitution.js +33 -0
- package/dist/PromptArgumentSubstitution.js.map +1 -0
- package/dist/PromptPreprocessor.d.ts +7 -0
- package/dist/PromptPreprocessor.d.ts.map +1 -0
- package/dist/PromptPreprocessor.js +34 -0
- package/dist/PromptPreprocessor.js.map +1 -0
- package/dist/PromptResolver.d.ts +9 -0
- package/dist/PromptResolver.d.ts.map +1 -0
- package/dist/PromptResolver.js +26 -0
- package/dist/PromptResolver.js.map +1 -0
- package/dist/RecoveryMessage.d.ts +15 -0
- package/dist/RecoveryMessage.d.ts.map +1 -0
- package/dist/RecoveryMessage.js +81 -0
- package/dist/RecoveryMessage.js.map +1 -0
- package/dist/Sandbox.d.ts +23 -0
- package/dist/Sandbox.d.ts.map +1 -0
- package/dist/Sandbox.js +5 -0
- package/dist/Sandbox.js.map +1 -0
- package/dist/SandboxFactory.d.ts +56 -0
- package/dist/SandboxFactory.d.ts.map +1 -0
- package/dist/SandboxFactory.js +219 -0
- package/dist/SandboxFactory.js.map +1 -0
- package/dist/SandboxLifecycle.d.ts +32 -0
- package/dist/SandboxLifecycle.d.ts.map +1 -0
- package/dist/SandboxLifecycle.js +152 -0
- package/dist/SandboxLifecycle.js.map +1 -0
- package/dist/SyncService.d.ts +20 -0
- package/dist/SyncService.d.ts.map +1 -0
- package/dist/SyncService.js +504 -0
- package/dist/SyncService.js.map +1 -0
- package/dist/TokenResolver.d.ts +6 -0
- package/dist/TokenResolver.d.ts.map +1 -0
- package/dist/TokenResolver.js +43 -0
- package/dist/TokenResolver.js.map +1 -0
- package/dist/WorktreeManager.d.ts +42 -0
- package/dist/WorktreeManager.d.ts.map +1 -0
- package/dist/WorktreeManager.js +170 -0
- package/dist/WorktreeManager.js.map +1 -0
- package/dist/cli.d.ts +22 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +217 -0
- package/dist/cli.js.map +1 -0
- package/dist/errors.d.ts +95 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +35 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/dist/main.d.ts +3 -0
- package/dist/main.d.ts.map +1 -0
- package/dist/main.js +16 -0
- package/dist/main.js.map +1 -0
- package/dist/run.d.ts +91 -0
- package/dist/run.d.ts.map +1 -0
- package/dist/run.js +155 -0
- package/dist/run.js.map +1 -0
- package/dist/templates/blank/main.ts +9 -0
- package/dist/templates/blank/prompt.md +12 -0
- package/dist/templates/blank/template.json +4 -0
- package/dist/templates/parallel-planner/implement-prompt.md +62 -0
- package/dist/templates/parallel-planner/main.ts +200 -0
- package/dist/templates/parallel-planner/merge-prompt.md +22 -0
- package/dist/templates/parallel-planner/plan-prompt.md +33 -0
- package/dist/templates/parallel-planner/template.json +4 -0
- package/dist/templates/sequential-reviewer/implement-prompt.md +62 -0
- package/dist/templates/sequential-reviewer/main.ts +102 -0
- package/dist/templates/sequential-reviewer/review-prompt.md +43 -0
- package/dist/templates/sequential-reviewer/template.json +4 -0
- package/dist/templates/simple-loop/main.ts +37 -0
- package/dist/templates/simple-loop/prompt.md +51 -0
- package/dist/templates/simple-loop/template.json +4 -0
- package/dist/templates.d.ts +2 -0
- package/dist/templates.d.ts.map +1 -0
- package/dist/templates.js +26 -0
- package/dist/templates.js.map +1 -0
- package/dist/terminalCleanup.d.ts +30 -0
- package/dist/terminalCleanup.d.ts.map +1 -0
- package/dist/terminalCleanup.js +37 -0
- package/dist/terminalCleanup.js.map +1 -0
- package/dist/testSandbox.d.ts +8 -0
- package/dist/testSandbox.d.ts.map +1 -0
- package/dist/testSandbox.js +101 -0
- package/dist/testSandbox.js.map +1 -0
- package/package.json +62 -0
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { FileSystem } from "@effect/platform";
|
|
2
|
+
import { NodeFileSystem } from "@effect/platform-node";
|
|
3
|
+
import { Effect, Layer } from "effect";
|
|
4
|
+
import { execFile, spawn } from "node:child_process";
|
|
5
|
+
import { dirname } from "node:path";
|
|
6
|
+
import { createInterface } from "node:readline";
|
|
7
|
+
import { CopyError, ExecError } from "./errors.js";
|
|
8
|
+
import { Sandbox } from "./Sandbox.js";
|
|
9
|
+
const makeFilesystemSandbox = (sandboxDir) => Effect.gen(function* () {
|
|
10
|
+
const fs = yield* FileSystem.FileSystem;
|
|
11
|
+
return {
|
|
12
|
+
exec: (command, options) => Effect.async((resume) => {
|
|
13
|
+
execFile("sh", ["-c", command], { cwd: options?.cwd ?? sandboxDir }, (error, stdout, stderr) => {
|
|
14
|
+
if (error && error.code === undefined) {
|
|
15
|
+
resume(Effect.fail(new ExecError({
|
|
16
|
+
command,
|
|
17
|
+
message: `Failed to exec: ${error.message}`,
|
|
18
|
+
})));
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
resume(Effect.succeed({
|
|
22
|
+
stdout: stdout.toString(),
|
|
23
|
+
stderr: stderr.toString(),
|
|
24
|
+
exitCode: typeof error?.code === "number"
|
|
25
|
+
? error.code
|
|
26
|
+
: 0,
|
|
27
|
+
}));
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
}),
|
|
31
|
+
execStreaming: (command, onStdoutLine, options) => Effect.async((resume) => {
|
|
32
|
+
const proc = spawn("sh", ["-c", command], {
|
|
33
|
+
cwd: options?.cwd ?? sandboxDir,
|
|
34
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
35
|
+
});
|
|
36
|
+
const stdoutChunks = [];
|
|
37
|
+
const stderrChunks = [];
|
|
38
|
+
const rl = createInterface({ input: proc.stdout });
|
|
39
|
+
rl.on("line", (line) => {
|
|
40
|
+
stdoutChunks.push(line);
|
|
41
|
+
onStdoutLine(line);
|
|
42
|
+
});
|
|
43
|
+
proc.stderr.on("data", (chunk) => {
|
|
44
|
+
stderrChunks.push(chunk.toString());
|
|
45
|
+
});
|
|
46
|
+
proc.on("error", (error) => {
|
|
47
|
+
resume(Effect.fail(new ExecError({
|
|
48
|
+
command,
|
|
49
|
+
message: `Failed to exec: ${error.message}`,
|
|
50
|
+
})));
|
|
51
|
+
});
|
|
52
|
+
proc.on("close", (code) => {
|
|
53
|
+
resume(Effect.succeed({
|
|
54
|
+
stdout: stdoutChunks.join("\n"),
|
|
55
|
+
stderr: stderrChunks.join(""),
|
|
56
|
+
exitCode: code ?? 0,
|
|
57
|
+
}));
|
|
58
|
+
});
|
|
59
|
+
}),
|
|
60
|
+
copyIn: (hostPath, sandboxPath) => Effect.gen(function* () {
|
|
61
|
+
yield* fs
|
|
62
|
+
.makeDirectory(dirname(sandboxPath), { recursive: true })
|
|
63
|
+
.pipe(Effect.mapError((error) => new CopyError({
|
|
64
|
+
message: `Failed to copy ${hostPath} -> ${sandboxPath}: ${error}`,
|
|
65
|
+
})));
|
|
66
|
+
yield* fs.copyFile(hostPath, sandboxPath).pipe(Effect.mapError((error) => new CopyError({
|
|
67
|
+
message: `Failed to copy ${hostPath} -> ${sandboxPath}: ${error}`,
|
|
68
|
+
})));
|
|
69
|
+
}),
|
|
70
|
+
copyOut: (sandboxPath, hostPath) => Effect.gen(function* () {
|
|
71
|
+
yield* fs.makeDirectory(dirname(hostPath), { recursive: true }).pipe(Effect.mapError((error) => new CopyError({
|
|
72
|
+
message: `Failed to copy ${sandboxPath} -> ${hostPath}: ${error}`,
|
|
73
|
+
})));
|
|
74
|
+
yield* fs.copyFile(sandboxPath, hostPath).pipe(Effect.mapError((error) => new CopyError({
|
|
75
|
+
message: `Failed to copy ${sandboxPath} -> ${hostPath}: ${error}`,
|
|
76
|
+
})));
|
|
77
|
+
}),
|
|
78
|
+
};
|
|
79
|
+
});
|
|
80
|
+
export const FilesystemSandbox = {
|
|
81
|
+
layer: (sandboxDir) => Layer.effect(Sandbox, makeFilesystemSandbox(sandboxDir)).pipe(Layer.provide(NodeFileSystem.layer)),
|
|
82
|
+
};
|
|
83
|
+
//# sourceMappingURL=FilesystemSandbox.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FilesystemSandbox.js","sourceRoot":"","sources":["../src/FilesystemSandbox.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { FileSystem } from "@effect/platform";
|
|
2
|
+
import { Effect } from "effect";
|
|
3
|
+
import type { AgentProvider } from "./AgentProvider.js";
|
|
4
|
+
export interface TemplateMetadata {
|
|
5
|
+
name: string;
|
|
6
|
+
description: string;
|
|
7
|
+
}
|
|
8
|
+
export declare const listTemplates: () => TemplateMetadata[];
|
|
9
|
+
export declare function getNextStepsLines(template: string, provider: AgentProvider): string[];
|
|
10
|
+
export declare const scaffold: (repoDir: string, provider: AgentProvider, templateName?: string) => Effect.Effect<void, Error, FileSystem.FileSystem>;
|
|
11
|
+
//# sourceMappingURL=InitService.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"InitService.d.ts","sourceRoot":"","sources":["../src/InitService.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAGhC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAQxD,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;CACrB;AAuBD,eAAO,MAAM,aAAa,0BAAsC,CAAC;AAEjE,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,aAAa,GACtB,MAAM,EAAE,CAyBV;AAyDD,eAAO,MAAM,QAAQ,wHA+CjB,CAAC"}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { FileSystem } from "@effect/platform";
|
|
2
|
+
import { Effect } from "effect";
|
|
3
|
+
import { dirname, join } from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
const GITIGNORE = `.env
|
|
6
|
+
patches/
|
|
7
|
+
logs/
|
|
8
|
+
worktrees/
|
|
9
|
+
`;
|
|
10
|
+
const TEMPLATES = [
|
|
11
|
+
{
|
|
12
|
+
name: "blank",
|
|
13
|
+
description: "Bare scaffold — write your own prompt and orchestration",
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
name: "simple-loop",
|
|
17
|
+
description: "Picks GitHub issues one by one and closes them",
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
name: "sequential-reviewer",
|
|
21
|
+
description: "Implements issues one by one, with a code review step after each",
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
name: "parallel-planner",
|
|
25
|
+
description: "Plans parallelizable issues, executes on separate branches, merges",
|
|
26
|
+
},
|
|
27
|
+
];
|
|
28
|
+
export const listTemplates = () => TEMPLATES;
|
|
29
|
+
export function getNextStepsLines(template, provider) {
|
|
30
|
+
const envLines = Object.entries(provider.envManifest).map(([key, description]) => ` - ${key} — ${description}`);
|
|
31
|
+
const envStep = ["1. Set the following in .sandcastle/.env:", ...envLines];
|
|
32
|
+
if (template === "blank") {
|
|
33
|
+
return [
|
|
34
|
+
"Next steps:",
|
|
35
|
+
...envStep,
|
|
36
|
+
"2. Read and customize .sandcastle/prompt.md to describe what you want the agent to do",
|
|
37
|
+
`3. Customize .sandcastle/main.ts — it uses the JS API (\`run()\`) to control how the agent runs`,
|
|
38
|
+
`4. Add "sandcastle": "npx tsx .sandcastle/main.ts" to your package.json scripts`,
|
|
39
|
+
"5. Run `npm run sandcastle` to start the agent",
|
|
40
|
+
];
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
return [
|
|
44
|
+
"Next steps:",
|
|
45
|
+
...envStep,
|
|
46
|
+
`2. Add "sandcastle": "npx tsx .sandcastle/main.ts" to your package.json scripts`,
|
|
47
|
+
'3. Templates use `copyToSandbox: ["node_modules"]` to copy your host node_modules into the sandbox for fast startup — the `npm install` in the onSandboxReady hook is a safety net for platform-specific binaries. Adjust both if you use a different package manager',
|
|
48
|
+
"4. Read and customize the prompt files in .sandcastle/ — they shape what the agent does",
|
|
49
|
+
"5. Run `npm run sandcastle` to start the agent",
|
|
50
|
+
];
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
function buildEnvExample(envManifest) {
|
|
54
|
+
return (Object.entries(envManifest)
|
|
55
|
+
.map(([key, comment]) => `# ${comment}\n${key}=`)
|
|
56
|
+
.join("\n") + "\n");
|
|
57
|
+
}
|
|
58
|
+
function getTemplatesDir() {
|
|
59
|
+
const thisFile = fileURLToPath(import.meta.url);
|
|
60
|
+
return join(dirname(thisFile), "templates");
|
|
61
|
+
}
|
|
62
|
+
const getTemplateDir = (templateName) => Effect.gen(function* () {
|
|
63
|
+
const template = TEMPLATES.find((t) => t.name === templateName);
|
|
64
|
+
if (!template) {
|
|
65
|
+
const names = TEMPLATES.map((t) => t.name).join(", ");
|
|
66
|
+
yield* Effect.fail(new Error(`Unknown template: "${templateName}". Available: ${names}`));
|
|
67
|
+
}
|
|
68
|
+
return join(getTemplatesDir(), templateName);
|
|
69
|
+
});
|
|
70
|
+
const copyTemplateFiles = (templateDir, destDir) => Effect.gen(function* () {
|
|
71
|
+
const fs = yield* FileSystem.FileSystem;
|
|
72
|
+
const files = yield* fs
|
|
73
|
+
.readDirectory(templateDir)
|
|
74
|
+
.pipe(Effect.mapError((e) => new Error(e.message)));
|
|
75
|
+
yield* Effect.all(files
|
|
76
|
+
.filter((f) => f !== "template.json" &&
|
|
77
|
+
!f.endsWith(".js") &&
|
|
78
|
+
!f.endsWith(".js.map") &&
|
|
79
|
+
!f.endsWith(".d.ts") &&
|
|
80
|
+
!f.endsWith(".d.ts.map"))
|
|
81
|
+
.map((f) => fs
|
|
82
|
+
.copyFile(join(templateDir, f), join(destDir, f))
|
|
83
|
+
.pipe(Effect.mapError((e) => new Error(e.message)))), { concurrency: "unbounded" });
|
|
84
|
+
});
|
|
85
|
+
export const scaffold = (repoDir, provider, templateName = "blank") => Effect.gen(function* () {
|
|
86
|
+
const fs = yield* FileSystem.FileSystem;
|
|
87
|
+
const configDir = join(repoDir, ".sandcastle");
|
|
88
|
+
const exists = yield* fs
|
|
89
|
+
.exists(configDir)
|
|
90
|
+
.pipe(Effect.mapError((e) => new Error(e.message)));
|
|
91
|
+
if (exists) {
|
|
92
|
+
yield* Effect.fail(new Error(".sandcastle/ directory already exists. Remove it first if you want to re-initialize."));
|
|
93
|
+
}
|
|
94
|
+
yield* fs
|
|
95
|
+
.makeDirectory(configDir, { recursive: false })
|
|
96
|
+
.pipe(Effect.mapError((e) => new Error(e.message)));
|
|
97
|
+
const templateDir = yield* getTemplateDir(templateName);
|
|
98
|
+
yield* Effect.all([
|
|
99
|
+
fs
|
|
100
|
+
.writeFileString(join(configDir, "Dockerfile"), provider.dockerfileTemplate)
|
|
101
|
+
.pipe(Effect.mapError((e) => new Error(e.message))),
|
|
102
|
+
fs
|
|
103
|
+
.writeFileString(join(configDir, ".env.example"), buildEnvExample(provider.envManifest))
|
|
104
|
+
.pipe(Effect.mapError((e) => new Error(e.message))),
|
|
105
|
+
fs
|
|
106
|
+
.writeFileString(join(configDir, ".gitignore"), GITIGNORE)
|
|
107
|
+
.pipe(Effect.mapError((e) => new Error(e.message))),
|
|
108
|
+
copyTemplateFiles(templateDir, configDir),
|
|
109
|
+
], { concurrency: "unbounded" });
|
|
110
|
+
});
|
|
111
|
+
//# sourceMappingURL=InitService.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"InitService.js","sourceRoot":"","sources":["../src/InitService.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { Effect } from "effect";
|
|
2
|
+
import { Display } from "./Display.js";
|
|
3
|
+
import type { SandboxError } from "./errors.js";
|
|
4
|
+
import { SandboxFactory } from "./SandboxFactory.js";
|
|
5
|
+
import { type SandboxHooks } from "./SandboxLifecycle.js";
|
|
6
|
+
export interface TokenUsage {
|
|
7
|
+
readonly input_tokens: number;
|
|
8
|
+
readonly output_tokens: number;
|
|
9
|
+
readonly cache_read_input_tokens: number;
|
|
10
|
+
readonly cache_creation_input_tokens: number;
|
|
11
|
+
readonly total_cost_usd: number;
|
|
12
|
+
readonly num_turns: number;
|
|
13
|
+
readonly duration_ms: number;
|
|
14
|
+
}
|
|
15
|
+
export declare const DEFAULT_MODEL = "claude-opus-4-6";
|
|
16
|
+
/** Extract displayable text from a stream-json line */
|
|
17
|
+
export declare const parseStreamJsonLine: (line: string) => {
|
|
18
|
+
type: "text";
|
|
19
|
+
text: string;
|
|
20
|
+
} | {
|
|
21
|
+
type: "result";
|
|
22
|
+
result: string;
|
|
23
|
+
usage: TokenUsage | null;
|
|
24
|
+
} | null;
|
|
25
|
+
export interface OrchestrateOptions {
|
|
26
|
+
readonly hostRepoDir: string;
|
|
27
|
+
readonly sandboxRepoDir: string;
|
|
28
|
+
readonly iterations: number;
|
|
29
|
+
readonly hooks?: SandboxHooks;
|
|
30
|
+
readonly prompt: string;
|
|
31
|
+
readonly branch?: string;
|
|
32
|
+
readonly model?: string;
|
|
33
|
+
readonly completionSignal?: string;
|
|
34
|
+
/** Timeout in seconds. If the run exceeds this, it fails with TimeoutError. Default: 1200 (20 minutes) */
|
|
35
|
+
readonly timeoutSeconds?: number;
|
|
36
|
+
/** Optional name for the run, prepended to status messages as [name] */
|
|
37
|
+
readonly name?: string;
|
|
38
|
+
}
|
|
39
|
+
export interface OrchestrateResult {
|
|
40
|
+
readonly iterationsRun: number;
|
|
41
|
+
readonly wasCompletionSignalDetected: boolean;
|
|
42
|
+
readonly stdout: string;
|
|
43
|
+
readonly commits: {
|
|
44
|
+
sha: string;
|
|
45
|
+
}[];
|
|
46
|
+
readonly branch: string;
|
|
47
|
+
}
|
|
48
|
+
export declare const orchestrate: (options: OrchestrateOptions) => Effect.Effect<OrchestrateResult, SandboxError, Display | SandboxFactory>;
|
|
49
|
+
//# sourceMappingURL=Orchestrator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Orchestrator.d.ts","sourceRoot":"","sources":["../src/Orchestrator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAY,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC1C,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAGvC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEhD,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAwB,KAAK,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAEhF,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,uBAAuB,EAAE,MAAM,CAAC;IACzC,QAAQ,CAAC,2BAA2B,EAAE,MAAM,CAAC;IAC7C,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;CAC9B;AAED,eAAO,MAAM,aAAa,oBAAoB,CAAC;AA6B/C,uDAAuD;AACvD,eAAO,MAAM,mBAAmB;;;;;;;QAsB/B,CAAC;AAkDF,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,KAAK,CAAC,EAAE,YAAY,CAAC;IAC9B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IACnC,0GAA0G;IAC1G,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IACjC,wEAAwE;IACxE,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,2BAA2B,EAAE,OAAO,CAAC;IAC9C,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,OAAO,EAAE;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IACpC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,eAAO,MAAM,WAAW,2GAsHvB,CAAC"}
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import { Duration, Effect } from "effect";
|
|
2
|
+
import { Display } from "./Display.js";
|
|
3
|
+
import { preprocessPrompt } from "./PromptPreprocessor.js";
|
|
4
|
+
import { AgentError, TimeoutError } from "./errors.js";
|
|
5
|
+
import { SandboxFactory } from "./SandboxFactory.js";
|
|
6
|
+
import { withSandboxLifecycle } from "./SandboxLifecycle.js";
|
|
7
|
+
export const DEFAULT_MODEL = "claude-opus-4-6";
|
|
8
|
+
const extractUsage = (obj) => {
|
|
9
|
+
const usage = obj.usage;
|
|
10
|
+
if (!usage ||
|
|
11
|
+
typeof usage.input_tokens !== "number" ||
|
|
12
|
+
typeof usage.output_tokens !== "number") {
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
return {
|
|
16
|
+
input_tokens: usage.input_tokens,
|
|
17
|
+
output_tokens: usage.output_tokens,
|
|
18
|
+
cache_read_input_tokens: typeof usage.cache_read_input_tokens === "number"
|
|
19
|
+
? usage.cache_read_input_tokens
|
|
20
|
+
: 0,
|
|
21
|
+
cache_creation_input_tokens: typeof usage.cache_creation_input_tokens === "number"
|
|
22
|
+
? usage.cache_creation_input_tokens
|
|
23
|
+
: 0,
|
|
24
|
+
total_cost_usd: typeof obj.total_cost_usd === "number" ? obj.total_cost_usd : 0,
|
|
25
|
+
num_turns: typeof obj.num_turns === "number" ? obj.num_turns : 0,
|
|
26
|
+
duration_ms: typeof obj.duration_ms === "number" ? obj.duration_ms : 0,
|
|
27
|
+
};
|
|
28
|
+
};
|
|
29
|
+
/** Extract displayable text from a stream-json line */
|
|
30
|
+
export const parseStreamJsonLine = (line) => {
|
|
31
|
+
if (!line.startsWith("{"))
|
|
32
|
+
return null;
|
|
33
|
+
try {
|
|
34
|
+
const obj = JSON.parse(line);
|
|
35
|
+
if (obj.type === "assistant" && Array.isArray(obj.message?.content)) {
|
|
36
|
+
const texts = obj.message.content
|
|
37
|
+
.filter((c) => c.type === "text")
|
|
38
|
+
.map((c) => c.text);
|
|
39
|
+
if (texts.length > 0)
|
|
40
|
+
return { type: "text", text: texts.join("") };
|
|
41
|
+
}
|
|
42
|
+
if (obj.type === "result" && typeof obj.result === "string") {
|
|
43
|
+
return { type: "result", result: obj.result, usage: extractUsage(obj) };
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
// Not valid JSON — skip
|
|
48
|
+
}
|
|
49
|
+
return null;
|
|
50
|
+
};
|
|
51
|
+
const invokeAgent = (sandbox, sandboxRepoDir, prompt, model, onText) => Effect.gen(function* () {
|
|
52
|
+
let resultText = "";
|
|
53
|
+
let tokenUsage = null;
|
|
54
|
+
const execResult = yield* sandbox.execStreaming(`claude --print --verbose --dangerously-skip-permissions --output-format stream-json --model ${model} -p ${shellEscape(prompt)}`, (line) => {
|
|
55
|
+
const parsed = parseStreamJsonLine(line);
|
|
56
|
+
if (parsed?.type === "text") {
|
|
57
|
+
onText(parsed.text);
|
|
58
|
+
}
|
|
59
|
+
else if (parsed?.type === "result") {
|
|
60
|
+
resultText = parsed.result;
|
|
61
|
+
tokenUsage = parsed.usage;
|
|
62
|
+
}
|
|
63
|
+
}, { cwd: sandboxRepoDir });
|
|
64
|
+
if (execResult.exitCode !== 0) {
|
|
65
|
+
return yield* Effect.fail(new AgentError({
|
|
66
|
+
message: `Claude exited with code ${execResult.exitCode}:\n${execResult.stderr}`,
|
|
67
|
+
}));
|
|
68
|
+
}
|
|
69
|
+
return { result: resultText || execResult.stdout, usage: tokenUsage };
|
|
70
|
+
});
|
|
71
|
+
const shellEscape = (s) => "'" + s.replace(/'/g, "'\\''") + "'";
|
|
72
|
+
const formatNumber = (n) => n.toLocaleString("en-US");
|
|
73
|
+
const formatUsageRows = (usage) => ({
|
|
74
|
+
Tokens: `${formatNumber(usage.input_tokens)} in / ${formatNumber(usage.output_tokens)} out`,
|
|
75
|
+
Turns: `${usage.num_turns}`,
|
|
76
|
+
});
|
|
77
|
+
const DEFAULT_COMPLETION_SIGNAL = "<promise>COMPLETE</promise>";
|
|
78
|
+
const DEFAULT_TIMEOUT_SECONDS = 20 * 60; // 1200 seconds
|
|
79
|
+
export const orchestrate = (options) => {
|
|
80
|
+
const timeoutSeconds = options.timeoutSeconds ?? DEFAULT_TIMEOUT_SECONDS;
|
|
81
|
+
return Effect.gen(function* () {
|
|
82
|
+
const factory = yield* SandboxFactory;
|
|
83
|
+
const display = yield* Display;
|
|
84
|
+
const { hostRepoDir, sandboxRepoDir, iterations, hooks, prompt, branch } = options;
|
|
85
|
+
const resolvedModel = options.model ?? DEFAULT_MODEL;
|
|
86
|
+
const completionSignal = options.completionSignal ?? DEFAULT_COMPLETION_SIGNAL;
|
|
87
|
+
const label = (msg) => options.name ? `[${options.name}] ${msg}` : msg;
|
|
88
|
+
const allCommits = [];
|
|
89
|
+
let allStdout = "";
|
|
90
|
+
let resolvedBranch = "";
|
|
91
|
+
for (let i = 1; i <= iterations; i++) {
|
|
92
|
+
yield* display.status(label(`Iteration ${i}/${iterations}`), "info");
|
|
93
|
+
const lifecycleResult = yield* factory.withSandbox(({ hostWorktreePath }) => withSandboxLifecycle({
|
|
94
|
+
hostRepoDir,
|
|
95
|
+
sandboxRepoDir,
|
|
96
|
+
hooks,
|
|
97
|
+
branch,
|
|
98
|
+
hostWorktreePath,
|
|
99
|
+
}, (ctx) => Effect.gen(function* () {
|
|
100
|
+
// Preprocess prompt (run !`command` expressions inside sandbox)
|
|
101
|
+
const fullPrompt = yield* preprocessPrompt(prompt, ctx.sandbox, ctx.sandboxRepoDir);
|
|
102
|
+
yield* display.status(label("Agent started"), "success");
|
|
103
|
+
// Invoke the agent
|
|
104
|
+
const onText = (text) => {
|
|
105
|
+
Effect.runPromise(display.text(text));
|
|
106
|
+
};
|
|
107
|
+
const { result: agentOutput, usage } = yield* invokeAgent(ctx.sandbox, ctx.sandboxRepoDir, fullPrompt, resolvedModel, onText);
|
|
108
|
+
yield* display.status(label("Agent stopped"), "info");
|
|
109
|
+
// Log usage summary
|
|
110
|
+
if (usage) {
|
|
111
|
+
yield* display.summary("Token Usage", formatUsageRows(usage));
|
|
112
|
+
}
|
|
113
|
+
// Check completion signal
|
|
114
|
+
if (agentOutput.includes(completionSignal)) {
|
|
115
|
+
return {
|
|
116
|
+
wasCompletionSignalDetected: true,
|
|
117
|
+
stdout: agentOutput,
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
return {
|
|
121
|
+
wasCompletionSignalDetected: false,
|
|
122
|
+
stdout: agentOutput,
|
|
123
|
+
};
|
|
124
|
+
})));
|
|
125
|
+
allCommits.push(...lifecycleResult.commits);
|
|
126
|
+
allStdout += lifecycleResult.result.stdout;
|
|
127
|
+
resolvedBranch = lifecycleResult.branch;
|
|
128
|
+
if (lifecycleResult.result.wasCompletionSignalDetected) {
|
|
129
|
+
yield* display.status(label(`Agent signaled completion after ${i} iteration(s).`), "success");
|
|
130
|
+
return {
|
|
131
|
+
iterationsRun: i,
|
|
132
|
+
wasCompletionSignalDetected: true,
|
|
133
|
+
stdout: allStdout,
|
|
134
|
+
commits: allCommits,
|
|
135
|
+
branch: resolvedBranch,
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
yield* display.status(label(`Reached max iterations (${iterations}).`), "info");
|
|
140
|
+
return {
|
|
141
|
+
iterationsRun: iterations,
|
|
142
|
+
wasCompletionSignalDetected: false,
|
|
143
|
+
stdout: allStdout,
|
|
144
|
+
commits: allCommits,
|
|
145
|
+
branch: resolvedBranch,
|
|
146
|
+
};
|
|
147
|
+
}).pipe(Effect.timeoutFail({
|
|
148
|
+
duration: Duration.seconds(timeoutSeconds),
|
|
149
|
+
onTimeout: () => new TimeoutError({
|
|
150
|
+
message: `Run timed out after ${timeoutSeconds / 60} minutes`,
|
|
151
|
+
timeoutSeconds,
|
|
152
|
+
}),
|
|
153
|
+
}));
|
|
154
|
+
};
|
|
155
|
+
//# sourceMappingURL=Orchestrator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Orchestrator.js","sourceRoot":"","sources":["../src/Orchestrator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { Effect } from "effect";
|
|
2
|
+
import { Display } from "./Display.js";
|
|
3
|
+
import { PromptError } from "./errors.js";
|
|
4
|
+
export type PromptArgs = Record<string, string | number | boolean>;
|
|
5
|
+
export declare const substitutePromptArgs: (prompt: string, args: PromptArgs) => Effect.Effect<string, PromptError, Display>;
|
|
6
|
+
//# sourceMappingURL=PromptArgumentSubstitution.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PromptArgumentSubstitution.d.ts","sourceRoot":"","sources":["../src/PromptArgumentSubstitution.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE1C,MAAM,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,CAAC;AAInE,eAAO,MAAM,oBAAoB,mFA4ChC,CAAC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { Effect } from "effect";
|
|
2
|
+
import { Display } from "./Display.js";
|
|
3
|
+
import { PromptError } from "./errors.js";
|
|
4
|
+
const PLACEHOLDER_PATTERN = /\{\{([A-Za-z_][A-Za-z0-9_]*)\}\}/g;
|
|
5
|
+
export const substitutePromptArgs = (prompt, args) => {
|
|
6
|
+
const matches = [...prompt.matchAll(PLACEHOLDER_PATTERN)];
|
|
7
|
+
if (matches.length === 0 && Object.keys(args).length === 0) {
|
|
8
|
+
return Effect.succeed(prompt);
|
|
9
|
+
}
|
|
10
|
+
return Effect.gen(function* () {
|
|
11
|
+
const display = yield* Display;
|
|
12
|
+
// Collect all keys referenced in the prompt
|
|
13
|
+
const referencedKeys = new Set(matches.map((m) => m[1]));
|
|
14
|
+
// Check for missing keys (placeholder in prompt but no matching arg)
|
|
15
|
+
for (const key of referencedKeys) {
|
|
16
|
+
if (!(key in args)) {
|
|
17
|
+
return yield* Effect.fail(new PromptError({
|
|
18
|
+
message: `Prompt argument "{{${key}}}" has no matching value in promptArgs`,
|
|
19
|
+
}));
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
// Warn about unused keys (arg provided but no matching placeholder)
|
|
23
|
+
for (const key of Object.keys(args)) {
|
|
24
|
+
if (!referencedKeys.has(key)) {
|
|
25
|
+
yield* display.status(`Prompt argument "${key}" was provided but not referenced in the prompt`, "warn");
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
// Replace all placeholders with their values
|
|
29
|
+
const result = prompt.replace(PLACEHOLDER_PATTERN, (_match, key) => args[key].toString());
|
|
30
|
+
return result;
|
|
31
|
+
});
|
|
32
|
+
};
|
|
33
|
+
//# sourceMappingURL=PromptArgumentSubstitution.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PromptArgumentSubstitution.js","sourceRoot":"","sources":["../src/PromptArgumentSubstitution.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAI1C,MAAM,mBAAmB,GAAG,mCAAmC,CAAC;AAEhE,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAClC,MAAc,EACd,IAAgB,EAC6B,EAAE;IAC/C,MAAM,OAAO,GAAG,CAAC,GAAG,MAAM,CAAC,QAAQ,CAAC,mBAAmB,CAAC,CAAC,CAAC;IAE1D,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC3D,OAAO,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IAChC,CAAC;IAED,OAAO,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;QACzB,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,OAAO,CAAC;QAE/B,4CAA4C;QAC5C,MAAM,cAAc,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAE,CAAC,CAAC,CAAC;QAE1D,qEAAqE;QACrE,KAAK,MAAM,GAAG,IAAI,cAAc,EAAE,CAAC;YACjC,IAAI,CAAC,CAAC,GAAG,IAAI,IAAI,CAAC,EAAE,CAAC;gBACnB,OAAO,KAAK,CAAC,CAAC,MAAM,CAAC,IAAI,CACvB,IAAI,WAAW,CAAC;oBACd,OAAO,EAAE,sBAAsB,GAAG,yCAAyC;iBAC5E,CAAC,CACH,CAAC;YACJ,CAAC;QACH,CAAC;QAED,oEAAoE;QACpE,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YACpC,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;gBAC7B,KAAK,CAAC,CAAC,OAAO,CAAC,MAAM,CACnB,oBAAoB,GAAG,iDAAiD,EACxE,MAAM,CACP,CAAC;YACJ,CAAC;QACH,CAAC;QAED,6CAA6C;QAC7C,MAAM,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,mBAAmB,EAAE,CAAC,MAAM,EAAE,GAAG,EAAE,EAAE,CACjE,IAAI,CAAC,GAAa,CAAE,CAAC,QAAQ,EAAE,CAChC,CAAC;QAEF,OAAO,MAAM,CAAC;IAChB,CAAC,CAAC,CAAC;AACL,CAAC,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { Effect } from "effect";
|
|
2
|
+
import { Display } from "./Display.js";
|
|
3
|
+
import { PromptError } from "./errors.js";
|
|
4
|
+
import type { ExecError } from "./errors.js";
|
|
5
|
+
import type { SandboxService } from "./SandboxFactory.js";
|
|
6
|
+
export declare const preprocessPrompt: (prompt: string, sandbox: SandboxService, cwd: string) => Effect.Effect<string, ExecError | PromptError, Display>;
|
|
7
|
+
//# sourceMappingURL=PromptPreprocessor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PromptPreprocessor.d.ts","sourceRoot":"","sources":["../src/PromptPreprocessor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAE1D,eAAO,MAAM,gBAAgB,mHAuC5B,CAAC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { Effect } from "effect";
|
|
2
|
+
import { Display } from "./Display.js";
|
|
3
|
+
import { PromptError } from "./errors.js";
|
|
4
|
+
export const preprocessPrompt = (prompt, sandbox, cwd) => {
|
|
5
|
+
const pattern = /!`([^`]+)`/g;
|
|
6
|
+
const matches = [...prompt.matchAll(pattern)];
|
|
7
|
+
if (matches.length === 0) {
|
|
8
|
+
return Effect.succeed(prompt);
|
|
9
|
+
}
|
|
10
|
+
return Effect.gen(function* () {
|
|
11
|
+
const display = yield* Display;
|
|
12
|
+
return yield* display.taskLog("Expanding shell expressions", (message) => Effect.gen(function* () {
|
|
13
|
+
let result = prompt;
|
|
14
|
+
// Process matches in reverse order to preserve indices
|
|
15
|
+
for (const match of [...matches].reverse()) {
|
|
16
|
+
const command = match[1];
|
|
17
|
+
const index = match.index;
|
|
18
|
+
message(command);
|
|
19
|
+
const execResult = yield* sandbox.exec(command, { cwd });
|
|
20
|
+
if (execResult.exitCode !== 0) {
|
|
21
|
+
return yield* Effect.fail(new PromptError({
|
|
22
|
+
message: `Command \`${command}\` exited with code ${execResult.exitCode}: ${execResult.stderr}`,
|
|
23
|
+
}));
|
|
24
|
+
}
|
|
25
|
+
result =
|
|
26
|
+
result.slice(0, index) +
|
|
27
|
+
execResult.stdout.trimEnd() +
|
|
28
|
+
result.slice(index + match[0].length);
|
|
29
|
+
}
|
|
30
|
+
return result;
|
|
31
|
+
}));
|
|
32
|
+
});
|
|
33
|
+
};
|
|
34
|
+
//# sourceMappingURL=PromptPreprocessor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PromptPreprocessor.js","sourceRoot":"","sources":["../src/PromptPreprocessor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAI1C,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAC9B,MAAc,EACd,OAAuB,EACvB,GAAW,EAC8C,EAAE;IAC3D,MAAM,OAAO,GAAG,aAAa,CAAC;IAC9B,MAAM,OAAO,GAAG,CAAC,GAAG,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;IAE9C,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IAChC,CAAC;IAED,OAAO,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;QACzB,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,OAAO,CAAC;QAC/B,OAAO,KAAK,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,6BAA6B,EAAE,CAAC,OAAO,EAAE,EAAE,CACvE,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;YAClB,IAAI,MAAM,GAAG,MAAM,CAAC;YACpB,uDAAuD;YACvD,KAAK,MAAM,KAAK,IAAI,CAAC,GAAG,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC;gBAC3C,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,CAAE,CAAC;gBAC1B,MAAM,KAAK,GAAG,KAAK,CAAC,KAAM,CAAC;gBAC3B,OAAO,CAAC,OAAO,CAAC,CAAC;gBACjB,MAAM,UAAU,GAAG,KAAK,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC;gBACzD,IAAI,UAAU,CAAC,QAAQ,KAAK,CAAC,EAAE,CAAC;oBAC9B,OAAO,KAAK,CAAC,CAAC,MAAM,CAAC,IAAI,CACvB,IAAI,WAAW,CAAC;wBACd,OAAO,EAAE,aAAa,OAAO,uBAAuB,UAAU,CAAC,QAAQ,KAAK,UAAU,CAAC,MAAM,EAAE;qBAChG,CAAC,CACH,CAAC;gBACJ,CAAC;gBACD,MAAM;oBACJ,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC;wBACtB,UAAU,CAAC,MAAM,CAAC,OAAO,EAAE;wBAC3B,MAAM,CAAC,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;YAC1C,CAAC;YACD,OAAO,MAAM,CAAC;QAChB,CAAC,CAAC,CACH,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { FileSystem } from "@effect/platform";
|
|
2
|
+
import { Effect } from "effect";
|
|
3
|
+
import { PromptError } from "./errors.js";
|
|
4
|
+
export interface ResolvePromptOptions {
|
|
5
|
+
readonly prompt?: string;
|
|
6
|
+
readonly promptFile?: string;
|
|
7
|
+
}
|
|
8
|
+
export declare const resolvePrompt: (options: ResolvePromptOptions) => Effect.Effect<string, PromptError, FileSystem.FileSystem>;
|
|
9
|
+
//# sourceMappingURL=PromptResolver.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PromptResolver.d.ts","sourceRoot":"","sources":["../src/PromptResolver.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE1C,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED,eAAO,MAAM,aAAa,8FAsCzB,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { FileSystem } from "@effect/platform";
|
|
2
|
+
import { Effect } from "effect";
|
|
3
|
+
import { PromptError } from "./errors.js";
|
|
4
|
+
export const resolvePrompt = (options) => {
|
|
5
|
+
const { prompt, promptFile } = options;
|
|
6
|
+
if (prompt !== undefined && promptFile !== undefined) {
|
|
7
|
+
return Effect.fail(new PromptError({
|
|
8
|
+
message: "Cannot provide both --prompt and --prompt-file",
|
|
9
|
+
}));
|
|
10
|
+
}
|
|
11
|
+
if (prompt !== undefined) {
|
|
12
|
+
return Effect.succeed(prompt);
|
|
13
|
+
}
|
|
14
|
+
if (promptFile === undefined) {
|
|
15
|
+
return Effect.fail(new PromptError({
|
|
16
|
+
message: "Must provide either prompt or promptFile. Pass prompt: '...' or promptFile: './.sandcastle/prompt.md' to run().",
|
|
17
|
+
}));
|
|
18
|
+
}
|
|
19
|
+
return Effect.gen(function* () {
|
|
20
|
+
const fs = yield* FileSystem.FileSystem;
|
|
21
|
+
return yield* fs.readFileString(promptFile).pipe(Effect.catchAll((e) => Effect.fail(new PromptError({
|
|
22
|
+
message: `Failed to read prompt from ${promptFile}: ${e}`,
|
|
23
|
+
}))));
|
|
24
|
+
});
|
|
25
|
+
};
|
|
26
|
+
//# sourceMappingURL=PromptResolver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PromptResolver.js","sourceRoot":"","sources":["../src/PromptResolver.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAO1C,MAAM,CAAC,MAAM,aAAa,GAAG,CAC3B,OAA6B,EAC8B,EAAE;IAC7D,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,GAAG,OAAO,CAAC;IAEvC,IAAI,MAAM,KAAK,SAAS,IAAI,UAAU,KAAK,SAAS,EAAE,CAAC;QACrD,OAAO,MAAM,CAAC,IAAI,CAChB,IAAI,WAAW,CAAC;YACd,OAAO,EAAE,gDAAgD;SAC1D,CAAC,CACH,CAAC;IACJ,CAAC;IAED,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;QACzB,OAAO,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IAChC,CAAC;IAED,IAAI,UAAU,KAAK,SAAS,EAAE,CAAC;QAC7B,OAAO,MAAM,CAAC,IAAI,CAChB,IAAI,WAAW,CAAC;YACd,OAAO,EACL,iHAAiH;SACpH,CAAC,CACH,CAAC;IACJ,CAAC;IAED,OAAO,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;QACzB,MAAM,EAAE,GAAG,KAAK,CAAC,CAAC,UAAU,CAAC,UAAU,CAAC;QACxC,OAAO,KAAK,CAAC,CAAC,EAAE,CAAC,cAAc,CAAC,UAAU,CAAC,CAAC,IAAI,CAC9C,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,EAAE,CACpB,MAAM,CAAC,IAAI,CACT,IAAI,WAAW,CAAC;YACd,OAAO,EAAE,8BAA8B,UAAU,KAAK,CAAC,EAAE;SAC1D,CAAC,CACH,CACF,CACF,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export type FailedStep = "commits" | "diff" | "untracked";
|
|
2
|
+
export interface RecoveryInput {
|
|
3
|
+
readonly patchDir: string;
|
|
4
|
+
readonly failedStep: FailedStep;
|
|
5
|
+
readonly hasCommits: boolean;
|
|
6
|
+
readonly hasDiff: boolean;
|
|
7
|
+
readonly hasUntracked: boolean;
|
|
8
|
+
readonly branch?: string;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Build copy-pastable recovery commands for a failed sync-out.
|
|
12
|
+
* Pure function: takes failure state, returns formatted terminal output.
|
|
13
|
+
*/
|
|
14
|
+
export declare const buildRecoveryMessage: (input: RecoveryInput) => string;
|
|
15
|
+
//# sourceMappingURL=RecoveryMessage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RecoveryMessage.d.ts","sourceRoot":"","sources":["../src/RecoveryMessage.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,UAAU,GAAG,SAAS,GAAG,MAAM,GAAG,WAAW,CAAC;AAE1D,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAC;IAChC,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;IAC7B,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC;IAC/B,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED;;;GAGG;AACH,eAAO,MAAM,oBAAoB,kCAmEhC,CAAC"}
|